1/*
2   +----------------------------------------------------------------------+
3   | PHP Version 5                                                        |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1997-2014 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 at 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   | Author: George Wang <gwang@litespeedtech.com>                        |
16   +----------------------------------------------------------------------+
17*/
18
19#include "php.h"
20#include "SAPI.h"
21#include "php_main.h"
22#include "php_ini.h"
23#include "php_variables.h"
24#include "zend_highlight.h"
25#include "zend.h"
26
27#include "lsapilib.h"
28
29#include <stdio.h>
30
31#if HAVE_STDLIB_H
32#include <stdlib.h>
33#endif
34
35#if HAVE_UNISTD_H
36#include <unistd.h>
37#endif
38
39#ifdef PHP_WIN32
40
41#include <io.h>
42#include <fcntl.h>
43#include "win32/php_registry.h"
44
45#else
46
47#include <sys/wait.h>
48
49#endif
50
51#include <sys/stat.h>
52
53#if HAVE_SYS_TYPES_H
54
55#include <sys/types.h>
56
57#endif
58
59#if HAVE_SIGNAL_H
60
61#include <signal.h>
62
63#endif
64
65#include <sys/socket.h>
66#include <arpa/inet.h>
67#include <netinet/in.h>
68
69
70#define SAPI_LSAPI_MAX_HEADER_LENGTH 2048
71
72static int  lsapi_mode       = 1;
73static char *php_self        = "";
74static char *script_filename = "";
75static int  source_highlight = 0;
76static int  ignore_php_ini   = 0;
77static char * argv0 = NULL;
78static int  engine = 1;
79#ifdef ZTS
80zend_compiler_globals    *compiler_globals;
81zend_executor_globals    *executor_globals;
82php_core_globals         *core_globals;
83sapi_globals_struct      *sapi_globals;
84void ***tsrm_ls;
85#endif
86
87zend_module_entry litespeed_module_entry;
88
89/* {{{ php_lsapi_startup
90 */
91static int php_lsapi_startup(sapi_module_struct *sapi_module)
92{
93    if (php_module_startup(sapi_module, NULL, 0)==FAILURE) {
94        return FAILURE;
95    }
96    argv0 = sapi_module->executable_location;
97    return SUCCESS;
98}
99/* }}} */
100
101/* {{{ sapi_lsapi_ini_defaults */
102
103/* overwriteable ini defaults must be set in sapi_cli_ini_defaults() */
104#define INI_DEFAULT(name,value)\
105    ZVAL_STRING(tmp, value, 0);\
106    zend_hash_update(configuration_hash, name, sizeof(name), tmp, sizeof(zval), (void**)&entry);\
107    Z_STRVAL_P(entry) = zend_strndup(Z_STRVAL_P(entry), Z_STRLEN_P(entry))
108
109static void sapi_lsapi_ini_defaults(HashTable *configuration_hash)
110{
111    zval *tmp, *entry;
112
113#if PHP_MAJOR_VERSION > 4
114/*
115    MAKE_STD_ZVAL(tmp);
116
117    INI_DEFAULT("register_long_arrays", "0");
118
119    FREE_ZVAL(tmp);
120*/
121#endif
122
123}
124/* }}} */
125
126
127/* {{{ sapi_lsapi_ub_write
128 */
129static int sapi_lsapi_ub_write(const char *str, uint str_length TSRMLS_DC)
130{
131    int ret;
132    int remain;
133    if ( lsapi_mode ) {
134        ret  = LSAPI_Write( str, str_length );
135        if ( ret < str_length ) {
136            php_handle_aborted_connection();
137            return str_length - ret;
138        }
139    } else {
140        remain = str_length;
141        while( remain > 0 ) {
142            ret = write( 1, str, remain );
143            if ( ret <= 0 ) {
144                php_handle_aborted_connection();
145                return str_length - remain;
146            }
147            str += ret;
148            remain -= ret;
149        }
150    }
151    return str_length;
152}
153/* }}} */
154
155
156/* {{{ sapi_lsapi_flush
157 */
158static void sapi_lsapi_flush( void * server_context TSRMLS_DC )
159{
160    if ( lsapi_mode ) {
161        if ( LSAPI_Flush() == -1) {
162            php_handle_aborted_connection();
163        }
164    }
165}
166/* }}} */
167
168
169/* {{{ sapi_lsapi_deactivate
170 */
171static int sapi_lsapi_deactivate(TSRMLS_D)
172{
173    if ( SG(request_info).path_translated )
174    {
175        efree( SG(request_info).path_translated );
176    }
177
178    return SUCCESS;
179}
180/* }}} */
181
182
183
184
185/* {{{ sapi_lsapi_getenv
186 */
187static char *sapi_lsapi_getenv( char * name, size_t name_len TSRMLS_DC )
188{
189    if ( lsapi_mode ) {
190        return LSAPI_GetEnv( name );
191    } else {
192        return getenv( name );
193    }
194}
195/* }}} */
196
197
198/*
199static int add_variable( const char * pKey, int keyLen, const char * pValue, int valLen,
200                         void * arg )
201{
202    php_register_variable_safe((char *)pKey, (char *)pValue, valLen, (zval *)arg TSRMLS_CC);
203    return 1;
204}
205*/
206
207static int add_variable( const char * pKey, int keyLen, const char * pValue, int valLen,
208                         void * arg )
209{
210    zval * gpc_element, **gpc_element_p;
211    HashTable * symtable1 = Z_ARRVAL_P((zval * )arg);
212    register char * pKey1 = (char *)pKey;
213
214    MAKE_STD_ZVAL(gpc_element);
215    Z_STRLEN_P( gpc_element ) = valLen;
216    Z_STRVAL_P( gpc_element ) = estrndup(pValue, valLen);
217    Z_TYPE_P( gpc_element ) = IS_STRING;
218#if PHP_MAJOR_VERSION > 4
219    zend_symtable_update( symtable1, pKey1, keyLen + 1, &gpc_element, sizeof( zval *), (void **) &gpc_element_p );
220#else
221    zend_hash_update( symtable1, pKey1, keyLen + 1, &gpc_element, sizeof( zval *), (void **) &gpc_element_p );
222#endif
223    return 1;
224}
225
226
227#if ((PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION < 4) || PHP_MAJOR_VERSION < 5)
228static int add_variable_magic_quote( const char * pKey, int keyLen, const char * pValue, int valLen,
229                         void * arg )
230{
231    zval * gpc_element, **gpc_element_p;
232    HashTable * symtable1 = Z_ARRVAL_P((zval * )arg);
233    register char * pKey1 = (char *)pKey;
234
235    MAKE_STD_ZVAL(gpc_element);
236    Z_STRLEN_P( gpc_element ) = valLen;
237    Z_STRVAL_P( gpc_element ) = php_addslashes((char *)pValue, valLen, &Z_STRLEN_P( gpc_element ), 0 );
238    Z_TYPE_P( gpc_element ) = IS_STRING;
239#if PHP_MAJOR_VERSION > 4
240    zend_symtable_update( symtable1, pKey1, keyLen + 1, &gpc_element, sizeof( zval *), (void **) &gpc_element_p );
241#else
242    zend_hash_update( symtable1, pKey1, keyLen + 1, &gpc_element, sizeof( zval *), (void **) &gpc_element_p );
243#endif
244    return 1;
245}
246
247#endif
248
249/* {{{ sapi_lsapi_register_variables
250 */
251static void sapi_lsapi_register_variables(zval *track_vars_array TSRMLS_DC)
252{
253    char * php_self = "";
254    if ( lsapi_mode ) {
255        if ( (SG(request_info).request_uri ) )
256            php_self = (SG(request_info).request_uri );
257
258#if ((PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION < 4) || PHP_MAJOR_VERSION < 5)
259        if (!PG(magic_quotes_gpc)) {
260#endif
261            LSAPI_ForeachHeader( add_variable, track_vars_array );
262            LSAPI_ForeachEnv( add_variable, track_vars_array );
263            add_variable("PHP_SELF", 8, php_self, strlen( php_self ), track_vars_array );
264#if ((PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION < 4) || PHP_MAJOR_VERSION < 5)
265        } else {
266            LSAPI_ForeachHeader( add_variable_magic_quote, track_vars_array );
267            LSAPI_ForeachEnv( add_variable_magic_quote, track_vars_array );
268            add_variable_magic_quote("PHP_SELF", 8, php_self, strlen( php_self ), track_vars_array );
269        }
270#endif
271        php_import_environment_variables(track_vars_array TSRMLS_CC);
272    } else {
273        php_import_environment_variables(track_vars_array TSRMLS_CC);
274
275        php_register_variable("PHP_SELF", php_self, track_vars_array TSRMLS_CC);
276        php_register_variable("SCRIPT_NAME", php_self, track_vars_array TSRMLS_CC);
277        php_register_variable("SCRIPT_FILENAME", script_filename, track_vars_array TSRMLS_CC);
278        php_register_variable("PATH_TRANSLATED", script_filename, track_vars_array TSRMLS_CC);
279        php_register_variable("DOCUMENT_ROOT", "", track_vars_array TSRMLS_CC);
280
281    }
282}
283/* }}} */
284
285
286/* {{{ sapi_lsapi_read_post
287 */
288static int sapi_lsapi_read_post(char *buffer, uint count_bytes TSRMLS_DC)
289{
290    if ( lsapi_mode ) {
291        return LSAPI_ReadReqBody( buffer, (unsigned long long)count_bytes );
292    } else {
293        return 0;
294    }
295}
296/* }}} */
297
298
299
300
301/* {{{ sapi_lsapi_read_cookies
302 */
303static char *sapi_lsapi_read_cookies(TSRMLS_D)
304{
305    if ( lsapi_mode ) {
306        return LSAPI_GetHeader( H_COOKIE );
307    } else {
308        return NULL;
309    }
310}
311/* }}} */
312
313
314/* {{{ sapi_lsapi_send_headers
315 */
316static int sapi_lsapi_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
317{
318    sapi_header_struct  *h;
319    zend_llist_position pos;
320    if ( lsapi_mode ) {
321        LSAPI_SetRespStatus( SG(sapi_headers).http_response_code );
322
323        h = zend_llist_get_first_ex(&sapi_headers->headers, &pos);
324        while (h) {
325            if ( h->header_len > 0 ) {
326                LSAPI_AppendRespHeader(h->header, h->header_len);
327            }
328            h = zend_llist_get_next_ex(&sapi_headers->headers, &pos);
329        }
330        if (SG(sapi_headers).send_default_content_type) {
331            char    *hd;
332            int     len;
333            char    headerBuf[SAPI_LSAPI_MAX_HEADER_LENGTH];
334
335            hd = sapi_get_default_content_type(TSRMLS_C);
336            len = snprintf( headerBuf, SAPI_LSAPI_MAX_HEADER_LENGTH - 1,
337                            "Content-type: %s", hd );
338            efree(hd);
339
340            LSAPI_AppendRespHeader( headerBuf, len );
341        }
342    }
343    LSAPI_FinalizeRespHeaders();
344    return SAPI_HEADER_SENT_SUCCESSFULLY;
345
346
347}
348/* }}} */
349
350
351/* {{{ sapi_lsapi_send_headers
352 */
353static void sapi_lsapi_log_message(char *message TSRMLS_DC)
354{
355    char buf[8192];
356    int len = strlen( message );
357    if ( *(message + len - 1 ) != '\n' )
358    {
359        snprintf( buf, 8191, "%s\n", message );
360        message = buf;
361        ++len;
362    }
363    LSAPI_Write_Stderr( message, len);
364}
365/* }}} */
366
367
368/* {{{ sapi_module_struct cgi_sapi_module
369 */
370static sapi_module_struct lsapi_sapi_module =
371{
372    "litespeed",
373    "LiteSpeed V6.6",
374
375    php_lsapi_startup,              /* startup */
376    php_module_shutdown_wrapper,    /* shutdown */
377
378    NULL,                           /* activate */
379    sapi_lsapi_deactivate,          /* deactivate */
380
381    sapi_lsapi_ub_write,            /* unbuffered write */
382    sapi_lsapi_flush,               /* flush */
383    NULL,                           /* get uid */
384    sapi_lsapi_getenv,              /* getenv */
385
386    php_error,                      /* error handler */
387
388    NULL,                           /* header handler */
389    sapi_lsapi_send_headers,        /* send headers handler */
390    NULL,                           /* send header handler */
391
392    sapi_lsapi_read_post,           /* read POST data */
393    sapi_lsapi_read_cookies,        /* read Cookies */
394
395    sapi_lsapi_register_variables,  /* register server variables */
396    sapi_lsapi_log_message,         /* Log message */
397
398    NULL,                           /* php.ini path override */
399    NULL,                           /* block interruptions */
400    NULL,                           /* unblock interruptions */
401    NULL,                           /* default post reader */
402    NULL,                           /* treat data */
403    NULL,                           /* executable location */
404
405    0,                              /* php.ini ignore */
406
407    STANDARD_SAPI_MODULE_PROPERTIES
408
409};
410/* }}} */
411
412static int init_request_info( TSRMLS_D )
413{
414    char * pContentType = LSAPI_GetHeader( H_CONTENT_TYPE );
415    char * pAuth;
416
417    SG(request_info).content_type = pContentType ? pContentType : "";
418    SG(request_info).request_method = LSAPI_GetRequestMethod();
419    SG(request_info).query_string = LSAPI_GetQueryString();
420    SG(request_info).request_uri = LSAPI_GetScriptName();
421    SG(request_info).content_length = LSAPI_GetReqBodyLen();
422    SG(request_info).path_translated = estrdup( LSAPI_GetScriptFileName());
423
424    /* It is not reset by zend engine, set it to 0. */
425    SG(sapi_headers).http_response_code = 0;
426
427    pAuth = LSAPI_GetHeader( H_AUTHORIZATION );
428    php_handle_auth_data(pAuth TSRMLS_CC);
429}
430
431static char s_cur_chdir[4096] = "";
432
433static int lsapi_chdir_primary_script( zend_file_handle * file_handle )
434{
435#if PHP_MAJOR_VERSION > 4
436    char * p;
437    char ch;
438
439    SG(options) |= SAPI_OPTION_NO_CHDIR;
440    getcwd( s_cur_chdir, sizeof( s_cur_chdir ) );
441
442    p = strrchr( file_handle->filename, '/' );
443    if ( *p )
444    {
445        *p = 0;
446        if ( strcmp( file_handle->filename, s_cur_chdir ) != 0 ) {
447            chdir( file_handle->filename );
448        }
449        *p++ = '/';
450        ch = *p;
451        *p = 0;
452        if ( !CWDG(cwd).cwd ||
453             ( strcmp( file_handle->filename, CWDG(cwd).cwd ) != 0 ) ) {
454            CWDG(cwd).cwd_length = p - file_handle->filename;
455            CWDG(cwd).cwd = (char *) realloc(CWDG(cwd).cwd, CWDG(cwd).cwd_length+1);
456            memmove( CWDG(cwd).cwd, file_handle->filename, CWDG(cwd).cwd_length+1 );
457        }
458        *p = ch;
459    }
460    /* virtual_file_ex(&CWDG(cwd), file_handle->filename, NULL, CWD_REALPATH); */
461#else
462    VCWD_CHDIR_FILE( file_handle->filename );
463#endif
464    return 0;
465}
466
467static int lsapi_fopen_primary_script( zend_file_handle * file_handle )
468{
469    FILE * fp;
470    char * p;
471    fp = fopen( SG(request_info).path_translated, "rb" );
472    if ( !fp )
473    {
474        return -1;
475    }
476    file_handle->type = ZEND_HANDLE_FP;
477    file_handle->handle.fp = fp;
478    file_handle->filename = SG(request_info).path_translated;
479    file_handle->free_filename = 0;
480    file_handle->opened_path = NULL;
481
482    lsapi_chdir_primary_script( file_handle );
483
484    return 0;
485}
486
487static int lsapi_execute_script( zend_file_handle * file_handle TSRMLS_DC)
488{
489    char *p;
490    int len;
491    file_handle->type = ZEND_HANDLE_FILENAME;
492    file_handle->handle.fd = 0;
493    file_handle->filename = SG(request_info).path_translated;
494    file_handle->free_filename = 0;
495    file_handle->opened_path = NULL;
496
497    p = argv0;
498    *p++ = ':';
499    len = strlen( SG(request_info).path_translated );
500    if ( len > 45 )
501        len = len - 45;
502    else
503        len = 0;
504    memccpy( p, SG(request_info).path_translated + len, 0, 46 );
505
506    php_execute_script(file_handle TSRMLS_CC);
507    return 0;
508
509}
510
511
512static int lsapi_module_main(int show_source TSRMLS_DC)
513{
514    zend_file_handle file_handle = {0};
515
516    if (php_request_startup(TSRMLS_C) == FAILURE ) {
517        return -1;
518    }
519    if (show_source) {
520        zend_syntax_highlighter_ini syntax_highlighter_ini;
521
522        php_get_highlight_struct(&syntax_highlighter_ini);
523        highlight_file(SG(request_info).path_translated, &syntax_highlighter_ini TSRMLS_CC);
524    } else {
525        lsapi_execute_script( &file_handle TSRMLS_CC);
526    }
527    zend_try {
528        php_request_shutdown(NULL);
529        memset( argv0, 0, 46 );
530    } zend_end_try();
531    return 0;
532}
533
534
535static int alter_ini( const char * pKey, int keyLen, const char * pValue, int valLen,
536                void * arg )
537{
538    int type = ZEND_INI_PERDIR;
539    if ( '\001' == *pKey ) {
540        ++pKey;
541        if ( *pKey == 4 ) {
542            type = ZEND_INI_SYSTEM;
543        }
544        ++pKey;
545        --keyLen;
546        if (( keyLen == 7 )&&( strncasecmp( pKey, "engine", 6 )== 0 ))
547        {
548            if ( *pValue == '0' )
549                engine = 0;
550        }
551        else
552            zend_alter_ini_entry((char *)pKey, keyLen,
553                             (char *)pValue, valLen,
554                             type, PHP_INI_STAGE_ACTIVATE);
555    }
556    return 1;
557}
558
559
560static void override_ini()
561{
562
563    LSAPI_ForeachSpecialEnv( alter_ini, NULL );
564
565}
566
567
568static int processReq( TSRMLS_D )
569{
570    int ret = 0;
571    zend_first_try {
572
573        /* avoid server_context==NULL checks */
574        SG(server_context) = (void *) 1;
575
576        engine = 1;
577        override_ini();
578
579        if ( engine ) {
580            init_request_info( TSRMLS_C );
581
582            if ( lsapi_module_main( source_highlight TSRMLS_CC ) == -1 ) {
583                ret = -1;
584            }
585        } else {
586            LSAPI_AppendRespHeader( "status: 403", 11 );
587            LSAPI_AppendRespHeader( "content-type: text/html", 23 );
588            LSAPI_Write( "Forbidden: PHP engine is disable.\n", 34 );
589        }
590    } zend_end_try();
591    return ret;
592}
593
594static void cli_usage( TSRMLS_D )
595{
596    static const char * usage =
597        "Usage: php\n"
598        "      php -[b|c|n|h|i|q|s|v|?] [<file>] [args...]\n"
599        "  Run in LSAPI mode, only '-b', '-s' and '-c' are effective\n"
600        "  Run in Command Line Interpreter mode when parameters are specified\n"
601        "\n"
602        "  -b <address:port>|<port> Bind Path for external LSAPI Server mode\n"
603        "  -c <path>|<file> Look for php.ini file in this directory\n"
604        "  -n    No php.ini file will be used\n"
605        "  -h    This help\n"
606        "  -i    PHP information\n"
607        "  -l    Syntax check\n"
608        "  -q    Quiet-mode.  Suppress HTTP Header output.\n"
609        "  -s    Display colour syntax highlighted source.\n"
610        "  -v    Version number\n"
611        "  -?    This help\n"
612        "\n"
613        "  args...    Arguments passed to script.\n";
614    php_output_startup();
615    php_output_activate(TSRMLS_C);
616    php_printf( "%s", usage );
617#ifdef PHP_OUTPUT_NEWAPI
618    php_output_end_all(TSRMLS_C);
619#else
620    php_end_ob_buffers(1 TSRMLS_CC);
621#endif
622}
623
624static int parse_opt( int argc, char * argv[], int *climode,
625                        char **php_ini_path, char ** php_bind )
626{
627    char ** p = &argv[1];
628    char ** argend= &argv[argc];
629    int c;
630    while (( p < argend )&&(**p == '-' )) {
631        c = *((*p)+1);
632        ++p;
633        switch( c ) {
634        case 'b':
635            if ( p >= argend ) {
636                fprintf( stderr, "TCP or socket address must be specified following '-b' option.\n");
637                return -1;
638            }
639            *php_bind = strdup(*p++);
640            break;
641
642        case 'c':
643            if ( p >= argend ) {
644                fprintf( stderr, "<path> or <file> must be specified following '-c' option.\n");
645
646                return -1;
647            }
648            *php_ini_path = strdup( *p++ );
649            break;
650        case 's':
651            source_highlight = 1;
652            break;
653        case 'n':
654            ignore_php_ini = 1;
655            break;
656        case '?':
657            if ( *((*(p-1))+2) == 's' )
658                exit( 99 );
659        case 'h':
660        case 'i':
661        case 'l':
662        case 'q':
663        case 'v':
664        default:
665            *climode = 1;
666            break;
667        }
668    }
669    if ( p - argv < argc ) {
670        *climode = 1;
671    }
672    return 0;
673}
674
675static int cli_main( int argc, char * argv[] )
676{
677
678    static const char * ini_defaults[] = {
679        "report_zend_debug",    "0",
680        "display_errors",       "1",
681        "register_argc_argv",   "1",
682        "html_errors",          "0",
683        "implicit_flush",       "1",
684        "output_buffering",     "0",
685        "max_execution_time",   "0",
686        "max_input_time",       "-1",
687        NULL
688    };
689
690    const char ** ini;
691    char ** p = &argv[1];
692    char ** argend= &argv[argc];
693    int ret = -1;
694    int c;
695    lsapi_mode = 0;        /* enter CLI mode */
696
697#ifdef PHP_WIN32
698    _fmode = _O_BINARY;            /*sets default for file streams to binary */
699    setmode(_fileno(stdin), O_BINARY);    /* make the stdio mode be binary */
700    setmode(_fileno(stdout), O_BINARY);   /* make the stdio mode be binary */
701    setmode(_fileno(stderr), O_BINARY);   /* make the stdio mode be binary */
702#endif
703
704    zend_first_try     {
705        SG(server_context) = (void *) 1;
706
707        zend_uv.html_errors = 0; /* tell the engine we're in non-html mode */
708        CG(in_compilation) = 0; /* not initialized but needed for several options */
709        EG(uninitialized_zval_ptr) = NULL;
710
711        for( ini = ini_defaults; *ini; ini+=2 ) {
712            zend_alter_ini_entry( (char *)*ini, strlen( *ini )+1,
713                                (char *)*(ini+1), strlen( *(ini+1) ),
714                                PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE);
715        }
716
717        while (( p < argend )&&(**p == '-' )) {
718            c = *((*p)+1);
719            ++p;
720            switch( c ) {
721            case 'q':
722                break;
723            case 'i':
724                if (php_request_startup(TSRMLS_C) != FAILURE) {
725                    php_print_info(0xFFFFFFFF TSRMLS_CC);
726#ifdef PHP_OUTPUT_NEWAPI
727                    php_output_end_all(TSRMLS_C);
728#else
729                    php_end_ob_buffers(1 TSRMLS_CC);
730#endif
731                    php_request_shutdown( NULL );
732                    ret = 0;
733                }
734                break;
735            case 'v':
736                if (php_request_startup(TSRMLS_C) != FAILURE) {
737#if ZEND_DEBUG
738                    php_printf("PHP %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2014 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version());
739#else
740                    php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2014 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version());
741#endif
742#ifdef PHP_OUTPUT_NEWAPI
743                    php_output_end_all(TSRMLS_C);
744#else
745                    php_end_ob_buffers(1 TSRMLS_CC);
746#endif
747                    php_request_shutdown( NULL );
748                    ret = 0;
749                }
750                break;
751            case 'c':
752                ++p;
753            /* fall through */
754            case 's':
755                break;
756            case 'l':
757                source_highlight = 2;
758                break;
759            case 'h':
760            case '?':
761            default:
762                cli_usage(TSRMLS_C);
763                ret = 0;
764                break;
765
766            }
767        }
768        if ( ret == -1 ) {
769            if ( *p ) {
770                zend_file_handle file_handle = {0};
771
772                file_handle.type = ZEND_HANDLE_FP;
773                file_handle.handle.fp = VCWD_FOPEN(*p, "rb");
774
775                if ( file_handle.handle.fp ) {
776                    script_filename = *p;
777                    php_self = *p;
778
779                    SG(request_info).path_translated = estrdup(*p);
780                    SG(request_info).argc = argc - (p - argv);
781                    SG(request_info).argv = p;
782
783                    if (php_request_startup(TSRMLS_C) == FAILURE ) {
784                        fclose( file_handle.handle.fp );
785                        ret = 2;
786                    } else {
787                        if (source_highlight == 1) {
788                            zend_syntax_highlighter_ini syntax_highlighter_ini;
789
790                            php_get_highlight_struct(&syntax_highlighter_ini);
791                            highlight_file(SG(request_info).path_translated, &syntax_highlighter_ini TSRMLS_CC);
792                        } else if (source_highlight == 2) {
793                            file_handle.filename = *p;
794                            file_handle.free_filename = 0;
795                            file_handle.opened_path = NULL;
796                            ret = php_lint_script(&file_handle TSRMLS_CC);
797                            if (ret==SUCCESS) {
798                                zend_printf("No syntax errors detected in %s\n", file_handle.filename);
799                            } else {
800                                zend_printf("Errors parsing %s\n", file_handle.filename);
801                            }
802
803                        } else {
804                            file_handle.filename = *p;
805                            file_handle.free_filename = 0;
806                            file_handle.opened_path = NULL;
807
808                            php_execute_script(&file_handle TSRMLS_CC);
809                            ret = EG(exit_status);
810                       }
811
812                        php_request_shutdown( NULL );
813                    }
814                } else {
815                    php_printf("Could not open input file: %s.\n", *p);
816                }
817            } else {
818                cli_usage(TSRMLS_C);
819            }
820        }
821
822    }zend_end_try();
823
824    php_module_shutdown(TSRMLS_C);
825
826#ifdef ZTS
827    tsrm_shutdown();
828#endif
829    return ret;
830}
831
832static int s_stop;
833void litespeed_cleanup(int signal)
834{
835    s_stop = signal;
836}
837
838
839void start_children( int children )
840{
841    struct sigaction act, old_term, old_quit, old_int, old_usr1;
842    int running = 0;
843    int status;
844    pid_t pid;
845
846    /* Create a process group */
847    setsid();
848
849    /* Set up handler to kill children upon exit */
850    act.sa_flags = 0;
851    act.sa_handler = litespeed_cleanup;
852    if( sigaction( SIGTERM, &act, &old_term ) ||
853        sigaction( SIGINT,  &act, &old_int  ) ||
854        sigaction( SIGUSR1, &act, &old_usr1 ) ||
855        sigaction( SIGQUIT, &act, &old_quit )) {
856        perror( "Can't set signals" );
857        exit( 1 );
858    }
859    s_stop = 0;
860    while( 1 ) {
861        while((!s_stop )&&( running < children )) {
862            pid = fork();
863            switch( pid ) {
864            case 0: /* children process */
865
866                /* don't catch our signals */
867                sigaction( SIGTERM, &old_term, 0 );
868                sigaction( SIGQUIT, &old_quit, 0 );
869                sigaction( SIGINT,  &old_int,  0 );
870                sigaction( SIGUSR1, &old_usr1, 0 );
871                return ;
872            case -1:
873                perror( "php (pre-forking)" );
874                exit( 1 );
875                break;
876            default: /* parent process */
877                running++;
878                break;
879            }
880        }
881        if ( s_stop ) {
882            break;
883        }
884        pid = wait( &status );
885        running--;
886    }
887    kill( -getpgrp(), SIGUSR1 );
888    exit( 0 );
889}
890
891void setArgv0( int argc, char * argv[] )
892{
893    char * p;
894    int i;
895    argv0 = argv[0] + strlen( argv[0] );
896    p = argv0;
897    while(( p > argv[0] )&&( p[-1] != '/'))
898        --p;
899    if ( p > argv[0] )
900    {
901        memmove( argv[0], p, argv0 - p );
902        memset( argv[0] + ( argv0 - p ), 0, p - argv[0] );
903        argv0 = argv[0] + (argv0 - p);
904    }
905    for( i = 1; i < argc; ++i )
906    {
907        memset( argv[i], 0, strlen( argv[i] ) );
908    }
909}
910
911#include <fcntl.h>
912int main( int argc, char * argv[] )
913{
914    int ret;
915    int bindFd;
916
917    char * php_ini_path = NULL;
918    char * php_bind     = NULL;
919    int n;
920    int climode = 0;
921    struct timeval tv_req_begin;
922    struct timeval tv_req_end;
923    int slow_script_msec = 0;
924    char time_buf[40];
925
926#ifdef HAVE_SIGNAL_H
927#if defined(SIGPIPE) && defined(SIG_IGN)
928    signal(SIGPIPE, SIG_IGN);
929#endif
930#endif
931
932#ifdef ZTS
933    tsrm_startup(1, 1, 0, NULL);
934#endif
935
936    if (argc > 1 ) {
937        if ( parse_opt( argc, argv, &climode,
938                &php_ini_path, &php_bind ) == -1 ) {
939            return 1;
940        }
941    }
942    if ( climode ) {
943        lsapi_sapi_module.phpinfo_as_text = 1;
944    } else {
945        setArgv0(argc, argv );
946    }
947
948    sapi_startup(&lsapi_sapi_module);
949
950#ifdef ZTS
951    compiler_globals = ts_resource(compiler_globals_id);
952    executor_globals = ts_resource(executor_globals_id);
953    core_globals = ts_resource(core_globals_id);
954    sapi_globals = ts_resource(sapi_globals_id);
955    tsrm_ls = ts_resource(0);
956
957    SG(request_info).path_translated = NULL;
958#endif
959
960    lsapi_sapi_module.executable_location = argv[0];
961
962    if ( ignore_php_ini )
963        lsapi_sapi_module.php_ini_ignore = 1;
964
965    if ( php_ini_path ) {
966        lsapi_sapi_module.php_ini_path_override = php_ini_path;
967    }
968
969
970    lsapi_sapi_module.ini_defaults = sapi_lsapi_ini_defaults;
971
972    if (php_module_startup(&lsapi_sapi_module, &litespeed_module_entry, 1) == FAILURE) {
973#ifdef ZTS
974        tsrm_shutdown();
975#endif
976        return FAILURE;
977    }
978
979    if ( climode ) {
980        return cli_main(argc, argv);
981    }
982
983    if ( php_bind ) {
984        bindFd = LSAPI_CreateListenSock( php_bind, 10 );
985        if ( bindFd == -1 ) {
986            fprintf( stderr,
987                     "Failed to bind socket [%s]: %s\n", php_bind, strerror( errno ) );
988            exit( 2 );
989        }
990        if ( bindFd != 0 ) {
991            dup2( bindFd, 0 );
992            close( bindFd );
993        }
994    }
995
996    LSAPI_Init();
997
998    LSAPI_Init_Env_Parameters( NULL );
999
1000    slow_script_msec = LSAPI_Get_Slow_Req_Msecs();
1001
1002    if ( php_bind ) {
1003        LSAPI_No_Check_ppid();
1004        free( php_bind );
1005        php_bind = NULL;
1006    }
1007
1008    while( LSAPI_Prefork_Accept_r( &g_req ) >= 0 ) {
1009        if ( slow_script_msec ) {
1010            gettimeofday( &tv_req_begin, NULL );
1011        }
1012        ret = processReq(TSRMLS_C);
1013        if ( slow_script_msec ) {
1014            gettimeofday( &tv_req_end, NULL );
1015            n = ((long) tv_req_end.tv_sec - tv_req_begin.tv_sec ) * 1000
1016                + (tv_req_end.tv_usec - tv_req_begin.tv_usec) / 1000;
1017            if ( n > slow_script_msec )
1018            {
1019                strftime( time_buf, 30, "%d/%b/%Y:%H:%M:%S", localtime( &tv_req_end.tv_sec ) );
1020                fprintf( stderr, "[%s] Slow PHP script: %d ms\n  URL: %s %s\n  Query String: %s\n  Script: %s\n",
1021                         time_buf, n,  LSAPI_GetRequestMethod(),
1022                         LSAPI_GetScriptName(), LSAPI_GetQueryString(),
1023                         LSAPI_GetScriptFileName() );
1024
1025            }
1026        }
1027        LSAPI_Finish();
1028        if ( ret ) {
1029            break;
1030        }
1031    }
1032    php_module_shutdown(TSRMLS_C);
1033
1034#ifdef ZTS
1035    tsrm_shutdown();
1036#endif
1037    return ret;
1038}
1039
1040
1041/*   LiteSpeed PHP module starts here */
1042
1043/* {{{ arginfo */
1044ZEND_BEGIN_ARG_INFO(arginfo_litespeed__void, 0)
1045ZEND_END_ARG_INFO()
1046/* }}} */
1047
1048PHP_FUNCTION(litespeed_request_headers);
1049PHP_FUNCTION(litespeed_response_headers);
1050PHP_FUNCTION(apache_get_modules);
1051
1052PHP_MINFO_FUNCTION(litespeed);
1053
1054zend_function_entry litespeed_functions[] = {
1055    PHP_FE(litespeed_request_headers,   arginfo_litespeed__void)
1056    PHP_FE(litespeed_response_headers,  arginfo_litespeed__void)
1057    PHP_FE(apache_get_modules,          arginfo_litespeed__void)
1058    PHP_FALIAS(getallheaders,           litespeed_request_headers,  arginfo_litespeed__void)
1059    PHP_FALIAS(apache_request_headers,  litespeed_request_headers,  arginfo_litespeed__void)
1060    PHP_FALIAS(apache_response_headers, litespeed_response_headers, arginfo_litespeed__void)
1061    {NULL, NULL, NULL}
1062};
1063
1064static PHP_MINIT_FUNCTION(litespeed)
1065{
1066    /* REGISTER_INI_ENTRIES(); */
1067    return SUCCESS;
1068}
1069
1070
1071static PHP_MSHUTDOWN_FUNCTION(litespeed)
1072{
1073    /* UNREGISTER_INI_ENTRIES(); */
1074    return SUCCESS;
1075}
1076
1077zend_module_entry litespeed_module_entry = {
1078    STANDARD_MODULE_HEADER,
1079    "litespeed",
1080    litespeed_functions,
1081    PHP_MINIT(litespeed),
1082    PHP_MSHUTDOWN(litespeed),
1083    NULL,
1084    NULL,
1085    NULL,
1086    NO_VERSION_YET,
1087    STANDARD_MODULE_PROPERTIES
1088};
1089
1090static int add_associate_array( const char * pKey, int keyLen, const char * pValue, int valLen,
1091                         void * arg )
1092{
1093    add_assoc_string_ex( (zval *)arg, (char *)pKey, keyLen+1, (char *)pValue);
1094    return 1;
1095}
1096
1097
1098/* {{{ proto array litespeed_request_headers(void)
1099   Fetch all HTTP request headers */
1100PHP_FUNCTION(litespeed_request_headers)
1101{
1102    /* TODO: */
1103    if (ZEND_NUM_ARGS() > 0) {
1104        WRONG_PARAM_COUNT;
1105    }
1106    array_init(return_value);
1107
1108    LSAPI_ForeachOrgHeader( add_associate_array, return_value );
1109
1110}
1111/* }}} */
1112
1113
1114
1115/* {{{ proto array litespeed_response_headers(void)
1116   Fetch all HTTP response headers */
1117PHP_FUNCTION(litespeed_response_headers)
1118{
1119    sapi_header_struct  *h;
1120    zend_llist_position pos;
1121    char *       p;
1122    int          len;
1123    char         headerBuf[SAPI_LSAPI_MAX_HEADER_LENGTH];
1124
1125    if (ZEND_NUM_ARGS() > 0) {
1126        WRONG_PARAM_COUNT;
1127    }
1128
1129    if (!&SG(sapi_headers).headers) {
1130        RETURN_FALSE;
1131    }
1132    array_init(return_value);
1133
1134    h = zend_llist_get_first_ex(&SG(sapi_headers).headers, &pos);
1135    while (h) {
1136        if ( h->header_len > 0 ) {
1137            p = strchr( h->header, ':' );
1138            len = p - h->header;
1139            if (( p )&&( len > 0 )) {
1140                memmove( headerBuf, h->header, len );
1141                while( len > 0 && (isspace( headerBuf[len-1])) ) {
1142                    --len;
1143                }
1144                headerBuf[len] = 0;
1145                if ( len ) {
1146                    while( isspace(*++p));
1147                    add_assoc_string_ex(return_value, headerBuf, len+1, p);
1148                }
1149            }
1150        }
1151        h = zend_llist_get_next_ex(&SG(sapi_headers).headers, &pos);
1152    }
1153}
1154
1155/* }}} */
1156
1157
1158/* {{{ proto array apache_get_modules(void)
1159   Fetch all loaded module names  */
1160PHP_FUNCTION(apache_get_modules)
1161{
1162    /* TODO: */
1163    if (ZEND_NUM_ARGS() > 0) {
1164        WRONG_PARAM_COUNT;
1165    }
1166    array_init(return_value);
1167    add_next_index_string(return_value, "mod_rewrite");
1168    add_next_index_string(return_value, "mod_mime");
1169    add_next_index_string(return_value, "mod_headers");
1170    add_next_index_string(return_value, "mod_expires");
1171}
1172/* }}} */
1173
1174
1175/*
1176 * Local variables:
1177 * tab-width: 4
1178 * c-basic-offset: 4
1179 * End:
1180 * vim600: sw=4 ts=4 fdm=marker
1181 * vim<600: sw=4 ts=4
1182 */
1183
1184
1185