FrankenPHP下Symfony上传失败主因是其默认client_max_body_size仅16MB且不继承PHP配置,必须在frankenphp.yaml中显式设http: max_body_size: 512M或通过FRANKENPHP_HTTP_MAX_BODY_SIZE=512M环境变量覆盖,否则请求在PHP解析前就被413拦截。

FrankenPHP 下 Symfony 文件上传失败,大概率不是 Symfony 或 PHP 代码的问题,而是 FrankenPHP 的默认 HTTP 请求体限制(client_max_body_size)比传统 Nginx 更激进——它默认只允许 16MB,且不读取 php.ini 中的 upload_max_filesize 来自动放宽。你改了 PHP 配置却依然报错,就是卡在这儿。
FrankenPHP 的 client_max_body_size 必须显式配置
FrankenPHP 不继承 Nginx 的配置习惯,也不自动同步 PHP 的上传限制。它的请求体上限由内置 HTTP 服务器直接控制,且默认值极低(16MB),远低于常见业务需求。
- 在 FrankenPHP 的配置文件(通常是
frankenphp.yaml或通过环境变量)中,必须显式设置:http: max_body_size: 512M
- 若用命令行启动,可通过环境变量覆盖:
FRANKENPHP_HTTP_MAX_BODY_SIZE=512M ./frankenphp - 该值必须 ≥ PHP 的
post_max_size(推荐大 2–4MB,预留表单字段空间);否则即使 PHP 层允许,FrankenPHP 会在解析请求前直接 413 Request Entity Too Large 拒绝整个请求 - 注意:这个配置影响所有 POST/PUT 请求体,不只是文件上传;但文件上传最敏感,因为它是唯一可能撑满 body 的场景
UPLOAD_ERR_INI_SIZE(错误码 1)在 FrankenPHP 下的特殊含义
当看到 $_FILES['file']['error'] === 1,别急着改 php.ini。FrankenPHP 下,这个错误码可能被“误报”——实际是 FrankenPHP 已经截断了请求体,PHP 根本没收到完整文件,$_FILES 数组为空或 size=0,move_uploaded_file() 因源文件不存在而失败,最终抛出模糊异常。
- 先确认是否真被 FrankenPHP 截断:检查响应状态码是否为
413;或在控制器开头加var_dump($_SERVER['CONTENT_LENGTH']);,若远小于你期望的文件大小,就是它干的 - 不要依赖
phpinfo()查upload_max_filesize—— FrankenPHP 启动时会加载 PHP 配置,但请求体拦截发生在 PHP 解析之前,此时配置根本没机会生效 - 错误码 1 和 2(
UPLOAD_ERR_FORM_SIZE)在 FrankenPHP 下难以区分,统一优先排查max_body_size
Symfony 表单绑定失效的典型表现与定位
在 FrankenPHP 环境下,$form->handleRequest($request) 可能静默跳过文件字段,$form->isValid() 返回 true,但 $data['file'] 是 null。这不是验证逻辑漏了,而是请求体被截断后,$_FILES 数组为空,Symfony 表单组件压根拿不到 UploadedFile 实例。
立即学习“PHP免费学习笔记(深入)”;
- 在控制器里加诊断代码:
dump($request->files->all(), $_FILES);—— 若两者都为空,100% 是 FrankenPHP 层拦截 - FileType 字段的
'required' => true在这种情况下毫无意义:没有文件数据传进来,表单不会触发任何文件校验,直接当作空字段处理 - 不要在
handleRequest()后才检查$file->getError()—— 此时$file可能是null,调用方法会报Call to a member function getError() on null - 安全写法是:
$file = $request->files->get('file'); if (!$file instanceof UploadedFile || $file->getError() !== UPLOAD_ERR_OK) { /* 处理错误 */ }
为什么不能只靠前端分片上传来绕过?
分片上传确实能规避单次请求超限,但它把复杂度从服务端转移到了客户端和网络层:需维护分片顺序、重试逻辑、合并时机;且 FrankenPHP 的 max_body_size 仍要设得足够容纳单个分片(比如 20MB 分片就得 ≥20MB)。更重要的是,它掩盖了配置缺失问题,导致其他非上传接口(如大 JSON payload 的 API)未来也可能突然 413。
- FrankenPHP 的
max_body_size是全局开关,应按业务最大单体载荷设置(如允许上传 500MB 视频,则设为512M) - 分片上传适合真正超大文件(>2GB)或弱网环境,不是上传限制配置不到位的补救手段
- 生产环境必须同时保留 PHP 层校验(
Constraints\File)和 FrankenPHP 层拦截——前者防恶意 MIME、后者防 DoS 式大请求
FrankenPHP 的简洁性来自统一管控,代价是配置点更集中、更不可绕过。上传失败时,第一反应不该是翻 Symfony 文档或改 php.ini,而是查 frankenphp.yaml 里的 max_body_size —— 这个值一旦设错,后面所有 PHP 和 Symfony 层的努力都是徒劳。



















