shane           Sat Jan 25 17:02:46 2003 EDT

  Modified files:              (Branch: PHP_4_3)
    /php4/sapi/cgi      cgi_main.c 
  Log:
  MFH
  
  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.190.2.11 php4/sapi/cgi/cgi_main.c:1.190.2.12
--- php4/sapi/cgi/cgi_main.c:1.190.2.11 Tue Jan  7 19:44:58 2003
+++ php4/sapi/cgi/cgi_main.c    Sat Jan 25 17:02:45 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,16 +381,23 @@
                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)
 {
        return sapi_cgibin_getenv((char *)"HTTP_COOKIE",0 TSRMLS_CC);
@@ -534,95 +540,161 @@
 }
 /* }}} */
 
+
 /* {{{ 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);
+       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;
 
-       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
-               
+       /* 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;
 
@@ -635,7 +707,7 @@
                                                 * then we can modify PATH_INFO
                                                 * accordingly
                                                 *
-                                                * we now have the makings of 
+                                                * we now have the makings of
                                                 * PATH_INFO=/test
                                                 * SCRIPT_FILENAME=/docroot/info.php
                                                 *
@@ -644,24 +716,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,92 +740,67 @@
                                                         *
                                                         * 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)) {
-                                                       /* 
+                                                       /*
                                                         * 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 +961,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 +1221,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 +1396,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

Reply via email to