Журнал изменений

Официальный сайт SLAED CMS

Журнал изменений

Фильтр и поиск

Всего: 1066 Доступных коммитов | Отфильтровано: 1066 Коммиты | Страница: 1 / 107
Сегодня (28.07.2026)
Docs: record stage 1 batch 2 of the comment plan
Автор: Eduard Laas | Дата: 12:42 28.07.2026

A new chat starts from this file rather than from the working tree, so the batch that moved the frontend reads has to leave behind what it decided, what it measured and what it deliberately did not touch.

Core changes:

  1. Comment plan progress (docs/COMMENTS-REDESIGN-2026.md):
  2. Batch 2 recorded with what landed, which checks ran and what they reported
  3. Decisions written down: the unreachable admin read branch left with the read it built, the page size no longer dividing by zero, the two single-letter locals renamed, and why the no-direct-SQL guard belongs to batch 6

  4. The setting invariant recorded: the class snapshots $conf['comments'] while the render function still reads sort and nump live, which is safe only because nothing writes that section at runtime

  5. Deviation recorded: the batch inherits the unmeasured moderator branch, since the signed-in views need a session no CLI probe can hold

  6. Function size re-measured after the move: 186 lines instead of 253, with the new line range

Benefits:

  • The stage keeps one place where every decision of every batch survives
  • The next batch knows which verification gaps it inherits instead of rediscovering them

Technical notes:

  • Documentation only; no code, schema or behaviour is touched by this commit
Refactor: frontend comment reads move into the Comment class
Автор: Eduard Laas | Дата: 12:42 28.07.2026

Stage 1 batch 2 of docs/COMMENTS-REDESIGN-2026.md: the render function no longer queries the comment table itself. It asks the subsystem for one page and assembles markup, which is what lets the later stages change storage and sorting in one place instead of at every call site.

Core changes:

  1. Comment list rendering (core/system.php):
  2. ashowcom() reads through $com->getList() instead of its own SQL

    • the count query, the page query and the author group join are gone
    • pagination, the visibility scope and the running comment number now come
from the class, so a count can no longer disagree with the page it counts
  • the unreachable ADMIN_FILE read branch left with the read it built; the
admin render branches stay until the function itself is removed
  • local names follow the naming rules of .rules/global.md

    • the running number $a became $numb, the checkbox flag $b became $mark

Benefits:

  • 253 lines down to 186, and no direct comment SQL left in the render path
  • one description of what a viewer may see, shared by the count and the page
  • a broken comments.num setting falls back to 15 instead of dividing by zero

Technical notes:

  • no schema, template or markup change; the rendered output is byte for byte the same

  • verified against the pre-move file over 26 URLs in both sort directions: first, middle, last, out-of-range and zero pages, a target with no comments, a target spilling one row onto a second page, one holding exactly the page size, garbage and negative page parameters, and a missing target id

  • comment-baseline verify stays OK on all eight modules
  • the signed-in and moderator views need a browser session and are not covered by this batch

Docs: record stage 1 batch 1 and the eight-module comment baseline
Автор: Eduard Laas | Дата: 12:02 28.07.2026

The markup baseline the comment stage checks its parity against covered six of the eight modules, which would have let two of them drift unnoticed through the whole refactor. Both fixtures are restored and the plan now carries what batch 1 decided, so the next chat starts from a record of the work rather than from the code alone.

Core changes:

  1. Comment plan progress (docs/COMMENTS-REDESIGN-2026.md):
  2. Batch 1 recorded with what landed, which checks ran and what they reported
  3. Decisions written down: the third constructor argument, the parser kept unused until it is needed, the pager and scope helpers, status = 1 for public reads, the two placeholders of the author search, and the name shared with the global getUserList()
  4. Deviations recorded: six read methods instead of the four the plan named, and the moderator branch written but not measured because the probe is a guest
  5. The baseline blocker is closed, since capture now records all eight modules
  6. Comment table facts re-measured: 7357 rows, media back in the distribution with its two fixture rows
  7. Baseline fixture procedure (docs/TESTS.md):
  8. The preparation SQL is recorded beside the revert it already carried, so a lost fixture can be rebuilt rather than guessed
  9. note and links are named explicitly because both are TEXT NOT NULL without a default and the server runs STRICT_TRANS_TABLES; the documented statements were proven executable against the live schema
  10. The category permission values are explained, because catmids() filters the view by them and the schema default is not an open state
  11. Unit test inventory brought up to date with the comment and mail test files

