You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2226 lines
64 KiB

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