Home >php教程 >php手册 >[转][转]王帅:深入PHP内核

[转][转]王帅:深入PHP内核

WBOY
WBOYOriginal
2016-06-06 20:14:501128browse

深入PHP内核关于作者:王帅,腾讯企业QQ SaaS团队Leader。深入PHP内核(一)——弱类型变量原理探究摘要:PHP作为一门简单而强大的语言,能够提供很多Web适用的



深入PHP内核

如果你对弱类型原理理解不深刻,在变量比较时候,会出现“超出预期”的惊喜。

[php] 

第二阶段是请求初始化阶段(RINT),在模块初始化并激活后,会创建PHP运行环境,同时调用所有模块注册的RINT函数,调用每个扩展的请求初始化函数 ,设定特定的环境变量、分配资源或执行其他任务,如审核。

[php] 

第三阶段,请求处理完成后,会调用PHP_RSHUTDOWN_FUNCTION进行回收,这是每个扩展的请求关闭函数,执行最后的清理工作。Zend引擎执行清理过程、垃圾收集、对之前的请求期间用到的每个变量执行unset。请求完成可能是执行到脚本完成,也可能是调用die()或exit()函数完成

第四阶段,当PHP生命周期结束时候,PHP_MSHUTDOWN_FUNCTION对模块进行回收处理,这是每个扩展的模块关闭函数,用于关闭自己的内核子系统。

[php] 

1. CLI/CGI模式

CLI和CGI都属于单进程模式,PHP的生命周期在一次请求中完成。也就是说每次执行PHP脚本,都会执行第二部分讲的四个INT和Shutdown事件。

由上面代码可见,PHP的SAPI像是面向对象中基类,SAPI.h和SAPI.c包含的函数是抽象基类的声明和定义,各个服务器用的SAPI模式,则是继承了这个基类,并重新定义基类方法的子类。

总结

PHP的SAPI是Zend引擎提供的一组标准交互接口,通过注册初始化、析构、输入、输出等接口,我们可以将应用程序运行在Zend引擎上,也可以把PHP嵌入到类似Apache的Web Server中。PHP常见的SAPI模式有五种,CGI/CLI模式、多进程模式、多线程模式、FastCGI模式和内嵌模式。

了解PHP的SAPI机制意义重大,帮助我们理解PHP的生命周期,并了解如何更好的通过C/C++为PHP编写扩展,并在生命周期中找到提高系统性能的方式。




深入PHP内核(三)——内核利器哈希表与哈希碰撞攻击


摘要:PHP作为一门简单而强大的语言,能够提供很多Web适用的语言特性。从实践出发,继弱类型变量原理探究后,王帅将继续带大家弄清PHP内核中的一些常用部分,本期则是内核利器哈希表与哈希碰撞攻击。

【导读】王帅在海量分布式Web系统有超过8年沉淀,主导过多个大型系统的架构设计,目前在腾讯企业SaaS团队。

PHP内核系列文章,是作者在PHP领域实践中,把相关原理性的知识,通过更便于理解的方式,系统整理出来分享给读者。希望通过PHP原理性的轻量解读,对这门Web领域最热门技术的优秀架构分析解构,让更多的人不断的深入了解语言的原理本身,更容易定位、理解一些问题背后原因,更游刃有余的做基础架构设计。同时希望影响更多的人才投入Web开源领域,不仅是应用和学习一门技术、组件,同样能够贡献更多高质量组件,像战国时期的百家争鸣一样,PHP开源界花开遍地。

作者一直倡导技术的深入学习就像职业篮球训练,80%的时间都是基本功的训练,球场上实际战术的练习只是基本功的应用。同样的,学习PHP语言本身的特性,应当是每个PHP领域工程师所掌握、理解的,至于系统的架构设计也是基于对Linux、Mysql、Nginx等原理机制足够理解后,战术性的使用。

1)  *ht 是哈希表的指针,这里既可以传入一个已存在的HashTable, 也可以通过内核宏ALLOC_HASHTABLE(ht)来自动申请一块HashTable内存。ALLOC_HASHTABLE(ht)相当于ht=emalloc(sizeof(HashTable))

2)  nSize 哈希表能拥有的最大数量。通过预先申请好内存的方式,减少哈希表rehash操作。

3)  pHashFunction 自定义哈希函数的钩子

4)  pDesctructor 哈希表析构的回调函数,当删除一个哈希表的时候,会调用。

5)  persistent 对应HashTable.persistent,当设置为true的时候,不会在RSHUTDOWN阶段自动销毁。

我们通过更新哈希表的操作方式,来分析哈希表的操作机制: 

[php] 

1) 通过哈希算法  times33(Key) & (nTableSize-1) ,生成Key对应的哈希值A,获取arBuckets[A]的值

2) 判断arBuckets[A]是否存在,如果存在而且没有哈希冲突,进行数据update(UPDATE_DATA)。如果存在但是Key不相同说明有哈希冲突,在arBuckets[A]链表中寻找Key是否存在,如果存在,执行update操作(UPDATE_DATA)

3) 如果arBuckets[A]不存在,创建新的arBucket[A](INIT_DATA)。或哈希冲突情况下,在arBuckets[A]的链表中找不到Key。创建新的bucket(INIT_DATA),并把新的buckets放在arBucket[A]链表头

4) 维护哈希表的逻辑链表(CONNECT_TO_GLOBAL_DLLIST)。

5) 如果发现新插入元素已经超过HashTable的nTableSize,自动扩容至2倍nTableSize,重新哈希后维护新的HashTable。

3. PHP使用的哈希函数

PHP的哈希表是用Times33哈希算法,又称为DJBX33A。这是一个使用比较广泛的对字符串的哈希算法,计算速度快,散列均匀,Perl和Apache都使用了这个算法。算法原理就是不断的乘以33,其算法原型如下:

[php] 

PHP在哈希算法上有所优化,使用了(hash4. 操作哈希表的内部函数

PHP的变量符号表是通过哈希表来维护,,首先介绍一下再PHP扩展中如何创建一个新的变量。PHP变量介绍,请看我上一篇文章,

这里的zend_hash_update会更新变量符号表。PHP的数组也是用哈希表来维护,下面通过操作一个array来解释如何使用哈希表来才做数组。

增加一个关联数组:

[php] 

增加一个索引数组:

[php] 

哈希表的增删改查

[php] 

哈希表的遍历

[php] 

数组操作函数reset(), each(), current(), next()会用这些函数来实现。

比较,排序 

[php] 

哈希表有一套排序算法。sort(), asort(), resort(), arsort(), ksort(), krsort()

详细请见: 

以下这个例子就是这个原理的实现,插入65535个数据需要消耗30秒,而正常情况下仅需要0.01秒。

[php] 

结果是

[php] 

  • Inserting 65536 evil elements took 32.726480007172 seconds   
  • Inserting 65536 good elements took 0.014460802078247 seconds  
  • 文章来源:

    对于哈希碰撞攻击有2中常见形式:通过POST攻击或通过反序列化攻击。PHP会自动把HTTP包中POST的数据解析成数组$_POST,如果我们构造一个无限大的哈希冲突的值,可以造成拒绝服务攻击。

    PHP5.3.9+是通过增加一个限制来尽量避免被此类攻击影响:

    [php] 

  • - max_input_vars - 指定 GET/POST/COOKIE 的最大输入变量数。默认是1000。  
  • Statement:
    The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn