软件版本

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-fpmps 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;
        }
    }