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

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

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

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

Всего: 1114 Доступных коммитов | Отфильтровано: 1114 Коммиты | Страница: 1 / 112
Сегодня (14.08.2026)
Docs: the Fileinfo upload plan becomes a task with a named cause and a check per format
Автор: Eduard Laas | Дата: 00:14 14.08.2026

The document stopped being a briefing that asks the reader to confirm a problem and became the task itself: the cause is named, the four points that produce it are given with file and line, and every one of the twenty-one allowed types gets the structural check its fallback must pass.

Core changes:

  1. Statement of the task (docs/UPLOAD-FILEINFO-PLAN-2026.md):
  2. the constraint is stated first: a clean SLAED without Composer or vendor

    • routes, JSON, result shape and the database stay as they are
    • content validation is not weakened, and GD and cURL stay required where they already were
  3. the cause is named: production PHP 8.4.22 built with --disable-fileinfo
  4. The points that produce the refusal:
  5. checkUploadInput() answers unsupported before input, size and extension are looked at
  6. the same read blocks remote upload
  7. getFileMime() answers null when finfo is absent or cannot be created
  8. the route shows unsupported as a format error
  9. The filename contract:
  10. the extension comes from the submitted name and the content from the temporary path

    • the fallback never reads the type off the name the file is finally stored under
  11. The work itself:
  12. the order of checks is fixed so a missing Fileinfo cannot mask missing, size or transfer
  13. one content validator serves local and remote upload, reading through fopen/fread/fseek
  14. a table gives the required structural check and the canonical MIME for each allowed type

Benefits:

  • the reader of the plan can start writing code instead of first reproducing the fault
  • a per-format table makes the acceptance of the change checkable rather than arguable

Technical notes:

  • documentation only: no code, schema or configuration is touched by this commit
Style: the private message strings say the shortest true thing and stop starting in lower case
Автор: Eduard Laas | Дата: 00:14 14.08.2026

Every string this page shows stands in a chip, a shelf note, a card or a counter, and never inside a sentence, so each one begins with a capital and drops the words its box cannot carry. The forward prefix stops being an untranslated abbreviation and becomes the noun each locale really uses, the way the reply prefix already did.

