nginx 访问 index.php 文件变成下载
软件版本
php7 回退到 php5.6
nginx 1.10
前言
之前也碰到这样情况,好像就是php语言的解释器 fastcgi 没有配置正确。
记得当时在 server 中加了一段类似下面这样的配置
location ~ \.php$ {
#root /home/wwwroot;
fastcgi_pass 127.0.0.1:9000;
#fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
#fastcgi_pass unix:/tmp/php-cgi.sock;
try_files $uri /index.php =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
fastcgi_pass
还有过类似 # 号注释起来的两种取值。两者区别:Nginx 中 fastcgi_pass 的配置问题。
Nginx 和 PHP-FPM 的进程间通信有两种方式,一种是 TCP,一种是 UNIX Domain Socket(tcp 对应的 ip 形式,unix 对应 unix 形式)。
简单来讲就是,tcp 形式可以跨服务器(网络)通信,而 Unix 形式不经过网络,只能用于 Nginx 跟 PHP-FPM 都在同一服务器的场景。
php-fpm 两个配置文件 /etc/php-fpm.conf
和 /etc/php-fpm.d/www.conf
。其中 /etc/php-fpm.d/www.conf
配置文件中包含了 php-fpm 运行的用户和用户组和 fastcgi 的默认通讯形式,我的默认配置:
#很重要
listen = 127.0.0.1:9000
listen.allowed_clients = 127.0.0.1
#很重要
user = apache
group = apache
所以 fastcgi_pass
根据 php-fpm 配置文件设置成 127.0.0.1:9000
,注意 nginx 的 vhost 设置每一句末尾要加上分号。
然后就是运行用户和用户组了。php-fpm 运行的用户和用户组应该与 nginx 运行的用户及用户组一致。可用 ps aux | grep php-fpm
和 ps aux | grep nginx
查看软件运行用户和用户组(nginx 运行用户在 nginx.conf
中有定义)。
tip:每次修改软件的配置文件,都需要重启才能生效。
service nginx restart
service php-fpm restart
或
systemctl restart nginx
systemctl restart php-fpm
service和systemctl
service 命令其实是去 /etc/init.d
目录下,去执行相关程序。其中有些脚本需要我们自己编写,如 redis。
systemctl 命令兼容了 service ,即 systemctl 也会去 /etc/init.d
目录下,查看,执行相关程序。systemctl 还可以命令管理 systemd 的资源 Unit。
两个命令不一定都存在。
如果 service 和 systemctl 指令都启动不了,说明你的 PHP 有可能是编译安装的,PHP-FPM 启动方式:php-fpm 的重启方法(php7.3) 。可以 php-fpm -v
或者 which php-fpm
查看是否 php-fpm 是否在 path 中,如果 php-fpm 在 path中(可以直接调用)并且暂未启动,可以直接 php-fpm
就可以启动了。启动时会自动引入其配置文件,所以直接输入指令即可。
正文
一步一步排查问题:
1.检查 php-fpm 是否启动。
两种方式:
- 查看 php-fpm 进程是否存在
- 查看 9000 端口是否被占用
当 Nginx 与 php-fpm 通讯方式为 TCP,9000 端口会被调用,而两者一般情况下,都是以 TCP 方式通讯,所以 9000 端口是否被占用可以作为一种检验方式。
# 查看 php-fpm 进程
ps aux |grep php-fpm
或者
netstat -antp | grep 9000
如果 php-fpm 没有启动,我们就需要手动启动 php-fpm 进程了。
# 以服务形式运行
service php-fpm start
# 正常编译安装
## 查找执行文件位置
find / -name php-fpm
## 执行
.../bin/php-fpm
2.用一个测试文件看看是否能解析 php 文件
echo '<?php echo phpinfo()' > /path/to/nginx/html/info.php
然后 ip 或域名拼接上文件名,看是否可以看到 php 配置信息。
如果查看不了,可以参考前言部分,配置 php-fpm 和 nginx。也可以查看 nginx 错误日志,看看是什么错。
我的 nginx 错误目录为:/var/log/nginx/error.log
。如果不一致,也可以 find / -name error.log
或者 find /-name nginx
一个个排查路径,找到错误日志。
3.到了这步,php 解析没有问题了,那就只剩下一些 url 优化,或者索引文件问题了。
检查一下虚拟主机对应的 root 地址下,是否有 index.php 文件。检查一下 nginx 的默认配置里是否有 index
项:
index index.html index.htm index.php;
然后就是 URL 改写(优化)了。我用的是 ci 框架,一般都会在项目根目录下放置一个 .htaccess
文件。
防止 .htaccess
文件被读取(server 下添加):
location ~ /\.ht {
deny all;
}
平常迁移代码都没什么问题(不管是 nginx 还是 apache ),直接就可以读到并且跳转到 ci 配置的默认路由下:
<IfModule mod_rewrite.c>
RewriteEngine On
# RewriteBase /
RewriteCond %{REQUEST_URI} ^system.*
RewriteRule ^(.*)$ /index.php?/$1 [L]
RewriteCond %{REQUEST_URI} ^application.*
RewriteRule ^(.*)$ /index.php?/$1 [L]
RewriteCond $1 !^(index\.php|assets|upload)
RewriteRule ^(.*)$ index.php?/$1 [L]
</IfModule>
这次不灵了,怀疑是不是这次装的 nginx 根本就没有去读取 .htaccess
文件?我就把这个文件删掉了,果然没有任何变化。
.htaccess
文件不起作用,那就只能往 vhost 的 server 配置上想办法了。
找了一个替换方案,作用就是把请求中的 index.php? 部分去除
## 针对 php 低版本,try_files 指令不认识,以下是兼容写法
if (!-e $request_filename) {
rewrite ^.*$ /index.php last;
}
还有文档提到一个方案,就是 location ~ \.php$
部分改成 location ~ .*\.php$
。我是在加了这个之后,并且添加了 url 改写部分配置,变好的。但后来发现:有个虚拟主机在 chrome 浏览器还是有点小问题,我在其他浏览器或者其他人电脑的相通版本的 chrome 浏览器上查看都是好的,但我自己的电脑上直接用域名访问,还是会出现下载文件的情况。如果直接访问index.php 文件或者加上路由信息 /c/a 都变现正常,这很奇怪,烦了很久也没找到答案。
结尾
中间不自信,感觉 php7 可能会带来一些新的麻烦,再加上老板、产品不断地催促,就改成 php56 版本了。
但这并没有解决问题,最终还是慢慢推敲,一步一步才完结的。
如果中间尝试了各种方法仍然没有起作用的话,尝试清一下浏览器缓存。我有过多次配置好之后,不起作用的情况,结果清楚缓存或者换一个浏览器尝试证明,配置已经是好的了。
完整 server 配置:
server
{
listen 80;
server_name platform.xx.com;
index index.html index.htm index.php;
root /usr/share/nginx/html/xx/platform;
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
location / {
try_files $uri $uri /index.php$uri;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
location ~ /\.ht {
deny all;
}
if (!-e $request_filename) {
rewrite ^.*$ /index.php last;
}
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
{
expires 30d;
}
location ~ .*\.(js|css)?$
{
expires 12h;
}
error_log /var/log/nginx/platform.error.log;
access_log /var/log/nginx/platform.access.log;
}
另附:隐藏 index.php 文件名的兼容写法
location / {
try_files $uri $uri/ /index.php$uri;
# nginx 低版本兼容版
if (!-e $request_filename) {
rewrite ^(.*)$ /index.php?s=$1 last;
rewrite ^/(.*)$ /index.php/$1 last;
break;
}
}