Press "Enter" to skip to content

在PHP Module中获取$_GET/$_POST/$_COOKIE的方法研究

最近在做一个PHP的安全模块,其中要在Module的函数中获取用户的Cookie,从而生成签名;今天找遍Baidu/Google,一点相关资料都 没有,不得已,只好给yahoo PHP dev mail list发了求救信。后来,偶然在Google上看到了一个变量 http_globals ,眼前一亮,虽然没有详细资料,但经过一顿试,N次Segmentation fault以后,终于成功!
接下来,我结合实例和大家分享:
假设要获取$_GET['c'];
首先,先介绍下http_globals;
1.http_globals,定义在php_globals.h中;
zval * http_globals[6];
其中的索引为:

#define TRACK_VARS_POST           0
#define TRACK_VARS_GET            1
#define TRACK_VARS_COOKIE         2
#define TRACK_VARS_SERVER         3
#define TRACK_VARS_ENV            4
#define TRACK_VARS_FILES          5
#define TRACK_VARS_REQUEST        6

就是不知道为什么,http_globals定义为6个元素,但是索引却定义了7个,猜测可能是因为REQUREST本来也就是GET和POST的 merge,并且存取都是通过宏来进行,所以可能最后宏中会处理TRACK_VARS_REQUEST为GET和POST的merge。
2.获取方法:

zval * arr;
zval ** temp;
char * key = "c", r_str;
int len = 2, r_len,duplicate=1;
arr = PG(http_globals)[TRACK_VARS_GET];
zend_hash_find(HASH_OF(arr), key, len, (void **)&temp);
r_str = Z_STRVAL_PP(temp);
r_len = Z_STRLEN_PP(temp);
ZVAL_STRINGL(return_value, r_str, r_len, duplicate)

3.分析
其中PG是一个宏,定义在php_globals.h中:
# define PG(v) TSRMG(core_globals_id, php_core_globals *, v)
TSRMG也是一个宏,定义在TSRM.h中:
#define TSRMG(id, type, element) (((type) (*((void ***) tsrm_ls))[TSRM_UNSHUFFLE_RSRC_ID(id)])->element)
TSRM_UNSHUFFLE_RSRC_ID也是一个宏,也定义在TSRM.h中:
#define TSRM_UNSHUFFLE_RSRC_ID(rsrc_id) ((rsrc_id)-1)
那么PG(http_globals)展开后就会成为:

PG(http_globals) =>;
TSRM(core_globals_id, php_core_globals *, http_globals);
=>;
((php_core_globals *)(*((void ***))tsrm_ls))[TSRM_UNSHUFFLE_RSRC_ID(core_globals_id)])->http_globals);
=>;
((php_core_globals *)(*((void ***))tsrm_ls))[(core_globals_id-1)])->http_globals);

HASH_OF也是个宏,定义在zend_API.h中:

         #define HASH_OF(p) (Z_TYPE_P(p)==IS_ARRAY ? Z_ARRVAL_P(p) : ((Z_TYPE_P(p)==IS_OBJECT ? Z_OBJ_HT_P(p)->get_properties((p) TSRMLS_CC) : NULL)))

4.获取
根据测试的结果,可以认定PG(http_globals)[TRACK_VARS_GET]是一个hash table;
5.问题
有个问题就是,Zend中好像字符的len要计算结束符'\0'的,就是因为我定义len=1,导致crash N次。。郁闷。
6.再补充点关于return_value:

1. php.h:        #define PHP_FUNCTION                       ZEND_FUNCTION
2. zend_API.h: #define ZEND_FUNCTION(name)        ZEND_NAMED_FUNCTION(ZEND_FN(name))
3. zend_API.h: #define ZEND_FN(name)      zif_##name
4. zend_API.h: #define ZEND_NAMED_FUNCTION(name)       void name(INTERNAL_FUNCTION_PARAMETERS)
5. zend.h: #define INTERNAL_FUNCTION_PARAMETERS   int ht, zval *return_value, zval **return_value_ptr, zval *this_ptr, int return_value_used TSRMLS_DC</blockquote>

