IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> PHP知识库 -> PHP参数解析源码 -> 正文阅读

[PHP知识库]PHP参数解析源码

PHP 使用 ZEND_PARSE_PARAMETERS_START ...??ZEND_PARSE_PARAMETERS_END 进行参数解析

PHP_FUNCTION(strpos)
{
	zval *needle;
	zend_string *haystack;
	const char *found = NULL;
	char  needle_char[2];
	zend_long  offset = 0;
    // 解析参数
	ZEND_PARSE_PARAMETERS_START(2, 3)
		Z_PARAM_STR(haystack)
		Z_PARAM_ZVAL(needle)
		Z_PARAM_OPTIONAL
		Z_PARAM_LONG(offset)
	ZEND_PARSE_PARAMETERS_END();
    ...
    ...
    ...
}
ZEND_PARSE_PARAMETERS_START ZEND_PARSE_PARAMETERS_END 为宏定义(以下代码位于Zend/zend_API.h)???????
#define ZEND_PARSE_PARAMETERS_START_EX(flags, min_num_args, max_num_args) do { \
		const int _flags = (flags); \
		int _min_num_args = (min_num_args); \
		int _max_num_args = (max_num_args); \
		int _num_args = EX_NUM_ARGS(); \
		int _i = 0; \
		zval *_real_arg, *_arg = NULL; \
		zend_expected_type _expected_type = Z_EXPECTED_LONG; \
		char *_error = NULL; \
		zend_bool _dummy; \
		zend_bool _optional = 0; \
		int _error_code = ZPP_ERROR_OK; \
		((void)_i); \
		((void)_real_arg); \
		((void)_arg); \
		((void)_expected_type); \
		((void)_error); \
		((void)_dummy); \
		((void)_optional); \
		\
		do { \
			if (UNEXPECTED(_num_args < _min_num_args) || \
			    (UNEXPECTED(_num_args > _max_num_args) && \
			     EXPECTED(_max_num_args >= 0))) { \
				if (!(_flags & ZEND_PARSE_PARAMS_QUIET)) { \
					if (_flags & ZEND_PARSE_PARAMS_THROW) { \
						zend_wrong_parameters_count_exception(_min_num_args, _max_num_args); \
					} else { \
						zend_wrong_parameters_count_error(_min_num_args, _max_num_args); \
					} \
				} \
				_error_code = ZPP_ERROR_FAILURE; \
				break; \
			} \
			_real_arg = ZEND_CALL_ARG(execute_data, 0);

#define ZEND_PARSE_PARAMETERS_START(min_num_args, max_num_args) \
	ZEND_PARSE_PARAMETERS_START_EX(0, min_num_args, max_num_args)

#define ZEND_PARSE_PARAMETERS_END_EX(failure) \
		} while (0); \
		if (UNEXPECTED(_error_code != ZPP_ERROR_OK)) { \
			if (!(_flags & ZEND_PARSE_PARAMS_QUIET)) { \
				if (_error_code == ZPP_ERROR_WRONG_CALLBACK) { \
					if (_flags & ZEND_PARSE_PARAMS_THROW) { \
						zend_wrong_callback_exception(_i, _error); \
					} else { \
						zend_wrong_callback_error(_i, _error); \
					} \
				} else if (_error_code == ZPP_ERROR_WRONG_CLASS) { \
					if (_flags & ZEND_PARSE_PARAMS_THROW) { \
						zend_wrong_parameter_class_exception(_i, _error, _arg); \
					} else { \
						zend_wrong_parameter_class_error(_i, _error, _arg); \
					} \
				} else if (_error_code == ZPP_ERROR_WRONG_ARG) { \
					if (_flags & ZEND_PARSE_PARAMS_THROW) { \
						zend_wrong_parameter_type_exception(_i, _expected_type, _arg); \
					} else { \
						zend_wrong_parameter_type_error(_i, _expected_type, _arg); \
					} \
				} \
			} \
			failure; \
		} \
	} while (0)

#define ZEND_PARSE_PARAMETERS_END() \
	ZEND_PARSE_PARAMETERS_END_EX(return)

替换后参数解析代码如下(以strpos中参数解析为例)

