后台媒体库点「添加」或拖一张图进去,进度条走到一半突然停,或直接弹出「HTTP 错误」「超过了最大上传限制」「无法写入上传目录」------列表里没有新附件,前台也就谈不上图。这和今天已经写过的数据库连不上、表单收不到信、HTTPS 重定向环、整站「严重错误」、Woo 结账转圈不是一类故障:站点能打开,卡在 上传链路本身 (PHP 收文件 → 写入 wp-content/uploads → 可选再推对象存储/CDN)。
更稳的顺序是:先看报错文案与 Network 里 async-upload.php / media-new.php 的状态码 → 核 upload_max_filesize、post_max_size、Nginx client_max_body_size(或 Apache LimitRequestBody)→ 再查 uploads 目录属主与权限、open_basedir → 然后排安全/WAF 插件是否拦了上传 POST → 最后才动 OSS/S3 插件与 CDN 回源。别一上来就重装 WordPress 或换主题。
先分清:PHP 体积 vs 目录权限 vs 安全/WAF vs 对象存储
「上传图片失败」常见落在四条线上,别混着改:
- PHP / Web 服务器体积上限 :单文件超过
upload_max_filesize,或整次 POST 超过post_max_size/client_max_body_size。表现多为「超过了最大上传限制」、空响应、或 413 Request Entity Too Large。 - 目录权限 / open_basedir / 磁盘满 :
wp-content/uploads(含当年月子目录)不可写,或open_basedir把 PHP 关在站点根外。表现多为「无法创建目录」「无法写入文件」,debug.log里常见Permission denied。 - 安全插件 / 主机 WAF / ModSecurity :把
async-upload.php的 multipart POST 当恶意请求拦掉。表现多为 HTTP 错误、403、或上传请求返回 HTML 挑战页;小图偶发成功、大图/特定扩展名必挂。 - 对象存储 / CDN 插件:本地其实已写入,但 OSS/S3 同步失败、Bucket 权限、或媒体 URL 被改成外链后回源 404。表现多为后台有附件记录但缩略图裂图,或上传「成功」后前台打不开。
先把媒体库报错原文、浏览器 Network 里那一次上传请求的状态码与响应前几行记下来,再决定是改 php.ini 还是排 WAF,比同时调权限、关插件、换 OSS 更省事。
第一步:看清报错与 Network ------ 别先猜「权限」
用管理员账号打开 媒体 → 添加,F12 → Network,勾选 Preserve log,再上传一张已知大小的测试图(例如 2MB JPEG):
- 找到指向
async-upload.php(经典上传)或admin-ajax.php/ RESTwp/v2/media(区块编辑器、部分插件)的请求。 - 看 Status :
- 200 且响应是 JSON(含
id、url)→ 服务端接收基本成功,问题多半在后续缩略图生成、对象存储同步或前端显示; - 413 → 几乎肯定是 Nginx/Apache/CDN 的请求体上限;
- 403 / 401 / 406 → 优先怀疑安全插件、WAF、主机防火墙、错误的防盗链;
- 500 → 翻
wp-content/debug.log与 PHP-FPM/Nginx error log,常是权限、内存、或某个上传钩子 Fatal; - 空 body / 连接重置 → 常见于
post_max_size过小导致 PHP 直接丢弃 POST,或进程被 OOM 杀掉。
- 200 且响应是 JSON(含
- 对照后台文案:
- 「超过了最大上传限制」→ 先走第二步 PHP/Web 上限;
- 「无法写入上传目录」→ 第三步权限;
- 笼统「HTTP 错误」→ 必须靠 Network + 日志,不要只盯媒体库红字。
- 顺手在 工具 → 站点健康 → 信息 → 服务器 记下当前
upload_max_filesize、post_max_size、memory_limit、max_execution_time。站点健康里的值与phpinfo()/ 面板不一致时,以 实际处理该请求的 PHP-FPM 池 为准(多版本 PHP 主机很常见)。
生产排查时固定用同一张测试图、同一浏览器无痕会话;每改一处只复测一次上传,并保留改之前的配置截图/备份。扩展名先用 .jpg/.png,排完再测 .webp/.svg(后两者常被安全策略单独限制)。

第二步:对齐 PHP 体积与 Web 服务器请求体上限
目标很简单:浏览器能发出的包,PHP 与前置代理都能完整收进来。最小可核对片段(数值按业务改,示例为 64M):
ini
; php.ini 或 .user.ini / 面板「PHP 配置」
upload_max_filesize = 64M
post_max_size = 64M
memory_limit = 256M
max_execution_time = 120
max_input_time = 120
注意:post_max_size 必须 ≥ upload_max_filesize;只改其中一个不够。改完后重启 PHP-FPM(或面板里「重载 PHP」),再回站点健康确认数值已变。
若前面是 Nginx:
nginx
# http / server / location 任一合适层级
client_max_body_size 64m;
Apache 则查 LimitRequestBody,以及 mod_security 是否另有请求体限制。Cloudflare / 国内 CDN 也有上传大小档位------边缘直接 413 时,本地 php.ini 怎么改都无效,要在 CDN 控制台或回源规则里放宽,或对 wp-admin 上传路径绕过不合理的边缘限制。
WordPress 侧还会读 wp_max_upload_size()(取 PHP 上限与常量的较小值)。若在 wp-config.php 里自定义过相关过滤,确认没有把上限又压回去。多站点网络管理里另有「最大上传文件大小」选项,子站受网络级限制时,单站 php.ini 再大也传不上去。
改完:清 opcode 缓存(若有)→ 无痕再传同一张图。仍失败且已不是 413/「超过最大上传限制」,带着 Network 证据进权限与安全插件,不要反复只调体积数字。
上传与常见报错的对照(含体积、权限、插件拦截等入口)可放在同一张表里核对,避免只改了一侧:可参考 常见报错速查,把「媒体库 HTTP 错误」和「超过最大上传限制」两条链路一起过一遍。
第三步:uploads 目录权限、属主、open_basedir、磁盘
体积已够但仍写失败时,查文件系统:
- 路径 :默认是
wp-content/uploads/YYYY/MM/。确认wp-content、uploads、当年月目录都存在;若「按月组织」开启但目录创建失败,后台常直接报无法创建目录。 - 属主 :PHP-FPM / Apache 运行用户(常见
www-data、nginx、面板虚拟主机用户)必须能在该目录创建文件。属主是root而 PHP 是www时,表现就是间歇或必然写失败。 - 权限 :目录常见
755(或主机要求的750),文件644。不要 图省事把uploads递归改成777长期挂着------排障临时对比可以,确认后应收紧,并记进变更说明。 - open_basedir :面板或
php.ini若把可访问路径收得很死,可能挡在uploads或临时目录(upload_tmp_dir/ 系统/tmp)之外。debug.log里出现open_basedir restriction就是这类。 - 磁盘与 inode :
df -h与df -i;磁盘满或 inode 耗尽时,小文件也会「上传失败」,和权限文案容易混淆。 - 只读挂载 / 容器卷:容器、部分 PaaS、或误把站点挂成只读时,本地上传必挂;这类环境通常应走对象存储,而不是硬改权限。
用 SSH/面板文件管理建一个测试文件到 uploads 下,能建再删,比只看数字权限更直接。若仅「大图失败、小图成功」且体积已放宽,回头查 max_execution_time、GD/Imagick 生成多尺寸时是否超时或内存不够------那是后处理阶段,不是「没收进 PHP」。
第四步:安全插件、WAF,以及对象存储 / CDN
前三步都干净,Network 仍 403/「HTTP 错误」,或本地文件已在 uploads 但前台裂图,查这一层:
安全 / WAF
- Wordfence、iThemes、Sucuri、主机 ModSecurity、云 WAF:查封锁日志里是否有
async-upload.php、admin-ajax.php、wp-json/wp/v2/media。 - 临时对管理员 IP 或上传路径做放行对比(只改一条规则、测完记结果);确认是误杀后再做长期白名单,不要为了传图长期关掉整站防火墙。
- 禁用「扫描上传文件扩展名过严」类选项时,优先收紧到允许的业务类型(jpg/png/webp/pdf),而不是全开。
- 登录会话/nonce 过期时,上传也可能变 403;换无痕重新登录再测,排除「权限其实没问题」。
对象存储与 CDN
- 已装 OSS/S3/COS 插件时:看插件日志是否在「本地保存成功」之后同步失败(密钥、Endpoint、Bucket 地域、ACL)。
- 「仅本地」开关:排障时可先改为本地存储对比;若本地正常、开 OSS 即裂图,问题在存储插件而非 WP 核心上传。
- CDN 回源:媒体 URL 被改成 CDN 域名后,回源 Host、鉴权、防盗链配置错误会导致后台能预览、前台 403/404。
- 迁移过后常见:数据库里附件 URL 仍是旧域名/旧 Bucket;那是 URL 替换问题,不是「这一次上传」失败------别和当前上传故障混治。
每改一类(只动一条 WAF 规则,或只切换 OSS 本地/远程),无痕复测一次上传,并保留规则导出,方便回滚。
验证与回滚
建议验收动作(同一无痕管理员会话):
- 上传 1 张小于当前上限的 JPEG → 媒体库出现缩略图,附件详情 URL 可访问。
- 再传 1 张接近但不超过上限的大图 → 应成功;再传一张明确超过上限的图 → 应得到清晰的「超过最大上传限制」类提示,而不是含糊 HTTP 错误(说明上限与报错路径一致)。
- 区块编辑器与「媒体 → 添加」各测一次,避免只修了经典上传、REST 上传仍被拦。
- 若启用了对象存储:确认本地
uploads与远端对象都有文件,前台 URL 200。 - 回滚策略:php.ini / Nginx 体积改动可回退到变更前备份;权限临时
777必须收紧;WAF 放行规则可单条撤销;OSS 插件先切回本地再查密钥。不要在未备份时批量停用全部安全插件。
排障窗口尽量短;确认无误后关掉临时打开的 WP_DEBUG_LOG 啰嗦级别,恢复生产基线。
验收清单(技术)
- Network:上传请求(
async-upload.php/ REST media)状态与响应已核对,能区分 413、403、500、空 body -
upload_max_filesize≤post_max_size;Nginxclient_max_body_size(或 Apache 等价)≥ 业务需要;站点健康数值已刷新 -
wp-content/uploads(含年月目录)属主正确、目录可写;open_basedir/ 磁盘 / inode 无挡 - 安全插件与 WAF 日志无误杀上传 POST;必要时仅对管理员或上传路径放行并已复测
- 对象存储/CDN:本地与远端一致,或已切回本地验证核心上传正常;附件 URL 可访问
- 小图 + 近上限大图 + 区块编辑器路径均已复测;临时调试项与过宽权限已收紧