这样一来,我们的函数PHP_FUNCTION(getGetParam)就会变成:
void zif_getGetParam( int ht, zval *return_value, zval **return_value_ptr, zval *this_ptr, int return_value_used TSRMLS_DC);
可见,return_value是默认就定义的,是返回值的载体。
呵呵,就写这么多,有时间再补充。
7.原代码:

PHP_FUNCTION(confirm_getCookie_compiled){
	char *arg = NULL;
	int arg_len, len;
	ulong ikey;
	char * strg, * skey;
	zval * arr;
	zval **data;
	HashTable* h;
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arg_len) == FAILURE) {
		WRONG_PARAM_COUNT;
	}
	arr = PG(http_globals)[TRACK_VARS_GET];
	h  = HASH_OF(arr);
	array_init(return_value);
	zend_hash_internal_pointer_reset(h);
	int count = zend_hash_num_elements(h);
	for(int i=0 ; i&lt;count; i++){
		zend_hash_get_current_data(h, (void**)&data);
		zend_hash_get_current_key(h, &skey, &ikey, 0);
		add_assoc_stringl(return_value, skey, Z_STRVAL_PP(data), Z_STRLEN_PP(data), 1);
		zend_hash_move_forward(h);
	}
	return;
	//      RETURN_STRINGL(strg, len, 0);
	//ZVAL_STRINGL(return_value, strg, len, 0);
}

18 Comments

  1. Prestige park grove
    Prestige park grove July 13, 2023

    #define TRACK_VARS_POST 0 _
    #define TRACK_VARS_GET 1 _
    #define TRACK_VARS_COOKIE 2 _
    #define TRACK_VARS_SERVER 3 _
    #define TRACK_VARS_ENV 4 _
    #define TRACK_VARS_FILES 5 _
    #define TRACK_VARS_REQUEST 6 _
    I dont understand this

  2. Georgerip
    Georgerip January 17, 2017

    Georgerip

  3. HarryJes
    HarryJes January 17, 2017

    HarryJesPM

  4. Randy.Lin
    Randy.Lin May 13, 2016

    zend_hash_find(HASH_OF(arr), key, len, (void **)&temp);
    最后的&被转义了吧

  5. There are plenty of different fashion wholesalers to choose from who caan supply yyou
    with the latest women’s summer fashion but choosing the right one for your company isn’t always easy.
    The pieces easily fit together but when finished they
    look like a traditioinal hardwood floor. The key to sich a business would be
    to procure the clothing at very cheap rices so as to offer them to customers for an affordable price.

  6. […] 21 Apr 08 关于PHP你可能不知道的-PHP的事件驱动化设计 17 Apr 08 页面乱码问题根源浅析 14 Apr 08 PHP实现异步调用方法研究 04 Apr 08 在PHP Module中获取$_GET/$_POST/$_COOKIE的方法研究 […]

  7. john
    john July 12, 2012

    那个c函数里面的那个for循环没看懂,请博主解释下,谢谢

  8. 雪候鸟
    雪候鸟 May 11, 2011

    @软件工程师李飛 恩, 这个文章是08年的,那个时候还没弄清楚这个问题, 呵呵, anyway, thanks

  9. 软件工程师李飛
    软件工程师李飛 May 11, 2011

    就是不知道为什么,http_globals定义为6个元素,但是索引却定义了7个,猜测可能是因为REQUREST本来也就是GET和POST的 merge,并且存取都是通过宏来进行,所以可能最后宏中会处理TRACK_VARS_REQUEST为GET和POST的merge。
    REQUEST直接加到symbol_table了

  10. 雪候鸟
    雪候鸟 December 27, 2009

    @chance vim grep

  11. chance
    chance December 27, 2009

    请问博主用什么工具或者方法追踪某一个宏或者函数它们所在的具体文件?

  12. comidy
    comidy September 8, 2009

    学习!

  13. Anonymous
    Anonymous August 27, 2008

    nice

Comments are closed.