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