Nginx+PHP5.6-FPM环境下仅index.php可执行,其余PHP文件被下载
我来帮你搞定这个头疼的问题——你猜的完全没错,根源确实在rewrite规则和Nginx的location匹配逻辑上!
问题分析
你的配置里,location /块中的if (!-e $request_filename){ rewrite ^(.*)$ /$1.php break; }是罪魁祸首:
- 当你访问
/product这类不带.php的路径时,rewrite会把它转成/product.php,但你用了break标记——这个标记会让Nginx终止当前location的处理流程,不会重新发起location匹配。 - 结果就是,rewrite后的
.php请求并没有进入到专门处理PHP的location ~* \.php(/|$)块,Nginx还是把它当成普通静态文件返回,自然就被浏览器下载了。 - 另外,Nginx官方其实非常不推荐在
location /里使用if块,它的行为经常会超出预期。
修复方案
我们分两步调整配置,既解决问题又符合Nginx最佳实践:
1. 替换if块为try_files(推荐)
把location /里的if逻辑删掉,换成try_files指令,这是Nginx官方推荐的处理静态文件和路由的方式:
location / { # 保持你的业务rewrite规则,但把break改成last rewrite ^/(.*)/p/(.*)?$ /product.php?slug=$2 last; rewrite ^/?([A-Za-z0-9_-]+)/?$ /vendor.php?vendor=$1 last; # 用try_files替代if块,自动尝试匹配文件、目录、加.php的路径 try_files $uri $uri/ $uri.php =404; }
last标记会让rewrite后的请求重新匹配所有location,这样转成.php的请求就能被PHP处理块捕获。
2. 调整其他rewrite块的标记
把其他业务location里的break也换成last,确保所有rewrite后的请求都能正确进入对应处理块:
location /cart { rewrite ^/cart/?$ /cart.php last; } location /checkout { rewrite ^/checkout/?$ /checkout.php last; } # 其他类似的location块都做同样修改
3. 检查PHP处理块的配置
你的PHP处理块整体没问题,但要注意include nginxconfig.io/php_fastcgi.conf可能已经包含了部分fastcgi参数,比如SCRIPT_FILENAME,如果重复定义可能有冲突。可以打开这个文件确认一下,如果里面已经有fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;,可以把你自己写的fastcgi_param SCRIPT_FILENAME $request_filename;删掉,避免冲突。
测试与生效
修改完配置后,先验证配置语法是否正确:
nginx -t
如果输出test is successful,就重启Nginx让配置生效:
# 系统是systemd的话用这个 systemctl restart nginx # 老系统用这个 service nginx restart
这样调整后,除了index.php之外的其他PHP文件应该就能正常执行了。
内容的提问来源于stack exchange,提问作者Olubodun Agbalaya

