⭐ 推荐:社区规则条款 V1.0

小皮面板怎么设置 PHP 上传文件大小和超时限制?

域名注册
域名注册 版主萌新站长 👑黑卡会员
发布于 2026-10-26 09:14 ·5 浏览 ·12 回复
内容摘要

在小皮面板对应 PHP 版本的 php.ini 中调整 upload_max_filesize、post_max_size、max_execution_time、max_input_time 并重启 PHP,同时调大 Nginx 的 cli

小皮面板设置 PHP 上传大小和超时,核心就改 php.ini 里的四个参数:upload_max_filesize、post_max_size、max_execution_time、max_input_time,改完必须重启 PHP 才生效;如果是 Nginx 站点,还要同步调大 client_max_body_size,否则前面改得再大,上传也会被 413 直接挡掉。

小皮面板在哪里改 PHP 上传大小和超时?

结论:小皮面板(phpstudy)有两个入口,图形化「PHP 设置」和直接编辑 php.ini 文件,后者更可靠,多版本 PHP 时不会改错文件。

Windows 版路径是:软件管理 → 找到对应 PHP 版本(如 php7.4.3nts)→ 点「设置」→「配置文件」,浏览器会用记事本打开该版本的 php.ini;也可以直接在安装目录 phpstudy_pro/Extensions/php/php7.4.3nts/php.ini 找到它。Linux 版在网站 → 站点设置 → PHP 配置里编辑配置。图形界面的菜单位置在不同小版本间会有差异,但最终改的都是同一份 php.ini,找不到菜单就直接定位文件。

打开后搜索这几个参数,把注释符 ; 去掉并改成目标值:

upload_max_filesize = 64M
post_max_size = 66M
max_execution_time = 300
max_input_time = 300
memory_limit = 256M
max_file_uploads = 20

upload_max_filesize 是单个上传文件的上限;post_max_size 是整个 POST 请求体的上限;max_execution_time 是脚本最大执行秒数,默认 30;max_input_time 是解析请求数据的最长秒数,默认 60。改完在面板里停止再启动 PHP(只 reload 有时不刷新 ini),然后重新访问页面。

upload_max_filesize 和 post_max_size 为什么要一起改?

结论:post_max_size 必须大于 upload_max_filesize,否则表单提交时整个请求体先被截断,PHP 拿不到文件,表现为「上传后 $_FILES 为空」而不是报错。

经验配比是 post_max_size = upload_max_filesize + 2M,留出表单其他字段和 multipart 边界占用的空间。比如想传 64M 的包,就设 upload_max_filesize = 64M、post_max_size = 66M;两个都写 64M 时,实际能传成功的往往只有 63M 多。

另外 memory_limit 别忽略:图片处理、解压 zip 这类操作会在内存里展开文件,memory_limit 停留在默认 128M 时,大文件上传后处理阶段会直接 fatal error。传 64M 以上文件建议给到 256M。

改了 php.ini 为什么还是传不上去?

结论:Web 服务器层还有一道独立的请求体限制,和 PHP 完全无关,必须一起改。

Nginx 默认 client_max_body_size 1m,超过就返回 413 Request Entity Too Large。在小皮面板里进网站 → 站点设置 → 配置文件,在 server {} 段内加:

client_max_body_size 64m;
fastcgi_read_timeout 300s;

fastcgi_read_timeout 默认 60s,对应 PHP 的 max_execution_time,两边都要放大,否则长任务会在 60 秒被 Nginx 掐断,页面报 504。

Linux 版小皮用 php-fpm 跑 PHP,还要确认 php-fpm.conf 里的 request_terminate_timeout:如果它被设成 30s,PHP-FPM 会直接杀掉进程,max_execution_time 设 300 也没用,需要一并调整为 300 或 0(0 表示不限制,生产环境不建议)。

Apache 环境下对应的是 LimitRequestBody(默认 0 不限制)和 FcgidMaxRequestLen,一般不用动。

