今天翻鸟哥的blog看这个转了一下,这是写扩展取变量值最基本的入门,但还有一方法,大家都不常用,通过hashtable去find这全局变量。有空再把方法贴上来
· 作者:laruence(http://www.laruence.com/)
· 本文地址: http://www.laruence.com/2008/04/04/17.html
· 转载请注明出处
最近在做一个PHP的安全模块,其中要在Module的函数中获取用户的Cookie,从而生成签名;今天找遍Baidu/Google,一点相关资料都没有,不得已,只好给yahoo PHP dev mail list发了求救信。后来,偶然在Google上看到了一个变量http_globals ,眼前一亮,虽然没有详细资料,但经过一顿试,N次Segmentation fault以后,终于成功!
接下来,我结合实例和大家分享: 笑话365
假设要获取$_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
**
)
&
amp
;
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
)]
)-&
gt
;
http_globals
);
=>;
((
php_core_globals
*
)(
*
((void
***
))
tsrm_ls
))[(
core_globals_id
-
1
)]
)-&
gt
;
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
)
-&
gt
;
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);
}