array( min, max|null ), arg => array( position => spec ). * * @package hexloom-php-version-scan */ defined( 'ABSPATH' ) || exit; /** * Rule definitions. */ final class Hxpc_Rules { /** * All rules, id => definition. * * @return array */ public static function all(): array { $m83d = 'https://www.php.net/manual/en/migration83.deprecated.php#migration83.deprecated.'; $m83i = 'https://www.php.net/manual/en/migration83.incompatible.php#migration83.incompatible.'; $m84d = 'https://www.php.net/manual/en/migration84.deprecated.php#migration84.deprecated.'; $m84i = 'https://www.php.net/manual/en/migration84.incompatible.php#migration84.incompatible.'; $m85d = 'https://www.php.net/manual/en/migration85.deprecated.php#migration85.deprecated.'; $m85i = 'https://www.php.net/manual/en/migration85.incompatible.php#migration85.incompatible.'; $mysqli_refresh = array( 'MYSQLI_REFRESH_GRANT', 'MYSQLI_REFRESH_LOG', 'MYSQLI_REFRESH_TABLES', 'MYSQLI_REFRESH_HOSTS', 'MYSQLI_REFRESH_STATUS', 'MYSQLI_REFRESH_THREADS', 'MYSQLI_REFRESH_REPLICA', 'MYSQLI_REFRESH_SLAVE', 'MYSQLI_REFRESH_MASTER', 'MYSQLI_REFRESH_BACKUP_LOG', 'MYSQLI_STORE_RESULT_COPY_DATA' ); $mhash = array( 'MHASH_CRC32', 'MHASH_MD5', 'MHASH_SHA1', 'MHASH_HAVAL256', 'MHASH_RIPEMD160', 'MHASH_TIGER', 'MHASH_GOST', 'MHASH_CRC32B', 'MHASH_HAVAL224', 'MHASH_HAVAL192', 'MHASH_HAVAL160', 'MHASH_HAVAL128', 'MHASH_TIGER128', 'MHASH_TIGER160', 'MHASH_MD4', 'MHASH_SHA256', 'MHASH_ADLER32', 'MHASH_SHA224', 'MHASH_SHA512', 'MHASH_SHA384', 'MHASH_WHIRLPOOL', 'MHASH_RIPEMD128', 'MHASH_RIPEMD256', 'MHASH_RIPEMD320', 'MHASH_SNEFRU256', 'MHASH_MD2', 'MHASH_FNV132', 'MHASH_FNV1A32', 'MHASH_FNV164', 'MHASH_FNV1A64', 'MHASH_JOAAT', 'MHASH_CRC32C', 'MHASH_MURMUR3A', 'MHASH_MURMUR3C', 'MHASH_MURMUR3F', 'MHASH_XXH32', 'MHASH_XXH64', 'MHASH_XXH3', 'MHASH_XXH128' ); $pdo = array( 'DBLIB_ATTR_CONNECTION_TIMEOUT', 'DBLIB_ATTR_QUERY_TIMEOUT', 'DBLIB_ATTR_STRINGIFY_UNIQUEIDENTIFIER', 'DBLIB_ATTR_VERSION', 'DBLIB_ATTR_TDS_VERSION', 'DBLIB_ATTR_SKIP_EMPTY_ROWSETS', 'DBLIB_ATTR_DATETIME_CONVERT', 'FB_ATTR_DATE_FORMAT', 'FB_ATTR_TIME_FORMAT', 'FB_ATTR_TIMESTAMP_FORMAT', 'MYSQL_ATTR_USE_BUFFERED_QUERY', 'MYSQL_ATTR_LOCAL_INFILE', 'MYSQL_ATTR_LOCAL_INFILE_DIRECTORY', 'MYSQL_ATTR_INIT_COMMAND', 'MYSQL_ATTR_MAX_BUFFER_SIZE', 'MYSQL_ATTR_READ_DEFAULT_FILE', 'MYSQL_ATTR_READ_DEFAULT_GROUP', 'MYSQL_ATTR_COMPRESS', 'MYSQL_ATTR_DIRECT_QUERY', 'MYSQL_ATTR_FOUND_ROWS', 'MYSQL_ATTR_IGNORE_SPACE', 'MYSQL_ATTR_SSL_KEY', 'MYSQL_ATTR_SSL_CERT', 'MYSQL_ATTR_SSL_CA', 'MYSQL_ATTR_SSL_CAPATH', 'MYSQL_ATTR_SSL_CIPHER', 'MYSQL_ATTR_SSL_VERIFY_SERVER_CERT', 'MYSQL_ATTR_SERVER_PUBLIC_KEY', 'MYSQL_ATTR_MULTI_STATEMENTS', 'ODBC_ATTR_USE_CURSOR_LIBRARY', 'ODBC_ATTR_ASSUME_UTF8', 'ODBC_SQL_USE_IF_NEEDED', 'ODBC_SQL_USE_DRIVER', 'ODBC_SQL_USE_ODBC', 'PGSQL_ATTR_DISABLE_PREPARES', 'SQLITE_ATTR_EXTENDED_RESULT_CODES', 'SQLITE_ATTR_OPEN_FLAGS', 'SQLITE_ATTR_READONLY_STATEMENT', 'SQLITE_DETERMINISTIC', 'SQLITE_OPEN_READONLY', 'SQLITE_OPEN_READWRITE', 'SQLITE_OPEN_CREATE', 'PGSQL_TRANSACTION_IDLE', 'PGSQL_TRANSACTION_ACTIVE', 'PGSQL_TRANSACTION_INTRANS', 'PGSQL_TRANSACTION_INERROR', 'PGSQL_TRANSACTION_UNKNOWN' ); $imap = array( 'imap_open', 'imap_reopen', 'imap_close', 'imap_is_open', 'imap_num_msg', 'imap_num_recent', 'imap_headers', 'imap_headerinfo', 'imap_rfc822_parse_headers', 'imap_rfc822_write_address', 'imap_rfc822_parse_adrlist', 'imap_body', 'imap_fetchtext', 'imap_bodystruct', 'imap_fetchbody', 'imap_fetchmime', 'imap_savebody', 'imap_fetchheader', 'imap_fetchstructure', 'imap_gc', 'imap_expunge', 'imap_delete', 'imap_undelete', 'imap_check', 'imap_listscan', 'imap_scan', 'imap_scanmailbox', 'imap_mail_copy', 'imap_mail_move', 'imap_mail_compose', 'imap_createmailbox', 'imap_create', 'imap_renamemailbox', 'imap_rename', 'imap_deletemailbox', 'imap_subscribe', 'imap_unsubscribe', 'imap_append', 'imap_ping', 'imap_base64', 'imap_qprint', 'imap_8bit', 'imap_binary', 'imap_utf8', 'imap_status', 'imap_mailboxmsginfo', 'imap_setflag_full', 'imap_clearflag_full', 'imap_sort', 'imap_uid', 'imap_msgno', 'imap_list', 'imap_listmailbox', 'imap_lsub', 'imap_listsubscribed', 'imap_getsubscribed', 'imap_getmailboxes', 'imap_fetch_overview', 'imap_alerts', 'imap_errors', 'imap_last_error', 'imap_search', 'imap_utf7_decode', 'imap_utf7_encode', 'imap_utf8_to_mutf7', 'imap_mutf7_to_utf8', 'imap_mime_header_decode', 'imap_thread', 'imap_timeout', 'imap_get_quota', 'imap_get_quotaroot', 'imap_set_quota', 'imap_setacl', 'imap_getacl', 'imap_mail' ); return array( // PHP 8.3. 'php83-get-class-no-args' => array( 'since' => '8.3', 'level' => 'deprecated', 'title' => 'get_class() without arguments', 'what' => '{name}() is called without an argument.', 'fix' => 'Pass the object, for example get_class( $this ), or use self::class, static::class or parent::class.', 'doc' => $m83d . 'core.get-class', 'trigger' => array( 'func' => array( 'get_class', 'get_parent_class' ), 'when' => array( array( 'argc' => array( 0, 0 ) ) ), ), ), 'php83-assert-options' => array( 'since' => '8.3', 'level' => 'deprecated', 'title' => 'assert_options() function', 'what' => 'Calls assert_options().', 'fix' => 'Stop calling assert_options(). Use the zend.assertions and assert.exception settings in php.ini.', 'doc' => $m83d . 'standard', 'trigger' => array( 'func' => array( 'assert_options' ) ), ), 'php83-assert-constants' => array( 'since' => '8.3', 'level' => 'deprecated', 'title' => 'ASSERT_* constants', 'what' => 'Uses the constant {name}.', 'fix' => 'Remove it together with the assert_options() call. Use zend.assertions in php.ini.', 'doc' => $m83d . 'standard', 'trigger' => array( 'const' => array( 'ASSERT_ACTIVE', 'ASSERT_BAIL', 'ASSERT_CALLBACK', 'ASSERT_EXCEPTION', 'ASSERT_WARNING' ) ), ), 'php83-assert-ini' => array( 'since' => '8.3', 'level' => 'deprecated', 'title' => 'Changing an assert.* setting', 'what' => 'ini_set() changes {name}.', 'fix' => 'Do not change assert.* settings at run time. Use zend.assertions in php.ini.', 'doc' => $m83d . 'standard', 'trigger' => array( 'ini' => array( 'assert.active' => array( 'bool_ne' => array( true ) ), 'assert.bail' => array( 'bool_ne' => array( false ) ), 'assert.callback' => array( 'ne' => array( '' ) ), 'assert.exception' => array( 'bool_ne' => array( true ) ), 'assert.warning' => array( 'bool_ne' => array( true ) ), ), ), ), 'php83-numberformatter-type-currency' => array( 'since' => '8.3', 'level' => 'deprecated', 'title' => 'NumberFormatter::TYPE_CURRENCY', 'what' => 'Uses the constant NumberFormatter::TYPE_CURRENCY.', 'fix' => 'Format currency with NumberFormatter::CURRENCY and format(), or use formatCurrency().', 'doc' => $m83d . 'intl', 'trigger' => array( 'cconst' => array( 'NumberFormatter' => array( 'TYPE_CURRENCY' ) ) ), ), 'php83-u-multiple-decimal-seperators' => array( 'since' => '8.3', 'level' => 'deprecated', 'title' => 'U_MULTIPLE_DECIMAL_SEPERATORS constant', 'what' => 'Uses the misspelled constant U_MULTIPLE_DECIMAL_SEPERATORS.', 'fix' => 'Use U_MULTIPLE_DECIMAL_SEPARATORS.', 'doc' => $m83d . 'intl', 'trigger' => array( 'const' => array( 'U_MULTIPLE_DECIMAL_SEPERATORS' ) ), ), 'php83-mt-rand-php' => array( 'since' => '8.3', 'level' => 'deprecated', 'title' => 'MT_RAND_PHP mode', 'what' => 'Uses the constant MT_RAND_PHP.', 'fix' => 'Use the default Mt19937 mode: call mt_srand( $seed ) without MT_RAND_PHP.', 'doc' => $m83d . 'random', 'trigger' => array( 'const' => array( 'MT_RAND_PHP' ) ), ), 'php83-ziparchive-fl-recompress' => array( 'since' => '8.3', 'level' => 'deprecated', 'title' => 'ZipArchive::FL_RECOMPRESS', 'what' => 'Uses the constant ZipArchive::FL_RECOMPRESS.', 'fix' => 'Remove the flag. libzip will drop it in a future version.', 'doc' => $m83d . 'zip', 'trigger' => array( 'cconst' => array( 'ZipArchive' => array( 'FL_RECOMPRESS' ) ) ), ), 'php83-ldap-connect-port' => array( 'since' => '8.3', 'level' => 'deprecated', 'title' => 'ldap_connect() with a separate port', 'what' => 'ldap_connect() is called with a host and a port.', 'fix' => 'Pass one URI instead, for example ldap_connect( "ldap://host:389" ).', 'doc' => $m83d . 'ldap', 'trigger' => array( 'func' => array( 'ldap_connect' ), 'when' => array( array( 'argc' => array( 2, null ) ) ), ), ), 'php83-mb-strimwidth-negative' => array( 'since' => '8.3', 'level' => 'deprecated', 'title' => 'mb_strimwidth() with a negative width', 'what' => 'mb_strimwidth() is called with a negative width.', 'fix' => 'Pass a width of zero or more, or compute the width before the call.', 'doc' => $m83d . 'mbstring', 'trigger' => array( 'func' => array( 'mb_strimwidth' ), 'when' => array( array( 'arg' => array( 3 => array( 'neg' => true ) ) ) ), ), ), 'php83-file-append-flag' => array( 'since' => '8.3', 'level' => 'removed', 'title' => 'file() with FILE_APPEND', 'what' => 'file() is called with the FILE_APPEND flag and throws a ValueError.', 'fix' => 'Remove FILE_APPEND from the flags. file() only reads; use file_put_contents() to append.', 'doc' => $m83i . 'standard', 'trigger' => array( 'func' => array( 'file' ), 'when' => array( array( 'arg' => array( 2 => array( 'has_const' => array( 'FILE_APPEND' ) ) ) ) ), ), ), 'php83-imagerotate-4-args' => array( 'since' => '8.3', 'level' => 'removed', 'title' => 'imagerotate() with four arguments', 'what' => 'imagerotate() is called with four arguments and throws an ArgumentCountError.', 'fix' => 'Remove the fourth argument ($ignore_transparent). It has had no effect since PHP 7.', 'doc' => 'https://www.php.net/manual/en/migration83.other-changes.php#migration83.other-changes.functions.gd', 'trigger' => array( 'func' => array( 'imagerotate' ), 'when' => array( array( 'argc' => array( 4, null ) ) ), ), ), 'php83-opcache-consistency-checks' => array( 'since' => '8.3', 'level' => 'removed', 'title' => 'opcache.consistency_checks setting', 'what' => '{name}() uses opcache.consistency_checks, which PHP 8.3 removed.', 'fix' => 'Remove the call. The setting no longer exists, so ini_get() returns false.', 'doc' => $m83i . 'opcache', 'trigger' => array( 'func' => array( 'ini_get', 'ini_set', 'ini_alter', 'ini_restore' ), 'when' => array( array( 'arg' => array( 1 => array( 'str' => array( 'opcache.consistency_checks' ) ) ) ) ), ), ), // PHP 8.4. 'php84-implicit-nullable' => array( 'since' => '8.4', 'level' => 'deprecated', 'title' => 'Implicitly nullable parameter type', 'what' => 'A typed parameter has a null default but its type does not allow null.', 'fix' => 'Make null explicit: write ?Type $param = null, or Type|null $param = null.', 'doc' => $m84d . 'core.implicitly-nullable-parameter', 'trigger' => array( 'nullable' => true ), ), 'php84-e-strict' => array( 'since' => '8.4', 'level' => 'deprecated', 'title' => 'E_STRICT constant', 'what' => 'Uses the constant E_STRICT.', 'fix' => 'Remove E_STRICT. PHP no longer has this error level.', 'doc' => $m84i . 'core.e-strict', 'trigger' => array( 'const' => array( 'E_STRICT' ) ), ), 'php84-trigger-error-user-error' => array( 'since' => '8.4', 'level' => 'deprecated', 'title' => 'E_USER_ERROR passed to trigger_error()', 'what' => '{name}() is called with E_USER_ERROR.', 'fix' => 'Throw an exception, or call exit with a message, instead of E_USER_ERROR.', 'doc' => $m84d . 'core', 'trigger' => array( 'func' => array( 'trigger_error', 'user_error' ), 'when' => array( array( 'arg' => array( 2 => array( 'const' => array( 'E_USER_ERROR' ), 'int' => array( 256 ), ), ), ), ), ), ), 'php84-underscore-class-name' => array( 'since' => '8.4', 'level' => 'deprecated', 'title' => '"_" as a class name', 'what' => 'A class, interface, trait or enum is named "_".', 'fix' => 'Rename it. A single underscore is not allowed as a class name.', 'doc' => $m84d . 'core.underscore-class-name', 'trigger' => array( 'class_name' => '_' ), ), 'php84-curlopt-binarytransfer' => array( 'since' => '8.4', 'level' => 'deprecated', 'title' => 'CURLOPT_BINARYTRANSFER constant', 'what' => 'Uses the constant CURLOPT_BINARYTRANSFER.', 'fix' => 'Remove it. The option has had no effect since PHP 5.1.3.', 'doc' => $m84d . 'core.curl', 'trigger' => array( 'const' => array( 'CURLOPT_BINARYTRANSFER' ) ), ), 'php84-sunfuncs-ret' => array( 'since' => '8.4', 'level' => 'deprecated', 'title' => 'SUNFUNCS_RET_* constants', 'what' => 'Uses the constant {name}.', 'fix' => 'Use date_sun_info() instead of date_sunrise() and date_sunset().', 'doc' => $m84d . 'core.date', 'trigger' => array( 'const' => array( 'SUNFUNCS_RET_TIMESTAMP', 'SUNFUNCS_RET_STRING', 'SUNFUNCS_RET_DOUBLE' ) ), ), 'php84-dom-php-err' => array( 'since' => '8.4', 'level' => 'deprecated', 'title' => 'DOM_PHP_ERR constant', 'what' => 'Uses the constant DOM_PHP_ERR.', 'fix' => 'Remove it. DOM no longer raises this error code.', 'doc' => $m84d . 'core.dom', 'trigger' => array( 'const' => array( 'DOM_PHP_ERR' ) ), ), 'php84-soap-functions-all' => array( 'since' => '8.4', 'level' => 'deprecated', 'title' => 'SOAP_FUNCTIONS_ALL constant', 'what' => 'Uses the constant SOAP_FUNCTIONS_ALL.', 'fix' => 'Pass an array of function names to SoapServer::addFunction().', 'doc' => $m84d . 'core.soap', 'trigger' => array( 'const' => array( 'SOAP_FUNCTIONS_ALL' ) ), ), 'php84-sid-constant' => array( 'since' => '8.4', 'level' => 'deprecated', 'title' => 'SID constant', 'what' => 'Uses the constant SID.', 'fix' => 'Use session_id() and session_name(), and keep session IDs in cookies.', 'doc' => $m84d . 'session', 'trigger' => array( 'const' => array( 'SID' ) ), ), 'php84-session-ini' => array( 'since' => '8.4', 'level' => 'deprecated', 'title' => 'Changing a session ID setting', 'what' => 'ini_set() changes {name}.', 'fix' => 'Leave the session ID settings at their defaults and keep session IDs in cookies.', 'doc' => $m84d . 'session', 'trigger' => array( 'ini' => array( 'session.sid_length' => array( 'ne' => array( '32' ) ), 'session.sid_bits_per_character' => array( 'ne' => array( '4' ) ), 'session.use_only_cookies' => array( 'in' => array( '0', '' ) ), 'session.use_trans_sid' => array( 'in' => array( '1' ) ), 'session.trans_sid_hosts' => array( 'ne' => array( '' ) ), 'session.trans_sid_tags' => array( 'ne' => array( 'a=href,area=href,frame=src,form=' ) ), 'session.referer_check' => array( 'ne' => array( '' ) ), ), ), ), 'php84-session-save-handler-callbacks' => array( 'since' => '8.4', 'level' => 'deprecated', 'title' => 'session_set_save_handler() with separate callbacks', 'what' => 'session_set_save_handler() is called with separate callbacks.', 'fix' => 'Pass an object that implements SessionHandlerInterface instead.', 'doc' => $m84d . 'session', 'trigger' => array( 'func' => array( 'session_set_save_handler' ), 'when' => array( array( 'argc' => array( 3, null ) ) ), ), ), 'php84-mysqli-ping-kill-refresh' => array( 'since' => '8.4', 'level' => 'deprecated', 'title' => 'mysqli_ping(), mysqli_kill(), mysqli_refresh()', 'what' => 'Calls {name}().', 'fix' => 'Remove mysqli_ping(); for kill and refresh run the SQL KILL or FLUSH statement with mysqli_query().', 'doc' => $m84d . 'core.mysqli', 'trigger' => array( 'func' => array( 'mysqli_ping', 'mysqli_kill', 'mysqli_refresh' ) ), ), 'php84-mysqli-deprecated-constants' => array( 'since' => '8.4', 'level' => 'deprecated', 'title' => 'MYSQLI_REFRESH_* constants', 'what' => 'Uses the constant {name}.', 'fix' => 'Remove it. Use SQL FLUSH statements and mysqli_store_result() without a mode.', 'doc' => $m84d . 'core.mysqli', 'trigger' => array( 'const' => $mysqli_refresh ), ), 'php84-mysqli-removed-constants' => array( 'since' => '8.4', 'level' => 'removed', 'title' => 'Removed mysqli constant', 'what' => 'The constant {name} no longer exists.', 'fix' => 'Remove it. The feature was never implemented or is not available with mysqlnd.', 'doc' => $m84i . 'mysqli', 'trigger' => array( 'const' => array( 'MYSQLI_SET_CHARSET_DIR', 'MYSQLI_STMT_ATTR_PREFETCH_ROWS', 'MYSQLI_CURSOR_TYPE_FOR_UPDATE', 'MYSQLI_CURSOR_TYPE_SCROLLABLE', 'MYSQLI_TYPE_INTERVAL' ) ), ), 'php84-lcg-value' => array( 'since' => '8.4', 'level' => 'deprecated', 'title' => 'lcg_value() function', 'what' => 'Calls lcg_value().', 'fix' => 'Use mt_rand() / mt_getrandmax(), or \Random\Randomizer::getFloat().', 'doc' => $m84d . 'random', 'trigger' => array( 'func' => array( 'lcg_value' ) ), ), 'php84-xml-set-object' => array( 'since' => '8.4', 'level' => 'deprecated', 'title' => 'xml_set_object() function', 'what' => 'Calls xml_set_object().', 'fix' => 'Pass callables such as array( $object, "method" ) to the xml_set_*_handler() functions.', 'doc' => $m84d . 'core.xml', 'trigger' => array( 'func' => array( 'xml_set_object' ) ), ), 'php84-stream-context-set-option' => array( 'since' => '8.4', 'level' => 'deprecated', 'title' => 'stream_context_set_option() with two arguments', 'what' => 'stream_context_set_option() is called with two arguments.', 'fix' => 'Use stream_context_set_options( $context, $options ).', 'doc' => $m84d . 'standard', 'trigger' => array( 'func' => array( 'stream_context_set_option' ), 'when' => array( array( 'argc' => array( 2, 2 ) ) ), ), ), 'php84-csv-escape-default' => array( 'since' => '8.4', 'level' => 'deprecated', 'title' => 'CSV call without the $escape argument', 'what' => '{name}() relies on the default $escape value.', 'fix' => 'Pass $escape explicitly. Use "" to turn escaping off or "\\\\" to keep the old behaviour.', 'doc' => $m84d . 'standard', 'trigger' => array( 'func_lt' => array( 'fputcsv' => 5, 'fgetcsv' => 5, 'str_getcsv' => 4, ), ), ), 'php84-reflectionmethod-one-arg' => array( 'since' => '8.4', 'level' => 'deprecated', 'title' => 'new ReflectionMethod() with one argument', 'what' => 'ReflectionMethod is constructed with a single "Class::method" string.', 'fix' => 'Use ReflectionMethod::createFromMethodName(), or pass the class and the method name separately.', 'doc' => $m84d . 'reflection', 'trigger' => array( 'new' => array( 'ReflectionMethod' ), 'when' => array( array( 'argc' => array( 1, 1 ) ) ), ), ), 'php84-dateperiod-iso-string' => array( 'since' => '8.4', 'level' => 'deprecated', 'title' => 'new DatePeriod() from an ISO string', 'what' => 'DatePeriod is constructed from an ISO 8601 string.', 'fix' => 'Use DatePeriod::createFromISO8601String().', 'doc' => $m84d . 'core.date', 'trigger' => array( 'new' => array( 'DatePeriod' ), 'when' => array( array( 'arg' => array( 1 => array( 'str_any' => true ) ) ) ), ), ), 'php84-gmp-final' => array( 'since' => '8.4', 'level' => 'removed', 'title' => 'Class extends GMP', 'what' => 'A class extends GMP, which is final.', 'fix' => 'Wrap a GMP object instead of extending it.', 'doc' => $m84i . 'gmp', 'trigger' => array( 'extends' => array( 'GMP' ) ), ), 'php84-imap-unbundled' => array( 'since' => '8.4', 'level' => 'removed', 'title' => 'IMAP extension no longer bundled', 'what' => 'Calls {name}(), which needs the IMAP extension.', 'fix' => 'Install the PECL imap package on the server, or switch to a mail library that does not need it.', 'doc' => 'https://www.php.net/manual/en/migration84.removed-extensions.php', 'guard_ext' => 'imap', 'trigger' => array( 'func' => $imap ), ), // PHP 8.5. 'php85-non-canonical-cast' => array( 'since' => '8.5', 'level' => 'deprecated', 'title' => 'Non-canonical cast name', 'what' => 'Uses the cast {name}.', 'fix' => 'Write (bool), (int), (float) or (string) instead of (boolean), (integer), (double) or (binary).', 'doc' => $m85d . 'core.non-canonical-cast-names', 'trigger' => array( 'cast' => array( 'boolean', 'integer', 'double', 'binary' ) ), ), 'php85-backtick' => array( 'since' => '8.5', 'level' => 'deprecated', 'title' => 'Backtick operator', 'what' => 'Uses the backtick operator to run a shell command.', 'fix' => 'Call shell_exec() with the command string.', 'doc' => $m85d . 'core.the-backtick-operator', 'trigger' => array( 'backtick' => true ), ), 'php85-case-semicolon' => array( 'since' => '8.5', 'level' => 'deprecated', 'title' => 'case ended with a semicolon', 'what' => 'A case or default label ends with ; instead of :.', 'fix' => 'End the case or default label with a colon.', 'doc' => $m85d . 'core.case-statements-with-semicolon', 'trigger' => array( 'case_semicolon' => true ), ), 'php85-handle-close-functions' => array( 'since' => '8.5', 'level' => 'deprecated', 'title' => 'Close function for an object that frees itself', 'what' => 'Calls {name}().', 'fix' => 'Remove the call. The object is freed when no variable refers to it.', 'doc' => $m85d . 'curl', 'trigger' => array( 'func' => array( 'curl_close', 'curl_share_close', 'finfo_close', 'imagedestroy', 'xml_parser_free' ) ), ), 'php85-mysqli-execute' => array( 'since' => '8.5', 'level' => 'deprecated', 'title' => 'mysqli_execute() alias', 'what' => 'Calls mysqli_execute().', 'fix' => 'Use mysqli_stmt_execute().', 'doc' => $m85d . 'mysqli', 'trigger' => array( 'func' => array( 'mysqli_execute' ) ), ), 'php85-socket-set-timeout' => array( 'since' => '8.5', 'level' => 'deprecated', 'title' => 'socket_set_timeout() alias', 'what' => 'Calls socket_set_timeout().', 'fix' => 'Use stream_set_timeout().', 'doc' => $m85d . 'standard', 'trigger' => array( 'func' => array( 'socket_set_timeout' ) ), ), 'php85-get-defined-functions-arg' => array( 'since' => '8.5', 'level' => 'deprecated', 'title' => 'get_defined_functions() with an argument', 'what' => 'get_defined_functions() is called with $exclude_disabled.', 'fix' => 'Call get_defined_functions() without arguments. The parameter has had no effect since PHP 8.0.', 'doc' => $m85d . 'core', 'trigger' => array( 'func' => array( 'get_defined_functions' ), 'when' => array( array( 'argc' => array( 1, null ) ) ), ), ), 'php85-mhash-constants' => array( 'since' => '8.5', 'level' => 'deprecated', 'title' => 'MHASH_* constants', 'what' => 'Uses the constant {name}.', 'fix' => 'Use hash() and hash_hmac() with the algorithm name.', 'doc' => $m85d . 'hash', 'trigger' => array( 'const' => $mhash ), ), 'php85-date-rfc7231' => array( 'since' => '8.5', 'level' => 'deprecated', 'title' => 'DATE_RFC7231 constant', 'what' => 'Uses the constant {name}.', 'fix' => 'Format with the string "D, d M Y H:i:s \G\M\T" on a UTC date.', 'doc' => $m85d . 'date', 'trigger' => array( 'const' => array( 'DATE_RFC7231' ), 'cconst' => array( 'DateTimeInterface' => array( 'RFC7231' ), 'DateTime' => array( 'RFC7231' ), 'DateTimeImmutable' => array( 'RFC7231' ), ), ), ), 'php85-pdo-driver-constants' => array( 'since' => '8.5', 'level' => 'deprecated', 'title' => 'Driver-specific constant on PDO', 'what' => 'Uses the constant {name}.', 'fix' => 'Use the same constant on the driver class, for example Pdo\Mysql::ATTR_INIT_COMMAND.', 'doc' => $m85d . 'pdo', 'trigger' => array( 'cconst' => array( 'PDO' => $pdo ) ), ), 'php85-dir-handle-null' => array( 'since' => '8.5', 'level' => 'deprecated', 'title' => 'readdir(), rewinddir(), closedir() without a handle', 'what' => '{name}() relies on the last opened directory.', 'fix' => 'Pass the directory handle that opendir() returned.', 'doc' => $m85d . 'standard', 'trigger' => array( 'func' => array( 'readdir', 'rewinddir', 'closedir' ), 'when' => array( array( 'argc' => array( 0, 0 ) ), array( 'arg' => array( 1 => array( 'null' => true ) ) ), ), ), ), 'php85-chr-out-of-range' => array( 'since' => '8.5', 'level' => 'deprecated', 'title' => 'chr() with a value outside 0-255', 'what' => 'chr() is called with a number outside 0 to 255.', 'fix' => 'Pass a value from 0 to 255, for example $code % 256.', 'doc' => $m85d . 'standard', 'trigger' => array( 'func' => array( 'chr' ), 'when' => array( array( 'arg' => array( 1 => array( 'int_out' => array( 0, 255 ) ) ) ) ), ), ), 'php85-ord-multibyte' => array( 'since' => '8.5', 'level' => 'deprecated', 'title' => 'ord() with a string that is not one byte', 'what' => 'ord() is called with a string literal that is not one byte long.', 'fix' => 'Pass a single byte, or use mb_ord() for a multibyte character.', 'doc' => $m85d . 'standard', 'trigger' => array( 'func' => array( 'ord' ), 'when' => array( array( 'arg' => array( 1 => array( 'str_len_ne' => 1 ) ) ) ), ), ), 'php85-finfo-buffer-context' => array( 'since' => '8.5', 'level' => 'deprecated', 'title' => 'finfo_buffer() with a context', 'what' => 'finfo_buffer() is called with a $context argument.', 'fix' => 'Remove the fourth argument. It is ignored.', 'doc' => $m85d . 'fileinfo', 'trigger' => array( 'func' => array( 'finfo_buffer' ), 'when' => array( array( 'argc' => array( 4, null ) ) ), ), ), 'php85-class-alias-reserved' => array( 'since' => '8.5', 'level' => 'removed', 'title' => 'class_alias() to "array" or "callable"', 'what' => 'class_alias() uses a reserved type name as the alias.', 'fix' => 'Choose another alias name.', 'doc' => $m85i . 'core.array-callable-alias', 'trigger' => array( 'func' => array( 'class_alias' ), 'when' => array( array( 'arg' => array( 2 => array( 'stri' => array( 'array', 'callable' ) ) ) ) ), ), ), 'php85-report-memleaks' => array( 'since' => '8.5', 'level' => 'deprecated', 'title' => 'report_memleaks setting', 'what' => 'ini_set() changes report_memleaks.', 'fix' => 'Remove the call. The setting is deprecated.', 'doc' => $m85d . 'core.return-memleaks-ini-directive', 'trigger' => array( 'ini' => array( 'report_memleaks' => array( 'bool_ne' => array( true ) ) ) ), ), 'php85-intl-error-level' => array( 'since' => '8.5', 'level' => 'deprecated', 'title' => 'intl.error_level setting', 'what' => 'ini_set() sets intl.error_level to a value other than 0.', 'fix' => 'Check intl error codes yourself, or enable intl.use_exceptions.', 'doc' => $m85d . 'intl', 'trigger' => array( 'ini' => array( 'intl.error_level' => array( 'ne' => array( '0', '' ) ) ) ), ), 'php85-openssl-pkey-derive-length' => array( 'since' => '8.5', 'level' => 'deprecated', 'title' => 'openssl_pkey_derive() with a key length', 'what' => 'openssl_pkey_derive() is called with $key_length.', 'fix' => 'Remove the third argument and truncate the result yourself if you need a shorter key.', 'doc' => $m85d . 'openssl', 'trigger' => array( 'func' => array( 'openssl_pkey_derive' ), 'when' => array( array( 'argc' => array( 3, null ) ) ), ), ), 'php85-autoload-call-unregister' => array( 'since' => '8.5', 'level' => 'deprecated', 'title' => 'spl_autoload_unregister( "spl_autoload_call" )', 'what' => 'spl_autoload_unregister() is called with spl_autoload_call.', 'fix' => 'Loop over spl_autoload_functions() and unregister each autoloader.', 'doc' => $m85d . 'spl', 'trigger' => array( 'func' => array( 'spl_autoload_unregister' ), 'when' => array( array( 'arg' => array( 1 => array( 'stri' => array( 'spl_autoload_call' ) ) ) ) ), ), ), 'php85-disable-classes-ini' => array( 'since' => '8.5', 'level' => 'removed', 'title' => 'disable_classes setting', 'what' => '{name}() uses disable_classes, which PHP 8.5 removed.', 'fix' => 'Do not rely on disable_classes. ini_get() returns false on PHP 8.5.', 'doc' => $m85i . 'core.disable-ini-setting', 'trigger' => array( 'func' => array( 'ini_get', 'ini_set', 'ini_alter', 'ini_restore' ), 'when' => array( array( 'arg' => array( 1 => array( 'str' => array( 'disable_classes' ) ) ) ) ), ), ), ); } /** * Display fields of one rule. * * @param string $rule_id Rule id. * @return array title, since, level, fix, doc (empty array for an unknown id). */ public static function meta( string $rule_id ): array { $all = self::all(); if ( ! isset( $all[ $rule_id ] ) ) { return array(); } $r = $all[ $rule_id ]; return array( 'title' => $r['title'], 'since' => $r['since'], 'level' => $r['level'], 'fix' => $r['fix'], 'doc' => $r['doc'], ); } }