ます’s Blog - どうでもいい記事100選

どうでもいい記事100選

getenv関数

今までgetenv関数は最初にスーパーグローバル配列を参照して、存在しなければガチのgetenvを実行すると思っていたのですが、どうも大きな勘違いをしていたようで、不勉強ながら今更sapi_module_structの中身を確認してみました。
「sapi_module_struct」をgrepした結果、最初にsapi_module_structで定義した関数を実行して、存在しなければガチのgetenvを実行するようでした。

個人的には最初にスーパーグローバル配列を参照して、存在しなければガチのgetenvを実行して欲しいので(また)やっつけパッチ。

--- php-4.4.9,orig/ext/standard/basic_functions.c	2007-12-31 16:22:51.000000000 +0900
+++ php-4.4.9/ext/standard/basic_functions.c	2009-08-25 20:45:25.000000000 +0900
@@ -1345,10 +1345,26 @@
 {
 	char *ptr, *str;
 	int str_len;
+	zval **server_vars, **env_vars, **data;
 
 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) {
 		RETURN_FALSE;
 	}
+
+	if (zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void **) &server_vars) == SUCCESS &&
+	    Z_TYPE_PP(server_vars) == IS_ARRAY &&
+	    zend_hash_find(Z_ARRVAL_PP(server_vars), str, str_len+1, (void **) &data)==SUCCESS &&
+	    Z_TYPE_PP(data) == IS_STRING) {
+		RETURN_STRINGL(Z_STRVAL_PP(data), Z_STRLEN_PP(data), 1);
+	}
+
+	if (zend_hash_find(&EG(symbol_table), "_ENV", sizeof("_ENV"), (void **) &env_vars) == SUCCESS &&
+	    Z_TYPE_PP(env_vars) == IS_ARRAY &&
+	    zend_hash_find(Z_ARRVAL_PP(env_vars), str, str_len+1, (void **) &data)==SUCCESS &&
+	    Z_TYPE_PP(data) == IS_STRING) {
+		RETURN_STRINGL(Z_STRVAL_PP(data), Z_STRLEN_PP(data), 1);
+	}
+
 	ptr = sapi_getenv(str, str_len TSRMLS_CC);
 	if (! ptr) {
 		ptr = getenv(str);
--- php-5.2.10,orig/ext/standard/basic_functions.c	2009-05-20 21:09:33.000000000 +0900
+++ php-5.2.10/ext/standard/basic_functions.c	2009-08-25 20:45:35.000000000 +0900
@@ -4400,10 +4400,25 @@
 {
 	char *ptr, *str;
 	int str_len;
+	zval **server_vars, **env_vars, **data;
 
 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) {
 		RETURN_FALSE;
 	}
+	if (zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void **) &server_vars) == SUCCESS &&
+	    Z_TYPE_PP(server_vars) == IS_ARRAY &&
+	    zend_hash_find(Z_ARRVAL_PP(server_vars), str, str_len+1, (void **) &data)==SUCCESS &&
+	    Z_TYPE_PP(data) == IS_STRING) {
+		RETURN_STRINGL(Z_STRVAL_PP(data), Z_STRLEN_PP(data), 1);
+	}
+
+	if (zend_hash_find(&EG(symbol_table), "_ENV", sizeof("_ENV"), (void **) &env_vars) == SUCCESS &&
+	    Z_TYPE_PP(env_vars) == IS_ARRAY &&
+	    zend_hash_find(Z_ARRVAL_PP(env_vars), str, str_len+1, (void **) &data)==SUCCESS &&
+	    Z_TYPE_PP(data) == IS_STRING) {
+		RETURN_STRINGL(Z_STRVAL_PP(data), Z_STRLEN_PP(data), 1);
+	}
+
 	ptr = sapi_getenv(str, str_len TSRMLS_CC);
 	if(ptr) RETURN_STRING(ptr, 0);
 	ptr = getenv(str);
--- php-5.3.0,orig/ext/standard/basic_functions.c	2009-06-20 15:07:35.000000000 +0900
+++ php-5.3.0/ext/standard/basic_functions.c	2009-08-25 20:45:44.000000000 +0900
@@ -3959,11 +3959,26 @@
 {
 	char *ptr, *str;
 	int str_len;
+	zval **server_vars, **env_vars, **data;
 
 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) {
 		RETURN_FALSE;
 	}
 
