首页 后端开发 php教程 深入理解PHP与WEB服务器交互

深入理解PHP与WEB服务器交互

Aug 21, 2019 pm 05:55 PM
php web服务器

深入理解PHP与WEB服务器交互

  大家都知道,PHP需要在具体的WEB服务器中才能运行,例如Nginx、Apache等,但是PHP是怎样启动,又是怎样在服务器中运行,然后两者又是怎样进行交互的呢? 

推荐教程:php视频教程

1.WEB服务器调用PHP接口 

  以Apache服务器为例,我们看看该服务器是怎样启动PHP,并调用PHP中的方法。Apache服务器启动并运行PHP时,一般是通过mod_php7模块的形式集成(如果是php5.*版本,就是mod_php5模块,模块后缀名根据php版本而定),mod_php7的结构如下(源码路径为php/sapi/apache2handler/mod_php7.c):

AP_MODULE_DECLARE_DATA module php7_module = {
    STANDARD20_MODULE_STUFF,/* 宏,包括版本,版本,模块索引,模块名,下个模块指针等信息 */
    create_php_config,      /* create per-directory config structure */
    merge_php_config,       /* merge per-directory config structures */
    NULL,                   /* create per-server config structure */
    NULL,                   /* merge per-server config structures */
    php_dir_cmds,           /* 模块定义的所有指令 */
    php_ap2_register_hook   /* register hooks */
};
登录后复制

  当Apache需要调用PHP中的方法时,只需要将该请求通过mod_php7模块传达给PHP,PHP层处理完后将数据返回给Apache,整个过程就结束了(补充一下:Apache服务器启动PHP时,其实有两种加载方式,一种为静态加载,一种为动态加载,刚才讨论的mod_php5模块加载方式可以理解为静态加载,也就是需要重新启动Apache服务器,才能将PHP加载进去;动态加载不需要重启服务器,只需要通过发送信号的方式将PHP固定的模块加载到服务器,以达到PHP启动的目的,但是在进行动态加载前,需要将加载模块编译成动态链接库,然后将其配置到服务器的配置文件中)。上面已经给出Apache在PHP中的model结构,下面给出Apache服务器中对应的module结构,如下(该源代码在Apache中,下同):

struct module_struct {
    int version;
    int minor_version;
    int module_index;
    const char *name;
    void *dynamic_load_handle;
    struct module_struct *next;
    unsigned long magic;
    void (*rewrite_args) (process_rec *process);
    void *(*create_dir_config) (apr_pool_t *p, char *dir);
    void *(*merge_dir_config) (apr_pool_t *p, void *base_conf, void *new_conf);
    void *(*create_server_config) (apr_pool_t *p, server_rec *s);
    void *(*merge_server_config) (apr_pool_t *p, void *base_conf, void *new_conf);
    const command_rec *cmds;
    void (*register_hooks) (apr_pool_t *p);
}
登录后复制

  可以看得出php7_module和module_struct还是有很大不同,不过如果看到php7_module.STANDARD20_MODULE_STUFF这个宏的定义方式,你可能就会觉得这两个结构体很像,其实这个宏定义了module_struct中的前8个参数,定义如下:

#define STANDARD20_MODULE_STUFF MODULE_MAGIC_NUMBER_MAJOR, \
    MODULE_MAGIC_NUMBER_MINOR, \
    -1, \
    __FILE__, \
    NULL, \
    NULL, \
    MODULE_MAGIC_COOKIE, \
    NULL /* rewrite args spot */
登录后复制

  然后php7_module.php_dir_cmds定义了模块的所有指令集合,具体定义内容如下(代码路径为php/sapi/apache2handler/apache_config.c):

