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 /* }}} */ 〜 省略 〜 %