+	if (zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void **) &server_vars) == SUCCESS &&
+	    Z_TYPE_PP(server_vars) == IS_ARRAY &&
+	    zend_hash_find(Z_ARRVAL_PP(server_vars), str, str_len+1, (void **) &data)==SUCCESS &&
+	    Z_TYPE_PP(data) == IS_STRING) {
+		RETURN_STRINGL(Z_STRVAL_PP(data), Z_STRLEN_PP(data), 1);
+	}
+
+	if (zend_hash_find(&EG(symbol_table), "_ENV", sizeof("_ENV"), (void **) &env_vars) == SUCCESS &&
+	    Z_TYPE_PP(env_vars) == IS_ARRAY &&
+	    zend_hash_find(Z_ARRVAL_PP(env_vars), str, str_len+1, (void **) &data)==SUCCESS &&
+	    Z_TYPE_PP(data) == IS_STRING) {
+		RETURN_STRINGL(Z_STRVAL_PP(data), Z_STRLEN_PP(data), 1);
+	}
+
 	/* SAPI method returns an emalloc()'d string */
 	ptr = sapi_getenv(str, str_len TSRMLS_CC);
 	if (ptr) {

gist.githubにも登録しておきました。

以下が実行結果。

% cat /usr/local/src/getenv.php
<?php

  error_reporting( E_ALL );

  $_SERVER["masugata"] = "seiji";
  $_ENV["seiji"]       = "masugata";

  var_dump( getenv( "masugata" ) );
  var_dump( getenv( "seiji" ) );

?>

% /usr/local/src/php-4.4.9,orig/sapi/cli/php -c . /usr/local/src/getenv.php
bool(false)
bool(false)

% /usr/local/src/php-4.4.9/sapi/cli/php -c . /usr/local/src/getenv.php
string(5) "seiji"
string(8) "masugata"

% /usr/local/src/php-5.2.10,orig/sapi/cli/php -c . /usr/local/src/getenv.php
bool(false)
bool(false)

% /usr/local/src/php-5.2.10/sapi/cli/php -c . /usr/local/src/getenv.php
string(5) "seiji"
string(8) "masugata"

% /usr/local/src/php-5.3.0,orig/sapi/cli/php -c . /usr/local/src/getenv.php
bool(false)
bool(false)

% /usr/local/src/php-5.3.0/sapi/cli/php -c . /usr/local/src/getenv.php
string(5) "seiji"
string(8) "masugata"

%

これで多少は使いやすくなるぜ。。。runkit拡張モジュール使えよってのは却下します。
実際には更に小細工をカマして限定した環境下でのみ動くようにしています。


確認したファイルは「/path/to/php-src/main/SAPI.c」「/path/to/php-src/main/SAPI.h」「/path/to/php-src/sapi/cgi/cgi_main.c」「/path/to/php-src/sapi/cli/php_cli.c」辺りです。
以下は5.3.0からの抜粋ですが、4.4.9や5.2.10でも構造は変わっていないので参考になるかと思います。

% less -N /usr/local/src/php-5.3.0/main/SAPI.c

        〜 省略 〜

    967 SAPI_API char *sapi_getenv(char *name, size_t name_len TSRMLS_DC)
    968 {
    969         if (sapi_module.getenv) {
    970                 char *value, *tmp = sapi_module.getenv(name, name_len TSRMLS_CC);
    971                 if (tmp) {
    972                         value = estrdup(tmp);
    973                 } else {
    974                         return NULL;
    975                 }
    976                 sapi_module.input_filter(PARSE_ENV, name, &value, strlen(value), NULL TSRMLS_CC);
    977                 return value;
    978         }
    979         return NULL;
    980 }

        〜 省略 〜

% less -N /usr/local/src/php-5.3.0/main/SAPI.h

        〜 省略 〜

    215 struct _sapi_module_struct {
    216         char *name;
    217         char *pretty_name;
    218
    219         int (*startup)(struct _sapi_module_struct *sapi_module);
    220         int (*shutdown)(struct _sapi_module_struct *sapi_module);
    221
    222         int (*activate)(TSRMLS_D);
    223         int (*deactivate)(TSRMLS_D);
    224
    225         int (*ub_write)(const char *str, unsigned int str_length TSRMLS_DC);
    226         void (*flush)(void *server_context);
    227         struct stat *(*get_stat)(TSRMLS_D);
    228         char *(*getenv)(char *name, size_t name_len TSRMLS_DC);  /*******TARGET*******/
    229
    230         void (*sapi_error)(int type, const char *error_msg, ...);
    231
    232         int (*header_handler)(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers TSRMLS_DC);
    233         int (*send_headers)(sapi_headers_struct *sapi_headers TSRMLS_DC);
    234         void (*send_header)(sapi_header_struct *sapi_header, void *server_context TSRMLS_DC);
    235
    236         int (*read_post)(char *buffer, uint count_bytes TSRMLS_DC);
    237         char *(*read_cookies)(TSRMLS_D);
    238
    239         void (*register_server_variables)(zval *track_vars_array TSRMLS_DC);
    240         void (*log_message)(char *message);
    241         time_t (*get_request_time)(TSRMLS_D);
    242         void (*terminate_process)(TSRMLS_D);
    243
    244         char *php_ini_path_override;
    245
    246         void (*block_interruptions)(void);
    247         void (*unblock_interruptions)(void);
    248
    249         void (*default_post_reader)(TSRMLS_D);
    250         void (*treat_data)(int arg, char *str, zval *destArray TSRMLS_DC);
    251         char *executable_location;
    252
    253         int php_ini_ignore;
    254
    255         int (*get_fd)(int *fd TSRMLS_DC);
    256
    257         int (*force_http_10)(TSRMLS_D);
    258
    259         int (*get_target_uid)(uid_t * TSRMLS_DC);
    260         int (*get_target_gid)(gid_t * TSRMLS_DC);
    261
    262         unsigned int (*input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC);
    263
    264         void (*ini_defaults)(HashTable *configuration_hash);
    265         int phpinfo_as_text;
    266
    267         char *ini_entries;
    268         const zend_function_entry *additional_functions;
    269         unsigned int (*input_filter_init)(TSRMLS_D);
    270 };

        〜 省略 〜

% less -N /usr/local/src/php-5.3.0/sapi/cgi/cgi_main.c

    509 static char *sapi_cgibin_getenv(char *name, size_t name_len TSRMLS_DC)
    510 {
    511         /* when php is started by mod_fastcgi, no regular environment
    512          * is provided to PHP.  It is always sent to PHP at the start
    513          * of a request.  So we have to do our own lookup to get env
    514          * vars.  This could probably be faster somehow.  */
    515         if (fcgi_is_fastcgi()) {
    516                 fcgi_request *request = (fcgi_request*) SG(server_context);
    517                 return fcgi_getenv(request, name, name_len);
    518         }
    519         /*  if cgi, or fastcgi and not found in fcgi env
    520                 check the regular environment */
    521         return getenv(name);
    522 }

        〜 省略 〜

    865 /* {{{ sapi_module_struct cgi_sapi_module
    866  */
    867 static sapi_module_struct cgi_sapi_module = {
    868         "cgi-fcgi",                     /* name */
    869         "CGI/FastCGI",                  /* pretty name */
    870
    871         php_cgi_startup,                /* startup */
    872         php_module_shutdown_wrapper,    /* shutdown */
    873
    874         sapi_cgi_activate,              /* activate */
    875         sapi_cgi_deactivate,            /* deactivate */
    876
    877         sapi_cgibin_ub_write,           /* unbuffered write */
    878         sapi_cgibin_flush,              /* flush */
    879         NULL,                           /* get uid */
    880         sapi_cgibin_getenv,             /* getenv */ /*******TARGET*******/
    881
    882         php_error,                      /* error handler */
    883
    884         NULL,                           /* header handler */
    885         sapi_cgi_send_headers,          /* send headers handler */
    886         NULL,                           /* send header handler */
    887
    888         sapi_cgi_read_post,             /* read POST data */
    889         sapi_cgi_read_cookies,          /* read Cookies */
    890
    891         sapi_cgi_register_variables,    /* register server variables */
    892         sapi_cgi_log_message,           /* Log message */
    893         NULL,                           /* Get request time */
    894         NULL,                           /* Child terminate */
    895
    896         STANDARD_SAPI_MODULE_PROPERTIES
    897 };
    898 /* }}} */

        〜 省略 〜

% less -N /usr/local/src/php-5.3.0/sapi/cli/php_cli.c

        〜 省略 〜

    423 /* {{{ sapi_module_struct cli_sapi_module
    424  */
    425 static sapi_module_struct cli_sapi_module = {
    426         "cli",                          /* name */
    427         "Command Line Interface",       /* pretty name */
    428
    429         php_cli_startup,                /* startup */
    430         php_module_shutdown_wrapper,    /* shutdown */
    431
    432         NULL,                           /* activate */
    433         sapi_cli_deactivate,            /* deactivate */
    434
    435         sapi_cli_ub_write,              /* unbuffered write */
    436         sapi_cli_flush,                 /* flush */
    437         NULL,                           /* get uid */
    438         NULL,                           /* getenv */ /*******TARGET*******/
    439
    440         php_error,                      /* error handler */
    441
    442         sapi_cli_header_handler,        /* header handler */
    443         sapi_cli_send_headers,          /* send headers handler */
    444         sapi_cli_send_header,           /* send header handler */
    445
    446         NULL,                           /* read POST data */
    447         sapi_cli_read_cookies,          /* read Cookies */
    448
    449         sapi_cli_register_variables,    /* register server variables */
    450         sapi_cli_log_message,           /* Log message */
    451         NULL,                           /* Get request time */
    452         NULL,                           /* Child terminate */
    453
    454         STANDARD_SAPI_MODULE_PROPERTIES
    455 };
    456 /* }}} */

        〜 省略 〜

%