日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > php >内容正文

php

深入理解PHP原理之PHP与WEB服务器交互

發布時間:2023/12/18 php 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 深入理解PHP原理之PHP与WEB服务器交互 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

往期精選(歡迎轉發~~)

  • 如何看待程序員35歲職業危機?
  • Java全套學習資料(14W字),耗時半年整理
  • 我肝了三個月,為你寫出了GO核心手冊
  • 消息隊列:從選型到原理,一文帶你全部掌握
  • 肝了一個月的ETCD,從Raft原理到實踐
  • 更多…

大家都知道,PHP需要在具體的WEB服務器中才能運行,例如Nginx、Apache等,但是PHP是怎樣啟動,又是怎樣在服務器中運行,然后兩者又是怎樣進行交互的呢?
  
1.WEB服務器調用PHP接口
  以Apache服務器為例,我們看看該服務器是怎樣啟動PHP,并調用PHP中的方法。Apache服務器啟動并運行PHP時,一般是通過mod_php7模塊的形式集成(如果是php5.*版本,就是mod_php5模塊,模塊后綴名根據php版本而定),mod_php7的結構如下(源碼路徑為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 */ };

當Apache需要調用PHP中的方法時,只需要將該請求通過mod_php7模塊傳達給PHP,PHP層處理完后將數據返回給Apache,整個過程就結束了(補充一下:Apache服務器啟動PHP時,其實有兩種加載方式,一種為靜態加載,一種為動態加載,剛才討論的mod_php5模塊加載方式可以理解為靜態加載,也就是需要重新啟動Apache服務器,才能將PHP加載進去;動態加載不需要重啟服務器,只需要通過發送信號的方式將PHP固定的模塊加載到服務器,以達到PHP啟動的目的,但是在進行動態加載前,需要將加載模塊編譯成動態鏈接庫,然后將其配置到服務器的配置文件中)。上面已經給出Apache在PHP中的model結構,下面給出Apache服務器中對應的module結構,如下(該源代碼在Apache中,下同):

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); }

可以看得出php7_module和module_struct還是有很大不同,不過如果看到php7_module.STANDARD20_MODULE_STUFF這個宏的定義方式,你可能就會覺得這兩個結構體很像,其實這個宏定義了module_struct中的前8個參數,定義如下:

#define STANDARD20_MODULE_STUFF MODULE_MAGIC_NUMBER_MAJOR, \MODULE_MAGIC_NUMBER_MINOR, \-1, \__FILE__, \NULL, \NULL, \MODULE_MAGIC_COOKIE, \NULL /* rewrite args spot */

然后php7_module.php_dir_cmds定義了模塊的所有指令集合,具體定義內容如下(代碼路徑為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} };

