{"record":{"id":"de2bf04cc6a15e93","repo":"paragonie/random_compat","slug":"randomcompat-strlen-expects-a-string","errorCode":null,"errorMessage":"RandomCompat_strlen() expects a string","messagePattern":"RandomCompat_strlen\\(\\) expects a string","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"lib/byte_safe_strings.php","lineNumber":50,"sourceCode":"            &&\n        ((int) ini_get('mbstring.func_overload')) & MB_OVERLOAD_STRING\n    ) {\n        /**\n         * strlen() implementation that isn't brittle to mbstring.func_overload\n         *\n         * This version uses mb_strlen() in '8bit' mode to treat strings as raw\n         * binary rather than UTF-8, ISO-8859-1, etc\n         *\n         * @param string $binary_string\n         *\n         * @throws TypeError\n         *\n         * @return int\n         */\n        function RandomCompat_strlen($binary_string)\n        {\n            if (!is_string($binary_string)) {\n                throw new TypeError(\n                    'RandomCompat_strlen() expects a string'\n                );\n            }\n\n            return (int) mb_strlen($binary_string, '8bit');\n        }\n\n    } else {\n        /**\n         * strlen() implementation that isn't brittle to mbstring.func_overload\n         *\n         * This version just used the default strlen()\n         *\n         * @param string $binary_string\n         *\n         * @throws TypeError\n         *\n         * @return int","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/paragonie/random_compat/blob/b5d188cc9d5e02f94d2c41da23093f1ef557c5b1/lib/byte_safe_strings.php#L32-L68","documentation":"random_compat's RandomCompat_strlen() is a byte-safe wrapper around mb_strlen($str, '8bit') used to guarantee binary-safe string length on PHP 5/7 builds where the multibyte extension behaves differently. Before measuring, it asserts that the argument is actually a PHP string; if not, it throws TypeError. This is defensive input validation because random_compat's public API (e.g. random_bytes(), RandomCompat_substr()) deals exclusively with binary strings and must never silently accept ints, null, objects, or arrays.","triggerScenarios":"Calling RandomCompat_strlen() directly with a non-string (e.g. an int, null, float, bool, array, or object). Most commonly it happens indirectly: passing a non-string as the first argument to RandomCompat_substr(), which then calls RandomCompat_strlen($binary_string) at the '$length === null' branch or the '$start === RandomCompat_strlen(...)' consistency check before its own validation order catches some cases.","commonSituations":"Developers treating random_compat as a general string utility and passing int/float output of arithmetic (e.g. a length computed from an API), passing null from an unset variable or failed function return, decoding JSON where a field was expected to be a string but came back as a number or null, or calling RandomCompat_substr() with a non-string first argument so the nested RandomCompat_strlen() call explodes first.","solutions":["Cast or verify the value is a string before calling: is_string($s) || throw new InvalidArgumentException(); or $s = (string) $s only if coercion is safe.","If the value comes from JSON/API input, validate the field type at the boundary before passing it into random_compat functions.","Call the public API random_bytes($n) / random_int($a,$b) instead of internal RandomCompat_* helpers; those take ints and handle conversion themselves.","Trace the caller (RandomCompat_substr) — the real bug is the first argument to RandomCompat_substr(), not strlen."],"exampleFix":"// before\n$len = RandomCompat_strlen($maybeInt);\n// after\nif (!is_string($maybeInt)) {\n    throw new InvalidArgumentException('Expected a binary string');\n}\n$len = RandomCompat_strlen($maybeInt);","handlingStrategy":"type-guard","validationCode":"function assertBinaryString($value): void {\n    if (!is_string($value)) {\n        throw new InvalidArgumentException(\n            'Expected binary string, got ' . gettype($value)\n        );\n    }\n}\nassertBinaryString($input);","typeGuard":"function isBinaryString($value): bool {\n    return is_string($value);\n}\nif (isBinaryString($input)) {\n    $len = RandomCompat_strlen($input);\n}","tryCatchPattern":"try {\n    $len = RandomCompat_strlen($input);\n} catch (TypeError $e) {\n    // $input was not a string; log and recover or rethrow with context\n    throw new InvalidArgumentException('RandomCompat_strlen requires a string', 0, $e);\n}","preventionTips":["Always is_string()-check values from JSON, DB, or config before byte-level helpers.","Never rely on PHP's implicit string coercion for binary data.","Use the public random_bytes()/random_int() API instead of RandomCompat_* internals.","Enable strict_types=1 so coercion bugs surface at your own boundary first."],"tags":["php","typeerror","string-type","random-compat"],"backgroundTag":"type-mismatch","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"}