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