shane Sat Jan 25 17:01:54 2003 EDT Modified files: /php4/sapi/cgi cgi_main.c Log: fix bug 21261 putenv on some platforms requires we provide the memory cleanup env parsing logic fix bug 21367 missed optargs in a previous patch
Index: php4/sapi/cgi/cgi_main.c diff -u php4/sapi/cgi/cgi_main.c:1.207 php4/sapi/cgi/cgi_main.c:1.208 --- php4/sapi/cgi/cgi_main.c:1.207 Tue Jan 7 19:41:53 2003 +++ php4/sapi/cgi/cgi_main.c Sat Jan 25 17:01:53 2003 @@ -137,7 +137,7 @@ #define TRANSLATE_SLASHES(path) #endif -#define OPTSTRING "aCc:d:ef:g:hilmnqsw?vz:" +#define OPTSTRING "abCc:d:ef:g:hilmnqsw?vz:" static int print_module_info(zend_module_entry *module, void *arg TSRMLS_DC) { @@ -360,11 +360,11 @@ return getenv(name); } -static int _sapi_cgibin_putenv(char *name, char *value TSRMLS_DC) +static char *_sapi_cgibin_putenv(char *name, char *value TSRMLS_DC) { int len=0; char *buf = NULL; - if (!name) return -1; + if (!name) return NULL; len = strlen(name) + (value?strlen(value):0) + sizeof("=") + 2; buf = (char *)emalloc(len); if (value) { @@ -372,7 +372,6 @@ } else { snprintf(buf,len-1,"%s=", name); } - #if PHP_FASTCGI /* when php is started by mod_fastcgi, no regular environment is provided to PHP. It is always sent to PHP at the start @@ -382,14 +381,20 @@ FCGX_Request *request = (FCGX_Request *)SG(server_context); FCGX_PutEnv(request,buf); efree(buf); - return 0; + return sapi_cgibin_getenv(name,0 TSRMLS_CC); } #endif /* if cgi, or fastcgi and not found in fcgi env - check the regular environment */ - putenv(buf); + check the regular environment + this leaks, but it's only cgi anyway, we'll fix + it for 5.0 + */ + if (value) + putenv(strdup(buf)); + else + putenv(buf); efree(buf); - return 0; + return getenv(name); } static char *sapi_cgi_read_cookies(TSRMLS_D) @@ -535,94 +540,159 @@ /* }}} */ /* {{{ init_request_info + + initializes request_info structure + + specificly in this section we handle proper translations + for: + + PATH_INFO + derived from the portion of the URI path following + the script name but preceding any query data + may be empty + + PATH_TRANSLATED + derived by taking any path-info component of the + request URI and performing any virtual-to-physical + translation appropriate to map it onto the server's + document repository structure + + empty if PATH_INFO is empty + + The env var PATH_TRANSLATED **IS DIFFERENT** than the + request_info.path_translated variable, the latter should + match SCRIPT_FILENAME instead. + + SCRIPT_NAME + set to a URL path that could identify the CGI script + rather than the interpreter. PHP_SELF is set to this. + + REQUEST_URI + uri section following the domain:port part of a URI + + SCRIPT_FILENAME + The virtual-to-physical translation of SCRIPT_NAME (as per + PATH_TRANSLATED) + + These settings are documented at + http://cgi-spec.golux.com/ + + + Based on the following URL request: + + http://localhost/info.php/test?a=b + + should produce, which btw is the same as if + we were running under mod_cgi on apache (ie. not + using ScriptAlias directives): + + PATH_INFO=/test + PATH_TRANSLATED=/docroot/test + SCRIPT_NAME=/info.php + REQUEST_URI=/info.php/test?a=b + SCRIPT_FILENAME=/docroot/info.php + QUERY_STRING=a=b + + but what we get is (cgi/mod_fastcgi under apache): + + PATH_INFO=/info.php/test + PATH_TRANSLATED=/docroot/info.php/test + SCRIPT_NAME=/php/php-cgi (from the Action setting I suppose) + REQUEST_URI=/info.php/test?a=b + SCRIPT_FILENAME=/path/to/php/bin/php-cgi (Action setting translated) + QUERY_STRING=a=b + + Comments in the code below refer to using the above URL in a request + */ static void init_request_info(TSRMLS_D) { - char *content_length = sapi_cgibin_getenv("CONTENT_LENGTH",0 TSRMLS_CC); - char *content_type = sapi_cgibin_getenv("CONTENT_TYPE",0 TSRMLS_CC); - const char *auth; - char *env_path_translated; + char *env_script_filename = sapi_cgibin_getenv("SCRIPT_FILENAME",0 TSRMLS_CC); + char *env_path_translated = sapi_cgibin_getenv("PATH_TRANSLATED",0 TSRMLS_CC); + char *script_path_translated = env_script_filename; + + /* some broken servers do not have script_filename or argv0 + an example, IIS configured in some ways. then they do more + broken stuff and set path_translated to the cgi script location */ + if (!script_path_translated && env_path_translated) + script_path_translated = env_path_translated; + /* initialize the defaults */ SG(request_info).path_translated = NULL; - /* - * If for some reason the CGI interface is not setting the - * PATH_TRANSLATED correctly, SG(request_info).path_translated is NULL. - * We still call php_fopen_primary_script, because if you set doc_root - * or user_dir configuration directives, SCRIPT_NAME is used to construct - * the filename as a side effect of php_fopen_primary_script. - * - * Fixup path stuff to conform to CGI spec - * - * http://localhost/info.php/test?a=b - * - * should produce, which btw is the same as if - * we were running under mod_cgi on apache (ie. not - * using ScriptAlias directives): - * - * PATH_INFO=/test - * PATH_TRANSLATED=/docroot/test - * SCRIPT_NAME=/info.php - * REQUEST_URI=/info.php/test?a=b - * SCRIPT_FILENAME=/docroot/info.php - * QUERY_STRING=a=b - * - * cgi/mod_fastcgi under apache produce: - * - * PATH_INFO=/info.php/test - * PATH_TRANSLATED=/docroot/info.php/test - * SCRIPT_NAME=/php/php-cgi (from the Action setting I suppose) - * REQUEST_URI=/info.php/test?a=b - * SCRIPT_FILENAME=/path/to/php/bin/php-cgi (Action setting translated) - * QUERY_STRING=a=b - * - * Comments in the code below refer to using the above URL in a request - * - */ - - env_path_translated = sapi_cgibin_getenv("PATH_TRANSLATED",0 TSRMLS_CC); - - if(env_path_translated) { -#ifdef __riscos__ - /* Convert path to unix format*/ - __riscosify_control|=__RISCOSIFY_DONT_CHECK_DIR; - env_path_translated=__unixify(env_path_translated,0,NULL,1,0); -#endif + SG(request_info).request_method = NULL; + SG(request_info).query_string = NULL; + SG(request_info).request_uri = NULL; + SG(request_info).content_type = NULL; + SG(request_info).content_length = 0; + SG(sapi_headers).http_response_code = 200; + /* script_path_translated being set is a good indication that + we are running in a cgi environment, since it is always + null otherwise. otherwise, the filename + of the script will be retreived later via argc/argv */ + if (script_path_translated) { + const char *auth; + char *content_length = sapi_cgibin_getenv("CONTENT_LENGTH",0 +TSRMLS_CC); + char *content_type = sapi_cgibin_getenv("CONTENT_TYPE",0 TSRMLS_CC); #if ENABLE_PATHINFO_CHECK - /* - * if the file doesn't exist, try to extract PATH_INFO out - * of it by stat'ing back through the '/' - * this fixes url's like /info.php/test - * - * ini cgi.fix_pathinfo is on by default, but can be turned off - * if someone is running a server that does this correctly - */ + struct stat st; + char *env_path_info = sapi_cgibin_getenv("PATH_INFO",0 TSRMLS_CC); + char *env_script_name = sapi_cgibin_getenv("SCRIPT_NAME",0 TSRMLS_CC); + char *env_redirect_url = sapi_cgibin_getenv("REDIRECT_URL",0 +TSRMLS_CC); + char *env_document_root = sapi_cgibin_getenv("DOCUMENT_ROOT",0 +TSRMLS_CC); + if (fix_pathinfo) { - struct stat st; - char *env_script_name = sapi_cgibin_getenv("SCRIPT_NAME",0 TSRMLS_CC); - char *env_path_info = sapi_cgibin_getenv("PATH_INFO",0 TSRMLS_CC); - char *env_redirect_url = sapi_cgibin_getenv("REDIRECT_URL",0 TSRMLS_CC); - if (env_path_info) env_path_info = estrdup(env_path_info); - - if (env_redirect_url || - (env_script_name && env_path_info && - strcmp(env_path_info,env_script_name)==0)) { - /* - * if PHP is setup under a ScriptAlias in Apache, the - * redirect_url variable will be set. In this case, script_* - * points to the executable, not the script. We have to - * reset this stuff and clear PATH_INFO since it is also wrong. - * This unfortunately is Apache specific. IIS sets PATH_INFO - * and SCRIPT_NAME to the same thing if there is no *real* PATH_INFO. - */ - _sapi_cgibin_putenv("SCRIPT_FILENAME",env_path_translated TSRMLS_CC); - _sapi_cgibin_putenv("PATH_INFO",NULL TSRMLS_CC); - if (env_redirect_url) - _sapi_cgibin_putenv("SCRIPT_NAME",env_redirect_url TSRMLS_CC); + + /* save the originals first for anything we change later */ + if (env_path_translated) + +_sapi_cgibin_putenv("ORIG_PATH_TRANSLATED",env_path_translated TSRMLS_CC); + if (env_path_info) + _sapi_cgibin_putenv("ORIG_PATH_INFO",env_path_info +TSRMLS_CC); + if (env_script_name) + _sapi_cgibin_putenv("ORIG_SCRIPT_NAME",env_script_name +TSRMLS_CC); + if (env_script_filename) + +_sapi_cgibin_putenv("ORIG_SCRIPT_FILENAME",env_script_filename TSRMLS_CC); + + if (!env_document_root) { + /* IIS version of DOCUMENT_ROOT, not avail in cgi, but +is in fastcgi */ + env_document_root = +sapi_cgibin_getenv("APPL_PHYSICAL_PATH",0 TSRMLS_CC); + /* ini version of document root */ + if (!env_document_root) + env_document_root = PG(doc_root); + + /* set the document root, this makes a more + consistent env for php scripts */ + if (env_document_root) { + env_document_root = +_sapi_cgibin_putenv("DOCUMENT_ROOT",env_document_root TSRMLS_CC); + /* fix docroot */ + TRANSLATE_SLASHES(env_document_root); + } } - if (stat( env_path_translated, &st ) == -1 ) { - char *pt = estrdup(env_path_translated); + if (env_redirect_url) { + /* + pretty much apache specific. If we have a +redirect_url + then our script_filename and script_name point to +the + php executable + */ + script_path_translated = env_path_translated; + /* we correct SCRIPT_NAME now in case we don't have +PATH_INFO */ + env_script_name = +_sapi_cgibin_putenv("SCRIPT_NAME",env_redirect_url TSRMLS_CC); + } + +#ifdef __riscos__ + /* Convert path to unix format*/ + __riscosify_control|=__RISCOSIFY_DONT_CHECK_DIR; + +script_path_translated=__unixify(script_path_translated,0,NULL,1,0); +#endif + + /* + * if the file doesn't exist, try to extract PATH_INFO out + * of it by stat'ing back through the '/' + * this fixes url's like /info.php/test + */ + if (stat( script_path_translated, &st ) == -1 ) { + char *pt = estrdup(script_path_translated); int len = strlen(pt); char *ptr; @@ -644,24 +714,23 @@ * we have to play the game of hide and seek to figure * out what SCRIPT_NAME should be */ - char *env_document_root = sapi_cgibin_getenv("DOCUMENT_ROOT",0 TSRMLS_CC); int slen = len - strlen(pt); int pilen = strlen( env_path_info ); char *path_info = env_path_info + pilen - slen; - _sapi_cgibin_putenv("PATH_INFO",path_info TSRMLS_CC); - _sapi_cgibin_putenv("SCRIPT_FILENAME",pt TSRMLS_CC); + env_path_info = +_sapi_cgibin_putenv("PATH_INFO",path_info TSRMLS_CC); + script_path_translated = +_sapi_cgibin_putenv("SCRIPT_FILENAME",pt TSRMLS_CC); TRANSLATE_SLASHES(pt); /* figure out docroot SCRIPT_FILENAME minus SCRIPT_NAME */ - if (!env_document_root) - env_document_root = PG(doc_root); + if (env_document_root) { int l = strlen(env_document_root); int path_translated_len = 0; char *path_translated = NULL; + if +(env_document_root[l-1]=='/') --l; /* we have docroot, so we should have: * DOCUMENT_ROOT=/docroot @@ -669,17 +738,17 @@ * * SCRIPT_NAME is the portion of the path beyond docroot */ - _sapi_cgibin_putenv("SCRIPT_NAME",pt+l TSRMLS_CC); + env_script_name = +_sapi_cgibin_putenv("SCRIPT_NAME",pt+l TSRMLS_CC); /* * PATH_TRANSATED = DOCUMENT_ROOT + PATH_INFO */ - path_translated_len = l + strlen(path_info) + 2; + path_translated_len = l + +strlen(env_path_info) + 2; path_translated = (char *)emalloc(path_translated_len); *path_translated = 0; - strcat(path_translated,env_document_root); - strcat(path_translated,path_info); - _sapi_cgibin_putenv("PATH_TRANSLATED",path_translated TSRMLS_CC); + +strncat(path_translated,env_document_root,l); + +strcat(path_translated,env_path_info); + env_path_translated = +_sapi_cgibin_putenv("PATH_TRANSLATED",path_translated TSRMLS_CC); efree(path_translated); } else if (env_script_name && strstr(pt,env_script_name)) { @@ -687,74 +756,49 @@ * PATH_TRANSATED = PATH_TRANSATED - SCRIPT_NAME + PATH_INFO */ int ptlen = strlen(pt)-strlen(env_script_name); - int path_translated_len = ptlen + strlen(path_info) + 2; + int path_translated_len = +ptlen + strlen(env_path_info) + 2; char *path_translated = NULL; path_translated = (char *)emalloc(path_translated_len); *path_translated = 0; strncat(path_translated,pt,ptlen); - strcat(path_translated,path_info); - _sapi_cgibin_putenv("PATH_TRANSLATED",path_translated TSRMLS_CC); + +strcat(path_translated,env_path_info); + env_path_translated = +_sapi_cgibin_putenv("PATH_TRANSLATED",path_translated TSRMLS_CC); efree(path_translated); } break; } } + if (!ptr) { + /* + * if we stripped out all the '/' and still +didn't find + * a valid path... we will fail, badly. of +course we would + * have failed anyway... we output 'no input +file' now. + */ + script_path_translated = +_sapi_cgibin_putenv("SCRIPT_FILENAME",NULL TSRMLS_CC); + SG(sapi_headers).http_response_code = 404; + } if (pt) efree(pt); - /* - * if we stripped out all the '/' and still didn't find - * a valid path... we will fail, badly. of course we would - * have failed anyway... is there a nice way to error? - */ + } else { + /* make sure path_info/translated are empty */ + script_path_translated = +_sapi_cgibin_putenv("SCRIPT_FILENAME",script_path_translated TSRMLS_CC); + _sapi_cgibin_putenv("PATH_INFO",NULL TSRMLS_CC); + _sapi_cgibin_putenv("PATH_TRANSLATED",NULL TSRMLS_CC); } - if (env_path_info) efree(env_path_info); - } else -#endif - { - /* old broken logic here, but at least reverts to - * previous behaviour if the fixup is ignored, or there - * is a working server. - * - * 1. DISCARD_PATH IS BAD - * 2. PATH_INFO will never be right - */ -#if DISCARD_PATH - env_path_translated = sapi_cgibin_getenv("SCRIPT_FILENAME",0 TSRMLS_CC); -#else - env_path_translated = sapi_cgibin_getenv("PATH_TRANSLATED",0 TSRMLS_CC); -#endif - SG(request_info).path_translated = env_path_translated; } - } +#endif - SG(request_info).request_method = sapi_cgibin_getenv("REQUEST_METHOD",0 TSRMLS_CC); - SG(request_info).query_string = sapi_cgibin_getenv("QUERY_STRING",0 TSRMLS_CC); - SG(request_info).request_uri = sapi_cgibin_getenv("SCRIPT_NAME",0 TSRMLS_CC); - - if (!SG(request_info).request_uri) { - /* this is old logic, and completely incorrect by CGI spec - * this is used to generate PHP_SELF, which should actually - * match SCRIPT_NAME. This is being left so PHP will be as broken - * as it was before if a server does not set SCRIPT_NAME. - */ - SG(request_info).request_uri = sapi_cgibin_getenv("PATH_INFO",0 TSRMLS_CC); + SG(request_info).request_method = +sapi_cgibin_getenv("REQUEST_METHOD",0 TSRMLS_CC); + SG(request_info).query_string = sapi_cgibin_getenv("QUERY_STRING",0 +TSRMLS_CC); + SG(request_info).request_uri = sapi_cgibin_getenv("SCRIPT_NAME",0 +TSRMLS_CC); + if (script_path_translated) + SG(request_info).path_translated = +estrdup(script_path_translated); + SG(request_info).content_type = (content_type ? content_type : "" ); + SG(request_info).content_length = +(content_length?atoi(content_length):0); + + /* The CGI RFC allows servers to pass on unvalidated Authorization +data */ + auth = sapi_cgibin_getenv("HTTP_AUTHORIZATION",0 TSRMLS_CC); + php_handle_auth_data(auth TSRMLS_CC); } - if (!SG(request_info).path_translated) { - /* if this didn't get set above, do it now, default to script_filename */ - SG(request_info).path_translated = sapi_cgibin_getenv("SCRIPT_FILENAME",0 TSRMLS_CC); - } - if (!SG(request_info).path_translated) { - /* server didn't set script_filename, default to path_translated */ - SG(request_info).path_translated = sapi_cgibin_getenv("PATH_TRANSLATED",0 TSRMLS_CC); - } - if (SG(request_info).path_translated) - SG(request_info).path_translated = estrdup(SG(request_info).path_translated); - SG(request_info).content_type = (content_type ? content_type : "" ); - SG(request_info).content_length = (content_length?atoi(content_length):0); - SG(sapi_headers).http_response_code = 200; - - /* The CGI RFC allows servers to pass on unvalidated Authorization data */ - auth = sapi_cgibin_getenv("HTTP_AUTHORIZATION",0 TSRMLS_CC); - php_handle_auth_data(auth TSRMLS_CC); } /* }}} */ @@ -915,31 +959,20 @@ case 'n': cgi_sapi_module.php_ini_ignore = 1; break; - } - - } - ap_php_optind = orig_optind; - ap_php_optarg = orig_optarg; - } - #if PHP_FASTCGI - if (!cgi && !fastcgi) { - /* if we're started on command line, check to see if - we are being started as an 'external' fastcgi - server by accepting a bindpath parameter. */ - while ((c=ap_php_getopt(argc, argv, OPTSTRING))!=-1) { - switch (c) { + /* if we're started on command line, check to see if + we are being started as an 'external' fastcgi + server by accepting a bindpath parameter. */ case 'b': - bindpath= strdup(ap_php_optarg); + if (!fastcgi) bindpath= strdup(ap_php_optarg); break; +#endif } } ap_php_optind = orig_optind; ap_php_optarg = orig_optarg; } -#endif - #ifdef ZTS compiler_globals = ts_resource(compiler_globals_id); @@ -1186,11 +1219,7 @@ #if PHP_FASTCGI && !fastcgi #endif - ) { /* never execute the arguments if you are a CGI */ - if (SG(request_info).argv0) { - free(SG(request_info).argv0); - SG(request_info).argv0 = NULL; - } + ) { if (cgi_sapi_module.php_ini_path_override && cgi_sapi_module.php_ini_ignore) { no_headers = 1; @@ -1365,6 +1394,7 @@ if (fastcgi) { file_handle.type = ZEND_HANDLE_FILENAME; file_handle.filename = SG(request_info).path_translated; + file_handle.handle.fp = NULL; } else { #endif file_handle.filename = "-";
-- PHP CVS Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php