xref: /PHP-7.4/ext/phar/phar_object.c (revision 2ff853aa)
13066cfb3SMarcus Boerger /*
23066cfb3SMarcus Boerger   +----------------------------------------------------------------------+
33066cfb3SMarcus Boerger   | phar php single-file executable PHP extension                        |
43066cfb3SMarcus Boerger   +----------------------------------------------------------------------+
5a6519d05SXinchen Hui   | Copyright (c) The PHP Group                                          |
63066cfb3SMarcus Boerger   +----------------------------------------------------------------------+
73066cfb3SMarcus Boerger   | This source file is subject to version 3.01 of the PHP license,      |
83066cfb3SMarcus Boerger   | that is bundled with this package in the file LICENSE, and is        |
93066cfb3SMarcus Boerger   | available through the world-wide-web at the following url:           |
103066cfb3SMarcus Boerger   | http://www.php.net/license/3_01.txt.                                 |
113066cfb3SMarcus Boerger   | If you did not receive a copy of the PHP license and are unable to   |
123066cfb3SMarcus Boerger   | obtain it through the world-wide-web, please send a note to          |
133066cfb3SMarcus Boerger   | license@php.net so we can mail you a copy immediately.               |
143066cfb3SMarcus Boerger   +----------------------------------------------------------------------+
153066cfb3SMarcus Boerger   | Authors: Gregory Beaver <cellog@php.net>                             |
163066cfb3SMarcus Boerger   |          Marcus Boerger <helly@php.net>                              |
173066cfb3SMarcus Boerger   +----------------------------------------------------------------------+
183066cfb3SMarcus Boerger */
193066cfb3SMarcus Boerger 
203066cfb3SMarcus Boerger #include "phar_internal.h"
218fb4205aSGreg Beaver #include "func_interceptors.h"
223066cfb3SMarcus Boerger 
233066cfb3SMarcus Boerger static zend_class_entry *phar_ce_archive;
24001ffec1SSteph Fox static zend_class_entry *phar_ce_data;
25c7a5d062SGreg Beaver static zend_class_entry *phar_ce_PharException;
263066cfb3SMarcus Boerger static zend_class_entry *phar_ce_entry;
273066cfb3SMarcus Boerger 
phar_file_type(HashTable * mimes,char * file,char ** mime_type)28bdeb220fSAnatol Belski static int phar_file_type(HashTable *mimes, char *file, char **mime_type) /* {{{ */
2902c7ff13SGreg Beaver {
3002c7ff13SGreg Beaver 	char *ext;
3102c7ff13SGreg Beaver 	phar_mime_type *mime;
3202c7ff13SGreg Beaver 	ext = strrchr(file, '.');
3302c7ff13SGreg Beaver 	if (!ext) {
3402c7ff13SGreg Beaver 		*mime_type = "text/plain";
3502c7ff13SGreg Beaver 		/* no file extension = assume text/plain */
3602c7ff13SGreg Beaver 		return PHAR_MIME_OTHER;
3702c7ff13SGreg Beaver 	}
386cef8da2SGreg Beaver 	++ext;
39df5ad846SDmitry Stogov 	if (NULL == (mime = zend_hash_str_find_ptr(mimes, ext, strlen(ext)))) {
4002c7ff13SGreg Beaver 		*mime_type = "application/octet-stream";
4102c7ff13SGreg Beaver 		return PHAR_MIME_OTHER;
4202c7ff13SGreg Beaver 	}
4302c7ff13SGreg Beaver 	*mime_type = mime->mime;
4402c7ff13SGreg Beaver 	return mime->type;
4502c7ff13SGreg Beaver }
4602c7ff13SGreg Beaver /* }}} */
4702c7ff13SGreg Beaver 
phar_mung_server_vars(char * fname,char * entry,size_t entry_len,char * basename,size_t request_uri_len)482e5ac355SAnatol Belski static void phar_mung_server_vars(char *fname, char *entry, size_t entry_len, char *basename, size_t request_uri_len) /* {{{ */
49e8a5b205SGreg Beaver {
50c6aa379dSSteph Fox 	HashTable *_SERVER;
51df5ad846SDmitry Stogov 	zval *stuff;
52e8a5b205SGreg Beaver 	char *path_info;
53b1ff0c52SStanislav Malyshev 	size_t basename_len = strlen(basename);
54b1ff0c52SStanislav Malyshev 	size_t code;
55df5ad846SDmitry Stogov 	zval temp;
56e8a5b205SGreg Beaver 
57e8a5b205SGreg Beaver 	/* "tweak" $_SERVER variables requested in earlier call to Phar::mungServer() */
58df5ad846SDmitry Stogov 	if (Z_TYPE(PG(http_globals)[TRACK_VARS_SERVER]) == IS_UNDEF) {
59e8a5b205SGreg Beaver 		return;
60e8a5b205SGreg Beaver 	}
61e8a5b205SGreg Beaver 
62df5ad846SDmitry Stogov 	_SERVER = Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]);
63c6aa379dSSteph Fox 
64a38e4ff9SGreg Beaver 	/* PATH_INFO and PATH_TRANSLATED should always be munged */
65df5ad846SDmitry Stogov 	if (NULL != (stuff = zend_hash_str_find(_SERVER, "PATH_INFO", sizeof("PATH_INFO")-1))) {
66df5ad846SDmitry Stogov 		path_info = Z_STRVAL_P(stuff);
67c3e3c98eSAnatol Belski 		code = Z_STRLEN_P(stuff);
68cf1d42e0SKalle Sommer Nielsen 		if (code > (size_t)entry_len && !memcmp(path_info, entry, entry_len)) {
69df5ad846SDmitry Stogov 			ZVAL_STR(&temp, Z_STR_P(stuff));
70df5ad846SDmitry Stogov 			ZVAL_STRINGL(stuff, path_info + entry_len, request_uri_len);
71df5ad846SDmitry Stogov 			zend_hash_str_update(_SERVER, "PHAR_PATH_INFO", sizeof("PHAR_PATH_INFO")-1, &temp);
7215f8facdSGreg Beaver 		}
73a38e4ff9SGreg Beaver 	}
74e67c5843SGreg Beaver 
75df5ad846SDmitry Stogov 	if (NULL != (stuff = zend_hash_str_find(_SERVER, "PATH_TRANSLATED", sizeof("PATH_TRANSLATED")-1))) {
7601c8aee7SDmitry Stogov 		zend_string *str = strpprintf(4096, "phar://%s%s", fname, entry);
7785fa4d77SFelipe Pena 
78df5ad846SDmitry Stogov 		ZVAL_STR(&temp, Z_STR_P(stuff));
793bc8a958SDmitry Stogov 		ZVAL_NEW_STR(stuff, str);
80df5ad846SDmitry Stogov 
8101c8aee7SDmitry Stogov 		zend_hash_str_update(_SERVER, "PHAR_PATH_TRANSLATED", sizeof("PHAR_PATH_TRANSLATED")-1, &temp);
82a38e4ff9SGreg Beaver 	}
83c6aa379dSSteph Fox 
8447f2e42fSXinchen Hui 	if (!PHAR_G(phar_SERVER_mung_list)) {
85a38e4ff9SGreg Beaver 		return;
86a38e4ff9SGreg Beaver 	}
87c6aa379dSSteph Fox 
8847f2e42fSXinchen Hui 	if (PHAR_G(phar_SERVER_mung_list) & PHAR_MUNG_REQUEST_URI) {
89df5ad846SDmitry Stogov 		if (NULL != (stuff = zend_hash_str_find(_SERVER, "REQUEST_URI", sizeof("REQUEST_URI")-1))) {
90df5ad846SDmitry Stogov 			path_info = Z_STRVAL_P(stuff);
91c3e3c98eSAnatol Belski 			code = Z_STRLEN_P(stuff);
92df5ad846SDmitry Stogov 			if (code > basename_len && !memcmp(path_info, basename, basename_len)) {
93df5ad846SDmitry Stogov 				ZVAL_STR(&temp, Z_STR_P(stuff));
94df5ad846SDmitry Stogov 				ZVAL_STRINGL(stuff, path_info + basename_len, code - basename_len);
95df5ad846SDmitry Stogov 				zend_hash_str_update(_SERVER, "PHAR_REQUEST_URI", sizeof("PHAR_REQUEST_URI")-1, &temp);
9615f8facdSGreg Beaver 			}
97e67c5843SGreg Beaver 		}
98e67c5843SGreg Beaver 	}
99c6aa379dSSteph Fox 
10047f2e42fSXinchen Hui 	if (PHAR_G(phar_SERVER_mung_list) & PHAR_MUNG_PHP_SELF) {
101df5ad846SDmitry Stogov 		if (NULL != (stuff = zend_hash_str_find(_SERVER, "PHP_SELF", sizeof("PHP_SELF")-1))) {
102df5ad846SDmitry Stogov 			path_info = Z_STRVAL_P(stuff);
103c3e3c98eSAnatol Belski 			code = Z_STRLEN_P(stuff);
104df5ad846SDmitry Stogov 
105df5ad846SDmitry Stogov 			if (code > basename_len && !memcmp(path_info, basename, basename_len)) {
106df5ad846SDmitry Stogov 				ZVAL_STR(&temp, Z_STR_P(stuff));
107df5ad846SDmitry Stogov 				ZVAL_STRINGL(stuff, path_info + basename_len, code - basename_len);
108df5ad846SDmitry Stogov 				zend_hash_str_update(_SERVER, "PHAR_PHP_SELF", sizeof("PHAR_PHP_SELF")-1, &temp);
10915f8facdSGreg Beaver 			}
110e67c5843SGreg Beaver 		}
111e67c5843SGreg Beaver 	}
112e8a5b205SGreg Beaver 
11347f2e42fSXinchen Hui 	if (PHAR_G(phar_SERVER_mung_list) & PHAR_MUNG_SCRIPT_NAME) {
114df5ad846SDmitry Stogov 		if (NULL != (stuff = zend_hash_str_find(_SERVER, "SCRIPT_NAME", sizeof("SCRIPT_NAME")-1))) {
115df5ad846SDmitry Stogov 			ZVAL_STR(&temp, Z_STR_P(stuff));
116df5ad846SDmitry Stogov 			ZVAL_STRINGL(stuff, entry, entry_len);
117df5ad846SDmitry Stogov 			zend_hash_str_update(_SERVER, "PHAR_SCRIPT_NAME", sizeof("PHAR_SCRIPT_NAME")-1, &temp);
118c6aa379dSSteph Fox 		}
119e8a5b205SGreg Beaver 	}
120e8a5b205SGreg Beaver 
12147f2e42fSXinchen Hui 	if (PHAR_G(phar_SERVER_mung_list) & PHAR_MUNG_SCRIPT_FILENAME) {
122df5ad846SDmitry Stogov 		if (NULL != (stuff = zend_hash_str_find(_SERVER, "SCRIPT_FILENAME", sizeof("SCRIPT_FILENAME")-1))) {
12301c8aee7SDmitry Stogov 			zend_string *str = strpprintf(4096, "phar://%s%s", fname, entry);
124e67c5843SGreg Beaver 
125df5ad846SDmitry Stogov 			ZVAL_STR(&temp, Z_STR_P(stuff));
1263bc8a958SDmitry Stogov 			ZVAL_NEW_STR(stuff, str);
12785fa4d77SFelipe Pena 
128df5ad846SDmitry Stogov 			zend_hash_str_update(_SERVER, "PHAR_SCRIPT_FILENAME", sizeof("PHAR_SCRIPT_FILENAME")-1, &temp);
129e8a5b205SGreg Beaver 		}
130e8a5b205SGreg Beaver 	}
131e8a5b205SGreg Beaver }
1326d9453aaSAntony Dovgal /* }}} */
133e8a5b205SGreg Beaver 
phar_file_action(phar_archive_data * phar,phar_entry_info * info,char * mime_type,int code,char * entry,size_t entry_len,char * arch,char * basename,char * ru,size_t ru_len)1342e5ac355SAnatol Belski static int phar_file_action(phar_archive_data *phar, phar_entry_info *info, char *mime_type, int code, char *entry, size_t entry_len, char *arch, char *basename, char *ru, size_t ru_len) /* {{{ */
13502c7ff13SGreg Beaver {
1361fed0e5aSKalle Sommer Nielsen 	char *name = NULL, buf[8192];
1371fed0e5aSKalle Sommer Nielsen 	const char *cwd;
13802c7ff13SGreg Beaver 	zend_syntax_highlighter_ini syntax_highlighter_ini;
13902c7ff13SGreg Beaver 	sapi_header_line ctr = {0};
14002c7ff13SGreg Beaver 	size_t got;
141df5ad846SDmitry Stogov 	zval dummy;
142b1ff0c52SStanislav Malyshev 	size_t name_len;
14302c7ff13SGreg Beaver 	zend_file_handle file_handle;
14402c7ff13SGreg Beaver 	zend_op_array *new_op_array;
145df5ad846SDmitry Stogov 	zval result;
146c6aa379dSSteph Fox 	php_stream *fp;
1474d997f63SAnatol Belski 	zend_off_t position;
14802c7ff13SGreg Beaver 
14902c7ff13SGreg Beaver 	switch (code) {
15002c7ff13SGreg Beaver 		case PHAR_MIME_PHPS:
151e8a5b205SGreg Beaver 			efree(basename);
15202c7ff13SGreg Beaver 			/* highlight source */
1533dcee1c8SGreg Beaver 			if (entry[0] == '/') {
154b1ff0c52SStanislav Malyshev 				spprintf(&name, 4096, "phar://%s%s", arch, entry);
1553dcee1c8SGreg Beaver 			} else {
156b1ff0c52SStanislav Malyshev 				spprintf(&name, 4096, "phar://%s/%s", arch, entry);
1573dcee1c8SGreg Beaver 			}
15802c7ff13SGreg Beaver 			php_get_highlight_struct(&syntax_highlighter_ini);
15902c7ff13SGreg Beaver 
160bdeb220fSAnatol Belski 			highlight_file(name, &syntax_highlighter_ini);
16102c7ff13SGreg Beaver 
16202c7ff13SGreg Beaver 			efree(name);
163e1a41da6SGreg Beaver #ifdef PHP_WIN32
164e1a41da6SGreg Beaver 			efree(arch);
165e1a41da6SGreg Beaver #endif
16602c7ff13SGreg Beaver 			zend_bailout();
16702c7ff13SGreg Beaver 		case PHAR_MIME_OTHER:
16802c7ff13SGreg Beaver 			/* send headers, output file contents */
169e8a5b205SGreg Beaver 			efree(basename);
17002c7ff13SGreg Beaver 			ctr.line_len = spprintf(&(ctr.line), 0, "Content-type: %s", mime_type);
171bdeb220fSAnatol Belski 			sapi_header_op(SAPI_HEADER_REPLACE, &ctr);
17202c7ff13SGreg Beaver 			efree(ctr.line);
173cd011d1eSSteph Fox 			ctr.line_len = spprintf(&(ctr.line), 0, "Content-length: %u", info->uncompressed_filesize);
174bdeb220fSAnatol Belski 			sapi_header_op(SAPI_HEADER_REPLACE, &ctr);
17502c7ff13SGreg Beaver 			efree(ctr.line);
176c6aa379dSSteph Fox 
177bdeb220fSAnatol Belski 			if (FAILURE == sapi_send_headers()) {
17802c7ff13SGreg Beaver 				zend_bailout();
17902c7ff13SGreg Beaver 			}
18002c7ff13SGreg Beaver 
18102c7ff13SGreg Beaver 			/* prepare to output  */
182bdeb220fSAnatol Belski 			fp = phar_get_efp(info, 1);
183c6aa379dSSteph Fox 
184c6aa379dSSteph Fox 			if (!fp) {
185652d39c3SGreg Beaver 				char *error;
186bdeb220fSAnatol Belski 				if (!phar_open_jit(phar, info, &error)) {
187652d39c3SGreg Beaver 					if (error) {
188bdeb220fSAnatol Belski 						zend_throw_exception_ex(phar_ce_PharException, 0, "%s", error);
189652d39c3SGreg Beaver 						efree(error);
190652d39c3SGreg Beaver 					}
191652d39c3SGreg Beaver 					return -1;
192652d39c3SGreg Beaver 				}
193bdeb220fSAnatol Belski 				fp = phar_get_efp(info, 1);
19402c7ff13SGreg Beaver 			}
195c6aa379dSSteph Fox 			position = 0;
196bdeb220fSAnatol Belski 			phar_seek_efp(info, 0, SEEK_SET, 0, 1);
197c6aa379dSSteph Fox 
19802c7ff13SGreg Beaver 			do {
199c6aa379dSSteph Fox 				got = php_stream_read(fp, buf, MIN(8192, info->uncompressed_filesize - position));
200c6aa379dSSteph Fox 				if (got > 0) {
201c6aa379dSSteph Fox 					PHPWRITE(buf, got);
202c6aa379dSSteph Fox 					position += got;
2034d997f63SAnatol Belski 					if (position == (zend_off_t) info->uncompressed_filesize) {
204c6aa379dSSteph Fox 						break;
205c6aa379dSSteph Fox 					}
20602c7ff13SGreg Beaver 				}
20702c7ff13SGreg Beaver 			} while (1);
20802c7ff13SGreg Beaver 
2098e18f1caSGreg Beaver 			zend_bailout();
21002c7ff13SGreg Beaver 		case PHAR_MIME_PHP:
211e8a5b205SGreg Beaver 			if (basename) {
212bdeb220fSAnatol Belski 				phar_mung_server_vars(arch, entry, entry_len, basename, ru_len);
213e8a5b205SGreg Beaver 				efree(basename);
214e8a5b205SGreg Beaver 			}
215c6aa379dSSteph Fox 
2163dcee1c8SGreg Beaver 			if (entry[0] == '/') {
2173dcee1c8SGreg Beaver 				name_len = spprintf(&name, 4096, "phar://%s%s", arch, entry);
2183dcee1c8SGreg Beaver 			} else {
2193dcee1c8SGreg Beaver 				name_len = spprintf(&name, 4096, "phar://%s/%s", arch, entry);
2203dcee1c8SGreg Beaver 			}
22102c7ff13SGreg Beaver 
222c6aa379dSSteph Fox 			zend_stream_init_filename(&file_handle, name);
223c6aa379dSSteph Fox 
224c6aa379dSSteph Fox 			PHAR_G(cwd) = NULL;
225c6aa379dSSteph Fox 			PHAR_G(cwd_len) = 0;
226c6aa379dSSteph Fox 
227c6aa379dSSteph Fox 			ZVAL_NULL(&dummy);
228ab4c2cafSGreg Beaver 			if (zend_hash_str_add(&EG(included_files), name, name_len, &dummy) != NULL) {
229ab4c2cafSGreg Beaver 				if ((cwd = zend_memrchr(entry, '/', entry_len))) {
230c6aa379dSSteph Fox 					PHAR_G(cwd_init) = 1;
231df5ad846SDmitry Stogov 					if (entry == cwd) {
232df5ad846SDmitry Stogov 						/* root directory */
233c6aa379dSSteph Fox 						PHAR_G(cwd_len) = 0;
2340c2f3b76SGreg Beaver 						PHAR_G(cwd) = NULL;
23556e84a39SGreg Beaver 					} else if (entry[0] == '/') {
23656e84a39SGreg Beaver 						PHAR_G(cwd_len) = (cwd - (entry + 1));
23756e84a39SGreg Beaver 						PHAR_G(cwd) = estrndup(entry + 1, PHAR_G(cwd_len));
23856e84a39SGreg Beaver 					} else {
23956e84a39SGreg Beaver 						PHAR_G(cwd_len) = (cwd - entry);
2402e5ac355SAnatol Belski 						PHAR_G(cwd) = estrndup(entry, PHAR_G(cwd_len));
241ab4c2cafSGreg Beaver 					}
242ab4c2cafSGreg Beaver 				}
2432e5ac355SAnatol Belski 
244ab4c2cafSGreg Beaver 				new_op_array = zend_compile_file(&file_handle, ZEND_REQUIRE);
245ab4c2cafSGreg Beaver 
246ab4c2cafSGreg Beaver 				if (!new_op_array) {
247c6aa379dSSteph Fox 					zend_hash_str_del(&EG(included_files), name, name_len);
248bdeb220fSAnatol Belski 				}
249c6aa379dSSteph Fox 
250c6aa379dSSteph Fox 				zend_destroy_file_handle(&file_handle);
251df5ad846SDmitry Stogov 
252c6aa379dSSteph Fox 			} else {
253c6aa379dSSteph Fox 				efree(name);
254bdeb220fSAnatol Belski 				new_op_array = NULL;
255c6aa379dSSteph Fox 			}
25602c7ff13SGreg Beaver #ifdef PHP_WIN32
257c6aa379dSSteph Fox 			efree(arch);
25802c7ff13SGreg Beaver #endif
25902c7ff13SGreg Beaver 			if (new_op_array) {
260e1a41da6SGreg Beaver 				ZVAL_UNDEF(&result);
261e1a41da6SGreg Beaver 
262e1a41da6SGreg Beaver 				zend_try {
26302c7ff13SGreg Beaver 					zend_execute(new_op_array, &result);
264df5ad846SDmitry Stogov 					if (PHAR_G(cwd)) {
265ab4c2cafSGreg Beaver 						efree(PHAR_G(cwd));
266ab4c2cafSGreg Beaver 						PHAR_G(cwd) = NULL;
267bdeb220fSAnatol Belski 						PHAR_G(cwd_len) = 0;
26831f3c2adSGreg Beaver 					}
26931f3c2adSGreg Beaver 
27031f3c2adSGreg Beaver 					PHAR_G(cwd_init) = 0;
27131f3c2adSGreg Beaver 					efree(name);
27231f3c2adSGreg Beaver 					destroy_op_array(new_op_array);
273c6aa379dSSteph Fox 					efree(new_op_array);
27431f3c2adSGreg Beaver 					zval_ptr_dtor(&result);
27531f3c2adSGreg Beaver 				} zend_catch {
276bdeb220fSAnatol Belski 					if (PHAR_G(cwd)) {
27731f3c2adSGreg Beaver 						efree(PHAR_G(cwd));
278df5ad846SDmitry Stogov 						PHAR_G(cwd) = NULL;
27931f3c2adSGreg Beaver 						PHAR_G(cwd_len) = 0;
28031f3c2adSGreg Beaver 					}
28131f3c2adSGreg Beaver 
28231f3c2adSGreg Beaver 					PHAR_G(cwd_init) = 0;
28331f3c2adSGreg Beaver 					efree(name);
28431f3c2adSGreg Beaver 				} zend_end_try();
28531f3c2adSGreg Beaver 
28631f3c2adSGreg Beaver 				zend_bailout();
28731f3c2adSGreg Beaver 			}
28831f3c2adSGreg Beaver 
289c6aa379dSSteph Fox 			return PHAR_MIME_PHP;
29002c7ff13SGreg Beaver 	}
29102c7ff13SGreg Beaver 	return -1;
292c6aa379dSSteph Fox }
29302c7ff13SGreg Beaver /* }}} */
29402c7ff13SGreg Beaver 
phar_do_403(char * entry,size_t entry_len)29502c7ff13SGreg Beaver static void phar_do_403(char *entry, size_t entry_len) /* {{{ */
29602c7ff13SGreg Beaver {
2976d9453aaSAntony Dovgal 	sapi_header_line ctr = {0};
29802c7ff13SGreg Beaver 
2992e5ac355SAnatol Belski 	ctr.response_code = 403;
300e67c5843SGreg Beaver 	ctr.line_len = sizeof("HTTP/1.0 403 Access Denied")-1;
301e67c5843SGreg Beaver 	ctr.line = "HTTP/1.0 403 Access Denied";
302e67c5843SGreg Beaver 	sapi_header_op(SAPI_HEADER_REPLACE, &ctr);
303e67c5843SGreg Beaver 	sapi_send_headers();
304d256caf7SNikita Popov 	PHPWRITE("<html>\n <head>\n  <title>Access Denied</title>\n </head>\n <body>\n  <h1>403 - File ", sizeof("<html>\n <head>\n  <title>Access Denied</title>\n </head>\n <body>\n  <h1>403 - File ") - 1);
305e67c5843SGreg Beaver 	PHPWRITE("Access Denied</h1>\n </body>\n</html>", sizeof("Access Denied</h1>\n </body>\n</html>") - 1);
306bdeb220fSAnatol Belski }
307bdeb220fSAnatol Belski /* }}} */
308e67c5843SGreg Beaver 
phar_do_404(phar_archive_data * phar,char * fname,size_t fname_len,char * f404,size_t f404_len,char * entry,size_t entry_len)3096e64aba4SStanislav Malyshev static void phar_do_404(phar_archive_data *phar, char *fname, size_t fname_len, char *f404, size_t f404_len, char *entry, size_t entry_len) /* {{{ */
310e67c5843SGreg Beaver {
3116d9453aaSAntony Dovgal 	sapi_header_line ctr = {0};
312e67c5843SGreg Beaver 	phar_entry_info	*info;
3132e5ac355SAnatol Belski 
314acc44900SGreg Beaver 	if (phar && f404_len) {
315c6aa379dSSteph Fox 		info = phar_get_entry_info(phar, f404, f404_len, NULL, 1);
316c6aa379dSSteph Fox 
317c6aa379dSSteph Fox 		if (info) {
318c6aa379dSSteph Fox 			phar_file_action(phar, info, "text/html", PHAR_MIME_PHP, f404, f404_len, fname, NULL, NULL, 0);
319bdeb220fSAnatol Belski 			return;
320c6aa379dSSteph Fox 		}
321c6aa379dSSteph Fox 	}
322bdeb220fSAnatol Belski 
323c6aa379dSSteph Fox 	ctr.response_code = 404;
324acc44900SGreg Beaver 	ctr.line_len = sizeof("HTTP/1.0 404 Not Found")-1;
325acc44900SGreg Beaver 	ctr.line = "HTTP/1.0 404 Not Found";
326c6aa379dSSteph Fox 	sapi_header_op(SAPI_HEADER_REPLACE, &ctr);
327c6aa379dSSteph Fox 	sapi_send_headers();
328d256caf7SNikita Popov 	PHPWRITE("<html>\n <head>\n  <title>File Not Found</title>\n </head>\n <body>\n  <h1>404 - File ", sizeof("<html>\n <head>\n  <title>File Not Found</title>\n </head>\n <body>\n  <h1>404 - File ") - 1);
329c6aa379dSSteph Fox 	PHPWRITE("Not Found</h1>\n </body>\n</html>",  sizeof("Not Found</h1>\n </body>\n</html>") - 1);
330bdeb220fSAnatol Belski }
331bdeb220fSAnatol Belski /* }}} */
332c6aa379dSSteph Fox 
3336e64aba4SStanislav Malyshev /* post-process REQUEST_URI and retrieve the actual request URI.  This is for
334acc44900SGreg Beaver    cases like http://localhost/blah.phar/path/to/file.php/extra/stuff
3356d9453aaSAntony Dovgal    which calls "blah.phar" file "path/to/file.php" with PATH_INFO "/extra/stuff" */
phar_postprocess_ru_web(char * fname,size_t fname_len,char ** entry,size_t * entry_len,char ** ru,size_t * ru_len)336acc44900SGreg Beaver static void phar_postprocess_ru_web(char *fname, size_t fname_len, char **entry, size_t *entry_len, char **ru, size_t *ru_len) /* {{{ */
33776b8f306SGreg Beaver {
33876b8f306SGreg Beaver 	char *e = *entry + 1, *u = NULL, *u1 = NULL, *saveu = NULL;
33976b8f306SGreg Beaver 	size_t e_len = *entry_len - 1, u_len = 0;
3402e5ac355SAnatol Belski 	phar_archive_data *pphar;
341e67c5843SGreg Beaver 
34225cdc7deSGreg Beaver 	/* we already know we can retrieve the phar if we reach here */
3432e5ac355SAnatol Belski 	pphar = zend_hash_str_find_ptr(&(PHAR_G(phar_fname_map)), fname, fname_len);
344df5ad846SDmitry Stogov 
345e67c5843SGreg Beaver 	if (!pphar && PHAR_G(manifest_cached)) {
346e67c5843SGreg Beaver 		pphar = zend_hash_str_find_ptr(&cached_phars, fname, fname_len);
34747f2e42fSXinchen Hui 	}
348e67c5843SGreg Beaver 
349c6aa379dSSteph Fox 	do {
350df5ad846SDmitry Stogov 		if (zend_hash_str_exists(&(pphar->manifest), e, e_len)) {
351c6aa379dSSteph Fox 			if (u) {
352c6aa379dSSteph Fox 				u[0] = '/';
353e67c5843SGreg Beaver 				*ru = estrndup(u, u_len+1);
354df5ad846SDmitry Stogov 				++u_len;
355e67c5843SGreg Beaver 				u[0] = '\0';
356e67c5843SGreg Beaver 			} else {
357e67c5843SGreg Beaver 				*ru = NULL;
3586cef8da2SGreg Beaver 			}
359e67c5843SGreg Beaver 			*ru_len = u_len;
360e67c5843SGreg Beaver 			*entry_len = e_len + 1;
361e67c5843SGreg Beaver 			return;
362e67c5843SGreg Beaver 		}
363e67c5843SGreg Beaver 
364e67c5843SGreg Beaver 		if (u) {
365e67c5843SGreg Beaver 			u1 = strrchr(e, '/');
366e67c5843SGreg Beaver 			u[0] = '/';
367c6aa379dSSteph Fox 			saveu = u;
368e67c5843SGreg Beaver 			e_len += u_len + 1;
36925cdc7deSGreg Beaver 			u = u1;
370e67c5843SGreg Beaver 			if (!u) {
371e67c5843SGreg Beaver 				return;
37225cdc7deSGreg Beaver 			}
37325cdc7deSGreg Beaver 		} else {
37425cdc7deSGreg Beaver 			u = strrchr(e, '/');
37525cdc7deSGreg Beaver 			if (!u) {
37625cdc7deSGreg Beaver 				if (saveu) {
37725cdc7deSGreg Beaver 					saveu[0] = '/';
37825cdc7deSGreg Beaver 				}
37925cdc7deSGreg Beaver 				return;
38025cdc7deSGreg Beaver 			}
38125cdc7deSGreg Beaver 		}
38225cdc7deSGreg Beaver 
38325cdc7deSGreg Beaver 		u[0] = '\0';
384e67c5843SGreg Beaver 		u_len = strlen(u + 1);
385e67c5843SGreg Beaver 		e_len -= u_len + 1;
386c6aa379dSSteph Fox 	} while (1);
387e67c5843SGreg Beaver }
3882e5ac355SAnatol Belski /* }}} */
389e67c5843SGreg Beaver 
390e67c5843SGreg Beaver /* {{{ proto void Phar::running([bool retphar = true])
391e67c5843SGreg Beaver  * return the name of the currently running phar archive.  If the optional parameter
3926d9453aaSAntony Dovgal  * is set to true, return the phar:// URL to the currently running phar
393e67c5843SGreg Beaver  */
PHP_METHOD(Phar,running)39439c4f38cSGreg Beaver PHP_METHOD(Phar, running)
39539c4f38cSGreg Beaver {
39639c4f38cSGreg Beaver 	char *fname, *arch, *entry;
397ec7f89feSGreg Beaver 	size_t fname_len, arch_len, entry_len;
39839c4f38cSGreg Beaver 	zend_bool retphar = 1;
399ec7f89feSGreg Beaver 
400ec7f89feSGreg Beaver 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &retphar) == FAILURE) {
4012e5ac355SAnatol Belski 		return;
40239c4f38cSGreg Beaver 	}
40339c4f38cSGreg Beaver 
404bdeb220fSAnatol Belski 	fname = (char*)zend_get_executed_filename();
40539c4f38cSGreg Beaver 	fname_len = strlen(fname);
40639c4f38cSGreg Beaver 
407ec7f89feSGreg Beaver 	if (fname_len > 7 && !memcmp(fname, "phar://", 7) && SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0)) {
408bdeb220fSAnatol Belski 		efree(entry);
4092e5ac355SAnatol Belski 		if (retphar) {
410ec7f89feSGreg Beaver 			RETVAL_STRINGL(fname, arch_len + 7);
411bdeb220fSAnatol Belski 			efree(arch);
412ec7f89feSGreg Beaver 			return;
41339c4f38cSGreg Beaver 		} else {
414df5ad846SDmitry Stogov 			// TODO: avoid reallocation ???
41539c4f38cSGreg Beaver 			RETVAL_STRINGL(arch, arch_len);
41639c4f38cSGreg Beaver 			efree(arch);
41739c4f38cSGreg Beaver 			return;
418df5ad846SDmitry Stogov 		}
419df5ad846SDmitry Stogov 	}
420df5ad846SDmitry Stogov 
421df5ad846SDmitry Stogov 	RETURN_EMPTY_STRING();
42239c4f38cSGreg Beaver }
423ec7f89feSGreg Beaver /* }}} */
424c6aa379dSSteph Fox 
425df5ad846SDmitry Stogov /* {{{ proto void Phar::mount(string pharpath, string externalfile)
426ec7f89feSGreg Beaver  * mount an external file or path to a location within the phar.  This maps
427ec7f89feSGreg Beaver  * an external file or directory to a location within the phar archive, allowing
428ec7f89feSGreg Beaver  * reference to an external location as if it were within the phar archive.  This
4296798dc44SGreg Beaver  * is useful for writable temp files like databases
4306798dc44SGreg Beaver  */
PHP_METHOD(Phar,mount)4316798dc44SGreg Beaver PHP_METHOD(Phar, mount)
4326798dc44SGreg Beaver {
4336798dc44SGreg Beaver 	char *fname, *arch = NULL, *entry = NULL, *path, *actual;
4346798dc44SGreg Beaver 	size_t fname_len, arch_len, entry_len;
4356798dc44SGreg Beaver 	size_t path_len, actual_len;
4366798dc44SGreg Beaver 	phar_archive_data *pphar;
4373d953abaSGreg Beaver #ifdef PHP_WIN32
4382e5ac355SAnatol Belski 	char *save_fname;
4391e3e9e0bSAnatol Belski 	ALLOCA_FLAG(fname_use_heap)
440df5ad846SDmitry Stogov #endif
4416798dc44SGreg Beaver 
4421e9b1752SStanislav Malyshev 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "pp", &path, &path_len, &actual, &actual_len) == FAILURE) {
4436798dc44SGreg Beaver 		return;
4446798dc44SGreg Beaver 	}
4456798dc44SGreg Beaver 
446bdeb220fSAnatol Belski 	fname = (char*)zend_get_executed_filename();
4472e5ac355SAnatol Belski 	fname_len = strlen(fname);
4486798dc44SGreg Beaver 
449c6aa379dSSteph Fox #ifdef PHP_WIN32
450c6aa379dSSteph Fox 	save_fname = fname;
451c6aa379dSSteph Fox 	if (memchr(fname, '\\', fname_len)) {
452c6aa379dSSteph Fox 		fname = do_alloca(fname_len + 1, fname_use_heap);
453bdeb220fSAnatol Belski 		memcpy(fname, save_fname, fname_len);
454ec7f89feSGreg Beaver 		fname[fname_len] = '\0';
4554388a65aSGreg Beaver 		phar_unixify_path_separators(fname, fname_len);
456c6aa379dSSteph Fox 	}
4574388a65aSGreg Beaver #endif
458bdeb220fSAnatol Belski 
4594388a65aSGreg Beaver 	if (fname_len > 7 && !memcmp(fname, "phar://", 7) && SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0)) {
4604388a65aSGreg Beaver 		efree(entry);
4614388a65aSGreg Beaver 		entry = NULL;
4624388a65aSGreg Beaver 
46347f2e42fSXinchen Hui 		if (path_len > 7 && !memcmp(path, "phar://", 7)) {
464df5ad846SDmitry Stogov 			zend_throw_exception_ex(phar_ce_PharException, 0, "Can only mount internal paths within a phar archive, use a relative path instead of \"%s\"", path);
465bdeb220fSAnatol Belski 			efree(arch);
466c6aa379dSSteph Fox 			goto finish;
467c6aa379dSSteph Fox 		}
468c6aa379dSSteph Fox carry_on2:
469c6aa379dSSteph Fox 		if (NULL == (pphar = zend_hash_str_find_ptr(&(PHAR_G(phar_fname_map)), arch, arch_len))) {
470bdeb220fSAnatol Belski 			if (PHAR_G(manifest_cached) && NULL != (pphar = zend_hash_str_find_ptr(&cached_phars, arch, arch_len))) {
471c6aa379dSSteph Fox 				if (SUCCESS == phar_copy_on_write(&pphar)) {
4723d953abaSGreg Beaver 					goto carry_on;
4733d953abaSGreg Beaver 				}
4743d953abaSGreg Beaver 			}
4756798dc44SGreg Beaver 
4766798dc44SGreg Beaver 			zend_throw_exception_ex(phar_ce_PharException, 0, "%s is not a phar archive, cannot mount", arch);
477ec7f89feSGreg Beaver 
4782e5ac355SAnatol Belski 			if (arch) {
479bdeb220fSAnatol Belski 				efree(arch);
4804388a65aSGreg Beaver 			}
4814388a65aSGreg Beaver 
4824388a65aSGreg Beaver 			goto finish;
483c6aa379dSSteph Fox 		}
4843d953abaSGreg Beaver carry_on:
4853d953abaSGreg Beaver 		if (SUCCESS != phar_mount_entry(pphar, actual, actual_len, path, path_len)) {
4863d953abaSGreg Beaver 			zend_throw_exception_ex(phar_ce_PharException, 0, "Mounting of %s to %s within phar %s failed", path, actual, arch);
487c6aa379dSSteph Fox 			if (path && path == entry) {
4880c2f3b76SGreg Beaver 				efree(entry);
4896798dc44SGreg Beaver 			}
490c6aa379dSSteph Fox 
4913d953abaSGreg Beaver 			if (arch) {
4924388a65aSGreg Beaver 				efree(arch);
4934388a65aSGreg Beaver 			}
494c6aa379dSSteph Fox 
4953d953abaSGreg Beaver 			goto finish;
4963d953abaSGreg Beaver 		}
4973d953abaSGreg Beaver 
498c6aa379dSSteph Fox 		if (entry && path && path == entry) {
499ec7f89feSGreg Beaver 			efree(entry);
5009cbb5210SDmitry Stogov 		}
501c6aa379dSSteph Fox 
502df5ad846SDmitry Stogov 		if (arch) {
503bdeb220fSAnatol Belski 			efree(arch);
504c6aa379dSSteph Fox 		}
505c6aa379dSSteph Fox 
506c6aa379dSSteph Fox 		goto finish;
507ec7f89feSGreg Beaver 	} else if (HT_IS_INITIALIZED(&PHAR_G(phar_fname_map)) && NULL != (pphar = zend_hash_str_find_ptr(&(PHAR_G(phar_fname_map)), fname, fname_len))) {
5082e5ac355SAnatol Belski 		goto carry_on;
5094388a65aSGreg Beaver 	} else if (PHAR_G(manifest_cached) && NULL != (pphar = zend_hash_str_find_ptr(&cached_phars, fname, fname_len))) {
5104388a65aSGreg Beaver 		if (SUCCESS == phar_copy_on_write(&pphar)) {
5114388a65aSGreg Beaver 			goto carry_on;
5126798dc44SGreg Beaver 		}
513c6aa379dSSteph Fox 
514bdeb220fSAnatol Belski 		goto carry_on;
5156798dc44SGreg Beaver 	} else if (SUCCESS == phar_split_fname(path, path_len, &arch, &arch_len, &entry, &entry_len, 2, 0)) {
5166798dc44SGreg Beaver 		path = entry;
5176798dc44SGreg Beaver 		path_len = entry_len;
518e67c5843SGreg Beaver 		goto carry_on2;
51902c7ff13SGreg Beaver 	}
5205200481aSGreg Beaver 
5215200481aSGreg Beaver 	zend_throw_exception_ex(phar_ce_PharException, 0, "Mounting of %s to %s failed", path, actual);
5225200481aSGreg Beaver 
5235200481aSGreg Beaver finish: ;
52402c7ff13SGreg Beaver #ifdef PHP_WIN32
52502c7ff13SGreg Beaver 	if (fname != save_fname) {
52602c7ff13SGreg Beaver 		free_alloca(fname, fname_use_heap);
527e67c5843SGreg Beaver 		fname = save_fname;
528549bf83bSGreg Beaver 	}
5295c0e1185SRemi Collet #endif
5302e5ac355SAnatol Belski }
5311fed0e5aSKalle Sommer Nielsen /* }}} */
5321fed0e5aSKalle Sommer Nielsen 
5336db8d4f8SAnatol Belski /* {{{ proto void Phar::webPhar([string alias, [string index, [string f404, [array mimetypes, [callback rewrites]]]]])
5342e5ac355SAnatol Belski  * mapPhar for web-based phars. Reads the currently executed file (a phar)
5352e5ac355SAnatol Belski  * and registers its manifest. When executed in the CLI or CGI command-line sapi,
536c6aa379dSSteph Fox  * this works exactly like mapPhar().  When executed by a web-based sapi, this
537cc42ac9dSXinchen Hui  * reads $_SERVER['REQUEST_URI'] (the actual original value) and parses out the
5386beb91c2SAnatol Belski  * intended internal file.
53902c7ff13SGreg Beaver  */
PHP_METHOD(Phar,webPhar)540bdeb220fSAnatol Belski PHP_METHOD(Phar, webPhar)
54102c7ff13SGreg Beaver {
54202c7ff13SGreg Beaver 	zval *mimeoverride = NULL, *rewrite = NULL;
54302c7ff13SGreg Beaver 	char *alias = NULL, *error, *index_php = NULL, *f404 = NULL, *ru = NULL;
544bdeb220fSAnatol Belski 	size_t alias_len = 0, f404_len = 0, free_pathinfo = 0;
545bdeb220fSAnatol Belski 	size_t ru_len = 0;
546de5238a3SGreg Beaver 	char *fname, *path_info, *mime_type = NULL, *entry, *pt;
547c6aa379dSSteph Fox 	const char *basename;
5482e5ac355SAnatol Belski 	size_t fname_len, index_php_len = 0;
54902c7ff13SGreg Beaver 	size_t entry_len;
550bdeb220fSAnatol Belski 	int code, not_cgi;
55102c7ff13SGreg Beaver 	phar_archive_data *phar = NULL;
55202c7ff13SGreg Beaver 	phar_entry_info *info = NULL;
55302c7ff13SGreg Beaver 	size_t sapi_mod_name_len = strlen(sapi_module.name);
55402c7ff13SGreg Beaver 
55502c7ff13SGreg Beaver 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s!s!saz", &alias, &alias_len, &index_php, &index_php_len, &f404, &f404_len, &mimeoverride, &rewrite) == FAILURE) {
55602c7ff13SGreg Beaver 		return;
557c0c08719SChristian Weiske 	}
558c0c08719SChristian Weiske 
559c0c08719SChristian Weiske 	phar_request_initialize();
560c0c08719SChristian Weiske 	fname = (char*)zend_get_executed_filename();
561c0c08719SChristian Weiske 	fname_len = strlen(fname);
562c0c08719SChristian Weiske 
563c0c08719SChristian Weiske 	if (phar_open_executed_filename(alias, alias_len, &error) != SUCCESS) {
564c0c08719SChristian Weiske 		if (error) {
565c0c08719SChristian Weiske 			zend_throw_exception_ex(phar_ce_PharException, 0, "%s", error);
566c0c08719SChristian Weiske 			efree(error);
567c0c08719SChristian Weiske 		}
568c0c08719SChristian Weiske 		return;
56902c7ff13SGreg Beaver 	}
57002c7ff13SGreg Beaver 
571c6aa379dSSteph Fox 	/* retrieve requested file within phar */
572e1a41da6SGreg Beaver 	if (!(SG(request_info).request_method
573e1a41da6SGreg Beaver           && SG(request_info).request_uri
574e1a41da6SGreg Beaver           && (!strcmp(SG(request_info).request_method, "GET")
575e1a41da6SGreg Beaver            || !strcmp(SG(request_info).request_method, "POST")
576c6aa379dSSteph Fox            || !strcmp(SG(request_info).request_method, "DELETE")
577c6aa379dSSteph Fox            || !strcmp(SG(request_info).request_method, "HEAD")
57802c7ff13SGreg Beaver            || !strcmp(SG(request_info).request_method, "OPTIONS")
57902c7ff13SGreg Beaver            || !strcmp(SG(request_info).request_method, "PATCH")
58002c7ff13SGreg Beaver            || !strcmp(SG(request_info).request_method, "PUT")
5816cef8da2SGreg Beaver           )
58202c7ff13SGreg Beaver          )
583e8a5b205SGreg Beaver       ) {
5846beb91c2SAnatol Belski 		return;
5856beb91c2SAnatol Belski 	}
5866beb91c2SAnatol Belski 
5871cac0aa8SGreg Beaver #ifdef PHP_WIN32
588df5ad846SDmitry Stogov 	if (memchr(fname, '\\', fname_len)) {
589df5ad846SDmitry Stogov 		fname = estrndup(fname, fname_len);
590df5ad846SDmitry Stogov 		phar_unixify_path_separators(fname, fname_len);
591c6aa379dSSteph Fox 	}
592df5ad846SDmitry Stogov #endif
593df5ad846SDmitry Stogov 	basename = zend_memrchr(fname, '/', fname_len);
594df5ad846SDmitry Stogov 
595c6aa379dSSteph Fox 	if (!basename) {
596c6aa379dSSteph Fox 		basename = fname;
597c6aa379dSSteph Fox 	} else {
598df5ad846SDmitry Stogov 		++basename;
599df5ad846SDmitry Stogov 	}
6002e5ac355SAnatol Belski 
601df5ad846SDmitry Stogov 	if ((sapi_mod_name_len == sizeof("cgi-fcgi") - 1 && !strncmp(sapi_module.name, "cgi-fcgi", sizeof("cgi-fcgi") - 1))
602c3e3c98eSAnatol Belski 		|| (sapi_mod_name_len == sizeof("fpm-fcgi") - 1 && !strncmp(sapi_module.name, "fpm-fcgi", sizeof("fpm-fcgi") - 1))
603c3e3c98eSAnatol Belski 		|| (sapi_mod_name_len == sizeof("cgi") - 1 && !strncmp(sapi_module.name, "cgi", sizeof("cgi") - 1))) {
604c3e3c98eSAnatol Belski 
605c6aa379dSSteph Fox 		if (Z_TYPE(PG(http_globals)[TRACK_VARS_SERVER]) != IS_UNDEF) {
606c6aa379dSSteph Fox 			HashTable *_server = Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]);
607c6aa379dSSteph Fox 			zval *z_script_name, *z_path_info;
608c6aa379dSSteph Fox 
609df5ad846SDmitry Stogov 			if (NULL == (z_script_name = zend_hash_str_find(_server, "SCRIPT_NAME", sizeof("SCRIPT_NAME")-1)) ||
610c6aa379dSSteph Fox 				IS_STRING != Z_TYPE_P(z_script_name) ||
611c6aa379dSSteph Fox 				!strstr(Z_STRVAL_P(z_script_name), basename)) {
612c3e3c98eSAnatol Belski 				goto finish;
613c6aa379dSSteph Fox 			}
6141cac0aa8SGreg Beaver 
615c6aa379dSSteph Fox 			if (NULL != (z_path_info = zend_hash_str_find(_server, "PATH_INFO", sizeof("PATH_INFO")-1)) &&
616c6aa379dSSteph Fox 				IS_STRING == Z_TYPE_P(z_path_info)) {
617bdeb220fSAnatol Belski 				entry_len = Z_STRLEN_P(z_path_info);
618c6aa379dSSteph Fox 				entry = estrndup(Z_STRVAL_P(z_path_info), entry_len);
619c6aa379dSSteph Fox 				path_info = emalloc(Z_STRLEN_P(z_script_name) + entry_len + 1);
620c6aa379dSSteph Fox 				memcpy(path_info, Z_STRVAL_P(z_script_name), Z_STRLEN_P(z_script_name));
621c6aa379dSSteph Fox 				memcpy(path_info + Z_STRLEN_P(z_script_name), entry, entry_len + 1);
622c6aa379dSSteph Fox 				free_pathinfo = 1;
623bdeb220fSAnatol Belski 			} else {
624c6aa379dSSteph Fox 				entry_len = 0;
625c6aa379dSSteph Fox 				entry = estrndup("", 0);
626c6aa379dSSteph Fox 				path_info = Z_STRVAL_P(z_script_name);
6272e5ac355SAnatol Belski 			}
628c6aa379dSSteph Fox 
629c6aa379dSSteph Fox 			pt = estrndup(Z_STRVAL_P(z_script_name), Z_STRLEN_P(z_script_name));
630c6aa379dSSteph Fox 
631c6aa379dSSteph Fox 		} else {
632c6aa379dSSteph Fox 			char *testit;
633c6aa379dSSteph Fox 
634c6aa379dSSteph Fox 			testit = sapi_getenv("SCRIPT_NAME", sizeof("SCRIPT_NAME")-1);
635c6aa379dSSteph Fox 			if (!(pt = strstr(testit, basename))) {
636c6aa379dSSteph Fox 				efree(testit);
637c6aa379dSSteph Fox 				goto finish;
6381cac0aa8SGreg Beaver 			}
639a3c91073SGreg Beaver 
6401cac0aa8SGreg Beaver 			path_info = sapi_getenv("PATH_INFO", sizeof("PATH_INFO")-1);
6411cac0aa8SGreg Beaver 
6421cac0aa8SGreg Beaver 			if (path_info) {
643e67c5843SGreg Beaver 				entry = path_info;
644e67c5843SGreg Beaver 				entry_len = strlen(entry);
645e67c5843SGreg Beaver 				spprintf(&path_info, 0, "%s%s", testit, path_info);
646e67c5843SGreg Beaver 				free_pathinfo = 1;
647e67c5843SGreg Beaver 			} else {
6482e5ac355SAnatol Belski 				path_info = testit;
649e67c5843SGreg Beaver 				free_pathinfo = 1;
650e67c5843SGreg Beaver 				entry = estrndup("", 0);
651e67c5843SGreg Beaver 				entry_len = 0;
652e67c5843SGreg Beaver 			}
653a3c91073SGreg Beaver 
654e8a5b205SGreg Beaver 			pt = estrndup(testit, (pt - testit) + (fname_len - (basename - fname)));
655e8a5b205SGreg Beaver 		}
656e67c5843SGreg Beaver 		not_cgi = 0;
657e67c5843SGreg Beaver 	} else {
658e67c5843SGreg Beaver 		path_info = SG(request_info).request_uri;
659df5ad846SDmitry Stogov 
660e67c5843SGreg Beaver 		if (!(pt = strstr(path_info, basename))) {
661df5ad846SDmitry Stogov 			/* this can happen with rewrite rules - and we have no idea what to do then, so return */
662e67c5843SGreg Beaver 			goto finish;
663bdeb220fSAnatol Belski 		}
664bdeb220fSAnatol Belski 
665c6aa379dSSteph Fox 		entry_len = strlen(path_info);
666e67c5843SGreg Beaver 		entry_len -= (pt - path_info) + (fname_len - (basename - fname));
667e67c5843SGreg Beaver 		entry = estrndup(pt + (fname_len - (basename - fname)), entry_len);
668e67c5843SGreg Beaver 
6690b5faa44SAnatol Belski 		pt = estrndup(path_info, (pt - path_info) + (fname_len - (basename - fname)));
670c6aa379dSSteph Fox 		not_cgi = 1;
671e67c5843SGreg Beaver 	}
672e67c5843SGreg Beaver 
673e67c5843SGreg Beaver 	if (rewrite) {
674e67c5843SGreg Beaver 		zend_fcall_info fci;
675df5ad846SDmitry Stogov 		zend_fcall_info_cache fcc;
676df5ad846SDmitry Stogov 		zval params, retval;
677df5ad846SDmitry Stogov 
678e8a5b205SGreg Beaver 		ZVAL_STRINGL(&params, entry, entry_len);
679bdeb220fSAnatol Belski 
680e67c5843SGreg Beaver 		if (FAILURE == zend_fcall_info_init(rewrite, 0, &fci, &fcc, NULL, NULL)) {
681bdeb220fSAnatol Belski 			zend_throw_exception_ex(phar_ce_PharException, 0, "phar error: invalid rewrite callback");
682e67c5843SGreg Beaver 
683c6aa379dSSteph Fox 			if (free_pathinfo) {
684e67c5843SGreg Beaver 				efree(path_info);
685e67c5843SGreg Beaver 			}
686e67c5843SGreg Beaver 			efree(pt);
6870b5faa44SAnatol Belski 
688c6aa379dSSteph Fox 			goto finish;
689e67c5843SGreg Beaver 		}
690e67c5843SGreg Beaver 
691c6aa379dSSteph Fox 		fci.param_count = 1;
692df5ad846SDmitry Stogov 		fci.params = &params;
693e67c5843SGreg Beaver 		Z_ADDREF(params);
694e67c5843SGreg Beaver 		fci.retval = &retval;
695e67c5843SGreg Beaver 
696bdeb220fSAnatol Belski 		if (FAILURE == zend_call_function(&fci, &fcc)) {
6970b5faa44SAnatol Belski 			if (!EG(exception)) {
698e67c5843SGreg Beaver 				zend_throw_exception_ex(phar_ce_PharException, 0, "phar error: failed to call rewrite callback");
699e67c5843SGreg Beaver 			}
700c6aa379dSSteph Fox 
701df5ad846SDmitry Stogov 			if (free_pathinfo) {
702f08aea10SSteph Fox 				efree(path_info);
703e67c5843SGreg Beaver 			}
704c3e3c98eSAnatol Belski 			efree(pt);
7052e5ac355SAnatol Belski 
706e67c5843SGreg Beaver 			goto finish;
707df5ad846SDmitry Stogov 		}
708df5ad846SDmitry Stogov 
709bdeb220fSAnatol Belski 		if (Z_TYPE_P(fci.retval) == IS_UNDEF || Z_TYPE(retval) == IS_UNDEF) {
710c6aa379dSSteph Fox 			if (free_pathinfo) {
711e67c5843SGreg Beaver 				efree(path_info);
712e67c5843SGreg Beaver 			}
713e67c5843SGreg Beaver 			zend_throw_exception_ex(phar_ce_PharException, 0, "phar error: rewrite callback must return a string or false");
7140b5faa44SAnatol Belski 			efree(pt);
715c6aa379dSSteph Fox 			goto finish;
716e67c5843SGreg Beaver 		}
717e67c5843SGreg Beaver 
718e67c5843SGreg Beaver 		switch (Z_TYPE(retval)) {
719e67c5843SGreg Beaver 			case IS_STRING:
720e67c5843SGreg Beaver 				efree(entry);
721e67c5843SGreg Beaver 				entry = estrndup(Z_STRVAL_P(fci.retval), Z_STRLEN_P(fci.retval));
7220b5faa44SAnatol Belski 				entry_len = Z_STRLEN_P(fci.retval);
723c6aa379dSSteph Fox 				break;
724bdeb220fSAnatol Belski 			case IS_TRUE:
725e67c5843SGreg Beaver 			case IS_FALSE:
726e67c5843SGreg Beaver 				phar_do_403(entry, entry_len);
727e67c5843SGreg Beaver 
7281cac0aa8SGreg Beaver 				if (free_pathinfo) {
729e67c5843SGreg Beaver 					efree(path_info);
7302e5ac355SAnatol Belski 				}
731e67c5843SGreg Beaver 				efree(pt);
732c6aa379dSSteph Fox 
733e8a5b205SGreg Beaver 				zend_bailout();
734e8a5b205SGreg Beaver 				goto finish;
735e8a5b205SGreg Beaver 			default:
736e8a5b205SGreg Beaver 				if (free_pathinfo) {
737e8a5b205SGreg Beaver 					efree(path_info);
7382e5ac355SAnatol Belski 				}
7392b9a4279SGreg Beaver 				efree(pt);
7402b9a4279SGreg Beaver 
7416cef8da2SGreg Beaver 				zend_throw_exception_ex(phar_ce_PharException, 0, "phar error: rewrite callback must return a string or false");
7422b9a4279SGreg Beaver 				goto finish;
743e8a5b205SGreg Beaver 		}
744e8a5b205SGreg Beaver 	}
745e8a5b205SGreg Beaver 
746e8a5b205SGreg Beaver 	if (entry_len) {
747e8a5b205SGreg Beaver 		phar_postprocess_ru_web(fname, fname_len, &entry, &entry_len, &ru, &ru_len);
748c6aa379dSSteph Fox 	}
7492e5ac355SAnatol Belski 
750bdeb220fSAnatol Belski 	if (!entry_len || (entry_len == 1 && entry[0] == '/')) {
7512e5ac355SAnatol Belski 		efree(entry);
752c6aa379dSSteph Fox 		/* direct request */
7531cac0aa8SGreg Beaver 		if (index_php_len) {
7541cac0aa8SGreg Beaver 			entry = index_php;
7551cac0aa8SGreg Beaver 			entry_len = index_php_len;
756c6aa379dSSteph Fox 			if (entry[0] != '/') {
757e8a5b205SGreg Beaver 				spprintf(&entry, 0, "/%s", index_php);
758e8a5b205SGreg Beaver 				++entry_len;
759cc42ac9dSXinchen Hui 			}
760e8a5b205SGreg Beaver 		} else {
761e8a5b205SGreg Beaver 			/* assume "index.php" is starting point */
762d256caf7SNikita Popov 			entry = estrndup("/index.php", sizeof("/index.php"));
763e8a5b205SGreg Beaver 			entry_len = sizeof("/index.php")-1;
764bdeb220fSAnatol Belski 		}
765e8a5b205SGreg Beaver 
76643f26386SGreg Beaver 		if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, NULL) ||
76743f26386SGreg Beaver 			(info = phar_get_entry_info(phar, entry, entry_len, NULL, 0)) == NULL) {
7687575b012SGreg Beaver 			phar_do_404(phar, fname, fname_len, f404, f404_len, entry, entry_len);
7697575b012SGreg Beaver 
7707575b012SGreg Beaver 			if (free_pathinfo) {
771c6aa379dSSteph Fox 				efree(path_info);
772e8a5b205SGreg Beaver 			}
773c6aa379dSSteph Fox 
7742b9a4279SGreg Beaver 			zend_bailout();
7752b9a4279SGreg Beaver 		} else {
77608b7b764SGreg Beaver 			char *tmp = NULL, sa = '\0';
7772b9a4279SGreg Beaver 			sapi_header_line ctr = {0};
77808b7b764SGreg Beaver 			ctr.response_code = 301;
779c6aa379dSSteph Fox 			ctr.line_len = sizeof("HTTP/1.1 301 Moved Permanently")-1;
78043f26386SGreg Beaver 			ctr.line = "HTTP/1.1 301 Moved Permanently";
7817575b012SGreg Beaver 			sapi_header_op(SAPI_HEADER_REPLACE, &ctr);
7827575b012SGreg Beaver 
783c6aa379dSSteph Fox 			if (not_cgi) {
7841cac0aa8SGreg Beaver 				tmp = strstr(path_info, basename) + fname_len;
7851cac0aa8SGreg Beaver 				sa = *tmp;
7861cac0aa8SGreg Beaver 				*tmp = '\0';
787c6aa379dSSteph Fox 			}
788bdeb220fSAnatol Belski 
789bdeb220fSAnatol Belski 			ctr.response_code = 0;
790e8a5b205SGreg Beaver 
791e8a5b205SGreg Beaver 			if (path_info[strlen(path_info)-1] == '/') {
7925200481aSGreg Beaver 				ctr.line_len = spprintf(&(ctr.line), 4096, "Location: %s%s", path_info, entry + 1);
79302c7ff13SGreg Beaver 			} else {
79402c7ff13SGreg Beaver 				ctr.line_len = spprintf(&(ctr.line), 4096, "Location: %s%s", path_info, entry);
7952e5ac355SAnatol Belski 			}
796bdeb220fSAnatol Belski 
7972e5ac355SAnatol Belski 			if (not_cgi) {
798acc44900SGreg Beaver 				*tmp = sa;
799acc44900SGreg Beaver 			}
800acc44900SGreg Beaver 
801acc44900SGreg Beaver 			if (free_pathinfo) {
802acc44900SGreg Beaver 				efree(path_info);
803acc44900SGreg Beaver 			}
804c6aa379dSSteph Fox 
8051fed0e5aSKalle Sommer Nielsen 			sapi_header_op(SAPI_HEADER_REPLACE, &ctr);
806df5ad846SDmitry Stogov 			sapi_send_headers();
807c1ae13b9SSteph Fox 			efree(ctr.line);
808c6aa379dSSteph Fox 			zend_bailout();
809c6aa379dSSteph Fox 		}
810c1ae13b9SSteph Fox 	}
811df5ad846SDmitry Stogov 
812