9.PHP内核探索:通过mod_php5支持PHP

时间:2022-08-26 13:45:59

Apache对PHP的支持是通过Apache的模块mod_php5来支持的。如果希望Apache支持PHP的话,在./configure步 骤需要指定--with-apxs2=/usr/local/apache2/bin/apxs 表示告诉编译器通过Apache的mod_php5 /apxs来提供对PHP5的解析。

在最后一步make install的时候我们会看到将动态链接库libphp5.so(Apache模块)拷贝到apache2的安装目录的modules目录下,并且还需 要在httpd.conf配置文件中添加LoadModule语句来动态将libphp5.so 模块加载进来,从而实现Apache对php的支持。

由于该模式实在太经典了,因此这里关于安装部分不准备详述了,相对来说比较简单。我们知道nginx一般包括两个用途HTTP Server和Reverse Proxy Server(反向代理服务器)。在前端可以部署nginx作为reverse proxy server,后端布置多个Apache来实现机群系统server cluster架构的。

因此,实际生产中,我们仍旧能够保留Apache+mod_php5的经典App Server,而仅仅使用nginx来当做前端的reverse proxy server来实现代理和负载均衡。 因此,建议nginx(1个或者多个)+多个apache的架构继续使用下去。

Apache2的mod_php5模块包括sapi/apache2handler和sapi/apache2filter两个目录 在apache2_handle/mod_php5.c文件中,模块定义的相关代码如下:

01 AP_MODULE_DECLARE_DATA module php5_module = {
02     STANDARD20_MODULE_STUFF,
03         /* 宏,包括版本,小版本,模块索引,模块名,下一个模块指针等信息,其中模块名以__FILE__体现 */
04     create_php_config,      /* create per-directory config structure */
05     merge_php_config,       /* merge per-directory config structures */
06     NULL,                   /* create per-server config structure */
07     NULL,                   /* merge per-server config structures */
08     php_dir_cmds,           /* 模块定义的所有的指令 */
09     php_ap2_register_hook
10         /* 注册钩子,此函数通过ap_hoo_开头的函数在一次请求处理过程中对于指定的步骤注册钩子 */
11 };

它所对应的是Apache的module结构,module的结构定义如下:

01 typedef struct module_struct module;
02 struct module_struct {
03     int version;
04     int minor_version;
05     int module_index;
06     const char *name;
07     void *dynamic_load_handle;
08     struct module_struct *next;
09     unsigned long magic;
10     void (*rewrite_args) (process_rec *process);
11     void *(*create_dir_config) (apr_pool_t *p, char *dir);
12     void *(*merge_dir_config) (apr_pool_t *p, void *base_conf, void *new_conf);
13     void *(*create_server_config) (apr_pool_t *p, server_rec *s);
14     void *(*merge_server_config) (apr_pool_t *p, void *base_conf, void *new_conf);
15     const command_rec *cmds;
16     void (*register_hooks) (apr_pool_t *p);
17 }

上面的模块结构与我们在mod_php5.c中所看到的结构有一点不同,这是由于STANDARD20_MODULE_STUFF的原因, 这个宏它包含了前面8个字段的定义。STANDARD20_MODULE_STUFF宏的定义如下:

1 /** Use this in all standard modules */
2 #define STANDARD20_MODULE_STUFF MODULE_MAGIC_NUMBER_MAJOR, \
3                 MODULE_MAGIC_NUMBER_MINOR, \
4                 -1, \
5                 __FILE__, \
6                 NULL, \
7                 NULL, \
8                 MODULE_MAGIC_COOKIE, \
9                                 NULL      /* rewrite args spot */

在php5_module定义的结构中,php_dir_cmds是模块定义的所有的指令集合,其定义的内容如下:

01 const command_rec php_dir_cmds[] =
02 {
03     AP_INIT_TAKE2("php_value", php_apache_value_handler, NULL,
04         OR_OPTIONS, "PHP Value Modifier"),
05     AP_INIT_TAKE2("php_flag", php_apache_flag_handler, NULL,
06         OR_OPTIONS, "PHP Flag Modifier"),
07     AP_INIT_TAKE2("php_admin_value", php_apache_admin_value_handler,
08         NULL, ACCESS_CONF|RSRC_CONF, "PHP Value Modifier (Admin)"),
09     AP_INIT_TAKE2("php_admin_flag", php_apache_admin_flag_handler,
10         NULL, ACCESS_CONF|RSRC_CONF, "PHP Flag Modifier (Admin)"),
11     AP_INIT_TAKE1("PHPINIDir", php_apache_phpini_set, NULL,
12         RSRC_CONF, "Directory containing the php.ini file"),
13     {NULL}
14 };

