入门客AI创业平台(我带你入门,你带我飞行)
博文笔记

PHP函数源码之SESSION实现机制

创建时间:2016-09-03 投稿人: 浏览次数:508

Session是以扩展的形式嵌入到PHP内核的,所以我们可以把Session当成扩展来看待。

一般扩展被载入到PHP会经过下面几个过程

[cpp] view plain copy  在CODE上查看代码片派生到我的代码片
  1. #define PHP_MINIT_FUNCTION      ZEND_MODULE_STARTUP_D       // 初始化module时运行   
  2. #define PHP_MSHUTDOWN_FUNCTION  ZEND_MODULE_SHUTDOWN_D      // 当module被卸载时运行  
  3. #define PHP_RINIT_FUNCTION      ZEND_MODULE_ACTIVATE_D      // 当一个REQUEST请求初始化时运行  
  4. #define PHP_RSHUTDOWN_FUNCTION  ZEND_MODULE_DEACTIVATE_D    // 当一个REQUEST请求结束时运行    
  5. #define PHP_MINFO_FUNCTION      ZEND_MODULE_INFO_D          // 这个是设置phpinfo中这个模块的信息  
  6. #define PHP_GINIT_FUNCTION      ZEND_GINIT_FUNCTION         // 初始化全局变量时   
  7. #define PHP_GSHUTDOWN_FUNCTION  ZEND_GSHUTDOWN_FUNCTION     // 释放全局变量时  
具体的执行顺序跟PHP的生命周期相同
MINIT -> RINIT ->RSHUTDOWN -> MSHUTDOWN

对于Session而言,PHP_MINIT_FUNCTION主要完成的初始化工作包括(注:不同版本的PHP具体处理过程并不完全相同,如PHP 5.4+提供了SessionHandlerInterface,这样可以通过session_set_save_handler ( SessionHandlerInterface $sessionhandler )的方式自定义Session的处理机制,而不必像之前一样使用冗长的boolsession_set_save_handler ( callable $open , callable $close , callable $read , callable $write , callable $destroy , callable $gc [, callable $create_sid ] )):

(1).  注册$_SESSION超全局变量:

[cpp] view plain copy  在CODE上查看代码片派生到我的代码片
  1. zend_register_auto_global("_SESSION", sizeof("_SESSION")-1, NULL TSRMLS_CC);    
就是说,$_SESSION超全局变量实际上是在session的MINIT阶段被注册的。

相关阅读 :PHP语言中的超级全局变量(Superglobals) http://www.walu.cc/phpbook/12.5.md

(2).  读取ini文件中的相关配置。

[cpp] view plain copy  在CODE上查看代码片派生到我的代码片
  1. REGISTER_INI_ENTRIES();    

 REGISTER_INI_ENTRIES();实际上是一个宏定义:

#define REGISTER_INI_ENTRIES() zend_register_ini_entries(ini_entries, module_number TSRMLS_CC)

因此,实际上是调用zend_register_ini_entries(ini_entries, module_number TSRMLS_CC)。关于ini文件的解析和配置,已经超出了本文的范畴,可以参考这篇文章:http://www.cnblogs.com/driftcloudy/p/4011954.html 。

   扩展中读取和设置ini的相关配置位于PHP_INI_BEGIN和PHP_INI_END宏之间。对于session而言,实际上包括:

