[PHP Extension] Super Globals

PHP 2010. 9. 13. 10:02



$_SERVER, $_SESSION 같은 super globals를 가져오기 위한 방법.
소스파일을 하나 더 추가하므로 config.m4 에도 추가된 소스파일을 명시할 것.



config.m4
PHP_ARG_ENABLE(myext, whether to enable myext support,
[ --enable-myext Enable myext support])

if test "$PHP_MYEXT" = "yes"; then
    AC_DEFINE(HAVE_MYEXT, 1, [whether you have myext])
    PHP_NEW_EXTENSION(myext, myext.c superglobals.c, $ext_shared)
fi




php_myext.h
#ifndef PHP_MYEXT_H
#define PHP_MYEXT_H

#define PHP_MYEXT_VERSION "1.0" // 버전
#define PHP_MYEXT_EXTNAME "myext" // 이름

// Thread Safe Resource Manager
#ifdef ZTS
#include "TSRM.h"
#endif

// $_SERVER 반환
PHP_FUNCTION(myext_get_server_vars);

// 모듈엔트리
extern zend_module_entry myext_module_entry;
#define phpext_myext_ptr &myext_module_entry

#endif




myext.c
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "php.h"
#include "php_myext.h"

#include "superglobals.c"

// function entry
static function_entry myext_functions[] = {
    PHP_FE(myext_get_server_vars, NULL)
    {NULL, NULL, NULL}
};

zend_module_entry myext_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
    STANDARD_MODULE_HEADER,
#endif
    PHP_MYEXT_EXTNAME,
    myext_functions, // function_entry
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
#if ZEND_MODULE_API_NO >= 20010901
    PHP_MYEXT_VERSION,
#endif
    STANDARD_MODULE_PROPERTIES
};

#ifdef COMIPLE_DL_MYEXT
ZEND_GET_MODULE(myext)
#endif

// $_SERVER 반환
PHP_FUNCTION(myext_get_server_vars)
{
    RETURN_ZVAL(*$_SERVER, 1, 1);
}




superglobals.c
zval **_get_superglobal(char *sg_name TSRMLS_CC)
{
    zval **superglobal;
   
    if (zend_hash_find(&EG(symbol_table), sg_name, strlen(sg_name)+1, (void**)&superglobal)==FAILURE) {
        zval *d;
        MAKE_STD_ZVAL(d);
        array_init(d);
        if (zend_hash_add(&EG(symbol_table), sg_name, strlen(sg_name)+1, (void*)*d, sizeof(zval*), NULL)==SUCCESS) {
            zend_hash_find(&EG(symbol_table), sg_name, strlen(sg_name)+1, (void**)&superglobal);
        }
    }

    return superglobal;
}

// $_SERVER
#define $_SERVER _get_superglobal("_SERVER" TSRMLS_CC)




super globals는 실행전역(ExecuteGlobals)의 symbol_table에 있다.
해당 테이블은 HashTable이며 찾는 방법은 superglobals.c의 _get_superglobal() 함수에 가장 기본적인 형태로 나와있다.
zend_hash_find() 함수를 이용해서 해당 HashTable을 뒤져서 찾아내 반환한다.
(상단 함수에서 못찾으면 배열 하나를 생성해서 해당 HashTable에 추가해주는 로직도 있다.)

상단의 소스대로 작성해서 var_dump(myext_get_server_vars()); 해보면 $_SERVER의 값들이 출력된다.

잘 보면 HashTable을 뒤질 때 이름을 가지고 찾는데, 같ㅇ느 방식으로 이름만 바꿔서 $_SESSION, $_COOKIE도 가져올 수 있다.

만약 $_SERVER['REMOTE_ADDR']을 가져오고 싶다면 zend_hash_find()를 2단계로 수행하면 된다.
먼저, &EG(symbol_table) 에서 $_SERVER를 가져온다.
가져온 값도 역시 HashTable이다.
그러므로 가져온 HashTable에 한 번 더 zend_hash_find()로 'REMOTE_ADDR' 값을 가져오면 최종적으로 $_SERVER['REMOTE_ADDR'] 값을 가져올 수 있다.
Posted by bloodguy
,