Benefits:

  • The parity claim of the stage covers all eight commenting modules instead of six
  • A stand that lost a fixture can be repaired from the document instead of from memory
  • Every decision of the batch survives into the next chat, which starts without its context

Technical notes:

  • Documentation only; no code, schema or behaviour is touched by this commit
  • The fixture rows themselves live in the local database and are not part of the repository, as storage/baseline is ignored by git
Feature: Comment class carrying the read half of the comment engine
Автор: Eduard Laas | Дата: 12:01 28.07.2026

Stage 1, batch 1 of docs/COMMENTS-REDESIGN-2026.md opens the move of the comment engine out of the 253-line ashowcom() monolith into one class. This batch adds the class and its reads only; nothing calls them yet, so the running system is untouched and every later batch migrates call sites against a surface already proven equal to the queries it replaces.

Core changes:

  1. Comment subsystem (core/classes/comment.php):
  2. New class owning every read of the comment table

    • getCount() and getList() serve the frontend list with its pagination
    • getAdminList() serves the moderation list across state, module and the five search fields
    • getComment(), getUserList() and getModuleList() serve the admin edit form, the profile activity feed and the module selector
  3. CommentStatus and CommentMode enums replace the bare 0/1/2 literals of status and acomm
  4. getScope() and getAdminScope() build a visibility scope once and getTotal() counts against that same source, so a list and its count cannot describe different rows
  5. getAuthors() resolves the author records of one page in a single round trip, keeping the group-join precedence the current rendering relies on
  6. getPager() holds the page arithmetic the frontend and the moderation list currently spell out twice
  7. Request wiring (core/system.php):
  8. The class loads beside the other services and is constructed after the parser as $com
  9. The constructor takes $conf as a third argument because no class in core/classes reaches for a global and the reads need the comments section for their pagination
  10. Read parity harness (tests/Support/contract_probe.php, tests/Unit/CommentReadTest.php):
  11. New commentread probe mode puts every legacy statement beside the method replacing it, against the live rows of the installation
  12. 8 test cases cover the count, the first and last list page, the author record, the activity feed, the module list, a single read, a missing id and all five moderation filters
  13. The list case was proven to fail by flipping the sort direction, so the parity claim is measured rather than asserted

Benefits:

  • Byte parity of the rendered comment list becomes checkable per batch instead of at the end of a twenty-site diff
  • One visibility predicate per list removes the class of defect the hand-built where/count pair of the admin module still carries
  • The read surface is settled before any call site moves, so the migration batches change callers only

Technical notes:

  • No table, column or index changes; no behaviour change, because nothing calls the class yet
  • Public reads select status = 1 rather than status != 0 per the design query rule; the column holds 0 and 1 only across all 7357 rows and the probe proves the results identical
  • The author search keeps two placeholders for one term because emulated prepares are off and a native statement refuses a repeated named placeholder
  • getUserList() shares its name with the unrelated global function at core/system.php:4792, which no stage removes; a method and a function of one name coexist without ambiguity
Refactor: migrate every mail call site to the Mail service
Автор: Eduard Laas | Дата: 11:35 28.07.2026

Stage 1 of docs/MAIL-2026.md ends here: all 26 outgoing-mail call sites now go through $mailer->addQueue() and the global addMail() is deleted, so the transport choice added in batches 1-5 becomes the only way a message leaves the system. Stage 2 can then turn the same call into a queue row without touching a single caller.

Core changes:

  1. Call site migration (26 sites in 16 files):
  2. every caller passes a named array instead of six positional arguments

    • kind names the originating feature: account, admins, contact, forum,
help, money, order, privat, recommend, security, shop, newsletter
  • addAdminMail() passes comment or content depending on its own $iscmt,