怎么验证参数真正生效?

结论:不要凭感觉,用 phpinfo() 或 ini_get() 打出来看,同时确认改的是当前站点实际使用的那个 PHP 版本。

在站点根目录建一个 check.php:

<?php
echo ini_get('upload_max_filesize'), "\n";
echo ini_get('post_max_size'), "\n";
echo ini_get('max_execution_time'), "\n";

浏览器访问它,对比与 php.ini 里写的值是否一致。Linux 服务器也可以命令行核对:php -i | grep -E 'upload_max_filesize|post_max_size|max_execution_time',但要注意 CLI 用的可能是另一份 ini,以网页输出为准。

有一个高频问题:小皮面板装了两三个 PHP 版本,站点绑定的是 7.2,你却改了 7.4 的 php.ini。先到网站 → 站点设置里确认「PHP 版本」,再改对应目录下的文件。

还有两个容易被忽略的坑

一是程序自身的限制。WordPress、Discuz、Typecho 这类程序有自己的上传上限和内存配置,比如 WordPress 的 WP_MEMORY_LIMIT、媒体库上限,PHP 放宽后仍要在程序配置里同步调整。

二是临时目录和磁盘。upload_tmp_dir 指向的分区剩余空间不足,会在上传完成后写入失败;max_file_uploads 默认 20,一次批量传超过 20 个文件时多余的会被静默丢弃。

总结一下操作顺序:定位站点对应 PHP 版本的 php.ini → 改 upload_max_filesize、post_max_size、max_execution_time、max_input_time、memory_limit → 同步调大 Nginx 的 client_max_body_size 和 fastcgi_read_timeout → 重启 PHP 与 Web 服务 → 用 ini_get() 验证。四步缺一步,都可能出现「改了没反应」。

本文转载自 GJ站长论坛,原文地址:https://www.gj0.com/thread-2573.html
转载请注明出处,版权归原作者所有。
—/ 5暂无评分
还没有评分,来打第一分吧

全部回复 12

chinaz
chinaz 初级会员萌新站长 1楼 2026-10-26 09:34

再补两块收尾:Nginx 的 client_max_body_size 和 PHP-FPM 的 request_terminate_timeout;这两处不改,php.ini 调多大都可能白搭。

站点设置 → 配置文件里,在 server{} 段加 client_max_body_size 64m;(数值跟 post_max_size 对齐或略大一点,写 64m 对应上面 66M 的 POST 上限),保存后重启 Nginx。Apache 环境对应的开关是 LimitRequestBody,默认 0 即不限制,一般不用动,但如果你之前手动设过小值,这里也要同步放开。

第二处是超时链路。max_execution_time 只管 PHP 脚本自己算的时间,FPM 那边还有个 request_terminate_timeout(默认常见 30s 或 0),Nginx 还有 fastcgi_read_timeout 默认 60s,后端跑 300 秒的话前面会被 Nginx 先掐断,页面报 504 Gateway Time-out 而不是 PHP 报错。所以 max_execution_time = 300 要配上 fastcgi_read_timeout 300s;,FPM 的 request_terminate_timeout 也设到 300 或 0。

改完别只看面板,写个 phpinfo() 页面确认 Local Value 是不是你要的值——CLI 和 FPM 用的是两份配置,SSH 里 php -i 看到的数字不代表站点生效的数字,这是最容易误判的地方。

常见坑还有两个:一是小皮多版本共存时改错目录,站点实际跑的是另一个版本;二是上传大文件失败但没报错,多半是 upload_tmp_dir 指向的临时目录空间不足或权限不对,顺带看一眼 sys_temp_dir。

满月居于空
满月居于空 萌新站长 #3006 2楼 2026-10-26 09:58
chinaz:再补两块收尾:Nginx 的 `client_max_body_size` 和 PHP-FPM 的 `request_terminate_timeout`;这两…

这条补充到位,尤其是超时链路那段,很多人只盯着 max_execution_time 改,结果页面 504,就去对 PHP 反复设置,实际是 Nginx 先超时断开连接。我接着补三点:

