This source file includes following definitions.
- user_config_cache_entry_dtor
- print_module_info
- module_name_cmp
- print_modules
- print_extension_info
- extension_name_cmp
- print_extensions
- sapi_cgibin_single_write
- sapi_cgibin_ub_write
- sapi_cgibin_flush
- sapi_cgi_send_headers
- sapi_cgi_read_post
- sapi_cgibin_getenv
- _sapi_cgibin_putenv
- sapi_cgi_read_cookies
- cgi_php_import_environment_variables
- sapi_cgi_register_variables
- sapi_cgi_log_fastcgi
- sapi_cgi_log_message
- php_cgi_ini_activate_user_config
- sapi_cgi_activate
- sapi_cgi_deactivate
- php_cgi_startup
- php_cgi_usage
- is_valid_path
- init_request_info
- fastcgi_ini_parser
- PHP_INI_BEGIN
- PHP_MINIT_FUNCTION
- PHP_MSHUTDOWN_FUNCTION
- PHP_MINFO_FUNCTION
- PHP_FUNCTION
- main
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 #include "php.h"
27 #include "php_globals.h"
28 #include "php_variables.h"
29 #include "zend_modules.h"
30 #include "php.h"
31 #include "zend_ini_scanner.h"
32 #include "zend_globals.h"
33 #include "zend_stream.h"
34
35 #include "SAPI.h"
36
37 #include <stdio.h>
38 #include "php.h"
39
40 #ifdef PHP_WIN32
41 # include "win32/time.h"
42 # include "win32/signal.h"
43 # include <process.h>
44 #endif
45
46 #if HAVE_SYS_TIME_H
47 # include <sys/time.h>
48 #endif
49
50 #if HAVE_UNISTD_H
51 # include <unistd.h>
52 #endif
53
54 #if HAVE_SIGNAL_H
55 # include <signal.h>
56 #endif
57
58 #if HAVE_SETLOCALE
59 # include <locale.h>
60 #endif
61
62 #if HAVE_SYS_TYPES_H
63 # include <sys/types.h>
64 #endif
65
66 #if HAVE_SYS_WAIT_H
67 # include <sys/wait.h>
68 #endif
69
70 #if HAVE_FCNTL_H
71 # include <fcntl.h>
72 #endif
73
74 #include "zend.h"
75 #include "zend_extensions.h"
76 #include "php_ini.h"
77 #include "php_globals.h"
78 #include "php_main.h"
79 #include "fopen_wrappers.h"
80 #include "ext/standard/php_standard.h"
81
82 #ifdef PHP_WIN32
83 # include <io.h>
84 # include <fcntl.h>
85 # include "win32/php_registry.h"
86 #endif
87
88 #ifdef __riscos__
89 # include <unixlib/local.h>
90 int __riscosify_control = __RISCOSIFY_STRICT_UNIX_SPECS;
91 #endif
92
93 #include "zend_compile.h"
94 #include "zend_execute.h"
95 #include "zend_highlight.h"
96 #include "zend_indent.h"
97
98 #include "php_getopt.h"
99
100 #include "fastcgi.h"
101
102 #include <php_config.h>
103 #include "fpm.h"
104 #include "fpm_request.h"
105 #include "fpm_status.h"
106 #include "fpm_conf.h"
107 #include "fpm_php.h"
108 #include "fpm_log.h"
109 #include "zlog.h"
110
111 #ifndef PHP_WIN32
112
113 struct sigaction act, old_term, old_quit, old_int;
114 #endif
115
116 static void (*php_php_import_environment_variables)(zval *array_ptr TSRMLS_DC);
117
118 #ifndef PHP_WIN32
119
120
121
122
123
124 static int parent = 1;
125 #endif
126
127 static int request_body_fd;
128 static int fpm_is_running = 0;
129
130 static char *sapi_cgibin_getenv(char *name, size_t name_len TSRMLS_DC);
131 static void fastcgi_ini_parser(zval *arg1, zval *arg2, zval *arg3, int callback_type, void *arg TSRMLS_DC);
132
133 #define PHP_MODE_STANDARD 1
134 #define PHP_MODE_HIGHLIGHT 2
135 #define PHP_MODE_INDENT 3
136 #define PHP_MODE_LINT 4
137 #define PHP_MODE_STRIP 5
138
139 static char *php_optarg = NULL;
140 static int php_optind = 1;
141 static zend_module_entry cgi_module_entry;
142
143 static const opt_struct OPTIONS[] = {
144 {'c', 1, "php-ini"},
145 {'d', 1, "define"},
146 {'e', 0, "profile-info"},
147 {'h', 0, "help"},
148 {'i', 0, "info"},
149 {'m', 0, "modules"},
150 {'n', 0, "no-php-ini"},
151 {'?', 0, "usage"},
152 {'v', 0, "version"},
153 {'y', 1, "fpm-config"},
154 {'t', 0, "test"},
155 {'p', 1, "prefix"},
156 {'g', 1, "pid"},
157 {'R', 0, "allow-to-run-as-root"},
158 {'D', 0, "daemonize"},
159 {'F', 0, "nodaemonize"},
160 {'O', 0, "force-stderr"},
161 {'-', 0, NULL}
162 };
163
164 typedef struct _php_cgi_globals_struct {
165 zend_bool rfc2616_headers;
166 zend_bool nph;
167 zend_bool fix_pathinfo;
168 zend_bool force_redirect;
169 zend_bool discard_path;
170 zend_bool fcgi_logging;
171 char *redirect_status_env;
172 HashTable user_config_cache;
173 char *error_header;
174 char *fpm_config;
175 } php_cgi_globals_struct;
176
177
178
179
180
181
182
183
184
185
186 typedef struct _user_config_cache_entry {
187 time_t expires;
188 HashTable *user_config;
189 } user_config_cache_entry;
190
191 static void user_config_cache_entry_dtor(user_config_cache_entry *entry)
192 {
193 zend_hash_destroy(entry->user_config);
194 free(entry->user_config);
195 }
196
197
198 #ifdef ZTS
199 static int php_cgi_globals_id;
200 #define CGIG(v) TSRMG(php_cgi_globals_id, php_cgi_globals_struct *, v)
201 #else
202 static php_cgi_globals_struct php_cgi_globals;
203 #define CGIG(v) (php_cgi_globals.v)
204 #endif
205
206 #ifdef PHP_WIN32
207 #define TRANSLATE_SLASHES(path) \
208 { \
209 char *tmp = path; \
210 while (*tmp) { \
211 if (*tmp == '\\') *tmp = '/'; \
212 tmp++; \
213 } \
214 }
215 #else
216 #define TRANSLATE_SLASHES(path)
217 #endif
218
219 static int print_module_info(zend_module_entry *module, void *arg TSRMLS_DC)
220 {
221 php_printf("%s\n", module->name);
222 return 0;
223 }
224
225 static int module_name_cmp(const void *a, const void *b TSRMLS_DC)
226 {
227 Bucket *f = *((Bucket **) a);
228 Bucket *s = *((Bucket **) b);
229
230 return strcasecmp( ((zend_module_entry *)f->pData)->name,
231 ((zend_module_entry *)s->pData)->name);
232 }
233
234 static void print_modules(TSRMLS_D)
235 {
236 HashTable sorted_registry;
237 zend_module_entry tmp;
238
239 zend_hash_init(&sorted_registry, 50, NULL, NULL, 1);
240 zend_hash_copy(&sorted_registry, &module_registry, NULL, &tmp, sizeof(zend_module_entry));
241 zend_hash_sort(&sorted_registry, zend_qsort, module_name_cmp, 0 TSRMLS_CC);
242 zend_hash_apply_with_argument(&sorted_registry, (apply_func_arg_t) print_module_info, NULL TSRMLS_CC);
243 zend_hash_destroy(&sorted_registry);
244 }
245
246 static int print_extension_info(zend_extension *ext, void *arg TSRMLS_DC)
247 {
248 php_printf("%s\n", ext->name);
249 return 0;
250 }
251
252 static int extension_name_cmp(const zend_llist_element **f, const zend_llist_element **s TSRMLS_DC)
253 {
254 return strcmp( ((zend_extension *)(*f)->data)->name,
255 ((zend_extension *)(*s)->data)->name);
256 }
257
258 static void print_extensions(TSRMLS_D)
259 {
260 zend_llist sorted_exts;
261
262 zend_llist_copy(&sorted_exts, &zend_extensions);
263 sorted_exts.dtor = NULL;
264 zend_llist_sort(&sorted_exts, extension_name_cmp TSRMLS_CC);
265 zend_llist_apply_with_argument(&sorted_exts, (llist_apply_with_arg_func_t) print_extension_info, NULL TSRMLS_CC);
266 zend_llist_destroy(&sorted_exts);
267 }
268
269 #ifndef STDOUT_FILENO
270 #define STDOUT_FILENO 1
271 #endif
272
273 static inline size_t sapi_cgibin_single_write(const char *str, uint str_length TSRMLS_DC)
274 {
275 ssize_t ret;
276
277
278 if (fpm_is_running) {
279 fcgi_request *request = (fcgi_request*) SG(server_context);
280 ret = fcgi_write(request, FCGI_STDOUT, str, str_length);
281 if (ret <= 0) {
282 return 0;
283 }
284 return (size_t)ret;
285 }
286
287
288 #ifdef PHP_WRITE_STDOUT
289 ret = write(STDOUT_FILENO, str, str_length);
290 if (ret <= 0) {
291 return 0;
292 }
293 return (size_t)ret;
294 #else
295 return fwrite(str, 1, MIN(str_length, 16384), stdout);
296 #endif
297 }
298
299 static int sapi_cgibin_ub_write(const char *str, uint str_length TSRMLS_DC)
300 {
301 const char *ptr = str;
302 uint remaining = str_length;
303 size_t ret;
304
305 while (remaining > 0) {
306 ret = sapi_cgibin_single_write(ptr, remaining TSRMLS_CC);
307 if (!ret) {
308 php_handle_aborted_connection();
309 return str_length - remaining;
310 }
311 ptr += ret;
312 remaining -= ret;
313 }
314
315 return str_length;
316 }
317
318
319 static void sapi_cgibin_flush(void *server_context)
320 {
321
322 if (fpm_is_running) {
323 fcgi_request *request = (fcgi_request*) server_context;
324 if (
325 #ifndef PHP_WIN32
326 !parent &&
327 #endif
328 request && !fcgi_flush(request, 0)) {
329 php_handle_aborted_connection();
330 }
331 return;
332 }
333
334
335 if (fflush(stdout) == EOF) {
336 php_handle_aborted_connection();
337 }
338 }
339
340 #define SAPI_CGI_MAX_HEADER_LENGTH 1024
341
342 typedef struct _http_error {
343 int code;
344 const char* msg;
345 } http_error;
346
347 static const http_error http_error_codes[] = {
348 {100, "Continue"},
349 {101, "Switching Protocols"},
350 {200, "OK"},
351 {201, "Created"},
352 {202, "Accepted"},
353 {203, "Non-Authoritative Information"},
354 {204, "No Content"},
355 {205, "Reset Content"},
356 {206, "Partial Content"},
357 {300, "Multiple Choices"},
358 {301, "Moved Permanently"},
359 {302, "Moved Temporarily"},
360 {303, "See Other"},
361 {304, "Not Modified"},
362 {305, "Use Proxy"},
363 {400, "Bad Request"},
364 {401, "Unauthorized"},
365 {402, "Payment Required"},
366 {403, "Forbidden"},
367 {404, "Not Found"},
368 {405, "Method Not Allowed"},
369 {406, "Not Acceptable"},
370 {407, "Proxy Authentication Required"},
371 {408, "Request Time-out"},
372 {409, "Conflict"},
373 {410, "Gone"},
374 {411, "Length Required"},
375 {412, "Precondition Failed"},
376 {413, "Request Entity Too Large"},
377 {414, "Request-URI Too Large"},
378 {415, "Unsupported Media Type"},
379 {428, "Precondition Required"},
380 {429, "Too Many Requests"},
381 {431, "Request Header Fields Too Large"},
382 {451, "Unavailable For Legal Reasons"},
383 {500, "Internal Server Error"},
384 {501, "Not Implemented"},
385 {502, "Bad Gateway"},
386 {503, "Service Unavailable"},
387 {504, "Gateway Time-out"},
388 {505, "HTTP Version not supported"},
389 {511, "Network Authentication Required"},
390 {0, NULL}
391 };
392
393 static int sapi_cgi_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
394 {
395 char buf[SAPI_CGI_MAX_HEADER_LENGTH];
396 sapi_header_struct *h;
397 zend_llist_position pos;
398 zend_bool ignore_status = 0;
399 int response_status = SG(sapi_headers).http_response_code;
400
401 if (SG(request_info).no_headers == 1) {
402 return SAPI_HEADER_SENT_SUCCESSFULLY;
403 }
404
405 if (CGIG(nph) || SG(sapi_headers).http_response_code != 200)
406 {
407 int len;
408 zend_bool has_status = 0;
409
410 if (CGIG(rfc2616_headers) && SG(sapi_headers).http_status_line) {
411 char *s;
412 len = slprintf(buf, SAPI_CGI_MAX_HEADER_LENGTH, "%s\r\n", SG(sapi_headers).http_status_line);
413 if ((s = strchr(SG(sapi_headers).http_status_line, ' '))) {
414 response_status = atoi((s + 1));
415 }
416
417 if (len > SAPI_CGI_MAX_HEADER_LENGTH) {
418 len = SAPI_CGI_MAX_HEADER_LENGTH;
419 }
420
421 } else {
422 char *s;
423
424 if (SG(sapi_headers).http_status_line &&
425 (s = strchr(SG(sapi_headers).http_status_line, ' ')) != 0 &&
426 (s - SG(sapi_headers).http_status_line) >= 5 &&
427 strncasecmp(SG(sapi_headers).http_status_line, "HTTP/", 5) == 0
428 ) {
429 len = slprintf(buf, sizeof(buf), "Status:%s\r\n", s);
430 response_status = atoi((s + 1));
431 } else {
432 h = (sapi_header_struct*)zend_llist_get_first_ex(&sapi_headers->headers, &pos);
433 while (h) {
434 if (h->header_len > sizeof("Status:") - 1 &&
435 strncasecmp(h->header, "Status:", sizeof("Status:") - 1) == 0
436 ) {
437 has_status = 1;
438 break;
439 }
440 h = (sapi_header_struct*)zend_llist_get_next_ex(&sapi_headers->headers, &pos);
441 }
442 if (!has_status) {
443 http_error *err = (http_error*)http_error_codes;
444
445 while (err->code != 0) {
446 if (err->code == SG(sapi_headers).http_response_code) {
447 break;
448 }
449 err++;
450 }
451 if (err->msg) {
452 len = slprintf(buf, sizeof(buf), "Status: %d %s\r\n", SG(sapi_headers).http_response_code, err->msg);
453 } else {
454 len = slprintf(buf, sizeof(buf), "Status: %d\r\n", SG(sapi_headers).http_response_code);
455 }
456 }
457 }
458 }
459
460 if (!has_status) {
461 PHPWRITE_H(buf, len);
462 ignore_status = 1;
463 }
464 }
465
466 h = (sapi_header_struct*)zend_llist_get_first_ex(&sapi_headers->headers, &pos);
467 while (h) {
468
469 if (h->header_len) {
470 if (h->header_len > sizeof("Status:") - 1 &&
471 strncasecmp(h->header, "Status:", sizeof("Status:") - 1) == 0
472 ) {
473 if (!ignore_status) {
474 ignore_status = 1;
475 PHPWRITE_H(h->header, h->header_len);
476 PHPWRITE_H("\r\n", 2);
477 }
478 } else if (response_status == 304 && h->header_len > sizeof("Content-Type:") - 1 &&
479 strncasecmp(h->header, "Content-Type:", sizeof("Content-Type:") - 1) == 0
480 ) {
481 h = (sapi_header_struct*)zend_llist_get_next_ex(&sapi_headers->headers, &pos);
482 continue;
483 } else {
484 PHPWRITE_H(h->header, h->header_len);
485 PHPWRITE_H("\r\n", 2);
486 }
487 }
488 h = (sapi_header_struct*)zend_llist_get_next_ex(&sapi_headers->headers, &pos);
489 }
490 PHPWRITE_H("\r\n", 2);
491
492 return SAPI_HEADER_SENT_SUCCESSFULLY;
493 }
494
495 #ifndef STDIN_FILENO
496 # define STDIN_FILENO 0
497 #endif
498
499 static int sapi_cgi_read_post(char *buffer, uint count_bytes TSRMLS_DC)
500 {
501 uint read_bytes = 0;
502 int tmp_read_bytes;
503 size_t remaining = SG(request_info).content_length - SG(read_post_bytes);
504
505 if (remaining < count_bytes) {
506 count_bytes = remaining;
507 }
508 while (read_bytes < count_bytes) {
509 fcgi_request *request = (fcgi_request*) SG(server_context);
510 if (request_body_fd == -1) {
511 char *request_body_filename = sapi_cgibin_getenv((char *) "REQUEST_BODY_FILE",
512 sizeof("REQUEST_BODY_FILE") - 1 TSRMLS_CC);
513
514 if (request_body_filename && *request_body_filename) {
515 request_body_fd = open(request_body_filename, O_RDONLY);
516
517 if (0 > request_body_fd) {
518 php_error(E_WARNING, "REQUEST_BODY_FILE: open('%s') failed: %s (%d)",
519 request_body_filename, strerror(errno), errno);
520 return 0;
521 }
522 }
523 }
524
525
526 if (request_body_fd < 0) {
527 tmp_read_bytes = fcgi_read(request, buffer + read_bytes, count_bytes - read_bytes);
528 } else {
529 tmp_read_bytes = read(request_body_fd, buffer + read_bytes, count_bytes - read_bytes);
530 }
531 if (tmp_read_bytes <= 0) {
532 break;
533 }
534 read_bytes += tmp_read_bytes;
535 }
536 return read_bytes;
537 }
538
539 static char *sapi_cgibin_getenv(char *name, size_t name_len TSRMLS_DC)
540 {
541
542 if (fpm_is_running) {
543 fcgi_request *request = (fcgi_request*) SG(server_context);
544 return fcgi_getenv(request, name, name_len);
545 }
546
547
548 return getenv(name);
549 }
550
551 static char *_sapi_cgibin_putenv(char *name, char *value TSRMLS_DC)
552 {
553 int name_len;
554
555 if (!name) {
556 return NULL;
557 }
558 name_len = strlen(name);
559
560 fcgi_request *request = (fcgi_request*) SG(server_context);
561 return fcgi_putenv(request, name, name_len, value);
562 }
563
564 static char *sapi_cgi_read_cookies(TSRMLS_D)
565 {
566 return sapi_cgibin_getenv((char *) "HTTP_COOKIE", sizeof("HTTP_COOKIE") - 1 TSRMLS_CC);
567 }
568
569 void cgi_php_import_environment_variables(zval *array_ptr TSRMLS_DC)
570 {
571 fcgi_request *request;
572 HashPosition pos;
573 char *var, **val;
574 uint var_len;
575 ulong idx;
576 int filter_arg;
577
578
579 if (PG(http_globals)[TRACK_VARS_ENV] &&
580 array_ptr != PG(http_globals)[TRACK_VARS_ENV] &&
581 Z_TYPE_P(PG(http_globals)[TRACK_VARS_ENV]) == IS_ARRAY &&
582 zend_hash_num_elements(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_ENV])) > 0
583 ) {
584 zval_dtor(array_ptr);
585 *array_ptr = *PG(http_globals)[TRACK_VARS_ENV];
586 INIT_PZVAL(array_ptr);
587 zval_copy_ctor(array_ptr);
588 return;
589 } else if (PG(http_globals)[TRACK_VARS_SERVER] &&
590 array_ptr != PG(http_globals)[TRACK_VARS_SERVER] &&
591 Z_TYPE_P(PG(http_globals)[TRACK_VARS_SERVER]) == IS_ARRAY &&
592 zend_hash_num_elements(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_SERVER])) > 0
593 ) {
594 zval_dtor(array_ptr);
595 *array_ptr = *PG(http_globals)[TRACK_VARS_SERVER];
596 INIT_PZVAL(array_ptr);
597 zval_copy_ctor(array_ptr);
598 return;
599 }
600
601
602 php_php_import_environment_variables(array_ptr TSRMLS_CC);
603
604 request = (fcgi_request*) SG(server_context);
605 filter_arg = (array_ptr == PG(http_globals)[TRACK_VARS_ENV])?PARSE_ENV:PARSE_SERVER;
606
607 for (zend_hash_internal_pointer_reset_ex(request->env, &pos);
608 zend_hash_get_current_key_ex(request->env, &var, &var_len, &idx, 0, &pos) == HASH_KEY_IS_STRING &&
609 zend_hash_get_current_data_ex(request->env, (void **) &val, &pos) == SUCCESS;
610 zend_hash_move_forward_ex(request->env, &pos)
611 ) {
612 unsigned int new_val_len;
613
614 if (sapi_module.input_filter(filter_arg, var, val, strlen(*val), &new_val_len TSRMLS_CC)) {
615 php_register_variable_safe(var, *val, new_val_len, array_ptr TSRMLS_CC);
616 }
617 }
618 }
619
620 static void sapi_cgi_register_variables(zval *track_vars_array TSRMLS_DC)
621 {
622 unsigned int php_self_len;
623 char *php_self;
624
625
626
627
628 php_import_environment_variables(track_vars_array TSRMLS_CC);
629
630 if (CGIG(fix_pathinfo)) {
631 char *script_name = SG(request_info).request_uri;
632 unsigned int script_name_len = script_name ? strlen(script_name) : 0;
633 char *path_info = sapi_cgibin_getenv("PATH_INFO", sizeof("PATH_INFO") - 1 TSRMLS_CC);
634 unsigned int path_info_len = path_info ? strlen(path_info) : 0;
635
636 php_self_len = script_name_len + path_info_len;
637 php_self = emalloc(php_self_len + 1);
638
639
640 if (script_name) {
641 memcpy(php_self, script_name, script_name_len + 1);
642 }
643 if (path_info) {
644 memcpy(php_self + script_name_len, path_info, path_info_len + 1);
645 }
646
647
648 if (sapi_module.input_filter(PARSE_SERVER, "PHP_SELF", &php_self, php_self_len, &php_self_len TSRMLS_CC)) {
649 php_register_variable_safe("PHP_SELF", php_self, php_self_len, track_vars_array TSRMLS_CC);
650 }
651 efree(php_self);
652 } else {
653 php_self = SG(request_info).request_uri ? SG(request_info).request_uri : "";
654 php_self_len = strlen(php_self);
655 if (sapi_module.input_filter(PARSE_SERVER, "PHP_SELF", &php_self, php_self_len, &php_self_len TSRMLS_CC)) {
656 php_register_variable_safe("PHP_SELF", php_self, php_self_len, track_vars_array TSRMLS_CC);
657 }
658 }
659 }
660
661
662
663
664
665 void sapi_cgi_log_fastcgi(int level, char *message, size_t len)
666 {
667 TSRMLS_FETCH();
668
669 fcgi_request *request = (fcgi_request*) SG(server_context);
670
671
672
673
674
675
676 if (CGIG(fcgi_logging) && request && message && len > 0) {
677 ssize_t ret;
678 char *buf = malloc(len + 2);
679 memcpy(buf, message, len);
680 memcpy(buf + len, "\n", sizeof("\n"));
681 ret = fcgi_write(request, FCGI_STDERR, buf, len + 1);
682 free(buf);
683 if (ret < 0) {
684 php_handle_aborted_connection();
685 }
686 }
687 }
688
689
690
691
692 static void sapi_cgi_log_message(char *message)
693 {
694 zlog(ZLOG_NOTICE, "PHP message: %s", message);
695 }
696
697
698
699
700 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)
701 {
702 char *ptr;
703 user_config_cache_entry *new_entry, *entry;
704 time_t request_time = sapi_get_request_time(TSRMLS_C);
705
706
707 if (zend_hash_find(&CGIG(user_config_cache), path, path_len + 1, (void **) &entry) == FAILURE) {
708 new_entry = pemalloc(sizeof(user_config_cache_entry), 1);
709 new_entry->expires = 0;
710 new_entry->user_config = (HashTable *) pemalloc(sizeof(HashTable), 1);
711 zend_hash_init(new_entry->user_config, 0, NULL, (dtor_func_t) config_zval_dtor, 1);
712 zend_hash_update(&CGIG(user_config_cache), path, path_len + 1, new_entry, sizeof(user_config_cache_entry), (void **) &entry);
713 free(new_entry);
714 }
715
716
717 if (request_time > entry->expires) {
718 char * real_path;
719 int real_path_len;
720 char *s1, *s2;
721 int s_len;
722
723
724 zend_hash_clean(entry->user_config);
725
726 if (!IS_ABSOLUTE_PATH(path, path_len)) {
727 real_path = tsrm_realpath(path, NULL TSRMLS_CC);
728 if (real_path == NULL) {
729 return;
730 }
731 real_path_len = strlen(real_path);
732 path = real_path;
733 path_len = real_path_len;
734 }
735
736 if (path_len > doc_root_len) {
737 s1 = (char *) doc_root;
738 s2 = path;
739 s_len = doc_root_len;
740 } else {
741 s1 = path;
742 s2 = (char *) doc_root;
743 s_len = path_len;
744 }
745
746
747
748
749
750 #ifdef PHP_WIN32
751 if (strnicmp(s1, s2, s_len) == 0) {
752 #else
753 if (strncmp(s1, s2, s_len) == 0) {
754 #endif
755 ptr = s2 + start;
756 while ((ptr = strchr(ptr, DEFAULT_SLASH)) != NULL) {
757 *ptr = 0;
758 php_parse_user_ini_file(path, PG(user_ini_filename), entry->user_config TSRMLS_CC);
759 *ptr = '/';
760 ptr++;
761 }
762 } else {
763 php_parse_user_ini_file(path, PG(user_ini_filename), entry->user_config TSRMLS_CC);
764 }
765
766 entry->expires = request_time + PG(user_ini_cache_ttl);
767 }
768
769
770 php_ini_activate_config(entry->user_config, PHP_INI_PERDIR, PHP_INI_STAGE_HTACCESS TSRMLS_CC);
771 }
772
773
774 static int sapi_cgi_activate(TSRMLS_D)
775 {
776 char *path, *doc_root, *server_name;
777 uint path_len, doc_root_len, server_name_len;
778
779
780 if (!SG(request_info).path_translated) {
781 return FAILURE;
782 }
783
784 if (php_ini_has_per_host_config()) {
785
786 server_name = sapi_cgibin_getenv("SERVER_NAME", sizeof("SERVER_NAME") - 1 TSRMLS_CC);
787
788 if (server_name) {
789 server_name_len = strlen(server_name);
790 server_name = estrndup(server_name, server_name_len);
791 zend_str_tolower(server_name, server_name_len);
792 php_ini_activate_per_host_config(server_name, server_name_len + 1 TSRMLS_CC);
793 efree(server_name);
794 }
795 }
796
797 if (php_ini_has_per_dir_config() ||
798 (PG(user_ini_filename) && *PG(user_ini_filename))
799 ) {
800
801 path_len = strlen(SG(request_info).path_translated);
802
803
804 if (!IS_SLASH(SG(request_info).path_translated[path_len])) {
805 path = emalloc(path_len + 2);
806 memcpy(path, SG(request_info).path_translated, path_len + 1);
807 path_len = zend_dirname(path, path_len);
808 path[path_len++] = DEFAULT_SLASH;
809 } else {
810 path = estrndup(SG(request_info).path_translated, path_len);
811 path_len = zend_dirname(path, path_len);
812 }
813 path[path_len] = 0;
814
815
816 php_ini_activate_per_dir_config(path, path_len TSRMLS_CC);
817
818
819 if (PG(user_ini_filename) && *PG(user_ini_filename)) {
820 doc_root = sapi_cgibin_getenv("DOCUMENT_ROOT", sizeof("DOCUMENT_ROOT") - 1 TSRMLS_CC);
821
822 if (doc_root) {
823 doc_root_len = strlen(doc_root);
824 if (doc_root_len > 0 && IS_SLASH(doc_root[doc_root_len - 1])) {
825 --doc_root_len;
826 }
827 #ifdef PHP_WIN32
828
829 doc_root = estrndup(doc_root, doc_root_len);
830 zend_str_tolower(doc_root, doc_root_len);
831 #endif
832 php_cgi_ini_activate_user_config(path, path_len, doc_root, doc_root_len, doc_root_len - 1 TSRMLS_CC);
833 }
834 }
835
836 #ifdef PHP_WIN32
837 efree(doc_root);
838 #endif
839 efree(path);
840 }
841
842 return SUCCESS;
843 }
844
845 static int sapi_cgi_deactivate(TSRMLS_D)
846 {
847
848
849
850
851 if (SG(sapi_started)) {
852 if (
853 #ifndef PHP_WIN32
854 !parent &&
855 #endif
856 !fcgi_finish_request((fcgi_request*)SG(server_context), 0)) {
857 php_handle_aborted_connection();
858 }
859 }
860 return SUCCESS;
861 }
862
863 static int php_cgi_startup(sapi_module_struct *sapi_module)
864 {
865 if (php_module_startup(sapi_module, &cgi_module_entry, 1) == FAILURE) {
866 return FAILURE;
867 }
868 return SUCCESS;
869 }
870
871
872
873 static sapi_module_struct cgi_sapi_module = {
874 "fpm-fcgi",
875 "FPM/FastCGI",
876
877 php_cgi_startup,
878 php_module_shutdown_wrapper,
879
880 sapi_cgi_activate,
881 sapi_cgi_deactivate,
882
883 sapi_cgibin_ub_write,
884 sapi_cgibin_flush,
885 NULL,
886 sapi_cgibin_getenv,
887
888 php_error,
889
890 NULL,
891 sapi_cgi_send_headers,
892 NULL,
893
894 sapi_cgi_read_post,
895 sapi_cgi_read_cookies,
896
897 sapi_cgi_register_variables,
898 sapi_cgi_log_message,
899 NULL,
900 NULL,
901
902 STANDARD_SAPI_MODULE_PROPERTIES
903 };
904
905
906
907 ZEND_BEGIN_ARG_INFO(arginfo_dl, 0)
908 ZEND_ARG_INFO(0, extension_filename)
909 ZEND_END_ARG_INFO()
910
911
912 static const zend_function_entry additional_functions[] = {
913 ZEND_FE(dl, arginfo_dl)
914 {NULL, NULL, NULL}
915 };
916
917
918
919 static void php_cgi_usage(char *argv0)
920 {
921 char *prog;
922
923 prog = strrchr(argv0, '/');
924 if (prog) {
925 prog++;
926 } else {
927 prog = "php";
928 }
929
930 php_printf( "Usage: %s [-n] [-e] [-h] [-i] [-m] [-v] [-t] [-p <prefix>] [-g <pid>] [-c <file>] [-d foo[=bar]] [-y <file>] [-D] [-F [-O]]\n"
931 " -c <path>|<file> Look for php.ini file in this directory\n"
932 " -n No php.ini file will be used\n"
933 " -d foo[=bar] Define INI entry foo with value 'bar'\n"
934 " -e Generate extended information for debugger/profiler\n"
935 " -h This help\n"
936 " -i PHP information\n"
937 " -m Show compiled in modules\n"
938 " -v Version number\n"
939 " -p, --prefix <dir>\n"
940 " Specify alternative prefix path to FastCGI process manager (default: %s).\n"
941 " -g, --pid <file>\n"
942 " Specify the PID file location.\n"
943 " -y, --fpm-config <file>\n"
944 " Specify alternative path to FastCGI process manager config file.\n"
945 " -t, --test Test FPM configuration and exit\n"
946 " -D, --daemonize force to run in background, and ignore daemonize option from config file\n"
947 " -F, --nodaemonize\n"
948 " force to stay in foreground, and ignore daemonize option from config file\n"
949 " -O, --force-stderr\n"
950 " force output to stderr in nodaemonize even if stderr is not a TTY\n"
951 " -R, --allow-to-run-as-root\n"
952 " Allow pool to run as root (disabled by default)\n",
953 prog, PHP_PREFIX);
954 }
955
956
957
958
959
960
961
962 static int is_valid_path(const char *path)
963 {
964 const char *p;
965
966 if (!path) {
967 return 0;
968 }
969 p = strstr(path, "..");
970 if (p) {
971 if ((p == path || IS_SLASH(*(p-1))) &&
972 (*(p+2) == 0 || IS_SLASH(*(p+2)))
973 ) {
974 return 0;
975 }
976 while (1) {
977 p = strstr(p+1, "..");
978 if (!p) {
979 break;
980 }
981 if (IS_SLASH(*(p-1)) &&
982 (*(p+2) == 0 || IS_SLASH(*(p+2)))
983 ) {
984 return 0;
985 }
986 }
987 }
988 return 1;
989 }
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058 static void init_request_info(TSRMLS_D)
1059 {
1060 char *env_script_filename = sapi_cgibin_getenv("SCRIPT_FILENAME", sizeof("SCRIPT_FILENAME") - 1 TSRMLS_CC);
1061 char *env_path_translated = sapi_cgibin_getenv("PATH_TRANSLATED", sizeof("PATH_TRANSLATED") - 1 TSRMLS_CC);
1062 char *script_path_translated = env_script_filename;
1063 char *ini;
1064 int apache_was_here = 0;
1065
1066
1067
1068
1069 if (!script_path_translated && env_path_translated) {
1070 script_path_translated = env_path_translated;
1071 }
1072
1073
1074 SG(request_info).path_translated = NULL;
1075 SG(request_info).request_method = NULL;
1076 SG(request_info).proto_num = 1000;
1077 SG(request_info).query_string = NULL;
1078 SG(request_info).request_uri = NULL;
1079 SG(request_info).content_type = NULL;
1080 SG(request_info).content_length = 0;
1081 SG(sapi_headers).http_response_code = 200;
1082
1083
1084
1085
1086
1087 if (script_path_translated) {
1088 const char *auth;
1089 char *content_length = sapi_cgibin_getenv("CONTENT_LENGTH", sizeof("CONTENT_LENGTH") - 1 TSRMLS_CC);
1090 char *content_type = sapi_cgibin_getenv("CONTENT_TYPE", sizeof("CONTENT_TYPE") - 1 TSRMLS_CC);
1091 char *env_path_info = sapi_cgibin_getenv("PATH_INFO", sizeof("PATH_INFO") - 1 TSRMLS_CC);
1092 char *env_script_name = sapi_cgibin_getenv("SCRIPT_NAME", sizeof("SCRIPT_NAME") - 1 TSRMLS_CC);
1093
1094
1095 char *env_server_software = sapi_cgibin_getenv("SERVER_SOFTWARE", sizeof("SERVER_SOFTWARE") - 1 TSRMLS_CC);
1096 if (env_server_software &&
1097 env_script_name &&
1098 env_path_info &&
1099 strncmp(env_server_software, "Microsoft-IIS", sizeof("Microsoft-IIS") - 1) == 0 &&
1100 strncmp(env_path_info, env_script_name, strlen(env_script_name)) == 0
1101 ) {
1102 env_path_info = _sapi_cgibin_putenv("ORIG_PATH_INFO", env_path_info TSRMLS_CC);
1103 env_path_info += strlen(env_script_name);
1104 if (*env_path_info == 0) {
1105 env_path_info = NULL;
1106 }
1107 env_path_info = _sapi_cgibin_putenv("PATH_INFO", env_path_info TSRMLS_CC);
1108 }
1109
1110 #define APACHE_PROXY_FCGI_PREFIX "proxy:fcgi://"
1111 #define APACHE_PROXY_BALANCER_PREFIX "proxy:balancer://"
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121 if (env_script_filename &&
1122 strncasecmp(env_script_filename, APACHE_PROXY_FCGI_PREFIX, sizeof(APACHE_PROXY_FCGI_PREFIX) - 1) == 0) {
1123
1124 char *p = env_script_filename + (sizeof(APACHE_PROXY_FCGI_PREFIX) - 1);
1125 while (*p != '\0' && *p != '/') {
1126 p++;
1127 }
1128 if (*p != '\0') {
1129
1130
1131
1132 memmove(env_script_filename, p, strlen(p) + 1);
1133 apache_was_here = 1;
1134 }
1135
1136 p = strchr(env_script_filename, '?');
1137 if (p) {
1138 *p =0;
1139 }
1140 }
1141
1142 if (env_script_filename &&
1143 strncasecmp(env_script_filename, APACHE_PROXY_BALANCER_PREFIX, sizeof(APACHE_PROXY_BALANCER_PREFIX) - 1) == 0) {
1144
1145 char *p = env_script_filename + (sizeof(APACHE_PROXY_BALANCER_PREFIX) - 1);
1146 while (*p != '\0' && *p != '/') {
1147 p++;
1148 }
1149 if (*p != '\0') {
1150
1151
1152
1153 memmove(env_script_filename, p, strlen(p) + 1);
1154 apache_was_here = 1;
1155 }
1156
1157 p = strchr(env_script_filename, '?');
1158 if (p) {
1159 *p =0;
1160 }
1161 }
1162
1163 if (CGIG(fix_pathinfo)) {
1164 struct stat st;
1165 char *real_path = NULL;
1166 char *env_redirect_url = sapi_cgibin_getenv("REDIRECT_URL", sizeof("REDIRECT_URL") - 1 TSRMLS_CC);
1167 char *env_document_root = sapi_cgibin_getenv("DOCUMENT_ROOT", sizeof("DOCUMENT_ROOT") - 1 TSRMLS_CC);
1168 char *orig_path_translated = env_path_translated;
1169 char *orig_path_info = env_path_info;
1170 char *orig_script_name = env_script_name;
1171 char *orig_script_filename = env_script_filename;
1172 int script_path_translated_len;
1173
1174 if (!env_document_root && PG(doc_root)) {
1175 env_document_root = _sapi_cgibin_putenv("DOCUMENT_ROOT", PG(doc_root) TSRMLS_CC);
1176
1177 TRANSLATE_SLASHES(env_document_root);
1178 }
1179
1180 if (!apache_was_here && env_path_translated != NULL && env_redirect_url != NULL &&
1181 env_path_translated != script_path_translated &&
1182 strcmp(env_path_translated, script_path_translated) != 0) {
1183
1184
1185
1186
1187
1188
1189
1190
1191 script_path_translated = env_path_translated;
1192
1193 env_script_name = env_redirect_url;
1194 }
1195
1196 #ifdef __riscos__
1197
1198 __riscosify_control |= __RISCOSIFY_DONT_CHECK_DIR;
1199 script_path_translated = __unixify(script_path_translated, 0, NULL, 1, 0);
1200 #endif
1201
1202
1203
1204
1205
1206
1207 if (script_path_translated &&
1208 (script_path_translated_len = strlen(script_path_translated)) > 0 &&
1209 (script_path_translated[script_path_translated_len-1] == '/' ||
1210 #ifdef PHP_WIN32
1211 script_path_translated[script_path_translated_len-1] == '\\' ||
1212 #endif
1213 (real_path = tsrm_realpath(script_path_translated, NULL TSRMLS_CC)) == NULL)
1214 ) {
1215 char *pt = estrndup(script_path_translated, script_path_translated_len);
1216 int len = script_path_translated_len;
1217 char *ptr;
1218
1219 if (pt) {
1220 while ((ptr = strrchr(pt, '/')) || (ptr = strrchr(pt, '\\'))) {
1221 *ptr = 0;
1222 if (stat(pt, &st) == 0 && S_ISREG(st.st_mode)) {
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238 int ptlen = strlen(pt);
1239 int slen = len - ptlen;
1240 int pilen = env_path_info ? strlen(env_path_info) : 0;
1241 int tflag = 0;
1242 char *path_info;
1243 if (apache_was_here) {
1244
1245 path_info = script_path_translated + ptlen;
1246 tflag = (slen != 0 && (!orig_path_info || strcmp(orig_path_info, path_info) != 0));
1247 } else {
1248 path_info = env_path_info ? env_path_info + pilen - slen : NULL;
1249 tflag = (orig_path_info != path_info);
1250 }
1251
1252 if (tflag) {
1253 if (orig_path_info) {
1254 char old;
1255
1256 _sapi_cgibin_putenv("ORIG_PATH_INFO", orig_path_info TSRMLS_CC);
1257 old = path_info[0];
1258 path_info[0] = 0;
1259 if (!orig_script_name ||
1260 strcmp(orig_script_name, env_path_info) != 0) {
1261 if (orig_script_name) {
1262 _sapi_cgibin_putenv("ORIG_SCRIPT_NAME", orig_script_name TSRMLS_CC);
1263 }
1264 SG(request_info).request_uri = _sapi_cgibin_putenv("SCRIPT_NAME", env_path_info TSRMLS_CC);
1265 } else {
1266 SG(request_info).request_uri = orig_script_name;
1267 }
1268 path_info[0] = old;
1269 } else if (apache_was_here && env_script_name) {
1270
1271
1272
1273
1274 int snlen = strlen(env_script_name);
1275 if (snlen>slen && !strcmp(env_script_name+snlen-slen, path_info)) {
1276 _sapi_cgibin_putenv("ORIG_SCRIPT_NAME", orig_script_name TSRMLS_CC);
1277 env_script_name[snlen-slen] = 0;
1278 SG(request_info).request_uri = _sapi_cgibin_putenv("SCRIPT_NAME", env_script_name TSRMLS_CC);
1279 }
1280 }
1281 env_path_info = _sapi_cgibin_putenv("PATH_INFO", path_info TSRMLS_CC);
1282 }
1283 if (!orig_script_filename ||
1284 strcmp(orig_script_filename, pt) != 0) {
1285 if (orig_script_filename) {
1286 _sapi_cgibin_putenv("ORIG_SCRIPT_FILENAME", orig_script_filename TSRMLS_CC);
1287 }
1288 script_path_translated = _sapi_cgibin_putenv("SCRIPT_FILENAME", pt TSRMLS_CC);
1289 }
1290 TRANSLATE_SLASHES(pt);
1291
1292
1293
1294
1295 if (env_document_root) {
1296 int l = strlen(env_document_root);
1297 int path_translated_len = 0;
1298 char *path_translated = NULL;
1299
1300 if (l && env_document_root[l - 1] == '/') {
1301 --l;
1302 }
1303
1304
1305
1306
1307
1308
1309
1310 path_translated_len = l + (env_path_info ? strlen(env_path_info) : 0);
1311 path_translated = (char *) emalloc(path_translated_len + 1);
1312 memcpy(path_translated, env_document_root, l);
1313 if (env_path_info) {
1314 memcpy(path_translated + l, env_path_info, (path_translated_len - l));
1315 }
1316 path_translated[path_translated_len] = '\0';
1317 if (orig_path_translated) {
1318 _sapi_cgibin_putenv("ORIG_PATH_TRANSLATED", orig_path_translated TSRMLS_CC);
1319 }
1320 env_path_translated = _sapi_cgibin_putenv("PATH_TRANSLATED", path_translated TSRMLS_CC);
1321 efree(path_translated);
1322 } else if ( env_script_name &&
1323 strstr(pt, env_script_name)
1324 ) {
1325
1326 int ptlen = strlen(pt) - strlen(env_script_name);
1327 int path_translated_len = ptlen + (env_path_info ? strlen(env_path_info) : 0);
1328 char *path_translated = NULL;
1329
1330 path_translated = (char *) emalloc(path_translated_len + 1);
1331 memcpy(path_translated, pt, ptlen);
1332 if (env_path_info) {
1333 memcpy(path_translated + ptlen, env_path_info, path_translated_len - ptlen);
1334 }
1335 path_translated[path_translated_len] = '\0';
1336 if (orig_path_translated) {
1337 _sapi_cgibin_putenv("ORIG_PATH_TRANSLATED", orig_path_translated TSRMLS_CC);
1338 }
1339 env_path_translated = _sapi_cgibin_putenv("PATH_TRANSLATED", path_translated TSRMLS_CC);
1340 efree(path_translated);
1341 }
1342 break;
1343 }
1344 }
1345 } else {
1346 ptr = NULL;
1347 }
1348 if (!ptr) {
1349
1350
1351
1352
1353
1354 if (orig_script_filename) {
1355 _sapi_cgibin_putenv("ORIG_SCRIPT_FILENAME", orig_script_filename TSRMLS_CC);
1356 }
1357 script_path_translated = _sapi_cgibin_putenv("SCRIPT_FILENAME", NULL TSRMLS_CC);
1358 SG(sapi_headers).http_response_code = 404;
1359 }
1360 if (!SG(request_info).request_uri) {
1361 if (!orig_script_name ||
1362 strcmp(orig_script_name, env_script_name) != 0) {
1363 if (orig_script_name) {
1364 _sapi_cgibin_putenv("ORIG_SCRIPT_NAME", orig_script_name TSRMLS_CC);
1365 }
1366 SG(request_info).request_uri = _sapi_cgibin_putenv("SCRIPT_NAME", env_script_name TSRMLS_CC);
1367 } else {
1368 SG(request_info).request_uri = orig_script_name;
1369 }
1370 }
1371 if (pt) {
1372 efree(pt);
1373 }
1374 } else {
1375
1376 if (!orig_script_filename ||
1377 (script_path_translated != orig_script_filename &&
1378 strcmp(script_path_translated, orig_script_filename) != 0)) {
1379 if (orig_script_filename) {
1380 _sapi_cgibin_putenv("ORIG_SCRIPT_FILENAME", orig_script_filename TSRMLS_CC);
1381 }
1382 script_path_translated = _sapi_cgibin_putenv("SCRIPT_FILENAME", script_path_translated TSRMLS_CC);
1383 }
1384 if (!apache_was_here && env_redirect_url) {
1385
1386
1387 if (orig_path_info) {
1388 _sapi_cgibin_putenv("ORIG_PATH_INFO", orig_path_info TSRMLS_CC);
1389 _sapi_cgibin_putenv("PATH_INFO", NULL TSRMLS_CC);
1390 }
1391 if (orig_path_translated) {
1392 _sapi_cgibin_putenv("ORIG_PATH_TRANSLATED", orig_path_translated TSRMLS_CC);
1393 _sapi_cgibin_putenv("PATH_TRANSLATED", NULL TSRMLS_CC);
1394 }
1395 }
1396 if (env_script_name != orig_script_name) {
1397 if (orig_script_name) {
1398 _sapi_cgibin_putenv("ORIG_SCRIPT_NAME", orig_script_name TSRMLS_CC);
1399 }
1400 SG(request_info).request_uri = _sapi_cgibin_putenv("SCRIPT_NAME", env_script_name TSRMLS_CC);
1401 } else {
1402 SG(request_info).request_uri = env_script_name;
1403 }
1404 efree(real_path);
1405 }
1406 } else {
1407
1408 if (env_path_info) {
1409 SG(request_info).request_uri = env_path_info;
1410 } else {
1411 SG(request_info).request_uri = env_script_name;
1412 }
1413 if (!CGIG(discard_path) && env_path_translated) {
1414 script_path_translated = env_path_translated;
1415 }
1416 }
1417
1418 if (is_valid_path(script_path_translated)) {
1419 SG(request_info).path_translated = estrdup(script_path_translated);
1420 }
1421
1422 SG(request_info).request_method = sapi_cgibin_getenv("REQUEST_METHOD", sizeof("REQUEST_METHOD") - 1 TSRMLS_CC);
1423
1424 SG(request_info).query_string = sapi_cgibin_getenv("QUERY_STRING", sizeof("QUERY_STRING") - 1 TSRMLS_CC);
1425 SG(request_info).content_type = (content_type ? content_type : "" );
1426 SG(request_info).content_length = (content_length ? atol(content_length) : 0);
1427
1428
1429 auth = sapi_cgibin_getenv("HTTP_AUTHORIZATION", sizeof("HTTP_AUTHORIZATION") - 1 TSRMLS_CC);
1430 php_handle_auth_data(auth TSRMLS_CC);
1431 }
1432
1433
1434 ini = sapi_cgibin_getenv("PHP_VALUE", sizeof("PHP_VALUE") - 1 TSRMLS_CC);
1435 if (ini) {
1436 int mode = ZEND_INI_USER;
1437 char *tmp;
1438 spprintf(&tmp, 0, "%s\n", ini);
1439 zend_parse_ini_string(tmp, 1, ZEND_INI_SCANNER_NORMAL, (zend_ini_parser_cb_t)fastcgi_ini_parser, &mode TSRMLS_CC);
1440 efree(tmp);
1441 }
1442
1443 ini = sapi_cgibin_getenv("PHP_ADMIN_VALUE", sizeof("PHP_ADMIN_VALUE") - 1 TSRMLS_CC);
1444 if (ini) {
1445 int mode = ZEND_INI_SYSTEM;
1446 char *tmp;
1447 spprintf(&tmp, 0, "%s\n", ini);
1448 zend_parse_ini_string(tmp, 1, ZEND_INI_SCANNER_NORMAL, (zend_ini_parser_cb_t)fastcgi_ini_parser, &mode TSRMLS_CC);
1449 efree(tmp);
1450 }
1451 }
1452
1453
1454 static void fastcgi_ini_parser(zval *arg1, zval *arg2, zval *arg3, int callback_type, void *arg TSRMLS_DC)
1455 {
1456 int *mode = (int *)arg;
1457 char *key;
1458 char *value = NULL;
1459 struct key_value_s kv;
1460
1461 if (!mode || !arg1) return;
1462
1463 if (callback_type != ZEND_INI_PARSER_ENTRY) {
1464 zlog(ZLOG_ERROR, "Passing INI directive through FastCGI: only classic entries are allowed");
1465 return;
1466 }
1467
1468 key = Z_STRVAL_P(arg1);
1469
1470 if (!key || strlen(key) < 1) {
1471 zlog(ZLOG_ERROR, "Passing INI directive through FastCGI: empty key");
1472 return;
1473 }
1474
1475 if (arg2) {
1476 value = Z_STRVAL_P(arg2);
1477 }
1478
1479 if (!value) {
1480 zlog(ZLOG_ERROR, "Passing INI directive through FastCGI: empty value for key '%s'", key);
1481 return;
1482 }
1483
1484 kv.key = key;
1485 kv.value = value;
1486 kv.next = NULL;
1487 if (fpm_php_apply_defines_ex(&kv, *mode) == -1) {
1488 zlog(ZLOG_ERROR, "Passing INI directive through FastCGI: unable to set '%s'", key);
1489 }
1490 }
1491
1492
1493 PHP_INI_BEGIN()
1494 STD_PHP_INI_ENTRY("cgi.rfc2616_headers", "0", PHP_INI_ALL, OnUpdateBool, rfc2616_headers, php_cgi_globals_struct, php_cgi_globals)
1495 STD_PHP_INI_ENTRY("cgi.nph", "0", PHP_INI_ALL, OnUpdateBool, nph, php_cgi_globals_struct, php_cgi_globals)
1496 STD_PHP_INI_ENTRY("cgi.force_redirect", "1", PHP_INI_SYSTEM, OnUpdateBool, force_redirect, php_cgi_globals_struct, php_cgi_globals)
1497 STD_PHP_INI_ENTRY("cgi.redirect_status_env", NULL, PHP_INI_SYSTEM, OnUpdateString, redirect_status_env, php_cgi_globals_struct, php_cgi_globals)
1498 STD_PHP_INI_ENTRY("cgi.fix_pathinfo", "1", PHP_INI_SYSTEM, OnUpdateBool, fix_pathinfo, php_cgi_globals_struct, php_cgi_globals)
1499 STD_PHP_INI_ENTRY("cgi.discard_path", "0", PHP_INI_SYSTEM, OnUpdateBool, discard_path, php_cgi_globals_struct, php_cgi_globals)
1500 STD_PHP_INI_ENTRY("fastcgi.logging", "1", PHP_INI_SYSTEM, OnUpdateBool, fcgi_logging, php_cgi_globals_struct, php_cgi_globals)
1501 STD_PHP_INI_ENTRY("fastcgi.error_header", NULL, PHP_INI_SYSTEM, OnUpdateString, error_header, php_cgi_globals_struct, php_cgi_globals)
1502 STD_PHP_INI_ENTRY("fpm.config", NULL, PHP_INI_SYSTEM, OnUpdateString, fpm_config, php_cgi_globals_struct, php_cgi_globals)
1503 PHP_INI_END()
1504
1505
1506
1507 static void php_cgi_globals_ctor(php_cgi_globals_struct *php_cgi_globals TSRMLS_DC)
1508 {
1509 php_cgi_globals->rfc2616_headers = 0;
1510 php_cgi_globals->nph = 0;
1511 php_cgi_globals->force_redirect = 1;
1512 php_cgi_globals->redirect_status_env = NULL;
1513 php_cgi_globals->fix_pathinfo = 1;
1514 php_cgi_globals->discard_path = 0;
1515 php_cgi_globals->fcgi_logging = 1;
1516 zend_hash_init(&php_cgi_globals->user_config_cache, 0, NULL, (dtor_func_t) user_config_cache_entry_dtor, 1);
1517 php_cgi_globals->error_header = NULL;
1518 php_cgi_globals->fpm_config = NULL;
1519 }
1520
1521
1522
1523
1524 static PHP_MINIT_FUNCTION(cgi)
1525 {
1526 #ifdef ZTS
1527 ts_allocate_id(&php_cgi_globals_id, sizeof(php_cgi_globals_struct), (ts_allocate_ctor) php_cgi_globals_ctor, NULL);
1528 #else
1529 php_cgi_globals_ctor(&php_cgi_globals TSRMLS_CC);
1530 #endif
1531 REGISTER_INI_ENTRIES();
1532 return SUCCESS;
1533 }
1534
1535
1536
1537
1538 static PHP_MSHUTDOWN_FUNCTION(cgi)
1539 {
1540 zend_hash_destroy(&CGIG(user_config_cache));
1541
1542 UNREGISTER_INI_ENTRIES();
1543 return SUCCESS;
1544 }
1545
1546
1547
1548
1549 static PHP_MINFO_FUNCTION(cgi)
1550 {
1551 php_info_print_table_start();
1552 php_info_print_table_row(2, "php-fpm", "active");
1553 php_info_print_table_end();
1554
1555 DISPLAY_INI_ENTRIES();
1556 }
1557
1558
1559 PHP_FUNCTION(fastcgi_finish_request)
1560 {
1561 fcgi_request *request = (fcgi_request*) SG(server_context);
1562
1563 if (request->fd >= 0) {
1564
1565 php_output_end_all(TSRMLS_C);
1566 php_header(TSRMLS_C);
1567
1568 fcgi_flush(request, 1);
1569 fcgi_close(request, 0, 0);
1570 RETURN_TRUE;
1571 }
1572
1573 RETURN_FALSE;
1574
1575 }
1576
1577
1578 static const zend_function_entry cgi_fcgi_sapi_functions[] = {
1579 PHP_FE(fastcgi_finish_request, NULL)
1580 {NULL, NULL, NULL}
1581 };
1582
1583 static zend_module_entry cgi_module_entry = {
1584 STANDARD_MODULE_HEADER,
1585 "cgi-fcgi",
1586 cgi_fcgi_sapi_functions,
1587 PHP_MINIT(cgi),
1588 PHP_MSHUTDOWN(cgi),
1589 NULL,
1590 NULL,
1591 PHP_MINFO(cgi),
1592 NO_VERSION_YET,
1593 STANDARD_MODULE_PROPERTIES
1594 };
1595
1596
1597
1598 int main(int argc, char *argv[])
1599 {
1600 int exit_status = FPM_EXIT_OK;
1601 int cgi = 0, c, use_extended_info = 0;
1602 zend_file_handle file_handle;
1603
1604
1605 int orig_optind = php_optind;
1606 char *orig_optarg = php_optarg;
1607 int ini_entries_len = 0;
1608
1609
1610 #ifdef ZTS
1611 void ***tsrm_ls;
1612 #endif
1613
1614 int max_requests = 500;
1615 int requests = 0;
1616 int fcgi_fd = 0;
1617 fcgi_request request;
1618 char *fpm_config = NULL;
1619 char *fpm_prefix = NULL;
1620 char *fpm_pid = NULL;
1621 int test_conf = 0;
1622 int force_daemon = -1;
1623 int force_stderr = 0;
1624 int php_information = 0;
1625 int php_allow_to_run_as_root = 0;
1626
1627 #ifdef HAVE_SIGNAL_H
1628 #if defined(SIGPIPE) && defined(SIG_IGN)
1629 signal(SIGPIPE, SIG_IGN);
1630
1631
1632
1633
1634
1635 #endif
1636 #endif
1637
1638 #ifdef ZTS
1639 tsrm_startup(1, 1, 0, NULL);
1640 tsrm_ls = ts_resource(0);
1641 #endif
1642
1643 sapi_startup(&cgi_sapi_module);
1644 cgi_sapi_module.php_ini_path_override = NULL;
1645 cgi_sapi_module.php_ini_ignore_cwd = 1;
1646
1647 fcgi_init();
1648
1649 #ifdef PHP_WIN32
1650 _fmode = _O_BINARY;
1651 setmode(_fileno(stdin), O_BINARY);
1652 setmode(_fileno(stdout), O_BINARY);
1653 setmode(_fileno(stderr), O_BINARY);
1654 #endif
1655
1656 while ((c = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 0, 2)) != -1) {
1657 switch (c) {
1658 case 'c':
1659 if (cgi_sapi_module.php_ini_path_override) {
1660 free(cgi_sapi_module.php_ini_path_override);
1661 }
1662 cgi_sapi_module.php_ini_path_override = strdup(php_optarg);
1663 break;
1664
1665 case 'n':
1666 cgi_sapi_module.php_ini_ignore = 1;
1667 break;
1668
1669 case 'd': {
1670
1671 int len = strlen(php_optarg);
1672 char *val;
1673
1674 if ((val = strchr(php_optarg, '='))) {
1675 val++;
1676 if (!isalnum(*val) && *val != '"' && *val != '\'' && *val != '\0') {
1677 cgi_sapi_module.ini_entries = realloc(cgi_sapi_module.ini_entries, ini_entries_len + len + sizeof("\"\"\n\0"));
1678 memcpy(cgi_sapi_module.ini_entries + ini_entries_len, php_optarg, (val - php_optarg));
1679 ini_entries_len += (val - php_optarg);
1680 memcpy(cgi_sapi_module.ini_entries + ini_entries_len, "\"", 1);
1681 ini_entries_len++;
1682 memcpy(cgi_sapi_module.ini_entries + ini_entries_len, val, len - (val - php_optarg));
1683 ini_entries_len += len - (val - php_optarg);
1684 memcpy(cgi_sapi_module.ini_entries + ini_entries_len, "\"\n\0", sizeof("\"\n\0"));
1685 ini_entries_len += sizeof("\n\0\"") - 2;
1686 } else {
1687 cgi_sapi_module.ini_entries = realloc(cgi_sapi_module.ini_entries, ini_entries_len + len + sizeof("\n\0"));
1688 memcpy(cgi_sapi_module.ini_entries + ini_entries_len, php_optarg, len);
1689 memcpy(cgi_sapi_module.ini_entries + ini_entries_len + len, "\n\0", sizeof("\n\0"));
1690 ini_entries_len += len + sizeof("\n\0") - 2;
1691 }
1692 } else {
1693 cgi_sapi_module.ini_entries = realloc(cgi_sapi_module.ini_entries, ini_entries_len + len + sizeof("=1\n\0"));
1694 memcpy(cgi_sapi_module.ini_entries + ini_entries_len, php_optarg, len);
1695 memcpy(cgi_sapi_module.ini_entries + ini_entries_len + len, "=1\n\0", sizeof("=1\n\0"));
1696 ini_entries_len += len + sizeof("=1\n\0") - 2;
1697 }
1698 break;
1699 }
1700
1701 case 'y':
1702 fpm_config = php_optarg;
1703 break;
1704
1705 case 'p':
1706 fpm_prefix = php_optarg;
1707 break;
1708
1709 case 'g':
1710 fpm_pid = php_optarg;
1711 break;
1712
1713 case 'e':
1714 use_extended_info = 1;
1715 break;
1716
1717 case 't':
1718 test_conf++;
1719 break;
1720
1721 case 'm':
1722 cgi_sapi_module.startup(&cgi_sapi_module);
1723 php_output_activate(TSRMLS_C);
1724 SG(headers_sent) = 1;
1725 php_printf("[PHP Modules]\n");
1726 print_modules(TSRMLS_C);
1727 php_printf("\n[Zend Modules]\n");
1728 print_extensions(TSRMLS_C);
1729 php_printf("\n");
1730 php_output_end_all(TSRMLS_C);
1731 php_output_deactivate(TSRMLS_C);
1732 fcgi_shutdown();
1733 exit_status = FPM_EXIT_OK;
1734 goto out;
1735
1736 case 'i':
1737 php_information = 1;
1738 break;
1739
1740 case 'R':
1741 php_allow_to_run_as_root = 1;
1742 break;
1743
1744 case 'D':
1745 force_daemon = 1;
1746 break;
1747
1748 case 'F':
1749 force_daemon = 0;
1750 break;
1751
1752 case 'O':
1753 force_stderr = 1;
1754 break;
1755
1756 default:
1757 case 'h':
1758 case '?':
1759 cgi_sapi_module.startup(&cgi_sapi_module);
1760 php_output_activate(TSRMLS_C);
1761 SG(headers_sent) = 1;
1762 php_cgi_usage(argv[0]);
1763 php_output_end_all(TSRMLS_C);
1764 php_output_deactivate(TSRMLS_C);
1765 fcgi_shutdown();
1766 exit_status = (c == 'h') ? FPM_EXIT_OK : FPM_EXIT_USAGE;
1767 goto out;
1768
1769 case 'v':
1770 cgi_sapi_module.startup(&cgi_sapi_module);
1771 if (php_request_startup(TSRMLS_C) == FAILURE) {
1772 SG(server_context) = NULL;
1773 php_module_shutdown(TSRMLS_C);
1774 return FPM_EXIT_SOFTWARE;
1775 }
1776 SG(headers_sent) = 1;
1777 SG(request_info).no_headers = 1;
1778
1779 #if ZEND_DEBUG
1780 php_printf("PHP %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2016 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version());
1781 #else
1782 php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2016 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version());
1783 #endif
1784 php_request_shutdown((void *) 0);
1785 fcgi_shutdown();
1786 exit_status = FPM_EXIT_OK;
1787 goto out;
1788 }
1789 }
1790
1791 if (php_information) {
1792 cgi_sapi_module.phpinfo_as_text = 1;
1793 cgi_sapi_module.startup(&cgi_sapi_module);
1794 if (php_request_startup(TSRMLS_C) == FAILURE) {
1795 SG(server_context) = NULL;
1796 php_module_shutdown(TSRMLS_C);
1797 return FPM_EXIT_SOFTWARE;
1798 }
1799 SG(headers_sent) = 1;
1800 SG(request_info).no_headers = 1;
1801 php_print_info(0xFFFFFFFF TSRMLS_CC);
1802 php_request_shutdown((void *) 0);
1803 fcgi_shutdown();
1804 exit_status = FPM_EXIT_OK;
1805 goto out;
1806 }
1807
1808
1809 if (argc != php_optind) {
1810 cgi_sapi_module.startup(&cgi_sapi_module);
1811 php_output_activate(TSRMLS_C);
1812 SG(headers_sent) = 1;
1813 php_cgi_usage(argv[0]);
1814 php_output_end_all(TSRMLS_C);
1815 php_output_deactivate(TSRMLS_C);
1816 fcgi_shutdown();
1817 exit_status = FPM_EXIT_USAGE;
1818 goto out;
1819 }
1820
1821 php_optind = orig_optind;
1822 php_optarg = orig_optarg;
1823
1824 #ifdef ZTS
1825 SG(request_info).path_translated = NULL;
1826 #endif
1827
1828 cgi_sapi_module.additional_functions = additional_functions;
1829 cgi_sapi_module.executable_location = argv[0];
1830
1831
1832 if (cgi_sapi_module.startup(&cgi_sapi_module) == FAILURE) {
1833 #ifdef ZTS
1834 tsrm_shutdown();
1835 #endif
1836 return FPM_EXIT_SOFTWARE;
1837 }
1838
1839 if (use_extended_info) {
1840 CG(compiler_options) |= ZEND_COMPILE_EXTENDED_INFO;
1841 }
1842
1843
1844 if (cgi && CGIG(force_redirect)) {
1845
1846
1847
1848
1849
1850
1851 if (!getenv("REDIRECT_STATUS") &&
1852 !getenv ("HTTP_REDIRECT_STATUS") &&
1853
1854
1855 (!CGIG(redirect_status_env) || !getenv(CGIG(redirect_status_env)))
1856 ) {
1857 zend_try {
1858 SG(sapi_headers).http_response_code = 400;
1859 PUTS("<b>Security Alert!</b> The PHP CGI cannot be accessed directly.\n\n\
1860 <p>This PHP CGI binary was compiled with force-cgi-redirect enabled. This\n\
1861 means that a page will only be served up if the REDIRECT_STATUS CGI variable is\n\
1862 set, e.g. via an Apache Action directive.</p>\n\
1863 <p>For more information as to <i>why</i> this behaviour exists, see the <a href=\"http://php.net/security.cgi-bin\">\
1864 manual page for CGI security</a>.</p>\n\
1865 <p>For more information about changing this behaviour or re-enabling this webserver,\n\
1866 consult the installation file that came with this distribution, or visit \n\
1867 <a href=\"http://php.net/install.windows\">the manual page</a>.</p>\n");
1868 } zend_catch {
1869 } zend_end_try();
1870 #if defined(ZTS) && !defined(PHP_DEBUG)
1871
1872
1873
1874
1875
1876
1877 tsrm_shutdown();
1878 #endif
1879 return FPM_EXIT_SOFTWARE;
1880 }
1881 }
1882
1883 if (0 > fpm_init(argc, argv, fpm_config ? fpm_config : CGIG(fpm_config), fpm_prefix, fpm_pid, test_conf, php_allow_to_run_as_root, force_daemon, force_stderr)) {
1884
1885 if (fpm_globals.send_config_pipe[1]) {
1886 int writeval = 0;
1887 zlog(ZLOG_DEBUG, "Sending \"0\" (error) to parent via fd=%d", fpm_globals.send_config_pipe[1]);
1888 write(fpm_globals.send_config_pipe[1], &writeval, sizeof(writeval));
1889 close(fpm_globals.send_config_pipe[1]);
1890 }
1891 return FPM_EXIT_CONFIG;
1892 }
1893
1894 if (fpm_globals.send_config_pipe[1]) {
1895 int writeval = 1;
1896 zlog(ZLOG_DEBUG, "Sending \"1\" (OK) to parent via fd=%d", fpm_globals.send_config_pipe[1]);
1897 write(fpm_globals.send_config_pipe[1], &writeval, sizeof(writeval));
1898 close(fpm_globals.send_config_pipe[1]);
1899 }
1900 fpm_is_running = 1;
1901
1902 fcgi_fd = fpm_run(&max_requests);
1903 parent = 0;
1904
1905
1906 zlog_set_external_logger(sapi_cgi_log_fastcgi);
1907
1908
1909 php_php_import_environment_variables = php_import_environment_variables;
1910 php_import_environment_variables = cgi_php_import_environment_variables;
1911
1912
1913 fcgi_init_request(&request, fcgi_fd);
1914
1915 zend_first_try {
1916 while (fcgi_accept_request(&request) >= 0) {
1917 char *primary_script = NULL;
1918 request_body_fd = -1;
1919 SG(server_context) = (void *) &request;
1920 init_request_info(TSRMLS_C);
1921 CG(interactive) = 0;
1922
1923 fpm_request_info();
1924
1925
1926
1927 if (php_request_startup(TSRMLS_C) == FAILURE) {
1928 fcgi_finish_request(&request, 1);
1929 SG(server_context) = NULL;
1930 php_module_shutdown(TSRMLS_C);
1931 return FPM_EXIT_SOFTWARE;
1932 }
1933
1934
1935
1936 if (!SG(request_info).request_method) {
1937 goto fastcgi_request_done;
1938 }
1939
1940 if (fpm_status_handle_request(TSRMLS_C)) {
1941 goto fastcgi_request_done;
1942 }
1943
1944
1945 if (!SG(request_info).path_translated) {
1946 zend_try {
1947 zlog(ZLOG_DEBUG, "Primary script unknown");
1948 SG(sapi_headers).http_response_code = 404;
1949 PUTS("File not found.\n");
1950 } zend_catch {
1951 } zend_end_try();
1952 goto fastcgi_request_done;
1953 }
1954
1955 if (fpm_php_limit_extensions(SG(request_info).path_translated)) {
1956 SG(sapi_headers).http_response_code = 403;
1957 PUTS("Access denied.\n");
1958 goto fastcgi_request_done;
1959 }
1960
1961
1962
1963
1964
1965 primary_script = estrdup(SG(request_info).path_translated);
1966
1967
1968 if (php_fopen_primary_script(&file_handle TSRMLS_CC) == FAILURE) {
1969 zend_try {
1970 zlog(ZLOG_ERROR, "Unable to open primary script: %s (%s)", primary_script, strerror(errno));
1971 if (errno == EACCES) {
1972 SG(sapi_headers).http_response_code = 403;
1973 PUTS("Access denied.\n");
1974 } else {
1975 SG(sapi_headers).http_response_code = 404;
1976 PUTS("No input file specified.\n");
1977 }
1978 } zend_catch {
1979 } zend_end_try();
1980
1981
1982
1983
1984 goto fastcgi_request_done;
1985 }
1986
1987 fpm_request_executing();
1988
1989 php_execute_script(&file_handle TSRMLS_CC);
1990
1991 fastcgi_request_done:
1992 if (primary_script) {
1993 efree(primary_script);
1994 }
1995
1996 if (request_body_fd != -1) {
1997 close(request_body_fd);
1998 }
1999 request_body_fd = -2;
2000
2001 if (EG(exit_status) == 255) {
2002 if (CGIG(error_header) && *CGIG(error_header)) {
2003 sapi_header_line ctr = {0};
2004
2005 ctr.line = CGIG(error_header);
2006 ctr.line_len = strlen(CGIG(error_header));
2007 sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
2008 }
2009 }
2010
2011 fpm_request_end(TSRMLS_C);
2012 fpm_log_write(NULL TSRMLS_CC);
2013
2014 STR_FREE(SG(request_info).path_translated);
2015 SG(request_info).path_translated = NULL;
2016
2017 php_request_shutdown((void *) 0);
2018
2019 requests++;
2020 if (max_requests && (requests == max_requests)) {
2021 fcgi_finish_request(&request, 1);
2022 break;
2023 }
2024
2025 }
2026 fcgi_shutdown();
2027
2028 if (cgi_sapi_module.php_ini_path_override) {
2029 free(cgi_sapi_module.php_ini_path_override);
2030 }
2031 if (cgi_sapi_module.ini_entries) {
2032 free(cgi_sapi_module.ini_entries);
2033 }
2034 } zend_catch {
2035 exit_status = FPM_EXIT_SOFTWARE;
2036 } zend_end_try();
2037
2038 out:
2039
2040 SG(server_context) = NULL;
2041 php_module_shutdown(TSRMLS_C);
2042
2043 if (parent) {
2044 sapi_shutdown();
2045 }
2046
2047 #ifdef ZTS
2048 tsrm_shutdown();
2049 #endif
2050
2051 #if defined(PHP_WIN32) && ZEND_DEBUG && 0
2052 _CrtDumpMemoryLeaks();
2053 #endif
2054
2055 return exit_status;
2056 }
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066