Fixes an intermittent session_start() failure caused by three independent issues in core/security.php that together prevented reliable output buffering.
Core changes:
- Bootstrap output buffering (core/security.php):
Remove UTF-8 BOM that was emitting 3 bytes before <?php on every cold request, committing HTTP headers before session_start() could set its cookie
Move ob_start() to line 10 — before getConfig(), setLang(), and DB connection — so any PHP notices/warnings from bootstrap are also buffered
- Remove duplicate ob_start() block that was placed after all bootstrap ops
- Legacy cleanup (core/security.php):
Remove '# Murder variables' unset() block — dead code from register_globals era (PHP 4.x); register_globals was removed in PHP 5.4 (2012); all listed variables are either function-scoped or assigned immediately after
Benefits: - session_start() no longer fails with 'headers already sent' - Bootstrap is clean and deterministic regardless of OPcache state - Dead code removed: 3 lines of unset() with zero security value in PHP 8.4
Technical notes: - output_buffering = 0 in OSPanel php.ini confirmed — ob_start() in security is the only buffer; must be first executable line after FUNC_FILE check - BOM removal applied via binary file_put_contents; no content change
After setLang() was introduced as the sole bootstrap initializer for \$locale, two categories of dead code emerged and are now removed.
Core changes:
- admin/index.php — two global declarations:
getAdminPanelBlocks(): remove \$locale from global list * Was needed for require_once \$path.'/language/'.\$locale.'.php' * Now replaced by getLang(\$name, true) which reads \$locale internally
getAdminPanel(): remove \$locale from global list * Same reason as above
- core/user.php — two no-op calls removed:
rss_channel(): remove getLang() * setLang() in bootstrap already loaded language/{\$locale}.php * _CHARSET constant is available before rss_channel() is ever called
open_search(): remove getLang() * Same reason — \$locale and all main constants set at bootstrap
Benefits: - global declarations reflect actual dependencies (no phantom imports) - No dead function calls in the hot path of rss and opensearch endpoints
Extracts locale determination and main file loading into a dedicated setLang(): void called once per request from bootstrap. getLang() now only loads module language files and returns \$locale — locale detection code no longer runs on every module getLang() call.
Core changes:
- setLang() (new, core/security.php):
- Determines active \$locale from config, \$_REQUEST, cookie
- Loads main language/\{locale\}.php with fallback to \$mlang
- Sets language cookie when locale changes
- void return — init function, called once in bootstrap
- getLang() (simplified, core/security.php):
- Removes locale detection block (moved to setLang)
- Removes static \$mload flag — no longer needed
- Guards: if (\$module === '') return \$locale; — no-op for bare calls
- Only responsibility: load module language file + return locale
- Bootstrap (core/security.php:26):
- getLang() → setLang()
Benefits: - Locale detection runs exactly once per request (was N times) - getCookies() / getVar() called once instead of per getLang() call - getLang() responsibility is now single: load module file - set/get verb split matches coding-standards §3: set=side-effect init, get=return value — previously get was doing set work (cookie, locale) - \$mload static removed — setLang() handles main file, require_once deduplicates
Technical notes: - All existing getLang(\$name) / getLang(\$name, true) call sites unchanged - getLang() bare calls in user.php (rss_channel, open_search) return \$locale — no-op, harmless - \$locale global is set by setLang() before any module code executes
Leftover uncommitted fixes from previous refactoring session.
Core changes:
- changelog/admin/index.php:
Extract exec() call into gitexec() wrapper with safety guards * Validates function exists, rejects control chars, checks 'git log' presence
- Change rencom(array, array) to rencom(array) — \$conf accessed via global
Fix config key refs: \$conf['showstat'] → \$conf['changelog']['showstat'], \$conf['showfile'] → \$conf['changelog']['showfile']
- Add missing \$conf to global declarations in changelog() and conf()
- rss/admin/index.php:
- Add \$conf to global declarations in rss() and save()
- voting/admin/index.php:
- Add \$conf to global declaration in conf()
- auto_links/admin/index.php:
- Remove redundant inline comment on safe SQL concatenation
Benefits: - exec() now wrapped in a safety-checked helper — reduces attack surface - Config access uses correct \$conf['changelog'] sub-key path
All call sites migrated to getLang(). The temporary get_lang() shim added during staged rollout is removed from core/security.php. All occurrences of the old function name are now gone from the codebase (exception: 'get_lang' string literal in filemanager plugin switch-case, which is unrelated to the language loader).
Core changes:
- core/user.php — 6 call sites:
- navi() line 74: get_lang('account') → getLang('account')
- navi() line 88: get_lang('clients') → getLang('clients')
- navi() line 95: get_lang('shop') → getLang('shop')
- navi() line 109: get_lang('help') → getLang('help')
- rss_channel() line 713: get_lang() → getLang()
- open_search() line 824: get_lang() → getLang()
- core/security.php:
- Remove get_lang() backward-compat shim (3 lines)
Benefits: - Codebase fully migrated to getLang() — single consistent API - Dead shim code eliminated - Refactoring CSV entry: get_lang,getLang,get,Lang,string,rename+extend
Technical notes: - plugins/filemanager/ajax_calls.php uses 'get_lang' as a string constant in a switch-case — not a function call, not modified
Bootstrap in index.php now calls getLang(\$name) before require_once for every module. The explicit getLang(\$conf['name']) on line 9-12 of each module file is therefore redundant and removed.
Core changes:
- 23 frontend modules — each modules/*/index.php:
Remove get_lang(\$conf['name']); line * account, auto_links, changelog, clients, contact, content, faq,
files, forum, help, jokes, links, media, money, news, order,
pages, recommend, rss, search, shop, users, whois
Benefits: - Modules no longer responsible for their own language bootstrapping - Reduces per-module boilerplate by one line - New modules work out of the box without extra setup
Technical notes: - modules/main, voting, sitemap had no getLang() call — untouched - No functional change: getLang() static cache makes double-call a no-op
Moves module language loading from individual modules into the bootstrap (index.php), so any module gets its language file automatically without needing an explicit getLang() call inside the module file itself. Replaces three direct require_once language file statements in admin/index.php with getLang(\$name, true), adding locale-fallback that was previously missing.
Core changes:
- index.php — frontend module bootstrap:
Add getLang(\$name) before require_once in all 4 module load branches * view=0 (public), view=1 (user/group), view=2 (moder), home-module branch
- Replace get_lang('shop') → getLang('shop') in \$go==2 AJAX branch
- Replace get_lang('admin') → getLang('admin') in \$go==5 AJAX branch
- admin/index.php — admin panel:
- Replace get_lang('admin') → getLang('admin') on bootstrap line
Replace 3x direct require_once language file with getLang(\$name, true) * getAdminPanelBlocks() panel-off branch (line 60) * getAdminPanel() panel-on branch (line 111) * module dispatch block (line 238) * All three now benefit from locale-fallback to \$mlang when locale file missing
Benefits: - New modules auto-receive language file without boilerplate getLang() call - Admin module language loading gains locale-fallback (was missing before) - Consistent load pattern: bootstrap always owns language lifecycle
Technical notes: - getLang() static cache is idempotent — double call from bootstrap + module is safe - \$locale global is set by getLang() before require_once executes
Renames get_lang() to getLang() following camelCase naming convention (coding-standards.md §4). Extends the function with a bool \$admin parameter that routes to modules/{module}/admin/language/ when true, making the loader universal for frontend, admin-panel and module-admin contexts. Removes the obsolete commented-out legacy function block (# OLD DELETE, 47 lines).
Core changes:
- getLang() (core/security.php):
Rename get_lang() → getLang() — camelCase per project standard * Signature: getLang(string \$module = '', bool \$admin = false): string
Add bool \$admin parameter for module-admin language path routing * getLang('news', true) → modules/news/admin/language/{locale}.php
Update \$lmods cache key to module|ctx|locale (ctx = 'a'|'f') * Prevents cache collision between frontend and admin contexts
Rename internal vars: \$candidates → \$list, \$loaded → \$done, \$fallback → \$fall * Aligns with 4-8 char rule (coding-standards.md §6)
- Remove # OLD DELETE block (legacy commented-out get_lang, lines 868–914)
- Bootstrap call (core/security.php:26):
- get_lang() → getLang()
Benefits: - Single universal function covers all three language-load contexts - Eliminates direct require_once language file scattered across admin/index.php - Consistent naming with getVar(), getAdminTabs(), getTheme() etc.
Technical notes: - \$lmods static cache remains: prevents redundant is_readable() per request - require_once PHP-level deduplication still prevents double file inclusion - filemanager plugin uses 'get_lang' as a string literal — unrelated, untouched
Standardises all public-facing module controllers: converts tab indentation to 4-space (recommend, users), corrects copyright header encoding and year (2021/2022 → 2026) across modules that were outdated, shortens verbose loop variables to concise local names, and adds defensive directory handling in main/index.php to prevent warnings when the screenshots directory is absent.
Core changes:
- main/index.php:
- Fix copyright year 2022 → 2026 and encoding © → ©
Wrap opendir() in is_dir() + false check before loop * Prevents PHP warning when uploads/screens/thumb is missing
- Guard shuffle() call with if ($screens) to skip empty arrays
- Add closedir() inside the safe branch
- recommend/index.php:
- Convert tabs to 4-space indentation throughout
- Fix copyright year 2021 → 2026
- users/index.php:
- Convert tabs to 4-space indentation
- Rename verbose loop variables ($user_id → $uid, etc.)
account, faq, forum, help, jokes, links, media, money, news, order, pages, shop, whois, search, files, clients, changelog, auto_links, content, contact, sitemap, rss/index.php:
- Rename DB-prefixed destructured vars to short local names
- Normalise copyright encoding/year where broken (© → ©)
- CRLF → LF line-ending normalisation on Windows-edited files
Benefits: - Consistent 4-space indentation across all frontend controllers - Correct copyright year in all module headers (2026) - No PHP warnings when optional directories are absent - Shorter variable names reduce line width in dense row-rendering loops
Technical notes: - No logic changes beyond the defensive is_dir() guard in main - CRLF → LF applied automatically by git on staging - Encoding fixes are cosmetic; runtime behaviour unchanged
Renames verbose DB-prefixed loop variables (user_id, ip_sender, user_name, ad_view, etc.) to concise local names ($uid, $ip, $nick, $view) across all admin module controllers. Migrates pagination config from deprecated $confu global to $conf['users'] sub-array in account admin. Removes unused $confu and $confn imports from global declarations.
Core changes:
- account/admin/index.php:
Rename $psearch → $search, $cnt_params → $pars in navi() * Avoids shadowing the search variable read later
Shorten all 26 $user_* destructured vars to single-word names * $user_id → $uid, $user_name → $name, $user_email → $mail, etc.
Replace $confu['anum'] / $confu['anump'] with $conf['users'][...] * Removes dependency on $confu global in account() and add()
- Remove $confn and $confu from global declarations in add()
- news/admin/index.php:
- Rename $ip_sender → $ip, $user_name → $nick, $ad_view → $view
- Inline $assoc_arr to $associated in save()
- Remove unused $confu from global declaration
media, money, links, shop, sitemap, whois, voting, files, faq, forum, help, jokes, pages, order, clients, changelog, auto_links, content, rss, contact/admin/index.php:
- Rename verbose loop/result variables to short local names
- Remove unused global imports ($confu, $confn where applicable)
Benefits: - Shorter destructuring lines fit within 120-char line limit - Eliminates $confu dependency in admin layer (uses $conf['users']) - Consistent naming style across all admin controllers
Technical notes: - No logic changes; purely cosmetic variable renames - $conf['users'] sub-array must exist (set by config loader) - CRLF → LF normalisation applied by git on staging