so a comment notice stays distinguishable from a new-content notice
  • the six sites that passed $id = 1 now pass client => true
  • recipient, sender and priority keep their existing meaning everywhere
  1. Legacy surface removal (core/security.php):
  2. addMail() deleted; no wrapper, alias or transitional signature remains
  3. with it go the self-written Return-Path header, the hand-built =?CHARSET?b?..?= subject and the error handler that discarded warnings

  4. Service construction moved (core/security.php, core/system.php):
  5. $mailer is created at core/security.php:54, right after $db and PREFIX_DB

    • addHackReport() and addWarnReport() are reached from the request scan
inside that same file, long before the previous construction point
  • a migrated security notice would otherwise have called a method on null
  • the require_once stays in core/system.php, ahead of the file that uses it
  • Documentation (CONTRIBUTING.md, docs/PERFORMANCE.md, docs/MAIL-2026.md):
  • the verb-prefix table illustrates add with addHackReport(), a function that still exists

  • the Outgoing Mail section describes the current entry point
  • the plan records the batch, four decisions and the remaining blockers

Benefits:

  • one entry point for outgoing mail, so the transport and later the queue are introduced behind a boundary no caller can bypass

  • a refused delivery is now recorded through Logger::addSite() with the transport and a masked recipient instead of being silently discarded

  • kind gives stage 2 the retention, priority and admin filter it needs without re-deriving anything at the call site

  • the newsletter body is parsed once per batch instead of once per recipient

Technical notes:

  • Breaking change: addMail() no longer exists. Any third-party module or local patch calling it must move to $mailer->addQueue().

  • An unresolvable sender now aborts the send rather than emitting an empty From, per the plan's validation rule.

  • Behaviour on the default transport is unchanged for an installation that configures nothing: an unset mail.transport still delivers through PHP mail().

  • Verified: php -l on all touched files, phpunit 306 tests / 3 skipped, phpstan clean, php-cs-fixer clean, front page and admin.php both 200, and a crafted request drove addHackReport() through the migrated path over real HTTP. Live delivery for the remaining call sites needs a host with a working MTA and is tracked in the plan.

Feature: mail settings, the test send and the value-driven row hook
Автор: Eduard Laas | Дата: 10:54 28.07.2026

Stage 1 batch 5 of docs/MAIL-2026.md gives the three transports a configuration and an administrator a way to prove it works before real mail depends on it. The delivery half of the subsystem is now reachable from the panel rather than from a hand-written file, and the shipped defaults keep every installation delivering through PHP mail() until someone chooses otherwise. The 26 call sites still use addMail(), so nothing an installation sends has changed.

Core changes:

  1. Configuration (config/mail.php):
  2. Ship every key the plan lists at its documented default, transport php, the site-derived and SMTP credential fields empty

    • keys are written in the order setConfigFile() writes them, since it sorts
before export and a shipped file in reading order would be rewritten by the
first save
  • the queue keys ship complete but have no control yet: a row for batch or
keep would govern machinery that arrives in stage 2
  1. Mail tab (admin/modules/config.php):
  2. getMailPanel() builds the _MAILOPT tab: transport, sender identity, SMTP, the Sendmail path, the test send, then the existing mtemp

    • getMailRow() carries the transport a row belongs to, so the value hook can
hide it for every other one
  • the password field renders empty whatever is stored, and an empty
submission keeps the stored value through the setConfigFile() merge
  • a missing openssl or a disabled proc_open is reported beside the control it
disables; neither control is removed, because a disabled field posts nothing
and the next save would silently reset it
  • save() writes config/mail.php over the stored section, so the queue keys and an unchanged password survive

    • transport and encryption accept only their listed values
    • a sender or Reply-To address that fails validation refuses the whole save
before any file is written, rather than being stored and silently stopping
delivery
  • mailtest() is the fourth operation: POST, checkSiteToken(), the recipient defaults to adminmail, and the answer is either success or the transport's own error string

    • the field carrying the password is dropped from the request first, because
Logger records every posted field with a failure entry and the button
submits the shared config form
  1. Row visibility (plugins/system/slaed.js):
  2. setFieldShows() shows a row only for named values of another control, beside the tab-index hook it complements and in the same style

    • a row is written visible and is only ever hidden, so the settings stay
