PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - sapi/cgi - cgi_main.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 565 1124 50.3 %
Date: 2019-08-09 Functions: 22 42 52.4 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Fri, 09 Aug 2019 14:59:14 +0000 (8 days ago)

Copyright © 2005-2019 The PHP Group
All rights reserved.