Nginx初认识之 Nginx支持PHP和TP5项目 (五) -张柏沛IT博客

正文内容

Nginx初认识之 Nginx支持PHP和TP5项目 (五)

栏目:Linux 发布时间:2020-02-10 22:22 浏览量:271

Nginx支持PHP和TP5项目

在Apache中,PHP是嵌入进Apache中的,而Apache是将PHP作为一个内部模块来运行的。但是对于nginx来说,nginx是把PHP作为一个进程,然后nginx进程和PHP创建的进程进行通信来支持PHP的。所以PHP要单独开一个进程运行,会占用一个端口,这种PHP运行方式叫做fastcgi运行方式。
所以Apache和PHP的关系像是爸爸和儿子,nginx和PHP的关系则是平等关系。
当nginx请求到php文件的时候,会将请求做一次转发,转发给PHP进程,PHP进程来处理这个请求,然后返回响应给nginx再返回给客户端。

根据上面nginx运行PHP的原理,我们就可以写相应的配置:

location ~ \.php$ {     # 当请求PHP文件时,也就是当url中有.php时
    root /var/www/html;     # 将根目录定位到/var/www/html,这里面放着PHP文件,或者是项目的入口文件所在的目录
    fastcgi_pass 127.0.0.1:9000;    # 将请求上下文转发给PHP进程,这个进程一般绑定的是9000端口
    fastcgi_index index.php;    
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;    # 相当于将nginx变量赋值给PHP的$_SERVER['SCRIPT_FILENAME'],作用是告诉PHP进程当前访问的PHP脚本的绝对路径,然后PHP才能找到这个php文件进行处理编译。
    include fastcgi_params;    #引入fastcgi_params文件中的变量,把这些变量发给PHP,如$document_root,$fastcgi_script_name这些变量,如果不引入这些变量,PHP就找不到要请求的PHP文件了。
}

例如请求 http://xxx.com/a/b/test.php ,那么 $fastcgi_script_name变量就是test.php

我们可以打开fastcgi_params这个文件看看:
vi /usr/local/nginx/conf/fastcgi_params

fastcgi_param  QUERY_STRING       $query_string;
fastcgi_param  REQUEST_METHOD     $request_method;
fastcgi_param  CONTENT_TYPE       $content_type;
fastcgi_param  CONTENT_LENGTH     $content_length;

fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;
fastcgi_param  REQUEST_URI        $request_uri;
fastcgi_param  DOCUMENT_URI       $document_uri;
fastcgi_param  DOCUMENT_ROOT      $document_root;
fastcgi_param  SERVER_PROTOCOL    $server_protocol;
fastcgi_param  REQUEST_SCHEME     $scheme;
fastcgi_param  HTTPS              $https if_not_empty;

fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
fastcgi_param  SERVER_SOFTWARE    nginx/$nginx_version;

fastcgi_param  REMOTE_ADDR        $remote_addr;
fastcgi_param  REMOTE_PORT        $remote_port;
fastcgi_param  SERVER_ADDR        $server_addr;
fastcgi_param  SERVER_PORT        $server_port;
fastcgi_param  SERVER_NAME        $server_name;

他会将nginx中的变量赋值给PHP中的$_SERVER,例如最后一条就是将 nginx 中的$server_name赋给PHP中的$_SERVER["SERVER_NAME"];


接下来要让nginx支持php,要先确保你安装了php-fpm,然后才能以fastcgi方式运行PHP。
如果是源码包安装的PHP,为了让PHP能以进程形式运行,所以编译安装PHP的时候要加一个 --enable-fpm 选项。

我的php是yum安装的php7.2,所以这里也使用yum安装php-fpm

yum search php72 | grep 'fpm'   # 查找php7.2的php-fpm的包名,显示为
# 显示php72w-fpm.x86_64 0:7.2.27-1.w7

yum install -y php72w-fpm

# 安装完毕之后,执行
php-fpm
netstat -an|grep :9000      # 检查9000是否绑定,php进程(fastcgi服务)默认绑定9000端口

接下来做个小测试看看nginx能否支持PHP
根目录:
/var/www/html
    |-index.php     # 内容为 echo "index";
    |-test.php      # 内容为 phpinfo();

 

server {
    server_name php.zbpblog.com;
    root /var/www/html;
    listen 8080;
    autoindex on;
    
    location / {
        index index.html index.php;
    }
    
    location ~ \.php$ {
        fastcgi_index index.php;
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
        
        # return 200 "$document_root$fastcgi_script_name";
    }
}

访问 http://php.zbpblog.com:8080  和 http://php.zbpblog.com:8080/test.php
如果能看到内容则nginx支持PHP成功。

 

 

接下来正式去配置nginx,让TP5项目能在nginx服务器运行

使用TP5+Apache项目时,访问url http://xxx.com/a/b/c ,.htaccess文件会将 http://xxx.com/a/b/c 重定向为 http://xxx.com/index.php/a/b/c,然后会指向根目录下的 /index.php ,而"/a/b/c"会被传入$_SERVER["PATH_INFO"]。

TP5会根据$_SERVER['PATH_INFO']找到要请求的模块、控制器和方法。PHP开启PATH_INFO才支持$_SERVER["PATH_INFO"](php.ini的cgi.fix_pathinfo=1)

 

