Resolve six distinct runtime errors surfaced in error_php.log and error_sql.log, all caused by PHP 8.4 strict type enforcement or missing null-guards on global variables.
Core changes:
- sport_referer INSERT (core/system.php):
- Column names refer/page → referer/link to match DB schema
- num_ajax() signature (core/system.php, core/user.php):
- Argument #10 \$id: int → string (DOM element name)
- Argument #11 \$cid / \$mnum: "" → 0 / 8 at all call sites
- Sitemap path fix (core/system.php):
doSitemap() still wrote to config/sitemap/ while SITEMAP_DIR points to storage/sitemap/ — unified all three path references
- Upload widget null-guards (core/system.php):
- \$user[0] → \$user[0] ?? 0 (admin has no user cookie)
- \$con[10] / \$con[11] → ?? 0 (short upload configs lack keys 10-11)
- checkemail() return type (core/system.php):
return \$stop → return \$stop ?? [] when no errors found (valid bot emails caused TypeError: must return array, null returned)
Benefits: - Eliminates all entries from error_sql.log and error_php.log - Consistent null-safe access on \$user and \$con arrays
Technical notes: - \$user is populated from cookie via explode(':'); absent in admin context - \$con comes from explode('|', uploads config string); length varies by module
Replace the legacy adm_info() function with getAdminInfo(), which auto-detects the info file path from the current request context (\$_GET['name']) instead of requiring explicit path parameters. Restructures admin/info/ from flat {name}-{locale}.html files into {name}/{locale}.html subdirectories.
Core changes:
- Function rename and rewrite (core/admin.php):
- New signature: getAdminInfo(): string (no parameters)
- Auto-detects module path: modules/{name}/admin/info/{locale}.html
- Auto-detects admin path: admin/info/{name}/{locale}.html
- AJAX save handler: POST type= + name= instead of mod= + name=
- \$obj parameter removed; callers use echo getAdminInfo() explicitly
- AJAX routing (index.php):
- case 'adm_info': adm_info() → echo getAdminInfo()
- Call sites — 23 admin modules (admin/modules/*.php):
- adm_info(1, 0, 'name') → getAdminInfo()
- Call sites — 23 module admins (modules/*/admin/index.php):
- adm_info(1, 'mod', 0) → getAdminInfo()
- Info file structure (admin/info/):
- Renamed {name}-{locale}.html → {name}/{locale}.html (subdirs)
- Added .htaccess + index.html per directory
Benefits: - Zero path parameters — function resolves location automatically - Consistent with SLAED get-prefix naming convention - Admin and module admins use identical call syntax
Technical notes: - Old flat-file format (admins-de.html) was already broken: code read wrong paths while files had already moved to subdirectories - getcat() call in admin.php fixed: "" → 0 for int \$id parameter
Fix mojibake in copyright headers (© → (c)) caused by UTF-8 double-encoding in source files. Remove corrupted Russian comments from forum module. Standardize indentation (tabs → 4-space) in access.php. Translate Russian doc-comments in ConfigValidationTest to English per project language rules.
Core changes:
Copyright encoding fix (admin/index.php, admin/modules/*, templates/admin/index.php, modules/changelog/admin/index.php, modules/whois/index.php):
- Replace garbled © with plain (c) in file headers
- Add missing newline at end of files
- Indentation normalization (core/access.php):
- Convert tab indentation to 4-space throughout the file
- No functional changes
- Dead code removal (modules/forum/index.php):
- Remove 5 Mojibake Russian comments that became unreadable garbled UTF-8
- Comments were orphaned annotations with no semantic value
- Array syntax modernization (modules/clients/index.php):
- array() constructor calls → short [] syntax
- Remove trailing blank line at EOF
- Test comment translation (tests/ConfigValidationTest.php):
- Translate PHPDoc comments and assertion messages from Russian to English
- Aligns with project rule: all code/comments/identifiers must be in English
Benefits: - Consistent file headers across all PHP files in the project - Readable source without mojibake artifacts - Uniform indentation style in core files
Technical notes: - No logic changes in any file — purely cosmetic/encoding fixes - core/admin.php included for CRLF → LF normalization (no content change)
Resolves three classes of runtime bugs: (1) HTML content mangled by parser when rendered via content/view module, (2) empty template file treated as missing template (TypeError cascade), (3) stash tokens leaking into rendered output due to single-pass resolution.
Core changes:
- filterMarkdown param reorder (core/system.php):
Signature: filterMarkdown(string $src, string $mod = '', bool $safe = true) * $safe is now an explicit opt-out (false) for admin/legacy content * bb_decode() updated: filterMarkdown($src, $mod, false)
- HTML passthrough fixes for safe=false mode (core/system.php):
filterMain: skip filterIndentedCode when safe=false — prevents tab-indented HTML lines being wrapped in <pre><code> blocks
filterBlocks: widen HTML block pattern from specific tag list to /^<\/?[a-zA-Z]/ so <p>, <tr>, <td> etc. are recognized as HTML blocks
filterBlocks: decode "/' entities before stashing HTML blocks (save_text(editor=0) encodes quotes as HTML entities)
filterBlocks: strtr($raw, $this->stash) before re-stashing — resolves inner BB-block tokens that were already stashed inside HTML blocks
- Multi-pass stash resolution (core/system.php):
filterHtml: single strtr → loop until no \x02{salt}: sentinel remains * Prevents stash tokens leaking when [tabs] BB block contains HTML blocks * Loop breaks on no-progress to avoid infinite loop
- Return type normalization (core/system.php):
- getThemeLoad(): ?string → string; returns '' for missing/unreadable files
replace_break/user_sinfo/user_sainfo/adminblock/add_menu/rss_read/ fields_out/engines_word: ?string → string with return '' fallback
- Template existence check (core/template.php):
setTemplateBasic/setTemplateWarning: use getThemeFile() for existence, then getThemeLoad() for content — distinguishes empty template from missing
- TemplateTest.php stubs updated to match new signatures
- content/view migration (modules/content/index.php):
Replace bb_decode() with filterMarkdown($hometext, $conf['name'], false) * Render admin HTML content correctly without XSS filtering
- Remove deprecated imagedestroy() calls (core/system.php):
- GdImage is a proper PHP object since 8.0; GC handles cleanup automatically
Benefits: - HTML content stored by admin now renders correctly in content/view - Empty theme templates (open.html etc.) no longer trigger "template missing" error - Stash tokens no longer appear in rendered page output - PHP 8.4 return type compliance across parser and template functions
Technical notes: - safe=false bypasses XSS filters — only use for admin-authored content - Multi-pass stash is O(depth) iterations, bounded by nesting depth - Cyrillic transliteration maps migrated to \u{XXXX} escapes for encoding safety
Replace ?string nullable returns with explicit string + return '' fallback to prevent TypeError when callers assume a string result. Covers save_text(), fields_save(), setMessageShow(), and userblock(). Also removes 35 unused $confXX transition aliases and dead commented log_report() code from security.php.
Core changes:
- Return type fixes (core/security.php):
save_text(): ?string → string; adds return '' when $text is falsy * Prevents TypeError in replace_break() at system.php:4793
- fields_save(): ?string → string; adds return '' when $field is not array
- Return type fixes (core/user.php):
- setMessageShow(): ?string → string; adds return '' at end of function
- userblock(): ?string → string; adds return '' when user has no block set
- Dead code removal (core/security.php):
- Remove 35 $confXX transition aliases — all confirmed unused after migration
- Remove commented-out log_report() legacy implementation
Benefits: - Eliminates runtime TypeError when save_text() result passed to replace_break() - PHP 8.4 strict typing compliance — no implicit null returns from typed functions - Cleaner security.php — removes ~60 lines of dead code
Technical notes: - Aliases were safety-net globals from $conf migration; all callers now use $conf['key'] directly - No functional change to return values — empty string is the correct semantic fallback
Uniform cleanup pass across all frontend and admin module files to align with the PHP 8.4 migration already applied to core.
Core changes:
- Admin modules — function renames (24 files):
head() → setHead(), foot() → setFoot() across all admin entry points * account, auto_links, changelog, clients, contact, content, faq * files, forum, help, jokes, links, media, money, news, order * pages, rss, shop, sitemap, voting, whois
- Indentation normalisation (all 39 files):
- Tabs replaced with 4-space indentation (PSR-12 style)
- Trailing blank lines removed from switch/case blocks
- clients/index.php — additional refactoring:
- systems() renamed to clients(); save_hidden() renamed to hidden()
- All internal call sites updated accordingly
- status column removed from SELECT (was fetched but never used)
- global $conf removed from download() and generator() (unused)
- Mojibake in $output substitution table fixed (© § Ц № Ў etc.)
- Mojibake in Russian comments decoded to proper UTF-8 Cyrillic
- Minor improvements in individual modules:
- changelog/index.php: $retcode initialised before by-ref use
- faq/index.php: intermediate $ncat variable eliminated
- news/index.php: spacing normalisation in type-hint default value
Benefits: - Consistent code style across all module files - Dead globals and unused SELECT columns removed - Broken substitution table in clients module corrected
Technical notes: - No behaviour changes in admin modules; rename-only - clients/index.php mojibake fix corrects runtime substitution values
Largest core file (5 800+ lines) fully migrated to PHP 8.4 standards: type declarations on all 103+ functions, array-syntax modernisation, mojibake elimination, and error-suppression removal.
Core changes:
- Type declarations (103+ functions):
Return types added across all public functions * void, never, string, ?string, int, bool, ?bool, array, array|false * int|string (is_bot, from_bot), mixed for heterogeneous params
- render_blocks(): void → ?string — function returns string in cases 'p'/'o'
- getBlocks(): return render_blocks() split to call + return (void compliance)
- isArray(): ?bool → bool; logic simplified to always return bool
- Array syntax (65 single-line conversions + 3 manual fixes):
- array() → [] everywhere except string literals
- Multi-line stream_context_create([...]) fixed manually
- Nested array() inside already-converted [...] on engine line fixed
- Mojibake elimination (runtime + comments):
- 6 em-dash occurrences (triple-encoded U+2014 → —)
- Cyrillic HTML transliteration table (lines 4815-4817) restored: А–Я
- 17 Russian comment lines translated to English
- Error suppression removal:
- @mkdir → mkdir (result already checked with if)
- @fopen → fopen (result already checked with if)
Benefits: - Complete type coverage enables reliable static analysis - Runtime mojibake in transliteration table eliminated - All error paths now explicit, no silent suppression
Technical notes: - No behaviour changes; refactor-only - Dead code mb_strtolower polyfill (PHP 8.4 built-in) left untouched
Migrate three core bootstrap files to PHP 8.4 standards: add return-type declarations to all functions, modernize array syntax, remove error suppression and update copyright year.
Core changes:
- Type declarations (access.php, security.php, user.php):
Add return type hints to all functions * setUnauthorized(): never, setExit(): never, getIp(): string * checkSecurity(): void, checkBot(): void, getBotList(): array * setLang(): void, getLang(): string, getusrinfo(): array|false * checklogin(): void, getAgent(): string, and more
- Syntax modernisation (all three files):
- array() constructors → short [] syntax throughout
- Remove @ error-suppression operators where result is already checked
- Housekeeping:
- Copyright year updated to 2026 (mojibake © → ©)
- Remaining Russian inline comments translated to English
Benefits: - Static analysis can now verify return types across call sites - Eliminates silent failures from suppressed errors - Consistent modern PHP 8.4 syntax
Technical notes: - No behaviour changes; refactor-only - setUnauthorized() and setExit() typed never — both call exit
Systematically replaces all legacy \$confXX alias references with direct \$conf['section']['key'] access across admin modules, core, blocks, and module files as part of the centralized config architecture migration.
Core changes:
- Admin modules (admin/modules/*.php — 20 files):
Replace \$confu, \$confn, \$confst, \$confr, \$confpr, \$conffo etc. with direct \$conf['users'], \$conf['news'], \$conf['statistic'] etc. access
- Remove now-unused alias variables from global declarations
- Core files (core/admin.php, core/access.php, core/template.php, core/classes/pdo.php):
- Migrate remaining \$confXX references to \$conf['section'] pattern
- Align with getConfig() unified config architecture
- Blocks and templates (blocks/.php, templates//.php):
- \$confu, \$conffav, \$confal, \$confv references replaced with direct access
- Module admin and frontend (modules/*/admin/index.php, modules/shop/index.php):
- \$confXX aliases replaced; global declarations trimmed accordingly
- Supporting files (index.php, setup/index.php, phpstan-bootstrap.php):
- Remaining alias usages updated to direct \$conf path
Benefits: - Single source of truth: all config reads go through \$conf loaded by getConfig() - Eliminates transition alias block dependencies; aliases can be removed incrementally - Reduces global variable pollution in functions
Technical notes: - Transition alias block in security.php retained for remaining consumers; individual aliases removed as their last usage is migrated - No behavior change: \$conf['key'] values are identical to former \$confXX aliases
Removes redundant config file re-inclusion in sitemap functions and fixes a variable name regression introduced during the $confXX → $conf migration.
Core changes:
- Sitemap config access (core/system.php):
doSitemap(): replace include('config/sitemap.php') + \$confma extraction with direct \$conf['sitemap']['key'] — config already loaded by getConfig()
- setHead(): same fix — removes duplicate filesystem read on every page load
- All \$confma['...'] references replaced with \$conf['sitemap']['...']
- \$sitemap_data intermediate variable eliminated
- Bug fix (core/user.php):
favorliste(): \$a = (\$num) ? ... used undefined \$num after renaming to \$cid during config migration; fixed to \$a = (\$cid) ? \$offset + 1 : 1
Benefits: - Eliminates one file_get_contents / include per sitemap check per request - No stale intermediate variable; config path is uniform across codebase - Pagination counter in favorliste() now correctly reflects current page
Technical notes: - \$confma transition alias in security.php is now fully unused; safe to remove - \$conf['sitemap'] is populated by getConfig() from config/sitemap.php return value





