Home>Article>Backend Development> In-depth understanding of PHP and WEB server interaction

In-depth understanding of PHP and WEB server interaction

angryTom
angryTom forward
2019-08-21 17:55:05 2467browse

In-depth understanding of PHP and WEB server interaction

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 */ };

When Apache needs to call a method in PHP, it only needs to convey the request to PHP through the mod_php7 module. After the PHP layer processes the data, it returns the data to Apache. The whole process is It’s over (just to 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 can be understood as static loading, which means that Apache needs to be restarted. The server can load PHP into it; dynamic loading does not require restarting the server. It only needs to load the PHP fixed module to the server by sending signals to achieve the purpose of PHP startup. However, before dynamic loading, the loaded module needs to be compiled. into a dynamic link library and then configure it 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); }

The 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 //... };

There are many variables in this structure, so I won’t list them one by one. Let’s briefly explain the variables inside: the startup function will be 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 };

  上述源码目录php/sapi/apache2handler/中,目录php/sapi下面放的都是通过SAPI调用的“第三方”,该目录结构如下图所示,目录php/sapi/apache2handler中都是与PHP交互的接口,sapi_apache2.c是PHP与Apache约定的SAPI接口文件。

20160821163330607 (1).jpg

  看到这里,大家应该基本清楚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!

Statement:
This article is reproduced at:csdn.net. If there is any infringement, please contact admin@php.cn delete