基于 Nginx + PHP-FPM 作为 HTTP 服务器

引言

PHP 对 HTTP 请求响应支持非常友好,可以通过 PHP 预定义的超全局变量获取 HTTP 请求数据:

  • $_SERVER:获取 HTTP 服务器数据
  • $_GET:获取 URL 查询字符串中的参数(GET 请求参数)
  • $_POST:获取 POST 请求数据(通常是表单请求)
  • $_FILES:获取通过 HTTP 上传的文件
  • $_COOKIE:获取 Cookie 中的数据
  • $_REQUEST:获取用户请求数据(包含 GET 和 POST 请求以及 Cookie 数据)

所有请求数据都是以关联数组的方式存储在对应的超全局变量中,比如要获取 GET 请求中的 name 参数,可以通过 $_GET['name'] 这种方式获取。

下面我们简单介绍下如何在 PHP 代码通过这些超全局变量中获取 HTTP 请求数据。

打印 $_SERVER 内容

PHP 本身不支持通过代码创建 HTTP 服务器,但是可以通过底层 SAPI 接口非常方便的与其他第三方 HTTP 服务器对接,比如 PHP-FPM、Apache、CGI 等。

在 PHP 代码中,可以通过 $_SERVER 获取所有服务器信息,包括 HTTP 请求头、PHP 脚本、服务器环境和系统环境变量等,详细细节可以参考 PHP 官方文档:https://www.php.net/manual/zh/reserved.variables.server.php

我们在 php_learning 目录下新建 http 子目录,并在该子目录下创建 index.php 保存本篇教程演示代码,我们尝试打印 $_SERVER 变量:

<?php

echo '<pre>';
var_dump($_SERVER);

使用 PHP 内置 HTTP 服务器

接下来在 php_learning/http 目录下启动 PHP 内置服务器:

-w652

然后在浏览器中访问 http://localhost:9000index.php 是默认首页),就可以看到所有 HTTP 服务器和请求信息:

-w1099

基于 Nginx + PHP-FPM 作为 HTTP 服务器

不过 PHP 内置 HTTP 服务器只能在本地开发环境使用(性能太差),生产环境可以选择 Apache(需要启用对应的 PHP 支持模块)或者 Nginx + PHP-FPM 组合作为 PHP HTTP 服务器,如果使用 Nginx + PHP-FPM 作为 HTTP 服务器的话,以 Laradock 集成开发环境为例,可以按照如下步骤操作。

注:Nginx + PHP-FPM 组合中,Nginx 是一个反向代理服务器,对于前端静态资源请求直接通过 Nginx 处理,对于后端 PHP 动态请求,会转发给 PHP-FPM 进程处理。关于这一块的更底层原理,可以参考这篇教程了解:基于 Nginx + PHP 驱动 Web 应用(下):请求处理与响应发送篇

配置 Nginx 虚拟主机

laradock 项目根目录下的 nginx/sites 目录下新增一个 php.conf 配置文件配置一个虚拟主机:

server {
    listen 80;
    server_name php.test;
    root /var/www/http;
    
    index index.html index.htm index.php;
    location / {
        try_files $uri $uri/ /index.php$is_args$args;
    }
    
    location ~ \.php$ {
        try_files $uri /index.php =404;
        fastcgi_pass php-upstream;
        fastcgi_index index.php;
        fastcgi_buffers 16 16k;
        fastcgi_buffer_size 32k;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        #fixes timeouts
        fastcgi_read_timeout 600;
        include fastcgi_params;
    }
    
    location ~ /\.ht {
        deny all;
    }
    location /.well-known/acme-challenge/ {
        root /var/www/letsencrypt/;
        log_not_found off;
    }
    error_log /var/log/nginx/php_error.log;
    access_log /var/log/nginx/php_access.log;
    
}

由于这里配置了一个虚拟域名 php.test,因此需要到本地 /etc/hosts 中添加这个域名映射(Windows 下位于 C:\Windows\system32\drivers\etc\hosts):

127.0.0.1 php.test

注:如果你想要了解虚拟主机配置中每个配置项的含义,请参考这篇教程:基于 Nginx + PHP 驱动 Web 应用(上):配置文件与虚拟主机篇

配置目录映射

虚拟主机配置中应用根目录设置的是 /var/www/http/var/wwwworkspace 容器中 Web 应用中的根目录,所以我们需要将宿主机中的 php_learning 目录映射到 /var/www 目录,这样,php_learning/http 项目代码才能与 /var/www/http 同步。

要完成这个映射,只需要在 laradock 目录下的 .env 文件中配置 APP_CODE_PATH_HOST 即可:

# Point to the path of your applications code on your host
APP_CODE_PATH_HOST=~/Development/php/php_learning

# Point to where the `APP_CODE_PATH_HOST` should be in the container
APP_CODE_PATH_CONTAINER=/var/www

Windows 系统请自行设置这个目录映射,比如我这里的 php_learning 位于 D:\projects\php\php_learning,laradock 位于 D:\laradock,则配置成这样就好了:

APP_CODE_PATH_HOST=../projects/php/php_learning/

这样一来,当我们启动 Nginx + PHP-FPM + Workspace 容器后,在浏览器中访问 http://php.test 时,Nginx 会将 PHP 请求转发给 PHP-FPM 处理,然后 PHP-FPM 会从项目默认入口文件 index.php 开始执行 PHP 脚本代码,从而完成请求分发和处理。

重构 & 启动相关容器

完成以上配置后,需要进入 laradock 目录重构 nginx 镜像:

docker-compose build nginx 

然后启动 nginx、php-fpm、workspace 容器 (nginx 依赖后面两个容器,所以会按照依赖关系依次启动):

docker-compose up -d nginx

-w687

运行 docker-compose ps 确保所有容器启动成功(State 状态值为 Up):

-w937

访问 PHP 应用

最后,在浏览器通过 http://php.test 即可访问 PHP 脚本 index.php,这一次信息更丰富,我们只截取部分进行分析:

-w1104

可以看到 Web 服务器变成了 Nginx,其他的脚本路径也变成了服务器上(Docker 容器)对应的路径和环境变量,请求参数、请求方法、请求头信息也都包含了,还可以从中获取服务端 IP 地址(SERVER_ADDR)和客户端 IP 地址信息(REMOTE_ADDR)。

小结

通过 $_SERVER 超全局变量可以获取到所有的 HTTP 请求信息和服务器信息,不过我们在 Web 应用中通常只对 HTTP 请求头和请求数据感兴趣,这些可以通过 $_GET$_POST$_REQUEST$_COOKIE$_FILES 等更具体的超全局变量获取,这些我们放到下篇教程去具体介绍。

另外也可以看到,PHP 屏蔽了 HTTP 请求协议的细节,我们不需要对请求头、请求实体、响应头、响应实体等更底层的 HTTP 报文结构进行了解就可以直接通过 PHP 封装的超全局变量获取请求信息,然后直接通过 echovar_dumpprint_r 等 PHP 语句和函数或者渲染一个包含 PHP 脚本的 HTML 文档即可将响应实体发送给客户端,非常简单。

上一篇: 通过 PDO 扩展与 MySQL 数据库交互(下):增删改查实现和数据库事务

下一篇: PHP 用户请求数据获取与文件上传