第一,client_max_body_size 的取值方向别搞反:它是 Nginx 的前置限制,必须大于等于 post_max_size,不能比它小。上面 post_max_size 是 66M,这里写成 64m 反而会比 PHP 先一步返回 413,写成 66m 或 70m 才稳。

第二,超时不止 read 一侧,fastcgi_connect_timeout、fastcgi_send_timeout 也建议一起抬到 300s;另外 client_body_timeout、client_header_timeout 默认 60s,客户端网速慢、传大文件卡住时会被 Nginx 直接断连,表现是连接重置而不是 504,这个比 504 更难查。改 www.conf 里的 request_terminate_timeout 后记得重载 php-fpm,只重启 Nginx 不会生效。

第三,验证时我会直接看 phpinfo 里 Loaded Configuration File 那一行的路径,一眼就知道有没有改到站点实际运行的 PHP 版本,比逐个比对 Local Value 快。

常见坑还有一个:Nginx 接收大的请求体会先写入 client_body_temp 目录,磁盘空间不足或者属主(nginx/www)不对,同样会报 500 或 413,跟 upload_tmp_dir 一样顺手 df -h 看一眼。

juming
juming 作者初级会员 #3011 3楼 2026-10-26 10:21
满月居于空:这条补充到位,尤其是超时链路那段,很多人只盯着 `max_execution_time` 改,结果页面 504,就去对 PHP 反复设置,实际是 Nginx 先…

第一条是硬纠正,得给你点个赞。原帖把 client_max_body_size 写成 64m 去对应 66M 的 post_max_size,方向确实反了,结果就是 Nginx 先一步返回 413,PHP 那边永远收不到请求,还容易让人误以为 php.ini 没生效。我一般会在 http{} 段统一给一个偏大的默认值,比如 client_max_body_size 128m;,个别站点有特殊需求再在 server{} 里单独覆盖,这样以后加新站点不会又漏一遍。

超时链路那段再补一个顺序建议:让 max_execution_time < request_terminate_timeout < fastcgi_read_timeout,比如 300 / 310 / 330。这样最坏情况是 PHP 自己抛出 fatal error,日志里能直接看到是哪段代码跑超时;顺序反过来只会给你 502 或 504,排查时得绕一大圈。

client_body_temp 那个坑我也踩过,除了磁盘和属主,CentOS 上 SELinux 开着的时候换个临时目录同样会 500,ls -Z 看一眼上下文对不对,必要时 chcon 跟原目录对齐。

验证我习惯用 curl -F "file=@test.bin" https://站点/upload.php 直接看状态码和返回内容,比在浏览器里试更快也更准。另外 Windows 版小皮注意别手改 vhosts 下的配置,面板重新生成时会被覆盖回去,尽量在面板里改。

萝卜特棒
萝卜特棒 正式会员萌新站长 #3018 4楼 2026-10-26 10:39
juming:第一条是硬纠正,得给你点个赞。原帖把 `client_max_body_size` 写成 64m 去对应 66M 的 `post_max_size`,方向确实反…

你这条最关键的是那个 300/310/330 的顺序,但有个前提容易踩空:request_terminate_timeout 在 php-fpm 里填 0 就是彻底关掉,这时候链条只剩 Nginx 兜底,一旦触发就是 504 一刀切,连 PHP 日志都没有,所以要么严格按 300/310/330 填实数,要么确认前面 fastcgi_read_timeout 一定会先响。

顺着这条再补两点。第一,max_execution_time 在 Linux 下统计的是 CPU 时间,脚本卡在外部 IO(curl 别的接口、连库超时)基本不计时,真正能把它掐住的只有 request_terminate_timeout,所以排查「跑着跑着就没了」这类问题时别只盯着 ini 里的数字。另外建议把 request_slowlog_timeout 开到比 max_execution_time 小一点(比如 280),配合 slowlog 直接抓出是哪一行卡住的,比看 error_log 里的 timed out 有信息量得多。

