{"record":{"id":"80ac7bdf190b53d8","repo":"symfony/http-foundation","slug":"the-filename-fallback-must-only-contain-ascii-characters","errorCode":null,"errorMessage":"The filename fallback must only contain ASCII characters.","messagePattern":"The filename fallback must only contain ASCII characters\\.","errorType":"exception","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"HeaderUtils.php","lineNumber":177,"sourceCode":"     *                                 it can be omitted, or just copied from $filename\n     *\n     * @throws \\InvalidArgumentException\n     *\n     * @see RFC 6266\n     */\n    public static function makeDisposition(string $disposition, string $filename, string $filenameFallback = ''): string\n    {\n        if (!\\in_array($disposition, [self::DISPOSITION_ATTACHMENT, self::DISPOSITION_INLINE], true)) {\n            throw new \\InvalidArgumentException(\\sprintf('The disposition must be either \"%s\" or \"%s\".', self::DISPOSITION_ATTACHMENT, self::DISPOSITION_INLINE));\n        }\n\n        if ('' === $filenameFallback) {\n            $filenameFallback = $filename;\n        }\n\n        // filenameFallback is not ASCII.\n        if (!preg_match('/^[\\x20-\\x7e]*$/', $filenameFallback)) {\n            throw new \\InvalidArgumentException('The filename fallback must only contain ASCII characters.');\n        }\n\n        // percent characters aren't safe in fallback.\n        if (str_contains($filenameFallback, '%')) {\n            throw new \\InvalidArgumentException('The filename fallback cannot contain the \"%\" character.');\n        }\n\n        // path separators aren't allowed in either.\n        if (str_contains($filename, '/') || str_contains($filename, '\\\\') || str_contains($filenameFallback, '/') || str_contains($filenameFallback, '\\\\')) {\n            throw new \\InvalidArgumentException('The filename and the fallback cannot contain the \"/\" and \"\\\\\" characters.');\n        }\n\n        $params = ['filename' => $filenameFallback];\n        if ($filename !== $filenameFallback) {\n            $params['filename*'] = \"utf-8''\".rawurlencode($filename);\n        }\n\n        return $disposition.'; '.self::toString($params, ';');","sourceCodeStart":159,"sourceCodeEnd":195,"githubUrl":"https://github.com/symfony/http-foundation/blob/5aea19cd678fa4140f6108406f1096de5e9ed6e4/HeaderUtils.php#L159-L195","documentation":"In makeDisposition(), the $filenameFallback (which defaults to $filename when empty) is checked with preg_match('/^[\\x20-\\x7e]*$/') to ensure it contains only printable ASCII characters. The fallback goes into the header verbatim, so non-ASCII bytes would produce a malformed/invalid header; hence the InvalidArgumentException.","triggerScenarios":"Calling makeDisposition($disposition, $filename) where $filename (used as implicit fallback) contains UTF-8/multibyte characters like 'ünïcode.pdf' or '日本語.pdf' and no ASCII-only $filenameFallback is supplied; or explicitly passing a non-ASCII $filenameFallback.","commonSituations":"Serving files with accented, Cyrillic, CJK or emoji names without providing an ASCII fallback; user-uploaded filenames with non-ASCII characters passed directly to makeDisposition; ISO-8859-1 encoded strings treated as ASCII.","solutions":["Pass an ASCII-only third argument as $filenameFallback, e.g. HeaderUtils::makeDisposition($d, 'ünïcode.pdf', 'unicode.pdf')","Transliterate the filename first (iconv with //TRANSLIT or a slugifier) to produce an ASCII fallback","Strip or replace non-ASCII bytes with a fallback like preg_replace('/[^\\x20-\\x7e]/', '_', $name)","Wrap in try/catch and fall back to a generic ASCII filename like 'download'"],"exampleFix":"// before\nHeaderUtils::makeDisposition('attachment', 'naïve file.pdf'); // throws\n// after\nHeaderUtils::makeDisposition('attachment', 'naïve file.pdf', 'naive file.pdf');","handlingStrategy":"validation","validationCode":"if (!preg_match('/^[\\x20-\\x7e]*$/', $filenameFallback)) {\n    $filenameFallback = iconv('UTF-8', 'ASCII//TRANSLIT', $filenameFallback) ?: 'download';\n}","typeGuard":"function isAsciiPrintable(string $s): bool {\n    return (bool) preg_match('/^[\\x20-\\x7e]*$/', $s);\n}","tryCatchPattern":"try {\n    $header = HeaderUtils::makeDisposition($disposition, $filename, $filenameFallback);\n} catch (\\InvalidArgumentException $e) {\n    $header = HeaderUtils::makeDisposition($disposition, $filename, 'download');\n}","preventionTips":["Always supply an explicit ASCII fallback when the filename may be non-ASCII","Transliterate uploads with iconv //TRANSLIT or a slugifier before building the header","Test with accented, CJK and emoji filenames"],"tags":["php","http-headers","ascii","filename","symfony"],"backgroundTag":"invalid-argument-format","analyzedSha":"5aea19cd678fa4140f6108406f1096de5e9ed6e4","analyzedAt":"2026-09-13T01:52:22.855Z","contentChangedAt":"2026-09-13T01:52:22.855Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}