File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / sapi / cgi / cgi_main.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 23:48:06 2012 UTC (12 years, 5 months ago) by misho
Branches: php, MAIN
CVS tags: v5_3_10, HEAD
php

    1: /*
    2:    +----------------------------------------------------------------------+
    3:    | PHP Version 5                                                        |
    4:    +----------------------------------------------------------------------+
    5:    | Copyright (c) 1997-2012 The PHP Group                                |
    6:    +----------------------------------------------------------------------+
    7:    | This source file is subject to version 3.01 of the PHP license,      |
    8:    | that is bundled with this package in the file LICENSE, and is        |
    9:    | available through the world-wide-web at the following url:           |
   10:    | http://www.php.net/license/3_01.txt                                  |
   11:    | If you did not receive a copy of the PHP license and are unable to   |
   12:    | obtain it through the world-wide-web, please send a note to          |
   13:    | license@php.net so we can mail you a copy immediately.               |
   14:    +----------------------------------------------------------------------+
   15:    | Authors: Rasmus Lerdorf <rasmus@lerdorf.on.ca>                       |
   16:    |          Stig Bakken <ssb@php.net>                                   |
   17:    |          Zeev Suraski <zeev@zend.com>                                |
   18:    | FastCGI: Ben Mansell <php@slimyhorror.com>                           |
   19:    |          Shane Caraveo <shane@caraveo.com>                           |
   20:    |          Dmitry Stogov <dmitry@zend.com>                             |
   21:    +----------------------------------------------------------------------+
   22: */
   23: 
   24: /* $Id: cgi_main.c,v 1.1.1.1 2012/02/21 23:48:06 misho Exp $ */
   25: 
   26: #include "php.h"
   27: #include "php_globals.h"
   28: #include "php_variables.h"
   29: #include "zend_modules.h"
   30: 
   31: #include "SAPI.h"
   32: 
   33: #include <stdio.h>
   34: #include "php.h"
   35: 
   36: #ifdef PHP_WIN32
   37: # include "win32/time.h"
   38: # include "win32/signal.h"
   39: # include <process.h>
   40: #endif
   41: 
   42: #if HAVE_SYS_TIME_H
   43: # include <sys/time.h>
   44: #endif
   45: 
   46: #if HAVE_UNISTD_H
   47: # include <unistd.h>
   48: #endif
   49: 
   50: #if HAVE_SIGNAL_H
   51: # include <signal.h>
   52: #endif
   53: 
   54: #if HAVE_SETLOCALE
   55: # include <locale.h>
   56: #endif
   57: 
   58: #if HAVE_SYS_TYPES_H
   59: # include <sys/types.h>
   60: #endif
   61: 
   62: #if HAVE_SYS_WAIT_H
   63: # include <sys/wait.h>
   64: #endif
   65: 
   66: #include "zend.h"
   67: #include "zend_extensions.h"
   68: #include "php_ini.h"
   69: #include "php_globals.h"
   70: #include "php_main.h"
   71: #include "fopen_wrappers.h"
   72: #include "ext/standard/php_standard.h"
   73: 
   74: #ifdef PHP_WIN32
   75: # include <io.h>
   76: # include <fcntl.h>
   77: # include "win32/php_registry.h"
   78: #endif
   79: 
   80: #ifdef __riscos__
   81: # include <unixlib/local.h>
   82: int __riscosify_control = __RISCOSIFY_STRICT_UNIX_SPECS;
   83: #endif
   84: 
   85: #include "zend_compile.h"
   86: #include "zend_execute.h"
   87: #include "zend_highlight.h"
   88: #include "zend_indent.h"
   89: 
   90: #include "php_getopt.h"
   91: 
   92: #include "fastcgi.h"
   93: 
   94: #ifndef PHP_WIN32
   95: /* XXX this will need to change later when threaded fastcgi is implemented.  shane */
   96: struct sigaction act, old_term, old_quit, old_int;
   97: #endif
   98: 
   99: static void (*php_php_import_environment_variables)(zval *array_ptr TSRMLS_DC);
  100: 
  101: #ifndef PHP_WIN32
  102: /* these globals used for forking children on unix systems */
  103: /**
  104:  * Number of child processes that will get created to service requests
  105:  */
  106: static int children = 0;
  107: 
  108: /**
  109:  * Set to non-zero if we are the parent process
  110:  */
  111: static int parent = 1;
  112: 
  113: /* Did parent received exit signals SIG_TERM/SIG_INT/SIG_QUIT */
  114: static int exit_signal = 0;
  115: 
  116: /* Is Parent waiting for children to exit */
  117: static int parent_waiting = 0;
  118: 
  119: /**
  120:  * Process group
  121:  */
  122: static pid_t pgroup;
  123: #endif
  124: 
  125: #define PHP_MODE_STANDARD	1
  126: #define PHP_MODE_HIGHLIGHT	2
  127: #define PHP_MODE_INDENT		3
  128: #define PHP_MODE_LINT		4
  129: #define PHP_MODE_STRIP		5
  130: 
  131: static char *php_optarg = NULL;
  132: static int php_optind = 1;
  133: static zend_module_entry cgi_module_entry;
  134: 
  135: static const opt_struct OPTIONS[] = {
  136: 	{'a', 0, "interactive"},
  137: 	{'b', 1, "bindpath"},
  138: 	{'C', 0, "no-chdir"},
  139: 	{'c', 1, "php-ini"},
  140: 	{'d', 1, "define"},
  141: 	{'e', 0, "profile-info"},
  142: 	{'f', 1, "file"},
  143: 	{'h', 0, "help"},
  144: 	{'i', 0, "info"},
  145: 	{'l', 0, "syntax-check"},
  146: 	{'m', 0, "modules"},
  147: 	{'n', 0, "no-php-ini"},
  148: 	{'q', 0, "no-header"},
  149: 	{'s', 0, "syntax-highlight"},
  150: 	{'s', 0, "syntax-highlighting"},
  151: 	{'w', 0, "strip"},
  152: 	{'?', 0, "usage"},/* help alias (both '?' and 'usage') */
  153: 	{'v', 0, "version"},
  154: 	{'z', 1, "zend-extension"},
  155:  	{'T', 1, "timing"},
  156: 	{'-', 0, NULL} /* end of args */
  157: };
  158: 
  159: typedef struct _php_cgi_globals_struct {
  160: 	zend_bool rfc2616_headers;
  161: 	zend_bool nph;
  162: 	zend_bool check_shebang_line;
  163: 	zend_bool fix_pathinfo;
  164: 	zend_bool force_redirect;
  165: 	zend_bool discard_path;
  166: 	zend_bool fcgi_logging;
  167: 	char *redirect_status_env;
  168: #ifdef PHP_WIN32
  169: 	zend_bool impersonate;
  170: #endif
  171: 	HashTable user_config_cache;
  172: } php_cgi_globals_struct;
  173: 
  174: /* {{{ user_config_cache
  175:  *
  176:  * Key for each cache entry is dirname(PATH_TRANSLATED).
  177:  *
  178:  * NOTE: Each cache entry config_hash contains the combination from all user ini files found in
  179:  *       the path starting from doc_root throught to dirname(PATH_TRANSLATED).  There is no point
  180:  *       storing per-file entries as it would not be possible to detect added / deleted entries
  181:  *       between separate files.
  182:  */
  183: typedef struct _user_config_cache_entry {
  184: 	time_t expires;
  185: 	HashTable *user_config;
  186: } user_config_cache_entry;
  187: 
  188: static void user_config_cache_entry_dtor(user_config_cache_entry *entry)
  189: {
  190: 	zend_hash_destroy(entry->user_config);
  191: 	free(entry->user_config);
  192: }
  193: /* }}} */
  194: 
  195: #ifdef ZTS
  196: static int php_cgi_globals_id;
  197: #define CGIG(v) TSRMG(php_cgi_globals_id, php_cgi_globals_struct *, v)
  198: #else
  199: static php_cgi_globals_struct php_cgi_globals;
  200: #define CGIG(v) (php_cgi_globals.v)
  201: #endif
  202: 
  203: #ifdef PHP_WIN32
  204: #define TRANSLATE_SLASHES(path) \
  205: 	{ \
  206: 		char *tmp = path; \
  207: 		while (*tmp) { \
  208: 			if (*tmp == '\\') *tmp = '/'; \
  209: 			tmp++; \
  210: 		} \
  211: 	}
  212: #else
  213: #define TRANSLATE_SLASHES(path)
  214: #endif
  215: 
  216: static int print_module_info(zend_module_entry *module, void *arg TSRMLS_DC)
  217: {
  218: 	php_printf("%s\n", module->name);
  219: 	return 0;
  220: }
  221: 
  222: static int module_name_cmp(const void *a, const void *b TSRMLS_DC)
  223: {
  224: 	Bucket *f = *((Bucket **) a);
  225: 	Bucket *s = *((Bucket **) b);
  226: 
  227: 	return strcasecmp(	((zend_module_entry *)f->pData)->name,
  228: 						((zend_module_entry *)s->pData)->name);
  229: }
  230: 
  231: static void print_modules(TSRMLS_D)
  232: {
  233: 	HashTable sorted_registry;
  234: 	zend_module_entry tmp;
  235: 
  236: 	zend_hash_init(&sorted_registry, 50, NULL, NULL, 1);
  237: 	zend_hash_copy(&sorted_registry, &module_registry, NULL, &tmp, sizeof(zend_module_entry));
  238: 	zend_hash_sort(&sorted_registry, zend_qsort, module_name_cmp, 0 TSRMLS_CC);
  239: 	zend_hash_apply_with_argument(&sorted_registry, (apply_func_arg_t) print_module_info, NULL TSRMLS_CC);
  240: 	zend_hash_destroy(&sorted_registry);
  241: }
  242: 
  243: static int print_extension_info(zend_extension *ext, void *arg TSRMLS_DC)
  244: {
  245: 	php_printf("%s\n", ext->name);
  246: 	return 0;
  247: }
  248: 
  249: static int extension_name_cmp(const zend_llist_element **f, const zend_llist_element **s TSRMLS_DC)
  250: {
  251: 	return strcmp(	((zend_extension *)(*f)->data)->name,
  252: 					((zend_extension *)(*s)->data)->name);
  253: }
  254: 
  255: static void print_extensions(TSRMLS_D)
  256: {
  257: 	zend_llist sorted_exts;
  258: 
  259: 	zend_llist_copy(&sorted_exts, &zend_extensions);
  260: 	sorted_exts.dtor = NULL;
  261: 	zend_llist_sort(&sorted_exts, extension_name_cmp TSRMLS_CC);
  262: 	zend_llist_apply_with_argument(&sorted_exts, (llist_apply_with_arg_func_t) print_extension_info, NULL TSRMLS_CC);
  263: 	zend_llist_destroy(&sorted_exts);
  264: }
  265: 
  266: #ifndef STDOUT_FILENO
  267: #define STDOUT_FILENO 1
  268: #endif
  269: 
  270: static inline size_t sapi_cgibin_single_write(const char *str, uint str_length TSRMLS_DC)
  271: {
  272: #ifdef PHP_WRITE_STDOUT
  273: 	long ret;
  274: #else
  275: 	size_t ret;
  276: #endif
  277: 
  278: 	if (fcgi_is_fastcgi()) {
  279: 		fcgi_request *request = (fcgi_request*) SG(server_context);
  280: 		long ret = fcgi_write(request, FCGI_STDOUT, str, str_length);
  281: 		if (ret <= 0) {
  282: 			return 0;
  283: 		}
  284: 		return ret;
  285: 	}
  286: 
  287: #ifdef PHP_WRITE_STDOUT
  288: 	ret = write(STDOUT_FILENO, str, str_length);
  289: 	if (ret <= 0) return 0;
  290: 	return ret;
  291: #else
  292: 	ret = fwrite(str, 1, MIN(str_length, 16384), stdout);
  293: 	return ret;
  294: #endif
  295: }
  296: 
  297: static int sapi_cgibin_ub_write(const char *str, uint str_length TSRMLS_DC)
  298: {
  299: 	const char *ptr = str;
  300: 	uint remaining = str_length;
  301: 	size_t ret;
  302: 
  303: 	while (remaining > 0) {
  304: 		ret = sapi_cgibin_single_write(ptr, remaining TSRMLS_CC);
  305: 		if (!ret) {
  306: 			php_handle_aborted_connection();
  307: 			return str_length - remaining;
  308: 		}
  309: 		ptr += ret;
  310: 		remaining -= ret;
  311: 	}
  312: 
  313: 	return str_length;
  314: }
  315: 
  316: 
  317: static void sapi_cgibin_flush(void *server_context)
  318: {
  319: 	if (fcgi_is_fastcgi()) {
  320: 		fcgi_request *request = (fcgi_request*) server_context;
  321: 		if (
  322: #ifndef PHP_WIN32
  323: 		!parent &&
  324: #endif
  325: 		request && !fcgi_flush(request, 0)) {
  326: 			php_handle_aborted_connection();
  327: 		}
  328: 		return;
  329: 	}
  330: 	if (fflush(stdout) == EOF) {
  331: 		php_handle_aborted_connection();
  332: 	}
  333: }
  334: 
  335: #define SAPI_CGI_MAX_HEADER_LENGTH 1024
  336: 
  337: typedef struct _http_error {
  338:   int code;
  339:   const char* msg;
  340: } http_error;
  341: 
  342: static const http_error http_error_codes[] = {
  343: 	{100, "Continue"},
  344: 	{101, "Switching Protocols"},
  345: 	{200, "OK"},
  346: 	{201, "Created"},
  347: 	{202, "Accepted"},
  348: 	{203, "Non-Authoritative Information"},
  349: 	{204, "No Content"},
  350: 	{205, "Reset Content"},
  351: 	{206, "Partial Content"},
  352: 	{300, "Multiple Choices"},
  353: 	{301, "Moved Permanently"},
  354: 	{302, "Moved Temporarily"},
  355: 	{303, "See Other"},
  356: 	{304, "Not Modified"},
  357: 	{305, "Use Proxy"},
  358: 	{400, "Bad Request"},
  359: 	{401, "Unauthorized"},
  360: 	{402, "Payment Required"},
  361: 	{403, "Forbidden"},
  362: 	{404, "Not Found"},
  363: 	{405, "Method Not Allowed"},
  364: 	{406, "Not Acceptable"},
  365: 	{407, "Proxy Authentication Required"},
  366: 	{408, "Request Time-out"},
  367: 	{409, "Conflict"},
  368: 	{410, "Gone"},
  369: 	{411, "Length Required"},
  370: 	{412, "Precondition Failed"},
  371: 	{413, "Request Entity Too Large"},
  372: 	{414, "Request-URI Too Large"},
  373: 	{415, "Unsupported Media Type"},
  374: 	{500, "Internal Server Error"},
  375: 	{501, "Not Implemented"},
  376: 	{502, "Bad Gateway"},
  377: 	{503, "Service Unavailable"},
  378: 	{504, "Gateway Time-out"},
  379: 	{505, "HTTP Version not supported"},
  380: 	{0,   NULL}
  381: };
  382: 
  383: static int sapi_cgi_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
  384: {
  385: 	char buf[SAPI_CGI_MAX_HEADER_LENGTH];
  386: 	sapi_header_struct *h;
  387: 	zend_llist_position pos;
  388: 	zend_bool ignore_status = 0;
  389: 	int response_status = SG(sapi_headers).http_response_code;
  390: 
  391: 	if (SG(request_info).no_headers == 1) {
  392: 		return  SAPI_HEADER_SENT_SUCCESSFULLY;
  393: 	}
  394: 
  395: 	if (CGIG(nph) || SG(sapi_headers).http_response_code != 200)
  396: 	{
  397: 		int len;
  398: 		zend_bool has_status = 0;
  399: 
  400: 		if (CGIG(rfc2616_headers) && SG(sapi_headers).http_status_line) {
  401: 			char *s;
  402: 			len = slprintf(buf, SAPI_CGI_MAX_HEADER_LENGTH, "%s\r\n", SG(sapi_headers).http_status_line);
  403: 			if ((s = strchr(SG(sapi_headers).http_status_line, ' '))) {
  404: 				response_status = atoi((s + 1));
  405: 			}
  406: 
  407: 			if (len > SAPI_CGI_MAX_HEADER_LENGTH) {
  408: 				len = SAPI_CGI_MAX_HEADER_LENGTH;
  409: 			}
  410: 
  411: 		} else {
  412: 			char *s;
  413: 
  414: 			if (SG(sapi_headers).http_status_line &&
  415: 				(s = strchr(SG(sapi_headers).http_status_line, ' ')) != 0 &&
  416: 				(s - SG(sapi_headers).http_status_line) >= 5 &&
  417: 				strncasecmp(SG(sapi_headers).http_status_line, "HTTP/", 5) == 0
  418: 			) {
  419: 				len = slprintf(buf, sizeof(buf), "Status:%s\r\n", s);
  420: 				response_status = atoi((s + 1));
  421: 			} else {
  422: 				h = (sapi_header_struct*)zend_llist_get_first_ex(&sapi_headers->headers, &pos);
  423: 				while (h) {
  424: 					if (h->header_len > sizeof("Status:")-1 &&
  425: 						strncasecmp(h->header, "Status:", sizeof("Status:")-1) == 0
  426: 					) {
  427: 						has_status = 1;
  428: 						break;
  429: 					}
  430: 					h = (sapi_header_struct*)zend_llist_get_next_ex(&sapi_headers->headers, &pos);
  431: 				}
  432: 				if (!has_status) {
  433: 					http_error *err = (http_error*)http_error_codes;
  434: 
  435: 					while (err->code != 0) {
  436: 						if (err->code == SG(sapi_headers).http_response_code) {
  437: 							break;
  438: 						}
  439: 						err++;
  440: 					}
  441: 					if (err->msg) {
  442: 						len = slprintf(buf, sizeof(buf), "Status: %d %s\r\n", SG(sapi_headers).http_response_code, err->msg);
  443: 					} else {
  444: 						len = slprintf(buf, sizeof(buf), "Status: %d\r\n", SG(sapi_headers).http_response_code);
  445: 					}
  446: 				}
  447: 			}
  448: 		}
  449: 
  450: 		if (!has_status) {
  451: 			PHPWRITE_H(buf, len);
  452: 			ignore_status = 1;
  453: 		}
  454: 	}
  455: 
  456: 	h = (sapi_header_struct*)zend_llist_get_first_ex(&sapi_headers->headers, &pos);
  457: 	while (h) {
  458: 		/* prevent CRLFCRLF */
  459: 		if (h->header_len) {
  460: 			if (h->header_len > sizeof("Status:")-1 && 
  461: 				strncasecmp(h->header, "Status:", sizeof("Status:")-1) == 0
  462: 			) {
  463: 				if (!ignore_status) {
  464: 					ignore_status = 1;
  465: 					PHPWRITE_H(h->header, h->header_len);
  466: 					PHPWRITE_H("\r\n", 2);
  467: 				}
  468: 			} else if (response_status == 304 && h->header_len > sizeof("Content-Type:")-1 &&
  469: 				strncasecmp(h->header, "Content-Type:", sizeof("Content-Type:")-1) == 0
  470: 			) {
  471: 				h = (sapi_header_struct*)zend_llist_get_next_ex(&sapi_headers->headers, &pos);
  472: 				continue;
  473: 			} else {
  474: 				PHPWRITE_H(h->header, h->header_len);
  475: 				PHPWRITE_H("\r\n", 2);
  476: 			}
  477: 		}
  478: 		h = (sapi_header_struct*)zend_llist_get_next_ex(&sapi_headers->headers, &pos);
  479: 	}
  480: 	PHPWRITE_H("\r\n", 2);
  481: 
  482: 	return SAPI_HEADER_SENT_SUCCESSFULLY;
  483: }
  484: 
  485: #ifndef STDIN_FILENO
  486: # define STDIN_FILENO 0
  487: #endif
  488: 
  489: static int sapi_cgi_read_post(char *buffer, uint count_bytes TSRMLS_DC)
  490: {
  491: 	uint read_bytes = 0;
  492: 	int tmp_read_bytes;
  493: 
  494: 	count_bytes = MIN(count_bytes, (uint) SG(request_info).content_length - SG(read_post_bytes));
  495: 	while (read_bytes < count_bytes) {
  496: 		if (fcgi_is_fastcgi()) {
  497: 			fcgi_request *request = (fcgi_request*) SG(server_context);
  498: 			tmp_read_bytes = fcgi_read(request, buffer + read_bytes, count_bytes - read_bytes);
  499: 		} else {
  500: 			tmp_read_bytes = read(STDIN_FILENO, buffer + read_bytes, count_bytes - read_bytes);
  501: 		}
  502: 		if (tmp_read_bytes <= 0) {
  503: 			break;
  504: 		}
  505: 		read_bytes += tmp_read_bytes;
  506: 	}
  507: 	return read_bytes;
  508: }
  509: 
  510: static char *sapi_cgibin_getenv(char *name, size_t name_len TSRMLS_DC)
  511: {
  512: 	/* when php is started by mod_fastcgi, no regular environment
  513: 	 * is provided to PHP.  It is always sent to PHP at the start
  514: 	 * of a request.  So we have to do our own lookup to get env
  515: 	 * vars.  This could probably be faster somehow.  */
  516: 	if (fcgi_is_fastcgi()) {
  517: 		fcgi_request *request = (fcgi_request*) SG(server_context);
  518: 		return fcgi_getenv(request, name, name_len);
  519: 	}
  520: 	/*  if cgi, or fastcgi and not found in fcgi env
  521: 		check the regular environment */
  522: 	return getenv(name);
  523: }
  524: 
  525: static char *_sapi_cgibin_putenv(char *name, char *value TSRMLS_DC)
  526: {
  527: 	int name_len;
  528: #if !HAVE_SETENV || !HAVE_UNSETENV
  529: 	int len;
  530: 	char *buf;
  531: #endif
  532: 
  533: 	if (!name) {
  534: 		return NULL;
  535: 	}
  536: 	name_len = strlen(name);
  537: 
  538: 	/* when php is started by mod_fastcgi, no regular environment
  539: 	 * is provided to PHP.  It is always sent to PHP at the start
  540: 	 * of a request.  So we have to do our own lookup to get env
  541: 	 * vars.  This could probably be faster somehow.  */
  542: 	if (fcgi_is_fastcgi()) {
  543: 		fcgi_request *request = (fcgi_request*) SG(server_context);
  544: 		return fcgi_putenv(request, name, name_len, value);
  545: 	}
  546: 
  547: #if HAVE_SETENV
  548: 	if (value) {
  549: 		setenv(name, value, 1);
  550: 	}
  551: #endif
  552: #if HAVE_UNSETENV
  553: 	if (!value) {
  554: 		unsetenv(name);
  555: 	}
  556: #endif
  557: 
  558: #if !HAVE_SETENV || !HAVE_UNSETENV
  559: 	/*  if cgi, or fastcgi and not found in fcgi env
  560: 		check the regular environment
  561: 		this leaks, but it's only cgi anyway, we'll fix
  562: 		it for 5.0
  563: 	*/
  564: 	len = name_len + (value ? strlen(value) : 0) + sizeof("=") + 2;
  565: 	buf = (char *) malloc(len);
  566: 	if (buf == NULL) {
  567: 		return getenv(name);
  568: 	}
  569: #endif
  570: #if !HAVE_SETENV
  571: 	if (value) {
  572: 		len = slprintf(buf, len - 1, "%s=%s", name, value);
  573: 		putenv(buf);
  574: 	}
  575: #endif
  576: #if !HAVE_UNSETENV
  577: 	if (!value) {
  578: 		len = slprintf(buf, len - 1, "%s=", name);
  579: 		putenv(buf);
  580: 	}
  581: #endif
  582: 	return getenv(name);
  583: }
  584: 
  585: static char *sapi_cgi_read_cookies(TSRMLS_D)
  586: {
  587: 	return sapi_cgibin_getenv((char *) "HTTP_COOKIE", sizeof("HTTP_COOKIE")-1 TSRMLS_CC);
  588: }
  589: 
  590: void cgi_php_import_environment_variables(zval *array_ptr TSRMLS_DC)
  591: {
  592: 	if (PG(http_globals)[TRACK_VARS_ENV] &&
  593: 		array_ptr != PG(http_globals)[TRACK_VARS_ENV] &&
  594: 		Z_TYPE_P(PG(http_globals)[TRACK_VARS_ENV]) == IS_ARRAY &&
  595: 		zend_hash_num_elements(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_ENV])) > 0
  596: 	) {
  597: 		zval_dtor(array_ptr);
  598: 		*array_ptr = *PG(http_globals)[TRACK_VARS_ENV];
  599: 		INIT_PZVAL(array_ptr);
  600: 		zval_copy_ctor(array_ptr);
  601: 		return;
  602: 	} else if (PG(http_globals)[TRACK_VARS_SERVER] &&
  603: 		array_ptr != PG(http_globals)[TRACK_VARS_SERVER] &&
  604: 		Z_TYPE_P(PG(http_globals)[TRACK_VARS_SERVER]) == IS_ARRAY &&
  605: 		zend_hash_num_elements(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_SERVER])) > 0
  606: 	) {
  607: 		zval_dtor(array_ptr);
  608: 		*array_ptr = *PG(http_globals)[TRACK_VARS_SERVER];
  609: 		INIT_PZVAL(array_ptr);
  610: 		zval_copy_ctor(array_ptr);
  611: 		return;
  612: 	}
  613: 
  614: 	/* call php's original import as a catch-all */
  615: 	php_php_import_environment_variables(array_ptr TSRMLS_CC);
  616: 
  617: 	if (fcgi_is_fastcgi()) {
  618: 		fcgi_request *request = (fcgi_request*) SG(server_context);
  619: 		HashPosition pos;
  620: 		int magic_quotes_gpc = PG(magic_quotes_gpc);
  621: 		char *var, **val;
  622: 		uint var_len;
  623: 		ulong idx;
  624: 		int filter_arg = (array_ptr == PG(http_globals)[TRACK_VARS_ENV])?PARSE_ENV:PARSE_SERVER;
  625: 
  626: 		/* turn off magic_quotes while importing environment variables */
  627: 		PG(magic_quotes_gpc) = 0;
  628: 		for (zend_hash_internal_pointer_reset_ex(request->env, &pos);
  629: 			zend_hash_get_current_key_ex(request->env, &var, &var_len, &idx, 0, &pos) == HASH_KEY_IS_STRING &&
  630: 			zend_hash_get_current_data_ex(request->env, (void **) &val, &pos) == SUCCESS;
  631: 			zend_hash_move_forward_ex(request->env, &pos)
  632: 		) {
  633: 			unsigned int new_val_len;
  634: 
  635: 			if (sapi_module.input_filter(filter_arg, var, val, strlen(*val), &new_val_len TSRMLS_CC)) {
  636: 				php_register_variable_safe(var, *val, new_val_len, array_ptr TSRMLS_CC);
  637: 			}
  638: 		}
  639: 		PG(magic_quotes_gpc) = magic_quotes_gpc;
  640: 	}
  641: }
  642: 
  643: static void sapi_cgi_register_variables(zval *track_vars_array TSRMLS_DC)
  644: {
  645: 	unsigned int php_self_len;
  646: 	char *php_self;
  647: 
  648: 	/* In CGI mode, we consider the environment to be a part of the server
  649: 	 * variables
  650: 	 */
  651: 	php_import_environment_variables(track_vars_array TSRMLS_CC);
  652: 
  653: 	if (CGIG(fix_pathinfo)) {
  654: 		char *script_name = SG(request_info).request_uri;
  655: 		unsigned int script_name_len = script_name ? strlen(script_name) : 0;
  656: 		char *path_info = sapi_cgibin_getenv("PATH_INFO", sizeof("PATH_INFO")-1 TSRMLS_CC);
  657: 		unsigned int path_info_len = path_info ? strlen(path_info) : 0;
  658: 
  659: 		php_self_len = script_name_len + path_info_len;
  660: 		php_self = emalloc(php_self_len + 1);
  661: 
  662: 		if (script_name) {
  663: 			memcpy(php_self, script_name, script_name_len + 1);
  664: 		}
  665: 		if (path_info) {
  666: 			memcpy(php_self + script_name_len, path_info, path_info_len + 1);
  667: 		}
  668: 
  669: 		/* Build the special-case PHP_SELF variable for the CGI version */
  670: 		if (sapi_module.input_filter(PARSE_SERVER, "PHP_SELF", &php_self, php_self_len, &php_self_len TSRMLS_CC)) {
  671: 			php_register_variable_safe("PHP_SELF", php_self, php_self_len, track_vars_array TSRMLS_CC);
  672: 		}
  673: 		efree(php_self);
  674: 	} else {
  675: 		php_self = SG(request_info).request_uri ? SG(request_info).request_uri : "";
  676: 		php_self_len = strlen(php_self);
  677: 		if (sapi_module.input_filter(PARSE_SERVER, "PHP_SELF", &php_self, php_self_len, &php_self_len TSRMLS_CC)) {
  678: 			php_register_variable_safe("PHP_SELF", php_self, php_self_len, track_vars_array TSRMLS_CC);
  679: 		}
  680: 	}
  681: }
  682: 
  683: static void sapi_cgi_log_message(char *message)
  684: {
  685: 	TSRMLS_FETCH();
  686: 
  687: 	if (fcgi_is_fastcgi() && CGIG(fcgi_logging)) {
  688: 		fcgi_request *request;
  689: 
  690: 		request = (fcgi_request*) SG(server_context);
  691: 		if (request) {
  692: 			int len = strlen(message);
  693: 			char *buf = malloc(len+2);
  694: 
  695: 			memcpy(buf, message, len);
  696: 			memcpy(buf + len, "\n", sizeof("\n"));
  697: 			fcgi_write(request, FCGI_STDERR, buf, len+1);
  698: 			free(buf);
  699: 		} else {
  700: 			fprintf(stderr, "%s\n", message);
  701: 		}
  702: 		/* ignore return code */
  703: 	} else {
  704: 		fprintf(stderr, "%s\n", message);
  705: 	}
  706: }
  707: 
  708: /* {{{ php_cgi_ini_activate_user_config
  709:  */
  710: static void php_cgi_ini_activate_user_config(char *path, int path_len, const char *doc_root, int doc_root_len, int start TSRMLS_DC)
  711: {
  712: 	char *ptr;
  713: 	user_config_cache_entry *new_entry, *entry;
  714: 	time_t request_time = sapi_get_request_time(TSRMLS_C);
  715: 
  716: 	/* Find cached config entry: If not found, create one */
  717: 	if (zend_hash_find(&CGIG(user_config_cache), path, path_len + 1, (void **) &entry) == FAILURE) {
  718: 		new_entry = pemalloc(sizeof(user_config_cache_entry), 1);
  719: 		new_entry->expires = 0;
  720: 		new_entry->user_config = (HashTable *) pemalloc(sizeof(HashTable), 1);
  721: 		zend_hash_init(new_entry->user_config, 0, NULL, (dtor_func_t) config_zval_dtor, 1);
  722: 		zend_hash_update(&CGIG(user_config_cache), path, path_len + 1, new_entry, sizeof(user_config_cache_entry), (void **) &entry);
  723: 		free(new_entry);
  724: 	}
  725: 
  726: 	/* Check whether cache entry has expired and rescan if it is */
  727: 	if (request_time > entry->expires) {
  728: 		char *real_path = NULL;
  729: 		int real_path_len;
  730: 		char *s1, *s2;
  731: 		int s_len;
  732: 
  733: 		/* Clear the expired config */
  734: 		zend_hash_clean(entry->user_config);
  735: 
  736: 		if (!IS_ABSOLUTE_PATH(path, path_len)) {
  737: 			real_path = tsrm_realpath(path, NULL TSRMLS_CC);
  738: 			/* see #51688, looks like we may get invalid path as doc root using cgi with apache */
  739: 			if (real_path == NULL) {
  740: 				return;
  741: 			}
  742: 			real_path_len = strlen(real_path);
  743: 			path = real_path;
  744: 			path_len = real_path_len;
  745: 		}
  746: 
  747: 		if (path_len > doc_root_len) {
  748: 			s1 = (char *) doc_root;
  749: 			s2 = path;
  750: 			s_len = doc_root_len;
  751: 		} else {
  752: 			s1 = path;
  753: 			s2 = (char *) doc_root;
  754: 			s_len = path_len;
  755: 		}
  756: 
  757: 		/* we have to test if path is part of DOCUMENT_ROOT.
  758: 		  if it is inside the docroot, we scan the tree up to the docroot 
  759: 			to find more user.ini, if not we only scan the current path.
  760: 		  */
  761: #ifdef PHP_WIN32
  762: 		if (strnicmp(s1, s2, s_len) == 0) {
  763: #else 
  764: 		if (strncmp(s1, s2, s_len) == 0) {
  765: #endif
  766: 			ptr = s2 + start;  /* start is the point where doc_root ends! */
  767: 			while ((ptr = strchr(ptr, DEFAULT_SLASH)) != NULL) {
  768: 				*ptr = 0;
  769: 				php_parse_user_ini_file(path, PG(user_ini_filename), entry->user_config TSRMLS_CC);
  770: 				*ptr = '/';
  771: 				ptr++;
  772: 			}
  773: 		} else {
  774: 			php_parse_user_ini_file(path, PG(user_ini_filename), entry->user_config TSRMLS_CC);
  775: 		}
  776: 
  777: 		if (real_path) {
  778: 			free(real_path);
  779: 		}
  780: 		entry->expires = request_time + PG(user_ini_cache_ttl);
  781: 	}
  782: 
  783: 	/* Activate ini entries with values from the user config hash */
  784: 	php_ini_activate_config(entry->user_config, PHP_INI_PERDIR, PHP_INI_STAGE_HTACCESS TSRMLS_CC);
  785: }
  786: /* }}} */
  787: 
  788: static int sapi_cgi_activate(TSRMLS_D)
  789: {
  790: 	char *path, *doc_root, *server_name;
  791: 	uint path_len, doc_root_len, server_name_len;
  792: 
  793: 	/* PATH_TRANSLATED should be defined at this stage but better safe than sorry :) */
  794: 	if (!SG(request_info).path_translated) {
  795: 		return FAILURE;
  796: 	}
  797: 
  798: 	if (php_ini_has_per_host_config()) {
  799: 		/* Activate per-host-system-configuration defined in php.ini and stored into configuration_hash during startup */
  800: 		server_name = sapi_cgibin_getenv("SERVER_NAME", sizeof("SERVER_NAME") - 1 TSRMLS_CC);
  801: 		/* SERVER_NAME should also be defined at this stage..but better check it anyway */
  802: 		if (server_name) {
  803: 			server_name_len = strlen(server_name);
  804: 			server_name = estrndup(server_name, server_name_len);
  805: 			zend_str_tolower(server_name, server_name_len);
  806: 			php_ini_activate_per_host_config(server_name, server_name_len + 1 TSRMLS_CC);
  807: 			efree(server_name);
  808: 		}
  809: 	}
  810: 
  811: 	if (php_ini_has_per_dir_config() ||
  812: 		(PG(user_ini_filename) && *PG(user_ini_filename))
  813: 	) {
  814: 		/* Prepare search path */
  815: 		path_len = strlen(SG(request_info).path_translated);
  816: 
  817: 		/* Make sure we have trailing slash! */
  818: 		if (!IS_SLASH(SG(request_info).path_translated[path_len])) {
  819: 			path = emalloc(path_len + 2);
  820: 			memcpy(path, SG(request_info).path_translated, path_len + 1);
  821: 			path_len = zend_dirname(path, path_len);
  822: 			path[path_len++] = DEFAULT_SLASH;
  823: 		} else {
  824: 			path = estrndup(SG(request_info).path_translated, path_len);
  825: 			path_len = zend_dirname(path, path_len);
  826: 		}
  827: 		path[path_len] = 0;
  828: 
  829: 		/* Activate per-dir-system-configuration defined in php.ini and stored into configuration_hash during startup */
  830: 		php_ini_activate_per_dir_config(path, path_len TSRMLS_CC); /* Note: for global settings sake we check from root to path */
  831: 
  832: 		/* Load and activate user ini files in path starting from DOCUMENT_ROOT */
  833: 		if (PG(user_ini_filename) && *PG(user_ini_filename)) {
  834: 			doc_root = sapi_cgibin_getenv("DOCUMENT_ROOT", sizeof("DOCUMENT_ROOT") - 1 TSRMLS_CC);
  835: 			/* DOCUMENT_ROOT should also be defined at this stage..but better check it anyway */
  836: 			if (doc_root) {
  837: 				doc_root_len = strlen(doc_root);
  838: 				if (doc_root_len > 0 && IS_SLASH(doc_root[doc_root_len - 1])) {
  839: 					--doc_root_len;
  840: 				}
  841: #ifdef PHP_WIN32
  842: 				/* paths on windows should be case-insensitive */
  843: 				doc_root = estrndup(doc_root, doc_root_len);
  844: 				zend_str_tolower(doc_root, doc_root_len);
  845: #endif
  846: 				php_cgi_ini_activate_user_config(path, path_len, doc_root, doc_root_len, doc_root_len - 1 TSRMLS_CC);
  847: 			}
  848: 		}
  849: 
  850: #ifdef PHP_WIN32
  851: 		efree(doc_root);
  852: #endif
  853: 		efree(path);
  854: 	}
  855: 
  856: 	return SUCCESS;
  857: }
  858: 
  859: static int sapi_cgi_deactivate(TSRMLS_D)
  860: {
  861: 	/* flush only when SAPI was started. The reasons are:
  862: 		1. SAPI Deactivate is called from two places: module init and request shutdown
  863: 		2. When the first call occurs and the request is not set up, flush fails on FastCGI.
  864: 	*/
  865: 	if (SG(sapi_started)) {
  866: 		if (fcgi_is_fastcgi()) {
  867: 			if (
  868: #ifndef PHP_WIN32
  869: 				!parent &&
  870: #endif
  871: 				!fcgi_finish_request((fcgi_request*)SG(server_context), 0)) {
  872: 				php_handle_aborted_connection();
  873: 			}
  874: 		} else {
  875: 			sapi_cgibin_flush(SG(server_context));
  876: 		}
  877: 	}
  878: 	return SUCCESS;
  879: }
  880: 
  881: static int php_cgi_startup(sapi_module_struct *sapi_module)
  882: {
  883: 	if (php_module_startup(sapi_module, &cgi_module_entry, 1) == FAILURE) {
  884: 		return FAILURE;
  885: 	}
  886: 	return SUCCESS;
  887: }
  888: 
  889: /* {{{ sapi_module_struct cgi_sapi_module
  890:  */
  891: static sapi_module_struct cgi_sapi_module = {
  892: 	"cgi-fcgi",						/* name */
  893: 	"CGI/FastCGI",					/* pretty name */
  894: 
  895: 	php_cgi_startup,				/* startup */
  896: 	php_module_shutdown_wrapper,	/* shutdown */
  897: 
  898: 	sapi_cgi_activate,				/* activate */
  899: 	sapi_cgi_deactivate,			/* deactivate */
  900: 
  901: 	sapi_cgibin_ub_write,			/* unbuffered write */
  902: 	sapi_cgibin_flush,				/* flush */
  903: 	NULL,							/* get uid */
  904: 	sapi_cgibin_getenv,				/* getenv */
  905: 
  906: 	php_error,						/* error handler */
  907: 
  908: 	NULL,							/* header handler */
  909: 	sapi_cgi_send_headers,			/* send headers handler */
  910: 	NULL,							/* send header handler */
  911: 
  912: 	sapi_cgi_read_post,				/* read POST data */
  913: 	sapi_cgi_read_cookies,			/* read Cookies */
  914: 
  915: 	sapi_cgi_register_variables,	/* register server variables */
  916: 	sapi_cgi_log_message,			/* Log message */
  917: 	NULL,							/* Get request time */
  918: 	NULL,							/* Child terminate */
  919: 
  920: 	STANDARD_SAPI_MODULE_PROPERTIES
  921: };
  922: /* }}} */
  923: 
  924: /* {{{ arginfo ext/standard/dl.c */
  925: ZEND_BEGIN_ARG_INFO(arginfo_dl, 0)
  926: 	ZEND_ARG_INFO(0, extension_filename)
  927: ZEND_END_ARG_INFO()
  928: /* }}} */
  929: 
  930: static const zend_function_entry additional_functions[] = {
  931: 	ZEND_FE(dl, arginfo_dl)
  932: 	{NULL, NULL, NULL}
  933: };
  934: 
  935: /* {{{ php_cgi_usage
  936:  */
  937: static void php_cgi_usage(char *argv0)
  938: {
  939: 	char *prog;
  940: 
  941: 	prog = strrchr(argv0, '/');
  942: 	if (prog) {
  943: 		prog++;
  944: 	} else {
  945: 		prog = "php";
  946: 	}
  947: 
  948: 	php_printf(	"Usage: %s [-q] [-h] [-s] [-v] [-i] [-f <file>]\n"
  949: 				"       %s <file> [args...]\n"
  950: 				"  -a               Run interactively\n"
  951: 				"  -b <address:port>|<port> Bind Path for external FASTCGI Server mode\n"
  952: 				"  -C               Do not chdir to the script's directory\n"
  953: 				"  -c <path>|<file> Look for php.ini file in this directory\n"
  954: 				"  -n               No php.ini file will be used\n"
  955: 				"  -d foo[=bar]     Define INI entry foo with value 'bar'\n"
  956: 				"  -e               Generate extended information for debugger/profiler\n"
  957: 				"  -f <file>        Parse <file>.  Implies `-q'\n"
  958: 				"  -h               This help\n"
  959: 				"  -i               PHP information\n"
  960: 				"  -l               Syntax check only (lint)\n"
  961: 				"  -m               Show compiled in modules\n"
  962: 				"  -q               Quiet-mode.  Suppress HTTP Header output.\n"
  963: 				"  -s               Display colour syntax highlighted source.\n"
  964: 				"  -v               Version number\n"
  965: 				"  -w               Display source with stripped comments and whitespace.\n"
  966: 				"  -z <file>        Load Zend extension <file>.\n"
  967: 				"  -T <count>       Measure execution time of script repeated <count> times.\n",
  968: 				prog, prog);
  969: }
  970: /* }}} */
  971: 
  972: /* {{{ is_valid_path
  973:  *
  974:  * some server configurations allow '..' to slip through in the
  975:  * translated path.   We'll just refuse to handle such a path.
  976:  */
  977: static int is_valid_path(const char *path)
  978: {
  979: 	const char *p;
  980: 
  981: 	if (!path) {
  982: 		return 0;
  983: 	}
  984: 	p = strstr(path, "..");
  985: 	if (p) {
  986: 		if ((p == path || IS_SLASH(*(p-1))) &&
  987: 			(*(p+2) == 0 || IS_SLASH(*(p+2)))
  988: 		) {
  989: 			return 0;
  990: 		}
  991: 		while (1) {
  992: 			p = strstr(p+1, "..");
  993: 			if (!p) {
  994: 				break;
  995: 			}
  996: 			if (IS_SLASH(*(p-1)) &&
  997: 				(*(p+2) == 0 || IS_SLASH(*(p+2)))
  998: 			) {
  999: 					return 0;
 1000: 			}
 1001: 		}
 1002: 	}
 1003: 	return 1;
 1004: }
 1005: /* }}} */
 1006: 
 1007: /* {{{ init_request_info
 1008: 
 1009:   initializes request_info structure
 1010: 
 1011:   specificly in this section we handle proper translations
 1012:   for:
 1013: 
 1014:   PATH_INFO
 1015: 	derived from the portion of the URI path following
 1016: 	the script name but preceding any query data
 1017: 	may be empty
 1018: 
 1019:   PATH_TRANSLATED
 1020:     derived by taking any path-info component of the
 1021: 	request URI and performing any virtual-to-physical
 1022: 	translation appropriate to map it onto the server's
 1023: 	document repository structure
 1024: 
 1025: 	empty if PATH_INFO is empty
 1026: 
 1027: 	The env var PATH_TRANSLATED **IS DIFFERENT** than the
 1028: 	request_info.path_translated variable, the latter should
 1029: 	match SCRIPT_FILENAME instead.
 1030: 
 1031:   SCRIPT_NAME
 1032:     set to a URL path that could identify the CGI script
 1033: 	rather than the interpreter.  PHP_SELF is set to this
 1034: 
 1035:   REQUEST_URI
 1036:     uri section following the domain:port part of a URI
 1037: 
 1038:   SCRIPT_FILENAME
 1039:     The virtual-to-physical translation of SCRIPT_NAME (as per
 1040: 	PATH_TRANSLATED)
 1041: 
 1042:   These settings are documented at
 1043:   http://cgi-spec.golux.com/
 1044: 
 1045: 
 1046:   Based on the following URL request:
 1047: 
 1048:   http://localhost/info.php/test?a=b
 1049: 
 1050:   should produce, which btw is the same as if
 1051:   we were running under mod_cgi on apache (ie. not
 1052:   using ScriptAlias directives):
 1053: 
 1054:   PATH_INFO=/test
 1055:   PATH_TRANSLATED=/docroot/test
 1056:   SCRIPT_NAME=/info.php
 1057:   REQUEST_URI=/info.php/test?a=b
 1058:   SCRIPT_FILENAME=/docroot/info.php
 1059:   QUERY_STRING=a=b
 1060: 
 1061:   but what we get is (cgi/mod_fastcgi under apache):
 1062: 
 1063:   PATH_INFO=/info.php/test
 1064:   PATH_TRANSLATED=/docroot/info.php/test
 1065:   SCRIPT_NAME=/php/php-cgi  (from the Action setting I suppose)
 1066:   REQUEST_URI=/info.php/test?a=b
 1067:   SCRIPT_FILENAME=/path/to/php/bin/php-cgi  (Action setting translated)
 1068:   QUERY_STRING=a=b
 1069: 
 1070:   Comments in the code below refer to using the above URL in a request
 1071: 
 1072:  */
 1073: static void init_request_info(TSRMLS_D)
 1074: {
 1075: 	char *env_script_filename = sapi_cgibin_getenv("SCRIPT_FILENAME", sizeof("SCRIPT_FILENAME")-1 TSRMLS_CC);
 1076: 	char *env_path_translated = sapi_cgibin_getenv("PATH_TRANSLATED", sizeof("PATH_TRANSLATED")-1 TSRMLS_CC);
 1077: 	char *script_path_translated = env_script_filename;
 1078: 
 1079: 	/* some broken servers do not have script_filename or argv0
 1080: 	 * an example, IIS configured in some ways.  then they do more
 1081: 	 * broken stuff and set path_translated to the cgi script location */
 1082: 	if (!script_path_translated && env_path_translated) {
 1083: 		script_path_translated = env_path_translated;
 1084: 	}
 1085: 
 1086: 	/* initialize the defaults */
 1087: 	SG(request_info).path_translated = NULL;
 1088: 	SG(request_info).request_method = NULL;
 1089: 	SG(request_info).proto_num = 1000;
 1090: 	SG(request_info).query_string = NULL;
 1091: 	SG(request_info).request_uri = NULL;
 1092: 	SG(request_info).content_type = NULL;
 1093: 	SG(request_info).content_length = 0;
 1094: 	SG(sapi_headers).http_response_code = 200;
 1095: 
 1096: 	/* script_path_translated being set is a good indication that
 1097: 	 * we are running in a cgi environment, since it is always
 1098: 	 * null otherwise.  otherwise, the filename
 1099: 	 * of the script will be retreived later via argc/argv */
 1100: 	if (script_path_translated) {
 1101: 		const char *auth;
 1102: 		char *content_length = sapi_cgibin_getenv("CONTENT_LENGTH", sizeof("CONTENT_LENGTH")-1 TSRMLS_CC);
 1103: 		char *content_type = sapi_cgibin_getenv("CONTENT_TYPE", sizeof("CONTENT_TYPE")-1 TSRMLS_CC);
 1104: 		char *env_path_info = sapi_cgibin_getenv("PATH_INFO", sizeof("PATH_INFO")-1 TSRMLS_CC);
 1105: 		char *env_script_name = sapi_cgibin_getenv("SCRIPT_NAME", sizeof("SCRIPT_NAME")-1 TSRMLS_CC);
 1106: 
 1107: 		/* Hack for buggy IIS that sets incorrect PATH_INFO */
 1108: 		char *env_server_software = sapi_cgibin_getenv("SERVER_SOFTWARE", sizeof("SERVER_SOFTWARE")-1 TSRMLS_CC);
 1109: 		if (env_server_software &&
 1110: 			env_script_name &&
 1111: 			env_path_info &&
 1112: 			strncmp(env_server_software, "Microsoft-IIS", sizeof("Microsoft-IIS")-1) == 0 &&
 1113: 			strncmp(env_path_info, env_script_name, strlen(env_script_name)) == 0
 1114: 		) {
 1115: 			env_path_info = _sapi_cgibin_putenv("ORIG_PATH_INFO", env_path_info TSRMLS_CC);
 1116: 			env_path_info += strlen(env_script_name);
 1117: 			if (*env_path_info == 0) {
 1118: 				env_path_info = NULL;
 1119: 			}
 1120: 			env_path_info = _sapi_cgibin_putenv("PATH_INFO", env_path_info TSRMLS_CC);
 1121: 		}
 1122: 
 1123: 		if (CGIG(fix_pathinfo)) {
 1124: 			struct stat st;
 1125: 			char *real_path = NULL;
 1126: 			char *env_redirect_url = sapi_cgibin_getenv("REDIRECT_URL", sizeof("REDIRECT_URL")-1 TSRMLS_CC);
 1127: 			char *env_document_root = sapi_cgibin_getenv("DOCUMENT_ROOT", sizeof("DOCUMENT_ROOT")-1 TSRMLS_CC);
 1128: 			char *orig_path_translated = env_path_translated;
 1129: 			char *orig_path_info = env_path_info;
 1130: 			char *orig_script_name = env_script_name;
 1131: 			char *orig_script_filename = env_script_filename;
 1132: 			int script_path_translated_len;
 1133: 
 1134: 			if (!env_document_root && PG(doc_root)) {
 1135: 				env_document_root = _sapi_cgibin_putenv("DOCUMENT_ROOT", PG(doc_root) TSRMLS_CC);
 1136: 				/* fix docroot */
 1137: 				TRANSLATE_SLASHES(env_document_root);
 1138: 			}
 1139: 
 1140: 			if (env_path_translated != NULL && env_redirect_url != NULL &&
 1141:  			    env_path_translated != script_path_translated &&
 1142:  			    strcmp(env_path_translated, script_path_translated) != 0) {
 1143: 				/*
 1144: 				 * pretty much apache specific.  If we have a redirect_url
 1145: 				 * then our script_filename and script_name point to the
 1146: 				 * php executable
 1147: 				 */
 1148: 				script_path_translated = env_path_translated;
 1149: 				/* we correct SCRIPT_NAME now in case we don't have PATH_INFO */
 1150: 				env_script_name = env_redirect_url;
 1151: 			}
 1152: 
 1153: #ifdef __riscos__
 1154: 			/* Convert path to unix format*/
 1155: 			__riscosify_control |= __RISCOSIFY_DONT_CHECK_DIR;
 1156: 			script_path_translated = __unixify(script_path_translated, 0, NULL, 1, 0);
 1157: #endif
 1158: 
 1159: 			/*
 1160: 			 * if the file doesn't exist, try to extract PATH_INFO out
 1161: 			 * of it by stat'ing back through the '/'
 1162: 			 * this fixes url's like /info.php/test
 1163: 			 */
 1164: 			if (script_path_translated &&
 1165: 				(script_path_translated_len = strlen(script_path_translated)) > 0 &&
 1166: 				(script_path_translated[script_path_translated_len-1] == '/' ||
 1167: #ifdef PHP_WIN32
 1168: 				script_path_translated[script_path_translated_len-1] == '\\' ||
 1169: #endif
 1170: 				(real_path = tsrm_realpath(script_path_translated, NULL TSRMLS_CC)) == NULL)
 1171: 			) {
 1172: 				char *pt = estrndup(script_path_translated, script_path_translated_len);
 1173: 				int len = script_path_translated_len;
 1174: 				char *ptr;
 1175: 
 1176: 				while ((ptr = strrchr(pt, '/')) || (ptr = strrchr(pt, '\\'))) {
 1177: 					*ptr = 0;
 1178: 					if (stat(pt, &st) == 0 && S_ISREG(st.st_mode)) {
 1179: 						/*
 1180: 						 * okay, we found the base script!
 1181: 						 * work out how many chars we had to strip off;
 1182: 						 * then we can modify PATH_INFO
 1183: 						 * accordingly
 1184: 						 *
 1185: 						 * we now have the makings of
 1186: 						 * PATH_INFO=/test
 1187: 						 * SCRIPT_FILENAME=/docroot/info.php
 1188: 						 *
 1189: 						 * we now need to figure out what docroot is.
 1190: 						 * if DOCUMENT_ROOT is set, this is easy, otherwise,
 1191: 						 * we have to play the game of hide and seek to figure
 1192: 						 * out what SCRIPT_NAME should be
 1193: 						 */
 1194: 						int slen = len - strlen(pt);
 1195: 						int pilen = env_path_info ? strlen(env_path_info) : 0;
 1196: 						char *path_info = env_path_info ? env_path_info + pilen - slen : NULL;
 1197: 
 1198: 						if (orig_path_info != path_info) {
 1199: 							if (orig_path_info) {
 1200: 								char old;
 1201: 
 1202: 								_sapi_cgibin_putenv("ORIG_PATH_INFO", orig_path_info TSRMLS_CC);
 1203: 								old = path_info[0];
 1204: 								path_info[0] = 0;
 1205: 								if (!orig_script_name ||
 1206: 									strcmp(orig_script_name, env_path_info) != 0) {
 1207: 									if (orig_script_name) {
 1208: 										_sapi_cgibin_putenv("ORIG_SCRIPT_NAME", orig_script_name TSRMLS_CC);
 1209: 									}
 1210: 									SG(request_info).request_uri = _sapi_cgibin_putenv("SCRIPT_NAME", env_path_info TSRMLS_CC);
 1211: 								} else {
 1212: 									SG(request_info).request_uri = orig_script_name;
 1213: 								}
 1214: 								path_info[0] = old;
 1215: 							}
 1216: 							env_path_info = _sapi_cgibin_putenv("PATH_INFO", path_info TSRMLS_CC);
 1217: 						}
 1218: 						if (!orig_script_filename ||
 1219: 							strcmp(orig_script_filename, pt) != 0) {
 1220: 							if (orig_script_filename) {
 1221: 								_sapi_cgibin_putenv("ORIG_SCRIPT_FILENAME", orig_script_filename TSRMLS_CC);
 1222: 							}
 1223: 							script_path_translated = _sapi_cgibin_putenv("SCRIPT_FILENAME", pt TSRMLS_CC);
 1224: 						}
 1225: 						TRANSLATE_SLASHES(pt);
 1226: 
 1227: 						/* figure out docroot
 1228: 						 * SCRIPT_FILENAME minus SCRIPT_NAME
 1229: 						 */
 1230: 						if (env_document_root) {
 1231: 							int l = strlen(env_document_root);
 1232: 							int path_translated_len = 0;
 1233: 							char *path_translated = NULL;
 1234: 
 1235: 							if (l && env_document_root[l - 1] == '/') {
 1236: 								--l;
 1237: 							}
 1238: 
 1239: 							/* we have docroot, so we should have:
 1240: 							 * DOCUMENT_ROOT=/docroot
 1241: 							 * SCRIPT_FILENAME=/docroot/info.php
 1242: 							 */
 1243: 
 1244: 							/* PATH_TRANSLATED = DOCUMENT_ROOT + PATH_INFO */
 1245: 							path_translated_len = l + (env_path_info ? strlen(env_path_info) : 0);
 1246: 							path_translated = (char *) emalloc(path_translated_len + 1);
 1247: 							memcpy(path_translated, env_document_root, l);
 1248: 							if (env_path_info) {
 1249: 								memcpy(path_translated + l, env_path_info, (path_translated_len - l));
 1250: 							}
 1251: 							path_translated[path_translated_len] = '\0';
 1252: 							if (orig_path_translated) {
 1253: 								_sapi_cgibin_putenv("ORIG_PATH_TRANSLATED", orig_path_translated TSRMLS_CC);
 1254: 							}
 1255: 							env_path_translated = _sapi_cgibin_putenv("PATH_TRANSLATED", path_translated TSRMLS_CC);
 1256: 							efree(path_translated);
 1257: 						} else if (	env_script_name &&
 1258: 									strstr(pt, env_script_name)
 1259: 						) {
 1260: 							/* PATH_TRANSLATED = PATH_TRANSLATED - SCRIPT_NAME + PATH_INFO */
 1261: 							int ptlen = strlen(pt) - strlen(env_script_name);
 1262: 							int path_translated_len = ptlen + (env_path_info ? strlen(env_path_info) : 0);
 1263: 							char *path_translated = NULL;
 1264: 
 1265: 							path_translated = (char *) emalloc(path_translated_len + 1);
 1266: 							memcpy(path_translated, pt, ptlen);
 1267: 							if (env_path_info) {
 1268: 								memcpy(path_translated + ptlen, env_path_info, path_translated_len - ptlen);
 1269: 							}
 1270: 							path_translated[path_translated_len] = '\0';
 1271: 							if (orig_path_translated) {
 1272: 								_sapi_cgibin_putenv("ORIG_PATH_TRANSLATED", orig_path_translated TSRMLS_CC);
 1273: 							}
 1274: 							env_path_translated = _sapi_cgibin_putenv("PATH_TRANSLATED", path_translated TSRMLS_CC);
 1275: 							efree(path_translated);
 1276: 						}
 1277: 						break;
 1278: 					}
 1279: 				}
 1280: 				if (!ptr) {
 1281: 					/*
 1282: 					 * if we stripped out all the '/' and still didn't find
 1283: 					 * a valid path... we will fail, badly. of course we would
 1284: 					 * have failed anyway... we output 'no input file' now.
 1285: 					 */
 1286: 					if (orig_script_filename) {
 1287: 						_sapi_cgibin_putenv("ORIG_SCRIPT_FILENAME", orig_script_filename TSRMLS_CC);
 1288: 					}
 1289: 					script_path_translated = _sapi_cgibin_putenv("SCRIPT_FILENAME", NULL TSRMLS_CC);
 1290: 					SG(sapi_headers).http_response_code = 404;
 1291: 				}
 1292: 				if (!SG(request_info).request_uri) {
 1293: 					if (!orig_script_name ||
 1294: 						strcmp(orig_script_name, env_script_name) != 0) {
 1295: 						if (orig_script_name) {
 1296: 							_sapi_cgibin_putenv("ORIG_SCRIPT_NAME", orig_script_name TSRMLS_CC);
 1297: 						}
 1298: 						SG(request_info).request_uri = _sapi_cgibin_putenv("SCRIPT_NAME", env_script_name TSRMLS_CC);
 1299: 					} else {
 1300: 						SG(request_info).request_uri = orig_script_name;
 1301: 					}
 1302: 				}
 1303: 				if (pt) {
 1304: 					efree(pt);
 1305: 				}
 1306: 			} else {
 1307: 				/* make sure path_info/translated are empty */
 1308: 				if (!orig_script_filename ||
 1309: 					(script_path_translated != orig_script_filename &&
 1310: 					strcmp(script_path_translated, orig_script_filename) != 0)) {
 1311: 					if (orig_script_filename) {
 1312: 						_sapi_cgibin_putenv("ORIG_SCRIPT_FILENAME", orig_script_filename TSRMLS_CC);
 1313: 					}
 1314: 					script_path_translated = _sapi_cgibin_putenv("SCRIPT_FILENAME", script_path_translated TSRMLS_CC);
 1315: 				}
 1316: 				if (env_redirect_url) {
 1317: 					if (orig_path_info) {
 1318: 						_sapi_cgibin_putenv("ORIG_PATH_INFO", orig_path_info TSRMLS_CC);
 1319: 						_sapi_cgibin_putenv("PATH_INFO", NULL TSRMLS_CC);
 1320: 					}
 1321: 					if (orig_path_translated) {
 1322: 						_sapi_cgibin_putenv("ORIG_PATH_TRANSLATED", orig_path_translated TSRMLS_CC);
 1323: 						_sapi_cgibin_putenv("PATH_TRANSLATED", NULL TSRMLS_CC);
 1324: 					}
 1325: 				}
 1326: 				if (env_script_name != orig_script_name) {
 1327: 					if (orig_script_name) {
 1328: 						_sapi_cgibin_putenv("ORIG_SCRIPT_NAME", orig_script_name TSRMLS_CC);
 1329: 					}
 1330: 					SG(request_info).request_uri = _sapi_cgibin_putenv("SCRIPT_NAME", env_script_name TSRMLS_CC);
 1331: 				} else {
 1332: 					SG(request_info).request_uri = env_script_name;
 1333: 				}
 1334: 				free(real_path);
 1335: 			}
 1336: 		} else {
 1337: 			/* pre 4.3 behaviour, shouldn't be used but provides BC */
 1338: 			if (env_path_info) {
 1339: 				SG(request_info).request_uri = env_path_info;
 1340: 			} else {
 1341: 				SG(request_info).request_uri = env_script_name;
 1342: 			}
 1343: 			if (!CGIG(discard_path) && env_path_translated) {
 1344: 				script_path_translated = env_path_translated;
 1345: 			}
 1346: 		}
 1347: 
 1348: 		if (is_valid_path(script_path_translated)) {
 1349: 			SG(request_info).path_translated = estrdup(script_path_translated);
 1350: 		}
 1351: 
 1352: 		SG(request_info).request_method = sapi_cgibin_getenv("REQUEST_METHOD", sizeof("REQUEST_METHOD")-1 TSRMLS_CC);
 1353: 		/* FIXME - Work out proto_num here */
 1354: 		SG(request_info).query_string = sapi_cgibin_getenv("QUERY_STRING", sizeof("QUERY_STRING")-1 TSRMLS_CC);
 1355: 		SG(request_info).content_type = (content_type ? content_type : "" );
 1356: 		SG(request_info).content_length = (content_length ? atol(content_length) : 0);
 1357: 
 1358: 		/* The CGI RFC allows servers to pass on unvalidated Authorization data */
 1359: 		auth = sapi_cgibin_getenv("HTTP_AUTHORIZATION", sizeof("HTTP_AUTHORIZATION")-1 TSRMLS_CC);
 1360: 		php_handle_auth_data(auth TSRMLS_CC);
 1361: 	}
 1362: }
 1363: /* }}} */
 1364: 
 1365: #ifndef PHP_WIN32
 1366: /**
 1367:  * Clean up child processes upon exit
 1368:  */
 1369: void fastcgi_cleanup(int signal)
 1370: {
 1371: #ifdef DEBUG_FASTCGI
 1372: 	fprintf(stderr, "FastCGI shutdown, pid %d\n", getpid());
 1373: #endif
 1374: 
 1375: 	sigaction(SIGTERM, &old_term, 0);
 1376: 
 1377: 	/* Kill all the processes in our process group */
 1378: 	kill(-pgroup, SIGTERM);
 1379: 
 1380: 	if (parent && parent_waiting) {
 1381: 		exit_signal = 1;
 1382: 	} else {
 1383: 		exit(0);
 1384: 	}
 1385: }
 1386: #endif
 1387: 
 1388: PHP_INI_BEGIN()
 1389: 	STD_PHP_INI_ENTRY("cgi.rfc2616_headers",     "0",  PHP_INI_ALL,    OnUpdateBool,   rfc2616_headers, php_cgi_globals_struct, php_cgi_globals)
 1390: 	STD_PHP_INI_ENTRY("cgi.nph",                 "0",  PHP_INI_ALL,    OnUpdateBool,   nph, php_cgi_globals_struct, php_cgi_globals)
 1391: 	STD_PHP_INI_ENTRY("cgi.check_shebang_line",  "1",  PHP_INI_SYSTEM, OnUpdateBool,   check_shebang_line, php_cgi_globals_struct, php_cgi_globals)
 1392: 	STD_PHP_INI_ENTRY("cgi.force_redirect",      "1",  PHP_INI_SYSTEM, OnUpdateBool,   force_redirect, php_cgi_globals_struct, php_cgi_globals)
 1393: 	STD_PHP_INI_ENTRY("cgi.redirect_status_env", NULL, PHP_INI_SYSTEM, OnUpdateString, redirect_status_env, php_cgi_globals_struct, php_cgi_globals)
 1394: 	STD_PHP_INI_ENTRY("cgi.fix_pathinfo",        "1",  PHP_INI_SYSTEM, OnUpdateBool,   fix_pathinfo, php_cgi_globals_struct, php_cgi_globals)
 1395: 	STD_PHP_INI_ENTRY("cgi.discard_path",        "0",  PHP_INI_SYSTEM, OnUpdateBool,   discard_path, php_cgi_globals_struct, php_cgi_globals)
 1396: 	STD_PHP_INI_ENTRY("fastcgi.logging",         "1",  PHP_INI_SYSTEM, OnUpdateBool,   fcgi_logging, php_cgi_globals_struct, php_cgi_globals)
 1397: #ifdef PHP_WIN32
 1398: 	STD_PHP_INI_ENTRY("fastcgi.impersonate",     "0",  PHP_INI_SYSTEM, OnUpdateBool,   impersonate, php_cgi_globals_struct, php_cgi_globals)
 1399: #endif
 1400: PHP_INI_END()
 1401: 
 1402: /* {{{ php_cgi_globals_ctor
 1403:  */
 1404: static void php_cgi_globals_ctor(php_cgi_globals_struct *php_cgi_globals TSRMLS_DC)
 1405: {
 1406: 	php_cgi_globals->rfc2616_headers = 0;
 1407: 	php_cgi_globals->nph = 0;
 1408: 	php_cgi_globals->check_shebang_line = 1;
 1409: 	php_cgi_globals->force_redirect = 1;
 1410: 	php_cgi_globals->redirect_status_env = NULL;
 1411: 	php_cgi_globals->fix_pathinfo = 1;
 1412: 	php_cgi_globals->discard_path = 0;
 1413: 	php_cgi_globals->fcgi_logging = 1;
 1414: #ifdef PHP_WIN32
 1415: 	php_cgi_globals->impersonate = 0;
 1416: #endif
 1417: 	zend_hash_init(&php_cgi_globals->user_config_cache, 0, NULL, (dtor_func_t) user_config_cache_entry_dtor, 1);
 1418: }
 1419: /* }}} */
 1420: 
 1421: /* {{{ PHP_MINIT_FUNCTION
 1422:  */
 1423: static PHP_MINIT_FUNCTION(cgi)
 1424: {
 1425: #ifdef ZTS
 1426: 	ts_allocate_id(&php_cgi_globals_id, sizeof(php_cgi_globals_struct), (ts_allocate_ctor) php_cgi_globals_ctor, NULL);
 1427: #else
 1428: 	php_cgi_globals_ctor(&php_cgi_globals TSRMLS_CC);
 1429: #endif
 1430: 	REGISTER_INI_ENTRIES();
 1431: 	return SUCCESS;
 1432: }
 1433: /* }}} */
 1434: 
 1435: /* {{{ PHP_MSHUTDOWN_FUNCTION
 1436:  */
 1437: static PHP_MSHUTDOWN_FUNCTION(cgi)
 1438: {
 1439: 	zend_hash_destroy(&CGIG(user_config_cache));
 1440: 
 1441: 	UNREGISTER_INI_ENTRIES();
 1442: 	return SUCCESS;
 1443: }
 1444: /* }}} */
 1445: 
 1446: /* {{{ PHP_MINFO_FUNCTION
 1447:  */
 1448: static PHP_MINFO_FUNCTION(cgi)
 1449: {
 1450: 	DISPLAY_INI_ENTRIES();
 1451: }
 1452: /* }}} */
 1453: 
 1454: static zend_module_entry cgi_module_entry = {
 1455: 	STANDARD_MODULE_HEADER,
 1456: 	"cgi-fcgi",
 1457: 	NULL,
 1458: 	PHP_MINIT(cgi),
 1459: 	PHP_MSHUTDOWN(cgi),
 1460: 	NULL,
 1461: 	NULL,
 1462: 	PHP_MINFO(cgi),
 1463: 	NO_VERSION_YET,
 1464: 	STANDARD_MODULE_PROPERTIES
 1465: };
 1466: 
 1467: /* {{{ main
 1468:  */
 1469: int main(int argc, char *argv[])
 1470: {
 1471: 	int free_query_string = 0;
 1472: 	int exit_status = SUCCESS;
 1473: 	int cgi = 0, c, i, len;
 1474: 	zend_file_handle file_handle;
 1475: 	char *s;
 1476: 
 1477: 	/* temporary locals */
 1478: 	int behavior = PHP_MODE_STANDARD;
 1479: 	int no_headers = 0;
 1480: 	int orig_optind = php_optind;
 1481: 	char *orig_optarg = php_optarg;
 1482: 	char *script_file = NULL;
 1483: 	int ini_entries_len = 0;
 1484: 	/* end of temporary locals */
 1485: 
 1486: #ifdef ZTS
 1487: 	void ***tsrm_ls;
 1488: #endif
 1489: 
 1490: 	int max_requests = 500;
 1491: 	int requests = 0;
 1492: 	int fastcgi = fcgi_is_fastcgi();
 1493: 	char *bindpath = NULL;
 1494: 	int fcgi_fd = 0;
 1495: 	fcgi_request request;
 1496: 	int repeats = 1;
 1497: 	int benchmark = 0;
 1498: #if HAVE_GETTIMEOFDAY
 1499: 	struct timeval start, end;
 1500: #else
 1501: 	time_t start, end;
 1502: #endif
 1503: #ifndef PHP_WIN32
 1504: 	int status = 0;
 1505: #endif
 1506: 
 1507: #if 0 && defined(PHP_DEBUG)
 1508: 	/* IIS is always making things more difficult.  This allows
 1509: 	 * us to stop PHP and attach a debugger before much gets started */
 1510: 	{
 1511: 		char szMessage [256];
 1512: 		wsprintf (szMessage, "Please attach a debugger to the process 0x%X [%d] (%s) and click OK", GetCurrentProcessId(), GetCurrentProcessId(), argv[0]);
 1513: 		MessageBox(NULL, szMessage, "CGI Debug Time!", MB_OK|MB_SERVICE_NOTIFICATION);
 1514: 	}
 1515: #endif
 1516: 
 1517: #ifdef HAVE_SIGNAL_H
 1518: #if defined(SIGPIPE) && defined(SIG_IGN)
 1519: 	signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE in standalone mode so
 1520: 								that sockets created via fsockopen()
 1521: 								don't kill PHP if the remote site
 1522: 								closes it.  in apache|apxs mode apache
 1523: 								does that for us!  thies@thieso.net
 1524: 								20000419 */
 1525: #endif
 1526: #endif
 1527: 
 1528: #ifdef ZTS
 1529: 	tsrm_startup(1, 1, 0, NULL);
 1530: 	tsrm_ls = ts_resource(0);
 1531: #endif
 1532: 
 1533: 	sapi_startup(&cgi_sapi_module);
 1534: 	cgi_sapi_module.php_ini_path_override = NULL;
 1535: 
 1536: #ifdef PHP_WIN32
 1537: 	_fmode = _O_BINARY; /* sets default for file streams to binary */
 1538: 	setmode(_fileno(stdin),  O_BINARY);	/* make the stdio mode be binary */
 1539: 	setmode(_fileno(stdout), O_BINARY);	/* make the stdio mode be binary */
 1540: 	setmode(_fileno(stderr), O_BINARY);	/* make the stdio mode be binary */
 1541: #endif
 1542: 
 1543: 	if (!fastcgi) {
 1544: 		/* Make sure we detect we are a cgi - a bit redundancy here,
 1545: 		 * but the default case is that we have to check only the first one. */
 1546: 		if (getenv("SERVER_SOFTWARE") ||
 1547: 			getenv("SERVER_NAME") ||
 1548: 			getenv("GATEWAY_INTERFACE") ||
 1549: 			getenv("REQUEST_METHOD")
 1550: 		) {
 1551: 			cgi = 1;
 1552: 		}
 1553: 	}
 1554: 
 1555: 	while ((c = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 0, 2)) != -1) {
 1556: 		switch (c) {
 1557: 			case 'c':
 1558: 				if (cgi_sapi_module.php_ini_path_override) {
 1559: 					free(cgi_sapi_module.php_ini_path_override);
 1560: 				}
 1561: 				cgi_sapi_module.php_ini_path_override = strdup(php_optarg);
 1562: 				break;
 1563: 			case 'n':
 1564: 				cgi_sapi_module.php_ini_ignore = 1;
 1565: 				break;
 1566: 			case 'd': {
 1567: 				/* define ini entries on command line */
 1568: 				int len = strlen(php_optarg);
 1569: 				char *val;
 1570: 
 1571: 				if ((val = strchr(php_optarg, '='))) {
 1572: 					val++;
 1573: 					if (!isalnum(*val) && *val != '"' && *val != '\'' && *val != '\0') {
 1574: 						cgi_sapi_module.ini_entries = realloc(cgi_sapi_module.ini_entries, ini_entries_len + len + sizeof("\"\"\n\0"));
 1575: 						memcpy(cgi_sapi_module.ini_entries + ini_entries_len, php_optarg, (val - php_optarg));
 1576: 						ini_entries_len += (val - php_optarg);
 1577: 						memcpy(cgi_sapi_module.ini_entries + ini_entries_len, "\"", 1);
 1578: 						ini_entries_len++;
 1579: 						memcpy(cgi_sapi_module.ini_entries + ini_entries_len, val, len - (val - php_optarg));
 1580: 						ini_entries_len += len - (val - php_optarg);
 1581: 						memcpy(cgi_sapi_module.ini_entries + ini_entries_len, "\"\n\0", sizeof("\"\n\0"));
 1582: 						ini_entries_len += sizeof("\n\0\"") - 2;
 1583: 					} else {
 1584: 						cgi_sapi_module.ini_entries = realloc(cgi_sapi_module.ini_entries, ini_entries_len + len + sizeof("\n\0"));
 1585: 						memcpy(cgi_sapi_module.ini_entries + ini_entries_len, php_optarg, len);
 1586: 						memcpy(cgi_sapi_module.ini_entries + ini_entries_len + len, "\n\0", sizeof("\n\0"));
 1587: 						ini_entries_len += len + sizeof("\n\0") - 2;
 1588: 					}
 1589: 				} else {
 1590: 					cgi_sapi_module.ini_entries = realloc(cgi_sapi_module.ini_entries, ini_entries_len + len + sizeof("=1\n\0"));
 1591: 					memcpy(cgi_sapi_module.ini_entries + ini_entries_len, php_optarg, len);
 1592: 					memcpy(cgi_sapi_module.ini_entries + ini_entries_len + len, "=1\n\0", sizeof("=1\n\0"));
 1593: 					ini_entries_len += len + sizeof("=1\n\0") - 2;
 1594: 				}
 1595: 				break;
 1596: 			}
 1597: 			/* if we're started on command line, check to see if
 1598: 			 * we are being started as an 'external' fastcgi
 1599: 			 * server by accepting a bindpath parameter. */
 1600: 			case 'b':
 1601: 				if (!fastcgi) {
 1602: 					bindpath = strdup(php_optarg);
 1603: 				}
 1604: 				break;
 1605: 			case 's': /* generate highlighted HTML from source */
 1606: 				behavior = PHP_MODE_HIGHLIGHT;
 1607: 				break;
 1608: 		}
 1609: 	}
 1610: 	php_optind = orig_optind;
 1611: 	php_optarg = orig_optarg;
 1612: 
 1613: #ifdef ZTS
 1614: 	SG(request_info).path_translated = NULL;
 1615: #endif
 1616: 
 1617: 	cgi_sapi_module.executable_location = argv[0];
 1618: 	if (!cgi && !fastcgi && !bindpath) {
 1619: 		cgi_sapi_module.additional_functions = additional_functions;
 1620: 	}
 1621: 
 1622: 	/* startup after we get the above ini override se we get things right */
 1623: 	if (cgi_sapi_module.startup(&cgi_sapi_module) == FAILURE) {
 1624: #ifdef ZTS
 1625: 		tsrm_shutdown();
 1626: #endif
 1627: 		return FAILURE;
 1628: 	}
 1629: 
 1630: 	/* check force_cgi after startup, so we have proper output */
 1631: 	if (cgi && CGIG(force_redirect)) {
 1632: 		/* Apache will generate REDIRECT_STATUS,
 1633: 		 * Netscape and redirect.so will generate HTTP_REDIRECT_STATUS.
 1634: 		 * redirect.so and installation instructions available from
 1635: 		 * http://www.koehntopp.de/php.
 1636: 		 *   -- kk@netuse.de
 1637: 		 */
 1638: 		if (!getenv("REDIRECT_STATUS") &&
 1639: 			!getenv ("HTTP_REDIRECT_STATUS") &&
 1640: 			/* this is to allow a different env var to be configured
 1641: 			 * in case some server does something different than above */
 1642: 			(!CGIG(redirect_status_env) || !getenv(CGIG(redirect_status_env)))
 1643: 		) {
 1644: 			zend_try {
 1645: 				SG(sapi_headers).http_response_code = 400;
 1646: 				PUTS("<b>Security Alert!</b> The PHP CGI cannot be accessed directly.\n\n\
 1647: <p>This PHP CGI binary was compiled with force-cgi-redirect enabled.  This\n\
 1648: means that a page will only be served up if the REDIRECT_STATUS CGI variable is\n\
 1649: set, e.g. via an Apache Action directive.</p>\n\
 1650: <p>For more information as to <i>why</i> this behaviour exists, see the <a href=\"http://php.net/security.cgi-bin\">\
 1651: manual page for CGI security</a>.</p>\n\
 1652: <p>For more information about changing this behaviour or re-enabling this webserver,\n\
 1653: consult the installation file that came with this distribution, or visit \n\
 1654: <a href=\"http://php.net/install.windows\">the manual page</a>.</p>\n");
 1655: 			} zend_catch {
 1656: 			} zend_end_try();
 1657: #if defined(ZTS) && !defined(PHP_DEBUG)
 1658: 			/* XXX we're crashing here in msvc6 debug builds at
 1659: 			 * php_message_handler_for_zend:839 because
 1660: 			 * SG(request_info).path_translated is an invalid pointer.
 1661: 			 * It still happens even though I set it to null, so something
 1662: 			 * weird is going on.
 1663: 			 */
 1664: 			tsrm_shutdown();
 1665: #endif
 1666: 			return FAILURE;
 1667: 		}
 1668: 	}
 1669: 
 1670: 	if (bindpath) {
 1671: 		fcgi_fd = fcgi_listen(bindpath, 128);
 1672: 		if (fcgi_fd < 0) {
 1673: 			fprintf(stderr, "Couldn't create FastCGI listen socket on port %s\n", bindpath);
 1674: #ifdef ZTS
 1675: 			tsrm_shutdown();
 1676: #endif
 1677: 			return FAILURE;
 1678: 		}
 1679: 		fastcgi = fcgi_is_fastcgi();
 1680: 	}
 1681: 	if (fastcgi) {
 1682: 		/* How many times to run PHP scripts before dying */
 1683: 		if (getenv("PHP_FCGI_MAX_REQUESTS")) {
 1684: 			max_requests = atoi(getenv("PHP_FCGI_MAX_REQUESTS"));
 1685: 			if (max_requests < 0) {
 1686: 				fprintf(stderr, "PHP_FCGI_MAX_REQUESTS is not valid\n");
 1687: 				return FAILURE;
 1688: 			}
 1689: 		}
 1690: 
 1691: 		/* make php call us to get _ENV vars */
 1692: 		php_php_import_environment_variables = php_import_environment_variables;
 1693: 		php_import_environment_variables = cgi_php_import_environment_variables;
 1694: 
 1695: 		/* library is already initialized, now init our request */
 1696: 		fcgi_init_request(&request, fcgi_fd);
 1697: 
 1698: #ifndef PHP_WIN32
 1699: 	/* Pre-fork, if required */
 1700: 	if (getenv("PHP_FCGI_CHILDREN")) {
 1701: 		char * children_str = getenv("PHP_FCGI_CHILDREN");
 1702: 		children = atoi(children_str);
 1703: 		if (children < 0) {
 1704: 			fprintf(stderr, "PHP_FCGI_CHILDREN is not valid\n");
 1705: 			return FAILURE;
 1706: 		}
 1707: 		fcgi_set_mgmt_var("FCGI_MAX_CONNS", sizeof("FCGI_MAX_CONNS")-1, children_str, strlen(children_str));
 1708: 		/* This is the number of concurrent requests, equals FCGI_MAX_CONNS */
 1709: 		fcgi_set_mgmt_var("FCGI_MAX_REQS",  sizeof("FCGI_MAX_REQS")-1,  children_str, strlen(children_str));
 1710: 	} else {
 1711: 		fcgi_set_mgmt_var("FCGI_MAX_CONNS", sizeof("FCGI_MAX_CONNS")-1, "1", sizeof("1")-1);
 1712: 		fcgi_set_mgmt_var("FCGI_MAX_REQS",  sizeof("FCGI_MAX_REQS")-1,  "1", sizeof("1")-1);
 1713: 	}
 1714: 
 1715: 	if (children) {
 1716: 		int running = 0;
 1717: 		pid_t pid;
 1718: 
 1719: 		/* Create a process group for ourself & children */
 1720: 		setsid();
 1721: 		pgroup = getpgrp();
 1722: #ifdef DEBUG_FASTCGI
 1723: 		fprintf(stderr, "Process group %d\n", pgroup);
 1724: #endif
 1725: 
 1726: 		/* Set up handler to kill children upon exit */
 1727: 		act.sa_flags = 0;
 1728: 		act.sa_handler = fastcgi_cleanup;
 1729: 		if (sigaction(SIGTERM, &act, &old_term) ||
 1730: 			sigaction(SIGINT,  &act, &old_int)  ||
 1731: 			sigaction(SIGQUIT, &act, &old_quit)
 1732: 		) {
 1733: 			perror("Can't set signals");
 1734: 			exit(1);
 1735: 		}
 1736: 
 1737: 		if (fcgi_in_shutdown()) {
 1738: 			goto parent_out;
 1739: 		}
 1740: 
 1741: 		while (parent) {
 1742: 			do {
 1743: #ifdef DEBUG_FASTCGI
 1744: 				fprintf(stderr, "Forking, %d running\n", running);
 1745: #endif
 1746: 				pid = fork();
 1747: 				switch (pid) {
 1748: 				case 0:
 1749: 					/* One of the children.
 1750: 					 * Make sure we don't go round the
 1751: 					 * fork loop any more
 1752: 					 */
 1753: 					parent = 0;
 1754: 
 1755: 					/* don't catch our signals */
 1756: 					sigaction(SIGTERM, &old_term, 0);
 1757: 					sigaction(SIGQUIT, &old_quit, 0);
 1758: 					sigaction(SIGINT,  &old_int,  0);
 1759: 					break;
 1760: 				case -1:
 1761: 					perror("php (pre-forking)");
 1762: 					exit(1);
 1763: 					break;
 1764: 				default:
 1765: 					/* Fine */
 1766: 					running++;
 1767: 					break;
 1768: 				}
 1769: 			} while (parent && (running < children));
 1770: 
 1771: 			if (parent) {
 1772: #ifdef DEBUG_FASTCGI
 1773: 				fprintf(stderr, "Wait for kids, pid %d\n", getpid());
 1774: #endif
 1775: 				parent_waiting = 1;
 1776: 				while (1) {
 1777: 					if (wait(&status) >= 0) {
 1778: 						running--;
 1779: 						break;
 1780: 					} else if (exit_signal) {
 1781: 						break;
 1782: 					}
 1783: 				}
 1784: 				if (exit_signal) {
 1785: #if 0
 1786: 					while (running > 0) {
 1787: 						while (wait(&status) < 0) {
 1788: 						}
 1789: 						running--;
 1790: 					}
 1791: #endif
 1792: 					goto parent_out;
 1793: 				}
 1794: 			}
 1795: 		}
 1796: 	} else {
 1797: 		parent = 0;
 1798: 	}
 1799: 
 1800: #endif /* WIN32 */
 1801: 	}
 1802: 
 1803: 	zend_first_try {
 1804: 		while ((c = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 1, 2)) != -1) {
 1805: 			switch (c) {
 1806: 				case 'T':
 1807: 					benchmark = 1;
 1808: 					repeats = atoi(php_optarg);
 1809: #ifdef HAVE_GETTIMEOFDAY
 1810: 					gettimeofday(&start, NULL);
 1811: #else
 1812: 					time(&start);
 1813: #endif
 1814: 					break;
 1815: 				case 'h':
 1816: 				case '?':
 1817: 					fcgi_shutdown();
 1818: 					no_headers = 1;
 1819: 					php_output_startup();
 1820: 					php_output_activate(TSRMLS_C);
 1821: 					SG(headers_sent) = 1;
 1822: 					php_cgi_usage(argv[0]);
 1823: 					php_end_ob_buffers(1 TSRMLS_CC);
 1824: 					exit_status = 0;
 1825: 					goto out;
 1826: 			}
 1827: 		}
 1828: 		php_optind = orig_optind;
 1829: 		php_optarg = orig_optarg;
 1830: 
 1831: 		/* start of FAST CGI loop */
 1832: 		/* Initialise FastCGI request structure */
 1833: #ifdef PHP_WIN32
 1834: 		/* attempt to set security impersonation for fastcgi
 1835: 		 * will only happen on NT based OS, others will ignore it. */
 1836: 		if (fastcgi && CGIG(impersonate)) {
 1837: 			fcgi_impersonate();
 1838: 		}
 1839: #endif
 1840: 		while (!fastcgi || fcgi_accept_request(&request) >= 0) {
 1841: 			SG(server_context) = (void *) &request;
 1842: 			init_request_info(TSRMLS_C);
 1843: 			CG(interactive) = 0;
 1844: 
 1845: 			if (!cgi && !fastcgi) {
 1846: 				while ((c = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 0, 2)) != -1) {
 1847: 					switch (c) {
 1848: 
 1849: 						case 'a':	/* interactive mode */
 1850: 							printf("Interactive mode enabled\n\n");
 1851: 							CG(interactive) = 1;
 1852: 							break;
 1853: 
 1854: 						case 'C': /* don't chdir to the script directory */
 1855: 							SG(options) |= SAPI_OPTION_NO_CHDIR;
 1856: 							break;
 1857: 
 1858: 						case 'e': /* enable extended info output */
 1859: 							CG(compiler_options) |= ZEND_COMPILE_EXTENDED_INFO;
 1860: 							break;
 1861: 
 1862: 						case 'f': /* parse file */
 1863: 							if (script_file) {
 1864: 								efree(script_file);
 1865: 							}
 1866: 							script_file = estrdup(php_optarg);
 1867: 							no_headers = 1;
 1868: 							break;
 1869: 
 1870: 						case 'i': /* php info & quit */
 1871: 							if (script_file) {
 1872: 								efree(script_file);
 1873: 							}
 1874: 							if (php_request_startup(TSRMLS_C) == FAILURE) {
 1875: 								SG(server_context) = NULL;
 1876: 								php_module_shutdown(TSRMLS_C);
 1877: 								return FAILURE;
 1878: 							}
 1879: 							if (no_headers) {
 1880: 								SG(headers_sent) = 1;
 1881: 								SG(request_info).no_headers = 1;
 1882: 							}
 1883: 							php_print_info(0xFFFFFFFF TSRMLS_CC);
 1884: 							php_request_shutdown((void *) 0);
 1885: 							fcgi_shutdown();
 1886: 							exit_status = 0;
 1887: 							goto out;
 1888: 
 1889: 						case 'l': /* syntax check mode */
 1890: 							no_headers = 1;
 1891: 							behavior = PHP_MODE_LINT;
 1892: 							break;
 1893: 
 1894: 						case 'm': /* list compiled in modules */
 1895: 							if (script_file) {
 1896: 								efree(script_file);
 1897: 							}
 1898: 							php_output_startup();
 1899: 							php_output_activate(TSRMLS_C);
 1900: 							SG(headers_sent) = 1;
 1901: 							php_printf("[PHP Modules]\n");
 1902: 							print_modules(TSRMLS_C);
 1903: 							php_printf("\n[Zend Modules]\n");
 1904: 							print_extensions(TSRMLS_C);
 1905: 							php_printf("\n");
 1906: 							php_end_ob_buffers(1 TSRMLS_CC);
 1907: 							fcgi_shutdown();
 1908: 							exit_status = 0;
 1909: 							goto out;
 1910: 
 1911: #if 0 /* not yet operational, see also below ... */
 1912: 						case '': /* generate indented source mode*/
 1913: 							behavior=PHP_MODE_INDENT;
 1914: 							break;
 1915: #endif
 1916: 
 1917: 						case 'q': /* do not generate HTTP headers */
 1918: 							no_headers = 1;
 1919: 							break;
 1920: 
 1921: 						case 'v': /* show php version & quit */
 1922: 							if (script_file) {
 1923: 								efree(script_file);
 1924: 							}
 1925: 							no_headers = 1;
 1926: 							if (php_request_startup(TSRMLS_C) == FAILURE) {
 1927: 								SG(server_context) = NULL;
 1928: 								php_module_shutdown(TSRMLS_C);
 1929: 								return FAILURE;
 1930: 							}
 1931: 							if (no_headers) {
 1932: 								SG(headers_sent) = 1;
 1933: 								SG(request_info).no_headers = 1;
 1934: 							}
 1935: #if SUHOSIN_PATCH
 1936: #if ZEND_DEBUG
 1937: 							php_printf("PHP %s with Suhosin-Patch (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2012 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version());
 1938: #else
 1939: 							php_printf("PHP %s with Suhosin-Patch (%s) (built: %s %s)\nCopyright (c) 1997-2012 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version());
 1940: #endif
 1941: #else
 1942: #if ZEND_DEBUG
 1943: 							php_printf("PHP %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2012 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version());
 1944: #else
 1945: 							php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2012 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version());
 1946: #endif
 1947: #endif
 1948: 							php_request_shutdown((void *) 0);
 1949: 							fcgi_shutdown();
 1950: 							exit_status = 0;
 1951: 							goto out;
 1952: 
 1953: 						case 'w':
 1954: 							behavior = PHP_MODE_STRIP;
 1955: 							break;
 1956: 
 1957: 						case 'z': /* load extension file */
 1958: 							zend_load_extension(php_optarg);
 1959: 							break;
 1960: 
 1961: 						default:
 1962: 							break;
 1963: 					}
 1964: 				}
 1965: 
 1966: 				if (script_file) {
 1967: 					/* override path_translated if -f on command line */
 1968: 					STR_FREE(SG(request_info).path_translated);
 1969: 					SG(request_info).path_translated = script_file;
 1970: 					/* before registering argv to module exchange the *new* argv[0] */
 1971: 					/* we can achieve this without allocating more memory */
 1972: 					SG(request_info).argc = argc - (php_optind - 1);
 1973: 					SG(request_info).argv = &argv[php_optind - 1];
 1974: 					SG(request_info).argv[0] = script_file;
 1975: 				} else if (argc > php_optind) {
 1976: 					/* file is on command line, but not in -f opt */
 1977: 					STR_FREE(SG(request_info).path_translated);
 1978: 					SG(request_info).path_translated = estrdup(argv[php_optind]);
 1979: 					/* arguments after the file are considered script args */
 1980: 					SG(request_info).argc = argc - php_optind;
 1981: 					SG(request_info).argv = &argv[php_optind];
 1982: 				}
 1983: 
 1984: 				if (no_headers) {
 1985: 					SG(headers_sent) = 1;
 1986: 					SG(request_info).no_headers = 1;
 1987: 				}
 1988: 
 1989: 				/* all remaining arguments are part of the query string
 1990: 				 * this section of code concatenates all remaining arguments
 1991: 				 * into a single string, seperating args with a &
 1992: 				 * this allows command lines like:
 1993: 				 *
 1994: 				 *  test.php v1=test v2=hello+world!
 1995: 				 *  test.php "v1=test&v2=hello world!"
 1996: 				 *  test.php v1=test "v2=hello world!"
 1997: 				*/
 1998: 				if (!SG(request_info).query_string && argc > php_optind) {
 1999: 					int slen = strlen(PG(arg_separator).input);
 2000: 					len = 0;
 2001: 					for (i = php_optind; i < argc; i++) {
 2002: 						if (i < (argc - 1)) {
 2003: 							len += strlen(argv[i]) + slen;
 2004: 						} else {
 2005: 							len += strlen(argv[i]);
 2006: 						}
 2007: 					}
 2008: 
 2009: 					len += 2;
 2010: 					s = malloc(len);
 2011: 					*s = '\0';			/* we are pretending it came from the environment  */
 2012: 					for (i = php_optind; i < argc; i++) {
 2013: 						strlcat(s, argv[i], len);
 2014: 						if (i < (argc - 1)) {
 2015: 							strlcat(s, PG(arg_separator).input, len);
 2016: 						}
 2017: 					}
 2018: 					SG(request_info).query_string = s;
 2019: 					free_query_string = 1;
 2020: 				}
 2021: 			} /* end !cgi && !fastcgi */
 2022: 
 2023: 			/*
 2024: 				we never take stdin if we're (f)cgi, always
 2025: 				rely on the web server giving us the info
 2026: 				we need in the environment.
 2027: 			*/
 2028: 			if (SG(request_info).path_translated || cgi || fastcgi) {
 2029: 				file_handle.type = ZEND_HANDLE_FILENAME;
 2030: 				file_handle.filename = SG(request_info).path_translated;
 2031: 				file_handle.handle.fp = NULL;
 2032: 			} else {
 2033: 				file_handle.filename = "-";
 2034: 				file_handle.type = ZEND_HANDLE_FP;
 2035: 				file_handle.handle.fp = stdin;
 2036: 			}
 2037: 
 2038: 			file_handle.opened_path = NULL;
 2039: 			file_handle.free_filename = 0;
 2040: 
 2041: 			/* request startup only after we've done all we can to
 2042: 			 * get path_translated */
 2043: 			if (php_request_startup(TSRMLS_C) == FAILURE) {
 2044: 				if (fastcgi) {
 2045: 					fcgi_finish_request(&request, 1);
 2046: 				}
 2047: 				SG(server_context) = NULL;
 2048: 				php_module_shutdown(TSRMLS_C);
 2049: 				return FAILURE;
 2050: 			}
 2051: 			if (no_headers) {
 2052: 				SG(headers_sent) = 1;
 2053: 				SG(request_info).no_headers = 1;
 2054: 			}
 2055: 
 2056: 			/*
 2057: 				at this point path_translated will be set if:
 2058: 				1. we are running from shell and got filename was there
 2059: 				2. we are running as cgi or fastcgi
 2060: 			*/
 2061: 			if (cgi || fastcgi || SG(request_info).path_translated) {
 2062: 				if (php_fopen_primary_script(&file_handle TSRMLS_CC) == FAILURE) {
 2063: 					zend_try {
 2064: 						if (errno == EACCES) {
 2065: 							SG(sapi_headers).http_response_code = 403;
 2066: 							PUTS("Access denied.\n");
 2067: 						} else {
 2068: 							SG(sapi_headers).http_response_code = 404;
 2069: 							PUTS("No input file specified.\n");
 2070: 						}
 2071: 					} zend_catch {
 2072: 					} zend_end_try();
 2073: 					/* we want to serve more requests if this is fastcgi
 2074: 					 * so cleanup and continue, request shutdown is
 2075: 					 * handled later */
 2076: 					if (fastcgi) {
 2077: 						goto fastcgi_request_done;
 2078: 					}
 2079: 
 2080: 					STR_FREE(SG(request_info).path_translated);
 2081: 
 2082: 					if (free_query_string && SG(request_info).query_string) {
 2083: 						free(SG(request_info).query_string);
 2084: 						SG(request_info).query_string = NULL;
 2085: 					}
 2086: 
 2087: 					php_request_shutdown((void *) 0);
 2088: 					SG(server_context) = NULL;
 2089: 					php_module_shutdown(TSRMLS_C);
 2090: 					sapi_shutdown();
 2091: #ifdef ZTS
 2092: 					tsrm_shutdown();
 2093: #endif
 2094: 					return FAILURE;
 2095: 				}
 2096: 			}
 2097: 
 2098: 			if (CGIG(check_shebang_line) && file_handle.handle.fp && (file_handle.handle.fp != stdin)) {
 2099: 				/* #!php support */
 2100: 				c = fgetc(file_handle.handle.fp);
 2101: 				if (c == '#') {
 2102: 					while (c != '\n' && c != '\r' && c != EOF) {
 2103: 						c = fgetc(file_handle.handle.fp);	/* skip to end of line */
 2104: 					}
 2105: 					/* handle situations where line is terminated by \r\n */
 2106: 					if (c == '\r') {
 2107: 						if (fgetc(file_handle.handle.fp) != '\n') {
 2108: 							long pos = ftell(file_handle.handle.fp);
 2109: 							fseek(file_handle.handle.fp, pos - 1, SEEK_SET);
 2110: 						}
 2111: 					}
 2112: 					CG(start_lineno) = 2;
 2113: 				} else {
 2114: 					rewind(file_handle.handle.fp);
 2115: 				}
 2116: 			}
 2117: 
 2118: 			switch (behavior) {
 2119: 				case PHP_MODE_STANDARD:
 2120: 					php_execute_script(&file_handle TSRMLS_CC);
 2121: 					break;
 2122: 				case PHP_MODE_LINT:
 2123: 					PG(during_request_startup) = 0;
 2124: 					exit_status = php_lint_script(&file_handle TSRMLS_CC);
 2125: 					if (exit_status == SUCCESS) {
 2126: 						zend_printf("No syntax errors detected in %s\n", file_handle.filename);
 2127: 					} else {
 2128: 						zend_printf("Errors parsing %s\n", file_handle.filename);
 2129: 					}
 2130: 					break;
 2131: 				case PHP_MODE_STRIP:
 2132: 					if (open_file_for_scanning(&file_handle TSRMLS_CC) == SUCCESS) {
 2133: 						zend_strip(TSRMLS_C);
 2134: 						zend_file_handle_dtor(&file_handle TSRMLS_CC);
 2135: 						php_end_ob_buffers(1 TSRMLS_CC);
 2136: 					}
 2137: 					return SUCCESS;
 2138: 					break;
 2139: 				case PHP_MODE_HIGHLIGHT:
 2140: 					{
 2141: 						zend_syntax_highlighter_ini syntax_highlighter_ini;
 2142: 
 2143: 						if (open_file_for_scanning(&file_handle TSRMLS_CC) == SUCCESS) {
 2144: 							php_get_highlight_struct(&syntax_highlighter_ini);
 2145: 							zend_highlight(&syntax_highlighter_ini TSRMLS_CC);
 2146: 							if (fastcgi) {
 2147: 								goto fastcgi_request_done;
 2148: 							}
 2149: 							zend_file_handle_dtor(&file_handle TSRMLS_CC);
 2150: 							php_end_ob_buffers(1 TSRMLS_CC);
 2151: 						}
 2152: 						return SUCCESS;
 2153: 					}
 2154: 					break;
 2155: #if 0
 2156: 				/* Zeev might want to do something with this one day */
 2157: 				case PHP_MODE_INDENT:
 2158: 					open_file_for_scanning(&file_handle TSRMLS_CC);
 2159: 					zend_indent();
 2160: 					zend_file_handle_dtor(&file_handle TSRMLS_CC);
 2161: 					return SUCCESS;
 2162: 					break;
 2163: #endif
 2164: 			}
 2165: 
 2166: fastcgi_request_done:
 2167: 			{
 2168: 				STR_FREE(SG(request_info).path_translated);
 2169: 
 2170: 				php_request_shutdown((void *) 0);
 2171: 
 2172: 				if (exit_status == 0) {
 2173: 					exit_status = EG(exit_status);
 2174: 				}
 2175: 
 2176: 				if (free_query_string && SG(request_info).query_string) {
 2177: 					free(SG(request_info).query_string);
 2178: 					SG(request_info).query_string = NULL;
 2179: 				}
 2180: 			}
 2181: 
 2182: 			if (!fastcgi) {
 2183: 				if (benchmark) {
 2184: 					repeats--;
 2185: 					if (repeats > 0) {
 2186: 						script_file = NULL;
 2187: 						php_optind = orig_optind;
 2188: 						php_optarg = orig_optarg;
 2189: 						continue;
 2190: 					}
 2191: 				}
 2192: 				break;
 2193: 			}
 2194: 
 2195: 			/* only fastcgi will get here */
 2196: 			requests++;
 2197: 			if (max_requests && (requests == max_requests)) {
 2198: 				fcgi_finish_request(&request, 1);
 2199: 				if (bindpath) {
 2200: 					free(bindpath);
 2201: 				}
 2202: 				if (max_requests != 1) {
 2203: 					/* no need to return exit_status of the last request */
 2204: 					exit_status = 0;
 2205: 				}
 2206: 				break;
 2207: 			}
 2208: 			/* end of fastcgi loop */
 2209: 		}
 2210: 		fcgi_shutdown();
 2211: 
 2212: 		if (cgi_sapi_module.php_ini_path_override) {
 2213: 			free(cgi_sapi_module.php_ini_path_override);
 2214: 		}
 2215: 		if (cgi_sapi_module.ini_entries) {
 2216: 			free(cgi_sapi_module.ini_entries);
 2217: 		}
 2218: 	} zend_catch {
 2219: 		exit_status = 255;
 2220: 	} zend_end_try();
 2221: 
 2222: out:
 2223: 	if (benchmark) {
 2224: 		int sec;
 2225: #ifdef HAVE_GETTIMEOFDAY
 2226: 		int usec;
 2227: 
 2228: 		gettimeofday(&end, NULL);
 2229: 		sec = (int)(end.tv_sec - start.tv_sec);
 2230: 		if (end.tv_usec >= start.tv_usec) {
 2231: 			usec = (int)(end.tv_usec - start.tv_usec);
 2232: 		} else {
 2233: 			sec -= 1;
 2234: 			usec = (int)(end.tv_usec + 1000000 - start.tv_usec);
 2235: 		}
 2236: 		fprintf(stderr, "\nElapsed time: %d.%06d sec\n", sec, usec);
 2237: #else
 2238: 		time(&end);
 2239: 		sec = (int)(end - start);
 2240: 		fprintf(stderr, "\nElapsed time: %d sec\n", sec);
 2241: #endif
 2242: 	}
 2243: 
 2244: #ifndef PHP_WIN32
 2245: parent_out:
 2246: #endif
 2247: 
 2248: 	SG(server_context) = NULL;
 2249: 	php_module_shutdown(TSRMLS_C);
 2250: 	sapi_shutdown();
 2251: 
 2252: #ifdef ZTS
 2253: 	tsrm_shutdown();
 2254: #endif
 2255: 
 2256: #if defined(PHP_WIN32) && ZEND_DEBUG && 0
 2257: 	_CrtDumpMemoryLeaks();
 2258: #endif
 2259: 
 2260: 	return exit_status;
 2261: }
 2262: /* }}} */
 2263: 
 2264: /*
 2265:  * Local variables:
 2266:  * tab-width: 4
 2267:  * c-basic-offset: 4
 2268:  * End:
 2269:  * vim600: sw=4 ts=4 fdm=marker
 2270:  * vim<600: sw=4 ts=4
 2271:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>