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.

1733 lines
48 KiB

27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
24 years ago
27 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
24 years ago
28 years ago
28 years ago
21 years ago
28 years ago
21 years ago
24 years ago
25 years ago
28 years ago
24 years ago
28 years ago
23 years ago
24 years ago
21 years ago
21 years ago
24 years ago
21 years ago
24 years ago
24 years ago
21 years ago
21 years ago
24 years ago
21 years ago
24 years ago
21 years ago
21 years ago
24 years ago
21 years ago
21 years ago
27 years ago
21 years ago
27 years ago
24 years ago
24 years ago
27 years ago
28 years ago
28 years ago
23 years ago
25 years ago
24 years ago
24 years ago
24 years ago
21 years ago
24 years ago
21 years ago
24 years ago
21 years ago
24 years ago
21 years ago
24 years ago
24 years ago
24 years ago
21 years ago
23 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
24 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
24 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
24 years ago
21 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
21 years ago
27 years ago
27 years ago
21 years ago
27 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
28 years ago
28 years ago
21 years ago
28 years ago
28 years ago
21 years ago
21 years ago
28 years ago
21 years ago
27 years ago
21 years ago
28 years ago
21 years ago
21 years ago
24 years ago
28 years ago
21 years ago
21 years ago
24 years ago
21 years ago
28 years ago
24 years ago
28 years ago
21 years ago
21 years ago
21 years ago
24 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
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
28 years ago
21 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
21 years ago
24 years ago
21 years ago
24 years ago
28 years ago
21 years ago
24 years ago
24 years ago
21 years ago
20 years ago
21 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
24 years ago
28 years ago
24 years ago
24 years ago
21 years ago
24 years ago
24 years ago
21 years ago
28 years ago
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 5 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2006 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. #if PHP_FASTCGI
  76. #include "fastcgi.h"
  77. #ifndef PHP_WIN32
  78. /* XXX this will need to change later when threaded fastcgi is
  79. implemented. shane */
  80. struct sigaction act, old_term, old_quit, old_int;
  81. #endif
  82. static void (*php_php_import_environment_variables)(zval *array_ptr TSRMLS_DC);
  83. #ifndef PHP_WIN32
  84. /* these globals used for forking children on unix systems */
  85. /**
  86. * Number of child processes that will get created to service requests
  87. */
  88. static int children = 0;
  89. /**
  90. * Set to non-zero if we are the parent process
  91. */
  92. static int parent = 1;
  93. /**
  94. * Process group
  95. */
  96. static pid_t pgroup;
  97. #endif
  98. #endif
  99. #define PHP_MODE_STANDARD 1
  100. #define PHP_MODE_HIGHLIGHT 2
  101. #define PHP_MODE_INDENT 3
  102. #define PHP_MODE_LINT 4
  103. #define PHP_MODE_STRIP 5
  104. static char *php_optarg = NULL;
  105. static int php_optind = 1;
  106. static const opt_struct OPTIONS[] = {
  107. {'a', 0, "interactive"},
  108. #ifndef PHP_WIN32
  109. {'b', 1, "bindpath"},
  110. #endif
  111. {'C', 0, "no-chdir"},
  112. {'c', 1, "php-ini"},
  113. {'d', 1, "define"},
  114. {'e', 0, "profile-info"},
  115. {'f', 1, "file"},
  116. {'g', 1, "global"},
  117. {'h', 0, "help"},
  118. {'i', 0, "info"},
  119. {'l', 0, "syntax-check"},
  120. {'m', 0, "modules"},
  121. {'n', 0, "no-php-ini"},
  122. {'q', 0, "no-header"},
  123. {'s', 0, "syntax-highlight"},
  124. {'s', 0, "syntax-highlighting"},
  125. {'w', 0, "strip"},
  126. {'?', 0, "usage"},/* help alias (both '?' and 'usage') */
  127. {'v', 0, "version"},
  128. {'z', 1, "zend-extension"},
  129. {'-', 0, NULL} /* end of args */
  130. };
  131. #if ENABLE_PATHINFO_CHECK
  132. /* true global. this is retreived once only, even for fastcgi */
  133. long fix_pathinfo = 1;
  134. #endif
  135. #if PHP_FASTCGI
  136. long fcgi_logging = 1;
  137. #endif
  138. static long rfc2616_headers = 0;
  139. static long cgi_nph = 0;
  140. #ifdef PHP_WIN32
  141. #define TRANSLATE_SLASHES(path) \
  142. { \
  143. char *tmp = path; \
  144. while (*tmp) { \
  145. if (*tmp == '\\') *tmp = '/'; \
  146. tmp++; \
  147. } \
  148. }
  149. #else
  150. #define TRANSLATE_SLASHES(path)
  151. #endif
  152. static int print_module_info(zend_module_entry *module, void *arg TSRMLS_DC)
  153. {
  154. php_printf("%s\n", module->name);
  155. return 0;
  156. }
  157. static int module_name_cmp(const void *a, const void *b TSRMLS_DC)
  158. {
  159. Bucket *f = *((Bucket **) a);
  160. Bucket *s = *((Bucket **) b);
  161. return strcasecmp(((zend_module_entry *)f->pData)->name,
  162. ((zend_module_entry *)s->pData)->name);
  163. }
  164. static void print_modules(TSRMLS_D)
  165. {
  166. HashTable sorted_registry;
  167. zend_module_entry tmp;
  168. zend_hash_init(&sorted_registry, 50, NULL, NULL, 1);
  169. zend_hash_copy(&sorted_registry, &module_registry, NULL, &tmp, sizeof(zend_module_entry));
  170. zend_hash_sort(&sorted_registry, zend_qsort, module_name_cmp, 0 TSRMLS_CC);
  171. zend_hash_apply_with_argument(&sorted_registry, (apply_func_arg_t) print_module_info, NULL TSRMLS_CC);
  172. zend_hash_destroy(&sorted_registry);
  173. }
  174. static int print_extension_info(zend_extension *ext, void *arg TSRMLS_DC)
  175. {
  176. php_printf("%s\n", ext->name);
  177. return 0;
  178. }
  179. static int extension_name_cmp(const zend_llist_element **f,
  180. const zend_llist_element **s TSRMLS_DC)
  181. {
  182. return strcmp(((zend_extension *)(*f)->data)->name,
  183. ((zend_extension *)(*s)->data)->name);
  184. }
  185. static void print_extensions(TSRMLS_D)
  186. {
  187. zend_llist sorted_exts;
  188. zend_llist_copy(&sorted_exts, &zend_extensions);
  189. zend_llist_sort(&sorted_exts, extension_name_cmp TSRMLS_CC);
  190. zend_llist_apply_with_argument(&sorted_exts, (llist_apply_with_arg_func_t) print_extension_info, NULL TSRMLS_CC);
  191. zend_llist_destroy(&sorted_exts);
  192. }
  193. #ifndef STDOUT_FILENO
  194. #define STDOUT_FILENO 1
  195. #endif
  196. static inline size_t sapi_cgibin_single_write(const char *str, uint str_length TSRMLS_DC)
  197. {
  198. #ifdef PHP_WRITE_STDOUT
  199. long ret;
  200. #else
  201. size_t ret;
  202. #endif
  203. #if PHP_FASTCGI
  204. if (fcgi_is_fastcgi()) {
  205. fcgi_request *request = (fcgi_request*) SG(server_context);
  206. long ret = fcgi_write(request, FCGI_STDOUT, str, str_length);
  207. if (ret <= 0) {
  208. return 0;
  209. }
  210. return ret;
  211. }
  212. #endif
  213. #ifdef PHP_WRITE_STDOUT
  214. ret = write(STDOUT_FILENO, str, str_length);
  215. if (ret <= 0) return 0;
  216. return ret;
  217. #else
  218. ret = fwrite(str, 1, MIN(str_length, 16384), stdout);
  219. return ret;
  220. #endif
  221. }
  222. static int sapi_cgibin_ub_write(const char *str, uint str_length TSRMLS_DC)
  223. {
  224. const char *ptr = str;
  225. uint remaining = str_length;
  226. size_t ret;
  227. while (remaining > 0) {
  228. ret = sapi_cgibin_single_write(ptr, remaining TSRMLS_CC);
  229. if (!ret) {
  230. php_handle_aborted_connection();
  231. return str_length - remaining;
  232. }
  233. ptr += ret;
  234. remaining -= ret;
  235. }
  236. return str_length;
  237. }
  238. static void sapi_cgibin_flush(void *server_context)
  239. {
  240. #if PHP_FASTCGI
  241. if (fcgi_is_fastcgi()) {
  242. fcgi_request *request = (fcgi_request*) server_context;
  243. if (
  244. #ifndef PHP_WIN32
  245. !parent &&
  246. #endif
  247. request && !fcgi_flush(request, 0)) {
  248. php_handle_aborted_connection();
  249. }
  250. return;
  251. }
  252. #endif
  253. if (fflush(stdout) == EOF) {
  254. php_handle_aborted_connection();
  255. }
  256. }
  257. #define SAPI_CGI_MAX_HEADER_LENGTH 1024
  258. static int sapi_cgi_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
  259. {
  260. char buf[SAPI_CGI_MAX_HEADER_LENGTH];
  261. sapi_header_struct *h;
  262. zend_llist_position pos;
  263. if (SG(request_info).no_headers == 1) {
  264. return SAPI_HEADER_SENT_SUCCESSFULLY;
  265. }
  266. if (cgi_nph || SG(sapi_headers).http_response_code != 200)
  267. {
  268. int len;
  269. if (rfc2616_headers && SG(sapi_headers).http_status_line) {
  270. len = snprintf(buf, SAPI_CGI_MAX_HEADER_LENGTH,
  271. "%s\r\n", SG(sapi_headers).http_status_line);
  272. if (len > SAPI_CGI_MAX_HEADER_LENGTH) {
  273. len = SAPI_CGI_MAX_HEADER_LENGTH;
  274. }
  275. } else {
  276. len = sprintf(buf, "Status: %d\r\n", SG(sapi_headers).http_response_code);
  277. }
  278. PHPWRITE_H(buf, len);
  279. }
  280. h = zend_llist_get_first_ex(&sapi_headers->headers, &pos);
  281. while (h) {
  282. /* prevent CRLFCRLF */
  283. if (h->header_len) {
  284. PHPWRITE_H(h->header, h->header_len);
  285. PHPWRITE_H("\r\n", 2);
  286. }
  287. h = zend_llist_get_next_ex(&sapi_headers->headers, &pos);
  288. }
  289. PHPWRITE_H("\r\n", 2);
  290. return SAPI_HEADER_SENT_SUCCESSFULLY;
  291. }
  292. static int sapi_cgi_read_post(char *buffer, uint count_bytes TSRMLS_DC)
  293. {
  294. uint read_bytes=0, tmp_read_bytes;
  295. #if PHP_FASTCGI
  296. char *pos = buffer;
  297. #endif
  298. count_bytes = MIN(count_bytes, (uint) SG(request_info).content_length - SG(read_post_bytes));
  299. while (read_bytes < count_bytes) {
  300. #if PHP_FASTCGI
  301. if (fcgi_is_fastcgi()) {
  302. fcgi_request *request = (fcgi_request*) SG(server_context);
  303. tmp_read_bytes = fcgi_read(request, pos, count_bytes - read_bytes);
  304. pos += tmp_read_bytes;
  305. } else {
  306. tmp_read_bytes = read(0, buffer + read_bytes, count_bytes - read_bytes);
  307. }
  308. #else
  309. tmp_read_bytes = read(0, buffer + read_bytes, count_bytes - read_bytes);
  310. #endif
  311. if (tmp_read_bytes <= 0) {
  312. break;
  313. }
  314. read_bytes += tmp_read_bytes;
  315. }
  316. return read_bytes;
  317. }
  318. static char *sapi_cgibin_getenv(char *name, size_t name_len TSRMLS_DC)
  319. {
  320. #if PHP_FASTCGI
  321. /* when php is started by mod_fastcgi, no regular environment
  322. is provided to PHP. It is always sent to PHP at the start
  323. of a request. So we have to do our own lookup to get env
  324. vars. This could probably be faster somehow. */
  325. if (fcgi_is_fastcgi()) {
  326. fcgi_request *request = (fcgi_request*) SG(server_context);
  327. return fcgi_getenv(request, name, name_len);
  328. }
  329. #endif
  330. /* if cgi, or fastcgi and not found in fcgi env
  331. check the regular environment */
  332. return getenv(name);
  333. }
  334. static char *_sapi_cgibin_putenv(char *name, char *value TSRMLS_DC)
  335. {
  336. int name_len;
  337. int len;
  338. char *buf;
  339. if (!name) {
  340. return NULL;
  341. }
  342. name_len = strlen(name);
  343. #if PHP_FASTCGI
  344. /* when php is started by mod_fastcgi, no regular environment
  345. is provided to PHP. It is always sent to PHP at the start
  346. of a request. So we have to do our own lookup to get env
  347. vars. This could probably be faster somehow. */
  348. if (fcgi_is_fastcgi()) {
  349. fcgi_request *request = (fcgi_request*) SG(server_context);
  350. return fcgi_putenv(request, name, name_len, value);
  351. }
  352. #endif
  353. /* if cgi, or fastcgi and not found in fcgi env
  354. check the regular environment
  355. this leaks, but it's only cgi anyway, we'll fix
  356. it for 5.0
  357. */
  358. len = name_len + (value ? strlen(value) : 0) + sizeof("=") + 2;
  359. buf = (char *) malloc(len);
  360. if (buf == NULL) {
  361. return getenv(name);
  362. }
  363. if (value) {
  364. len = snprintf(buf, len - 1, "%s=%s", name, value);
  365. } else {
  366. len = snprintf(buf, len - 1, "%s=", name);
  367. }
  368. putenv(buf);
  369. return getenv(name);
  370. }
  371. static char *sapi_cgi_read_cookies(TSRMLS_D)
  372. {
  373. return sapi_cgibin_getenv((char *) "HTTP_COOKIE", sizeof("HTTP_COOKIE")-1 TSRMLS_CC);
  374. }
  375. #if PHP_FASTCGI
  376. void cgi_php_import_environment_variables(zval *array_ptr TSRMLS_DC)
  377. {
  378. if (PG(http_globals)[TRACK_VARS_ENV] &&
  379. array_ptr != PG(http_globals)[TRACK_VARS_ENV] &&
  380. Z_TYPE_P(PG(http_globals)[TRACK_VARS_ENV]) == IS_ARRAY &&
  381. zend_hash_num_elements(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_ENV])) > 0) {
  382. zval_dtor(array_ptr);
  383. *array_ptr = *PG(http_globals)[TRACK_VARS_ENV];
  384. INIT_PZVAL(array_ptr);
  385. zval_copy_ctor(array_ptr);
  386. return;
  387. } else if (PG(http_globals)[TRACK_VARS_SERVER] &&
  388. array_ptr != PG(http_globals)[TRACK_VARS_SERVER] &&
  389. Z_TYPE_P(PG(http_globals)[TRACK_VARS_SERVER]) == IS_ARRAY &&
  390. zend_hash_num_elements(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_SERVER])) > 0) {
  391. zval_dtor(array_ptr);
  392. *array_ptr = *PG(http_globals)[TRACK_VARS_SERVER];
  393. INIT_PZVAL(array_ptr);
  394. zval_copy_ctor(array_ptr);
  395. return;
  396. }
  397. if (fcgi_is_fastcgi()) {
  398. fcgi_request *request = (fcgi_request*) SG(server_context);
  399. HashPosition pos;
  400. int magic_quotes_gpc = PG(magic_quotes_gpc);
  401. char *var, **val;
  402. uint var_len;
  403. ulong idx;
  404. /* turn off magic_quotes while importing environment variables */
  405. PG(magic_quotes_gpc) = 0;
  406. for (zend_hash_internal_pointer_reset_ex(&request->env, &pos);
  407. zend_hash_get_current_key_ex(&request->env, &var, &var_len, &idx, 0, &pos) == HASH_KEY_IS_STRING &&
  408. zend_hash_get_current_data_ex(&request->env, (void **) &val, &pos) == SUCCESS;
  409. zend_hash_move_forward_ex(&request->env, &pos)) {
  410. php_register_variable(var, *val, array_ptr TSRMLS_CC);
  411. }
  412. PG(magic_quotes_gpc) = magic_quotes_gpc;
  413. }
  414. /* call php's original import as a catch-all */
  415. php_php_import_environment_variables(array_ptr TSRMLS_CC);
  416. }
  417. #endif
  418. static void sapi_cgi_register_variables(zval *track_vars_array TSRMLS_DC)
  419. {
  420. /* In CGI mode, we consider the environment to be a part of the server
  421. * variables
  422. */
  423. php_import_environment_variables(track_vars_array TSRMLS_CC);
  424. /* Build the special-case PHP_SELF variable for the CGI version */
  425. php_register_variable("PHP_SELF", (SG(request_info).request_uri ? SG(request_info).request_uri : ""), track_vars_array TSRMLS_CC);
  426. }
  427. static void sapi_cgi_log_message(char *message)
  428. {
  429. #if PHP_FASTCGI
  430. if (fcgi_is_fastcgi() && fcgi_logging) {
  431. fcgi_request *request;
  432. TSRMLS_FETCH();
  433. request = (fcgi_request*) SG(server_context);
  434. if (request) {
  435. int len = strlen(message);
  436. char *buf = malloc(len+2);
  437. memcpy(buf, message, len);
  438. memcpy(buf + len, "\n", sizeof("\n"));
  439. fcgi_write(request, FCGI_STDERR, buf, len+1);
  440. free(buf);
  441. } else {
  442. fprintf(stderr, "%s\n", message);
  443. }
  444. /* ignore return code */
  445. } else
  446. #endif /* PHP_FASTCGI */
  447. fprintf(stderr, "%s\n", message);
  448. }
  449. static int sapi_cgi_deactivate(TSRMLS_D)
  450. {
  451. /* flush only when SAPI was started. The reasons are:
  452. 1. SAPI Deactivate is called from two places: module init and request shutdown
  453. 2. When the first call occurs and the request is not set up, flush fails on
  454. FastCGI.
  455. */
  456. if (SG(sapi_started)) {
  457. sapi_cgibin_flush(SG(server_context));
  458. }
  459. return SUCCESS;
  460. }
  461. static int php_cgi_startup(sapi_module_struct *sapi_module)
  462. {
  463. if (php_module_startup(sapi_module, NULL, 0) == FAILURE) {
  464. return FAILURE;
  465. }
  466. return SUCCESS;
  467. }
  468. /* {{{ sapi_module_struct cgi_sapi_module
  469. */
  470. static sapi_module_struct cgi_sapi_module = {
  471. #if PHP_FASTCGI
  472. "cgi-fcgi", /* name */
  473. "CGI/FastCGI", /* pretty name */
  474. #else
  475. "cgi", /* name */
  476. "CGI", /* pretty name */
  477. #endif
  478. php_cgi_startup, /* startup */
  479. php_module_shutdown_wrapper, /* shutdown */
  480. NULL, /* activate */
  481. sapi_cgi_deactivate, /* deactivate */
  482. sapi_cgibin_ub_write, /* unbuffered write */
  483. sapi_cgibin_flush, /* flush */
  484. NULL, /* get uid */
  485. sapi_cgibin_getenv, /* getenv */
  486. php_error, /* error handler */
  487. NULL, /* header handler */
  488. sapi_cgi_send_headers, /* send headers handler */
  489. NULL, /* send header handler */
  490. sapi_cgi_read_post, /* read POST data */
  491. sapi_cgi_read_cookies, /* read Cookies */
  492. sapi_cgi_register_variables, /* register server variables */
  493. sapi_cgi_log_message, /* Log message */
  494. NULL, /* Get request time */
  495. STANDARD_SAPI_MODULE_PROPERTIES
  496. };
  497. /* }}} */
  498. /* {{{ php_cgi_usage
  499. */
  500. static void php_cgi_usage(char *argv0)
  501. {
  502. char *prog;
  503. prog = strrchr(argv0, '/');
  504. if (prog) {
  505. prog++;
  506. } else {
  507. prog = "php";
  508. }
  509. php_printf("Usage: %s [-q] [-h] [-s] [-v] [-i] [-f <file>]\n"
  510. " %s <file> [args...]\n"
  511. " -a Run interactively\n"
  512. #if PHP_FASTCGI && !defined(PHP_WIN32)
  513. " -b <address:port>|<port> Bind Path for external FASTCGI Server mode\n"
  514. #endif
  515. " -C Do not chdir to the script's directory\n"
  516. " -c <path>|<file> Look for php.ini file in this directory\n"
  517. " -n No php.ini file will be used\n"
  518. " -d foo[=bar] Define INI entry foo with value 'bar'\n"
  519. " -e Generate extended information for debugger/profiler\n"
  520. " -f <file> Parse <file>. Implies `-q'\n"
  521. " -h This help\n"
  522. " -i PHP information\n"
  523. " -l Syntax check only (lint)\n"
  524. " -m Show compiled in modules\n"
  525. " -q Quiet-mode. Suppress HTTP Header output.\n"
  526. " -s Display colour syntax highlighted source.\n"
  527. " -v Version number\n"
  528. " -w Display source with stripped comments and whitespace.\n"
  529. " -z <file> Load Zend extension <file>.\n",
  530. prog, prog);
  531. }
  532. /* }}} */
  533. /* {{{ init_request_info
  534. initializes request_info structure
  535. specificly in this section we handle proper translations
  536. for:
  537. PATH_INFO
  538. derived from the portion of the URI path following
  539. the script name but preceding any query data
  540. may be empty
  541. PATH_TRANSLATED
  542. derived by taking any path-info component of the
  543. request URI and performing any virtual-to-physical
  544. translation appropriate to map it onto the server's
  545. document repository structure
  546. empty if PATH_INFO is empty
  547. The env var PATH_TRANSLATED **IS DIFFERENT** than the
  548. request_info.path_translated variable, the latter should
  549. match SCRIPT_FILENAME instead.
  550. SCRIPT_NAME
  551. set to a URL path that could identify the CGI script
  552. rather than the interpreter. PHP_SELF is set to this.
  553. REQUEST_URI
  554. uri section following the domain:port part of a URI
  555. SCRIPT_FILENAME
  556. The virtual-to-physical translation of SCRIPT_NAME (as per
  557. PATH_TRANSLATED)
  558. These settings are documented at
  559. http://cgi-spec.golux.com/
  560. Based on the following URL request:
  561. http://localhost/info.php/test?a=b
  562. should produce, which btw is the same as if
  563. we were running under mod_cgi on apache (ie. not
  564. using ScriptAlias directives):
  565. PATH_INFO=/test
  566. PATH_TRANSLATED=/docroot/test
  567. SCRIPT_NAME=/info.php
  568. REQUEST_URI=/info.php/test?a=b
  569. SCRIPT_FILENAME=/docroot/info.php
  570. QUERY_STRING=a=b
  571. but what we get is (cgi/mod_fastcgi under apache):
  572. PATH_INFO=/info.php/test
  573. PATH_TRANSLATED=/docroot/info.php/test
  574. SCRIPT_NAME=/php/php-cgi (from the Action setting I suppose)
  575. REQUEST_URI=/info.php/test?a=b
  576. SCRIPT_FILENAME=/path/to/php/bin/php-cgi (Action setting translated)
  577. QUERY_STRING=a=b
  578. Comments in the code below refer to using the above URL in a request
  579. */
  580. static void init_request_info(TSRMLS_D)
  581. {
  582. char *env_script_filename = sapi_cgibin_getenv("SCRIPT_FILENAME", sizeof("SCRIPT_FILENAME")-1 TSRMLS_CC);
  583. char *env_path_translated = sapi_cgibin_getenv("PATH_TRANSLATED", sizeof("PATH_TRANSLATED")-1 TSRMLS_CC);
  584. char *script_path_translated = env_script_filename;
  585. #if !DISCARD_PATH
  586. /* some broken servers do not have script_filename or argv0
  587. an example, IIS configured in some ways. then they do more
  588. broken stuff and set path_translated to the cgi script location */
  589. if (!script_path_translated && env_path_translated) {
  590. script_path_translated = env_path_translated;
  591. }
  592. #endif
  593. /* initialize the defaults */
  594. SG(request_info).path_translated = NULL;
  595. SG(request_info).request_method = NULL;
  596. SG(request_info).proto_num = 1000;
  597. SG(request_info).query_string = NULL;
  598. SG(request_info).request_uri = NULL;
  599. SG(request_info).content_type = NULL;
  600. SG(request_info).content_length = 0;
  601. SG(sapi_headers).http_response_code = 200;
  602. /* script_path_translated being set is a good indication that
  603. we are running in a cgi environment, since it is always
  604. null otherwise. otherwise, the filename
  605. of the script will be retreived later via argc/argv */
  606. if (script_path_translated) {
  607. const char *auth;
  608. char *content_length = sapi_cgibin_getenv("CONTENT_LENGTH", sizeof("CONTENT_LENGTH")-1 TSRMLS_CC);
  609. char *content_type = sapi_cgibin_getenv("CONTENT_TYPE", sizeof("CONTENT_TYPE")-1 TSRMLS_CC);
  610. char *env_path_info = sapi_cgibin_getenv("PATH_INFO", sizeof("PATH_INFO")-1 TSRMLS_CC);
  611. char *env_script_name = sapi_cgibin_getenv("SCRIPT_NAME", sizeof("SCRIPT_NAME")-1 TSRMLS_CC);
  612. #if ENABLE_PATHINFO_CHECK
  613. struct stat st;
  614. char *env_redirect_url = sapi_cgibin_getenv("REDIRECT_URL", sizeof("REDIRECT_URL")-1 TSRMLS_CC);
  615. char *env_document_root = sapi_cgibin_getenv("DOCUMENT_ROOT", sizeof("DOCUMENT_ROOT")-1 TSRMLS_CC);
  616. if (fix_pathinfo) {
  617. /* save the originals first for anything we change later */
  618. if (env_path_translated) {
  619. _sapi_cgibin_putenv("ORIG_PATH_TRANSLATED", env_path_translated TSRMLS_CC);
  620. }
  621. if (env_path_info) {
  622. _sapi_cgibin_putenv("ORIG_PATH_INFO", env_path_info TSRMLS_CC);
  623. }
  624. if (env_script_name) {
  625. _sapi_cgibin_putenv("ORIG_SCRIPT_NAME", env_script_name TSRMLS_CC);
  626. }
  627. if (env_script_filename) {
  628. _sapi_cgibin_putenv("ORIG_SCRIPT_FILENAME", env_script_filename TSRMLS_CC);
  629. }
  630. if (!env_document_root) {
  631. /* ini version of document root */
  632. if (!env_document_root) {
  633. env_document_root = PG(doc_root);
  634. }
  635. /* set the document root, this makes a more
  636. consistent env for php scripts */
  637. if (env_document_root) {
  638. env_document_root = _sapi_cgibin_putenv("DOCUMENT_ROOT", env_document_root TSRMLS_CC);
  639. /* fix docroot */
  640. TRANSLATE_SLASHES(env_document_root);
  641. }
  642. }
  643. if (env_path_translated != NULL && env_redirect_url != NULL) {
  644. /*
  645. pretty much apache specific. If we have a redirect_url
  646. then our script_filename and script_name point to the
  647. php executable
  648. */
  649. script_path_translated = env_path_translated;
  650. /* we correct SCRIPT_NAME now in case we don't have PATH_INFO */
  651. env_script_name = _sapi_cgibin_putenv("SCRIPT_NAME", env_redirect_url TSRMLS_CC);
  652. }
  653. #ifdef __riscos__
  654. /* Convert path to unix format*/
  655. __riscosify_control |= __RISCOSIFY_DONT_CHECK_DIR;
  656. script_path_translated = __unixify(script_path_translated, 0, NULL, 1, 0);
  657. #endif
  658. /*
  659. * if the file doesn't exist, try to extract PATH_INFO out
  660. * of it by stat'ing back through the '/'
  661. * this fixes url's like /info.php/test
  662. */
  663. if (script_path_translated && stat(script_path_translated, &st) == -1 ) {
  664. char *pt = estrdup(script_path_translated);
  665. int len = strlen(pt);
  666. char *ptr;
  667. while ((ptr = strrchr(pt, '/')) || (ptr = strrchr(pt, '\\'))) {
  668. *ptr = 0;
  669. if (stat(pt, &st) == 0 && S_ISREG(st.st_mode)) {
  670. /*
  671. * okay, we found the base script!
  672. * work out how many chars we had to strip off;
  673. * then we can modify PATH_INFO
  674. * accordingly
  675. *
  676. * we now have the makings of
  677. * PATH_INFO=/test
  678. * SCRIPT_FILENAME=/docroot/info.php
  679. *
  680. * we now need to figure out what docroot is.
  681. * if DOCUMENT_ROOT is set, this is easy, otherwise,
  682. * we have to play the game of hide and seek to figure
  683. * out what SCRIPT_NAME should be
  684. */
  685. int slen = len - strlen(pt);
  686. int pilen = strlen(env_path_info);
  687. char *path_info = env_path_info + pilen - slen;
  688. env_path_info = _sapi_cgibin_putenv("PATH_INFO", path_info TSRMLS_CC);
  689. script_path_translated = _sapi_cgibin_putenv("SCRIPT_FILENAME", pt TSRMLS_CC);
  690. TRANSLATE_SLASHES(pt);
  691. /* figure out docroot
  692. SCRIPT_FILENAME minus SCRIPT_NAME
  693. */
  694. if (env_document_root)
  695. {
  696. int l = strlen(env_document_root);
  697. int path_translated_len = 0;
  698. char *path_translated = NULL;
  699. if (env_document_root[l - 1] == '/') {
  700. --l;
  701. }
  702. /* we have docroot, so we should have:
  703. * DOCUMENT_ROOT=/docroot
  704. * SCRIPT_FILENAME=/docroot/info.php
  705. *
  706. * SCRIPT_NAME is the portion of the path beyond docroot
  707. */
  708. env_script_name = _sapi_cgibin_putenv("SCRIPT_NAME", pt + l TSRMLS_CC);
  709. /* PATH_TRANSATED = DOCUMENT_ROOT + PATH_INFO */
  710. path_translated_len = l + strlen(env_path_info) + 2;
  711. path_translated = (char *) emalloc(path_translated_len);
  712. *path_translated = 0;
  713. strncat(path_translated, env_document_root, l);
  714. strcat(path_translated, env_path_info);
  715. env_path_translated = _sapi_cgibin_putenv("PATH_TRANSLATED", path_translated TSRMLS_CC);
  716. efree(path_translated);
  717. } else if (env_script_name &&
  718. strstr(pt, env_script_name)
  719. ) {
  720. /* PATH_TRANSATED = PATH_TRANSATED - SCRIPT_NAME + PATH_INFO */
  721. int ptlen = strlen(pt) - strlen(env_script_name);
  722. int path_translated_len = ptlen + strlen(env_path_info) + 2;
  723. char *path_translated = NULL;
  724. path_translated = (char *) emalloc(path_translated_len);
  725. *path_translated = 0;
  726. strncat(path_translated, pt, ptlen);
  727. strcat(path_translated, env_path_info);
  728. env_path_translated = _sapi_cgibin_putenv("PATH_TRANSLATED", path_translated TSRMLS_CC);
  729. efree(path_translated);
  730. }
  731. break;
  732. }
  733. }
  734. if (!ptr) {
  735. /*
  736. * if we stripped out all the '/' and still didn't find
  737. * a valid path... we will fail, badly. of course we would
  738. * have failed anyway... we output 'no input file' now.
  739. */
  740. script_path_translated = _sapi_cgibin_putenv("SCRIPT_FILENAME", NULL TSRMLS_CC);
  741. SG(sapi_headers).http_response_code = 404;
  742. }
  743. if (pt) {
  744. efree(pt);
  745. }
  746. } else {
  747. /* make sure path_info/translated are empty */
  748. script_path_translated = _sapi_cgibin_putenv("SCRIPT_FILENAME", script_path_translated TSRMLS_CC);
  749. _sapi_cgibin_putenv("PATH_INFO", NULL TSRMLS_CC);
  750. _sapi_cgibin_putenv("PATH_TRANSLATED", NULL TSRMLS_CC);
  751. }
  752. SG(request_info).request_uri = sapi_cgibin_getenv("SCRIPT_NAME", sizeof("SCRIPT_NAME")-1 TSRMLS_CC);
  753. } else {
  754. #endif
  755. /* pre 4.3 behaviour, shouldn't be used but provides BC */
  756. if (env_path_info) {
  757. SG(request_info).request_uri = env_path_info;
  758. } else {
  759. SG(request_info).request_uri = env_script_name;
  760. }
  761. #if !DISCARD_PATH
  762. if (env_path_translated)
  763. script_path_translated = env_path_translated;
  764. #endif
  765. #if ENABLE_PATHINFO_CHECK
  766. }
  767. #endif
  768. SG(request_info).request_method = sapi_cgibin_getenv("REQUEST_METHOD", sizeof("REQUEST_METHOD")-1 TSRMLS_CC);
  769. /* FIXME - Work out proto_num here */
  770. SG(request_info).query_string = sapi_cgibin_getenv("QUERY_STRING", sizeof("QUERY_STRING")-1 TSRMLS_CC);
  771. /* some server configurations allow '..' to slip through in the
  772. translated path. We'll just refuse to handle such a path. */
  773. if (script_path_translated && !strstr(script_path_translated, "..")) {
  774. SG(request_info).path_translated = estrdup(script_path_translated);
  775. }
  776. SG(request_info).content_type = (content_type ? content_type : "" );
  777. SG(request_info).content_length = (content_length ? atoi(content_length) : 0);
  778. /* The CGI RFC allows servers to pass on unvalidated Authorization data */
  779. auth = sapi_cgibin_getenv("HTTP_AUTHORIZATION", sizeof("HTTP_AUTHORIZATION")-1 TSRMLS_CC);
  780. php_handle_auth_data(auth TSRMLS_CC);
  781. }
  782. }
  783. /* }}} */
  784. static void define_command_line_ini_entry(char *arg)
  785. {
  786. char *name, *value;
  787. name = arg;
  788. value = strchr(arg, '=');
  789. if (value) {
  790. *value = 0;
  791. value++;
  792. } else {
  793. value = "1";
  794. }
  795. zend_alter_ini_entry(name, strlen(name) + 1, value, strlen(value), PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE);
  796. }
  797. static void php_register_command_line_global_vars(char **arg TSRMLS_DC)
  798. {
  799. char *var, *val;
  800. var = *arg;
  801. val = strchr(var, '=');
  802. if (!val) {
  803. printf("No value specified for variable '%s'\n", var);
  804. } else {
  805. *val++ = '\0';
  806. php_register_variable(var, val, NULL TSRMLS_CC);
  807. }
  808. efree(*arg);
  809. }
  810. #if PHP_FASTCGI
  811. /**
  812. * Clean up child processes upon exit
  813. */
  814. void fastcgi_cleanup(int signal)
  815. {
  816. #ifdef DEBUG_FASTCGI
  817. fprintf(stderr, "FastCGI shutdown, pid %d\n", getpid());
  818. #endif
  819. #ifndef PHP_WIN32
  820. sigaction(SIGTERM, &old_term, 0);
  821. /* Kill all the processes in our process group */
  822. kill(-pgroup, SIGTERM);
  823. #endif
  824. /* We should exit at this point, but MacOSX doesn't seem to */
  825. exit(0);
  826. }
  827. #endif
  828. #if PHP_FASTCGI
  829. #ifndef PHP_WIN32
  830. static int is_port_number(const char *bindpath)
  831. {
  832. while (*bindpath) {
  833. if (*bindpath < '0' || *bindpath > '9') {
  834. return 0;
  835. }
  836. bindpath++;
  837. }
  838. return 1;
  839. }
  840. #endif
  841. #endif
  842. /* {{{ main
  843. */
  844. int main(int argc, char *argv[])
  845. {
  846. int exit_status = SUCCESS;
  847. int cgi = 0, c, i, len;
  848. zend_file_handle file_handle;
  849. int retval = FAILURE;
  850. char *s;
  851. /* temporary locals */
  852. int behavior = PHP_MODE_STANDARD;
  853. int no_headers = 0;
  854. int orig_optind = php_optind;
  855. char *orig_optarg = php_optarg;
  856. char *script_file = NULL;
  857. zend_llist global_vars;
  858. #if FORCE_CGI_REDIRECT
  859. long force_redirect = 1;
  860. char *redirect_status_env = NULL;
  861. #endif
  862. /* end of temporary locals */
  863. #ifdef ZTS
  864. zend_compiler_globals *compiler_globals;
  865. zend_executor_globals *executor_globals;
  866. php_core_globals *core_globals;
  867. sapi_globals_struct *sapi_globals;
  868. void ***tsrm_ls;
  869. #endif
  870. #if PHP_FASTCGI
  871. int max_requests = 500;
  872. int requests = 0;
  873. int fastcgi = fcgi_is_fastcgi();
  874. #ifndef PHP_WIN32
  875. char *bindpath = NULL;
  876. #endif
  877. int fcgi_fd = 0;
  878. fcgi_request request;
  879. #ifdef PHP_WIN32
  880. long impersonate = 0;
  881. #else
  882. int status = 0;
  883. #endif
  884. #endif /* PHP_FASTCGI */
  885. #if 0 && defined(PHP_DEBUG)
  886. /* IIS is always making things more difficult. This allows
  887. us to stop PHP and attach a debugger before much gets started */
  888. {
  889. char szMessage [256];
  890. wsprintf (szMessage, "Please attach a debugger to the process 0x%X [%d] (%s) and click OK",
  891. GetCurrentProcessId(), GetCurrentProcessId(), argv[0]);
  892. MessageBox(NULL, szMessage, "CGI Debug Time!", MB_OK|MB_SERVICE_NOTIFICATION);
  893. }
  894. #endif
  895. #ifdef HAVE_SIGNAL_H
  896. #if defined(SIGPIPE) && defined(SIG_IGN)
  897. signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE in standalone mode so
  898. that sockets created via fsockopen()
  899. don't kill PHP if the remote site
  900. closes it. in apache|apxs mode apache
  901. does that for us! thies@thieso.net
  902. 20000419 */
  903. #endif
  904. #endif
  905. #ifdef ZTS
  906. tsrm_startup(1, 1, 0, NULL);
  907. #endif
  908. sapi_startup(&cgi_sapi_module);
  909. #ifdef PHP_WIN32
  910. _fmode = _O_BINARY; /* sets default for file streams to binary */
  911. setmode(_fileno(stdin), O_BINARY); /* make the stdio mode be binary */
  912. setmode(_fileno(stdout), O_BINARY); /* make the stdio mode be binary */
  913. setmode(_fileno(stderr), O_BINARY); /* make the stdio mode be binary */
  914. #endif
  915. #if PHP_FASTCGI
  916. if (!fastcgi) {
  917. #endif
  918. /* Make sure we detect we are a cgi - a bit redundancy here,
  919. but the default case is that we have to check only the first one. */
  920. if (getenv("SERVER_SOFTWARE") ||
  921. getenv("SERVER_NAME") ||
  922. getenv("GATEWAY_INTERFACE") ||
  923. getenv("REQUEST_METHOD")
  924. ) {
  925. cgi = 1;
  926. }
  927. #if PHP_FASTCGI
  928. }
  929. #endif
  930. while ((c = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 0)) != -1) {
  931. switch (c) {
  932. case 'c':
  933. cgi_sapi_module.php_ini_path_override = strdup(php_optarg);
  934. break;
  935. case 'n':
  936. cgi_sapi_module.php_ini_ignore = 1;
  937. break;
  938. #if PHP_FASTCGI
  939. #ifndef PHP_WIN32
  940. /* if we're started on command line, check to see if
  941. we are being started as an 'external' fastcgi
  942. server by accepting a bindpath parameter. */
  943. case 'b':
  944. if (!fastcgi) {
  945. bindpath = strdup(php_optarg);
  946. }
  947. break;
  948. #endif
  949. #endif
  950. }
  951. }
  952. php_optind = orig_optind;
  953. php_optarg = orig_optarg;
  954. #ifdef ZTS
  955. compiler_globals = ts_resource(compiler_globals_id);
  956. executor_globals = ts_resource(executor_globals_id);
  957. core_globals = ts_resource(core_globals_id);
  958. sapi_globals = ts_resource(sapi_globals_id);
  959. tsrm_ls = ts_resource(0);
  960. SG(request_info).path_translated = NULL;
  961. #endif
  962. cgi_sapi_module.executable_location = argv[0];
  963. /* startup after we get the above ini override se we get things right */
  964. if (php_module_startup(&cgi_sapi_module, NULL, 0) == FAILURE) {
  965. #ifdef ZTS
  966. tsrm_shutdown();
  967. #endif
  968. return FAILURE;
  969. }
  970. #if FORCE_CGI_REDIRECT
  971. /* check force_cgi after startup, so we have proper output */
  972. if (cfg_get_long("cgi.force_redirect", &force_redirect) == FAILURE) {
  973. force_redirect = 1;
  974. }
  975. if (cgi && force_redirect) {
  976. if (cfg_get_string("cgi.redirect_status_env", &redirect_status_env) == FAILURE) {
  977. redirect_status_env = NULL;
  978. }
  979. /* Apache will generate REDIRECT_STATUS,
  980. * Netscape and redirect.so will generate HTTP_REDIRECT_STATUS.
  981. * redirect.so and installation instructions available from
  982. * http://www.koehntopp.de/php.
  983. * -- kk@netuse.de
  984. */
  985. if (!getenv("REDIRECT_STATUS")
  986. && !getenv ("HTTP_REDIRECT_STATUS")
  987. /* this is to allow a different env var to be configured
  988. in case some server does something different than above */
  989. && (!redirect_status_env || !getenv(redirect_status_env))
  990. ) {
  991. SG(sapi_headers).http_response_code = 400;
  992. PUTS("<b>Security Alert!</b> The PHP CGI cannot be accessed directly.\n\n\
  993. <p>This PHP CGI binary was compiled with force-cgi-redirect enabled. This\n\
  994. means that a page will only be served up if the REDIRECT_STATUS CGI variable is\n\
  995. set, e.g. via an Apache Action directive.</p>\n\
  996. <p>For more information as to <i>why</i> this behaviour exists, see the <a href=\"http://php.net/security.cgi-bin\">\
  997. manual page for CGI security</a>.</p>\n\
  998. <p>For more information about changing this behaviour or re-enabling this webserver,\n\
  999. consult the installation file that came with this distribution, or visit \n\
  1000. <a href=\"http://php.net/install.windows\">the manual page</a>.</p>\n");
  1001. #if defined(ZTS) && !defined(PHP_DEBUG)
  1002. /* XXX we're crashing here in msvc6 debug builds at
  1003. php_message_handler_for_zend:839 because
  1004. SG(request_info).path_translated is an invalid pointer.
  1005. It still happens even though I set it to null, so something
  1006. weird is going on.
  1007. */
  1008. tsrm_shutdown();
  1009. #endif
  1010. return FAILURE;
  1011. }
  1012. }
  1013. #endif /* FORCE_CGI_REDIRECT */
  1014. #if ENABLE_PATHINFO_CHECK
  1015. if (cfg_get_long("cgi.fix_pathinfo", &fix_pathinfo) == FAILURE) {
  1016. fix_pathinfo = 1;
  1017. }
  1018. #endif
  1019. #if PHP_FASTCGI
  1020. if (cfg_get_long("fastcgi.logging", &fcgi_logging) == FAILURE) {
  1021. fcgi_logging = 1;
  1022. }
  1023. #endif
  1024. /* Check wheater to send RFC2616 style headers compatible with
  1025. * PHP versions 4.2.3 and earlier compatible with web servers
  1026. * such as IIS. Default is informal CGI RFC header compatible
  1027. * with Apache.
  1028. */
  1029. if (cfg_get_long("cgi.rfc2616_headers", &rfc2616_headers) == FAILURE) {
  1030. rfc2616_headers = 0;
  1031. }
  1032. if (cfg_get_long("cgi.nph", &cgi_nph) == FAILURE) {
  1033. cgi_nph = 0;
  1034. }
  1035. #if PHP_FASTCGI
  1036. #ifndef PHP_WIN32
  1037. /* for windows, socket listening is broken in the fastcgi library itself
  1038. so dissabling this feature on windows till time is available to fix it */
  1039. if (bindpath) {
  1040. /* Pass on the arg to the FastCGI library, with one exception.
  1041. * If just a port is specified, then we prepend a ':' onto the
  1042. * path (it's what the fastcgi library expects)
  1043. */
  1044. if (strchr(bindpath, ':') == NULL && is_port_number(bindpath)) {
  1045. char *tmp;
  1046. tmp = malloc(strlen(bindpath) + 2);
  1047. tmp[0] = ':';
  1048. memcpy(tmp + 1, bindpath, strlen(bindpath) + 1);
  1049. fcgi_fd = fcgi_listen(tmp, 128);
  1050. free(tmp);
  1051. } else {
  1052. fcgi_fd = fcgi_listen(bindpath, 128);
  1053. }
  1054. if (fcgi_fd < 0) {
  1055. fprintf(stderr, "Couldn't create FastCGI listen socket on port %s\n", bindpath);
  1056. #ifdef ZTS
  1057. tsrm_shutdown();
  1058. #endif
  1059. return FAILURE;
  1060. }
  1061. fastcgi = fcgi_is_fastcgi();
  1062. }
  1063. #endif
  1064. if (fastcgi) {
  1065. /* How many times to run PHP scripts before dying */
  1066. if (getenv("PHP_FCGI_MAX_REQUESTS")) {
  1067. max_requests = atoi(getenv("PHP_FCGI_MAX_REQUESTS"));
  1068. if (max_requests < 0) {
  1069. fprintf(stderr, "PHP_FCGI_MAX_REQUESTS is not valid\n");
  1070. return FAILURE;
  1071. }
  1072. }
  1073. /* make php call us to get _ENV vars */
  1074. php_php_import_environment_variables = php_import_environment_variables;
  1075. php_import_environment_variables = cgi_php_import_environment_variables;
  1076. /* library is already initialized, now init our request */
  1077. fcgi_init_request(&request, fcgi_fd);
  1078. #ifndef PHP_WIN32
  1079. /* Pre-fork, if required */
  1080. if (getenv("PHP_FCGI_CHILDREN")) {
  1081. children = atoi(getenv("PHP_FCGI_CHILDREN"));
  1082. if (children < 0) {
  1083. fprintf(stderr, "PHP_FCGI_CHILDREN is not valid\n");
  1084. return FAILURE;
  1085. }
  1086. }
  1087. if (children) {
  1088. int running = 0;
  1089. pid_t pid;
  1090. /* Create a process group for ourself & children */
  1091. setsid();
  1092. pgroup = getpgrp();
  1093. #ifdef DEBUG_FASTCGI
  1094. fprintf(stderr, "Process group %d\n", pgroup);
  1095. #endif
  1096. /* Set up handler to kill children upon exit */
  1097. act.sa_flags = 0;
  1098. act.sa_handler = fastcgi_cleanup;
  1099. if (sigaction(SIGTERM, &act, &old_term) ||
  1100. sigaction(SIGINT, &act, &old_int) ||
  1101. sigaction(SIGQUIT, &act, &old_quit)) {
  1102. perror("Can't set signals");
  1103. exit(1);
  1104. }
  1105. while (parent) {
  1106. do {
  1107. #ifdef DEBUG_FASTCGI
  1108. fprintf(stderr, "Forking, %d running\n", running);
  1109. #endif
  1110. pid = fork();
  1111. switch (pid) {
  1112. case 0:
  1113. /* One of the children.
  1114. * Make sure we don't go round the
  1115. * fork loop any more
  1116. */
  1117. parent = 0;
  1118. /* don't catch our signals */
  1119. sigaction(SIGTERM, &old_term, 0);
  1120. sigaction(SIGQUIT, &old_quit, 0);
  1121. sigaction(SIGINT, &old_int, 0);
  1122. break;
  1123. case -1:
  1124. perror("php (pre-forking)");
  1125. exit(1);
  1126. break;
  1127. default:
  1128. /* Fine */
  1129. running++;
  1130. break;
  1131. }
  1132. } while (parent && (running < children));
  1133. if (parent) {
  1134. #ifdef DEBUG_FASTCGI
  1135. fprintf(stderr, "Wait for kids, pid %d\n", getpid());
  1136. #endif
  1137. while (wait(&status) < 0) {
  1138. }
  1139. running--;
  1140. }
  1141. }
  1142. } else {
  1143. parent = 0;
  1144. }
  1145. #endif /* WIN32 */
  1146. }
  1147. #endif /* FASTCGI */
  1148. zend_first_try {
  1149. while ((c = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 1)) != -1) {
  1150. switch (c) {
  1151. case 'h':
  1152. case '?':
  1153. no_headers = 1;
  1154. php_output_startup();
  1155. php_output_activate(TSRMLS_C);
  1156. SG(headers_sent) = 1;
  1157. php_cgi_usage(argv[0]);
  1158. php_end_ob_buffers(1 TSRMLS_CC);
  1159. exit(1);
  1160. break;
  1161. }
  1162. }
  1163. php_optind = orig_optind;
  1164. php_optarg = orig_optarg;
  1165. #if PHP_FASTCGI
  1166. /* start of FAST CGI loop */
  1167. /* Initialise FastCGI request structure */
  1168. #ifdef PHP_WIN32
  1169. /* attempt to set security impersonation for fastcgi
  1170. will only happen on NT based OS, others will ignore it. */
  1171. if (fastcgi) {
  1172. if (cfg_get_long("fastcgi.impersonate", &impersonate) == FAILURE) {
  1173. impersonate = 0;
  1174. }
  1175. if (impersonate) fcgi_impersonate();
  1176. }
  1177. #endif
  1178. while (!fastcgi || fcgi_accept_request(&request) >= 0) {
  1179. #endif
  1180. #if PHP_FASTCGI
  1181. SG(server_context) = (void *) &request;
  1182. #else
  1183. SG(server_context) = (void *) 1; /* avoid server_context==NULL checks */
  1184. #endif
  1185. init_request_info(TSRMLS_C);
  1186. zend_llist_init(&global_vars, sizeof(char *), NULL, 0);
  1187. CG(interactive) = 0;
  1188. if (!cgi
  1189. #if PHP_FASTCGI
  1190. && !fastcgi
  1191. #endif
  1192. ) {
  1193. if (cgi_sapi_module.php_ini_path_override && cgi_sapi_module.php_ini_ignore) {
  1194. no_headers = 1;
  1195. php_output_startup();
  1196. php_output_activate(TSRMLS_C);
  1197. SG(headers_sent) = 1;
  1198. php_printf("You cannot use both -n and -c switch. Use -h for help.\n");
  1199. php_end_ob_buffers(1 TSRMLS_CC);
  1200. exit(1);
  1201. }
  1202. while ((c = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 0)) != -1) {
  1203. switch (c) {
  1204. case 'a': /* interactive mode */
  1205. printf("Interactive mode enabled\n\n");
  1206. CG(interactive) = 1;
  1207. break;
  1208. case 'C': /* don't chdir to the script directory */
  1209. SG(options) |= SAPI_OPTION_NO_CHDIR;
  1210. break;
  1211. case 'd': /* define ini entries on command line */
  1212. define_command_line_ini_entry(php_optarg);
  1213. break;
  1214. case 'e': /* enable extended info output */
  1215. CG(extended_info) = 1;
  1216. break;
  1217. case 'f': /* parse file */
  1218. script_file = estrdup(php_optarg);
  1219. no_headers = 1;
  1220. /* arguments after the file are considered script args */
  1221. SG(request_info).argc = argc - (php_optind - 1);
  1222. SG(request_info).argv = &argv[php_optind - 1];
  1223. break;
  1224. case 'g': /* define global variables on command line */
  1225. {
  1226. char *arg = estrdup(php_optarg);
  1227. zend_llist_add_element(&global_vars, &arg);
  1228. }
  1229. break;
  1230. case 'i': /* php info & quit */
  1231. if (php_request_startup(TSRMLS_C) == FAILURE) {
  1232. php_module_shutdown(TSRMLS_C);
  1233. return FAILURE;
  1234. }
  1235. if (no_headers) {
  1236. SG(headers_sent) = 1;
  1237. SG(request_info).no_headers = 1;
  1238. }
  1239. php_print_info(0xFFFFFFFF TSRMLS_CC);
  1240. php_end_ob_buffers(1 TSRMLS_CC);
  1241. exit(0);
  1242. break;
  1243. case 'l': /* syntax check mode */
  1244. no_headers = 1;
  1245. behavior = PHP_MODE_LINT;
  1246. break;
  1247. case 'm': /* list compiled in modules */
  1248. php_output_startup();
  1249. php_output_activate(TSRMLS_C);
  1250. SG(headers_sent) = 1;
  1251. php_printf("[PHP Modules]\n");
  1252. print_modules(TSRMLS_C);
  1253. php_printf("\n[Zend Modules]\n");
  1254. print_extensions(TSRMLS_C);
  1255. php_printf("\n");
  1256. php_end_ob_buffers(1 TSRMLS_CC);
  1257. exit(0);
  1258. break;
  1259. #if 0 /* not yet operational, see also below ... */
  1260. case '': /* generate indented source mode*/
  1261. behavior=PHP_MODE_INDENT;
  1262. break;
  1263. #endif
  1264. case 'q': /* do not generate HTTP headers */
  1265. no_headers = 1;
  1266. break;
  1267. case 's': /* generate highlighted HTML from source */
  1268. behavior = PHP_MODE_HIGHLIGHT;
  1269. break;
  1270. case 'v': /* show php version & quit */
  1271. no_headers = 1;
  1272. if (php_request_startup(TSRMLS_C) == FAILURE) {
  1273. php_module_shutdown(TSRMLS_C);
  1274. return FAILURE;
  1275. }
  1276. if (no_headers) {
  1277. SG(headers_sent) = 1;
  1278. SG(request_info).no_headers = 1;
  1279. }
  1280. #if ZEND_DEBUG
  1281. php_printf("PHP %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2006 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version());
  1282. #else
  1283. php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2006 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version());
  1284. #endif
  1285. php_end_ob_buffers(1 TSRMLS_CC);
  1286. exit(0);
  1287. break;
  1288. case 'w':
  1289. behavior = PHP_MODE_STRIP;
  1290. break;
  1291. case 'z': /* load extension file */
  1292. zend_load_extension(php_optarg);
  1293. break;
  1294. default:
  1295. break;
  1296. }
  1297. }
  1298. if (script_file) {
  1299. /* override path_translated if -f on command line */
  1300. STR_FREE(SG(request_info).path_translated);
  1301. SG(request_info).path_translated = script_file;
  1302. }
  1303. if (no_headers) {
  1304. SG(headers_sent) = 1;
  1305. SG(request_info).no_headers = 1;
  1306. }
  1307. if (!SG(request_info).path_translated && argc > php_optind) {
  1308. /* arguments after the file are considered script args */
  1309. SG(request_info).argc = argc - php_optind;
  1310. SG(request_info).argv = &argv[php_optind];
  1311. /* file is on command line, but not in -f opt */
  1312. SG(request_info).path_translated = estrdup(argv[php_optind++]);
  1313. }
  1314. /* all remaining arguments are part of the query string
  1315. this section of code concatenates all remaining arguments
  1316. into a single string, seperating args with a &
  1317. this allows command lines like:
  1318. test.php v1=test v2=hello+world!
  1319. test.php "v1=test&v2=hello world!"
  1320. test.php v1=test "v2=hello world!"
  1321. */
  1322. if (!SG(request_info).query_string && argc > php_optind) {
  1323. len = 0;
  1324. for (i = php_optind; i < argc; i++) {
  1325. len += strlen(argv[i]) + 1;
  1326. }
  1327. s = malloc(len + 1); /* leak - but only for command line version, so ok */
  1328. *s = '\0'; /* we are pretending it came from the environment */
  1329. for (i = php_optind, len = 0; i < argc; i++) {
  1330. strcat(s, argv[i]);
  1331. if (i < (argc - 1)) {
  1332. strcat(s, PG(arg_separator).input);
  1333. }
  1334. }
  1335. SG(request_info).query_string = s;
  1336. }
  1337. } /* end !cgi && !fastcgi */
  1338. /*
  1339. we never take stdin if we're (f)cgi, always
  1340. rely on the web server giving us the info
  1341. we need in the environment.
  1342. */
  1343. if (SG(request_info).path_translated || cgi
  1344. #if PHP_FASTCGI
  1345. || fastcgi
  1346. #endif
  1347. )
  1348. {
  1349. file_handle.type = ZEND_HANDLE_FILENAME;
  1350. file_handle.filename = SG(request_info).path_translated;
  1351. file_handle.handle.fp = NULL;
  1352. } else {
  1353. file_handle.filename = "-";
  1354. file_handle.type = ZEND_HANDLE_FP;
  1355. file_handle.handle.fp = stdin;
  1356. }
  1357. file_handle.opened_path = NULL;
  1358. file_handle.free_filename = 0;
  1359. /* request startup only after we've done all we can to
  1360. get path_translated */
  1361. if (php_request_startup(TSRMLS_C) == FAILURE) {
  1362. #if PHP_FASTCGI
  1363. if (fastcgi) {
  1364. fcgi_finish_request(&request);
  1365. }
  1366. #endif
  1367. php_module_shutdown(TSRMLS_C);
  1368. return FAILURE;
  1369. }
  1370. if (no_headers) {
  1371. SG(headers_sent) = 1;
  1372. SG(request_info).no_headers = 1;
  1373. }
  1374. /* This actually destructs the elements of the list - ugly hack */
  1375. zend_llist_apply(&global_vars, (llist_apply_func_t) php_register_command_line_global_vars TSRMLS_CC);
  1376. zend_llist_destroy(&global_vars);
  1377. /*
  1378. at this point path_translated will be set if:
  1379. 1. we are running from shell and got filename was there
  1380. 2. we are running as cgi or fastcgi
  1381. */
  1382. if (cgi || SG(request_info).path_translated) {
  1383. retval = php_fopen_primary_script(&file_handle TSRMLS_CC);
  1384. }
  1385. /*
  1386. if we are unable to open path_translated and we are not
  1387. running from shell (so fp == NULL), then fail.
  1388. */
  1389. if (retval == FAILURE && file_handle.handle.fp == NULL) {
  1390. SG(sapi_headers).http_response_code = 404;
  1391. PUTS("No input file specified.\n");
  1392. #if PHP_FASTCGI
  1393. /* we want to serve more requests if this is fastcgi
  1394. so cleanup and continue, request shutdown is
  1395. handled later */
  1396. if (fastcgi) {
  1397. goto fastcgi_request_done;
  1398. }
  1399. #endif
  1400. php_request_shutdown((void *) 0);
  1401. php_module_shutdown(TSRMLS_C);
  1402. return FAILURE;
  1403. }
  1404. if (file_handle.handle.fp && (file_handle.handle.fp != stdin)) {
  1405. /* #!php support */
  1406. c = fgetc(file_handle.handle.fp);
  1407. if (c == '#') {
  1408. while (c != 10 && c != 13) {
  1409. c = fgetc(file_handle.handle.fp); /* skip to end of line */
  1410. }
  1411. /* handle situations where line is terminated by \r\n */
  1412. if (c == 13) {
  1413. if (fgetc(file_handle.handle.fp) != 10) {
  1414. long pos = ftell(file_handle.handle.fp);
  1415. fseek(file_handle.handle.fp, pos - 1, SEEK_SET);
  1416. }
  1417. }
  1418. CG(start_lineno) = 2;
  1419. } else {
  1420. rewind(file_handle.handle.fp);
  1421. }
  1422. }
  1423. switch (behavior) {
  1424. case PHP_MODE_STANDARD:
  1425. php_execute_script(&file_handle TSRMLS_CC);
  1426. break;
  1427. case PHP_MODE_LINT:
  1428. PG(during_request_startup) = 0;
  1429. exit_status = php_lint_script(&file_handle TSRMLS_CC);
  1430. if (exit_status == SUCCESS) {
  1431. zend_printf("No syntax errors detected in %s\n", file_handle.filename);
  1432. } else {
  1433. zend_printf("Errors parsing %s\n", file_handle.filename);
  1434. }
  1435. break;
  1436. case PHP_MODE_STRIP:
  1437. if (open_file_for_scanning(&file_handle TSRMLS_CC) == SUCCESS) {
  1438. zend_strip(TSRMLS_C);
  1439. fclose(file_handle.handle.fp);
  1440. php_end_ob_buffers(1 TSRMLS_CC);
  1441. }
  1442. return SUCCESS;
  1443. break;
  1444. case PHP_MODE_HIGHLIGHT:
  1445. {
  1446. zend_syntax_highlighter_ini syntax_highlighter_ini;
  1447. if (open_file_for_scanning(&file_handle TSRMLS_CC) == SUCCESS) {
  1448. php_get_highlight_struct(&syntax_highlighter_ini);
  1449. zend_highlight(&syntax_highlighter_ini TSRMLS_CC);
  1450. fclose(file_handle.handle.fp);
  1451. php_end_ob_buffers(1 TSRMLS_CC);
  1452. }
  1453. return SUCCESS;
  1454. }
  1455. break;
  1456. #if 0
  1457. /* Zeev might want to do something with this one day */
  1458. case PHP_MODE_INDENT:
  1459. open_file_for_scanning(&file_handle TSRMLS_CC);
  1460. zend_indent();
  1461. fclose(file_handle.handle.fp);
  1462. return SUCCESS;
  1463. break;
  1464. #endif
  1465. }
  1466. #if PHP_FASTCGI
  1467. fastcgi_request_done:
  1468. #endif
  1469. {
  1470. char *path_translated;
  1471. /* Go through this trouble so that the memory manager doesn't warn
  1472. * about SG(request_info).path_translated leaking
  1473. */
  1474. if (SG(request_info).path_translated) {
  1475. path_translated = strdup(SG(request_info).path_translated);
  1476. STR_FREE(SG(request_info).path_translated);
  1477. SG(request_info).path_translated = path_translated;
  1478. }
  1479. php_request_shutdown((void *) 0);
  1480. if (exit_status == 0) {
  1481. exit_status = EG(exit_status);
  1482. }
  1483. if (SG(request_info).path_translated) {
  1484. free(SG(request_info).path_translated);
  1485. SG(request_info).path_translated = NULL;
  1486. }
  1487. }
  1488. #if PHP_FASTCGI
  1489. if (!fastcgi) break;
  1490. /* only fastcgi will get here */
  1491. requests++;
  1492. if (max_requests && (requests == max_requests)) {
  1493. fcgi_finish_request(&request);
  1494. #ifndef PHP_WIN32
  1495. if (bindpath) {
  1496. free(bindpath);
  1497. }
  1498. #endif
  1499. break;
  1500. }
  1501. /* end of fastcgi loop */
  1502. }
  1503. #endif
  1504. if (cgi_sapi_module.php_ini_path_override) {
  1505. free(cgi_sapi_module.php_ini_path_override);
  1506. }
  1507. } zend_catch {
  1508. exit_status = 255;
  1509. } zend_end_try();
  1510. SG(server_context) = NULL;
  1511. php_module_shutdown(TSRMLS_C);
  1512. sapi_shutdown();
  1513. #ifdef ZTS
  1514. /*tsrm_shutdown();*/
  1515. #endif
  1516. #if defined(PHP_WIN32) && ZEND_DEBUG && 0
  1517. _CrtDumpMemoryLeaks();
  1518. #endif
  1519. return exit_status;
  1520. }
  1521. /* }}} */
  1522. /*
  1523. * Local variables:
  1524. * tab-width: 4
  1525. * c-basic-offset: 4
  1526. * End:
  1527. * vim600: sw=4 ts=4 fdm=marker
  1528. * vim<600: sw=4 ts=4
  1529. */