Everyone knows that PHP needs to run in a specific WEB server, such as Nginx, Apache, etc., but how does PHP start and how does it run in the server? How to interact?
Recommended tutorial: php video tutorial
##1.WEB server calls PHP interface
Taking the Apache server as an example, let’s see how the server starts PHP and calls methods in PHP. When the Apache server starts and runs PHP, it is usually integrated through the mod_php7 module (if it is the php5. 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 */ };
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); }
#define STANDARD20_MODULE_STUFF MODULE_MAGIC_NUMBER_MAJOR, \ MODULE_MAGIC_NUMBER_MINOR, \ -1, \ __FILE__, \ NULL, \ NULL, \ MODULE_MAGIC_COOKIE, \ NULL /* rewrite args spot */
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} };
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); }
2.PHP calls the WEB server interface
Before talking about this problem, we need to understand what SAPI is. SAPI is actually a common agreement observed between the server abstraction layer and the server abstraction layer. It can be easily understood. When PHP needs to call a method in the server, such as clearing the cache, the implementation method of clearing the cache is implemented in the server, and the PHP layer does not know it at all. How to call this method in the server? What should I do? At this time, both parties need to make an agreement, and then the server provides a set of agreed interfaces to PHP. We call these common agreements with the server abstraction layer the SAPI interface. The question is, for the server Apache, we can provide a set of SAPI, but if another server or other "third party" comes next time, then do we also have to provide them with a set of SAPI? What about a separate SAPI? Our smart PHP developers must have thought of this, that is, to provide a common set of SAPI interfaces for all "third parties", but you may ask, if the new "third parties" need the interface, your common SAPI does not Yes, what should I do? My understanding is to add new functions to the general SAPI interface of PHP. This is just my personal opinion. The general SAPI structure is as follows (source code path: 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 //... };
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
The above is the detailed content of In-depth understanding of PHP and WEB server interaction. For more information, please follow other related articles on the PHP Chinese website!