Point the five procedural prelude files at the new source-of-truth classes,
keeping them on disk as thin shims because the boot paths require_once them by
name and legacy code reads their globals/constants directly.
- Paths.php / AppConfig.php / Binaries.php -> ConstantsInitializer::init()
- ErrorCodes.php -> bridges ErrorResponder::codes() into $GLOBALS['rErrorCodes']
- ErrorHandler.php -> generateError()/generate404() shims (function_exists
guarded) delegating to ErrorResponder; production still exit()s, so the ~139
call sites are untouched.
Register ErrorHandler.php in composer autoload.files so the functions exist even
on paths that do not require the prelude; regenerate the production-only vendor
autoload accordingly.
The path/app-config constants are no longer literal define()s PHPStan can scan,
so add the four it previously learned from them but that were missing from the
stub (GIT_REPO_FANOUT, FANOUT_{RUN_PATH,CTL_SOCK,HTTP_SOCK}).
Debug/404 output stays byte-identical to the legacy functions (golden tests);
full suite, PHPStan, phpcs and make gates all green.
The front controller selected a pair of procedural files per scope
(<scope>_session.php + <scope>_functions.php) from a hardcoded map and
require'd them at global scope. Consolidate into a typed class hierarchy:
- ScopeBootstrap (interface) + ScopeBootstrapFactory::create($scope)
- Admin/Reseller/PlayerScopeBootstrap, each porting its former session +
functions logic 1:1 into boot()/bootSession()/bootFunctions().
index.php now calls ScopeBootstrapFactory::create($scope)->boot() instead
of building file paths and require'ing. Unknown scopes still fall back to
admin.
Behaviour is unchanged: the view-facing globals ($rUserInfo, $rPermissions,
$_STATUS, $customScript, $_PAGE, server/health flags) are still injected via
explicit `global` declarations in the boot methods, so the ~140 procedural
view templates read them from scope exactly as before. player_utility_-
functions.php is unchanged and still loaded by PlayerScopeBootstrap.
Also fix the PHPStan stub: SERVER_ID is an int (getMainID(): ?int, a
server_id PK), not a string. Moving its define() into a class method meant
PHPStan no longer inferred the type from a top-level define and fell back to
the stub, which wrongly typed it `(string) mt_rand()` — surfacing 20
false argument.type errors at int-param call sites. Stub now uses mt_rand().
Removes: admin_session_fc.php, admin_functions_fc.php, reseller_session.php,
reseller_functions.php, player_session.php, player_functions.php.
make phpstan / cs / gates all green.
gen-constants-stub.php had no Makefile/CI target, so tools/phpstan/
constants.stub.php (a bootstrapFile in phpstan.dist.neon) silently drifted:
regenerating it added DB_ACCESS_PWD and GIT_REPO_PROXY (real runtime define()s
in src/Core/Config/AppConfig.php that PHPStan could not see). Added `make
phpstan-stub` so the stub is regenerable/discoverable, and refreshed it
(129 -> 131 constants).
- constants stub: use mt_rand()-based exprs so PHPStan infers GENERAL types,
not literal 0/'' — fixes false division-by-zero (PACKET_SIZE) and
foreach-over-false (str_split with len 0). Load stub via bootstrapFiles so
result-cache invalidates on change.
- return contracts: explicit returns where a path fell through to null and
violated the declared type:
- StreamRepository::getById/getWatchFolder, GroupService::getById,
getStream() → return false (declared array|false).
- ServerRepository::getPublicURL → return '' when server missing (array→string).
- MagService::resetSTB → return query() result (declared bool).
- StreamUtils::getPlaylistSegments → explicit return null.
- NetworkUtils::stopDownload → @return null corrected to @return void.
- PlexController: getPlexToken() called with 5 args but accepts 4 — dropped
the dead 5th argument.
- DropboxClient::getMetaFromHeaders: array_shift() on an array_filter()
expression (not a variable, by-ref error) — assign to a var first.
- WatchdogCommand: wrap numeric-string subtractions (nginx/proc-stat values)
in floatval()/intval().