编写一个简单的扩展示例
使用php内置工具生成自定义扩展的框架。该工具在ext文件夹下面
./ext_skel --extname=wully
Ext_skel的主要参数(这里面只列举了最常用的两个)
--extname=module module is the name of your extension【必须有的】
生成模块的名称,会自动在ext内建立extname文件夹,最常用的
--proto=file file contains prototypes of functions to create【可选】
函数原型定义文件
官方说明地址:
http://www.php.net/manual/en/internals2.buildsys.skeleton.php
修正ext/wully/config.m4
修正后,运行:
./buildconf --force
./configure --enable-wully
Make & make install 及可以安装成功
可以通过运行 ext/wully/wully.php来校验是否安装成功
扩展的内部实现
依旧以生成的wully模块为例,这个模块的提供的外部函数在
const zend_function_entry wully_functions[]这里面陈列(wully.c),我们可以看到示例中定义的函数为
PHP_FE(confirm_wully_compiled, NULL)
这个模块的外部函数和模块在php请求各个阶段的调用逻辑是通过
wully_module_entry(zend_module_entry)结构传给php框架的
php扩展函数的实现逻辑
每一个扩展函数都是通过PHP_FUNCTION来实现的,例如我们的示例,通过PHP_FUNCTION(confirm_wully_compiled) 来实现的
内部如何获取php函数的参数
生成的源码函数为:
zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arg_len)
这个是一个参数,且参数类型为字符串的情况
调用的原型为:
zend_parse_parameters(int num_args TSRMLS_DC, char *type_spec, …);
有两个参数我们要特别注意下:
第一个参数为该函数获取的参数个数
第三个参数为php函数传过来的参数类型,下表是一个对应关系图
后面的参数则是参数的值,及参数的大小,第二个参数对应于线程安全,这里面先不关心
参数类型对应表
类型指定符 | 对应的C类型 | 描述 |
l | long | 符号整数 |
d | double | 浮点数 |
s | char *, int | 二进制字符串,长度 |
b | zend_bool | 逻辑型(1或0) |
r | zval * | 资源(文件指针,数据库连接等) |
a | zval * | 联合数组 |
o | zval * | 任何类型的对象 |
O | zval * | 指定类型的对象。需要提供目标对象的类类型 |
z | zval * | 无任何操作的zval |
再看一个三个参数,一个为字符串,两个为整数
zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sll", &arg, &arg_len,&n,&m)
PHP_FUNCTION展开模式:
#define PHP_FUNCTION ZEND_FUNCTION
#define ZEND_FUNCTION(name) ZEND_NAMED_FUNCTION(ZEND_FN(name))
#define ZEND_FN(name) zif_##name
#define ZEND_NAMED_FUNCTION(name) void name(INTERNAL_FUNCTION_PARAMETERS)
#define INTERNAL_FUNCTION_PARAMETERS int ht, zval *return_value, zval **return_value_ptr, zval *this_ptr, int return_value_used TSRMLS_DC
提供外部函数列表的展开模式,即PHP_FE
#define PHP_FE ZEND_FE
#define ZEND_FE(name, arg_info) ZEND_FENTRY(name, ZEND_FN(name), arg_info, 0)
#define ZEND_FENTRY(zend_name, name, arg_info, flags) { #zend_name, name, arg_info, (zend_uint) (sizeof(arg_info)/sizeof(struct _zend_arg_info)-1), flags },
按照php处理请求的各个阶段我们分为 mint rint script rshutdown mshutdown,我们自定义的外部扩展对请求的各个阶段也可以进行相应的干预。
各个阶段的干预接口为:
MINIT阶段:模块初始化阶段
对应PHP_MINIT(wully)的实现
在sapi的start阶段,调用zend_startup_module
ZEND_API int zend_startup_module(zend_module_entry *module)执行两个动作注册模块,启动模块
注册模块
zend_register_internal_module(module TSRMLS_CC)
把module放入 module_registry 中,其中 module_registry 为一个全局的hash tab
启动模块
zend_startup_module_ex(module TSRMLS_CC) == SUCCESS
检测依赖是否就绪,然后运行该module的 PHP_MINIT函数
MINIT宏展开模式:
#define PHP_MINIT ZEND_MODULE_STARTUP_N
#define ZEND_MINIT ZEND_MODULE_STARTUP_N
#define ZEND_MODULE_STARTUP_N(module) zm_startup_##module
RINIT阶段:请求初始化
对应PHP_RINIT(wully)的实现
int php_request_startup(TSRMLS_D)
void zend_activate_modules(TSRMLS_D)
int module_registry_request_startup(zend_module_entry *module TSRMLS_DC)
module->request_startup_func(module->type, module->module_number TSRMLS_CC)
RINIT宏展开模式
#define PHP_RINIT ZEND_MODULE_ACTIVATE_N
#define ZEND_RINIT ZEND_MODULE_ACTIVATE_N
#define ZEND_MODULE_ACTIVATE_N(module) zm_activate_##module
script阶段
我们的PHP_FUNCTION执行在script阶段,他们作为php语言编译和解释的一部分,纳入到opcode的执行中
PHP_RSHUTDOWN阶段:请求关闭
对应PHP_RSHUTDOWN(wully))的实现
void php_request_shutdown(void *dummy)
void zend_deactivate_modules(TSRMLS_D)
int module_registry_cleanup(zend_module_entry *module TSRMLS_DC)
module->request_shutdown_func(module->type, module->module_number TSRMLS_CC)
PHP_RSHUTDOWN 宏展开模式
#define PHP_RSHUTDOWN ZEND_MODULE_DEACTIVATE_N
#define ZEND_MODULE_DEACTIVATE_N(module) zm_deactivate_##module
PHP_MSHUTDOWN阶段:模块关闭
对应PHP_MSHUTDOWN(wully))的实现
在zend_startup中注册模块销毁时的析构函数
int zend_startup(zend_utility_functions *utility_functions, char **extensions TSRMLS_DC)
zend_hash_init_ex(&module_registry, 50, NULL, ZEND_MODULE_DTOR, 1, 0);
#define ZEND_MODULE_DTOR (void (*)(void *)) module_destructor
void module_destructor(zend_module_entry *module)
module->module_shutdown_func(module->type, module->module_number TSRMLS_CC);
PHP_MSHUTDOWN 宏展开模式
#define PHP_MSHUTDOWN ZEND_MODULE_SHUTDOWN_N
#define ZEND_MODULE_SHUTDOWN_N(module) zm_shutdown_##module
PHP_MINFO跟前面的宏意义有所不同,主要用于在phpinfo中显示模块的信息
#define PHP_MINFO ZEND_MODULE_INFO_N
#define ZEND_MINFO ZEND_MODULE_INFO_N

