Annotation of embedaddon/php/sapi/cgi/cgi_main.c, revision 1.1.1.1

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

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