{"record":{"id":"3b7e23c2c1f08d21","repo":"octobercms/october","slug":"system-lang-media-invalid-path-encoding","errorCode":null,"errorMessage":"system::lang.media.invalid_path_encoding","messagePattern":"system::lang\\.media\\.invalid_path_encoding","errorType":"exception","errorClass":"ApplicationException","httpStatus":null,"severity":"error","filePath":"modules/media/classes/MediaLibrary.php","lineNumber":495,"sourceCode":"     * validatePath checks if file path doesn't contain any substrings that would pose a security\n     * threat. Returns a normalized path. Throws an exception if the path is not valid. An option\n     * is provided, if only normalization is needed without validation.\n     * @param string $path\n     * @param bool $normalizeOnly\n     * @return string\n     */\n    public static function validatePath($path, $normalizeOnly = false): string\n    {\n        $path = str_replace('\\\\', '/', $path);\n        $path = '/'.trim($path, '/');\n\n        if ($normalizeOnly) {\n            return $path;\n        }\n\n        // Reject paths that are not valid UTF-8\n        if (!mb_check_encoding($path, 'UTF-8')) {\n            throw new ApplicationException(Lang::get('system::lang.media.invalid_path_encoding', ['path' => mb_scrub($path)]));\n        }\n\n        // Reject control, format and other invisible characters\n        if (preg_match('/[\\p{C}]/u', $path)) {\n            throw new ApplicationException(Lang::get('system::lang.media.invalid_path', compact('path')));\n        }\n\n        // Reject characters reserved by file systems and URLs\n        if (preg_match('/[<>:\"|?*]/', $path)) {\n            throw new ApplicationException(Lang::get('system::lang.media.invalid_path', compact('path')));\n        }\n\n        $regexDirectorySeparator = preg_quote('/', '#');\n        $regexDot = preg_quote('.', '#');\n        $regex = [\n            // Beginning of path\n            '(^'.$regexDot.'+?'.$regexDirectorySeparator.')',\n","sourceCodeStart":477,"sourceCodeEnd":513,"githubUrl":"https://github.com/octobercms/october/blob/b608633a7e8922487d91a8161499020121c3b3bf/modules/media/classes/MediaLibrary.php#L477-L513","documentation":"MediaLibrary::validatePath() normalizes a path and then requires it to be valid UTF-8: mb_check_encoding($path, 'UTF-8') must pass. A byte string in another encoding (Latin-1/Windows-1252 0xE9 for 'é', GBK multibyte, raw binary) triggers invalid_path_encoding, with the offending path scrubbed via mb_scrub for safe display. This guard exists because every later regex uses the /u modifier, which fails on invalid UTF-8, and storage backends assume UTF-8 keys.","triggerScenarios":"Calling a media API with a Windows-1252-encoded filename from a legacy integration; paths read from an old latin1 database column; a client percent-decoding URL-encoded bytes into non-UTF-8 sequences; binary garbage in a crafted request.","commonSituations":"Migrating media indexes from old systems; scripts that read filenames from a legacy filesystem without iconv; API consumers defaulting to a single-byte charset.","solutions":["Convert the encoding before calling the API: $path = mb_convert_encoding($path, 'UTF-8', 'Windows-1252'); (or iconv with //TRANSLIT)","Fix the source of the path: make DB columns utf8mb4 and store/emit UTF-8 everywhere","For display of already-corrupt data, pass mb_scrub($path) so invalid sequences are substituted instead of crashing"],"exampleFix":"// before — $path came from a latin1 source\n$clean = MediaLibrary::validatePath($path); // throws invalid_path_encoding\n\n// after — convert first, then validate\n$clean = MediaLibrary::validatePath(mb_convert_encoding($path, 'UTF-8', 'Windows-1252'));","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"function isUtf8Path(mixed $path): bool {\n    return is_string($path) && mb_check_encoding($path, 'UTF-8');\n}\n\n// usage\nif (!isUtf8Path($path)) {\n    $path = mb_convert_encoding($path, 'UTF-8', 'Windows-1252');\n}","tryCatchPattern":"try {\n    $clean = MediaLibrary::validatePath($path);\n} catch (ApplicationException $e) {\n    // invalid_path_encoding vs invalid_path can be distinguished by message\n    $path = mb_scrub($path);\n    $clean = MediaLibrary::validatePath($path);\n}","preventionTips":["Standardize on UTF-8 end to end: DB columns utf8mb4, API charset UTF-8","Convert legacy-encoded filenames at the boundary with mb_convert_encoding before any media call","Never pass raw bytes from external systems into path APIs"],"tags":["media","encoding","utf8","path-validation"],"backgroundTag":"invalid-utf8-encoding","analyzedSha":"b608633a7e8922487d91a8161499020121c3b3bf","analyzedAt":"2026-08-21T04:24:57.515Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}