Docker中运行的PHP 7.3-fpm应用仅能上传部分文件问题求助
问题解答
一、Docker镜像优化建议
- 合并RUN指令:当前Dockerfile中存在大量独立的RUN指令,每一条RUN都会生成新的镜像层,大幅拉高镜像体积。建议把同类型操作合并,比如所有apt安装操作合并为一个RUN段、所有pip安装操作合并为一个RUN段,操作完成后统一清理缓存。
- 统一工作目录:docker-compose里配置的
working_dir为/var/www/backend,但Dockerfile中设置的WORKDIR为/application,路径不一致会导致运行时路径预期错误,建议统一为/var/www/backend。 - 移除冗余操作:多次重复执行
apt-get update会拉长构建耗时,建议单次RUN开头只执行一次update,安装完成后立刻清理apt缓存、pip缓存,减少镜像体积。 - 移除非必要工具:生产镜像不需要vim这类调试工具,如果有临时调试需求,可以在容器运行后exec进入容器按需安装,避免不必要的体积占用。
- 修正挂载覆盖问题:docker-compose中将当前目录挂载到
/var/www,会直接覆盖Dockerfile里COPY到/var/www/backend/uploads的内容,也会覆盖此前chown修改的目录权限。建议要么调整挂载路径,要么在容器启动脚本中重新执行chown修正uploads目录权限。 - 可选多阶段构建:如果后续镜像体积仍然偏大,可以采用多阶段构建方案,将PHP扩展编译、pip依赖安装放在构建阶段完成,最终运行阶段只拷贝必要的二进制文件和依赖,避免编译工具残留。
二、文件上传失败原因排查
首先你当前的代码只有上传成功时才有输出,失败时没有任何错误提示,看起来就像无报错失败。建议先在代码中补充错误日志输出:
$app->post('/', function(Request $request, Response $response) { $directory = $this->get('upload_directory'); $uploadedFiles = $request->getUploadedFiles(); $uploadedFile = $uploadedFiles['filename']; if ($uploadedFile->getError() === UPLOAD_ERR_OK) { $filename = moveUploadedFile($directory, $uploadedFile); $response->write('uploaded ' . $filename . '<br/>'); } else { // 输出错误码,对应含义:1=超过php.ini上传大小限制、2=超过表单大小限制、3=文件上传不完整、4=未接收到文件 $response->write('上传失败,错误码:' . $uploadedFile->getError()); } });
根据你描述的Mac系统下的复现规律,大概率是以下几个原因导致:
- 先检查你挂载的
custom.ini配置,确认upload_max_filesize和post_max_size的数值,有可能其他位置的文件体积大于你用VSCode创建的测试文件,超过PHP上传限制导致失败。 - Mac系统隔离属性问题:Mac上非用户目录、非本地编辑器创建的文件,会被自动附加
com.apple.quarantine隔离属性,可能导致Postman读取文件异常。可以在终端执行xattr -l 测试文件路径查看是否有该属性,有的话执行xattr -d com.apple.quarantine 测试文件路径后重试上传。 - 上传目录权限问题:因为docker-compose的挂载覆盖了Dockerfile中的
chown操作,容器内uploads目录的实际所有者不是运行PHP的www-data用户,导致写入失败。可以进入容器执行ls -la /var/www/backend/uploads确认权限,如果所有者不对,可在docker-compose的php服务配置中添加user: "宿主机UID:宿主机GID"(Mac下执行id -u和id -g可获取当前用户的UID、GID),让容器内PHP运行用户和宿主机用户权限一致,即可正常写入。 - 检查是否有MIME类型拦截:如果你配置了中间件或者反向代理限制了上传文件的MIME类型,VSCode创建的文件默认MIME类型多为纯文本会被放行,其他类型文件可能被拦截,可在Postman的请求Body中确认上传文件的MIME类型是否符合预期。
内容的提问来源于stack exchange,提问作者user1020496
相关产品推荐
相关产品推荐