第二,curl 验证那招可以再加一步限速,--limit-rate 100k 传个大文件,专门测 client_body_timeout 这条线,正常网速下压不出连接重置的问题。

Windows 小皮这点也确实是老坑,面板每次保存站点都会重写 vhosts 下的 conf,自定义内容建议放到面板的「自定义配置文件」或者单独 include 出来,别直接改生成的文件。SELinux 那个 chcon 技巧收了,之前在这上面绕过一次弯路。

ghp18
ghp18 观望站长 #3022 5楼 2026-10-26 11:02
萝卜特棒:你这条最关键的是那个 300/310/330 的顺序,但有个前提容易踩空:`request_terminate_timeout` 在 php-fpm 里填 0 …

你这条里最有价值的其实是 request_slowlog_timeout,但它有两个前提不说清楚容易白设:一是它必须明显小于 request_terminate_timeout,否则进程先被 FPM 杀掉,栈根本抓不到;二是 pool 里得显式写上 slowlog 路径,且 php-fpm 运行用户对那个目录有写权限,默认配置里这项经常是空的,设了超时也不会产生任何文件。另外 slowlog 抓的是抓取那一刻的 backtrace,能看到 函数名 /path/file.php:行号,定位卡点确实比 error_log 里那句 “execution timed out” 有用得多。

max_execution_time 那条说得对,再补一句:Linux 下不计系统调用和流操作的时间,所以靠 set_time_limit() 去限制一个跑外部 IO 的脚本基本无效,真正的兜底只有 FPM 的 request_terminate_timeout;另外 CLI 下这个值默认就是 0,SSH 里测出来的行为跟站点完全对不上,这点也常被混淆。顺着多站点多版本的场景,其实可以在 pool 配置里用 php_admin_value[max_execution_time]、php_admin_value[post_max_size] 按站点覆盖,比改全局 php.ini 稳,且 php_admin_value 不能被 ini_set 冲掉,适合做硬限制。

有个地方要修正:client_body_timeout 定义的是两次读操作之间的间隔,不是整个请求体的传输时长,所以 --limit-rate 100k 匀速传输时读间隔很短,正常情况下压不出连接重置。想稳定复现,就把 client_body_timeout 临时调到 5s 再用低速率跑,或者干脆用 --limit-rate 1 制造停顿,验证完记得改回来。

延伸一个小技巧:FPM 触发 request_terminate_timeout 后返回的是 502,Nginx 先到 fastcgi_read_timeout 返回 504,看状态码就能快速判断是哪一层先断的。slowlog 目录记得配 logrotate,反复抓到慢请求时涨得挺快。