防止会话固定攻击的有效方法包括:1.在用户登录后重新生成会话ID;2.使用安全的会话ID生成算法;3.实施会话超时机制;4.使用HTTPS加密会话数据,这些措施能确保应用在面对会话固定攻击时坚不可摧。

实现无会话身份验证可以通过使用JSONWebTokens(JWT)来实现,这是一种基于令牌的认证系统,所有的必要信息都存储在令牌中,无需服务器端会话存储。1)使用JWT生成和验证令牌,2)确保使用HTTPS防止令牌被截获,3)在客户端安全存储令牌,4)在服务器端验证令牌以防篡改,5)实现令牌撤销机制,如使用短期访问令牌和长期刷新令牌。

PHP会话的安全风险主要包括会话劫持、会话固定、会话预测和会话中毒。1.会话劫持可以通过使用HTTPS和保护cookie来防范。2.会话固定可以通过在用户登录前重新生成会话ID来避免。3.会话预测需要确保会话ID的随机性和不可预测性。4.会话中毒可以通过对会话数据进行验证和过滤来预防。

销毁PHP会话需要先启动会话,然后清除数据并销毁会话文件。1.使用session_start()启动会话。2.用session_unset()清除会话数据。3.最后用session_destroy()销毁会话文件,确保数据安全和资源释放。

如何改变PHP的默认会话保存路径?可以通过以下步骤实现:在PHP脚本中使用session_save_path('/var/www/sessions');session_start();设置会话保存路径。在php.ini文件中设置session.save_path="/var/www/sessions"来全局改变会话保存路径。使用Memcached或Redis存储会话数据,如ini_set('session.save_handler','memcached');ini_set(

tomodifyDataNaphPsession,startTheSessionWithSession_start(),然后使用$ _sessionToset,修改,orremovevariables.1)startThesession.2)setthesession.2)使用$ _session.3)setormodifysessessvariables.3)emovervariableswithunset()

在PHP会话中可以存储数组。1.启动会话,使用session_start()。2.创建数组并存储在$_SESSION中。3.通过$_SESSION检索数组。4.优化会话数据以提升性能。

PHP会话垃圾回收通过概率机制触发,清理过期会话数据。1)配置文件中设置触发概率和会话生命周期;2)可使用cron任务优化高负载应用;3)需平衡垃圾回收频率与性能,避免数据丢失。


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

mPDF
mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),

WebStorm Mac版
好用的JavaScript开发工具

适用于 Eclipse 的 SAP NetWeaver 服务器适配器
将Eclipse与SAP NetWeaver应用服务器集成。

记事本++7.3.1
好用且免费的代码编辑器

VSCode Windows 64位 下载
微软推出的免费、功能强大的一款IDE编辑器