reachable when the script is not
  1. Locales (admin/lang/*.php):
  2. Twenty-one constants in all six languages, reusing _USER, _PASSWORD, _NONE, _SEND and _ERROR rather than adding scoped duplicates

  3. Tests and plan (tests/Unit/MailConfigTest.php, docs/MAIL-2026.md):
  4. Five cases hold the shipped file to its key set, its defaults, its key order and its string types, so a fresh install and an upgrade cannot diverge

  5. Record the batch in Progress with its decisions, the defect found and fixed inside it and the blockers left open

Benefits:

  • Delivery can be pointed at a relay, a binary or PHP mail() from the panel, and the choice is proved by a one-click test send instead of by the next password reset that fails

  • Configuration and its writability notice live where every other config section already lives, with no new module, no new tab and no new token mechanism

  • The value-driven hook is general: any row can now depend on the value of another field, which the tab-index hook could not express

Technical notes:

  • The test send reads the stored configuration, so settings are saved and then tested; the row says so

  • An empty password field cannot clear a stored password, which is what makes it safe to render the field empty

  • Header-bound values are stored as typed and sanitised where they reach a header, since the input text filter would corrupt a sender name inside MIME

  • Without JavaScript the config module shows its first tab only, which is how every tab on that screen already behaved

Feature: SMTP transport with its dialogue and tests
Автор: Eduard Laas | Дата: 10:04 28.07.2026

Stage 1 batch 4 of docs/MAIL-2026.md adds the third and last transport, the only one carrying real protocol risk, so the eight hazards the plan names are each closed and tested here. PHP ships a socket layer but no SMTP client, and this is the one part of the subsystem written against the protocol itself. Nothing selects it yet, since config/mail.php arrives in batch 5, so every installation keeps delivering through PHP mail().

Core changes:

  1. SMTP transport (core/classes/mail.php):
  2. addSmtpMail() conducts MAIL FROM, RCPT TO, DATA and the message over one connection that is opened once and kept

    • checkSmtpLink() returns the socket it already holds unless the relay
dropped it, which is what makes a stage 2 drain one handshake per run
  • checkSmtpGreet() runs the greeting, EHLO with a HELO fallback, STARTTLS
with the second EHLO it requires, and AUTH last
  • getSmtpReply() follows continuation lines to the final one and bounds them,
since a reply read a line at a time desynchronises the whole dialogue
  • checkSmtpStep() requires the expected reply code and aborts with the
relay's own text, so no unexpected code is read as an acceptance
  • getSmtpData() ends every line with CRLF whatever the stored body uses,
doubles a leading dot and leaves the terminating sequence the only bare one
  • setSmtpText() confirms every octet left, because a half-written command
desynchronises the dialogue and a closed socket is not a delivery
  • setSmtpFail() records the phase and the code stage 2 stores in its columns
and drops the connection, so no failure path leaves a socket open
  • TLS keeps peer and peer-name verification with no option to disable it, and is refused rather than skipped when openssl is missing

  • AUTH uses a mechanism the relay advertised, PLAIN before LOGIN; neither the password nor its encoded payload reaches a failure message at any level

  • Transport dispatch (core/classes/mail.php):
  • setDelivery() gained the smtp arm beside sendmail, with PHP mail() still the default for an unset or unknown value

  • Warning capture (core/classes/mail.php):
  • setWarnCatch() and getWarnText() replace the handler pattern batch 2 and batch 3 each carried a copy of, and serve the three new socket calls

    • an unhandled warning inside a pseudo-cron request would otherwise leak
into the response body a visitor receives
  1. Tests (tests/Unit/MailSmtpTest.php):
  2. Twenty cases drive the dialogue over a socket pair standing in for the relay, so multi-line replies, an unexpected code, dot-stuffing, CRLF line endings, the read timeout and the closed socket are exercised without a network

  3. Five guards were confirmed to fail their tests when removed: dot-stuffing, continuation handling, the advertised-mechanism read, the socket close and the connection reuse

  4. Plan (docs/MAIL-2026.md):
  5. Record the batch in Progress with its decisions, the defects found and fixed inside it and the blockers left open

Benefits:

  • An installation can point delivery at an authenticated relay, which is what most hosting now requires for mail to arrive at all

  • A hosted sender is reached through the SMTP credentials it publishes, with no code specific to any provider

  • Every failure carries the phase and the code, so a refusal can be attributed to connect, EHLO, AUTH, the sender, the recipient or the body

Technical notes:

  • Nothing writes mail.transport or any SMTP key yet, so no installation behaviour changes

  • No test reaches a relay: the dialogue is covered, the dialects real relays answer with are not, and the stage verification list covers them on a host that can deliver

  • Implicit SSL and the TLS handshake are the two paths no test enters, since a self-signed peer would only prove verification can be turned off

  • No new package: composer.json is untouched and the class uses PHP core only
Feature: Sendmail transport and transport dispatch
Автор: Eduard Laas | Дата: 09:37 28.07.2026

Stage 1 batch 3 of docs/MAIL-2026.md adds the second transport and the dispatch that chooses one. The binary is reached through proc_open() with an argument array, so no shell is involved and mail.sendmail stays a path rather than a command. Nothing selects it yet, since config/mail.php arrives in batch 5, so every installation keeps delivering through PHP mail().

Core changes:

  1. Sendmail transport (core/classes/mail.php):
  2. addSendMail() pipes the message into the configured binary and reads the exit status that popen() would hide

    • the command is an argument array: the path is validated as an existing
executable file and every argument (-t, -i, -f) is supplied by the class,
so panel access cannot become shell execution
  • -t takes the recipient from the To header, so no address is ever passed as
a command argument
  • proc_open() is probed rather than assumed, since shared hosting routinely
lists it in disable_functions
  • a short write is a failure of its own: a binary that died before reading
can still exit zero, which an unchecked fwrite() would report as accepted
  • the write uses the same warning handler as PHP mail(), because a closed
pipe raises one that would otherwise leak into the response body
  1. Transport dispatch (core/classes/mail.php):
  2. setDelivery() became the match on mail.transport that batch 2 promised

    • the default arm is PHP mail(), so an unset or unknown value keeps behaving
exactly as the installation does today
  1. Message composition (core/classes/mail.php):
  2. getHeaders() gained the subject, emitted only when the transport does not supply it, which is the rule the block already applied to To

  3. setError() bounds the recorded text at 255 characters, counted in characters so a multibyte transport response is not cut mid-character

  4. Tests (tests/Unit/MailTransportTest.php, tests/Unit/MailHeaderTest.php):
  5. Five cases over the two sendmail guards, the transport selection and the error bound, none of which start a process

  6. Both guards were confirmed to fail their tests when removed
  7. The eleven batch 1 getHeaders() calls carry the added argument, with no assertion changed

  8. Plan (docs/MAIL-2026.md):
  9. Record the batch in Progress with its decisions, the defects found and fixed inside it and the blockers left open

Benefits:

  • An installation whose host has no usable mail() gains a second way out
  • A failed delivery now carries the binary's own exit status and stderr
  • Message assembly stays in one place for the SMTP transport in batch 4

Technical notes:

  • Nothing writes mail.transport or mail.sendmail yet, so no installation behaviour changes

  • The pipe itself is unexercised here: this box has no sendmail binary, and the stage verification list covers it on a host that can deliver

  • No new package: composer.json is untouched and the class uses PHP core only
Feature: PHP Mail transport and the enqueue contract
Автор: Eduard Laas | Дата: 09:08 28.07.2026

Stage 1 batch 2 of docs/MAIL-2026.md adds the entry point every call site will use and the default transport behind it, so one place validates a message, composes it and hands it over. Nothing calls addQueue() yet and addMail() still delivers, so no installation behaviour changes; the 26 call sites migrate in batch 6.

Core changes:

  1. Enqueue contract (core/classes/mail.php):
  2. addQueue() accepts one message and delivers it, returning the transport result

    • recipient and sender are validated before a transport is entered, so an
address carrying a line break aborts the send instead of being cleaned
  • an unresolvable sender is refused rather than emitted as From: <>
  • client => true appends the IP, browser and agent hash block inside the
request that owns that data, replacing the magic $id of addMail()
  • priority defaults to 3, as addMail() did
  1. PHP Mail transport (core/classes/mail.php):
  2. setDelivery() encodes subject and body and hands them to the transport, which is the path the stage 2 drain will call instead of addQueue()

  3. addPhpMail() delivers through mail() with the envelope sender as -f

    • the envelope sender follows the resolved From, so the receiving side
authenticates the address the message claims
  • a host refusing the fifth parameter is expected: the fallback is attempted
and logged once per run, and the parameter is dropped for the rest of it
  • the warning handler captures the text instead of discarding it, and the
result of mail() is read rather than ignored
  • getMaskedMail() masks the address a failure records and refuses to log a value that does not validate, so an injected tail cannot reach the log

  • Tests (tests/Unit/MailTransportTest.php, tests/bootstrap.php):
  • Five cases over the pre-transport aborts, the mask and the client block, none of which enter mail() itself

  • getAgent() mock beside the getIp() one the bootstrap already carried
  • Plan (docs/MAIL-2026.md):
  • Record the batch in Progress with its decisions, the defects found and fixed inside it and the blockers left open

Benefits:

  • A refused message stops being invisible: it returns false, fills getError() and produces a Logger::addSite() entry with the transport and a masked address

  • Delivery has one entry point, so the stage 2 queue changes only what happens inside the object

  • A broken transport costs one attempt per message rather than two

Technical notes:

  • Headers reach mail() with CRLF where addMail() used bare LF; composition and semantics are unchanged, encoding and line handling deliberately are not

  • title length is validated in stage 2, where the VARCHAR(255) column exists
  • No new package: composer.json is untouched and the class uses PHP core only
Feature: mail service groundwork, message composition
Автор: Eduard Laas | Дата: 08:43 28.07.2026

Stage 1 batch 1 of docs/MAIL-2026.md adds the Mail service that will own every outgoing message. Only the composition half lands here: pure functions over one message with no transport behind them, so the RFC work is reviewable on its own before PHP mail, Sendmail and SMTP arrive. Nothing calls it yet, addMail() is untouched, and delivery behaviour is unchanged.

Core changes:

  1. Mail service (core/classes/mail.php):
  2. Resolve sender identity per the plan's table: mail.frommail and mail.fromname win, the caller's address and the site name are the fallbacks

  3. Assemble the MIME header block without a self-written Return-Path, which the receiving MTA owns

    • To is emitted only when the transport does not write its own, as PHP mail()
does and as Sendmail started with -t cannot
  • Reply-To drops the display name that only repeated the address
  • Encode subject and display name through mb_encode_mimeheader with B encoding and correct folding, replacing a hand-built encoded word that never folded

    • an encoded word is no longer wrapped in quotes, which RFC 2047 forbids
    • a plain ASCII display name becomes a proper quoted string instead
  • Wrap the base64 body at 76 characters, so a 5 KB message stops going out as a single 6720-octet line

  • Validate addresses with FILTER_VALIDATE_EMAIL and refuse control characters before whitespace is trimmed, so a trailing CRLF cannot be trimmed into a valid address

  • Strip control characters from header text bytewise; a UTF-8 aware pattern returns null on a malformed byte and would drop the whole value

  • Bootstrap (core/system.php):
  • Require the class between the config and core/security.php, and create $mailer once the database connection exists

  • Tests (tests/Unit/MailHeaderTest.php):
  • 23 cases over identity resolution, encoded-word folding limits, base64 line length, CRLF endings, encoding round trips and every address injection path

  • Plan (docs/MAIL-2026.md):
  • Record the batch in Progress with its decisions, its deviations and the defect found and fixed inside it

  • Re-measure the core/system.php line references that the new require shifted

Benefits:

  • Header and encoding conformance is reviewable before any transport depends on it
  • One place composes a message, so the three transports cannot each grow their own
  • Header injection is closed at a single sanitiser rather than per transport

Technical notes:

  • filterText() is no longer applied to subjects and addresses: it is an input filter that HTML-escapes a MIME subject, corrupts a local part containing &, and depends on request state the stage 2 drain will not have

  • Subject bytes therefore change for & < > " ' and %xx sequences; the plan states that byte parity is not the criterion for this stage

  • No new package: composer.json is untouched and the class uses PHP core only
  • No behaviour change yet: addMail() still delivers every one of the 26 call sites, which migrate in batch 6

Всего: 1066 на 107 страницах по 10 на каждой странице

1 2 3 4 5 6 7 8 9 10 107
Хотите опробовать SLAED CMS в действии?
Идеи и предложения
Обратная связь
Подтверждение

Поделиться
QR-код