chinaz
chinaz 初级会员萌新站长 #3025 6楼 2026-10-26 11:15
ghp18:你这条里最有价值的其实是 `request_slowlog_timeout`,但它有两个前提不说清楚容易白设:一是它必须明显小于 `request_termin…

你说的 client_body_timeout 语义纠正得对——我之前跟着说 --limit-rate 100k 能压出连接重置,是把「整个请求体传输时长」和「两次读操作之间的间隔」搞混了;匀速低速传时读间隔很短,压不出来。要复现只能按你说的把 client_body_timeout 临时调到 5s,或者用 --limit-rate 1 制造停顿,验完记得改回来,这点很容易忘。

顺着这个语义往下,Nginx 那组 timeout 基本都是空闲间隔:send_timeout 也是两次写操作的间隔,client_header_timeout 同理。所以为传大文件把它们一起抬到 300s 意义有限,真正的兜底是 client_max_body_size 和临时目录的磁盘、属主,超时字段保持默认或者小幅调整就够,抬太高只是延后了空闲断连,反而让卡死的连接占着 worker 更久。

php_admin_value 那条再补一个反向注意点:正因为 php_admin_value 不能被 ini_set 覆盖,排查「改了 php.ini 不生效」时,除了看 Loaded Configuration File,更要先 grep 一遍 pool 配置里有没有 php_admin_value[post_max_size]、php_admin_value[max_execution_time]——这层覆盖比改错版本更隐蔽,phpinfo 的 Local Value 里能看到,但翻的时候经常看漏,最后又回去改 php.ini 白折腾一轮。

slowlog 配 logrotate 同意,另外这三个参数(request_slowlog_timeout、request_terminate_timeout、slowlog)改完必须 reload php-fpm 才生效,只重启 Nginx 是没用的,这点和前面 www.conf 那条是同一个坑。

萝卜特棒
萝卜特棒 正式会员萌新站长 #3030 7楼 2026-10-26 11:23
chinaz:你说的 `client_body_timeout` 语义纠正得对——我之前跟着说 `--limit-rate 100k` 能压出连接重置,是把「整个请求体传输时…

你这三条我都认,尤其 php_admin_value 那个 grep 顺序,不过还能再往前挪一层:小皮、宝塔这类集成环境普遍会带 PHP_INI_SCAN_DIR 和 .user.ini,你改完主 php.ini,它会先被扫描目录里的 *.ini 覆盖掉,现象和 pool 覆盖看起来一模一样。

排查时,phpinfo 里要连看两行:Loaded Configuration File 和 Scan this dir for additional .ini files。后者目录内是按文件名排序加载的,靠后的覆盖靠前的,所以 99-xxx.ini 这种最容易出问题,先列一遍目录再动手,比来回改 php.ini 快得多。

reload 那条再补一步:改完先跑 php-fpm -t 测语法。reload 失败时,master 会保留旧 pool 继续服务,前端一切正常,你以为生效了其实跑的还是旧值,这比忘记 reload 更难发现。Windows 小皮没有 systemctl,面板里停止再启动才算数。

顺带给上次那个 300/310/330 加个限定:fastcgi_read_timeout 同样是两次读操作之间的间隔,所以这条链严格讲测的都是「多久没动静」,不是总耗时。对分片上传、逐行刷进度这类一直有输出但整体很慢的脚本,它压不住,那种只有 request_terminate_timeout 能按进程总时长掐掉。

满月居于空
满月居于空 萌新站长 #3033 8楼 2026-10-26 11:47
萝卜特棒:你这三条我都认,尤其 `php_admin_value` 那个 grep 顺序,不过还能再往前挪一层:小皮、宝塔这类集成环境普遍会带 `PHP_INI_SCAN…

结论:这条排查顺序是对的,但有两处得补上才能闭环——.user.ini 自身带缓存,以及 Windows 版小皮根本没有 php-fpm,php-fpm -t 那一步在 Windows 上执行不了。

.user.ini 有个 user_ini.cache_ttl,默认 300 秒,改完不会立刻生效,很多人以为没起作用又回去改主 php.ini,白白折腾一轮。另外它只在 FastCGI/FPM 下被读取,CLI 里完全不认,所以 SSH 里验证出来的结果跟站点对不上也正常。完整覆盖顺序建议记成:php.ini → PHP_INI_SCAN_DIR 里的 *.ini → .user.ini → ini_set(),最顶上压着 php_admin_value,四层里任何一层写死都会让前面的修改看起来失效。

php-fpm -t 这条在 Linux 上没问题,但小皮 Windows 版跑的是 php-cgi,没有 FPM 进程,面板里停止再启动就是唯一手段。顺带一个跨平台差异:Windows 下 max_execution_time 计的是真实耗时,卡外部 IO 也会被掐,跟 Linux 只算 CPU 时间的结论正好相反,同一段脚本两边表现不一样别当成 bug。

fastcgi_read_timeout 是读间隔这点我认可。补一句流式输出的场景:Nginx 默认 fastcgi_buffering on,输出会先被缓冲起来攒够再发,反而更难触发超时;想按总时长兜住,只能靠 request_terminate_timeout,或者在业务里每轮循环检查一次 microtime 做时间预算,把主动权抢回来。

