Home > Article > Backend Development > In-depth understanding of PHP principles and interaction between PHP and WEB server
Everyone knows that PHP needs to run in a specific WEB server, such as Nginx, Apache, etc., but how does PHP start, how does it run in the server, and how do the two interact?
1. The WEB server calls the 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.* version, it is the mod_php5
module, and the module suffix name depends on the PHP version). The structure of mod_php7 is as follows (the source code path is 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 */ };
When Apache needs to call a method in PHP, it only needs to communicate the request to PHP through the mod_php7 module. The PHP layer After processing, the data is returned to Apache, and the whole process is over (please add: when the Apache server starts PHP, there are actually two loading methods, one is static loading and the other is dynamic loading. The mod_php5 module loading method just discussed It can be understood as static loading, that is, the Apache server needs to be restarted to load PHP into it; dynamic loading does not require restarting the server, and only needs to load PHP fixed modules to the server by sending signals to achieve the purpose of PHP startup. But before dynamic loading, the loading module needs to be compiled into a dynamic link library, and then configured into the server's configuration file). The model structure of Apache in PHP has been given above. The corresponding module structure in the Apache server is given below, as follows (the source code is in Apache, the same below):
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); }
You can see php7_module and module_struct There are still big differences, but if you see the way the macro php7_module.STANDARD20_MODULE_STUFF is defined, you may think that the two structures are very similar. In fact, this macro defines the first 8 parameters in module_struct, which are defined as follows:
#define STANDARD20_MODULE_STUFF MODULE_MAGIC_NUMBER_MAJOR, \ MODULE_MAGIC_NUMBER_MINOR, \ -1, \ __FILE__, \ NULL, \ NULL, \ MODULE_MAGIC_COOKIE, \ NULL /* rewrite args spot */
Then php7_module.php_dir_cmds defines all the instruction sets of the module. The specific definition content is as follows (the code path is 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} };
In other words, the PHP layer only The above five instructions are provided to Apache. The implementation source code of each instruction is also in the apache_config.c file. Finally, only php7_module.php_ap2_register_hook is left. Its definition is as follows (the code path is 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 function contains 4 hooks and corresponding processing functions. pre_config, pre_config, post_config and child_init are startup hooks, which are called when the server starts. The handler hook is a request hook, which is Server requests are calls, and through these hooks, PHP can be started through the Apache server.
At this point, you must already know how the WEB server starts PHP and calls the methods in PHP. Now let me tell you how PHP calls the WEB server interface.
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 //... };
This structure has many variables, so I won’t list them one by one. Let’s briefly explain the variables inside: the startup function is called when SAPI is initialized, the shutdown function is used to release the data structure and memory of SAPI, read_cookie It is called when SAPI is activated, and then assigns the value obtained by this function to SG(request_info).cookie_data. So for the general SAPI provided by PHP, how does the Apache server customize its own interface? The specific structure is as follows (the source code path is 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 };
In the above source code directory php/sapi/apache2handler/, everything placed under the directory php/sapi is called through SAPI." Third Party", the directory structure is as shown in the figure below. The directory php/sapi/apache2handler contains the interface for interacting with PHP. sapi_apache2.c is the SAPI interface file agreed between PHP and Apache.
##
看到这里,大家应该基本清楚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的接口,是不是很简单呢:)
更多相关问题可以访问PHP中文网相关教程:https://www.php.cn/course/list/29/type/2.html
The above is the detailed content of In-depth understanding of PHP principles and interaction between PHP and WEB server. For more information, please follow other related articles on the PHP Chinese website!