const command_rec php_dir_cmds[] =
{
    AP_INIT_TAKE2("php_value", php_apache_value_handler, NULL, OR_OPTIONS, "PHP Value Modifier"),
    AP_INIT_TAKE2("php_flag", php_apache_flag_handler, NULL, OR_OPTIONS, "PHP Flag Modifier"),
    AP_INIT_TAKE2("php_admin_value", php_apache_admin_value_handler, NULL, ACCESS_CONF|RSRC_CONF, "PHP Value Modifier (Admin)
    "),
    AP_INIT_TAKE2("php_admin_flag", php_apache_admin_flag_handler, NULL, ACCESS_CONF|RSRC_CONF, "PHP Flag Modifier (Admin)"),
    AP_INIT_TAKE1("PHPINIDir", php_apache_phpini_set, NULL, RSRC_CONF, "Directory containing the php.ini file"),
    {NULL}
};
登录后复制

  也就是说,PHP层只给Apache提供了上述5个指令,每个指令的实现源码也在apache_config.c文件中,最后就剩php7_module.php_ap2_register_hook了,它定义的内容如下(代码路径为php/sapi/apache2handler/mod_php7.c):

void php_ap2_register_hook(apr_pool_t *p)
{
    ap_hook_pre_config(php_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
    ap_hook_post_config(php_apache_server_startup, NULL, NULL, APR_HOOK_MIDDLE);
    ap_hook_handler(php_handler, NULL, NULL, APR_HOOK_MIDDLE);
#ifdef ZEND_SIGNALS
    ap_hook_child_init(zend_signal_init, NULL, NULL, APR_HOOK_MIDDLE);
#endif
    ap_hook_child_init(php_apache_child_init, NULL, NULL, APR_HOOK_MIDDLE);
}
登录后复制

  php7_module.php_ap2_register_hook函数包含4个钩子和对应的处理函数,pre_config,pre_config、post_config和child_init是启动钩子,它们是在服务器启动时调用,handler钩子是请求挂钩,它是在服务器请求是调用,通过这些钩子,就可以通过Apache服务器启动PHP。

   将到这里,想必大家已经知道WEB服务器是如何启动PHP,并调用PHP中的方法了哈,下面再给大家讲讲PHP是如何调用WEB服务器接口的。

2.PHP调用WEB服务器接口

  在讲述这个问题前,我们需要了解一下什么是SAPI。SAPI其实是与服务器抽象层之间遵守的共同约定,可以这么简单理解,当PHP需要调用服务器中的方法,例如清除缓存,但是清除缓存的实现方法是在服务器中实现,PHP层根本就不知道怎么调用服务器中的该方法,怎么办?这时双方需要进行约定,然后服务器提供一套约定后的接口给PHP,我们把这些与服务器抽象层之间遵守的共同约定称为SAPI接口。

  问题来了,对于服务器Apache,我们可以提供一套SAPI,但是如果下次又来个其它的服务器,或者其它的“第三方”,那么我们是不是也要给他们提供一套单独的SAPI呢?我们聪明的PHP开发者肯定想到了这一点,即对所有的“第三方”提供一套通用的SAPI接口,但是你可以会问,如果新的“第三方”需要的接口,你的通用SAPI不支持,那怎么办呢,我的理解是将新的功能添加到PHP的通用SAPI接口中,仅仅是个人见解哈,通用SAPI结构如下(源码路径: php/main/SAPI.h):

struct _sapi_module_struct {
    char *name;         // 名字
    char *pretty_name;  // 更好理解的名字
    int (*startup)(struct _sapi_module_struct *sapi_module);    // 启动函数
    int (*shutdown)(struct _sapi_module_struct *sapi_module);   // 关闭函数
    int (*activate)(TSRMLS_D);           // 激活
    int (*deactivate)(TSRMLS_D);         // 停用
    void (*flush)(void *server_context); // flush
    char *(*read_cookies)(TSRMLS_D);     //read Cookies
    //...
};
登录后复制

  该结构体变量较多,就不一一列举,简要说明一下里面的变量:startup函数是当SAPI初始化时会被调用,shutdown函数是用来释放SAPI的数据结构和内存等,read_cookie 是在SAPI激活时被调用,然后将此函数获取的值赋值给SG(request_info).cookie_data。那么对于PHP提供的通用SAPI,Apache服务器又是怎样定制自己的接口呢?具体结构如下(源码路径为php/sapi/apache2handler/sapi_apache2.c):

static sapi_module_struct apache2_sapi_module = {
    "apache2handler",
    "Apache 2.0 Handler",

    php_apache2_startup,            /* startup */
    php_module_shutdown_wrapper,    /* shutdown */

    NULL,                           /* activate */
    NULL,                           /* deactivate */

    php_apache_sapi_ub_write,       /* unbuffered write */
    php_apache_sapi_flush,          /* flush */
    php_apache_sapi_get_stat,       /* get uid */
    php_apache_sapi_getenv,         /* getenv */

    php_error,                      /* error handler */

    php_apache_sapi_header_handler, /* header handler */
    php_apache_sapi_send_headers,   /* send headers handler */
    NULL,                           /* send header handler */

    php_apache_sapi_read_post,      /* read POST data */
    php_apache_sapi_read_cookies,   /* read Cookies */

    php_apache_sapi_register_variables,
    php_apache_sapi_log_message,        /* Log message */
    php_apache_sapi_get_request_time,   /* Request Time */
    NULL,                               /* Child Terminate */

    STANDARD_SAPI_MODULE_PROPERTIES
};
登录后复制

  上述源码目录php/sapi/apache2handler/中,目录php/sapi下面放的都是通过SAPI调用的“第三方”,该目录结构如下图所示,目录php/sapi/apache2handler中都是与PHP交互的接口,sapi_apache2.c是PHP与Apache约定的SAPI接口文件。

20160821163330607 (1).jpg

  看到这里,大家应该基本清楚PHP层是怎样调用服务器层的接口,为了巩固上面的知识,下面举个栗子,即在Apache服务器环境下读取cookie:

SG(request_info).cookie_data = sapi_module.read_cookies(TSRMLS_C);
登录后复制

对于任意一个服务器在加载时,我们都会指定sapi_module,Apache的sapi_module是apache2_sapi_module,它的read_cookies方法的是php_apache_sapi_read_cookies函数,这样就实现PHP层调用Apache的接口,是不是很简单呢:)  

3.后记 

  这篇博文是我参考《深入理解PHP内核》一书总结的,参考的内容为第二章第二节“SAPI概述”,不过我感觉该书中这部分内容讲的有点绕,我重新编排了,然后提取了里面的重点,并加入个人见解,如果在该文中有哪些讲的不对的地方,希望能帮我指出来,大家共同提高哈,谢谢!

原文地址:https://blog.csdn.net/lml200701158/article/details/52267573

以上是深入理解PHP与WEB服务器交互的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

热门话题

Java教程
1653
14
CakePHP 教程
1413
52
Laravel 教程
1305
25
PHP教程
1251
29
C# 教程
1224
24
PHP和Python:比较两种流行的编程语言 PHP和Python:比较两种流行的编程语言 Apr 14, 2025 am 12:13 AM

PHP和Python各有优势,选择依据项目需求。1.PHP适合web开发,尤其快速开发和维护网站。2.Python适用于数据科学、机器学习和人工智能,语法简洁,适合初学者。

PHP:网络开发的关键语言 PHP:网络开发的关键语言 Apr 13, 2025 am 12:08 AM

PHP是一种广泛应用于服务器端的脚本语言,特别适合web开发。1.PHP可以嵌入HTML,处理HTTP请求和响应,支持多种数据库。2.PHP用于生成动态网页内容,处理表单数据,访问数据库等,具有强大的社区支持和开源资源。3.PHP是解释型语言,执行过程包括词法分析、语法分析、编译和执行。4.PHP可以与MySQL结合用于用户注册系统等高级应用。5.调试PHP时,可使用error_reporting()和var_dump()等函数。6.优化PHP代码可通过缓存机制、优化数据库查询和使用内置函数。7

PHP行动:现实世界中的示例和应用程序 PHP行动:现实世界中的示例和应用程序 Apr 14, 2025 am 12:19 AM

PHP在电子商务、内容管理系统和API开发中广泛应用。1)电子商务:用于购物车功能和支付处理。2)内容管理系统:用于动态内容生成和用户管理。3)API开发:用于RESTfulAPI开发和API安全性。通过性能优化和最佳实践,PHP应用的效率和可维护性得以提升。