也就是說,PHP層只給Apache提供了上述5個指令,每個指令的實現源碼也在apache_config.c文件中,最后就剩php7_module.php_ap2_register_hook了,它定義的內容如下(代碼路徑為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_SIGNALSap_hook_child_init(zend_signal_init, NULL, NULL, APR_HOOK_MIDDLE); #endifap_hook_child_init(php_apache_child_init, NULL, NULL, APR_HOOK_MIDDLE); }

php7_module.php_ap2_register_hook函數包含4個鉤子和對應的處理函數,pre_config,pre_config、post_config和child_init是啟動鉤子,它們是在服務器啟動時調用,handler鉤子是請求掛鉤,它是在服務器請求是調用,通過這些鉤子,就可以通過Apache服務器啟動PHP。
   將到這里,想必大家已經知道WEB服務器是如何啟動PHP,并調用PHP中的方法了哈,下面再給大家講講PHP是如何調用WEB服務器接口的。

2.PHP調用WEB服務器接口
  在講述這個問題前,我們需要了解一下什么是SAPI。SAPI其實是與服務器抽象層之間遵守的共同約定,可以這么簡單理解,當PHP需要調用服務器中的方法,例如清除緩存,但是清除緩存的實現方法是在服務器中實現,PHP層根本就不知道怎么調用服務器中的該方法,怎么辦?這時雙方需要進行約定,然后服務器提供一套約定后的接口給PHP,我們把這些與服務器抽象層之間遵守的共同約定稱為SAPI接口。
  問題來了,對于服務器Apache,我們可以提供一套SAPI,但是如果下次又來個其它的服務器,或者其它的“第三方”,那么我們是不是也要給他們提供一套單獨的SAPI呢?我們聰明的PHP開發者肯定想到了這一點,即對所有的“第三方”提供一套通用的SAPI接口,但是你可以會問,如果新的“第三方”需要的接口,你的通用SAPI不支持,那怎么辦呢,我的理解是將新的功能添加到PHP的通用SAPI接口中,僅僅是個人見解哈,通用SAPI結構如下(源碼路徑: 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); // flushchar *(*read_cookies)(TSRMLS_D); //read Cookies//... };

該結構體變量較多,就不一一列舉,簡要說明一下里面的變量:startup函數是當SAPI初始化時會被調用,shutdown函數是用來釋放SAPI的數據結構和內存等,read_cookie 是在SAPI激活時被調用,然后將此函數獲取的值賦值給SG(request_info).cookie_data。那么對于PHP提供的通用SAPI,Apache服務器又是怎樣定制自己的接口呢?具體結構如下(源碼路徑為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概述”,不過我感覺該書中這部分內容講的有點繞,我重新編排了,然后提取了里面的重點,并加入個人見解,如果在該文中有哪些講的不對的地方,希望能幫我指出來,大家共同提高哈,謝謝!

參考: http://www.php-internals.com/

總結

以上是生活随笔為你收集整理的深入理解PHP原理之PHP与WEB服务器交互的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 久久久久久久久久av | 欧美亚洲国产一区二区三区 | 成年男女免费视频 | 亚洲欧洲免费视频 | 你懂的视频网站 | 人人看超碰 | www.一起操 | 成人av影院在线观看 | 免费一区二区三区视频在线 | 激情六月色 | 亚洲美女高潮久久久 | 首尔之春在线看 | 激情偷拍 | 日韩国产精品一区 | 日本免费小视频 | av在线播放一区二区三区 | 欧美精品久久久久久 | 黄色录像a| 久久久久久久久久一区 | 狠狠撸在线 | 精品二区在线 | 国产成人免费在线观看 | 999av视频 | 欧美区二区三区 | 亚洲成人网在线播放 | 国产精品久久久久高潮 | av高潮| 男人午夜av| 国产91精品在线观看 | av成人在线免费观看 | 青草热视频 | 农村妇女精品一区二区 | 久久久久久久久久久久电影 | youjizzxxx69 | 久久久精品影院 | 一级黄色片一级黄色片 | 成人综合一区 | 一级黄色片免费看 | av一二三区 | 中文久久久| 在线观看成人动漫 | 最新中文字幕在线观看 | 野外一级片 | 日韩女优在线观看 | 亚洲性欧美色 | 国产女主播在线观看 | 美女扒开内裤让男人捅 | 亚洲精品无码专区 | 人人看人人模 | 久久公开视频 | 韩国三级hd两男一女 | 国产免费中文字幕 | 久久久精品人妻无码专区 | 亚洲久久一区二区 | 亚洲 欧美 激情 小说 另类 | 四虎在线看片 | 在线少妇 | 春色av | 国产小视频在线观看 | 精品人妻中文无码av在线 | 日韩av三级在线观看 | 国产精品815.cc红桃 | 亚洲国产欧美日韩在线 | www一区二区三区 | 久久久久久一 | 最新av| www.午夜视频 | 黄色成人毛片 | 国产一区二区三区精品在线 | 国产做受视频 | av手机免费在线观看 | www午夜视频| 亚洲永久无码精品一区二区 | 美女脱了内裤喂我喝尿视频 | 亚洲伦理网 | 日本顶级大片 | 521av在线 | 少妇性xxxxxxxxx色武功 | 久久黄网站 | 欧美国产成人精品一区二区三区 | 优优色影院 | 欧美日韩国产免费 | 日本动漫艳母 | 超污巨黄的小短文 | 色九九视频 | 欧美aaa级 | 欧美亚洲成人网 | 国产一区二区久久精品 | 就爱啪啪网站 | 男人在线视频 | 熟妇大屁股一区二区三区视频 | 欧美日韩在线一区二区三区 | 深夜视频在线观看 | 亚洲成av人影院 | 在线观看国产精品入口男同 | 久久99精品久久久久子伦 | xxxx在线视频 | 网爆门在线 | 曰批免费视频播放免费 |