[cpp] view plain copy  在CODE上查看代码片派生到我的代码片
  1. /* {{{ PHP_INI 
  2.  */  
  3. PHP_INI_BEGIN()  
  4.     STD_PHP_INI_ENTRY("session.save_path",          "",          PHP_INI_ALL, OnUpdateSaveDir,save_path,          php_ps_globals,    ps_globals)  
  5.     STD_PHP_INI_ENTRY("session.name",               "PHPSESSID", PHP_INI_ALL, OnUpdateName, session_name,       php_ps_globals,    ps_globals)  
  6.     PHP_INI_ENTRY("session.save_handler",           "files",     PHP_INI_ALL, OnUpdateSaveHandler)  
  7.     STD_PHP_INI_BOOLEAN("session.auto_start",       "0",         PHP_INI_PERDIR, OnUpdateBool,   auto_start,         php_ps_globals,    ps_globals)  
  8.     STD_PHP_INI_ENTRY("session.gc_probability",     "1",         PHP_INI_ALL, OnUpdateLong,   gc_probability,     php_ps_globals,    ps_globals)  
  9.     STD_PHP_INI_ENTRY("session.gc_divisor",         "100",       PHP_INI_ALL, OnUpdateLong,   gc_divisor,         php_ps_globals,    ps_globals)  
  10.     STD_PHP_INI_ENTRY("session.gc_maxlifetime",     "1440",      PHP_INI_ALL, OnUpdateLong,   gc_maxlifetime,     php_ps_globals,    ps_globals)  
  11.     PHP_INI_ENTRY("session.serialize_handler",      "php",       PHP_INI_ALL, OnUpdateSerializer)  
  12.     STD_PHP_INI_ENTRY("session.cookie_lifetime",    "0",         PHP_INI_ALL, OnUpdateLong,   cookie_lifetime,    php_ps_globals,    ps_globals)  
  13.     STD_PHP_INI_ENTRY("session.cookie_path",        "/",         PHP_INI_ALL, OnUpdateString, cookie_path,        php_ps_globals,    ps_globals)  
  14.     STD_PHP_INI_ENTRY("session.cookie_domain",      "",          PHP_INI_ALL, OnUpdateString, cookie_domain,      php_ps_globals,    ps_globals)  
  15.     STD_PHP_INI_BOOLEAN("session.cookie_secure",    "",          PHP_INI_ALL, OnUpdateBool,   cookie_secure,      php_ps_globals,    ps_globals)  
  16.     STD_PHP_INI_BOOLEAN("session.cookie_httponly",  "",          PHP_INI_ALL, OnUpdateBool,   cookie_httponly,    php_ps_globals,    ps_globals)  
  17.     STD_PHP_INI_BOOLEAN("session.use_cookies",      "1",         PHP_INI_ALL, OnUpdateBool,   use_cookies,        php_ps_globals,    ps_globals)  
  18.     STD_PHP_INI_BOOLEAN("session.use_only_cookies", "1",         PHP_INI_ALL, OnUpdateBool,   use_only_cookies,   php_ps_globals,    ps_globals)  
  19.     STD_PHP_INI_BOOLEAN("session.use_strict_mode",  "0",         PHP_INI_ALL, OnUpdateBool,   use_strict_mode,    php_ps_globals,    ps_globals)  
  20.     STD_PHP_INI_ENTRY("session.referer_check",      "",          PHP_INI_ALL, OnUpdateString, extern_referer_chk, php_ps_globals,    ps_globals)  
  21. #if HAVE_DEV_URANDOM  
  22.     STD_PHP_INI_ENTRY("session.entropy_file",       "/dev/urandom",          PHP_INI_ALL, OnUpdateString, entropy_file,       php_ps_globals,    ps_globals)  
  23.     STD_PHP_INI_ENTRY("session.entropy_length",     "32",         PHP_INI_ALL, OnUpdateLong,   entropy_length,     php_ps_globals,    ps_globals)  
  24. #elif HAVE_DEV_ARANDOM  
  25.     STD_PHP_INI_ENTRY("session.entropy_file",       "/dev/arandom",          PHP_INI_ALL, OnUpdateString, entropy_file,       php_ps_globals,    ps_globals)  
  26.     STD_PHP_INI_ENTRY("session.entropy_length",     "32",         PHP_INI_ALL, OnUpdateLong,   entropy_length,     php_ps_globals,    ps_globals)  
  27. #else  
  28.     STD_PHP_INI_ENTRY("session.entropy_file",       "",          PHP_INI_ALL, OnUpdateString, entropy_file,       php_ps_globals,    ps_globals)  
  29.     STD_PHP_INI_ENTRY("session.entropy_length",     "0",         PHP_INI_ALL, OnUpdateLong,   entropy_length,     php_ps_globals,    ps_globals)  
  30. #endif  
  31.     STD_PHP_INI_ENTRY("session.cache_limiter",      "nocache",   PHP_INI_ALL, OnUpdateString, cache_limiter,      php_ps_globals,    ps_globals)  
  32.     STD_PHP_INI_ENTRY("session.cache_expire",       "180",       PHP_INI_ALL, OnUpdateLong,   cache_expire,       php_ps_globals,    ps_globals)  
  33.     PHP_INI_ENTRY("session.use_trans_sid",          "0",         PHP_INI_ALL, OnUpdateTransSid)  
  34.     PHP_INI_ENTRY("session.hash_function",          "0",         PHP_INI_ALL, OnUpdateHashFunc)  
  35.     STD_PHP_INI_ENTRY("session.hash_bits_per_character", "4",    PHP_INI_ALL, OnUpdateLong,   hash_bits_per_character, php_ps_globals, ps_globals)  
  36.   
  37.     /* Upload progress */  
  38.     STD_PHP_INI_BOOLEAN("session.upload_progress.enabled",  
  39.                                                     "1",     ZEND_INI_PERDIR, OnUpdateBool,        rfc1867_enabled, php_ps_globals, ps_globals)  
  40.     STD_PHP_INI_BOOLEAN("session.upload_progress.cleanup",  
  41.                                                     "1",     ZEND_INI_PERDIR, OnUpdateBool,        rfc1867_cleanup, php_ps_globals, ps_globals)  
  42.     STD_PHP_INI_ENTRY("session.upload_progress.prefix",  
  43.                                          "upload_progress_", ZEND_INI_PERDIR, OnUpdateSmartStr,      rfc1867_prefix,  php_ps_globals, ps_globals)  
  44.     STD_PHP_INI_ENTRY("session.upload_progress.name",  
  45.                               "PHP_SESSION_UPLOAD_PROGRESS", ZEND_INI_PERDIR, OnUpdateSmartStr,      rfc1867_name,    php_ps_globals, ps_globals)  
  46.     STD_PHP_INI_ENTRY("session.upload_progress.freq",  "1%", ZEND_INI_PERDIR, OnUpdateRfc1867Freq, rfc1867_freq,    php_ps_globals, ps_globals)  
  47.     STD_PHP_INI_ENTRY("session.upload_progress.min_freq",  
  48.                                                        "1",  ZEND_INI_PERDIR, OnUpdateReal,        rfc1867_min_freq,php_ps_globals, ps_globals)  
  49.   
  50.     /* Commented out until future discussion */  
  51.     /* PHP_INI_ENTRY("session.encode_sources", "globals,track", PHP_INI_ALL, NULL) */  
  52. PHP_INI_END()  
  53. /* }}} */  
 如果在ini文件中没有配置相关的参数项,在session的MINIT阶段,参数会被初始化为默认的值。