这是mod_php5模块定义的指令表。它实际上是一个command_rec结构的数组。 当Apache遇到指令的时候将逐一遍历各个模块中的指令表,查找是否有哪个模块能够处理该指令, 如果找到,则调用相应的处理函数,如果所有指令表中的模块都不能处理该指令,那么将报错。 如上可见,mod_php5模块仅提供php_value等5个指令。

php_ap2_register_hook函数的定义如下:

1 void php_ap2_register_hook(apr_pool_t *p)
2 {
3     ap_hook_pre_config(php_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
4     ap_hook_post_config(php_apache_server_startup, NULL, NULL, APR_HOOK_MIDDLE);
5     ap_hook_handler(php_handler, NULL, NULL, APR_HOOK_MIDDLE);
6     ap_hook_child_init(php_apache_child_init, NULL, NULL, APR_HOOK_MIDDLE);
7 }

以上代码声明了pre_config,post_config,handler和child_init 4个挂钩以及对应的处理函数。 其中pre_config,post_config,child_init是启动挂钩,它们在服务器启动时调用。 handler挂钩是请求挂钩,它在服务器处理请求时调用。其中在post_config挂钩中启动php。 它通过php_apache_server_startup函数实现。php_apache_server_startup函数通过调用 sapi_startup启动sapi, 并通过调用php_apache2_startup来注册sapi module struct(此结构在本节开头中有说明), 最后调用php_module_startup来初始化PHP, 其中又会初始化ZEND引擎,以及填充zend_module_struct中 的treat_data成员(通过php_startup_sapi_content_types)等。

到这里,我们知道了Apache加载mod_php5模块的整个过程,可是这个过程与我们的SAPI有什么关系呢? mod_php5也定义了属于Apache的sapi_module_struct结构:

01 static sapi_module_struct apache2_sapi_module = {
02 "apache2handler",
03 "Apache 2.0 Handler",
04   
05 php_apache2_startup,                /* startup */
06 php_module_shutdown_wrapper,            /* shutdown */
07   
08 NULL,                       /* activate */
09 NULL,                       /* deactivate */
10   
11 php_apache_sapi_ub_write,           /* unbuffered write */
12 php_apache_sapi_flush,              /* flush */
13 php_apache_sapi_get_stat,           /* get uid */
14 php_apache_sapi_getenv,             /* getenv */
15   
16 php_error,                  /* error handler */
17   
18 php_apache_sapi_header_handler,         /* header handler */
19 php_apache_sapi_send_headers,           /* send headers handler */
20 NULL,                       /* send header handler */
21   
22 php_apache_sapi_read_post,          /* read POST data */
23 php_apache_sapi_read_cookies,           /* read Cookies */
24   
25 php_apache_sapi_register_variables,
26 php_apache_sapi_log_message,            /* Log message */
27 php_apache_sapi_get_request_time,       /* Request Time */
28 NULL,                       /* Child Terminate */
29   
30 STANDARD_SAPI_MODULE_PROPERTIES
31 };

这些方法都专属于Apache服务器。以读取cookie为例,当我们在Apache服务器环境下,在PHP中调用读取Cookie时, 最终获取的数据的位置是在激活SAPI时。它所调用的方法是read_cookies。

1 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函数。 这也是定义SAPI结构的理由:统一接口,面向接口的编程,具有更好的扩展性和适应性。

9.PHP内核探索:通过mod_php5支持PHP的更多相关文章

  1. php内核探索 [转]

    PHP内核探索:从SAPI接口开始 PHP内核探索:一次请求的开始与结束 PHP内核探索:一次请求生命周期 PHP内核探索:单进程SAPI生命周期 PHP内核探索:多进程/线程的SAPI生命周期 PH ...

  2. PHP内核探索:哈希碰撞攻击是什么?

    最近哈希表碰撞攻击(Hashtable collisions as DOS attack)的话题不断被提起,各种语言纷纷中招.本文结合PHP内核源码,聊一聊这种攻击的原理及实现. 哈希表碰撞攻击的基本 ...

  3. PHP服务器脚本 PHP内核探索:新垃圾回收机制说明

    在5.2及更早版本的PHP中,没有专门的垃圾回收器GC(Garbage Collection),引擎在判断一个变量空间是否能够被释放的时候是依据这个变量的zval的refcount的值,如果refco ...

  4. 《PHP内核探索系列文章》系列分享专栏

    <PHP内核探索系列文章>已整理成PDF文档,点击可直接下载至本地查阅 简介 PHP内核探索系列文章收藏夹收藏有关PHP内核方面的知识的文章,对PHP高级进阶的朋友提供PHP内核方面的知识 ...

  5. PHP内核探索之变量(7)- 不平凡的字符串

    切,一个字符串有什么好研究的. 别这么说,看过<平凡的世界>么,平凡的字符串也可以有不平凡的故事.试看: (1)       在C语言中,strlen计算字符串的时间复杂度是?PHP中呢? ...

  6. PHP内核探索之变量(5)- session的基本原理

    这次说说session. session可以说是当前互联网提到的最多的名词之一了.它的含义很宽泛,可以指任何一次完整的事务交互(会话):如发送一次HTTP请求并接受响应,执行一条SQL语句都可以看做一 ...

  7. PHP内核探索之变量(3)- hash table

    在PHP中,除了zval, 另一个比较重要的数据结构非hash table莫属,例如我们最常见的数组,在底层便是hash table.除了数组,在线程安全(TSRM).GC.资源管理.Global变量 ...

  8. PHP内核探索之变量(2)-理解引用

    本文主要内容: 引论 符号表与zval 引用原理 回到最初的问题 一.引论 很久之前写了一篇关于引用的文章,当时写的寥寥草草,很多原理都没有说清楚.最近在翻阅Derick Rethans(home: ...

  9. 内核用户模式调试支持(Dbgk)

    简介 将详细分析Windows调试的内核模式接口.希望读者对C和通用NT内核体系结构和语义有一些基本的了解.此外,这并不是介绍什么是调试或如何编写调试器.它可以作为经验丰富的调试器编写人员或好奇的安全 ...

  10. PHP内核探索之变量(6)- 后续内核探索系列大纲备忘

    年前因为工作比较饱和,现在又忙着换工作的事情,基本停止了对博文的更新.后续的博文,还是慢慢补上吧. 为了不至于过于发散,先搞个未成形的大纲,如下: PHP内核探索之变量  不平凡的字符串 PHP内核探 ...

随机推荐

  1. iOS开发常用代码块

    遍历可变数组的同时删除数组元素 NSMutableArray *copyArray = [NSMutableArray arrayWithArray:array]; NSString *str1 = ...

  2. SharePoint 2013 Ajax 造成页面无法编辑

    1.如下图,在编辑页面的时候,出现如下错误“此网页自上次打开后已被修改,必须再次打开该网页”,页面上没有什么特别的设置,就是default.aspx: 2.编辑之前页面,只有一个内容编辑器部件,和若干 ...

  3. 向Array中添加快速排序

    快速排序思路 1) 假设第一个元素为基准元素 2) 把所有比基准元素小的记录放置在前一部分,把所有比基准元素大的记录放置在后一部分,并把基准元素放在这两部分的中间(i=j的位置) 快速排序实现 Fun ...

  4. CSS圆角,输入框提示信息,JS查找同级元素

    input { /*设置边框*/ border:1px solid #95B8E7; border-radius: 5px; /*设置圆角,IE不兼容*/ height:18px } placehol ...

  5. SQLServer 之 常用函数及查看

    一.查看 (1)应用程序名称              SELECT APP_NAME() (2)获取登录者名字           SELECT SUSER_NAME() (3)获取字段定义的长度  ...

  6. node&period;js在windows下的学习笔记&lpar;7&rpar;---express的app&period;js的详细配置说明

    var express = require('express'); var path = require('path'); var favicon = require('serve-favicon') ...

  7. FFT&lowbar;ad采样速率

    调用quartus的ip核测量频率和幅值,可以把程序分成四大部分.第一部分是AD采样模块,本次实验用的是ad828,最高采样率为70M, 根据奈贵斯特采样定律 Fs > 2Fc,即采样率要大于信 ...

  8. ssh转发代理:ssh-agent用法详解

    SSH系列文章: SSH基础:SSH和SSH服务 SSH转发代理:ssh-agent用法详解 SSH隧道:端口转发功能详解 使用ssh-agent之前 使用ssh公钥认证的方式可以免去ssh客户端(如 ...

  9. linux Page cache和buffer cache正解

    Page cache和buffer cache一直以来是两个比较容易混淆的概念,在网上也有很多人在争辩和猜想这两个cache到底有什么区别,讨论到最后也一直没有一个统一和正确的结论,在我工作的这一段时 ...

  10. 百度编辑器UEditor 点击上传图片选择框会延迟几秒才会显示 反应很慢&lpar;转&rpar;

    转自:http://www.blogxuan.com/php/show/323.html UEditor 编辑器点击上传文件选择框会延迟几秒才会显示,反应很慢,上传图片选择框显示很慢. 1.uedit ...