热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

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

  大家都知道,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接口文件。

  看到这里,大家应该基本清楚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社区 其它相关文章!


推荐阅读
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 这是原文链接:sendingformdata许多情况下,我们使用表单发送数据到服务器。服务器处理数据并返回响应给用户。这看起来很简单,但是 ... [详细]
  • 目录浏览漏洞与目录遍历漏洞的危害及修复方法
    本文讨论了目录浏览漏洞与目录遍历漏洞的危害,包括网站结构暴露、隐秘文件访问等。同时介绍了检测方法,如使用漏洞扫描器和搜索关键词。最后提供了针对常见中间件的修复方式,包括关闭目录浏览功能。对于保护网站安全具有一定的参考价值。 ... [详细]
  • 负载均衡_Nginx反向代理动静分离负载均衡及rewrite隐藏路径详解(Nginx Apache MySQL Redis)–第二部分
    nginx反向代理、动静分离、负载均衡及rewrite隐藏路径详解 ... [详细]
  • Linux下部署Symfoy2对app/cache和app/logs目录的权限设置,symfoy2logs
    php教程|php手册xml文件php教程-php手册Linux下部署Symfoy2对appcache和applogs目录的权限设置,symfoy2logs黑色记事本源码,vsco ... [详细]
  • Linux一键安装web环境全攻略
    摘自阿里云服务器官网,此处一键安装包下载:点此下载安装须知1、此安装包可在阿里云所有Linux系统上部署安装,此安装包包含的软件及版本为& ... [详细]
  • 如何实现织梦DedeCms全站伪静态
    本文介绍了如何通过修改织梦DedeCms源代码来实现全站伪静态,以提高管理和SEO效果。全站伪静态可以避免重复URL的问题,同时通过使用mod_rewrite伪静态模块和.htaccess正则表达式,可以更好地适应搜索引擎的需求。文章还提到了一些相关的技术和工具,如Ubuntu、qt编程、tomcat端口、爬虫、php request根目录等。 ... [详细]
  • mac php错误日志配置方法及错误级别修改
    本文介绍了在mac环境下配置php错误日志的方法,包括修改php.ini文件和httpd.conf文件的操作步骤。同时还介绍了如何修改错误级别,以及相应的错误级别参考链接。 ... [详细]
  • 一句话解决高并发的核心原则
    本文介绍了解决高并发的核心原则,即将用户访问请求尽量往前推,避免访问CDN、静态服务器、动态服务器、数据库和存储,从而实现高性能、高并发、高可扩展的网站架构。同时提到了Google的成功案例,以及适用于千万级别PV站和亿级PV网站的架构层次。 ... [详细]
  • 如何提高PHP编程技能及推荐高级教程
    本文介绍了如何提高PHP编程技能的方法,推荐了一些高级教程。学习任何一种编程语言都需要长期的坚持和不懈的努力,本文提醒读者要有足够的耐心和时间投入。通过实践操作学习,可以更好地理解和掌握PHP语言的特异性,特别是单引号和双引号的用法。同时,本文也指出了只走马观花看整体而不深入学习的学习方式无法真正掌握这门语言,建议读者要从整体来考虑局部,培养大局观。最后,本文提醒读者完成一个像模像样的网站需要付出更多的努力和实践。 ... [详细]
  • LVS实现负载均衡的原理LVS负载均衡负载均衡集群是LoadBalance集群。是一种将网络上的访问流量分布于各个节点,以降低服务器压力,更好的向客户端 ... [详细]
  • PHP组合工具以及开发所需的工具
    本文介绍了PHP开发中常用的组合工具和开发所需的工具。对于数据分析软件,包括Excel、hihidata、SPSS、SAS、MARLAB、Eview以及各种BI与报表工具等。同时还介绍了PHP开发所需的PHP MySQL Apache集成环境,包括推荐的AppServ等版本。 ... [详细]
  • Nginx Buffer 机制引发的下载故障
    Nginx ... [详细]
  • 现在比较流行使用静态网站生成器来搭建网站,博客产品着陆页微信转发页面等。但每次都需要对服务器进行配置,也是一个重复但繁琐的工作。使用DockerWeb,只需5分钟就能搭建一个基于D ... [详细]
  • centos6.8 下nginx1.10 安装 ... [详细]
author-avatar
我本僐悢
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有