Apache服务器是如何解析PHP 小编来给你解疑

作者 : 开心源码 本文共5593个字,预计阅读时间需要14分钟 发布时间: 2022-05-12 共198人阅读

为了让Apache支持php,我们通常的做法是编译一个apche的php板块, 在配置中配置让mod_php来解决php文件的请求. php板块通过注册apache2的ap_hook_post_config挂钩, 在apache启动的时候启动php板块以接受php的请求.

下面详情apache板块加载的基本知识以及PHP对于apache的实现

Apache板块加载机制简介


Apache的板块可以在运行的时候动态装载,这意味着对服务器可以进行功能扩展而不需要重新对源代码进行编译,甚至根本不需要中止服务器。 我们所需要做的仅仅是给服务器发送信号HUP或者者AP_SIG_GRACEFUL通知服务器重新载入板块。 但是在动态加载之前,我们需要将板块编译成为动态链接库。此时的动态加载就是加载动态链接库。

Apache中对动态链接库的解决是通过板块mod_so来完成的,因而mod_so板块不能被动态加载, 它只能被静态编译进Apache的核心。这意味着它是随着Apache一起启动的。

比方我们要加载PHP板块,那么首先我们需要在httpd.conf文件中增加一行:

LoadModule php5_module modules/mod_php5.so

该命令的第一个参数是板块的名称,名称可以在板块实现的源码中找到。第二个选项是该板块所处的路径。 假如需要在服务器运行时加载板块,可以通过发送信号HUP或者者AP_SIG_GRACEFUL给服务器,一旦接受到该信号,Apache将重新装载板块,而不需要重新启动服务器。

下面我们以PHP板块的加载为例,分析Apache的板块加载过程。在配置文件中增加了所上所示的指令后,Apache在加载板块时会根据板块名查找板块并加载, 对于每一个板块,Apache必需保证其文件名是以“mod_”开始的,如php的mod_php5.c。假如命名格式不对,Apache将认为此板块不合法。 module结构的name属性在最后是通过宏STANDARD20_MODULE_STUFF以__FILE__表现。 关于这点可以在后面详情mod_php5板块时有看到。 通过之前指令中指定的路径找到相关的动态链接库文件,Apache通过内部的函数获取动态链接库中的内容,并将板块的内容加载到内存中的指定变量中。

在真正激活板块之前,Apache会检查所加载的板块能否为真正的Apache板块,这个检测是通过检查magic字段进行的。而magic字段是通过宏STANDARD20_MODULE_STUFF表现,在这个宏中magic的值为MODULE_MAGIC_COOKIE,MODULE_MAGIC_COOKIE定义如下:

#define MODULE_MAGIC_COOKIE 0x41503232UL /* "AP22" */

最后Apache会调用相关函数(ap_add_loaded_module)将板块激活,此处的激活就是将板块放入相应的链表中(ap_top_modules链表:ap_top_modules链表用来保存Apache中所有的被激活的板块,包括默认的激活板块和激活的第三方板块。)

Apache2的mod_php5板块说明


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

AP_MODULE_DECLARE_DATA module php5_module = {
STANDARD20_MODULE_STUFF,
/* 宏,包括版本,小版本,板块索引,板块名,下一个板块指针等信息,其中板块名以__FILE__表现 */
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 /* 注册钩子,此函数通过ap_hoo_开头的函数在一次请求解决过程中对于指定的步骤注册钩子 */};

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

typedef struct module_struct module;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);}

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

/** Use this in all standard modules */#define STANDARD20_MODULE_STUFF MODULE_MAGIC_NUMBER_MAJOR, \
MODULE_MAGIC_NUMBER_MINOR, \ -1, \
__FILE__, \ NULL, \ NULL, \
MODULE_MAGIC_COOKIE, \ NULL /* rewrite args spot */

php_dir_cmds所定义的内容如下:

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板块定义的指令表。它实际上是一个command_rec结构的数组。 当Apache遇到指令的时候将逐一遍历各个板块中的指令表,查找能否有哪个板块能够解决该指令, 假如找到,则调用相应的解决函数,假如所有指令表中的板块都不能解决该指令,那么将报错。 如上可见,php板块仅提供php_value等5个指令。

php_ap2_register_hook函数的定义如下:

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);
ap_hook_child_init(php_apache_child_init, NULL, NULL, APR_HOOK_MIDDLE);}

以上代码公告了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的运行过程


Apache的运行分为启动阶段和运行阶段。 在启动阶段,Apache为了取得系统资源最大的使用权限,将以特权客户root(*nix系统)或者超级管理员Administrator(Windows系统)完成启动,并且整个过程处于一个单进程单线程的环境中,。 这个阶段包括配置文件解析(如http.conf文件)、板块加载(如mod_php,mod_perl)和系统资源初始化(例如日志文件、共享内存段、数据库连接等)等工作。

Apache的启动阶段执行了大量的初始化操作,并且将许多比较慢或者者花费比较高的操作都集中在这个阶段完成,以减少了后面解决请求服务的压力。

在运行阶段,Apache主要工作是解决客户的服务请求。 在这个阶段,Apache放弃特权客户级别,使用普通权限,这主要是基于安全性的考虑,防止因为代码的缺陷引起的安全漏洞。 Apache对HTTP的请求可以分为连接、解决和断开连接三个大的阶段。同时也可以分为11个小的阶段,依次为: Post-Read-Request,URI Translation,Header Parsing,Access Control,Authentication,Authorization,MIME Type Checking,FixUp,Response,Logging,CleanUp

Apache Hook机制


Apache 的Hook机制是指:Apache 允许板块(包括内部板块和外部板块,例如mod_php5.so,mod_perl.so等)将自己设置的函数注入到请求解决循环中。换句话说,板块可以在 Apache的任何一个解决阶段中挂接(Hook)上自己的解决函数,从而参加Apache的请求解决过程。 mod_php5.so/ php5apache2.dll就是将所包含的自己设置函数,通过Hook机制注入到Apache中,在Apache解决流程的各个阶段负责解决php请求。 关于Hook机制在Windows系统开发也经常遇到,在Windows开发既有系统级的钩子,又有应用级的钩子。

以上详情了apache的加载机制,hook机制,apache的运行过程以及php5板块的相关知识,下面简单的说明在查看源码中的少量常用对象。

Apache常用对象


在说到Apache的常用对象时,我们不得不先说下httpd.h文件。httpd.h文件包含了Apache的所有板块都需要的核心API。 它定义了许多系统常量。但是更重要的是它包含了下面少量对象的定义。

request_rec对象

当一个用户端请求到达Apache时,就会创立一个request_rec对象,当Apache解决完一个请求后,与这个请求对应的request_rec对象也会随之被释放。 request_rec对象包括与一个HTTP请求相关的所有数据,并且还包含少量Apache自己要用到的状态和用户端的内部字段。

server_rec对象

server_rec定义了一个逻辑上的WEB服务器。假如有定义虚拟主机,每一个虚拟主机拥有自己的server_rec对象。 server_rec对象在Apache启动时创立,当整个httpd关闭时才会被释放。 它包括服务器名称,连接信息,日志信息,针对服务器的配置,事务解决相关信息等 server_rec对象是继request_rec对象之后第二重要的对象。

conn_rec对象

conn_rec对象是TCP连接在Apache的内部表现。 它在用户端连接到服务器时创立,在连接断开时释放。

说明
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » Apache服务器是如何解析PHP 小编来给你解疑

发表回复