PHP常说的SAPI是什么

PHP常说的SAPI是什么什么是 SAPISAPI 全称是 ServerApplic 即服务器应用编程接口 实质上就是定义了一个统一的接口 它的核心就是一个结构体 sapi mod

大家好,欢迎来到IT知识分享网。

什么是SAPI

SAPI全称是Server Application Programming Interface,即服务器应用编程接口,实质上就是定义了一个统一的接口,它的核心就是一个结构体sapi_module_struct。SAPI提供给了外部应用跟php通信的管道,这个外部应用包括不限于Apache,httpd,liunx终端等,sapi通俗的讲就是php-cgi,php-cli,mod_php等,php就是php内核。PHP架构图如下:

PHP常说的SAPI是什么

从源码理解SAPI

首先看一下他的工作原理:

无论是cgi还是apache的mod_php、cli都是按sapi_module_struct结构实现的,这种做法屏蔽了php的不同实现,于是外部程序通过调用sapi接口的sapi_module_struct接口就可以无差别的调用不同的底层php程序。sapi_module_struct结构如下:

struct _sapi_module_struct { // SAPI模块结构 char *name; // 应用层名称,比如cli,cgi等 char *pretty_name; // 应用层更易读的名字,比如cli对应的就是Command Line Interface int (*startup)(struct _sapi_module_struct *sapi_module); // 当一个应用要调用php的时候,这个模块启动的时候会调用的函数 int (*shutdown)(struct _sapi_module_struct *sapi_module); // 当一个应用要调用php的时候,这个模块结束的时候会调用的函数 int (*activate)(void); // 在处理每个request的时候,激活需要调用的函数 int (*deactivate)(void); // 在处理完每个request的时候,收尾时候要调用的函数 size_t (*ub_write)(const char *str, size_t str_length); // 这个函数告诉php如何输出数据 void (*flush)(void *server_context); // 提供给php的刷新缓存的函数指针 zend_stat_t *(*get_stat)(void); // 用来判断要执行文件的权限,来判断是否有执行权限 char *(*getenv)(char *name, size_t name_len); // 获取环境变量的方法 void (*sapi_error)(int type, const char *error_msg, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3); // 错误处理方法 int (*header_handler)(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers); // 这个函数会在我们调用header()的时候被调用 int (*send_headers)(sapi_headers_struct *sapi_headers); // 发送所有的header void (*send_header)(sapi_header_struct *sapi_header, void *server_context); // 单独发送某一个header size_t (*read_post)(char *buffer, size_t count_bytes); // 如何获取HTTP POST中的数据 char *(*read_cookies)(void); // 如何获取cookie中的数据 void (*register_server_variables)(zval *track_vars_array); // 这个函数可以给$_SERVER中获取变量 void (*log_message)(char *message, int syslog_type_int); // 输出错误信息函数 double (*get_request_time)(void); // 获取请求时间的函数 void (*terminate_process)(void); // TODO: 调用exit的时候调用的方法 char *php_ini_path_override; // PHP的ini文件被复写了所复写的地址 void (*default_post_reader)(void); // 这里和前面的read_post有个差别,read_post负责如何获取POST数据,而这里的函数负责如何解析POST数据 void (*treat_data)(int arg, char *str, zval *destArray); // 对数据进行处理,比如进行安全过滤等。 default_post_reader/tread_data/input_filter是三个能对输入进行过滤和处理的函数 char *executable_location; // 执行的地理位置 int php_ini_ignore; // 是否不使用任何ini配置文件,比如php -n 就将这个位置设置为1 int php_ini_ignore_cwd; // 不在当前路径寻找php.ini int (*get_fd)(int *fd); // 获取执行文件的fd int (*force_http_10)(void); // 强制使用http1.0 int (*get_target_uid)(uid_t *); // 获取执行程序的uid int (*get_target_gid)(gid_t *); // 获取执行程序的gid unsigned int (*input_filter)(int arg, char *var, char val, size_t val_len, size_t *new_val_len); // 对输入进行过滤。比如将输入参数填充到自动全局变量$_GET, $_POST, $_COOKIE中 void (*ini_defaults)(HashTable *configuration_hash); // 默认的ini配置 int phpinfo_as_text; // 是否打印phpinfo信息 char *ini_entries; // 有没有附带的ini配置,比如使用php -d date.timezone=America/Adak,可以在命令行中设置时区 const zend_function_entry *additional_functions; // 每个SAPI模块特有的一些函数注册,比如cli的cli_get_process_title unsigned int (*input_filter_init)(void); // TODO: };

以mod_php为例

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_开头的函数在一次请求处理过程中对于指定的步骤注册钩子 */ };

着重看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); } 

ap_hook_post_config这个钩子在apache启动时调用php_apache_server_startup函数,然后函数内调用sapi_startup启动sapi。通过各模块mint()函数初始化模块,ap_hook_handler会在请求到来时运行php_handler函数,函数内再调用php_apache_request_ctor,执行rmint()操作

其他模式如cli、php-cgi等模式下,sapi_startup()函数是定义在int main主函数中,即直接运行就开始创建php程序,而mod_php一开始并不需运行,等到请求到来时会自动开始创建php程序。启动sapi后,php程序会再调用sapi_module中的startup函数指针,完成相应模式下php的创建工作。

cgi模式下的startup函数为php_cgi_startup,该函数再直接调用通用的php_module_stratup(&sapi_module)完成php创建,初始化zend引擎。

总结来说sapi定义了一种面向接口编程的规范,而php-cli、php-cgi等则是实现了该规范的程序

待续。。。。。。

注:

sapi_module_struct、sapi_startup()定义在SAPI.c中

php_module_startup()定义在main.c中

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/142018.html

(0)
上一篇 2025-05-13 14:33
下一篇 2025-05-13 14:45

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信