说明匹配表达式(PHP 8)及其与开关的不同。 说明匹配表达式(PHP 8)及其与开关的不同。 Apr 06, 2025 am 12:03 AM

在PHP8 中,match表达式是一种新的控制结构,用于根据表达式的值返回不同的结果。1)它类似于switch语句,但返回值而非执行语句块。2)match表达式使用严格比较(===),提升了安全性。3)它避免了switch语句中可能的break遗漏问题,增强了代码的简洁性和可读性。

PHP与Python:了解差异 PHP与Python:了解差异 Apr 11, 2025 am 12:15 AM

PHP和Python各有优势,选择应基于项目需求。1.PHP适合web开发,语法简单,执行效率高。2.Python适用于数据科学和机器学习,语法简洁,库丰富。

什么是跨站点伪造(CSRF),您如何在PHP中实施CSRF保护? 什么是跨站点伪造(CSRF),您如何在PHP中实施CSRF保护? Apr 07, 2025 am 12:02 AM

在PHP中可以通过使用不可预测的令牌来有效防范CSRF攻击。具体方法包括:1.生成并在表单中嵌入CSRF令牌;2.在处理请求时验证令牌的有效性。

PHP的目的:构建动态网站 PHP的目的:构建动态网站 Apr 15, 2025 am 12:18 AM

PHP用于构建动态网站,其核心功能包括:1.生成动态内容,通过与数据库对接实时生成网页;2.处理用户交互和表单提交,验证输入并响应操作;3.管理会话和用户认证,提供个性化体验;4.优化性能和遵循最佳实践,提升网站效率和安全性。

PHP的未来:改编和创新 PHP的未来:改编和创新 Apr 11, 2025 am 12:01 AM

PHP的未来将通过适应新技术趋势和引入创新特性来实现:1)适应云计算、容器化和微服务架构,支持Docker和Kubernetes;2)引入JIT编译器和枚举类型,提升性能和数据处理效率;3)持续优化性能和推广最佳实践。

See all articles