Jeder weiß, dass PHP auf einem bestimmten WEB-Server wie Nginx, Apache usw. ausgeführt werden muss, aber wie startet PHP, wie läuft es auf dem Server und dann beide Wie interagiere ich?
Empfohlene Tutorials: PHP-Video-Tutorial
1. WEB-Server ruft PHP-Schnittstelle auf
Am Beispiel des Apache-Servers sehen wir uns an, wie der Server PHP startet und Methoden in PHP aufruft. Wenn der Apache-Server PHP startet und ausführt, wird es normalerweise über das Modul mod_php7 integriert (wenn es sich um php5 handelt. 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 */ };
Wenn Apache eine Methode in PHP aufrufen muss, geschieht dies nur Die Anforderung muss über das Modul mod_php7 an PHP übermittelt werden. Nachdem die PHP-Schicht die Daten verarbeitet hat, ist der gesamte Vorgang abgeschlossen. (Bitte hinzufügen: Wenn der Apache-Server PHP startet, gibt es tatsächlich zwei Lademethoden Das eine ist statisches Laden und das andere ist dynamisches Laden. Die gerade besprochene Methode zum Laden von mod_php5-Modulen kann als statisches Laden verstanden werden, was bedeutet, dass Apache neu gestartet werden muss Der Server muss lediglich das PHP-Festmodul durch Senden von Signalen laden, um den Zweck des PHP-Starts zu erreichen. Vor dem dynamischen Laden muss das geladene Modul jedoch in eine dynamische Linkbibliothek kompiliert und dann konfiguriert werden Konfigurationsdatei des Servers). Die Modellstruktur von Apache in PHP wurde oben angegeben. Die entsprechende Modulstruktur im Apache-Server ist unten angegeben (der Quellcode befindet sich in Apache, derselbe unten):
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); }
Sie können php7_module sehen und module_struct Es gibt immer noch große Unterschiede, aber wenn Sie sehen, wie das Makro php7_module.STANDARD20_MODULE_STUFF definiert ist, denken Sie vielleicht, dass die beiden Strukturen sehr ähnlich sind. Tatsächlich definiert dieses Makro die ersten 8 Parameter in module_struct, die als definiert sind folgt:
#define STANDARD20_MODULE_STUFF MODULE_MAGIC_NUMBER_MAJOR, \ MODULE_MAGIC_NUMBER_MINOR, \ -1, \ __FILE__, \ NULL, \ NULL, \ MODULE_MAGIC_COOKIE, \ NULL /* rewrite args spot */
Dann definiert php7_module.php_dir_cmds alle Befehlssätze des Moduls. Die spezifische Definition lautet wie folgt (der Codepfad ist 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} };
Das heißt, die oben genannten fünf Anweisungen werden für Apache bereitgestellt. Der Implementierungsquellcode jeder Anweisung befindet sich schließlich in der Datei php7_module.php_ap2_register_hook Codepfad ist 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); }
Die Funktion php7_module.php_ap2_register_hook enthält 4 Hooks und entsprechende Verarbeitungsfunktionen. pre_config, pre_config, post_config und child_init sind Startup-Hooks, die aufgerufen werden, wenn die Der Handler-Hook ist ein Anforderungs-Hook. Serveranforderungen sind Aufrufe. Über diese Hooks kann PHP über den Apache-Server gestartet werden.
Zu diesem Zeitpunkt müssen Sie bereits wissen, wie der WEB-Server PHP startet und die Methoden in PHP aufruft. Lassen Sie mich Ihnen nun erklären, wie PHP die WEB-Server-Schnittstelle aufruft.
2. PHP ruft die WEB-Server-Schnittstelle auf
Bevor wir über dieses Problem sprechen, müssen wir verstehen, was SAPI ist. SAPI ist eigentlich eine gemeinsame Vereinbarung zwischen der Server-Abstraktionsschicht und der Server-Abstraktionsschicht. Es ist leicht zu verstehen, dass PHP eine Methode zum Löschen des Caches implementiert im Server, und die PHP-Schicht weiß es überhaupt nicht. Wie rufe ich diese Methode im Server auf? Zu diesem Zeitpunkt müssen beide Parteien eine Vereinbarung treffen, und dann stellt der Server eine Reihe vereinbarter Schnittstellen für PHP bereit. Wir nennen diese gemeinsamen Vereinbarungen mit der Server-Abstraktionsschicht die SAPI-Schnittstelle.
Die Frage ist, dass wir für den Server Apache einen Satz SAPI bereitstellen können, aber wenn das nächste Mal ein anderer Server oder ein anderer „Dritter“ hinzukommt, müssen wir ihnen dann auch einen Satz SAPI bereitstellen ? Wie wäre es mit einer separaten SAPI? Unsere intelligenten PHP-Entwickler müssen darüber nachgedacht haben, nämlich einen gemeinsamen Satz von SAPI-Schnittstellen für alle „Dritten“ bereitzustellen. Sie fragen sich jedoch möglicherweise: Wenn die neuen „Dritten“ die Schnittstelle benötigen, benötigt Ihr gemeinsames SAPI dies nicht , was soll ich tun? Mein Verständnis ist, neue Funktionen zur allgemeinen SAPI-Schnittstelle von PHP hinzuzufügen. Dies ist nur meine persönliche Meinung. Die allgemeine SAPI-Struktur ist wie folgt (Quellcode-Pfad: 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 //... };
Es gibt viele Variablen in dieser Struktur, daher werde ich sie nicht einzeln auflisten. Erklären wir kurz die darin enthaltenen Variablen: Die Startfunktion wird aufgerufen, wenn SAPI initialisiert wird, die Shutdown-Funktion wird zum Freigeben der SAPI-Datenstruktur verwendet und Speicher usw., read_cookie Es wird aufgerufen, wenn SAPI aktiviert ist, und weist dann den durch diese Funktion erhaltenen Wert SG(request_info).cookie_data zu. Wie passt der Apache-Server für das von PHP bereitgestellte allgemeine SAPI seine eigene Schnittstelle an? Die spezifische Struktur ist wie folgt (der Quellcodepfad ist 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接口文件。
看到这里,大家应该基本清楚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
Das obige ist der detaillierte Inhalt vonVertiefte Kenntnisse der Interaktion zwischen PHP und WEB-Servern. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!