Basic Information
The release-2.1 branch has multiple PHP 8.5 incompatibilities that need to be addressed. PHP 8.5 promotes several deprecations from PHP 8.1–8.4 to errors/removals, and the current codebase — originally targeting PHP 7.0 — is affected in numerous places. The CI workflow (.github/workflows/php.yml) only lints syntax up to PHP 8.4 and does not run any runtime tests, so these issues are not currently caught.
This issue consolidates all known and discoverable PHP 8.5 incompatibilities into a single tracking issue with exact code references.
1. trigger_error() with E_USER_ERROR (deprecated PHP 8.4, error in 8.5)
PHP 8.4 deprecated passing E_USER_ERROR to trigger_error(). In PHP 8.5, this will throw a ValueError. SMF's database error backtrace function passes E_USER_ERROR through from callers and also directly invokes trigger_error() with it.
Related issue: #9141 (open, in 2.1.8 milestone — but only covers the DB layer)
1a. Sources/Subs-Db-mysql.php — smf_db_error_backtrace()
|
function smf_db_error_backtrace($error_message, $log_message = '', $error_type = false, $file = null, $line = null) |
|
{ |
|
if (empty($log_message)) |
|
$log_message = $error_message; |
|
|
|
foreach (debug_backtrace() as $step) |
|
{ |
|
// Found it? |
|
if (strpos($step['function'], 'query') === false && !in_array(substr($step['function'], 0, 7), array('smf_db_', 'preg_re', 'db_erro', 'call_us')) && strpos($step['function'], '__') !== 0) |
|
{ |
|
$log_message .= '<br>Function: ' . $step['function']; |
|
break; |
|
} |
|
|
|
if (isset($step['line'])) |
|
{ |
|
$file = $step['file']; |
|
$line = $step['line']; |
|
} |
|
} |
|
|
|
// A special case - we want the file and line numbers for debugging. |
|
if ($error_type == 'return') |
|
return array($file, $line); |
|
|
|
// Is always a critical error. |
|
if (function_exists('log_error')) |
|
log_error($log_message, 'critical', $file, $line); |
|
|
|
if (function_exists('fatal_error')) |
|
{ |
|
fatal_error($error_message, false); |
|
|
|
// Cannot continue... |
|
exit; |
|
} |
|
elseif ($error_type) |
|
trigger_error($error_message . ($line !== null ? '<em>(' . basename($file) . '-' . $line . ')</em>' : ''), $error_type); |
|
else |
|
trigger_error($error_message . ($line !== null ? '<em>(' . basename($file) . '-' . $line . ')</em>' : '')); |
|
} |
The function accepts $error_type and passes it directly to trigger_error() on lines 913–915. Every caller that passes E_USER_ERROR triggers the deprecation:
- Line 195 —
smf_db_error_backtrace('Invalid value inserted...', '', E_USER_ERROR, ...)
- Line 209 — Integer type check failure
- Line 222 — Empty array_int
- Line 227 — Non-integer in array_int
- Line 235 — Non-array for array_int
- Line 243 — Empty array_string
- Line 251 — Non-array for array_string
- Line 258 — Invalid date
- Line 265 — Invalid time
- Line 274 ��� Invalid datetime
- Line 279 — Invalid float
- Line 296 — Invalid IPv4/IPv6
- Line 304 — Empty array_inet
- Line 311 — Invalid inet value
- Line 318 — Non-array for array_inet
|
smf_db_error_backtrace('Invalid value inserted or no type specified.', '', E_USER_ERROR, __FILE__, __LINE__); |
|
|
|
if ($matches[1] === 'literal') |
|
return '\'' . mysqli_real_escape_string($connection, $matches[2]) . '\''; |
|
|
|
if (!isset($values[$matches[2]])) |
|
smf_db_error_backtrace('The database value you\'re trying to insert does not exist: ' . (isset($smcFunc['htmlspecialchars']) ? $smcFunc['htmlspecialchars']($matches[2]) : htmlspecialchars($matches[2])), '', E_USER_ERROR, __FILE__, __LINE__); |
|
|
|
$replacement = $values[$matches[2]]; |
|
|
|
switch ($matches[1]) |
|
{ |
|
case 'int': |
|
if (!is_numeric($replacement) || (string) $replacement !== (string) (int) $replacement) |
|
smf_db_error_backtrace('Wrong value type sent to the database. Integer expected. (' . $matches[2] . ')', '', E_USER_ERROR, __FILE__, __LINE__); |
|
return (string) (int) $replacement; |
|
break; |
|
|
|
case 'string': |
|
case 'text': |
|
return sprintf('\'%1$s\'', mysqli_real_escape_string($connection, isset($smcFunc['fix_utf8mb4']) ? $smcFunc['fix_utf8mb4']($replacement) : $replacement)); |
|
break; |
|
|
|
case 'array_int': |
|
if (is_array($replacement)) |
|
{ |
|
if (empty($replacement)) |
|
smf_db_error_backtrace('Database error, given array of integer values is empty. (' . $matches[2] . ')', '', E_USER_ERROR, __FILE__, __LINE__); |
|
|
|
foreach ($replacement as $key => $value) |
|
{ |
|
if (!is_numeric($value) || (string) $value !== (string) (int) $value) |
|
smf_db_error_backtrace('Wrong value type sent to the database. Array of integers expected. (' . $matches[2] . ')', '', E_USER_ERROR, __FILE__, __LINE__); |
|
|
|
$replacement[$key] = (string) (int) $value; |
|
} |
|
|
|
return implode(', ', $replacement); |
|
} |
|
else |
|
smf_db_error_backtrace('Wrong value type sent to the database. Array of integers expected. (' . $matches[2] . ')', '', E_USER_ERROR, __FILE__, __LINE__); |
|
|
|
break; |
|
|
|
case 'array_string': |
|
if (is_array($replacement)) |
|
{ |
|
if (empty($replacement)) |
|
smf_db_error_backtrace('Database error, given array of string values is empty. (' . $matches[2] . ')', '', E_USER_ERROR, __FILE__, __LINE__); |
|
|
|
foreach ($replacement as $key => $value) |
|
$replacement[$key] = sprintf('\'%1$s\'', mysqli_real_escape_string($connection, isset($smcFunc['fix_utf8mb4']) ? $smcFunc['fix_utf8mb4']($value) : $value)); |
|
|
|
return implode(', ', $replacement); |
|
} |
|
else |
|
smf_db_error_backtrace('Wrong value type sent to the database. Array of strings expected. (' . $matches[2] . ')', '', E_USER_ERROR, __FILE__, __LINE__); |
|
break; |
|
|
|
case 'date': |
|
if (preg_match('~^(\d{4})-([0-1]?\d)-([0-3]?\d)$~', $replacement, $date_matches) === 1) |
|
return sprintf('\'%04d-%02d-%02d\'', $date_matches[1], $date_matches[2], $date_matches[3]); |
|
else |
|
smf_db_error_backtrace('Wrong value type sent to the database. Date expected. (' . $matches[2] . ')', '', E_USER_ERROR, __FILE__, __LINE__); |
|
break; |
|
|
|
case 'time': |
|
if (preg_match('~^([0-1]?\d|2[0-3]):([0-5]\d):([0-5]\d)$~', $replacement, $time_matches) === 1) |
|
return sprintf('\'%02d:%02d:%02d\'', $time_matches[1], $time_matches[2], $time_matches[3]); |
|
else |
|
smf_db_error_backtrace('Wrong value type sent to the database. Time expected. (' . $matches[2] . ')', '', E_USER_ERROR, __FILE__, __LINE__); |
|
break; |
|
|
|
case 'datetime': |
|
if (preg_match('~^(\d{4})-([0-1]?\d)-([0-3]?\d) ([0-1]?\d|2[0-3]):([0-5]\d):([0-5]\d)$~', $replacement, $datetime_matches) === 1) |
|
return 'str_to_date(' . |
|
sprintf('\'%04d-%02d-%02d %02d:%02d:%02d\'', $datetime_matches[1], $datetime_matches[2], $datetime_matches[3], $datetime_matches[4], $datetime_matches[5], $datetime_matches[6]) . |
|
',\'%Y-%m-%d %h:%i:%s\')'; |
|
else |
|
smf_db_error_backtrace('Wrong value type sent to the database. Datetime expected. (' . $matches[2] . ')', '', E_USER_ERROR, __FILE__, __LINE__); |
|
break; |
|
|
|
case 'float': |
|
if (!is_numeric($replacement)) |
|
smf_db_error_backtrace('Wrong value type sent to the database. Floating point number expected. (' . $matches[2] . ')', '', E_USER_ERROR, __FILE__, __LINE__); |
|
return (string) (float) $replacement; |
|
break; |
|
|
|
case 'identifier': |
|
// Backticks inside identifiers are supported as of MySQL 4.1. We don't need them for SMF. |
|
return '`' . implode('`.`', array_filter(explode('.', strtr($replacement, array('`' => ''))), 'strlen')) . '`'; |
|
break; |
|
|
|
case 'raw': |
|
return $replacement; |
|
break; |
|
|
|
case 'inet': |
|
if ($replacement == 'null' || $replacement == '') |
|
return 'null'; |
|
if (!isValidIP($replacement)) |
|
smf_db_error_backtrace('Wrong value type sent to the database. IPv4 or IPv6 expected.(' . $matches[2] . ')', '', E_USER_ERROR, __FILE__, __LINE__); |
|
//we don't use the native support of mysql > 5.6.2 |
|
return sprintf('unhex(\'%1$s\')', bin2hex(inet_pton($replacement))); |
|
|
|
case 'array_inet': |
|
if (is_array($replacement)) |
|
{ |
|
if (empty($replacement)) |
|
smf_db_error_backtrace('Database error, given array of IPv4 or IPv6 values is empty. (' . $matches[2] . ')', '', E_USER_ERROR, __FILE__, __LINE__); |
|
|
|
foreach ($replacement as $key => $value) |
|
{ |
|
if ($replacement == 'null' || $replacement == '') |
|
$replacement[$key] = 'null'; |
|
if (!isValidIP($value)) |
|
smf_db_error_backtrace('Wrong value type sent to the database. IPv4 or IPv6 expected.(' . $matches[2] . ')', '', E_USER_ERROR, __FILE__, __LINE__); |
|
$replacement[$key] = sprintf('unhex(\'%1$s\')', bin2hex(inet_pton($value))); |
|
} |
|
|
|
return implode(', ', $replacement); |
|
} |
|
else |
|
smf_db_error_backtrace('Wrong value type sent to the database. Array of IPv4 or IPv6 expected. (' . $matches[2] . ')', '', E_USER_ERROR, __FILE__, __LINE__); |
1b. Sources/Subs-Compat.php — disabled function polyfill uses eval() + trigger_error()
|
if (version_compare(PHP_VERSION, '8.0.0', '>=')) |
|
{ |
|
/* |
|
* This array contains function names that meet the following conditions: |
|
* |
|
* 1. SMF assumes they are defined, even if disabled. Note that prior to |
|
* PHP 8, this was always true for internal functions. |
|
* |
|
* 2. Some hosts are known to disable them. |
|
* |
|
* 3. SMF can get by without them (as opposed to missing functions that |
|
* really SHOULD cause execution to halt). |
|
*/ |
|
foreach (array('set_time_limit') as $func) |
|
{ |
|
if (!function_exists($func)) |
|
eval('function ' . $func . '() { trigger_error("' . $func . '() has been disabled for security reasons", E_USER_WARNING); }'); |
|
} |
|
unset($func); |
|
} |
Line 558 creates a polyfill via eval() that calls trigger_error() with E_USER_WARNING — this one is fine, but the overall pattern of using trigger_error() for fatal errors throughout the codebase is the concern.
Fix: Replace all trigger_error($msg, E_USER_ERROR) calls with a proper exception or fatal_error() call. The smf_db_error_backtrace() function already has a fatal_error() path — the trigger_error() fallback on line 913 needs to use E_USER_WARNING or throw an exception instead of E_USER_ERROR.
2. mysqli_ping() deprecated (PHP 8.4, removal expected in future)
mysqli_ping() was deprecated in PHP 8.4 and emits a deprecation warning.
|
'db_ping' => 'mysqli_ping', |
'db_ping' => 'mysqli_ping',
This maps $smcFunc['db_ping'] directly to the deprecated mysqli_ping function. Any code calling $smcFunc['db_ping']() will trigger deprecation warnings on PHP 8.4 and may fail on PHP 8.5+.
Fix: Replace with a wrapper that executes a lightweight query (e.g., SELECT 1) or uses mysqli_query() to test the connection.
3. SessionHandler return type declarations / #[\ReturnTypeWillChange]
The release-2.1 branch uses a custom session handler class that implements SessionHandlerInterface. Based on the version header comments (e.g., "When 8.1 is the minimum, this can be removed"), these methods use #[\ReturnTypeWillChange] to suppress return type warnings.
In PHP 8.5, #[\ReturnTypeWillChange] may no longer suppress warnings, and the missing return type declarations will generate deprecation notices or errors.
The affected methods that need proper return types are:
| Method |
Required Return Type |
open() |
bool |
close() |
bool |
read() |
string|false |
write() |
bool |
destroy() |
bool |
gc() |
int|false |
Fix: Add proper return type declarations to all SessionHandlerInterface methods and remove the #[\ReturnTypeWillChange] attributes. This is safe because SMF 2.1 already requires PHP 7.0+ and return types can be conditionally handled.
4. Passing null to non-nullable parameters of internal functions
PHP 8.1 deprecated passing null to non-nullable string parameters of internal functions. PHP 8.5 promotes these to TypeErrors. The release-2.1 codebase, written for PHP 7.0, does not guard against null in many places.
Related issue: #9173 (strtr() receiving array — open, not in any milestone)
4a. Sources/Subs-Db-mysql.php line 285 — strlen as callback to array_filter
|
return '`' . implode('`.`', array_filter(explode('.', strtr($replacement, array('`' => ''))), 'strlen')) . '`'; |
return '`' . implode('`.`', array_filter(explode('.', strtr($replacement, array('`' => ''))), 'strlen')) . '`';
If $replacement is null, strtr() will throw a TypeError in PHP 8.5. Additionally, 'strlen' as a callback to array_filter() will throw a TypeError if any element is null.
4b. Widespread $_SERVER / $_REQUEST / $modSettings values passed directly to string functions
Throughout the codebase, values from superglobals and $modSettings are passed directly to functions like strpos(), strlen(), strtolower(), htmlspecialchars(), trim(), strtr(), substr(), explode(), str_replace(), preg_match(), preg_replace(), urlencode(), rawurlencode(), md5(), sha1(), etc. — all of which require non-null string arguments in PHP 8.5.
Key high-traffic files that need auditing for null-to-string-function calls:
Sources/Load.php — loading settings, user info, themes
Sources/Subs.php — general utility functions
Sources/QueryString.php — URL/request parsing (directly handles $_GET, $_POST, $_REQUEST)
Sources/Security.php — security checks
Sources/LogInOut.php — authentication
Sources/Subs-Db-mysql.php — database layer
Sources/Subs-Compat.php — compatibility functions
Example pattern that breaks:
// If $modSettings['some_key'] is not set, it's null, and strlen(null) is a TypeError in 8.5
if (strlen($modSettings['some_key']) > 0)
Fix: Add null coalescing (?? '' or ?? 0) before passing potentially null values to internal functions, or add explicit null checks. A codebase-wide audit using static analysis (e.g., PHPStan level 6+) is strongly recommended.
5. Implicit nullable parameter types (deprecated PHP 8.4)
Since PHP 8.4, function signatures like function foo(string $bar = null) generate a deprecation warning. The correct form is function foo(?string $bar = null).
5a. Sources/Subs-Db-mysql.php — multiple functions
|
function smf_db_insert_id($table, $field = null, $connection = null) |
function smf_db_insert_id($table, $field = null, $connection = null)
The $field and $connection parameters default to null but have no type declarations. While this specific case is untyped (and thus unaffected), any typed parameters with = null defaults need the ? nullable prefix. A full audit of all function signatures is needed.
5b. Sources/Subs-Compat.php — mb_ord() and mb_chr() polyfills
|
function mb_ord($string, $encoding = null) |
|
function mb_chr($codepoint, $encoding = null) |
function mb_ord($string, $encoding = null)
function mb_chr($codepoint, $encoding = null)
These are polyfills only defined when the native functions don't exist, so they are unlikely to be active on PHP 8.5 (which ships mbstring). However, any similar patterns elsewhere in the codebase with explicit type hints will break.
Fix: Search the entire codebase for the regex pattern function\s+\w+\s*\([^)]*\b\w+\s+\$\w+\s*=\s*null and ensure all typed parameters with = null use ?type syntax.
6. CI/CD does not test PHP 8.5
https://github.com/SimpleMachines/SMF/blob/7438c2b04807bca3b3160801a3d40fd2f0f0ca7b/.github/workflows/php.yml
The GitHub Actions workflow only runs phplint against PHP 7.1–8.4. This is syntax checking only — it will not catch:
- Runtime deprecations promoted to errors
- Type errors from null coercion
- Behavioral changes in internal functions
Fix:
- Add PHP
8.5 to the lint matrix.
- Ideally, add a runtime test suite (even minimal smoke tests) that exercises key code paths under PHP 8.5.
Summary of required changes
| # |
Issue |
Severity on 8.5 |
Files affected |
| 1 |
trigger_error(E_USER_ERROR) |
🔴 ValueError |
Subs-Db-mysql.php (15+ call sites) |
| 2 |
mysqli_ping() deprecated |
🟡 Deprecation warning |
Subs-Db-mysql.php (line 61) |
| 3 |
Session handler missing return types |
🟡 Deprecation / potential error |
Session.php (6 methods) |
| 4 |
null to internal string functions |
🔴 TypeError |
Codebase-wide (Load.php, Subs.php, QueryString.php, Security.php, Subs-Db-mysql.php, etc.) |
| 5 |
Implicit nullable types |
🟡 Deprecation warning |
Any typed parameters with = null |
| 6 |
CI doesn't cover PHP 8.5 |
🟠 No safety net |
.github/workflows/php.yml |
Recommended approach
- Run PHPStan or Psalm at level 6+ against the
release-2.1 branch with PHP 8.5 as the target to surface all null coercion and type issues systematically.
- Fix the
trigger_error(E_USER_ERROR) calls first — these are guaranteed ValueErrors.
- Replace
mysqli_ping with a query-based connection check.
- Add return types to the session handler.
- Add PHP 8.5 to CI.
Version/Git revision
release-2.1 (2.1.7, commit 7438c2b)
Database Engine
All
PHP Version
8.5
Additional Information
Several related issues already exist but are fragmented and incomplete:
None of these individually address the full scope of PHP 8.5 incompatibility. This issue is intended to serve as a comprehensive tracker.
This is an anonymous contribution made via gitGost.
The original author's identity has been anonymized to protect their privacy.
Basic Information
The
release-2.1branch has multiple PHP 8.5 incompatibilities that need to be addressed. PHP 8.5 promotes several deprecations from PHP 8.1–8.4 to errors/removals, and the current codebase — originally targeting PHP 7.0 — is affected in numerous places. The CI workflow (.github/workflows/php.yml) only lints syntax up to PHP 8.4 and does not run any runtime tests, so these issues are not currently caught.This issue consolidates all known and discoverable PHP 8.5 incompatibilities into a single tracking issue with exact code references.
1.
trigger_error()withE_USER_ERROR(deprecated PHP 8.4, error in 8.5)PHP 8.4 deprecated passing
E_USER_ERRORtotrigger_error(). In PHP 8.5, this will throw aValueError. SMF's database error backtrace function passesE_USER_ERRORthrough from callers and also directly invokestrigger_error()with it.Related issue: #9141 (open, in 2.1.8 milestone — but only covers the DB layer)
1a.
Sources/Subs-Db-mysql.php—smf_db_error_backtrace()SMF/Sources/Subs-Db-mysql.php
Lines 876 to 916 in 7438c2b
The function accepts
$error_typeand passes it directly totrigger_error()on lines 913–915. Every caller that passesE_USER_ERRORtriggers the deprecation:smf_db_error_backtrace('Invalid value inserted...', '', E_USER_ERROR, ...)SMF/Sources/Subs-Db-mysql.php
Lines 195 to 318 in 7438c2b
1b.
Sources/Subs-Compat.php— disabled function polyfill useseval()+trigger_error()SMF/Sources/Subs-Compat.php
Lines 542 to 561 in 7438c2b
Line 558 creates a polyfill via
eval()that callstrigger_error()withE_USER_WARNING— this one is fine, but the overall pattern of usingtrigger_error()for fatal errors throughout the codebase is the concern.Fix: Replace all
trigger_error($msg, E_USER_ERROR)calls with a proper exception orfatal_error()call. Thesmf_db_error_backtrace()function already has afatal_error()path — thetrigger_error()fallback on line 913 needs to useE_USER_WARNINGor throw an exception instead ofE_USER_ERROR.2.
mysqli_ping()deprecated (PHP 8.4, removal expected in future)mysqli_ping()was deprecated in PHP 8.4 and emits a deprecation warning.SMF/Sources/Subs-Db-mysql.php
Line 61 in 7438c2b
This maps
$smcFunc['db_ping']directly to the deprecatedmysqli_pingfunction. Any code calling$smcFunc['db_ping']()will trigger deprecation warnings on PHP 8.4 and may fail on PHP 8.5+.Fix: Replace with a wrapper that executes a lightweight query (e.g.,
SELECT 1) or usesmysqli_query()to test the connection.3.
SessionHandlerreturn type declarations /#[\ReturnTypeWillChange]The
release-2.1branch uses a custom session handler class that implementsSessionHandlerInterface. Based on the version header comments (e.g., "When 8.1 is the minimum, this can be removed"), these methods use#[\ReturnTypeWillChange]to suppress return type warnings.In PHP 8.5,
#[\ReturnTypeWillChange]may no longer suppress warnings, and the missing return type declarations will generate deprecation notices or errors.The affected methods that need proper return types are:
open()boolclose()boolread()string|falsewrite()booldestroy()boolgc()int|falseFix: Add proper return type declarations to all
SessionHandlerInterfacemethods and remove the#[\ReturnTypeWillChange]attributes. This is safe because SMF 2.1 already requires PHP 7.0+ and return types can be conditionally handled.4. Passing
nullto non-nullable parameters of internal functionsPHP 8.1 deprecated passing
nullto non-nullable string parameters of internal functions. PHP 8.5 promotes these toTypeErrors. Therelease-2.1codebase, written for PHP 7.0, does not guard againstnullin many places.Related issue: #9173 (
strtr()receiving array — open, not in any milestone)4a.
Sources/Subs-Db-mysql.phpline 285 —strlenas callback toarray_filterSMF/Sources/Subs-Db-mysql.php
Line 285 in 7438c2b
If
$replacementisnull,strtr()will throw aTypeErrorin PHP 8.5. Additionally,'strlen'as a callback toarray_filter()will throw aTypeErrorif any element isnull.4b. Widespread
$_SERVER/$_REQUEST/$modSettingsvalues passed directly to string functionsThroughout the codebase, values from superglobals and
$modSettingsare passed directly to functions likestrpos(),strlen(),strtolower(),htmlspecialchars(),trim(),strtr(),substr(),explode(),str_replace(),preg_match(),preg_replace(),urlencode(),rawurlencode(),md5(),sha1(), etc. — all of which require non-null string arguments in PHP 8.5.Key high-traffic files that need auditing for null-to-string-function calls:
Sources/Load.php— loading settings, user info, themesSources/Subs.php— general utility functionsSources/QueryString.php— URL/request parsing (directly handles$_GET,$_POST,$_REQUEST)Sources/Security.php— security checksSources/LogInOut.php— authenticationSources/Subs-Db-mysql.php— database layerSources/Subs-Compat.php— compatibility functionsExample pattern that breaks:
Fix: Add null coalescing (
?? ''or?? 0) before passing potentially null values to internal functions, or add explicit null checks. A codebase-wide audit using static analysis (e.g., PHPStan level 6+) is strongly recommended.5. Implicit nullable parameter types (deprecated PHP 8.4)
Since PHP 8.4, function signatures like
function foo(string $bar = null)generate a deprecation warning. The correct form isfunction foo(?string $bar = null).5a.
Sources/Subs-Db-mysql.php— multiple functionsSMF/Sources/Subs-Db-mysql.php
Line 497 in 7438c2b
The
$fieldand$connectionparameters default tonullbut have no type declarations. While this specific case is untyped (and thus unaffected), any typed parameters with= nulldefaults need the?nullable prefix. A full audit of all function signatures is needed.5b.
Sources/Subs-Compat.php—mb_ord()andmb_chr()polyfillsSMF/Sources/Subs-Compat.php
Line 197 in 7438c2b
SMF/Sources/Subs-Compat.php
Line 310 in 7438c2b
These are polyfills only defined when the native functions don't exist, so they are unlikely to be active on PHP 8.5 (which ships mbstring). However, any similar patterns elsewhere in the codebase with explicit type hints will break.
Fix: Search the entire codebase for the regex pattern
function\s+\w+\s*\([^)]*\b\w+\s+\$\w+\s*=\s*nulland ensure all typed parameters with= nulluse?typesyntax.6. CI/CD does not test PHP 8.5
https://github.com/SimpleMachines/SMF/blob/7438c2b04807bca3b3160801a3d40fd2f0f0ca7b/.github/workflows/php.yml
The GitHub Actions workflow only runs
phplintagainst PHP 7.1–8.4. This is syntax checking only — it will not catch:Fix:
8.5to the lint matrix.Summary of required changes
trigger_error(E_USER_ERROR)ValueErrorSubs-Db-mysql.php(15+ call sites)mysqli_ping()deprecatedSubs-Db-mysql.php(line 61)Session.php(6 methods)nullto internal string functionsTypeErrorLoad.php,Subs.php,QueryString.php,Security.php,Subs-Db-mysql.php, etc.)= null.github/workflows/php.ymlRecommended approach
release-2.1branch with PHP 8.5 as the target to surface all null coercion and type issues systematically.trigger_error(E_USER_ERROR)calls first — these are guaranteedValueErrors.mysqli_pingwith a query-based connection check.Version/Git revision
release-2.1 (2.1.7, commit 7438c2b)
Database Engine
All
PHP Version
8.5
Additional Information
Several related issues already exist but are fragmented and incomplete:
E_USER_ERRORintrigger_error()(open, 2.1.8 milestone) — covers only the DB layerstrtr()argument type error (open, no milestone)Cannot use bool as array(closed/fixed)None of these individually address the full scope of PHP 8.5 incompatibility. This issue is intended to serve as a comprehensive tracker.
This is an anonymous contribution made via gitGost.
The original author's identity has been anonymized to protect their privacy.