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