PHP的GET/POST等大变量生成过程

  •   2009-07-31/22:54
  • · 作者:laruence()
    · 本文地址:http://www.laruence.com/2008/11/07/581.html
    · 转载请注明出处                                                  
    主要探讨了PHP的大变量的生成过程。另外如果你注意到, 当在表单中提交的input的name中如果有点号的时候, 在PHP中会自动把点号处理成下划线。并且你很想知道这是为什么,在什么时候发生的? 呵呵,本文也就这个问题做了回答。
    首先明确一个问题,PHP的变量名中是不能包含点号的。 但是为了处理表单中的点号命名,PHP就会自动把点号(.)转换成下划线(_)。
          要知道PHP是怎么处理的,首先我们要了解,$_GET, $_POST, $_COOKIE等变量的构造过程。
    在每个请求到来以后,apache处理到response阶段的时候, 会将控制权交给PHP模块, PHP模块会在处理请求之前首先间接调用php_request_startup (具体调用序列是send_php -> apache_php_module_main ->php_request_startup, 关于这部门可以参看我前面的文章(PHP Life Cycle) , 在php_request_startup中:
    int
    php_request_startup(TSRMLS_D)
    {
    int
    retval=SUCCESS;

    #if PHP_SIGCHILD
    signal(SIGCHLD,sigchld_handler);
    #endif
    if
    (php_start_sapi()==FAILURE)
    {
    return
    FAILURE;
       }
    php_output_activate(TSRMLS_C);
       sapi_activate(TSRMLS_C);
       php_hash_environment(TSRMLS_C);

       zend_try
    {
    PG(during_request_startup)=1;
            php_output_activate(TSRMLS_C);
            if
    (PG(expose_php))
    {
    sapi_add_header(SAPI_PHP_VERSION_HEADER,sizeof(SAPI_PHP_VERSION_HEADER)-1,1);
            }
    }
    zend_catch
    {
    retval=FAILURE;
       }
    zend_end_try();

       return
    retval;
    }


       注意其中的php_hash_environment(TSRMLS_C)函数调用 , 这个函数就是在请求处理前, 初始化请求相关的变量的函数。
      这个函数定义在: main/php_variables.c中 , 有兴趣的可以看看:
    int
    php_hash_environment(TSRMLS_D)
    {
    char*p;
            unsigned
    char
    _gpc_flags[5]={0,0,0,0,0};
            zend_bool
    jit_initialization=(PG(auto_globals_jit)&& !PG(register_globals)&& !PG(register_long_arrays));
            struct
    auto_global_record
    {
    char*name;
                   uint
    name_len;
                   char*long_name;
                   uint
    long_name_len;
                   zend_bool
    jit_initialization;
            }
    auto_global_records[]={
    {
    "_POST",sizeof("_POST"),"HTTP_POST_VARS",sizeof("HTTP_POST_VARS"),0
    },
                   {
    "_GET",sizeof("_GET"),"HTTP_GET_VARS",sizeof("HTTP_GET_VARS"),0
    },
                   {
    "_COOKIE",sizeof("_COOKIE"),"HTTP_COOKIE_VARS",sizeof("HTTP_COOKIE_VARS"),0
    },
                   {
    "_SERVER",sizeof("_SERVER"),"HTTP_SERVER_VARS",sizeof("HTTP_SERVER_VARS"),1
    },
                   {
    "_ENV",sizeof("_ENV"),"HTTP_ENV_VARS",sizeof("HTTP_ENV_VARS"),1
    },
                   {
    "_FILES",sizeof("_FILES"),"HTTP_POST_FILES",sizeof("HTTP_POST_FILES"),0
    },
            };
            size_t
    num_track_vars=sizeof(auto_global_records)/sizeof(struct
    auto_global_record);
            size_t
    i;

            /* jit_initialization = 0; */
    for
    (i=0;i<num_track_vars;i++)
    {
    PG(http_globals)[i]=NULL;
            }
    for
    (p=PG(variables_order);p&& *p;p++)
    {
    switch(*p)
    {
    case
    'p':
                            case
    'P':
                                    if
    (!_gpc_flags[0]&& !SG(headers_sent)&&SG(request_info).request_method&& !strcasecmp(SG(request_info).request_method,"POST"))
    {
    sapi_module.treat_data(PARSE_POST,NULL,NULL
    TSRMLS_CC);      /* POST Data */
    _gpc_flags[0]=1;
                                           if
    (PG(register_globals))
    {
    php_autoglobal_merge(&EG(symbol_table),Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_POST])
    TSRMLS_CC);
                                           }
    }
    break;
                       ....以下省略,www.devdao.com:
    }}}


       到了这里说个题外话, 就是在php.ini中, 可以使用variables_order来控制PHP是否生成某个大变量,已经大变量的生成顺序。
       关于顺序,就是说, 如果打开了auto_register_globals的情况下, 如果先处理p,后处理g,那么$_GET['a'],就会覆盖$_POST['a'];
       可以看到,离成功不远了,sapi_module.treat_data 也就是php_default_treat_data,
       在php_default_treat_data中,对于变量,都调用php_register_variable_safe来注册变量, 而php_register_variable_safe最终会调用php_register_variable_ex:
    PHPAPI
    void
    php_register_variable_ex(char*var,zval*val,zval*track_vars_array
    TSRMLS_DC)
    {
    char*p=NULL;
       char*ip;      /* index pointer */
    char*index, *escaped_index=NULL;
       int
    var_len,index_len;
       zval*gpc_element, **gpc_element_p;
       zend_bool
    is_array=0;
       HashTable*symtable1=NULL;

       assert(var!=NULL);

       if
    (track_vars_array)
    {
    symtable1=Z_ARRVAL_P(track_vars_array);
       }
    else
    if
    (PG(register_globals))
    {
    symtable1=EG(active_symbol_table);
       }
    if
    (!symtable1)
    {
    /* Nothing to do */
    zval_dtor(val);
            return;
       }
    /*
         * Prepare variable name
         */
    /* ignore leading spaces in the variable name */
    while
    (*var&& *var=='
    ')
    {
    var++;
       }
    /* ensure that we don't have spaces or dots in the variable name (not binary safe) */
    //特别注意以下这段。。。。
    for
    (p=var; *p;p++)
    {
    if
    (*p=='
    '|| *p=='.')
    {
                *p='_';
            }
    else
    if
    (*p=='[')
    {
    is_array=1;
                ip=p;
                *p=0;
                break;
            }
      ....以下省略

       呵呵,问题的原因找到了, 就是在php_register_variable的时候,会将(.)转换成(_).
    最后,再介绍下$_REQUEST变量的生成, 其实很简单, 在php_hash_environment中的最后, 会调用php_auto_globals_create_request(”_REQUEST”, sizeof(”_REQUEST”)-1TSRMLS_CC)来注册_REQUEST大变量, 在php_auto_globals_create_request(”_REQUEST”,sizeof(”_REQUEST”)-1 TSRMLS_CC)中,只是简单的将$_GET, $_POST, $_COOKIEmerge起来(G(http_globals)[TRACK_VARS_COOKIE]这部分,可以参看我较早前的在PHP Module中获取$_GET/$_POST/$_COOKIE的方法研究) :
    static
    zend_bool
    php_auto_globals_create_request(char*name,uint
    name_len
    TSRMLS_DC)
    {
    zval*form_variables;
       unsigned
    char
    _gpc_flags[3]={0,0,0};
       char*p;

       ALLOC_ZVAL(form_variables);
       array_init(form_variables);
       INIT_PZVAL(form_variables);

       for
    (p=PG(variables_order);p&& *p;p++)
    {
    switch
    (*p)
    {
    case'g':
                case'G':
                   if
    (!_gpc_flags[0])
    {
    php_autoglobal_merge(Z_ARRVAL_P(form_variables),Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_GET])
    TSRMLS_CC);
                        _gpc_flags[0]=1;
                   }
    break;                                                                                                                    case'p':
                case'P':
                   if
    (!_gpc_flags[1])
    {
    php_autoglobal_merge(Z_ARRVAL_P(form_variables),Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_POST])
    TSRMLS_CC);
                        _gpc_flags[1]=1;
                   }
    break;
                case'c':
                case'C':                                                                                                                        if
    (!_gpc_flags[2])
    {
    php_autoglobal_merge(Z_ARRVAL_P(form_variables),Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_COOKIE])
    TSRMLS_CC);
                        _gpc_flags[2]=1;
                   }
    break;
            }
    }
    zend_hash_update(&EG(symbol_table),"_REQUEST",sizeof("_REQUEST"), &form_variables,sizeof(zval*),NULL);
       return
    0;
    }


    评论 {{userinfo.comments}}

    {{money}}

    {{question.question}}

    A {{question.A}}
    B {{question.B}}
    C {{question.C}}
    D {{question.D}}
    提交

    驱动号 更多