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

来源:互联网 发布:软件销售总监 编辑:程序博客网 时间:2024/04/27 23:23
· 作者: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以后,终于成功!


    接下来,我结合实例和大家分享:
    假设要获取$_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

     这样一来,我们的函数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<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);

       }

 

最后,欢迎来信交流

 
原创粉丝点击