{"record":{"id":"060346f8c88e6f04","repo":"paragonie/random_compat","slug":"randomcompat-substr-third-argument-should-be-an-integer-or","errorCode":null,"errorMessage":"RandomCompat_substr(): Third argument should be an integer, or omitted","messagePattern":"RandomCompat_substr\\(\\): Third argument should be an integer, or omitted","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"lib/byte_safe_strings.php","lineNumber":125,"sourceCode":"                    'RandomCompat_substr(): First argument should be a string'\n                );\n            }\n\n            if (!is_int($start)) {\n                throw new TypeError(\n                    'RandomCompat_substr(): Second argument should be an integer'\n                );\n            }\n\n            if ($length === null) {\n                /**\n                 * mb_substr($str, 0, NULL, '8bit') returns an empty string on\n                 * PHP 5.3, so we have to find the length ourselves.\n                 */\n                /** @var int $length */\n                $length = RandomCompat_strlen($binary_string) - $start;\n            } elseif (!is_int($length)) {\n                throw new TypeError(\n                    'RandomCompat_substr(): Third argument should be an integer, or omitted'\n                );\n            }\n\n            // Consistency with PHP's behavior\n            if ($start === RandomCompat_strlen($binary_string) && $length === 0) {\n                return '';\n            }\n            if ($start > RandomCompat_strlen($binary_string)) {\n                return '';\n            }\n\n            return (string) mb_substr(\n                (string) $binary_string,\n                (int) $start,\n                (int) $length,\n                '8bit'\n            );","sourceCodeStart":107,"sourceCodeEnd":143,"githubUrl":"https://github.com/paragonie/random_compat/blob/b5d188cc9d5e02f94d2c41da23093f1ef557c5b1/lib/byte_safe_strings.php#L107-L143","documentation":"RandomCompat_substr()'s third parameter $length must be an integer or omitted (null, meaning 'rest of string'). When a non-int, non-null value (float, numeric string, bool) is supplied, the function throws TypeError. Note the library computes $length itself when null, because mb_substr($str, 0, NULL, '8bit') returns '' on PHP 5.3 — so passing null is always safe and correct.","triggerScenarios":"Calling RandomCompat_substr($str, $start, $length) where $length is a float from arithmetic (e.g. ceil(strlen($s)/2)), a numeric string from config/JSON (\"16\"), or a bool from a failed comparison. Only the elseif branch fires — $start was already a valid int.","commonSituations":"Computing half-lengths or chunk sizes with division producing floats; JSON/env config delivering lengths as strings; passing true/false from a conditional expression by accident; older PHP returning floats from certain math functions.","solutions":["Cast deliberately: $length = (int) $len after verifying it is numeric.","Use round()/floor() then cast when deriving lengths from division: $length = (int) ceil($size / 2).","Omit the parameter entirely (pass null) to mean 'to end of string' — the library computes it safely.","Validate with is_int($length) at the caller boundary before invoking."],"exampleFix":"// before\n$length = ceil(strlen($str) / 2); // float\n$half = RandomCompat_substr($str, 0, $length);\n// after\n$length = (int) ceil(RandomCompat_strlen($str) / 2);\n$half = RandomCompat_substr($str, 0, $length);","handlingStrategy":"validation","validationCode":"if ($length !== null && !is_int($length)) {\n    $length = (int) $length; // verify numeric-ness first for untrusted input\n}\n$part = RandomCompat_substr($str, $start, $length);","typeGuard":"function isValidLength($value): bool {\n    return $value === null || is_int($value);\n}\n$part = isValidLength($length)\n    ? RandomCompat_substr($str, $start, $length)\n    : RandomCompat_substr($str, $start);","tryCatchPattern":"try {\n    $part = RandomCompat_substr($str, $start, $length);\n} catch (TypeError $e) {\n    // non-int length; fall back to rest-of-string\n    $part = RandomCompat_substr($str, $start);\n}","preventionTips":["Pass null (or omit) for 'to end of string' — the library computes it safely even on PHP 5.3.","Cast results of division/ceil/floor to int before using as length.","Validate lengths from JSON/YAML/env which often arrive as strings.","Keep chunk-size math in one helper that guarantees int output."],"tags":["php","typeerror","substr","integer-argument"],"backgroundTag":"invalid-argument","analyzedSha":"b5d188cc9d5e02f94d2c41da23093f1ef557c5b1","analyzedAt":"2026-09-13T16:12:09.755Z","contentChangedAt":"2026-09-13T16:12:09.755Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}