do { 
        const int _flag = (0);  // 0 为ZEND_PARSE_PARAMETERS_START_EX(0, min_num_args, max_num_args) 中第一个参数
        int _min_num_args = (2); // 2 为 ZEND_PARSE_PARAMETERS_START(2, 3)中2
        int _max_num_args = (3); // 3 为 ZEND_PARSE_PARAMETERS_START(2, 3)中3
        int _num_args =(execute_data)->This.u2.num_args; // 参见 struct _zval_struct  参数数量
        int _i = 0; 
        zval *_real_arg, *_arg = NULL; 
        zend_expected_type _expected_type = Z_EXPECTED_LONG; 
        char *_error = NULL; 
        zend_bool _dummy; 
        zend_bool _optional = 0; 
        int _error_code = ZPP_ERROR_OK; 
        ((void)_i); 
        ((void)_real_arg); 
        ((void)_arg); 
        ((void)_expected_type); 
        ((void)_error); 
        ((void)_dummy); 
        ((void)_optional); 
        // 校验参数数量
        do { 
            if (UNEXPECTED(_num_args < _min_num_args) || 
                (UNEXPECTED(_num_args > _max_num_args) && 
                 EXPECTED(_max_num_args >= 0))) { 
                if (!(_0 & ZEND_PARSE_PARAMS_QUIET)) { 
                    if (_0 & ZEND_PARSE_PARAMS_THROW) { 
                        zend_wrong_parameters_count_exception(_min_num_args, _max_num_args); 
                    } else { 
                        zend_wrong_parameters_count_error(_min_num_args, _max_num_args); 
                    } 
                } 
                _error_code = ZPP_ERROR_FAILURE; 
                break; 
            } 
            _real_arg = ZEND_CALL_ARG(execute_data, 0);
            Z_PARAM_STR(haystack) // 解析参数
            Z_PARAM_ZVAL(needle) // 解析参数
            _optional = 1;
            Z_PARAM_LONG(offset) // 解析参数
        } while (0); 
        if (UNEXPECTED(_error_code != ZPP_ERROR_OK)) { 
            if (!(_flags & ZEND_PARSE_PARAMS_QUIET)) { 
                if (_error_code == ZPP_ERROR_WRONG_CALLBACK) { 
                    if (_flags & ZEND_PARSE_PARAMS_THROW) { 
                        zend_wrong_callback_exception(_i, _error); 
                    } else { 
                        zend_wrong_callback_error(_i, _error); 
                    } 
                } else if (_error_code == ZPP_ERROR_WRONG_CLASS) { 
                    if (_flags & ZEND_PARSE_PARAMS_THROW) { 
                        zend_wrong_parameter_class_exception(_i, _error, _arg); 
                    } else { 
                        zend_wrong_parameter_class_error(_i, _error, _arg); 
                    } 
                } else if (_error_code == ZPP_ERROR_WRONG_ARG) { 
                    if (_flags & ZEND_PARSE_PARAMS_THROW) { 
                        zend_wrong_parameter_type_exception(_i, _expected_type, _arg); 
                    } else { 
                        zend_wrong_parameter_type_error(_i, _expected_type, _arg); 
                    } 
                } 
            } 
            return; 
        } 
    } while (0)
Z_PARAM_STR(haystack) Z_PARAM_ZVAL(needle) Z_PARAM_LONG(offset) 将用户传入参数值解析至指定参数
#define Z_PARAM_STR_EX2(dest, check_null, deref, separate) \
		Z_PARAM_PROLOGUE(deref, separate); \
		if (UNEXPECTED(!zend_parse_arg_str(_arg, &dest, check_null))) { \
			_expected_type = Z_EXPECTED_STRING; \
			_error_code = ZPP_ERROR_WRONG_ARG; \
			break; \
		}

#define Z_PARAM_STR_EX(dest, check_null, separate) \
	Z_PARAM_STR_EX2(dest, check_null, separate, separate)

#define Z_PARAM_STR(dest) \
	Z_PARAM_STR_EX(dest, 0, 0)
#define Z_PARAM_ZVAL_EX2(dest, check_null, deref, separate) \
		Z_PARAM_PROLOGUE(deref, separate); \
		zend_parse_arg_zval_deref(_arg, &dest, check_null);

#define Z_PARAM_ZVAL_EX(dest, check_null, separate) \
	Z_PARAM_ZVAL_EX2(dest, check_null, separate, separate)

#define Z_PARAM_ZVAL(dest) \
	Z_PARAM_ZVAL_EX(dest, 0, 0)
#define Z_PARAM_LONG_EX2(dest, is_null, check_null, deref, separate) \
		Z_PARAM_PROLOGUE(deref, separate); \
		if (UNEXPECTED(!zend_parse_arg_long(_arg, &dest, &is_null, check_null, 0))) { \
			_expected_type = Z_EXPECTED_LONG; \
			_error_code = ZPP_ERROR_WRONG_ARG; \
			break; \
		}

#define Z_PARAM_LONG_EX(dest, is_null, check_null, separate) \
	Z_PARAM_LONG_EX2(dest, is_null, check_null, separate, separate)

#define Z_PARAM_LONG(dest) \
	Z_PARAM_LONG_EX(dest, _dummy, 0, 0)

先调用 Z_PARAM_PROLOGUE(deref, separate) 进行参数校验。_i表示第几个参数;_arg为第_i个参数。

#define Z_PARAM_PROLOGUE(deref, separate) \
	++_i; \
	ZEND_ASSERT(_i <= _min_num_args || _optional==1); \
	ZEND_ASSERT(_i >  _min_num_args || _optional==0); \
	if (_optional) { \
		if (UNEXPECTED(_i >_num_args)) break; \
	} \
	_real_arg++; \
	_arg = _real_arg; \
	if (deref) { \
		if (EXPECTED(Z_ISREF_P(_arg))) { \
			_arg = Z_REFVAL_P(_arg); \
		} \
	} \
	if (separate) { \
		SEPARATE_ZVAL_NOREF(_arg); \
	}

然后分别调用?zend_parse_arg_str? zend_parse_arg_zval_deref?zend_parse_arg_long 将

_arg赋值dest完成参数解析

  PHP知识库 最新文章
Laravel 下实现 Google 2fa 验证
UUCTF WP
DASCTF10月 web
XAMPP任意命令执行提升权限漏洞(CVE-2020-
[GYCTF2020]Easyphp
iwebsec靶场 代码执行关卡通关笔记
多个线程同步执行,多个线程依次执行,多个
php 没事记录下常用方法 (TP5.1)
php之jwt
2021-09-18
上一篇文章      下一篇文章      查看所有文章
加:2021-12-24 18:16:21  更:2021-12-24 18:16:26 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 15:16:40-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码