1 /*
2    +----------------------------------------------------------------------+
3    | Copyright (c) The PHP Group                                          |
4    +----------------------------------------------------------------------+
5    | This source file is subject to version 3.01 of the PHP license,      |
6    | that is bundled with this package in the file LICENSE, and is        |
7    | available through the world-wide-web at the following url:           |
8    | https://www.php.net/license/3_01.txt                                 |
9    | If you did not receive a copy of the PHP license and are unable to   |
10    | obtain it through the world-wide-web, please send a note to          |
11    | license@php.net so we can mail you a copy immediately.               |
12    +----------------------------------------------------------------------+
13    | Author: Edin Kadribasic <edink@php.net>                              |
14    |         Marcus Boerger <helly@php.net>                               |
15    |         Johannes Schlueter <johannes@php.net>                        |
16    |         Parts based on CGI SAPI Module by                            |
17    |         Rasmus Lerdorf, Stig Bakken and Zeev Suraski                 |
18    +----------------------------------------------------------------------+
19 */
20 
21 #include "php.h"
22 #include "php_globals.h"
23 #include "php_variables.h"
24 #include "zend_hash.h"
25 #include "zend_modules.h"
26 #include "zend_interfaces.h"
27 
28 #include "ext/reflection/php_reflection.h"
29 
30 #include "SAPI.h"
31 
32 #include <stdio.h>
33 #include "php.h"
34 #ifdef PHP_WIN32
35 #include "win32/time.h"
36 #include "win32/signal.h"
37 #include "win32/console.h"
38 #include <process.h>
39 #include <shellapi.h>
40 #endif
41 #if HAVE_SYS_TIME_H
42 #include <sys/time.h>
43 #endif
44 #if HAVE_UNISTD_H
45 #include <unistd.h>
46 #endif
47 
48 #include <signal.h>
49 #include <locale.h>
50 #include "zend.h"
51 #include "zend_extensions.h"
52 #include "php_ini.h"
53 #include "php_globals.h"
54 #include "php_main.h"
55 #include "fopen_wrappers.h"
56 #include "ext/standard/php_standard.h"
57 #include "ext/standard/dl_arginfo.h"
58 #include "cli.h"
59 #ifdef PHP_WIN32
60 #include <io.h>
61 #include <fcntl.h>
62 #include "win32/php_registry.h"
63 #endif
64 
65 #ifdef __riscos__
66 #include <unixlib/local.h>
67 #endif
68 
69 #include "zend_compile.h"
70 #include "zend_execute.h"
71 #include "zend_highlight.h"
72 #include "zend_exceptions.h"
73 
74 #include "php_getopt.h"
75 
76 #ifndef PHP_CLI_WIN32_NO_CONSOLE
77 #include "php_cli_server.h"
78 #endif
79 
80 #include "ps_title.h"
81 #include "php_cli_process_title.h"
82 #include "php_cli_process_title_arginfo.h"
83 
84 #ifndef PHP_WIN32
85 # define php_select(m, r, w, e, t)	select(m, r, w, e, t)
86 #else
87 # include "win32/select.h"
88 #endif
89 
90 #if defined(PHP_WIN32) && defined(HAVE_OPENSSL)
91 # include "openssl/applink.c"
92 #endif
93 
94 PHPAPI extern char *php_ini_opened_path;
95 PHPAPI extern char *php_ini_scanned_path;
96 PHPAPI extern char *php_ini_scanned_files;
97 
98 #if defined(PHP_WIN32)
99 #if defined(ZTS)
100 ZEND_TSRMLS_CACHE_DEFINE()
101 #endif
102 static DWORD orig_cp = 0;
103 #endif
104 
105 #ifndef O_BINARY
106 #define O_BINARY 0
107 #endif
108 
109 #define PHP_MODE_STANDARD      1
110 #define PHP_MODE_HIGHLIGHT     2
111 #define PHP_MODE_LINT          4
112 #define PHP_MODE_STRIP         5
113 #define PHP_MODE_CLI_DIRECT    6
114 #define PHP_MODE_PROCESS_STDIN 7
115 #define PHP_MODE_REFLECTION_FUNCTION    8
116 #define PHP_MODE_REFLECTION_CLASS       9
117 #define PHP_MODE_REFLECTION_EXTENSION   10
118 #define PHP_MODE_REFLECTION_EXT_INFO    11
119 #define PHP_MODE_REFLECTION_ZEND_EXTENSION 12
120 #define PHP_MODE_SHOW_INI_CONFIG        13
121 
122 cli_shell_callbacks_t cli_shell_callbacks = { NULL, NULL, NULL };
php_cli_get_shell_callbacks(void)123 PHP_CLI_API cli_shell_callbacks_t *php_cli_get_shell_callbacks(void)
124 {
125 	return &cli_shell_callbacks;
126 }
127 
128 const char HARDCODED_INI[] =
129 	"html_errors=0\n"
130 	"register_argc_argv=1\n"
131 	"implicit_flush=1\n"
132 	"output_buffering=0\n"
133 	"max_execution_time=0\n"
134 	"max_input_time=-1\n\0";
135 
136 
137 const opt_struct OPTIONS[] = {
138 	{'a', 0, "interactive"},
139 	{'B', 1, "process-begin"},
140 	{'C', 0, "no-chdir"}, /* for compatibility with CGI (do not chdir to script directory) */
141 	{'c', 1, "php-ini"},
142 	{'d', 1, "define"},
143 	{'E', 1, "process-end"},
144 	{'e', 0, "profile-info"},
145 	{'F', 1, "process-file"},
146 	{'f', 1, "file"},
147 	{'h', 0, "help"},
148 	{'i', 0, "info"},
149 	{'l', 0, "syntax-check"},
150 	{'m', 0, "modules"},
151 	{'n', 0, "no-php-ini"},
152 	{'q', 0, "no-header"}, /* for compatibility with CGI (do not generate HTTP headers) */
153 	{'R', 1, "process-code"},
154 	{'H', 0, "hide-args"},
155 	{'r', 1, "run"},
156 	{'s', 0, "syntax-highlight"},
157 	{'s', 0, "syntax-highlighting"},
158 	{'S', 1, "server"},
159 	{'t', 1, "docroot"},
160 	{'w', 0, "strip"},
161 	{'?', 0, "usage"},/* help alias (both '?' and 'usage') */
162 	{'v', 0, "version"},
163 	{'z', 1, "zend-extension"},
164 	{10,  1, "rf"},
165 	{10,  1, "rfunction"},
166 	{11,  1, "rc"},
167 	{11,  1, "rclass"},
168 	{12,  1, "re"},
169 	{12,  1, "rextension"},
170 	{13,  1, "rz"},
171 	{13,  1, "rzendextension"},
172 	{14,  1, "ri"},
173 	{14,  1, "rextinfo"},
174 	{15,  0, "ini"},
175 	/* Internal testing option -- may be changed or removed without notice,
176 	 * including in patch releases. */
177 	{16,  1, "repeat"},
178 	{'-', 0, NULL} /* end of args */
179 };
180 
module_name_cmp(Bucket * f,Bucket * s)181 static int module_name_cmp(Bucket *f, Bucket *s) /* {{{ */
182 {
183 	return strcasecmp(((zend_module_entry *)Z_PTR(f->val))->name,
184 				  ((zend_module_entry *)Z_PTR(s->val))->name);
185 }
186 /* }}} */
187 
print_modules(void)188 static void print_modules(void) /* {{{ */
189 {
190 	HashTable sorted_registry;
191 	zend_module_entry *module;
192 
193 	zend_hash_init(&sorted_registry, 50, NULL, NULL, 0);
194 	zend_hash_copy(&sorted_registry, &module_registry, NULL);
195 	zend_hash_sort(&sorted_registry, module_name_cmp, 0);
196 	ZEND_HASH_FOREACH_PTR(&sorted_registry, module) {
197 		php_printf("%s\n", module->name);
198 	} ZEND_HASH_FOREACH_END();
199 	zend_hash_destroy(&sorted_registry);
200 }
201 /* }}} */
202 
print_extension_info(zend_extension * ext)203 static void print_extension_info(zend_extension *ext) /* {{{ */
204 {
205 	php_printf("%s\n", ext->name);
206 }
207 /* }}} */
208 
extension_name_cmp(const zend_llist_element ** f,const zend_llist_element ** s)209 static int extension_name_cmp(const zend_llist_element **f, const zend_llist_element **s) /* {{{ */
210 {
211 	zend_extension *fe = (zend_extension*)(*f)->data;
212 	zend_extension *se = (zend_extension*)(*s)->data;
213 	return strcmp(fe->name, se->name);
214 }
215 /* }}} */
216 
print_extensions(void)217 static void print_extensions(void) /* {{{ */
218 {
219 	zend_llist sorted_exts;
220 
221 	zend_llist_copy(&sorted_exts, &zend_extensions);
222 	sorted_exts.dtor = NULL;
223 	zend_llist_sort(&sorted_exts, extension_name_cmp);
224 	zend_llist_apply(&sorted_exts, (llist_apply_func_t) print_extension_info);
225 	zend_llist_destroy(&sorted_exts);
226 }
227 /* }}} */
228 
229 #ifndef STDOUT_FILENO
230 #define STDOUT_FILENO 1
231 #endif
232 #ifndef STDERR_FILENO
233 #define STDERR_FILENO 2
234 #endif
235 
sapi_cli_select(php_socket_t fd)236 static inline int sapi_cli_select(php_socket_t fd)
237 {
238 	fd_set wfd;
239 	struct timeval tv;
240 	int ret;
241 
242 	FD_ZERO(&wfd);
243 
244 	PHP_SAFE_FD_SET(fd, &wfd);
245 
246 	tv.tv_sec = (long)FG(default_socket_timeout);
247 	tv.tv_usec = 0;
248 
249 	ret = php_select(fd+1, NULL, &wfd, NULL, &tv);
250 
251 	return ret != -1;
252 }
253 
sapi_cli_single_write(const char * str,size_t str_length)254 PHP_CLI_API ssize_t sapi_cli_single_write(const char *str, size_t str_length) /* {{{ */
255 {
256 	ssize_t ret;
257 
258 	if (cli_shell_callbacks.cli_shell_write) {
259 		cli_shell_callbacks.cli_shell_write(str, str_length);
260 	}
261 
262 #ifdef PHP_WRITE_STDOUT
263 	do {
264 		ret = write(STDOUT_FILENO, str, str_length);
265 	} while (ret <= 0 && errno == EAGAIN && sapi_cli_select(STDOUT_FILENO));
266 #else
267 	ret = fwrite(str, 1, MIN(str_length, 16384), stdout);
268 	if (ret == 0 && ferror(stdout)) {
269 		return -1;
270 	}
271 #endif
272 	return ret;
273 }
274 /* }}} */
275 
sapi_cli_ub_write(const char * str,size_t str_length)276 static size_t sapi_cli_ub_write(const char *str, size_t str_length) /* {{{ */
277 {
278 	const char *ptr = str;
279 	size_t remaining = str_length;
280 	ssize_t ret;
281 
282 	if (!str_length) {
283 		return 0;
284 	}
285 
286 	if (cli_shell_callbacks.cli_shell_ub_write) {
287 		size_t ub_wrote;
288 		ub_wrote = cli_shell_callbacks.cli_shell_ub_write(str, str_length);
289 		if (ub_wrote != (size_t) -1) {
290 			return ub_wrote;
291 		}
292 	}
293 
294 	while (remaining > 0)
295 	{
296 		ret = sapi_cli_single_write(ptr, remaining);
297 		if (ret < 0) {
298 #ifndef PHP_CLI_WIN32_NO_CONSOLE
299 			EG(exit_status) = 255;
300 			php_handle_aborted_connection();
301 #endif
302 			break;
303 		}
304 		ptr += ret;
305 		remaining -= ret;
306 	}
307 
308 	return (ptr - str);
309 }
310 /* }}} */
311 
sapi_cli_flush(void * server_context)312 static void sapi_cli_flush(void *server_context) /* {{{ */
313 {
314 	/* Ignore EBADF here, it's caused by the fact that STDIN/STDOUT/STDERR streams
315 	 * are/could be closed before fflush() is called.
316 	 */
317 	if (fflush(stdout)==EOF && errno!=EBADF) {
318 #ifndef PHP_CLI_WIN32_NO_CONSOLE
319 		php_handle_aborted_connection();
320 #endif
321 	}
322 }
323 /* }}} */
324 
325 static char *php_self = "";
326 static char *script_filename = "";
327 
sapi_cli_register_variables(zval * track_vars_array)328 static void sapi_cli_register_variables(zval *track_vars_array) /* {{{ */
329 {
330 	size_t len;
331 	char   *docroot = "";
332 
333 	/* In CGI mode, we consider the environment to be a part of the server
334 	 * variables
335 	 */
336 	php_import_environment_variables(track_vars_array);
337 
338 	/* Build the special-case PHP_SELF variable for the CLI version */
339 	len = strlen(php_self);
340 	if (sapi_module.input_filter(PARSE_SERVER, "PHP_SELF", &php_self, len, &len)) {
341 		php_register_variable("PHP_SELF", php_self, track_vars_array);
342 	}
343 	if (sapi_module.input_filter(PARSE_SERVER, "SCRIPT_NAME", &php_self, len, &len)) {
344 		php_register_variable("SCRIPT_NAME", php_self, track_vars_array);
345 	}
346 	/* filenames are empty for stdin */
347 	len = strlen(script_filename);
348 	if (sapi_module.input_filter(PARSE_SERVER, "SCRIPT_FILENAME", &script_filename, len, &len)) {
349 		php_register_variable("SCRIPT_FILENAME", script_filename, track_vars_array);
350 	}
351 	if (sapi_module.input_filter(PARSE_SERVER, "PATH_TRANSLATED", &script_filename, len, &len)) {
352 		php_register_variable("PATH_TRANSLATED", script_filename, track_vars_array);
353 	}
354 	/* just make it available */
355 	len = 0U;
356 	if (sapi_module.input_filter(PARSE_SERVER, "DOCUMENT_ROOT", &docroot, len, &len)) {
357 		php_register_variable("DOCUMENT_ROOT", docroot, track_vars_array);
358 	}
359 }
360 /* }}} */
361 
sapi_cli_log_message(const char * message,int syslog_type_int)362 static void sapi_cli_log_message(const char *message, int syslog_type_int) /* {{{ */
363 {
364 	fprintf(stderr, "%s\n", message);
365 #ifdef PHP_WIN32
366 	fflush(stderr);
367 #endif
368 }
369 /* }}} */
370 
sapi_cli_deactivate(void)371 static int sapi_cli_deactivate(void) /* {{{ */
372 {
373 	fflush(stdout);
374 	if(SG(request_info).argv0) {
375 		free(SG(request_info).argv0);
376 		SG(request_info).argv0 = NULL;
377 	}
378 	return SUCCESS;
379 }
380 /* }}} */
381 
sapi_cli_read_cookies(void)382 static char* sapi_cli_read_cookies(void) /* {{{ */
383 {
384 	return NULL;
385 }
386 /* }}} */
387 
sapi_cli_header_handler(sapi_header_struct * h,sapi_header_op_enum op,sapi_headers_struct * s)388 static int sapi_cli_header_handler(sapi_header_struct *h, sapi_header_op_enum op, sapi_headers_struct *s) /* {{{ */
389 {
390 	return 0;
391 }
392 /* }}} */
393 
sapi_cli_send_headers(sapi_headers_struct * sapi_headers)394 static int sapi_cli_send_headers(sapi_headers_struct *sapi_headers) /* {{{ */
395 {
396 	/* We do nothing here, this function is needed to prevent that the fallback
397 	 * header handling is called. */
398 	return SAPI_HEADER_SENT_SUCCESSFULLY;
399 }
400 /* }}} */
401 
sapi_cli_send_header(sapi_header_struct * sapi_header,void * server_context)402 static void sapi_cli_send_header(sapi_header_struct *sapi_header, void *server_context) /* {{{ */
403 {
404 }
405 /* }}} */
406 
php_cli_startup(sapi_module_struct * sapi_module)407 static int php_cli_startup(sapi_module_struct *sapi_module) /* {{{ */
408 {
409 	if (php_module_startup(sapi_module, NULL, 0)==FAILURE) {
410 		return FAILURE;
411 	}
412 	return SUCCESS;
413 }
414 /* }}} */
415 
416 /* {{{ sapi_cli_ini_defaults */
417 
418 /* overwritable ini defaults must be set in sapi_cli_ini_defaults() */
419 #define INI_DEFAULT(name,value)\
420 	ZVAL_NEW_STR(&tmp, zend_string_init(value, sizeof(value)-1, 1));\
421 	zend_hash_str_update(configuration_hash, name, sizeof(name)-1, &tmp);\
422 
sapi_cli_ini_defaults(HashTable * configuration_hash)423 static void sapi_cli_ini_defaults(HashTable *configuration_hash)
424 {
425 	zval tmp;
426 	INI_DEFAULT("display_errors", "1");
427 }
428 /* }}} */
429 
430 /* {{{ sapi_module_struct cli_sapi_module */
431 static sapi_module_struct cli_sapi_module = {
432 	"cli",							/* name */
433 	"Command Line Interface",    	/* pretty name */
434 
435 	php_cli_startup,				/* startup */
436 	php_module_shutdown_wrapper,	/* shutdown */
437 
438 	NULL,							/* activate */
439 	sapi_cli_deactivate,			/* deactivate */
440 
441 	sapi_cli_ub_write,		    	/* unbuffered write */
442 	sapi_cli_flush,				    /* flush */
443 	NULL,							/* get uid */
444 	NULL,							/* getenv */
445 
446 	php_error,						/* error handler */
447 
448 	sapi_cli_header_handler,		/* header handler */
449 	sapi_cli_send_headers,			/* send headers handler */
450 	sapi_cli_send_header,			/* send header handler */
451 
452 	NULL,				            /* read POST data */
453 	sapi_cli_read_cookies,          /* read Cookies */
454 
455 	sapi_cli_register_variables,	/* register server variables */
456 	sapi_cli_log_message,			/* Log message */
457 	NULL,							/* Get request time */
458 	NULL,							/* Child terminate */
459 
460 	STANDARD_SAPI_MODULE_PROPERTIES
461 };
462 /* }}} */
463 
464 static const zend_function_entry additional_functions[] = {
465 	ZEND_FE(dl, arginfo_dl)
466 	PHP_FE(cli_set_process_title,        arginfo_cli_set_process_title)
467 	PHP_FE(cli_get_process_title,        arginfo_cli_get_process_title)
468 	PHP_FE_END
469 };
470 
471 /* {{{ php_cli_usage */
php_cli_usage(char * argv0)472 static void php_cli_usage(char *argv0)
473 {
474 	char *prog;
475 
476 	prog = strrchr(argv0, '/');
477 	if (prog) {
478 		prog++;
479 	} else {
480 		prog = "php";
481 	}
482 
483 	printf( "Usage: %s [options] [-f] <file> [--] [args...]\n"
484 				"   %s [options] -r <code> [--] [args...]\n"
485 				"   %s [options] [-B <begin_code>] -R <code> [-E <end_code>] [--] [args...]\n"
486 				"   %s [options] [-B <begin_code>] -F <file> [-E <end_code>] [--] [args...]\n"
487 				"   %s [options] -S <addr>:<port> [-t docroot] [router]\n"
488 				"   %s [options] -- [args...]\n"
489 				"   %s [options] -a\n"
490 				"\n"
491 				"  -a               Run as interactive shell (requires readline extension)\n"
492 				"  -c <path>|<file> Look for php.ini file in this directory\n"
493 				"  -n               No configuration (ini) files will be used\n"
494 				"  -d foo[=bar]     Define INI entry foo with value 'bar'\n"
495 				"  -e               Generate extended information for debugger/profiler\n"
496 				"  -f <file>        Parse and execute <file>.\n"
497 				"  -h               This help\n"
498 				"  -i               PHP information\n"
499 				"  -l               Syntax check only (lint)\n"
500 				"  -m               Show compiled in modules\n"
501 				"  -r <code>        Run PHP <code> without using script tags <?..?>\n"
502 				"  -B <begin_code>  Run PHP <begin_code> before processing input lines\n"
503 				"  -R <code>        Run PHP <code> for every input line\n"
504 				"  -F <file>        Parse and execute <file> for every input line\n"
505 				"  -E <end_code>    Run PHP <end_code> after processing all input lines\n"
506 				"  -H               Hide any passed arguments from external tools.\n"
507 				"  -S <addr>:<port> Run with built-in web server.\n"
508 				"  -t <docroot>     Specify document root <docroot> for built-in web server.\n"
509 				"  -s               Output HTML syntax highlighted source.\n"
510 				"  -v               Version number\n"
511 				"  -w               Output source with stripped comments and whitespace.\n"
512 				"  -z <file>        Load Zend extension <file>.\n"
513 				"\n"
514 				"  args...          Arguments passed to script. Use -- args when first argument\n"
515 				"                   starts with - or script is read from stdin\n"
516 				"\n"
517 				"  --ini            Show configuration file names\n"
518 				"\n"
519 				"  --rf <name>      Show information about function <name>.\n"
520 				"  --rc <name>      Show information about class <name>.\n"
521 				"  --re <name>      Show information about extension <name>.\n"
522 				"  --rz <name>      Show information about Zend extension <name>.\n"
523 				"  --ri <name>      Show configuration for extension <name>.\n"
524 				"\n"
525 				, prog, prog, prog, prog, prog, prog, prog);
526 }
527 /* }}} */
528 
529 static php_stream *s_in_process = NULL;
530 
cli_register_file_handles(bool no_close)531 static void cli_register_file_handles(bool no_close) /* {{{ */
532 {
533 	php_stream *s_in, *s_out, *s_err;
534 	php_stream_context *sc_in=NULL, *sc_out=NULL, *sc_err=NULL;
535 	zend_constant ic, oc, ec;
536 
537 	s_in  = php_stream_open_wrapper_ex("php://stdin",  "rb", 0, NULL, sc_in);
538 	s_out = php_stream_open_wrapper_ex("php://stdout", "wb", 0, NULL, sc_out);
539 	s_err = php_stream_open_wrapper_ex("php://stderr", "wb", 0, NULL, sc_err);
540 
541 	if (s_in==NULL || s_out==NULL || s_err==NULL) {
542 		if (s_in) php_stream_close(s_in);
543 		if (s_out) php_stream_close(s_out);
544 		if (s_err) php_stream_close(s_err);
545 		return;
546 	}
547 
548 	if (no_close) {
549 		s_in->flags |= PHP_STREAM_FLAG_NO_CLOSE;
550 		s_out->flags |= PHP_STREAM_FLAG_NO_CLOSE;
551 		s_err->flags |= PHP_STREAM_FLAG_NO_CLOSE;
552 	}
553 
554 	s_in_process = s_in;
555 
556 	php_stream_to_zval(s_in,  &ic.value);
557 	php_stream_to_zval(s_out, &oc.value);
558 	php_stream_to_zval(s_err, &ec.value);
559 
560 	ZEND_CONSTANT_SET_FLAGS(&ic, CONST_CS, 0);
561 	ic.name = zend_string_init_interned("STDIN", sizeof("STDIN")-1, 0);
562 	zend_register_constant(&ic);
563 
564 	ZEND_CONSTANT_SET_FLAGS(&oc, CONST_CS, 0);
565 	oc.name = zend_string_init_interned("STDOUT", sizeof("STDOUT")-1, 0);
566 	zend_register_constant(&oc);
567 
568 	ZEND_CONSTANT_SET_FLAGS(&ec, CONST_CS, 0);
569 	ec.name = zend_string_init_interned("STDERR", sizeof("STDERR")-1, 0);
570 	zend_register_constant(&ec);
571 }
572 /* }}} */
573 
574 static const char *param_mode_conflict = "Either execute direct code, process stdin or use a file.\n";
575 
576 /* {{{ cli_seek_file_begin */
cli_seek_file_begin(zend_file_handle * file_handle,char * script_file)577 static int cli_seek_file_begin(zend_file_handle *file_handle, char *script_file)
578 {
579 	FILE *fp = VCWD_FOPEN(script_file, "rb");
580 	if (!fp) {
581 		php_printf("Could not open input file: %s\n", script_file);
582 		return FAILURE;
583 	}
584 
585 	zend_stream_init_fp(file_handle, fp, script_file);
586 	file_handle->primary_script = 1;
587 	return SUCCESS;
588 }
589 /* }}} */
590 
591 /*{{{ php_cli_win32_ctrl_handler */
592 #if defined(PHP_WIN32)
php_cli_win32_ctrl_handler(DWORD sig)593 BOOL WINAPI php_cli_win32_ctrl_handler(DWORD sig)
594 {
595 	(void)php_win32_cp_cli_do_restore(orig_cp);
596 
597 	return FALSE;
598 }
599 #endif
600 /*}}}*/
601 
do_cli(int argc,char ** argv)602 static int do_cli(int argc, char **argv) /* {{{ */
603 {
604 	int c;
605 	zend_file_handle file_handle;
606 	int behavior = PHP_MODE_STANDARD;
607 	char *reflection_what = NULL;
608 	volatile int request_started = 0;
609 	char *php_optarg = NULL, *orig_optarg = NULL;
610 	int php_optind = 1, orig_optind = 1;
611 	char *exec_direct=NULL, *exec_run=NULL, *exec_begin=NULL, *exec_end=NULL;
612 	char *arg_free=NULL, **arg_excp=&arg_free;
613 	char *script_file=NULL, *translated_path = NULL;
614 	int interactive=0;
615 	const char *param_error=NULL;
616 	int hide_argv = 0;
617 	int num_repeats = 1;
618 	pid_t pid = getpid();
619 
620 	file_handle.filename = NULL;
621 
622 	zend_try {
623 
624 		CG(in_compilation) = 0; /* not initialized but needed for several options */
625 
626 		while ((c = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 0, 2)) != -1) {
627 			switch (c) {
628 
629 			case 'i': /* php info & quit */
630 				if (php_request_startup()==FAILURE) {
631 					goto err;
632 				}
633 				request_started = 1;
634 				php_print_info(PHP_INFO_ALL & ~PHP_INFO_CREDITS);
635 				php_output_end_all();
636 				EG(exit_status) = (c == '?' && argc > 1 && !strchr(argv[1],  c));
637 				goto out;
638 
639 			case 'v': /* show php version & quit */
640 				php_printf("PHP %s (%s) (built: %s %s) (%s)\nCopyright (c) The PHP Group\n%s",
641 					PHP_VERSION, cli_sapi_module.name, __DATE__, __TIME__,
642 #ifdef ZTS
643 					"ZTS"
644 #else
645 					"NTS"
646 #endif
647 #ifdef PHP_BUILD_COMPILER
648 					" " PHP_BUILD_COMPILER
649 #endif
650 #ifdef PHP_BUILD_ARCH
651 					" " PHP_BUILD_ARCH
652 #endif
653 #if ZEND_DEBUG
654 					" DEBUG"
655 #endif
656 #ifdef HAVE_GCOV
657 					" GCOV"
658 #endif
659 					,
660 					get_zend_version()
661 				);
662 				sapi_deactivate();
663 				goto out;
664 
665 			case 'm': /* list compiled in modules */
666 				if (php_request_startup()==FAILURE) {
667 					goto err;
668 				}
669 				request_started = 1;
670 				php_printf("[PHP Modules]\n");
671 				print_modules();
672 				php_printf("\n[Zend Modules]\n");
673 				print_extensions();
674 				php_printf("\n");
675 				php_output_end_all();
676 				EG(exit_status) = 0;
677 				goto out;
678 
679 			default:
680 				break;
681 			}
682 		}
683 
684 		/* Set some CLI defaults */
685 		SG(options) |= SAPI_OPTION_NO_CHDIR;
686 
687 		php_optind = orig_optind;
688 		php_optarg = orig_optarg;
689 		while ((c = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 0, 2)) != -1) {
690 			switch (c) {
691 
692 			case 'a':	/* interactive mode */
693 				if (!cli_shell_callbacks.cli_shell_run) {
694 					param_error = "Interactive shell (-a) requires the readline extension.\n";
695 					break;
696 				}
697 				if (!interactive) {
698 					if (behavior != PHP_MODE_STANDARD) {
699 						param_error = param_mode_conflict;
700 						break;
701 					}
702 
703 					interactive=1;
704 				}
705 				break;
706 
707 			case 'C': /* don't chdir to the script directory */
708 				/* This is default so NOP */
709 				break;
710 
711 			case 'F':
712 				if (behavior == PHP_MODE_PROCESS_STDIN) {
713 					if (exec_run || script_file) {
714 						param_error = "You can use -R or -F only once.\n";
715 						break;
716 					}
717 				} else if (behavior != PHP_MODE_STANDARD) {
718 					param_error = param_mode_conflict;
719 					break;
720 				}
721 				behavior=PHP_MODE_PROCESS_STDIN;
722 				script_file = php_optarg;
723 				break;
724 
725 			case 'f': /* parse file */
726 				if (behavior == PHP_MODE_CLI_DIRECT || behavior == PHP_MODE_PROCESS_STDIN) {
727 					param_error = param_mode_conflict;
728 					break;
729 				} else if (script_file) {
730 					param_error = "You can use -f only once.\n";
731 					break;
732 				}
733 				script_file = php_optarg;
734 				break;
735 
736 			case 'l': /* syntax check mode */
737 				if (behavior != PHP_MODE_STANDARD) {
738 					break;
739 				}
740 				behavior=PHP_MODE_LINT;
741 				break;
742 
743 			case 'q': /* do not generate HTTP headers */
744 				/* This is default so NOP */
745 				break;
746 
747 			case 'r': /* run code from command line */
748 				if (behavior == PHP_MODE_CLI_DIRECT) {
749 					if (exec_direct || script_file) {
750 						param_error = "You can use -r only once.\n";
751 						break;
752 					}
753 				} else if (behavior != PHP_MODE_STANDARD || interactive) {
754 					param_error = param_mode_conflict;
755 					break;
756 				}
757 				behavior=PHP_MODE_CLI_DIRECT;
758 				exec_direct=php_optarg;
759 				break;
760 
761 			case 'R':
762 				if (behavior == PHP_MODE_PROCESS_STDIN) {
763 					if (exec_run || script_file) {
764 						param_error = "You can use -R or -F only once.\n";
765 						break;
766 					}
767 				} else if (behavior != PHP_MODE_STANDARD) {
768 					param_error = param_mode_conflict;
769 					break;
770 				}
771 				behavior=PHP_MODE_PROCESS_STDIN;
772 				exec_run=php_optarg;
773 				break;
774 
775 			case 'B':
776 				if (behavior == PHP_MODE_PROCESS_STDIN) {
777 					if (exec_begin) {
778 						param_error = "You can use -B only once.\n";
779 						break;
780 					}
781 				} else if (behavior != PHP_MODE_STANDARD || interactive) {
782 					param_error = param_mode_conflict;
783 					break;
784 				}
785 				behavior=PHP_MODE_PROCESS_STDIN;
786 				exec_begin=php_optarg;
787 				break;
788 
789 			case 'E':
790 				if (behavior == PHP_MODE_PROCESS_STDIN) {
791 					if (exec_end) {
792 						param_error = "You can use -E only once.\n";
793 						break;
794 					}
795 				} else if (behavior != PHP_MODE_STANDARD || interactive) {
796 					param_error = param_mode_conflict;
797 					break;
798 				}
799 				behavior=PHP_MODE_PROCESS_STDIN;
800 				exec_end=php_optarg;
801 				break;
802 
803 			case 's': /* generate highlighted HTML from source */
804 				if (behavior == PHP_MODE_CLI_DIRECT || behavior == PHP_MODE_PROCESS_STDIN) {
805 					param_error = "Source highlighting only works for files.\n";
806 					break;
807 				}
808 				behavior=PHP_MODE_HIGHLIGHT;
809 				break;
810 
811 			case 'w':
812 				if (behavior == PHP_MODE_CLI_DIRECT || behavior == PHP_MODE_PROCESS_STDIN) {
813 					param_error = "Source stripping only works for files.\n";
814 					break;
815 				}
816 				behavior=PHP_MODE_STRIP;
817 				break;
818 
819 			case 'z': /* load extension file */
820 				zend_load_extension(php_optarg);
821 				break;
822 			case 'H':
823 				hide_argv = 1;
824 				break;
825 			case 10:
826 				behavior=PHP_MODE_REFLECTION_FUNCTION;
827 				reflection_what = php_optarg;
828 				break;
829 			case 11:
830 				behavior=PHP_MODE_REFLECTION_CLASS;
831 				reflection_what = php_optarg;
832 				break;
833 			case 12:
834 				behavior=PHP_MODE_REFLECTION_EXTENSION;
835 				reflection_what = php_optarg;
836 				break;
837 			case 13:
838 				behavior=PHP_MODE_REFLECTION_ZEND_EXTENSION;
839 				reflection_what = php_optarg;
840 				break;
841 			case 14:
842 				behavior=PHP_MODE_REFLECTION_EXT_INFO;
843 				reflection_what = php_optarg;
844 				break;
845 			case 15:
846 				behavior = PHP_MODE_SHOW_INI_CONFIG;
847 				break;
848 			case 16:
849 				num_repeats = atoi(php_optarg);
850 				break;
851 			default:
852 				break;
853 			}
854 		}
855 
856 		if (param_error) {
857 			PUTS(param_error);
858 			EG(exit_status) = 1;
859 			goto err;
860 		}
861 
862 #if defined(PHP_WIN32) && !defined(PHP_CLI_WIN32_NO_CONSOLE) && (HAVE_LIBREADLINE || HAVE_LIBEDIT) && !defined(COMPILE_DL_READLINE)
863 		if (!interactive) {
864 		/* The -a option was not passed. If there is no file, it could
865 		 	still make sense to run interactively. The presence of a file
866 			is essential to mitigate buggy console info. */
867 			interactive = php_win32_console_is_own() &&
868 				!(script_file ||
869 					argc > php_optind && behavior!=PHP_MODE_CLI_DIRECT &&
870 					behavior!=PHP_MODE_PROCESS_STDIN &&
871 					strcmp(argv[php_optind-1],"--")
872 				);
873 		}
874 #endif
875 
876 		if (interactive) {
877 			printf("Interactive shell\n\n");
878 			fflush(stdout);
879 		}
880 
881 		if (num_repeats > 1) {
882 			fprintf(stdout, "Executing for the first time...\n");
883 			fflush(stdout);
884 		}
885 
886 do_repeat:
887 		/* only set script_file if not set already and not in direct mode and not at end of parameter list */
888 		if (argc > php_optind
889 		  && !script_file
890 		  && behavior!=PHP_MODE_CLI_DIRECT
891 		  && behavior!=PHP_MODE_PROCESS_STDIN
892 		  && strcmp(argv[php_optind-1],"--"))
893 		{
894 			script_file=argv[php_optind];
895 			php_optind++;
896 		}
897 		if (script_file) {
898 			virtual_cwd_activate();
899 			if (cli_seek_file_begin(&file_handle, script_file) != SUCCESS) {
900 				goto err;
901 			} else {
902 				char real_path[MAXPATHLEN];
903 				if (VCWD_REALPATH(script_file, real_path)) {
904 					translated_path = strdup(real_path);
905 				}
906 				script_filename = script_file;
907 				php_self = script_file;
908 			}
909 		} else {
910 			/* We could handle PHP_MODE_PROCESS_STDIN in a different manner  */
911 			/* here but this would make things only more complicated. And it */
912 			/* is consistent with the way -R works where the stdin file handle*/
913 			/* is also accessible. */
914 			php_self = "Standard input code";
915 			if (behavior < PHP_MODE_CLI_DIRECT
916 			 && (!interactive || PHP_MODE_STANDARD != PHP_MODE_STANDARD)) {
917 				zend_stream_init_fp(&file_handle, stdin, php_self);
918 				file_handle.primary_script = 1;
919 			}
920 		}
921 
922 		/* before registering argv to module exchange the *new* argv[0] */
923 		/* we can achieve this without allocating more memory */
924 		SG(request_info).argc=argc-php_optind+1;
925 		arg_excp = argv+php_optind-1;
926 		arg_free = argv[php_optind-1];
927 		SG(request_info).path_translated = translated_path ? translated_path : php_self;
928 		argv[php_optind-1] = php_self;
929 		SG(request_info).argv=argv+php_optind-1;
930 
931 		if (php_request_startup()==FAILURE) {
932 			*arg_excp = arg_free;
933 			PUTS("Could not startup.\n");
934 			goto err;
935 		}
936 		request_started = 1;
937 		CG(skip_shebang) = 1;
938 
939 		zend_register_bool_constant(
940 			ZEND_STRL("PHP_CLI_PROCESS_TITLE"),
941 			is_ps_title_available() == PS_TITLE_SUCCESS,
942 			CONST_CS, 0);
943 
944 		*arg_excp = arg_free; /* reconstruct argv */
945 
946 		if (hide_argv) {
947 			int i;
948 			for (i = 1; i < argc; i++) {
949 				memset(argv[i], 0, strlen(argv[i]));
950 			}
951 		}
952 
953 		zend_is_auto_global(ZSTR_KNOWN(ZEND_STR_AUTOGLOBAL_SERVER));
954 
955 		PG(during_request_startup) = 0;
956 		switch (behavior) {
957 		case PHP_MODE_STANDARD:
958 			if (script_file) {
959 				cli_register_file_handles(/* no_close */ PHP_DEBUG || num_repeats > 1);
960 			}
961 
962 			if (interactive) {
963 				EG(exit_status) = cli_shell_callbacks.cli_shell_run();
964 			} else {
965 				php_execute_script(&file_handle);
966 			}
967 			break;
968 		case PHP_MODE_LINT:
969 			EG(exit_status) = php_lint_script(&file_handle);
970 			if (EG(exit_status) == SUCCESS) {
971 				zend_printf("No syntax errors detected in %s\n", php_self);
972 			} else {
973 				zend_printf("Errors parsing %s\n", php_self);
974 			}
975 			break;
976 		case PHP_MODE_STRIP:
977 			if (open_file_for_scanning(&file_handle)==SUCCESS) {
978 				zend_strip();
979 			}
980 			goto out;
981 			break;
982 		case PHP_MODE_HIGHLIGHT:
983 			{
984 				zend_syntax_highlighter_ini syntax_highlighter_ini;
985 
986 				if (open_file_for_scanning(&file_handle)==SUCCESS) {
987 					php_get_highlight_struct(&syntax_highlighter_ini);
988 					zend_highlight(&syntax_highlighter_ini);
989 				}
990 				goto out;
991 			}
992 			break;
993 		case PHP_MODE_CLI_DIRECT:
994 			cli_register_file_handles(/* no_close */ PHP_DEBUG || num_repeats > 1);
995 			zend_eval_string_ex(exec_direct, NULL, "Command line code", 1);
996 			break;
997 
998 		case PHP_MODE_PROCESS_STDIN:
999 			{
1000 				char *input;
1001 				size_t len, index = 0;
1002 				zval argn, argi;
1003 
1004 				if (!exec_run && script_file) {
1005 					zend_string_release_ex(file_handle.filename, 0);
1006 					file_handle.filename = NULL;
1007 				}
1008 
1009 				cli_register_file_handles(/* no_close */ PHP_DEBUG || num_repeats > 1);
1010 
1011 				if (exec_begin) {
1012 					zend_eval_string_ex(exec_begin, NULL, "Command line begin code", 1);
1013 				}
1014 				while (EG(exit_status) == SUCCESS && (input=php_stream_gets(s_in_process, NULL, 0)) != NULL) {
1015 					len = strlen(input);
1016 					while (len > 0 && len-- && (input[len]=='\n' || input[len]=='\r')) {
1017 						input[len] = '\0';
1018 					}
1019 					ZVAL_STRINGL(&argn, input, len + 1);
1020 					zend_hash_str_update(&EG(symbol_table), "argn", sizeof("argn")-1, &argn);
1021 					ZVAL_LONG(&argi, ++index);
1022 					zend_hash_str_update(&EG(symbol_table), "argi", sizeof("argi")-1, &argi);
1023 					if (exec_run) {
1024 						zend_eval_string_ex(exec_run, NULL, "Command line run code", 1);
1025 					} else {
1026 						if (script_file) {
1027 							if (cli_seek_file_begin(&file_handle, script_file) != SUCCESS) {
1028 								EG(exit_status) = 1;
1029 							} else {
1030 								CG(skip_shebang) = 1;
1031 								php_execute_script(&file_handle);
1032 							}
1033 						}
1034 					}
1035 					efree(input);
1036 				}
1037 				if (exec_end) {
1038 					zend_eval_string_ex(exec_end, NULL, "Command line end code", 1);
1039 				}
1040 
1041 				break;
1042 			}
1043 
1044 			case PHP_MODE_REFLECTION_FUNCTION:
1045 			case PHP_MODE_REFLECTION_CLASS:
1046 			case PHP_MODE_REFLECTION_EXTENSION:
1047 			case PHP_MODE_REFLECTION_ZEND_EXTENSION:
1048 				{
1049 					zend_class_entry *pce = NULL;
1050 					zval arg, ref;
1051 					zend_execute_data execute_data;
1052 
1053 					switch (behavior) {
1054 						default:
1055 							break;
1056 						case PHP_MODE_REFLECTION_FUNCTION:
1057 							if (strstr(reflection_what, "::")) {
1058 								pce = reflection_method_ptr;
1059 							} else {
1060 								pce = reflection_function_ptr;
1061 							}
1062 							break;
1063 						case PHP_MODE_REFLECTION_CLASS:
1064 							pce = reflection_class_ptr;
1065 							break;
1066 						case PHP_MODE_REFLECTION_EXTENSION:
1067 							pce = reflection_extension_ptr;
1068 							break;
1069 						case PHP_MODE_REFLECTION_ZEND_EXTENSION:
1070 							pce = reflection_zend_extension_ptr;
1071 							break;
1072 					}
1073 
1074 					ZVAL_STRING(&arg, reflection_what);
1075 					object_init_ex(&ref, pce);
1076 
1077 					memset(&execute_data, 0, sizeof(zend_execute_data));
1078 					EG(current_execute_data) = &execute_data;
1079 					zend_call_known_instance_method_with_1_params(
1080 						pce->constructor, Z_OBJ(ref), NULL, &arg);
1081 
1082 					if (EG(exception)) {
1083 						zval rv;
1084 						zval *msg = zend_read_property(zend_ce_exception, EG(exception), "message", sizeof("message")-1, 0, &rv);
1085 						zend_printf("Exception: %s\n", Z_STRVAL_P(msg));
1086 						zend_object_release(EG(exception));
1087 						EG(exception) = NULL;
1088 						EG(exit_status) = 1;
1089 					} else {
1090 						zend_print_zval(&ref, 0);
1091 						zend_write("\n", 1);
1092 					}
1093 					zval_ptr_dtor(&ref);
1094 					zval_ptr_dtor(&arg);
1095 
1096 					break;
1097 				}
1098 			case PHP_MODE_REFLECTION_EXT_INFO:
1099 				{
1100 					size_t len = strlen(reflection_what);
1101 					char *lcname = zend_str_tolower_dup(reflection_what, len);
1102 					zend_module_entry *module;
1103 
1104 					if ((module = zend_hash_str_find_ptr(&module_registry, lcname, len)) == NULL) {
1105 						if (!strcmp(reflection_what, "main")) {
1106 							display_ini_entries(NULL);
1107 						} else {
1108 							zend_printf("Extension '%s' not present.\n", reflection_what);
1109 							EG(exit_status) = 1;
1110 						}
1111 					} else {
1112 						php_info_print_module(module);
1113 					}
1114 
1115 					efree(lcname);
1116 					break;
1117 				}
1118 
1119 			case PHP_MODE_SHOW_INI_CONFIG:
1120 				{
1121 					zend_printf("Configuration File (php.ini) Path: %s\n", PHP_CONFIG_FILE_PATH);
1122 					zend_printf("Loaded Configuration File:         %s\n", php_ini_opened_path ? php_ini_opened_path : "(none)");
1123 					zend_printf("Scan for additional .ini files in: %s\n", php_ini_scanned_path  ? php_ini_scanned_path : "(none)");
1124 					zend_printf("Additional .ini files parsed:      %s\n", php_ini_scanned_files ? php_ini_scanned_files : "(none)");
1125 					break;
1126 				}
1127 		}
1128 	} zend_end_try();
1129 
1130 out:
1131 	if (file_handle.filename) {
1132 		zend_destroy_file_handle(&file_handle);
1133 	}
1134 	if (request_started) {
1135 		php_request_shutdown((void *) 0);
1136 	}
1137 	if (translated_path) {
1138 		free(translated_path);
1139 	}
1140 	/* Don't repeat fork()ed processes. */
1141 	if (--num_repeats && pid == getpid()) {
1142 		fprintf(stdout, "Finished execution, repeating...\n");
1143 		fflush(stdout);
1144 		goto do_repeat;
1145 	}
1146 	return EG(exit_status);
1147 err:
1148 	sapi_deactivate();
1149 	zend_ini_deactivate();
1150 	EG(exit_status) = 1;
1151 	goto out;
1152 }
1153 /* }}} */
1154 
1155 /* {{{ main */
1156 #ifdef PHP_CLI_WIN32_NO_CONSOLE
WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd)1157 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
1158 #else
1159 int main(int argc, char *argv[])
1160 #endif
1161 {
1162 #if defined(PHP_WIN32)
1163 # ifdef PHP_CLI_WIN32_NO_CONSOLE
1164 	int argc = __argc;
1165 	char **argv = __argv;
1166 # endif
1167 	int num_args;
1168 	wchar_t **argv_wide;
1169 	char **argv_save = argv;
1170 	BOOL using_wide_argv = 0;
1171 #endif
1172 
1173 	int c;
1174 	int exit_status = SUCCESS;
1175 	int module_started = 0, sapi_started = 0;
1176 	char *php_optarg = NULL;
1177 	int php_optind = 1, use_extended_info = 0;
1178 	char *ini_path_override = NULL;
1179 	char *ini_entries = NULL;
1180 	size_t ini_entries_len = 0;
1181 	int ini_ignore = 0;
1182 	sapi_module_struct *sapi_module = &cli_sapi_module;
1183 
1184 	/*
1185 	 * Do not move this initialization. It needs to happen before argv is used
1186 	 * in any way.
1187 	 */
1188 	argv = save_ps_args(argc, argv);
1189 
1190 #if defined(PHP_WIN32) && !defined(PHP_CLI_WIN32_NO_CONSOLE)
1191 	php_win32_console_fileno_set_vt100(STDOUT_FILENO, TRUE);
1192 	php_win32_console_fileno_set_vt100(STDERR_FILENO, TRUE);
1193 #endif
1194 
1195 	cli_sapi_module.additional_functions = additional_functions;
1196 
1197 #if defined(PHP_WIN32) && defined(_DEBUG)
1198 	{
1199 		char *tmp = getenv("PHP_WIN32_DEBUG_HEAP");
1200 		if (tmp && ZEND_ATOL(tmp)) {
1201 			int tmp_flag;
1202 			_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
1203 			_CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
1204 			_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
1205 			_CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
1206 			_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
1207 			_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
1208 			tmp_flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
1209 			tmp_flag |= _CRTDBG_DELAY_FREE_MEM_DF;
1210 			tmp_flag |= _CRTDBG_LEAK_CHECK_DF;
1211 
1212 			_CrtSetDbgFlag(tmp_flag);
1213 		}
1214 	}
1215 #endif
1216 
1217 #if defined(SIGPIPE) && defined(SIG_IGN)
1218 	signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE in standalone mode so
1219 								that sockets created via fsockopen()
1220 								don't kill PHP if the remote site
1221 								closes it.  in apache|apxs mode apache
1222 								does that for us!  thies@thieso.net
1223 								20000419 */
1224 #endif
1225 
1226 #ifdef ZTS
1227 	php_tsrm_startup();
1228 # ifdef PHP_WIN32
1229 	ZEND_TSRMLS_CACHE_UPDATE();
1230 # endif
1231 #endif
1232 
1233 	zend_signal_startup();
1234 
1235 #ifdef PHP_WIN32
1236 	_fmode = _O_BINARY;			/*sets default for file streams to binary */
1237 	setmode(_fileno(stdin), O_BINARY);		/* make the stdio mode be binary */
1238 	setmode(_fileno(stdout), O_BINARY);		/* make the stdio mode be binary */
1239 	setmode(_fileno(stderr), O_BINARY);		/* make the stdio mode be binary */
1240 #endif
1241 
1242 	while ((c = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 1, 2))!=-1) {
1243 		switch (c) {
1244 			case 'c':
1245 				if (ini_path_override) {
1246 					free(ini_path_override);
1247 				}
1248 				ini_path_override = strdup(php_optarg);
1249 				break;
1250 			case 'n':
1251 				ini_ignore = 1;
1252 				break;
1253 			case 'd': {
1254 				/* define ini entries on command line */
1255 				size_t len = strlen(php_optarg);
1256 				char *val;
1257 
1258 				if ((val = strchr(php_optarg, '='))) {
1259 					val++;
1260 					if (!isalnum(*val) && *val != '"' && *val != '\'' && *val != '\0') {
1261 						ini_entries = realloc(ini_entries, ini_entries_len + len + sizeof("\"\"\n\0"));
1262 						memcpy(ini_entries + ini_entries_len, php_optarg, (val - php_optarg));
1263 						ini_entries_len += (val - php_optarg);
1264 						memcpy(ini_entries + ini_entries_len, "\"", 1);
1265 						ini_entries_len++;
1266 						memcpy(ini_entries + ini_entries_len, val, len - (val - php_optarg));
1267 						ini_entries_len += len - (val - php_optarg);
1268 						memcpy(ini_entries + ini_entries_len, "\"\n\0", sizeof("\"\n\0"));
1269 						ini_entries_len += sizeof("\n\0\"") - 2;
1270 					} else {
1271 						ini_entries = realloc(ini_entries, ini_entries_len + len + sizeof("\n\0"));
1272 						memcpy(ini_entries + ini_entries_len, php_optarg, len);
1273 						memcpy(ini_entries + ini_entries_len + len, "\n\0", sizeof("\n\0"));
1274 						ini_entries_len += len + sizeof("\n\0") - 2;
1275 					}
1276 				} else {
1277 					ini_entries = realloc(ini_entries, ini_entries_len + len + sizeof("=1\n\0"));
1278 					memcpy(ini_entries + ini_entries_len, php_optarg, len);
1279 					memcpy(ini_entries + ini_entries_len + len, "=1\n\0", sizeof("=1\n\0"));
1280 					ini_entries_len += len + sizeof("=1\n\0") - 2;
1281 				}
1282 				break;
1283 			}
1284 #ifndef PHP_CLI_WIN32_NO_CONSOLE
1285 			case 'S':
1286 				sapi_module = &cli_server_sapi_module;
1287 				cli_server_sapi_module.additional_functions = server_additional_functions;
1288 				break;
1289 #endif
1290 			case 'h': /* help & quit */
1291 			case '?':
1292 				php_cli_usage(argv[0]);
1293 				goto out;
1294 			case PHP_GETOPT_INVALID_ARG: /* print usage on bad options, exit 1 */
1295 				php_cli_usage(argv[0]);
1296 				exit_status = 1;
1297 				goto out;
1298 			case 'i': case 'v': case 'm':
1299 				sapi_module = &cli_sapi_module;
1300 				goto exit_loop;
1301 			case 'e': /* enable extended info output */
1302 				use_extended_info = 1;
1303 				break;
1304 		}
1305 	}
1306 exit_loop:
1307 
1308 	sapi_module->ini_defaults = sapi_cli_ini_defaults;
1309 	sapi_module->php_ini_path_override = ini_path_override;
1310 	sapi_module->phpinfo_as_text = 1;
1311 	sapi_module->php_ini_ignore_cwd = 1;
1312 	sapi_startup(sapi_module);
1313 	sapi_started = 1;
1314 
1315 	sapi_module->php_ini_ignore = ini_ignore;
1316 
1317 	sapi_module->executable_location = argv[0];
1318 
1319 	if (sapi_module == &cli_sapi_module) {
1320 		if (ini_entries) {
1321 			ini_entries = realloc(ini_entries, ini_entries_len + sizeof(HARDCODED_INI));
1322 			memmove(ini_entries + sizeof(HARDCODED_INI) - 2, ini_entries, ini_entries_len + 1);
1323 			memcpy(ini_entries, HARDCODED_INI, sizeof(HARDCODED_INI) - 2);
1324 		} else {
1325 			ini_entries = malloc(sizeof(HARDCODED_INI));
1326 			memcpy(ini_entries, HARDCODED_INI, sizeof(HARDCODED_INI));
1327 		}
1328 		ini_entries_len += sizeof(HARDCODED_INI) - 2;
1329 	}
1330 
1331 	sapi_module->ini_entries = ini_entries;
1332 
1333 	/* startup after we get the above ini override se we get things right */
1334 	if (sapi_module->startup(sapi_module) == FAILURE) {
1335 		/* there is no way to see if we must call zend_ini_deactivate()
1336 		 * since we cannot check if EG(ini_directives) has been initialized
1337 		 * because the executor's constructor does not set initialize it.
1338 		 * Apart from that there seems no need for zend_ini_deactivate() yet.
1339 		 * So we goto out_err.*/
1340 		exit_status = 1;
1341 		goto out;
1342 	}
1343 	module_started = 1;
1344 
1345 #if defined(PHP_WIN32)
1346 	php_win32_cp_cli_setup();
1347 	orig_cp = (php_win32_cp_get_orig())->id;
1348 	/* Ignore the delivered argv and argc, read from W API. This place
1349 		might be too late though, but this is the earliest place ATW
1350 		we can access the internal charset information from PHP. */
1351 	argv_wide = CommandLineToArgvW(GetCommandLineW(), &num_args);
1352 	PHP_WIN32_CP_W_TO_ANY_ARRAY(argv_wide, num_args, argv, argc)
1353 	using_wide_argv = 1;
1354 
1355 	SetConsoleCtrlHandler(php_cli_win32_ctrl_handler, TRUE);
1356 #endif
1357 
1358 	/* -e option */
1359 	if (use_extended_info) {
1360 		CG(compiler_options) |= ZEND_COMPILE_EXTENDED_INFO;
1361 	}
1362 
1363 	zend_first_try {
1364 #ifndef PHP_CLI_WIN32_NO_CONSOLE
1365 		if (sapi_module == &cli_sapi_module) {
1366 #endif
1367 			exit_status = do_cli(argc, argv);
1368 #ifndef PHP_CLI_WIN32_NO_CONSOLE
1369 		} else {
1370 			exit_status = do_cli_server(argc, argv);
1371 		}
1372 #endif
1373 	} zend_end_try();
1374 out:
1375 	if (ini_path_override) {
1376 		free(ini_path_override);
1377 	}
1378 	if (ini_entries) {
1379 		free(ini_entries);
1380 	}
1381 	if (module_started) {
1382 		php_module_shutdown();
1383 	}
1384 	if (sapi_started) {
1385 		sapi_shutdown();
1386 	}
1387 #ifdef ZTS
1388 	tsrm_shutdown();
1389 #endif
1390 
1391 #if defined(PHP_WIN32)
1392 	(void)php_win32_cp_cli_restore();
1393 
1394 	if (using_wide_argv) {
1395 		PHP_WIN32_CP_FREE_ARRAY(argv, argc);
1396 		LocalFree(argv_wide);
1397 	}
1398 	argv = argv_save;
1399 #endif
1400 	/*
1401 	 * Do not move this de-initialization. It needs to happen right before
1402 	 * exiting.
1403 	 */
1404 	cleanup_ps_args(argv);
1405 	exit(exit_status);
1406 }
1407 /* }}} */
1408