Core changes:

  1. The chips of the compose header (lang/*.php):
  2. _PRWAIT reads «Интервал 60 сек.» where it read «интервал между отправками 60 секунд»
  3. _PRLIMTO and _PRLIMSUB name the field and the bound and nothing else

    • «Имя, до 25 символов» and «Заголовок, до 100 символов»
    • all three now stand on one line at 1240 and 800 and on two at 390, where they wrapped
  4. The recipient card (lang/*.php):
  5. _PRBOXFULL, _PRBOXNEAR and _PRBOXROOM drop «получателя»

    • the name of the account stands one line above them in the same card
  6. The forward prefix (lang/*.php):
  7. _PRFWD was the untranslated Fwd in all six locales

    • it becomes «Пересылка», Forwarded, Weitergeleitet, Transfert, Przekazane, «Пересилання»
    • a forwarded subject now reads «Пересылка: …» the way a reply reads «Ответ: …»
  8. Capitals where a string stands alone (lang/*.php):
  9. _PRFREE, _PRSHOWN and _PRNOLIMIT, plus the Polish _PRFOCUSN

    • an outbox holding nothing prints _PRNOLIMIT with no counter before it, so it starts a line
    • the counter prints _PRSHOWN alone whenever no search is running

Benefits:

  • a chip says what it means without being cut or wrapped
  • nothing in the interface is left in an abbreviation only one language reads

Technical notes:

  • values only: no constant is added, renamed or retired, and every placeholder is preserved
  • all six locales carry the same wording in the same change
  • docs/PRIVATE-MESSAGES-2026.md records the pass and the widths it was measured at
Вчера (13.08.2026)
Feature: the mailbox gains a send form that warns before it refuses and a deck of what still waits
Автор: Eduard Laas | Дата: 23:58 13.08.2026

Batches 5 and 6 of docs/PRIVATE-MESSAGES-2026.md finish the two-column mailbox: the compose form answers with a recipient card that grades the mailbox a message would land in, and a focus deck puts the unread of both received folders above the list instead of on page four of one. The same pass corrects a quota that refused sends it had no business refusing and one that refused every send whenever the setting was zero.

Core changes:

  1. Recipient card and the bounded autocomplete (core/system.php, core/helpers.php):
  2. getUserCardData() resolves one exactly matched name and grades the mailbox it would land in

    • the grade folds getPercentTone() into room, nearly full and full, and never shows a number
    • a mailbox no setting bounds is graded none rather than well
  3. getUserList() answers a richer shape behind rich=1 and bounds both branches

    • {items, card} in one round trip, card filled only when the name resolved exactly
    • the rich branch answers 10 and the flat one 50, where it answered 1246 for a single letter
  4. getTplUserSearchInput() takes the card container a field opts in with
  5. Focus deck over the inbox (core/user.php, core/classes/privat.php):
  6. getRecentList() takes an unread argument reading the cabinet badge predicate across both folders
  7. getNewWhere() is that predicate, written once for the badge and the deck instead of twice
  8. getPrivatFocus() builds the deck, which renders over the inbox alone as the demo draws it

    • every slot addresses the inbox and carries the page, the search, the filters and the sort
    • the inbox action set gains unsave, because the deck shows saved messages never read
  9. Forwarding and the compose state (core/user.php, templates/lite/partials/privat-view.html):
  10. the compose view reads id and fwd, loads the source under the reader's own predicate

    • an empty recipient, a localised prefix and the body without the quote wrapper
  11. the compose state names what bounds a send: the interval and the two stored lengths
  12. Quota corrections (core/classes/privat.php):
  13. checkQuota() no longer refuses on the recipient's saved folder

    • an arriving row carries no saved flag, so it can only land in the inbox
    • the saved quota stays enforced in setMessageSaved(), where a message is moved into it
  14. both quota reads test the bound before comparing against it

    • a setting of zero is the absence of a bound, as the outbox, the ring and both alerts read it
    • count >= 0 used to be true forever, so a zero setting refused every send and every save
  15. Out-of-band discipline (core/user.php):
  16. the row travels back only where the caller stands on it, which the list row asks for

    • the deck and the deep link do not, because a swap with no target is an error and not a no-op

Benefits:

  • a full mailbox is visible before the send and not only in the refusal that follows it
  • what is unread is reachable from the top of the list rather than through the pager
  • a suggestion list is bounded, so a large membership cannot answer a page of a database
  • one predicate behind the badge and the deck, so a counter and its cards cannot drift apart

Technical notes:

  • no schema change: setup/sql is untouched and batch 7 is closed on its measurement
  • the flat autocomplete keeps its array shape for the twelve forms that read it, bounded at 50
  • span.html and input.html gain additive keys only; no existing caller renders differently
  • ten strings restyled and _PRFWD translated across de, en, fr, pl, ru and uk
  • PHPStan clean, 819 tests, PHP-CS-Fixer clean; the two quota tests fail against the unfixed code
Feature: the mailbox becomes two columns and the list stops giving up the screen
Автор: Eduard Laas | Дата: 18:06 13.08.2026

The private message page no longer redraws a whole tab for every action. A reader opens a message beside its list instead of in place of it, narrows the mailbox from a toolbar above it, and reads the quota off a ring on each shelf rather than off an alert that fired from half capacity.

Core changes:

  1. Private message subsystem (core/classes/privat.php):
  2. The list answers a selection instead of a whole mailbox

    • getPickWhere() lays the state, period and search conditions over the box predicate
    • one placeholder per column and a declared ESCAPE, because prepares are native here
    • the period binds a number of days, so the boundary is drawn by the server that wrote the row
  3. getBoxFacets() answers every chip number in one aggregate row
  4. getSortOrder() picks from four fixed shapes, each closing on a unique tie-breaker on the id
  5. getUnreadBoxCount(), getBoxLimit() and getBoxFill() answer the shelves and their rings
  6. The list row carries a snippet the server cuts, and getMessageView() answers the same cut
  7. Routes and adapters (core/user.php, modules/account/index.php):
  8. privat() loses the four htmx tabs and reads id, typ and uname
  9. getPrivateMessageView() answers one column: a mailbox, a message or the empty pane
  10. setPrivateMessageRead() answers the reading pane, with the row and the counters out of band
  11. getPrivatPick() reads the selection under fixed names and reduces it to fixed values
  12. getPrivatRowData(), getPrivatShelves() and getPrivatBadges() own the row and the counters
  13. The page number leaves cid and travels as pnum, so cid keeps its two meanings and gains no third
  14. Templates (templates/lite):
  15. partials/privat-page.html, privat-list.html, privat-view.html and fragments/privat-row.html
  16. One swap boundary each: the shell, the left column, the reading pane and a single row
  17. The shelf strip, the toolbar, the filter chips and the shared sl-knob ring
  18. Client behaviour (plugins/system/slaed.js):
  19. The pane switch and the back button of the narrow layout
  20. The reply form filled through the editor API from a hidden carrier textarea
  21. The filter chips, each group holding its value in one hidden field

Benefits:

  • Opening a message keeps the scroll position, the checkbox selection and the editor instance
  • The list, the filtered count and the pager come out of one predicate set inside one answer
  • The shelves and the chip facets answer the mailbox and stay independent of the toolbar
  • One tone ladder serves the quota rings, the server gauges and the debug panel

Technical notes:

  • No schema change and no new route; every state-changing route stays behind POST and the token
  • Row and reading-pane actions send no body at all, so the selection form cannot override them
  • Every new language constant is present in all six locales
  • The search stays a scan of one mailbox: EXPLAIN answers ref on in_box and never a table scan
  • docs/PRIVATE-MESSAGES-2026.md records which batches landed and what was measured
  • docs/UPLOAD-FILEINFO-PLAN-2026.md is an unrelated plan document carried in the same tree
Docs: the private message redesign gets its plan, and its round counters stop sitting off-centre
Автор: Eduard Laas | Дата: 11:10 13.08.2026

The two-column layout demo grows the two shelves it was missing and becomes a specification a fresh session can implement from: every decision it implies is written down next to the code that has to carry it. The counters and flags the layout reuses are fixed in the theme itself, so the fix reaches the cabinet and the mailbox that use them today.

Core changes:

  1. Missing shelves and their contract (demo/private-messages-final-2026.html):
  2. Sections for the saved box and the compose form, both with their own states

    • Saved: its own quota ring, bookmark flags, unsave in the row and in bulk
    • Compose: recipient autocomplete, the card with the recipient quota ring,
the real Toast UI, and all five answers the send route can give
  • A saved message no longer appears in the inbox, because the box predicate excludes it, and the shelf badges split the unread between them

  • The backend contract records what the layout demands: one main swap with addressable out-of-band targets, a snapshot page, the editor filled through its own API, the two-step deep link, and the mobile pane switch

  • Counters and state flags (templates/lite/assets/css/theme.css, templates/lite/fragments/span.html):

  • sl-chip-icon turns a label-less state flag into a round badge, and the fragment emits it only when the flag carries no text, so the chips that do carry a label keep their pill

  • sl-cab-badge and sl-pm-new centre their digit and declare border-box: one digit was sitting against the left padding inside a 32px oval

  • Unread badge (core/user.php):
  • getUserNavItems() caps the counter at 99+, because the badge is a circle on a tile and a four-digit number stretched it across the label

  • Work plan (docs/PRIVATE-MESSAGES-2026.md):
  • Seven batches from the data contracts to the conditional search index, each with its own verification, plus the predicate table every list query must match and the four questions that must be answered before their batch

Benefits:

  • The redesign can start in a new session from one document instead of being re-derived from a demo

  • Every counter in the theme is centred by the same method the chips use
  • Three audit rounds are answered in the plan: native prepares, the flat autocomplete contract, POST-only opening and snapshot parity

Technical notes:

  • No schema change, no new SQL, no route touched
  • The plan defers the search index to its own approved batch, because a BTREE index cannot serve a leading wildcard and FULLTEXT changes search semantics

Эта неделя (12.08.2026)
Docs: private message redesign labs and the layout chosen from them
Автор: Eduard Laas | Дата: 23:24 12.08.2026

Adds design prototypes for the account private-message page: eight distinct approaches, the variant selected from them, and three labs that settle the quota indicator and the filter toolbar. No runtime code, template or stylesheet is touched; every page is a self-contained artefact under demo/.

Core changes:

  1. Eight approaches (private-messages-v1-mailbox.html ... v8-flow.html):
  2. One page per approach: mailbox, split view, dense admin register, cards, messenger, minimal, high-volume and an experimental flow concept

  3. Each page covers inbox, outbox, unread, selected message, sender, subject, date, status, open/reply/delete/mark actions, search, filtering, paging, empty state and a mobile rendering

    • Mobile layouts run on @container, so the phone frames are the real narrow
rendering rather than a picture
  • The message field mounts the actual Toast UI editor from
plugins/editors/toastui instead of a placeholder textarea
  1. Chosen layout (private-messages-final-2026.html):
  2. Two-pane base: the list keeps its place while a message opens beside it
  3. Folder tiles carry an SVG quota ring in place of the text alert; the arc and the icon share one tone

    • Folders without a quota, the outbox and compose, draw a solid ring instead
    • pathLength="100" normalises the arc, so one percent is all a template needs
  4. The filter strip became a control: chips toggle, so a cleared filter can be restored, and read/unread exclude each other

  5. Reading toolbar keeps message actions together and moves navigation aside
  6. Decision labs (private-messages-quota-lab.html, quota-halo.html, toolbar-lab.html):

  7. Thirteen quota indicators, each in three states, all built from mechanics the theme already owns

  8. The refined ring with its thickness, size and cap alternatives
  9. Six filter-toolbar layouts with their trade-offs
  10. Index (private-messages-index.html):
  11. Description, benefits and drawbacks of every variant, a comparison table and links to all pages

  12. Records what the live page revealed and the contract each block would need

Benefits:

  • The layout decision rests on the running site rather than on assumptions
  • Reuse over invention: tables, chips, dial, pager, bulk bar, alerts, progress lines and rings all come from templates/lite

  • Every page states what the backend must supply, so integration can start from a written contract instead of a redrawing round

Technical notes:

  • Demo only: no PHP, template or theme file is modified
  • Extra CSS lives inside each page under its own prefix and never reaches the theme

  • Pages load repository assets only; no CDN and no new dependency
  • The chip set carries no attachment filter: _privat has no such column and a LIKE over the message body would scan the whole table

  • sl-knob exists only in templates/admin; using it on the site would require moving that block into templates/lite first

  • Backward compatible: nothing outside demo/ is affected
Fix: the generation counter leaves the tree it invalidates, and the help says what resets the cache
Автор: Eduard Laas | Дата: 18:25 12.08.2026

The page-cache generation counter lived inside storage/cache/pages, the directory the manual cache clear empties, so the clear reset the counter every stored page is keyed by. It now sits with the other persistent counters in storage/counter, and the clear advances it instead.

Core changes:

  1. Page-cache generation (core/classes/cache.php):
  2. getEpoch() and addEpoch() read and write COUNTER_DIR/cache.log

    • the counter is state, not a cache artifact: deleteAll() and the cache size report no longer reach it
    • the exclusive lock, the single bump per request and the zero on a missing file are unchanged
  3. deleteAll() ends on a bump of its own

    • unlink() reports failure silently, so a page the sweep could not remove has to stay unreachable
    • the directory guard moved into the body, so the bump runs even with no cache tree on disk
  4. Test bootstrap (tests/bootstrap.php):
  5. COUNTER_DIR is defined next to CACHE_DIR and LOGS_DIR, so the harness matches the constants core gives the class
  6. Documentation (docs/PAGE-CACHE-ROUTES-2026.md, admin/info/config/ru.md):
  7. the invalidation section names the counter file and the bump the clear performs
  8. the admin help gains the invalidation rule: admin writes, comment operations, post and vote from the front
  9. the cache structure list gains storage/cache/pages/locks, which appears only under cache_l

Benefits:

  • a cache clear can no longer resurrect a page whose file survived the sweep
  • the counter stops being counted and swept as if it were a cached file
  • the admin panel now explains why the page cache retires itself after an edit

Technical notes:

  • storage: the counter is storage/counter/cache.log; the documented cache clear on upgrade removes the obsolete storage/cache/pages/epoch
  • interface unchanged: getEpoch() and addEpoch() keep their signatures and all twelve call sites
  • backward compatible: an installation without the file reads zero, exactly as before
Fix: the script bundle stops rewriting the code it serves, and the feeds become documents a parser accepts
Автор: Eduard Laas | Дата: 15:39 12.08.2026

The JS minifier rewrote whole files with regular expressions, so it reached inside string literals and turned a subtraction into a decrement, and the bundler glued sources with a space, which let a file ending in a line comment swallow the next one. Both are gone. The RSS and OpenSearch documents carried raw ampersands and a wrong date format, so neither was well formed and every timestamp reported the month in place of the minutes.

Core changes:

  1. Script bundling keeps the sources intact (core/system.php, admin/modules/config.php, config/global.php, admin/lang/*.php):
  2. script_c and getCompressCode() are removed, together with the field, its writer entry and the constant

    • A regular expression cannot tell code from the inside of a string, so the pass rewrote both
    • On top of the transport compression a server applies to scripts it saved six to eight per cent
  3. Sources are concatenated with a semicolon and a line break instead of a space

    • A file ending in a line comment without a trailing break swallowed the first line of the next one
    • A statement left without its own semicolon joined the following file instead of ending
  4. ASSETS_VER becomes 3, because the key covers the sources and the settings but not the code that joins them
  5. Style bundling skips what is already minified (core/system.php):
  6. A file whose name carries .min. is stored as it is

    • The regex pass gains nothing there and costs build time on every rebuild
    • It also stripped the /*! license banner of vendor files, which is not ours to remove
  7. The feeds become well-formed XML (core/user.php):
  8. Every address is escaped before it enters the document, in the channel, the items and the search templates

    • An ampersand of a query string is a character reference in XML, so a strict reader rejected the file
    • The item address is built once per row instead of three times in three branches
  9. The date format is D, j M Y H:i:s O: the minute field held the month
  10. The image element of the OpenSearch document loses a literal backslash n from a single-quoted string
  11. Content-Encoding: none is dropped from both documents, so the server may compress them
  12. Compression covers the pages themselves (.htaccess):
  13. The deflate filter is selected by response type rather than by file name

    • A page is built by index.php, so no rule matching file names reaches the largest response of the site
  14. text/xsl is served with its own type, so a browser applies the sitemap stylesheet
  15. Cache housekeeping (core/system.php, core/classes/cache.php, admin/info/scheduler/ru.md):
  16. The sweep collects asset bundles as well

    • A bundle in use is rewritten on every rebuild, so only one no page points at reaches the retention window
  17. A public response drops the Pragma that PHP emits for every session: a response cannot both invite caching and forbid it

  18. getOutputHtml() loses its unused full mode, which stripped comments and glued tags
  19. Documentation and help (docs/PERFORMANCE.md, docs/PARSER.md, admin/info/*, UPGRADING.md):
  20. The security help states which field names are masked in the request context of a log entry
  21. The upgrade notes list the four cache fields and the action they need, without the history behind them
  22. The scheduler and parser pages describe the current behaviour of the sweep and of the format argument

Benefits:

  • A bundled script is byte for byte the sources it was built from, verified against a parser
  • Feed readers, validators and browser search integration accept the documents
  • Every page of the site is compressed on Apache as it already is on nginx
  • Asset bundles no longer accumulate on disk once their sources change

Technical notes:

  • Breaking: script_c disappears from config/global.php; an installation that had it set needs no action
  • ASSETS_VER = 3 rebuilds every CSS and JS bundle on the first request after the upgrade
  • The feeds keep their element order and their content; only escaping, the date field and the header change
Perf: the parser cache stops storing what it cannot repay, and the cache settings become four honest fields
Автор: Eduard Laas | Дата: 14:17 12.08.2026

The rendered-content cache kept every fragment, so short comments and teasers filled the directory while a daily rewrite cost more than the hits it saved. A size threshold now decides, the sweep that ages the leftovers out is enabled, and the settings screen loses the two fields that described the same decision twice or described nothing. On the way through, request logs stopped carrying the passwords a warning used to record.

Core changes:

  1. A size threshold for the rendered-content cache (core/classes/parser.php):
  2. CACHEMIN is 2048 bytes of source and getCachePath() returns nothing below it

    • The gate sits in the one function both the read and the write pass, so the two stay symmetric
    • The unit is bytes because parsing cost scales with bytes, not with characters
    • The empty-source case is covered by the threshold, so no separate check remains
  3. Break-even is near 700 bytes, but only at some thirty hits a day per fragment; from 2 KB a write repays after three or four hits, which is almost any traffic level

  4. The sweep that removes what already accumulated (config/scheduler.php):
  5. The cachegc job is enabled; it removes files older than max(cache_t * 24, 86400), never below CACHETTL
  6. The threshold stops new sub-threshold files but never removes existing ones: nothing else ages them
  7. Secrets stop reaching the logs (core/classes/logger.php, core/security.php, admin/modules/config.php):
  8. Logger masks request data by key name before it is bounded, in getContext() and only there

    • Any key holding pass, pwd, secret, token, key or code keeps its name and loses its value
    • The diagnostic context of a call is left alone, because it carries keys a name rule would destroy
  9. The address is masked as well, in url and referer: an OAuth callback and a reset link carry their secret in the query string

  10. The flood report names the posted fields instead of dumping them, so a password cannot arrive through the message text either

  11. The hand-written unset() in mailtest() is gone: one rule replaces one special case
  12. Four cache settings instead of six (admin/modules/config.php, config/global.php, core/system.php, index.php):
  13. cache_c and the second minify pass are gone; the stored page is now exactly the page that was served
  14. cache_d is merged into cache_b, which becomes a number of days with 0 for off
  15. Browser caching no longer depends on db_t; the publicly cached response drops the generation-time marker instead, decided where the public headers are actually sent

  16. OpenSearch, XSL and the asset route stop reading a setting: the first two take Cache::STATICDAYS, the third keeps its immutable year

  17. The page identity becomes pc3 and cache_version becomes 4, so no entry written under the old rules can be served and every install rebuilds its merged configuration

  18. The configuration writer stops mangling what it stores (core/system.php, setup/index.php, config/filetype.php):
  19. One value is one line however long it is; a configuration file is data, and the line limit governs code a person writes

    • The line-splitting cut multibyte characters in half, so one save of a localized form produced a
file that was no longer valid UTF-8
  • The installer carried a second copy of the same splitter and would have produced files the panel
does not
  • Line endings are normalized on the way in, because a textarea posts CRLF into a source file of this repository

  • One blind spot of the cache gets a record (core/classes/cache.php):
  • A stored file that exists but cannot be read is written to the file channel once per process

    • The page re-renders and the guard prevents the warning that would otherwise name it
    • One record per process, because a locked append per read would cost more than the fact is worth
  • Documentation and help (docs/PERFORMANCE.md, docs/PARSER.md, admin/info/config/ru.md, admin/info/scheduler/ru.md, UPGRADING.md):
  • The performance guide gains the parser layer it never described, with the threshold and its reason
  • The parser guide loses a cache guard that does not exist: the exclusion is $this->vary in the class
  • The configuration help describes what pages/data really stores, the new field set and the real scope of the caching options, which is the front page and the news list, not every section

  • The scheduler help had the cachegc job as disabled and as a full wipe; it is enabled and removes stale files only

  • docs/PAGE-CACHE-ROUTES-2026.md is the plan for widening the page cache to the other modules

Benefits:

  • The rendered-content directory holds the few documents that are expensive to parse instead of thousands of fragments that never repaid their write

  • A warning raised during a login, a registration or a profile save no longer records the password
  • Two settings fewer to explain, and the stored page can no longer differ from the served one
  • Saving the settings form on a localized installation no longer corrupts config/global.php

Technical notes:

  • Breaking: an installation running cache_b = '1' must set cache_b to its former cache_d, because a bare 1 now means one day. This install runs cache_b = '0' and carries nothing over

  • Breaking: cache_c and cache_d are removed from config/global.php; cache_version = 4 forces every install to rebuild config/local.php on the first request

  • Every stored page becomes unreachable at once through the pc3 prefix; cachegc removes the files
  • The browser-cache branch for HTML stays unreachable in practice while any page carries a CSRF token marker, which makes its entry dynamic and therefore no-store

Эта неделя (11.08.2026)
Style: line endings stop depending on the host, and the retired repair files leave the tree
Автор: Eduard Laas | Дата: 20:54 11.08.2026

Every writer in the project emitted PHP_EOL, so the same code produced CRLF on a Windows host and LF on a Linux one - in JSON log records, in generated PHP files and in the configuration the installer writes. All of them now emit "\n", and CRLF is produced only where a protocol requires it. The two hand-repair SQL files are gone with everything that referenced them.

Core changes:

  1. Log writers emit LF (core/classes/logger.php, admin/modules/database.php, core/security.php, core/system.php):
  2. The JSONL record terminator of all six channels, database.log, log.log and days.log

    • A record separator that depends on the host makes one machine format two ways
    • The reader was already tolerant, splitting on any break, so no stored log breaks
  3. Generated files emit LF (setup/index.php, admin/modules/lang.php, admin/modules/editor.php, admin/modules/blocks.php):
  4. The installer carried its own copy of setConfigFile() and wrote the same config files with CRLF

    • A configuration file therefore ended up mixed, depending on whether the installer or the panel touched it last
  5. Language files, block files, editor templates and robots.txt follow the same rule
  6. The block generator loses the hardcoded CRLF around its heredoc marker, which also removes a parser risk
  7. The admin IP filter stops missing a break (admin/modules/security.php):
  8. strtr() stripped PHP_EOL and therefore missed a lone LF on Linux and a lone CR on Windows
  9. It now strips CR, LF and space, so the stored list cannot carry a stray break on either host
  10. Mail bodies and assembled text emit LF (core/classes/mail.php, core/security.php, admin/modules/*, modules/help):
  11. The SMTP transport already normalises a body to CRLF before the dialogue, so that boundary is the only place CRLF belongs
  12. The retired repair files leave the tree (setup/sql/, docs/VERSIONS.md, tests/):
  13. update6_3_patch.sql and update6_3_text_once.sql are gone, and nothing references them any more
  14. The upgrade matrix drops to two rows, the hand-patch section and its recount route are removed
  15. The splitter scenario moves onto the shipped upgrade channel instead of the deleted file
  16. The privat probe drives one channel, and its expectation follows

Benefits:

  • A log, a generated file and a configuration read the same on every host the project runs on
  • One rule instead of a per-call-site choice: LF inside the application, CRLF only at the protocol boundary
  • The suite covers seven scenarios that were silently skipping on the missing files

Technical notes:

  • Existing logs stay mixed; old CRLF records are still read, because the reader splits on any break
  • A raw editor file written by the previous code on Windows shows its guard prefix once, and the first save repairs it
  • No schema change, no route contract change, and no compatibility layer for the removed files

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

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

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