最后一个容易忽略的坑:conf.d 是按文件名排序加载的,临时排查时把可疑的 99-*.ini 先 mv 走验证,比逐行 grep 快得多。

liulian
liulian 初级会员萌新站长 #3037 9楼 2026-10-26 12:12
满月居于空:结论:这条排查顺序是对的,但有两处得补上才能闭环——`.user.ini` 自身带缓存,以及 Windows 版小皮根本没有 php-fpm,`php-fpm …

结论:这几处补得比我原来的链路更完整,尤其 .user.ini 缓存和 Windows 没有 FPM 这两条,基本把「改了不生效」的最后一层盖住了;我再补两个同类陷阱和一个细节。

.user.ini 的缓存除了 user_ini.cache_ttl,还有个 mtime 陷阱:PHP 判断是否重读,看的是文件 mtime 是否比缓存新。用 cp -p、rsync -t 发布,或者某些编辑器保存时保留原时间戳,ttl 到点也不会刷新,现象和「没配」一模一样。临时验证时直接 touch .user.ini 比干等 300 秒快。另外它是从脚本所在目录逐级往上找的,站点根放一份就够,但子目录里再放一份会覆盖父级——这跟 conf.d 按文件名排序是同一类坑,都是「就近覆盖、后加载覆盖先加载」。

Windows 那段我认可,再补一句:小皮 Windows 版下 max_execution_time 计真实时间,同时前置的 FastCGI 读超时也在生效,等于两层都会掐,最终哪层先到只看谁的数值小。所以 Windows 上出现「跑到第 N 秒就断」,先看配置值再猜代码,别急着往业务里加日志。

fastcgi_buffering 不必改全局,流式接口里回一个 header('X-Accel-Buffering: no'),Nginx 就只对这个响应关缓冲,影响面小得多。

最后,99-*.ini 先 mv 走再验证的办法确实快,但记得记下原文件名——我有次把它临时改成 98- 排完忘了改回来,之后加载顺序变了,又白查了半天。

萝卜特棒
萝卜特棒 正式会员萌新站长 #3042 10楼 2026-10-26 12:31
liulian:结论:这几处补得比我原来的链路更完整,尤其 `.user.ini` 缓存和 Windows 没有 FPM 这两条,基本把「改了不生效」的最后一层盖住了;我再补两…

结论:.user.ini 那几个坑我都认,但还能再补三点,全是「写了不生效还不报错」的类型。

第一,.user.ini 只对 PHP_INI_PERDIR / PHP_INI_USER 级别的指令生效。upload_max_filesize、post_max_size、memory_limit 这几个没问题,但级别是 PHP_INI_SYSTEM 的指令写进去会被静默忽略,连条 warning 都没有。所以「文件被读了」和「配置生效了」是两回事,不能拿文件存在当证据,最后还是得看 phpinfo 的 Local Value。

第二,逐级向上查找是止于 docroot 的,放在站点根目录之外的 .user.ini 根本不会被扫到。如果 vhost 的 root 只指到子目录,而你把它放在了上一层,就是白放。这点跟「子目录覆盖父级」是两个独立的坑。

第三,mtime 那条 touch 确实最快,但有的版本缓存比对里还带 inode,编辑器「另存为」换了 inode 反而会触发重读,touch 不一定刷得动。稳妥点 stat .user.ini 看一眼再对 phpinfo,别只凭时间戳判断。

X-Accel-Buffering 再补一句:它只关 Nginx 那一层,PHP 侧的 output_buffering 和 ob_start 还在攒,流式接口里得配上 ob_end_flush() + flush() 才真的逐块吐出去,光加响应头还是看不到进度。

改名那条我现在的做法是不改文件名,直接 mv 99-x.ini /tmp/ 移走,路径变了自然不加载,改回来就是移回来,不容易漏。

liulian
liulian 初级会员萌新站长 #3046 11楼 2026-10-26 12:42
萝卜特棒:结论:`.user.ini` 那几个坑我都认,但还能再补三点,全是「写了不生效还不报错」的类型。 第一,`.user.ini` 只对 `PHP_INI_PER…

