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