我们可以看一下如果是Apache配置tp5项目,配置文件该怎么写:

<VirtualHost *:80>
  ServerName www.zbpblog.com
  DocumentRoot /var/www/zbpblog/public
  <Directory /var/www/zbpblog/public>
    Options +Indexes +Includes +FollowSymLinks +MultiViews
    AllowOverride All
    Require all granted
  </Directory>
</VirtualHost>

 

https站点的配置

<VirtualHost _default_:443>
DocumentRoot "/var/www/zbpblog/public"
ServerName www.zbpblog.com:443
ServerAlias zbpblog.com
SSLEngine on

SSLCertificateFile /var/www/ssl/Apache/2_www.zbpblog.com.crt
SSLCertificateKeyFile /var/www/ssl/Apache/3_www.zbpblog.com.key
SSLCertificateChainFile /var/www/ssl/Apache/zbp_chain.crt

<Directory "/var/www/zbpblog/public"> 
    Options +Indexes +Includes +FollowSymLinks +MultiViews
    AllowOverride All
    Require all granted
  </Directory>
</VirtualHost>       

 

.htaccess重定向文件如下:

<IfModule mod_rewrite.c>
  Options +FollowSymlinks -Multiviews
  RewriteEngine On

  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L]

</IfModule>

意思是访问一个URL,如果找不到对应的文件或者目录,就会在URI前加一个index.php,重定向到这个地址。

.htaccess是针对Apache的重定向文件,对于nginx可以在nginx.conf中写出意思和.htaccess一样的重定向配置。

 

接下来看看在nginx中如何配置tp5项目:

server {
    server_name www.zbpblog.com zbpblog.com;
    root /var/www/zbpblog/public;
    index index.html index.htm index.php;
    
    listen 80;
    
    #  rewrite ^(.*)$ https://www.zbpblog.com;
    
    location / {
        if (!-e $request_filename) {
            rewrite ^(.*)$ /index.php$1 last;   # 1
        }
    }
      
    location ~ \.php {      # 2
        # root           html;
        fastcgi_pass   127.0.0.1:9000;
        fastcgi_index  index.php;
        fastcgi_split_path_info ^(.+\.php)(.*)$;    # 3
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        
        # PHP开启PATH_INFO才支持$_SERVER["PATH_INFO"],找到php.ini的cgi.fix_pathinfo=1,如有注释将注释去掉开启。
        fastcgi_param PATH_INFO $fastcgi_path_info;     #4
        include        fastcgi_params;
    }
}

整个跳转过程如下:
访问 http://zbpblog.com/a/b/c 匹配到第一个location,满足if的条件,跳到 http://zbpblog.com/index.php/a/b/c,然后新URL会重新匹配所有location块,于是进入 # 2 的location块,在该location块中,nginx将PHP文件的请求转发给fastcgi服务,让PHP进程来编译index.php文件。

曾写错的地方:
# 1 处写为 rewrite ^(.*)$ /index.php$1 break;
使用break的话,重定向后的URL不会重新匹配location,意味着无法进入# 2中的location块,所以nginx就无法和PHP进程通信,nginx就无法解析PHP文件

# 2 处写为 location ~ \.php$
这么一来 http://abc.com/index.php/a/b/c 不匹配 \.php$ 这个正则,所以无法进入 # 2 的location块,nginx就无法和PHP进程通信,nginx就无法解析PHP文件

漏了# 3 和 # 4
这么一来,$_SERVER['PATH_INFO']为空,TP5无法接收到/index.php后的内容,tp5就无法知道使用哪个模块、控制器和方法。

 


接下来配置跳转https站点
思路:将进入到监听80端口的server块中的请求跳转到监听443端口的server块。
 

server {
    server_name www.zbpblog.com zbpblog.com;
    root /var/www/zbpblog/public;
    index index.html index.htm index.php;
    
    listen 80;
    
    rewrite ^(.*)$ https://www.zbpblog.com permanent;     # 加上permanent使用永久重定向,否则默认是302临时重定向
}

server {
    server_name www.zbpblog.com zbpblog.com;
    listen 443 ssl;     # ssl表示启用ssl
    root /var/www/zbpblog/public;
    index index.html index.php index.htm;
    
    # 指定cert文件和key文件的路径
    ssl_certificate /var/www/ssl/Apache/2_www.zbpblog.com.crt;
    ssl_certificate_key /var/www/ssl/Apache/3_www.zbpblog.com.key;
    
    location / {
        if (!-e $request_filename) {
            rewrite ^(.*)$ /index.php$1 last;
        }
    }
    
    location ~ \.php {
        fastcgi_index index.php;
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_split_path_info ^(.+\.php)(.*)$;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
        include fastcgi_params;
    }
}

只需要在443的server块中指定证书位置,监听443端口,启用ssl即可。

PS:上面只使用了两个证书:主证书和密钥证书;
此时谷歌是可以访问我的https站点了,但火狐浏览器要求还要添加中间证书。
此时可以将中间证书的内容复制,追加到主证书内即可,这样就算是添加了中间证书。

如果您需要转载,可以点击下方按钮可以进行复制粘贴;本站博客文章为原创,请转载时注明以下信息

张柏沛IT技术博客 > Nginx初认识之 Nginx支持PHP和TP5项目 (五)

热门推荐
推荐新闻