(3).  注册SessionHandler和SessionHandlerInterface这两个Class

自php 5.4起,php提供了SessionHandler和SessionHandlerInterface这两个Class, 因此还需要对这两个Class做相关的初始化工作。这是通过:

INIT_CLASS_ENTRY(ce, PS_IFACE_NAME, php_session_iface_functions);

INIT_CLASS_ENTRY(ce, PS_CLASS_NAME, php_session_class_functions);

来实现的,有兴趣的同学可以查看具体的实现过程,这里不再赘述。



[cpp] view plain copy  在CODE上查看代码片派生到我的代码片
  1. static PHP_RINIT_FUNCTION(session) /* {{{ */  
  2. {  
  3.     return php_rinit_session(PS(auto_start) TSRMLS_CC);  
  4. }  
  5. /* ******************************** 
  6.    * Module Setup and Destruction * 
  7.    ******************************** */  
  8.   
  9. static int php_rinit_session(zend_bool auto_start TSRMLS_DC) /* {{{ */  
  10. {// 初始化session相关的全局变量  
  11.     php_rinit_session_globals(TSRMLS_C);  
  12. // 根据ini的配置查找session.save_handler,从而确定是使用files还是user( 或者是其他的扩展方式)来处理session:  
  13.     if (PS(mod) == NULL) {  
  14.         char *value;  
  15.   
  16.         value = zend_ini_string("session.save_handler", sizeof("session.save_handler"), 0);  
  17.         if (value) {  
  18.             PS(mod) = _php_find_ps_module(value TSRMLS_CC);  
  19.         }  
  20.     }  
  21. // 确定完session的save_handler之后。需要确定serializer,Serializer用于完成session数据的序列化和反序列化  
  22.     if (PS(serializer) == NULL) {  
  23.         char *value;  
  24.   
  25.         value = zend_ini_string("session.serialize_handler", sizeof("session.serialize_handler"), 0);  
  26.         if (value) {  
  27.             PS(serializer) = _php_find_ps_serializer(value TSRMLS_CC);  
  28.         }  
  29.     }  
  30. // mod和serializer 如果有一个不成功,更新session_status 状态  
  31.     if (PS(mod) == NULL || PS(serializer) == NULL) {  
  32.         /* current status is unusable */  
  33.         PS(session_status) = php_session_disabled;  
  34.         return SUCCESS;  
  35.     }  
  36. // 如果ini 中 session.auto_start 为1 自动session_start  
  37.     if (auto_start) {  
  38.         php_session_start(TSRMLS_C);  
  39.     }  
  40.   
  41.     return SUCCESS;  
  42. } /* }}} */  
正如上面的代码所写,PHP_RINIT_FUNCTION(session)主要经过下面几个步骤:

(1).初始化session相关的全局变量,这是通过php_rinit_session_globals来完成的:

[cpp] view plain copy  在CODE上查看代码片派生到我的代码片
  1. /* Dispatched by RINIT and by php_session_destroy */  
  2. static inline void php_rinit_session_globals(TSRMLS_D) /* {{{ */  
  3. {  
  4.     PS(id) = NULL;  
  5.     PS(session_status) = php_session_none;  
  6.     PS(mod_data) = NULL;  
  7.     PS(mod_user_is_open) = 0;  
  8.     /* Do NOT init PS(mod_user_names) here! */  
  9.     PS(http_session_vars) = NULL;  
  10. }  
  11. /* }}} */  

(2).根据ini的配置查找session.save_handler,从而确定是使用files还是user( 或者是其他的扩展方式)来处理session:

[cpp] view plain copy  在CODE上查看代码片派生到我的代码片
  1. if (PS(mod) == NULL) {  
  2.         char *value;  
  3.   
  4.         value = zend_ini_string("session.save_handler", sizeof("session.save_handler"), 0);  
  5.         if (value) {  
  6.             PS(mod) = _php_find_ps_module(value TSRMLS_CC);  
  7.         }  
  8.     }  

 确定是user还是files来处理session的逻辑是由_php_find_ps_module来完成的,这个函数会依次查找ps_modules中预定义的module, 一旦查找成功,立即返回:

[cpp] view plain copy  在CODE上查看代码片派生到我的代码片
    声明:该文观点仅代表作者本人,入门客AI创业平台信息发布平台仅提供信息存储空间服务,如有疑问请联系rumenke@qq.com。