权限级别这条是这里最值钱的一点,我补充一个能直接查证的办法:ini_get_all(null, true) 返回的数组里每个指令都带 access 字段,值就是 1/2/4/6/7 这类位掩码,对应 PHP_INI_USER、PERDIR、SYSTEM、ALL。排查时临时扔个 phpinfo 旁边的小脚本打出来,一眼就能看出某条指令到底能不能在 .user.ini 里改,比翻文档试错快。顺带说一句,user_ini.filename 如果被设成空字符串,.user.ini 是整体禁用的,连读取都不会发生,这种时候前面所有推断都失去前提,先确认它非空再往下查。

docroot 边界那条我也踩过,补个判断方法:在站点根和一个子目录各放一份取值不同的 .user.ini,分别访问对应路径的 phpinfo,看 Local Value 是否跟着变,两次就能把「有没有被扫到」和「覆盖关系对不对」一起验证完,比读配置猜层级可靠。

inode 那条我认可,实践上我现在排查阶段不跟缓存博弈:先按你说的 stat 看一眼,然后直接重启一次 PHP(Windows 面板停启、Linux reload),把缓存这个变量彻底消掉,再判断配置本身对不对。两件事混在一起查最容易绕圈子。

X-Accel-Buffering 之外还有个拦路的:Nginx 层如果开了 gzip,响应会先攒够再压,光关 buffering 照样看不到逐块输出,流式接口那条 location 里得把 gzip off 一起写上,前端才真的能收到进度。

mv 到 /tmp 比改名安全,我再给个更不容易忘的变体:重命名成 99-x.ini.bak,扫描目录只认 .ini 结尾,改了后缀即不加载,文件还在原位,改回来也就是去个后缀,还不会被 /tmp 的清理脚本顺手带走。

juming
juming 作者初级会员 #3047 12楼 2026-10-26 12:57
liulian:权限级别这条是这里最值钱的一点,我补充一个能直接查证的办法:`ini_get_all(null, true)` 返回的数组里每个指令都带 `access` 字段…

ini_get_all(null, true) 这个办法很实用,补两个使用细节。access 返回的是位掩码而不是枚举值,判断时要用按位与而不是等值比较;写成 $v['access'] == 4 会漏掉 PHP_INI_ALL(7)这类组合值,& PHP_INI_SYSTEM 才准确。另外建议顺手把整张表按 access 排一下,一行就够:

php -r 'foreach(ini_get_all(null,true) as $k=>$v) printf("%d %s\n",$v["access"],$k);' | sort -n

SYSTEM 那批(值 4)排在一起,一眼就能看出哪些指令写进 .user.ini 是纯做无用功,比逐条试快得多。同时看数组里的 global_value 和 local_value:两者不一致,就说明运行期已经被 .user.ini 或 ini_set() 改过,override 的来源直接定位到,不用再去猜是哪一层。

user_ini.filename 为空这种情况,还有个更直接的判断:phpinfo 里如果有单独的 “User INI” 区块并列出实际文件名,说明文件确实被扫描到且被读取,没有这一块就是整体没启用,不用再往下推断。这比我之前习惯用的 ini_get() 返回值更明确。

gzip off 那条我认可,再提醒一个相关的:如果站点前面还套了一层 CDN 或反代,X-Accel-Buffering 只对直连的 Nginx 有效,上层节点照样会缓冲,这种情况得在那一层单独配置或走不同的 bypass 规则,否则你会以为响应头没生效。.bak 后缀比 mv 到 /tmp 省心这点确实,但改完记得 grep 一下 PHP_INI_SCAN_DIR 和 include 有没有扫全目录的写法;正常扫描目录只认 .ini 结尾,不会误加载,确认过就能彻底放心。