xref: /PHP-7.1/ext/phar/phar_object.c (revision cd1101e8)
1 /*
2   +----------------------------------------------------------------------+
3   | phar php single-file executable PHP extension                        |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 2005-2018 The PHP Group                                |
6   +----------------------------------------------------------------------+
7   | This source file is subject to version 3.01 of the PHP license,      |
8   | that is bundled with this package in the file LICENSE, and is        |
9   | available through the world-wide-web at the following url:           |
10   | http://www.php.net/license/3_01.txt.                                 |
11   | If you did not receive a copy of the PHP license and are unable to   |
12   | obtain it through the world-wide-web, please send a note to          |
13   | license@php.net so we can mail you a copy immediately.               |
14   +----------------------------------------------------------------------+
15   | Authors: Gregory Beaver <cellog@php.net>                             |
16   |          Marcus Boerger <helly@php.net>                              |
17   +----------------------------------------------------------------------+
18 */
19 
20 /* $Id$ */
21 
22 #include "phar_internal.h"
23 #include "func_interceptors.h"
24 
25 static zend_class_entry *phar_ce_archive;
26 static zend_class_entry *phar_ce_data;
27 static zend_class_entry *phar_ce_PharException;
28 static zend_class_entry *phar_ce_entry;
29 
phar_file_type(HashTable * mimes,char * file,char ** mime_type)30 static int phar_file_type(HashTable *mimes, char *file, char **mime_type) /* {{{ */
31 {
32 	char *ext;
33 	phar_mime_type *mime;
34 	ext = strrchr(file, '.');
35 	if (!ext) {
36 		*mime_type = "text/plain";
37 		/* no file extension = assume text/plain */
38 		return PHAR_MIME_OTHER;
39 	}
40 	++ext;
41 	if (NULL == (mime = zend_hash_str_find_ptr(mimes, ext, strlen(ext)))) {
42 		*mime_type = "application/octet-stream";
43 		return PHAR_MIME_OTHER;
44 	}
45 	*mime_type = mime->mime;
46 	return mime->type;
47 }
48 /* }}} */
49 
phar_mung_server_vars(char * fname,char * entry,int entry_len,char * basename,int request_uri_len)50 static void phar_mung_server_vars(char *fname, char *entry, int entry_len, char *basename, int request_uri_len) /* {{{ */
51 {
52 	HashTable *_SERVER;
53 	zval *stuff;
54 	char *path_info;
55 	size_t basename_len = strlen(basename);
56 	size_t code;
57 	zval temp;
58 
59 	/* "tweak" $_SERVER variables requested in earlier call to Phar::mungServer() */
60 	if (Z_TYPE(PG(http_globals)[TRACK_VARS_SERVER]) == IS_UNDEF) {
61 		return;
62 	}
63 
64 	_SERVER = Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]);
65 
66 	/* PATH_INFO and PATH_TRANSLATED should always be munged */
67 	if (NULL != (stuff = zend_hash_str_find(_SERVER, "PATH_INFO", sizeof("PATH_INFO")-1))) {
68 		path_info = Z_STRVAL_P(stuff);
69 		code = Z_STRLEN_P(stuff);
70 		if (code > entry_len && !memcmp(path_info, entry, entry_len)) {
71 			ZVAL_STR(&temp, Z_STR_P(stuff));
72 			ZVAL_STRINGL(stuff, path_info + entry_len, request_uri_len);
73 			zend_hash_str_update(_SERVER, "PHAR_PATH_INFO", sizeof("PHAR_PATH_INFO")-1, &temp);
74 		}
75 	}
76 
77 	if (NULL != (stuff = zend_hash_str_find(_SERVER, "PATH_TRANSLATED", sizeof("PATH_TRANSLATED")-1))) {
78 		zend_string *str = strpprintf(4096, "phar://%s%s", fname, entry);
79 
80 		ZVAL_STR(&temp, Z_STR_P(stuff));
81 		ZVAL_NEW_STR(stuff, str);
82 
83 		zend_hash_str_update(_SERVER, "PHAR_PATH_TRANSLATED", sizeof("PHAR_PATH_TRANSLATED")-1, &temp);
84 	}
85 
86 	if (!PHAR_G(phar_SERVER_mung_list)) {
87 		return;
88 	}
89 
90 	if (PHAR_G(phar_SERVER_mung_list) & PHAR_MUNG_REQUEST_URI) {
91 		if (NULL != (stuff = zend_hash_str_find(_SERVER, "REQUEST_URI", sizeof("REQUEST_URI")-1))) {
92 			path_info = Z_STRVAL_P(stuff);
93 			code = Z_STRLEN_P(stuff);
94 			if (code > basename_len && !memcmp(path_info, basename, basename_len)) {
95 				ZVAL_STR(&temp, Z_STR_P(stuff));
96 				ZVAL_STRINGL(stuff, path_info + basename_len, code - basename_len);
97 				zend_hash_str_update(_SERVER, "PHAR_REQUEST_URI", sizeof("PHAR_REQUEST_URI")-1, &temp);
98 			}
99 		}
100 	}
101 
102 	if (PHAR_G(phar_SERVER_mung_list) & PHAR_MUNG_PHP_SELF) {
103 		if (NULL != (stuff = zend_hash_str_find(_SERVER, "PHP_SELF", sizeof("PHP_SELF")-1))) {
104 			path_info = Z_STRVAL_P(stuff);
105 			code = Z_STRLEN_P(stuff);
106 
107 			if (code > basename_len && !memcmp(path_info, basename, basename_len)) {
108 				ZVAL_STR(&temp, Z_STR_P(stuff));
109 				ZVAL_STRINGL(stuff, path_info + basename_len, code - basename_len);
110 				zend_hash_str_update(_SERVER, "PHAR_PHP_SELF", sizeof("PHAR_PHP_SELF")-1, &temp);
111 			}
112 		}
113 	}
114 
115 	if (PHAR_G(phar_SERVER_mung_list) & PHAR_MUNG_SCRIPT_NAME) {
116 		if (NULL != (stuff = zend_hash_str_find(_SERVER, "SCRIPT_NAME", sizeof("SCRIPT_NAME")-1))) {
117 			ZVAL_STR(&temp, Z_STR_P(stuff));
118 			ZVAL_STRINGL(stuff, entry, entry_len);
119 			zend_hash_str_update(_SERVER, "PHAR_SCRIPT_NAME", sizeof("PHAR_SCRIPT_NAME")-1, &temp);
120 		}
121 	}
122 
123 	if (PHAR_G(phar_SERVER_mung_list) & PHAR_MUNG_SCRIPT_FILENAME) {
124 		if (NULL != (stuff = zend_hash_str_find(_SERVER, "SCRIPT_FILENAME", sizeof("SCRIPT_FILENAME")-1))) {
125 			zend_string *str = strpprintf(4096, "phar://%s%s", fname, entry);
126 
127 			ZVAL_STR(&temp, Z_STR_P(stuff));
128 			ZVAL_NEW_STR(stuff, str);
129 
130 			zend_hash_str_update(_SERVER, "PHAR_SCRIPT_FILENAME", sizeof("PHAR_SCRIPT_FILENAME")-1, &temp);
131 		}
132 	}
133 }
134 /* }}} */
135 
phar_file_action(phar_archive_data * phar,phar_entry_info * info,char * mime_type,int code,char * entry,int entry_len,char * arch,char * basename,char * ru,int ru_len)136 static int phar_file_action(phar_archive_data *phar, phar_entry_info *info, char *mime_type, int code, char *entry, int entry_len, char *arch, char *basename, char *ru, int ru_len) /* {{{ */
137 {
138 	char *name = NULL, buf[8192];
139 	const char *cwd;
140 	zend_syntax_highlighter_ini syntax_highlighter_ini;
141 	sapi_header_line ctr = {0};
142 	size_t got;
143 	zval dummy;
144 	size_t name_len;
145 	zend_file_handle file_handle;
146 	zend_op_array *new_op_array;
147 	zval result;
148 	php_stream *fp;
149 	zend_off_t position;
150 
151 	switch (code) {
152 		case PHAR_MIME_PHPS:
153 			efree(basename);
154 			/* highlight source */
155 			if (entry[0] == '/') {
156 				spprintf(&name, 4096, "phar://%s%s", arch, entry);
157 			} else {
158 				spprintf(&name, 4096, "phar://%s/%s", arch, entry);
159 			}
160 			php_get_highlight_struct(&syntax_highlighter_ini);
161 
162 			highlight_file(name, &syntax_highlighter_ini);
163 
164 			efree(name);
165 #ifdef PHP_WIN32
166 			efree(arch);
167 #endif
168 			zend_bailout();
169 		case PHAR_MIME_OTHER:
170 			/* send headers, output file contents */
171 			efree(basename);
172 			ctr.line_len = spprintf(&(ctr.line), 0, "Content-type: %s", mime_type);
173 			sapi_header_op(SAPI_HEADER_REPLACE, &ctr);
174 			efree(ctr.line);
175 			ctr.line_len = spprintf(&(ctr.line), 0, "Content-length: %u", info->uncompressed_filesize);
176 			sapi_header_op(SAPI_HEADER_REPLACE, &ctr);
177 			efree(ctr.line);
178 
179 			if (FAILURE == sapi_send_headers()) {
180 				zend_bailout();
181 			}
182 
183 			/* prepare to output  */
184 			fp = phar_get_efp(info, 1);
185 
186 			if (!fp) {
187 				char *error;
188 				if (!phar_open_jit(phar, info, &error)) {
189 					if (error) {
190 						zend_throw_exception_ex(phar_ce_PharException, 0, "%s", error);
191 						efree(error);
192 					}
193 					return -1;
194 				}
195 				fp = phar_get_efp(info, 1);
196 			}
197 			position = 0;
198 			phar_seek_efp(info, 0, SEEK_SET, 0, 1);
199 
200 			do {
201 				got = php_stream_read(fp, buf, MIN(8192, info->uncompressed_filesize - position));
202 				if (got > 0) {
203 					PHPWRITE(buf, got);
204 					position += got;
205 					if (position == (zend_off_t) info->uncompressed_filesize) {
206 						break;
207 					}
208 				}
209 			} while (1);
210 
211 			zend_bailout();
212 		case PHAR_MIME_PHP:
213 			if (basename) {
214 				phar_mung_server_vars(arch, entry, entry_len, basename, ru_len);
215 				efree(basename);
216 			}
217 
218 			if (entry[0] == '/') {
219 				name_len = spprintf(&name, 4096, "phar://%s%s", arch, entry);
220 			} else {
221 				name_len = spprintf(&name, 4096, "phar://%s/%s", arch, entry);
222 			}
223 
224 			file_handle.type = ZEND_HANDLE_FILENAME;
225 			file_handle.handle.fd = 0;
226 			file_handle.filename = name;
227 			file_handle.opened_path = NULL;
228 			file_handle.free_filename = 0;
229 
230 			PHAR_G(cwd) = NULL;
231 			PHAR_G(cwd_len) = 0;
232 
233 			ZVAL_NULL(&dummy);
234 			if (zend_hash_str_add(&EG(included_files), name, name_len, &dummy) != NULL) {
235 				if ((cwd = zend_memrchr(entry, '/', entry_len))) {
236 					PHAR_G(cwd_init) = 1;
237 					if (entry == cwd) {
238 						/* root directory */
239 						PHAR_G(cwd_len) = 0;
240 						PHAR_G(cwd) = NULL;
241 					} else if (entry[0] == '/') {
242 						PHAR_G(cwd_len) = (int)(cwd - (entry + 1));
243 						PHAR_G(cwd) = estrndup(entry + 1, PHAR_G(cwd_len));
244 					} else {
245 						PHAR_G(cwd_len) = (int)(cwd - entry);
246 						PHAR_G(cwd) = estrndup(entry, PHAR_G(cwd_len));
247 					}
248 				}
249 
250 				new_op_array = zend_compile_file(&file_handle, ZEND_REQUIRE);
251 
252 				if (!new_op_array) {
253 					zend_hash_str_del(&EG(included_files), name, name_len);
254 				}
255 
256 				zend_destroy_file_handle(&file_handle);
257 
258 			} else {
259 				efree(name);
260 				new_op_array = NULL;
261 			}
262 #ifdef PHP_WIN32
263 			efree(arch);
264 #endif
265 			if (new_op_array) {
266 				ZVAL_UNDEF(&result);
267 
268 				zend_try {
269 					zend_execute(new_op_array, &result);
270 					if (PHAR_G(cwd)) {
271 						efree(PHAR_G(cwd));
272 						PHAR_G(cwd) = NULL;
273 						PHAR_G(cwd_len) = 0;
274 					}
275 
276 					PHAR_G(cwd_init) = 0;
277 					efree(name);
278 					destroy_op_array(new_op_array);
279 					efree(new_op_array);
280 					zval_ptr_dtor(&result);
281 				} zend_catch {
282 					if (PHAR_G(cwd)) {
283 						efree(PHAR_G(cwd));
284 						PHAR_G(cwd) = NULL;
285 						PHAR_G(cwd_len) = 0;
286 					}
287 
288 					PHAR_G(cwd_init) = 0;
289 					efree(name);
290 				} zend_end_try();
291 
292 				zend_bailout();
293 			}
294 
295 			return PHAR_MIME_PHP;
296 	}
297 	return -1;
298 }
299 /* }}} */
300 
phar_do_403(char * entry,int entry_len)301 static void phar_do_403(char *entry, int entry_len) /* {{{ */
302 {
303 	sapi_header_line ctr = {0};
304 
305 	ctr.response_code = 403;
306 	ctr.line_len = sizeof("HTTP/1.0 403 Access Denied")-1;
307 	ctr.line = "HTTP/1.0 403 Access Denied";
308 	sapi_header_op(SAPI_HEADER_REPLACE, &ctr);
309 	sapi_send_headers();
310 	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);
311 	PHPWRITE("Access Denied</h1>\n </body>\n</html>", sizeof("Access Denied</h1>\n </body>\n</html>") - 1);
312 }
313 /* }}} */
314 
phar_do_404(phar_archive_data * phar,char * fname,int fname_len,char * f404,int f404_len,char * entry,size_t entry_len)315 static void phar_do_404(phar_archive_data *phar, char *fname, int fname_len, char *f404, int f404_len, char *entry, size_t entry_len) /* {{{ */
316 {
317 	sapi_header_line ctr = {0};
318 	phar_entry_info	*info;
319 
320 	if (phar && f404_len) {
321 		info = phar_get_entry_info(phar, f404, f404_len, NULL, 1);
322 
323 		if (info) {
324 			phar_file_action(phar, info, "text/html", PHAR_MIME_PHP, f404, f404_len, fname, NULL, NULL, 0);
325 			return;
326 		}
327 	}
328 
329 	ctr.response_code = 404;
330 	ctr.line_len = sizeof("HTTP/1.0 404 Not Found")-1;
331 	ctr.line = "HTTP/1.0 404 Not Found";
332 	sapi_header_op(SAPI_HEADER_REPLACE, &ctr);
333 	sapi_send_headers();
334 	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);
335 	PHPWRITE("Not Found</h1>\n </body>\n</html>",  sizeof("Not Found</h1>\n </body>\n</html>") - 1);
336 }
337 /* }}} */
338 
339 /* post-process REQUEST_URI and retrieve the actual request URI.  This is for
340    cases like http://localhost/blah.phar/path/to/file.php/extra/stuff
341    which calls "blah.phar" file "path/to/file.php" with PATH_INFO "/extra/stuff" */
phar_postprocess_ru_web(char * fname,int fname_len,char ** entry,int * entry_len,char ** ru,int * ru_len)342 static void phar_postprocess_ru_web(char *fname, int fname_len, char **entry, int *entry_len, char **ru, int *ru_len) /* {{{ */
343 {
344 	char *e = *entry + 1, *u = NULL, *u1 = NULL, *saveu = NULL;
345 	int e_len = *entry_len - 1, u_len = 0;
346 	phar_archive_data *pphar;
347 
348 	/* we already know we can retrieve the phar if we reach here */
349 	pphar = zend_hash_str_find_ptr(&(PHAR_G(phar_fname_map)), fname, fname_len);
350 
351 	if (!pphar && PHAR_G(manifest_cached)) {
352 		pphar = zend_hash_str_find_ptr(&cached_phars, fname, fname_len);
353 	}
354 
355 	do {
356 		if (zend_hash_str_exists(&(pphar->manifest), e, e_len)) {
357 			if (u) {
358 				u[0] = '/';
359 				*ru = estrndup(u, u_len+1);
360 				++u_len;
361 				u[0] = '\0';
362 			} else {
363 				*ru = NULL;
364 			}
365 			*ru_len = u_len;
366 			*entry_len = e_len + 1;
367 			return;
368 		}
369 
370 		if (u) {
371 			u1 = strrchr(e, '/');
372 			u[0] = '/';
373 			saveu = u;
374 			e_len += u_len + 1;
375 			u = u1;
376 			if (!u) {
377 				return;
378 			}
379 		} else {
380 			u = strrchr(e, '/');
381 			if (!u) {
382 				if (saveu) {
383 					saveu[0] = '/';
384 				}
385 				return;
386 			}
387 		}
388 
389 		u[0] = '\0';
390 		u_len = (int)strlen(u + 1);
391 		e_len -= u_len + 1;
392 
393 		if (e_len < 0) {
394 			if (saveu) {
395 				saveu[0] = '/';
396 			}
397 			return;
398 		}
399 	} while (1);
400 }
401 /* }}} */
402 
403 /* {{{ proto void Phar::running([bool retphar = true])
404  * return the name of the currently running phar archive.  If the optional parameter
405  * is set to true, return the phar:// URL to the currently running phar
406  */
PHP_METHOD(Phar,running)407 PHP_METHOD(Phar, running)
408 {
409 	char *fname, *arch, *entry;
410 	int fname_len, arch_len, entry_len;
411 	zend_bool retphar = 1;
412 
413 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &retphar) == FAILURE) {
414 		return;
415 	}
416 
417 	fname = (char*)zend_get_executed_filename();
418 	fname_len = (int)strlen(fname);
419 
420 	if (fname_len > 7 && !memcmp(fname, "phar://", 7) && SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0)) {
421 		efree(entry);
422 		if (retphar) {
423 			RETVAL_STRINGL(fname, arch_len + 7);
424 			efree(arch);
425 			return;
426 		} else {
427 			// TODO: avoid reallocation ???
428 			RETVAL_STRINGL(arch, arch_len);
429 			efree(arch);
430 			return;
431 		}
432 	}
433 
434 	RETURN_EMPTY_STRING();
435 }
436 /* }}} */
437 
438 /* {{{ proto void Phar::mount(string pharpath, string externalfile)
439  * mount an external file or path to a location within the phar.  This maps
440  * an external file or directory to a location within the phar archive, allowing
441  * reference to an external location as if it were within the phar archive.  This
442  * is useful for writable temp files like databases
443  */
PHP_METHOD(Phar,mount)444 PHP_METHOD(Phar, mount)
445 {
446 	char *fname, *arch = NULL, *entry = NULL, *path, *actual;
447 	int fname_len, arch_len, entry_len;
448 	size_t path_len, actual_len;
449 	phar_archive_data *pphar;
450 
451 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "pp", &path, &path_len, &actual, &actual_len) == FAILURE) {
452 		return;
453 	}
454 
455 	if (ZEND_SIZE_T_INT_OVFL(path_len) || ZEND_SIZE_T_INT_OVFL(actual_len)) {
456 		RETURN_FALSE;
457 	}
458 
459 	fname = (char*)zend_get_executed_filename();
460 	fname_len = (int)strlen(fname);
461 
462 #ifdef PHP_WIN32
463 	phar_unixify_path_separators(fname, fname_len);
464 #endif
465 
466 	if (fname_len > 7 && !memcmp(fname, "phar://", 7) && SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0)) {
467 		efree(entry);
468 		entry = NULL;
469 
470 		if (path_len > 7 && !memcmp(path, "phar://", 7)) {
471 			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);
472 			efree(arch);
473 			return;
474 		}
475 carry_on2:
476 		if (NULL == (pphar = zend_hash_str_find_ptr(&(PHAR_G(phar_fname_map)), arch, arch_len))) {
477 			if (PHAR_G(manifest_cached) && NULL != (pphar = zend_hash_str_find_ptr(&cached_phars, arch, arch_len))) {
478 				if (SUCCESS == phar_copy_on_write(&pphar)) {
479 					goto carry_on;
480 				}
481 			}
482 
483 			zend_throw_exception_ex(phar_ce_PharException, 0, "%s is not a phar archive, cannot mount", arch);
484 
485 			if (arch) {
486 				efree(arch);
487 			}
488 			return;
489 		}
490 carry_on:
491 		if (SUCCESS != phar_mount_entry(pphar, actual, (int)actual_len, path, (int)path_len)) {
492 			zend_throw_exception_ex(phar_ce_PharException, 0, "Mounting of %s to %s within phar %s failed", path, actual, arch);
493 			if (path && path == entry) {
494 				efree(entry);
495 			}
496 
497 			if (arch) {
498 				efree(arch);
499 			}
500 
501 			return;
502 		}
503 
504 		if (entry && path && path == entry) {
505 			efree(entry);
506 		}
507 
508 		if (arch) {
509 			efree(arch);
510 		}
511 
512 		return;
513 	} else if (PHAR_G(phar_fname_map.u.flags) && NULL != (pphar = zend_hash_str_find_ptr(&(PHAR_G(phar_fname_map)), fname, fname_len))) {
514 		goto carry_on;
515 	} else if (PHAR_G(manifest_cached) && NULL != (pphar = zend_hash_str_find_ptr(&cached_phars, fname, fname_len))) {
516 		if (SUCCESS == phar_copy_on_write(&pphar)) {
517 			goto carry_on;
518 		}
519 
520 		goto carry_on;
521 	} else if (SUCCESS == phar_split_fname(path, (int)path_len, &arch, &arch_len, &entry, &entry_len, 2, 0)) {
522 		path = entry;
523 		path_len = entry_len;
524 		goto carry_on2;
525 	}
526 
527 	zend_throw_exception_ex(phar_ce_PharException, 0, "Mounting of %s to %s failed", path, actual);
528 }
529 /* }}} */
530 
531 /* {{{ proto void Phar::webPhar([string alias, [string index, [string f404, [array mimetypes, [callback rewrites]]]]])
532  * mapPhar for web-based phars. Reads the currently executed file (a phar)
533  * and registers its manifest. When executed in the CLI or CGI command-line sapi,
534  * this works exactly like mapPhar().  When executed by a web-based sapi, this
535  * reads $_SERVER['REQUEST_URI'] (the actual original value) and parses out the
536  * intended internal file.
537  */
PHP_METHOD(Phar,webPhar)538 PHP_METHOD(Phar, webPhar)
539 {
540 	zval *mimeoverride = NULL, *rewrite = NULL;
541 	char *alias = NULL, *error, *index_php = NULL, *f404 = NULL, *ru = NULL;
542 	size_t alias_len = 0, f404_len = 0, free_pathinfo = 0;
543 	int  ru_len = 0;
544 	char *fname, *path_info, *mime_type = NULL, *entry, *pt;
545 	const char *basename;
546 	size_t fname_len, index_php_len = 0;
547 	int entry_len, code, not_cgi;
548 	phar_archive_data *phar = NULL;
549 	phar_entry_info *info = NULL;
550 	size_t sapi_mod_name_len = strlen(sapi_module.name);
551 
552 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s!s!saz", &alias, &alias_len, &index_php, &index_php_len, &f404, &f404_len, &mimeoverride, &rewrite) == FAILURE) {
553 		return;
554 	}
555 
556 	phar_request_initialize();
557 	fname = (char*)zend_get_executed_filename();
558 	fname_len = strlen(fname);
559 
560 	if (ZEND_SIZE_T_INT_OVFL(alias_len)
561 			|| ZEND_SIZE_T_INT_OVFL(f404_len) || ZEND_SIZE_T_INT_OVFL(index_php_len)) {
562 		RETURN_FALSE;
563 	}
564 
565 	if (phar_open_executed_filename(alias, (int)alias_len, &error) != SUCCESS) {
566 		if (error) {
567 			zend_throw_exception_ex(phar_ce_PharException, 0, "%s", error);
568 			efree(error);
569 		}
570 		return;
571 	}
572 
573 	/* retrieve requested file within phar */
574 	if (!(SG(request_info).request_method
575           && SG(request_info).request_uri
576           && (!strcmp(SG(request_info).request_method, "GET")
577            || !strcmp(SG(request_info).request_method, "POST")
578            || !strcmp(SG(request_info).request_method, "DELETE")
579            || !strcmp(SG(request_info).request_method, "HEAD")
580            || !strcmp(SG(request_info).request_method, "OPTIONS")
581            || !strcmp(SG(request_info).request_method, "PATCH")
582            || !strcmp(SG(request_info).request_method, "PUT")
583           )
584          )
585       ) {
586 		return;
587 	}
588 
589 #ifdef PHP_WIN32
590 	fname = estrndup(fname, fname_len);
591 	phar_unixify_path_separators(fname, fname_len);
592 #endif
593 	basename = zend_memrchr(fname, '/', fname_len);
594 
595 	if (!basename) {
596 		basename = fname;
597 	} else {
598 		++basename;
599 	}
600 
601 	if ((sapi_mod_name_len == sizeof("cgi-fcgi") - 1 && !strncmp(sapi_module.name, "cgi-fcgi", sizeof("cgi-fcgi") - 1))
602 		|| (sapi_mod_name_len == sizeof("fpm-fcgi") - 1 && !strncmp(sapi_module.name, "fpm-fcgi", sizeof("fpm-fcgi") - 1))
603 		|| (sapi_mod_name_len == sizeof("cgi") - 1 && !strncmp(sapi_module.name, "cgi", sizeof("cgi") - 1))) {
604 
605 		if (Z_TYPE(PG(http_globals)[TRACK_VARS_SERVER]) != IS_UNDEF) {
606 			HashTable *_server = Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]);
607 			zval *z_script_name, *z_path_info;
608 
609 			if (NULL == (z_script_name = zend_hash_str_find(_server, "SCRIPT_NAME", sizeof("SCRIPT_NAME")-1)) ||
610 				IS_STRING != Z_TYPE_P(z_script_name) ||
611 				!strstr(Z_STRVAL_P(z_script_name), basename)) {
612 				return;
613 			}
614 
615 			if (NULL != (z_path_info = zend_hash_str_find(_server, "PATH_INFO", sizeof("PATH_INFO")-1)) &&
616 				IS_STRING == Z_TYPE_P(z_path_info)) {
617 				entry_len = (int)Z_STRLEN_P(z_path_info);
618 				entry = estrndup(Z_STRVAL_P(z_path_info), entry_len);
619 				path_info = emalloc(Z_STRLEN_P(z_script_name) + entry_len + 1);
620 				memcpy(path_info, Z_STRVAL_P(z_script_name), Z_STRLEN_P(z_script_name));
621 				memcpy(path_info + Z_STRLEN_P(z_script_name), entry, entry_len + 1);
622 				free_pathinfo = 1;
623 			} else {
624 				entry_len = 0;
625 				entry = estrndup("", 0);
626 				path_info = Z_STRVAL_P(z_script_name);
627 			}
628 
629 			pt = estrndup(Z_STRVAL_P(z_script_name), Z_STRLEN_P(z_script_name));
630 
631 		} else {
632 			char *testit;
633 
634 			testit = sapi_getenv("SCRIPT_NAME", sizeof("SCRIPT_NAME")-1);
635 			if (!(pt = strstr(testit, basename))) {
636 				efree(testit);
637 				return;
638 			}
639 
640 			path_info = sapi_getenv("PATH_INFO", sizeof("PATH_INFO")-1);
641 
642 			if (path_info) {
643 				entry = path_info;
644 				entry_len = (int)strlen(entry);
645 				spprintf(&path_info, 0, "%s%s", testit, path_info);
646 				free_pathinfo = 1;
647 			} else {
648 				path_info = testit;
649 				free_pathinfo = 1;
650 				entry = estrndup("", 0);
651 				entry_len = 0;
652 			}
653 
654 			pt = estrndup(testit, (pt - testit) + (fname_len - (basename - fname)));
655 		}
656 		not_cgi = 0;
657 	} else {
658 		path_info = SG(request_info).request_uri;
659 
660 		if (!(pt = strstr(path_info, basename))) {
661 			/* this can happen with rewrite rules - and we have no idea what to do then, so return */
662 			return;
663 		}
664 
665 		entry_len = (int)strlen(path_info);
666 		entry_len -= (pt - path_info) + (fname_len - (basename - fname));
667 		entry = estrndup(pt + (fname_len - (basename - fname)), entry_len);
668 
669 		pt = estrndup(path_info, (pt - path_info) + (fname_len - (basename - fname)));
670 		not_cgi = 1;
671 	}
672 
673 	if (rewrite) {
674 		zend_fcall_info fci;
675 		zend_fcall_info_cache fcc;
676 		zval params, retval;
677 
678 		ZVAL_STRINGL(&params, entry, entry_len);
679 
680 		if (FAILURE == zend_fcall_info_init(rewrite, 0, &fci, &fcc, NULL, NULL)) {
681 			zend_throw_exception_ex(phar_ce_PharException, 0, "phar error: invalid rewrite callback");
682 
683 			if (free_pathinfo) {
684 				efree(path_info);
685 			}
686 			efree(pt);
687 
688 			return;
689 		}
690 
691 		fci.param_count = 1;
692 		fci.params = &params;
693 		Z_ADDREF(params);
694 		fci.retval = &retval;
695 
696 		if (FAILURE == zend_call_function(&fci, &fcc)) {
697 			if (!EG(exception)) {
698 				zend_throw_exception_ex(phar_ce_PharException, 0, "phar error: failed to call rewrite callback");
699 			}
700 
701 			if (free_pathinfo) {
702 				efree(path_info);
703 			}
704 			efree(pt);
705 
706 			return;
707 		}
708 
709 		if (Z_TYPE_P(fci.retval) == IS_UNDEF || Z_TYPE(retval) == IS_UNDEF) {
710 			if (free_pathinfo) {
711 				efree(path_info);
712 			}
713 			zend_throw_exception_ex(phar_ce_PharException, 0, "phar error: rewrite callback must return a string or false");
714 			efree(pt);
715 			return;
716 		}
717 
718 		switch (Z_TYPE(retval)) {
719 			case IS_STRING:
720 				efree(entry);
721 				if (ZEND_SIZE_T_INT_OVFL(Z_STRLEN_P(fci.retval))) {
722 					zend_throw_exception_ex(phar_ce_PharException, 0, "phar error: rewrite callback returned oversized value");
723 					return;
724 				}
725 				entry = estrndup(Z_STRVAL_P(fci.retval), Z_STRLEN_P(fci.retval));
726 				entry_len = (int)Z_STRLEN_P(fci.retval);
727 				break;
728 			case IS_TRUE:
729 			case IS_FALSE:
730 				phar_do_403(entry, entry_len);
731 
732 				if (free_pathinfo) {
733 					efree(path_info);
734 				}
735 				efree(pt);
736 
737 				zend_bailout();
738 				return;
739 			default:
740 				if (free_pathinfo) {
741 					efree(path_info);
742 				}
743 				efree(pt);
744 
745 				zend_throw_exception_ex(phar_ce_PharException, 0, "phar error: rewrite callback must return a string or false");
746 				return;
747 		}
748 	}
749 
750 	if (entry_len) {
751 		phar_postprocess_ru_web(fname, (int)fname_len, &entry, &entry_len, &ru, &ru_len);
752 	}
753 
754 	if (!entry_len || (entry_len == 1 && entry[0] == '/')) {
755 		efree(entry);
756 		/* direct request */
757 		if (index_php_len) {
758 			entry = index_php;
759 			entry_len = (int)index_php_len;
760 			if (entry[0] != '/') {
761 				spprintf(&entry, 0, "/%s", index_php);
762 				++entry_len;
763 			}
764 		} else {
765 			/* assume "index.php" is starting point */
766 			entry = estrndup("/index.php", sizeof("/index.php"));
767 			entry_len = sizeof("/index.php")-1;
768 		}
769 
770 		if (FAILURE == phar_get_archive(&phar, fname, (int)fname_len, NULL, 0, NULL) ||
771 			(info = phar_get_entry_info(phar, entry, entry_len, NULL, 0)) == NULL) {
772 			phar_do_404(phar, fname, (int)fname_len, f404, (int)f404_len, entry, entry_len);
773 
774 			if (free_pathinfo) {
775 				efree(path_info);
776 			}
777 
778 			zend_bailout();
779 		} else {
780 			char *tmp = NULL, sa = '\0';
781 			sapi_header_line ctr = {0};
782 			ctr.response_code = 301;
783 			ctr.line_len = sizeof("HTTP/1.1 301 Moved Permanently")-1;
784 			ctr.line = "HTTP/1.1 301 Moved Permanently";
785 			sapi_header_op(SAPI_HEADER_REPLACE, &ctr);
786 
787 			if (not_cgi) {
788 				tmp = strstr(path_info, basename) + fname_len;
789 				sa = *tmp;
790 				*tmp = '\0';
791 			}
792 
793 			ctr.response_code = 0;
794 
795 			if (path_info[strlen(path_info)-1] == '/') {
796 				ctr.line_len = spprintf(&(ctr.line), 4096, "Location: %s%s", path_info, entry + 1);
797 			} else {
798 				ctr.line_len = spprintf(&(ctr.line), 4096, "Location: %s%s", path_info, entry);
799 			}
800 
801 			if (not_cgi) {
802 				*tmp = sa;
803 			}
804 
805 			if (free_pathinfo) {
806 				efree(path_info);
807 			}
808 
809 			sapi_header_op(SAPI_HEADER_REPLACE, &ctr);
810 			sapi_send_headers();
811 			efree(ctr.line);
812 			zend_bailout();
813 		}
814 	}
815 
816 	if (FAILURE == phar_get_archive(&phar, fname, (int)fname_len, NULL, 0, NULL) ||
817 		(info = phar_get_entry_info(phar, entry, entry_len, NULL, 0)) == NULL) {
818 		phar_do_404(phar, fname, (int)fname_len, f404, (int)f404_len, entry, entry_len);
819 #ifdef PHP_WIN32
820 		efree(fname);
821 #endif
822 		zend_bailout();
823 	}
824 
825 	if (mimeoverride && zend_hash_num_elements(Z_ARRVAL_P(mimeoverride))) {
826 		const char *ext = zend_memrchr(entry, '.', entry_len);
827 		zval *val;
828 
829 		if (ext) {
830 			++ext;
831 
832 			if (NULL != (val = zend_hash_str_find(Z_ARRVAL_P(mimeoverride), ext, strlen(ext)))) {
833 				switch (Z_TYPE_P(val)) {
834 					case IS_LONG:
835 						if (Z_LVAL_P(val) == PHAR_MIME_PHP || Z_LVAL_P(val) == PHAR_MIME_PHPS) {
836 							mime_type = "";
837 							code = (int)Z_LVAL_P(val);
838 						} else {
839 							zend_throw_exception_ex(phar_ce_PharException, 0, "Unknown mime type specifier used, only Phar::PHP, Phar::PHPS and a mime type string are allowed");
840 							if (free_pathinfo) {
841 								efree(path_info);
842 							}
843 							efree(pt);
844 							efree(entry);
845 #ifdef PHP_WIN32
846 							efree(fname);
847 #endif
848 							RETURN_FALSE;
849 						}
850 						break;
851 					case IS_STRING:
852 						mime_type = Z_STRVAL_P(val);
853 						code = PHAR_MIME_OTHER;
854 						break;
855 					default:
856 						zend_throw_exception_ex(phar_ce_PharException, 0, "Unknown mime type specifier used (not a string or int), only Phar::PHP, Phar::PHPS and a mime type string are allowed");
857 						if (free_pathinfo) {
858 							efree(path_info);
859 						}
860 						efree(pt);
861 						efree(entry);
862 #ifdef PHP_WIN32
863 						efree(fname);
864 #endif
865 						RETURN_FALSE;
866 				}
867 			}
868 		}
869 	}
870 
871 	if (!mime_type) {
872 		code = phar_file_type(&PHAR_G(mime_types), entry, &mime_type);
873 	}
874 	phar_file_action(phar, info, mime_type, code, entry, entry_len, fname, pt, ru, ru_len);
875 }
876 /* }}} */
877 
878 /* {{{ proto void Phar::mungServer(array munglist)
879  * Defines a list of up to 4 $_SERVER variables that should be modified for execution
880  * to mask the presence of the phar archive.  This should be used in conjunction with
881  * Phar::webPhar(), and has no effect otherwise
882  * SCRIPT_NAME, PHP_SELF, REQUEST_URI and SCRIPT_FILENAME
883  */
PHP_METHOD(Phar,mungServer)884 PHP_METHOD(Phar, mungServer)
885 {
886 	zval *mungvalues, *data;
887 
888 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "a", &mungvalues) == FAILURE) {
889 		return;
890 	}
891 
892 	if (!zend_hash_num_elements(Z_ARRVAL_P(mungvalues))) {
893 		zend_throw_exception_ex(phar_ce_PharException, 0, "No values passed to Phar::mungServer(), expecting an array of any of these strings: PHP_SELF, REQUEST_URI, SCRIPT_FILENAME, SCRIPT_NAME");
894 		return;
895 	}
896 
897 	if (zend_hash_num_elements(Z_ARRVAL_P(mungvalues)) > 4) {
898 		zend_throw_exception_ex(phar_ce_PharException, 0, "Too many values passed to Phar::mungServer(), expecting an array of any of these strings: PHP_SELF, REQUEST_URI, SCRIPT_FILENAME, SCRIPT_NAME");
899 		return;
900 	}
901 
902 	phar_request_initialize();
903 
904 	ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(mungvalues), data) {
905 
906 		if (Z_TYPE_P(data) != IS_STRING) {
907 			zend_throw_exception_ex(phar_ce_PharException, 0, "Non-string value passed to Phar::mungServer(), expecting an array of any of these strings: PHP_SELF, REQUEST_URI, SCRIPT_FILENAME, SCRIPT_NAME");
908 			return;
909 		}
910 
911 		if (Z_STRLEN_P(data) == sizeof("PHP_SELF")-1 && !strncmp(Z_STRVAL_P(data), "PHP_SELF", sizeof("PHP_SELF")-1)) {
912 			PHAR_G(phar_SERVER_mung_list) |= PHAR_MUNG_PHP_SELF;
913 		}
914 
915 		if (Z_STRLEN_P(data) == sizeof("REQUEST_URI")-1) {
916 			if (!strncmp(Z_STRVAL_P(data), "REQUEST_URI", sizeof("REQUEST_URI")-1)) {
917 				PHAR_G(phar_SERVER_mung_list) |= PHAR_MUNG_REQUEST_URI;
918 			}
919 			if (!strncmp(Z_STRVAL_P(data), "SCRIPT_NAME", sizeof("SCRIPT_NAME")-1)) {
920 				PHAR_G(phar_SERVER_mung_list) |= PHAR_MUNG_SCRIPT_NAME;
921 			}
922 		}
923 
924 		if (Z_STRLEN_P(data) == sizeof("SCRIPT_FILENAME")-1 && !strncmp(Z_STRVAL_P(data), "SCRIPT_FILENAME", sizeof("SCRIPT_FILENAME")-1)) {
925 			PHAR_G(phar_SERVER_mung_list) |= PHAR_MUNG_SCRIPT_FILENAME;
926 		}
927 	} ZEND_HASH_FOREACH_END();
928 }
929 /* }}} */
930 
931 /* {{{ proto void Phar::interceptFileFuncs()
932  * instructs phar to intercept fopen, file_get_contents, opendir, and all of the stat-related functions
933  * and return stat on files within the phar for relative paths
934  *
935  * Once called, this cannot be reversed, and continue until the end of the request.
936  *
937  * This allows legacy scripts to be pharred unmodified
938  */
PHP_METHOD(Phar,interceptFileFuncs)939 PHP_METHOD(Phar, interceptFileFuncs)
940 {
941 	if (zend_parse_parameters_none() == FAILURE) {
942 		return;
943 	}
944 	phar_intercept_functions();
945 }
946 /* }}} */
947 
948 /* {{{ proto array Phar::createDefaultStub([string indexfile[, string webindexfile]])
949  * Return a stub that can be used to run a phar-based archive without the phar extension
950  * indexfile is the CLI startup filename, which defaults to "index.php", webindexfile
951  * is the web startup filename, and also defaults to "index.php"
952  */
PHP_METHOD(Phar,createDefaultStub)953 PHP_METHOD(Phar, createDefaultStub)
954 {
955 	char *index = NULL, *webindex = NULL, *error;
956 	zend_string *stub;
957 	size_t index_len = 0, webindex_len = 0;
958 
959 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|pp", &index, &index_len, &webindex, &webindex_len) == FAILURE) {
960 		return;
961 	}
962 
963 	stub = phar_create_default_stub(index, webindex, &error);
964 
965 	if (error) {
966 		zend_throw_exception_ex(phar_ce_PharException, 0, "%s", error);
967 		efree(error);
968 		return;
969 	}
970 	RETURN_NEW_STR(stub);
971 }
972 /* }}} */
973 
974 /* {{{ proto mixed Phar::mapPhar([string alias, [int dataoffset]])
975  * Reads the currently executed file (a phar) and registers its manifest */
PHP_METHOD(Phar,mapPhar)976 PHP_METHOD(Phar, mapPhar)
977 {
978 	char *alias = NULL, *error;
979 	size_t alias_len = 0;
980 	zend_long dataoffset = 0;
981 
982 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s!l", &alias, &alias_len, &dataoffset) == FAILURE) {
983 		return;
984 	}
985 
986 	if (ZEND_SIZE_T_INT_OVFL(alias_len)) {
987 		RETURN_FALSE;
988 	}
989 	phar_request_initialize();
990 
991 	RETVAL_BOOL(phar_open_executed_filename(alias, (int)alias_len, &error) == SUCCESS);
992 
993 	if (error) {
994 		zend_throw_exception_ex(phar_ce_PharException, 0, "%s", error);
995 		efree(error);
996 	}
997 } /* }}} */
998 
999 /* {{{ proto mixed Phar::loadPhar(string filename [, string alias])
1000  * Loads any phar archive with an alias */
PHP_METHOD(Phar,loadPhar)1001 PHP_METHOD(Phar, loadPhar)
1002 {
1003 	char *fname, *alias = NULL, *error;
1004 	size_t fname_len, alias_len = 0;
1005 
1006 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "p|s!", &fname, &fname_len, &alias, &alias_len) == FAILURE) {
1007 		return;
1008 	}
1009 
1010 	if (ZEND_SIZE_T_INT_OVFL(alias_len) || ZEND_SIZE_T_INT_OVFL(fname_len)) {
1011 		RETURN_FALSE;
1012 	}
1013 	phar_request_initialize();
1014 
1015 	RETVAL_BOOL(phar_open_from_filename(fname, (int)fname_len, alias, (int)alias_len, REPORT_ERRORS, NULL, &error) == SUCCESS);
1016 
1017 	if (error) {
1018 		zend_throw_exception_ex(phar_ce_PharException, 0, "%s", error);
1019 		efree(error);
1020 	}
1021 } /* }}} */
1022 
1023 /* {{{ proto string Phar::apiVersion()
1024  * Returns the api version */
PHP_METHOD(Phar,apiVersion)1025 PHP_METHOD(Phar, apiVersion)
1026 {
1027 	if (zend_parse_parameters_none() == FAILURE) {
1028 		return;
1029 	}
1030 	RETURN_STRINGL(PHP_PHAR_API_VERSION, sizeof(PHP_PHAR_API_VERSION)-1);
1031 }
1032 /* }}}*/
1033 
1034 /* {{{ proto bool Phar::canCompress([int method])
1035  * Returns whether phar extension supports compression using zlib/bzip2 */
PHP_METHOD(Phar,canCompress)1036 PHP_METHOD(Phar, canCompress)
1037 {
1038 	zend_long method = 0;
1039 
1040 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &method) == FAILURE) {
1041 		return;
1042 	}
1043 
1044 	phar_request_initialize();
1045 	switch (method) {
1046 	case PHAR_ENT_COMPRESSED_GZ:
1047 		if (PHAR_G(has_zlib)) {
1048 			RETURN_TRUE;
1049 		} else {
1050 			RETURN_FALSE;
1051 		}
1052 	case PHAR_ENT_COMPRESSED_BZ2:
1053 		if (PHAR_G(has_bz2)) {
1054 			RETURN_TRUE;
1055 		} else {
1056 			RETURN_FALSE;
1057 		}
1058 	default:
1059 		if (PHAR_G(has_zlib) || PHAR_G(has_bz2)) {
1060 			RETURN_TRUE;
1061 		} else {
1062 			RETURN_FALSE;
1063 		}
1064 	}
1065 }
1066 /* }}} */
1067 
1068 /* {{{ proto bool Phar::canWrite()
1069  * Returns whether phar extension supports writing and creating phars */
PHP_METHOD(Phar,canWrite)1070 PHP_METHOD(Phar, canWrite)
1071 {
1072 	if (zend_parse_parameters_none() == FAILURE) {
1073 		return;
1074 	}
1075 	RETURN_BOOL(!PHAR_G(readonly));
1076 }
1077 /* }}} */
1078 
1079 /* {{{ proto bool Phar::isValidPharFilename(string filename[, bool executable = true])
1080  * Returns whether the given filename is a valid phar filename */
PHP_METHOD(Phar,isValidPharFilename)1081 PHP_METHOD(Phar, isValidPharFilename)
1082 {
1083 	char *fname;
1084 	const char *ext_str;
1085 	size_t fname_len;
1086 	int ext_len, is_executable;
1087 	zend_bool executable = 1;
1088 
1089 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "p|b", &fname, &fname_len, &executable) == FAILURE) {
1090 		return;
1091 	}
1092 
1093 	if (ZEND_SIZE_T_INT_OVFL(fname_len)) {
1094 		RETURN_FALSE;
1095 	}
1096 
1097 	is_executable = executable;
1098 	RETVAL_BOOL(phar_detect_phar_fname_ext(fname, (int)fname_len, &ext_str, &ext_len, is_executable, 2, 1) == SUCCESS);
1099 }
1100 /* }}} */
1101 
1102 /**
1103  * from spl_directory
1104  */
phar_spl_foreign_dtor(spl_filesystem_object * object)1105 static void phar_spl_foreign_dtor(spl_filesystem_object *object) /* {{{ */
1106 {
1107 	phar_archive_data *phar = (phar_archive_data *) object->oth;
1108 
1109 	if (!phar->is_persistent) {
1110 		phar_archive_delref(phar);
1111 	}
1112 
1113 	object->oth = NULL;
1114 }
1115 /* }}} */
1116 
1117 /**
1118  * from spl_directory
1119  */
phar_spl_foreign_clone(spl_filesystem_object * src,spl_filesystem_object * dst)1120 static void phar_spl_foreign_clone(spl_filesystem_object *src, spl_filesystem_object *dst) /* {{{ */
1121 {
1122 	phar_archive_data *phar_data = (phar_archive_data *) dst->oth;
1123 
1124 	if (!phar_data->is_persistent) {
1125 		++(phar_data->refcount);
1126 	}
1127 }
1128 /* }}} */
1129 
1130 static spl_other_handler phar_spl_foreign_handler = {
1131 	phar_spl_foreign_dtor,
1132 	phar_spl_foreign_clone
1133 };
1134 
1135 /* {{{ proto void Phar::__construct(string fname [, int flags [, string alias]])
1136  * Construct a Phar archive object
1137  *
1138  * proto void PharData::__construct(string fname [[, int flags [, string alias]], int file format = Phar::TAR])
1139  * Construct a PharData archive object
1140  *
1141  * This function is used as the constructor for both the Phar and PharData
1142  * classes, hence the two prototypes above.
1143  */
PHP_METHOD(Phar,__construct)1144 PHP_METHOD(Phar, __construct)
1145 {
1146 	char *fname, *alias = NULL, *error, *arch = NULL, *entry = NULL, *save_fname;
1147 	size_t fname_len, alias_len = 0;
1148 	int arch_len, entry_len, is_data;
1149 	zend_long flags = SPL_FILE_DIR_SKIPDOTS|SPL_FILE_DIR_UNIXPATHS;
1150 	zend_long format = 0;
1151 	phar_archive_object *phar_obj;
1152 	phar_archive_data   *phar_data;
1153 	zval *zobj = getThis(), arg1, arg2;
1154 
1155 	phar_obj = (phar_archive_object*)((char*)Z_OBJ_P(zobj) - Z_OBJ_P(zobj)->handlers->offset);
1156 
1157 	is_data = instanceof_function(Z_OBJCE_P(zobj), phar_ce_data);
1158 
1159 	if (is_data) {
1160 		if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "p|ls!l", &fname, &fname_len, &flags, &alias, &alias_len, &format) == FAILURE) {
1161 			return;
1162 		}
1163 	} else {
1164 		if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "p|ls!", &fname, &fname_len, &flags, &alias, &alias_len) == FAILURE) {
1165 			return;
1166 		}
1167 	}
1168 
1169 	if (ZEND_SIZE_T_INT_OVFL(alias_len) || ZEND_SIZE_T_INT_OVFL(fname_len)) {
1170 		RETURN_FALSE;
1171 	}
1172 	if (phar_obj->archive) {
1173 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Cannot call constructor twice");
1174 		return;
1175 	}
1176 
1177 	save_fname = fname;
1178 	if (SUCCESS == phar_split_fname(fname, (int)fname_len, &arch, &arch_len, &entry, &entry_len, !is_data, 2)) {
1179 		/* use arch (the basename for the archive) for fname instead of fname */
1180 		/* this allows support for RecursiveDirectoryIterator of subdirectories */
1181 #ifdef PHP_WIN32
1182 		phar_unixify_path_separators(arch, arch_len);
1183 #endif
1184 		fname = arch;
1185 		fname_len = arch_len;
1186 #ifdef PHP_WIN32
1187 	} else {
1188 		arch = estrndup(fname, fname_len);
1189 		arch_len = fname_len;
1190 		fname = arch;
1191 		phar_unixify_path_separators(arch, arch_len);
1192 #endif
1193 	}
1194 
1195 	if (phar_open_or_create_filename(fname, (int)fname_len, alias, (int)alias_len, is_data, REPORT_ERRORS, &phar_data, &error) == FAILURE) {
1196 
1197 		if (fname == arch && fname != save_fname) {
1198 			efree(arch);
1199 			fname = save_fname;
1200 		}
1201 
1202 		if (entry) {
1203 			efree(entry);
1204 		}
1205 
1206 		if (error) {
1207 			zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0,
1208 				"%s", error);
1209 			efree(error);
1210 		} else {
1211 			zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0,
1212 				"Phar creation or opening failed");
1213 		}
1214 
1215 		return;
1216 	}
1217 
1218 	if (is_data && phar_data->is_tar && phar_data->is_brandnew && format == PHAR_FORMAT_ZIP) {
1219 		phar_data->is_zip = 1;
1220 		phar_data->is_tar = 0;
1221 	}
1222 
1223 	if (fname == arch) {
1224 		efree(arch);
1225 		fname = save_fname;
1226 	}
1227 
1228 	if ((is_data && !phar_data->is_data) || (!is_data && phar_data->is_data)) {
1229 		if (is_data) {
1230 			zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0,
1231 				"PharData class can only be used for non-executable tar and zip archives");
1232 		} else {
1233 			zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0,
1234 				"Phar class can only be used for executable tar and zip archives");
1235 		}
1236 		efree(entry);
1237 		return;
1238 	}
1239 
1240 	is_data = phar_data->is_data;
1241 
1242 	if (!phar_data->is_persistent) {
1243 		++(phar_data->refcount);
1244 	}
1245 
1246 	phar_obj->archive = phar_data;
1247 	phar_obj->spl.oth_handler = &phar_spl_foreign_handler;
1248 
1249 	if (entry) {
1250 		fname_len = spprintf(&fname, 0, "phar://%s%s", phar_data->fname, entry);
1251 		efree(entry);
1252 	} else {
1253 		fname_len = spprintf(&fname, 0, "phar://%s", phar_data->fname);
1254 	}
1255 
1256 	ZVAL_STRINGL(&arg1, fname, fname_len);
1257 	ZVAL_LONG(&arg2, flags);
1258 
1259 	zend_call_method_with_2_params(zobj, Z_OBJCE_P(zobj),
1260 		&spl_ce_RecursiveDirectoryIterator->constructor, "__construct", NULL, &arg1, &arg2);
1261 
1262 	zval_ptr_dtor(&arg1);
1263 
1264 	if (!phar_data->is_persistent) {
1265 		phar_obj->archive->is_data = is_data;
1266 	} else if (!EG(exception)) {
1267 		/* register this guy so we can modify if necessary */
1268 		zend_hash_str_add_ptr(&PHAR_G(phar_persist_map), (const char *) phar_obj->archive, sizeof(phar_obj->archive), phar_obj);
1269 	}
1270 
1271 	phar_obj->spl.info_class = phar_ce_entry;
1272 	efree(fname);
1273 }
1274 /* }}} */
1275 
1276 /* {{{ proto array Phar::getSupportedSignatures()
1277  * Return array of supported signature types
1278  */
PHP_METHOD(Phar,getSupportedSignatures)1279 PHP_METHOD(Phar, getSupportedSignatures)
1280 {
1281 	if (zend_parse_parameters_none() == FAILURE) {
1282 		return;
1283 	}
1284 
1285 	array_init(return_value);
1286 
1287 	add_next_index_stringl(return_value, "MD5", 3);
1288 	add_next_index_stringl(return_value, "SHA-1", 5);
1289 #ifdef PHAR_HASH_OK
1290 	add_next_index_stringl(return_value, "SHA-256", 7);
1291 	add_next_index_stringl(return_value, "SHA-512", 7);
1292 #endif
1293 #if PHAR_HAVE_OPENSSL
1294 	add_next_index_stringl(return_value, "OpenSSL", 7);
1295 #else
1296 	if (zend_hash_str_exists(&module_registry, "openssl", sizeof("openssl")-1)) {
1297 		add_next_index_stringl(return_value, "OpenSSL", 7);
1298 	}
1299 #endif
1300 }
1301 /* }}} */
1302 
1303 /* {{{ proto array Phar::getSupportedCompression()
1304  * Return array of supported comparession algorithms
1305  */
PHP_METHOD(Phar,getSupportedCompression)1306 PHP_METHOD(Phar, getSupportedCompression)
1307 {
1308 	if (zend_parse_parameters_none() == FAILURE) {
1309 		return;
1310 	}
1311 
1312 	array_init(return_value);
1313 	phar_request_initialize();
1314 
1315 	if (PHAR_G(has_zlib)) {
1316 		add_next_index_stringl(return_value, "GZ", 2);
1317 	}
1318 
1319 	if (PHAR_G(has_bz2)) {
1320 		add_next_index_stringl(return_value, "BZIP2", 5);
1321 	}
1322 }
1323 /* }}} */
1324 
1325 /* {{{ proto array Phar::unlinkArchive(string archive)
1326  * Completely remove a phar archive from memory and disk
1327  */
PHP_METHOD(Phar,unlinkArchive)1328 PHP_METHOD(Phar, unlinkArchive)
1329 {
1330 	char *fname, *error, *zname, *arch, *entry;
1331 	size_t fname_len;
1332 	int zname_len, arch_len, entry_len;
1333 	phar_archive_data *phar;
1334 
1335 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "p", &fname, &fname_len) == FAILURE) {
1336 		RETURN_FALSE;
1337 	}
1338 
1339 	if (ZEND_SIZE_T_INT_OVFL(fname_len)) {
1340 		RETURN_FALSE;
1341 	}
1342 	if (!fname_len) {
1343 		zend_throw_exception_ex(phar_ce_PharException, 0, "Unknown phar archive \"\"");
1344 		return;
1345 	}
1346 
1347 	if (FAILURE == phar_open_from_filename(fname, (int)fname_len, NULL, 0, REPORT_ERRORS, &phar, &error)) {
1348 		if (error) {
1349 			zend_throw_exception_ex(phar_ce_PharException, 0, "Unknown phar archive \"%s\": %s", fname, error);
1350 			efree(error);
1351 		} else {
1352 			zend_throw_exception_ex(phar_ce_PharException, 0, "Unknown phar archive \"%s\"", fname);
1353 		}
1354 		return;
1355 	}
1356 
1357 	zname = (char*)zend_get_executed_filename();
1358 	zname_len = (int)strlen(zname);
1359 
1360 	if (zname_len > 7 && !memcmp(zname, "phar://", 7) && SUCCESS == phar_split_fname(zname, zname_len, &arch, &arch_len, &entry, &entry_len, 2, 0)) {
1361 		if ((size_t)arch_len == fname_len && !memcmp(arch, fname, arch_len)) {
1362 			zend_throw_exception_ex(phar_ce_PharException, 0, "phar archive \"%s\" cannot be unlinked from within itself", fname);
1363 			efree(arch);
1364 			efree(entry);
1365 			return;
1366 		}
1367 		efree(arch);
1368 		efree(entry);
1369 	}
1370 
1371 	if (phar->is_persistent) {
1372 		zend_throw_exception_ex(phar_ce_PharException, 0, "phar archive \"%s\" is in phar.cache_list, cannot unlinkArchive()", fname);
1373 		return;
1374 	}
1375 
1376 	if (phar->refcount) {
1377 		zend_throw_exception_ex(phar_ce_PharException, 0, "phar archive \"%s\" has open file handles or objects.  fclose() all file handles, and unset() all objects prior to calling unlinkArchive()", fname);
1378 		return;
1379 	}
1380 
1381 	fname = estrndup(phar->fname, phar->fname_len);
1382 
1383 	/* invalidate phar cache */
1384 	PHAR_G(last_phar) = NULL;
1385 	PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
1386 
1387 	phar_archive_delref(phar);
1388 	unlink(fname);
1389 	efree(fname);
1390 	RETURN_TRUE;
1391 }
1392 /* }}} */
1393 
1394 #define PHAR_ARCHIVE_OBJECT() \
1395 	zval *zobj = getThis(); \
1396 	phar_archive_object *phar_obj = (phar_archive_object*)((char*)Z_OBJ_P(zobj) - Z_OBJ_P(zobj)->handlers->offset); \
1397 	if (!phar_obj->archive) { \
1398 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, \
1399 			"Cannot call method on an uninitialized Phar object"); \
1400 		return; \
1401 	}
1402 
1403 /* {{{ proto void Phar::__destruct()
1404  * if persistent, remove from the cache
1405  */
PHP_METHOD(Phar,__destruct)1406 PHP_METHOD(Phar, __destruct)
1407 {
1408 	zval *zobj = getThis();
1409 	phar_archive_object *phar_obj = (phar_archive_object*)((char*)Z_OBJ_P(zobj) - Z_OBJ_P(zobj)->handlers->offset);
1410 
1411 	if (phar_obj->archive && phar_obj->archive->is_persistent) {
1412 		zend_hash_str_del(&PHAR_G(phar_persist_map), (const char *) phar_obj->archive, sizeof(phar_obj->archive));
1413 	}
1414 }
1415 /* }}} */
1416 
1417 struct _phar_t {
1418 	phar_archive_object *p;
1419 	zend_class_entry *c;
1420 	char *b;
1421 	zval *ret;
1422 	php_stream *fp;
1423 	uint l;
1424 	int count;
1425 };
1426 
phar_build(zend_object_iterator * iter,void * puser)1427 static int phar_build(zend_object_iterator *iter, void *puser) /* {{{ */
1428 {
1429 	zval *value;
1430 	zend_bool close_fp = 1;
1431 	struct _phar_t *p_obj = (struct _phar_t*) puser;
1432 	uint base_len = p_obj->l, str_key_len;
1433 	phar_entry_data *data;
1434 	php_stream *fp;
1435 	php_stat_len fname_len;
1436 	size_t contents_len;
1437 	char *fname, *error = NULL, *base = p_obj->b, *save = NULL, *temp = NULL;
1438 	zend_string *opened;
1439 	char *str_key;
1440 	zend_class_entry *ce = p_obj->c;
1441 	phar_archive_object *phar_obj = p_obj->p;
1442 
1443 	value = iter->funcs->get_current_data(iter);
1444 
1445 	if (EG(exception)) {
1446 		return ZEND_HASH_APPLY_STOP;
1447 	}
1448 
1449 	if (!value) {
1450 		/* failure in get_current_data */
1451 		zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0, "Iterator %s returned no value", ZSTR_VAL(ce->name));
1452 		return ZEND_HASH_APPLY_STOP;
1453 	}
1454 
1455 	switch (Z_TYPE_P(value)) {
1456 		case IS_STRING:
1457 			break;
1458 		case IS_RESOURCE:
1459 			php_stream_from_zval_no_verify(fp, value);
1460 
1461 			if (!fp) {
1462 				zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Iterator %s returned an invalid stream handle", ZSTR_VAL(ce->name));
1463 				return ZEND_HASH_APPLY_STOP;
1464 			}
1465 
1466 			if (iter->funcs->get_current_key) {
1467 				zval key;
1468 				iter->funcs->get_current_key(iter, &key);
1469 
1470 				if (EG(exception)) {
1471 					return ZEND_HASH_APPLY_STOP;
1472 				}
1473 
1474 				if (Z_TYPE(key) != IS_STRING) {
1475 					zval_dtor(&key);
1476 					zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0, "Iterator %s returned an invalid key (must return a string)", ZSTR_VAL(ce->name));
1477 					return ZEND_HASH_APPLY_STOP;
1478 				}
1479 
1480 				if (ZEND_SIZE_T_INT_OVFL(Z_STRLEN(key))) {
1481 					zval_dtor(&key);
1482 					zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0, "Iterator %v returned an invalid key (too long)", ZSTR_VAL(ce->name));
1483 					return ZEND_HASH_APPLY_STOP;
1484 				}
1485 
1486 				str_key_len = (int)Z_STRLEN(key);
1487 				str_key = estrndup(Z_STRVAL(key), str_key_len);
1488 
1489 				save = str_key;
1490 				zval_dtor(&key);
1491 			} else {
1492 				zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0, "Iterator %s returned an invalid key (must return a string)", ZSTR_VAL(ce->name));
1493 				return ZEND_HASH_APPLY_STOP;
1494 			}
1495 
1496 			close_fp = 0;
1497 			opened = zend_string_init("[stream]", sizeof("[stream]") - 1, 0);
1498 			goto after_open_fp;
1499 		case IS_OBJECT:
1500 			if (instanceof_function(Z_OBJCE_P(value), spl_ce_SplFileInfo)) {
1501 				char *test = NULL;
1502 				zval dummy;
1503 				spl_filesystem_object *intern = (spl_filesystem_object*)((char*)Z_OBJ_P(value) - Z_OBJ_P(value)->handlers->offset);
1504 
1505 				if (!base_len) {
1506 					zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Iterator %s returns an SplFileInfo object, so base directory must be specified", ZSTR_VAL(ce->name));
1507 					return ZEND_HASH_APPLY_STOP;
1508 				}
1509 
1510 				switch (intern->type) {
1511 					case SPL_FS_DIR:
1512 						test = spl_filesystem_object_get_path(intern, NULL);
1513 						fname_len = (php_stat_len)spprintf(&fname, 0, "%s%c%s", test, DEFAULT_SLASH, intern->u.dir.entry.d_name);
1514 						php_stat(fname, fname_len, FS_IS_DIR, &dummy);
1515 
1516 						if (Z_TYPE(dummy) == IS_TRUE) {
1517 							/* ignore directories */
1518 							efree(fname);
1519 							return ZEND_HASH_APPLY_KEEP;
1520 						}
1521 
1522 						test = expand_filepath(fname, NULL);
1523 						efree(fname);
1524 
1525 						if (test) {
1526 							fname = test;
1527 							fname_len = (php_stat_len)strlen(fname);
1528 						} else {
1529 							zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0, "Could not resolve file path");
1530 							return ZEND_HASH_APPLY_STOP;
1531 						}
1532 
1533 						save = fname;
1534 						goto phar_spl_fileinfo;
1535 					case SPL_FS_INFO:
1536 					case SPL_FS_FILE:
1537 						fname = expand_filepath(intern->file_name, NULL);
1538 						if (!fname) {
1539 							zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0, "Could not resolve file path");
1540 							return ZEND_HASH_APPLY_STOP;
1541 						}
1542 
1543 						fname_len = (php_stat_len)strlen(fname);
1544 						save = fname;
1545 						goto phar_spl_fileinfo;
1546 				}
1547 			}
1548 			/* fall-through */
1549 		default:
1550 			zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0, "Iterator %s returned an invalid value (must return a string)", ZSTR_VAL(ce->name));
1551 			return ZEND_HASH_APPLY_STOP;
1552 	}
1553 
1554 	fname = Z_STRVAL_P(value);
1555 	fname_len = (php_stat_len)Z_STRLEN_P(value);
1556 
1557 phar_spl_fileinfo:
1558 	if (base_len) {
1559 		temp = expand_filepath(base, NULL);
1560 		if (!temp) {
1561 			zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0, "Could not resolve file path");
1562 			if (save) {
1563 				efree(save);
1564 			}
1565 			return ZEND_HASH_APPLY_STOP;
1566 		}
1567 
1568 		base = temp;
1569 		base_len = (int)strlen(base);
1570 
1571 		if (strstr(fname, base)) {
1572 			str_key_len = fname_len - base_len;
1573 
1574 			if (str_key_len <= 0) {
1575 				if (save) {
1576 					efree(save);
1577 					efree(temp);
1578 				}
1579 				return ZEND_HASH_APPLY_KEEP;
1580 			}
1581 
1582 			str_key = fname + base_len;
1583 
1584 			if (*str_key == '/' || *str_key == '\\') {
1585 				str_key++;
1586 				str_key_len--;
1587 			}
1588 
1589 		} else {
1590 			zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0, "Iterator %s returned a path \"%s\" that is not in the base directory \"%s\"", ZSTR_VAL(ce->name), fname, base);
1591 
1592 			if (save) {
1593 				efree(save);
1594 				efree(temp);
1595 			}
1596 
1597 			return ZEND_HASH_APPLY_STOP;
1598 		}
1599 	} else {
1600 		if (iter->funcs->get_current_key) {
1601 			zval key;
1602 			iter->funcs->get_current_key(iter, &key);
1603 
1604 			if (EG(exception)) {
1605 				return ZEND_HASH_APPLY_STOP;
1606 			}
1607 
1608 			if (Z_TYPE(key) != IS_STRING) {
1609 				zval_dtor(&key);
1610 				zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0, "Iterator %s returned an invalid key (must return a string)", ZSTR_VAL(ce->name));
1611 				return ZEND_HASH_APPLY_STOP;
1612 			}
1613 
1614 			if (ZEND_SIZE_T_INT_OVFL(Z_STRLEN(key))) {
1615 				zval_dtor(&key);
1616 				zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0, "Iterator %v returned an invalid key (too long)", ZSTR_VAL(ce->name));
1617 				return ZEND_HASH_APPLY_STOP;
1618 			}
1619 
1620 			str_key_len = (int)Z_STRLEN(key);
1621 			str_key = estrndup(Z_STRVAL(key), str_key_len);
1622 
1623 			save = str_key;
1624 			zval_dtor(&key);
1625 		} else {
1626 			zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0, "Iterator %s returned an invalid key (must return a string)", ZSTR_VAL(ce->name));
1627 			return ZEND_HASH_APPLY_STOP;
1628 		}
1629 	}
1630 
1631 	if (php_check_open_basedir(fname)) {
1632 		zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0, "Iterator %s returned a path \"%s\" that open_basedir prevents opening", ZSTR_VAL(ce->name), fname);
1633 
1634 		if (save) {
1635 			efree(save);
1636 		}
1637 
1638 		if (temp) {
1639 			efree(temp);
1640 		}
1641 
1642 		return ZEND_HASH_APPLY_STOP;
1643 	}
1644 
1645 	/* try to open source file, then create internal phar file and copy contents */
1646 	fp = php_stream_open_wrapper(fname, "rb", STREAM_MUST_SEEK|0, &opened);
1647 
1648 	if (!fp) {
1649 		zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0, "Iterator %s returned a file that could not be opened \"%s\"", ZSTR_VAL(ce->name), fname);
1650 
1651 		if (save) {
1652 			efree(save);
1653 		}
1654 
1655 		if (temp) {
1656 			efree(temp);
1657 		}
1658 
1659 		return ZEND_HASH_APPLY_STOP;
1660 	}
1661 after_open_fp:
1662 	if (str_key_len >= sizeof(".phar")-1 && !memcmp(str_key, ".phar", sizeof(".phar")-1)) {
1663 		/* silently skip any files that would be added to the magic .phar directory */
1664 		if (save) {
1665 			efree(save);
1666 		}
1667 
1668 		if (temp) {
1669 			efree(temp);
1670 		}
1671 
1672 		if (opened) {
1673 			zend_string_release(opened);
1674 		}
1675 
1676 		if (close_fp) {
1677 			php_stream_close(fp);
1678 		}
1679 
1680 		return ZEND_HASH_APPLY_KEEP;
1681 	}
1682 
1683 	if (!(data = phar_get_or_create_entry_data(phar_obj->archive->fname, phar_obj->archive->fname_len, str_key, str_key_len, "w+b", 0, &error, 1))) {
1684 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Entry %s cannot be created: %s", str_key, error);
1685 		efree(error);
1686 
1687 		if (save) {
1688 			efree(save);
1689 		}
1690 
1691 		if (opened) {
1692 			zend_string_release(opened);
1693 		}
1694 
1695 		if (temp) {
1696 			efree(temp);
1697 		}
1698 
1699 		if (close_fp) {
1700 			php_stream_close(fp);
1701 		}
1702 
1703 		return ZEND_HASH_APPLY_STOP;
1704 
1705 	} else {
1706 		if (error) {
1707 			efree(error);
1708 		}
1709 		/* convert to PHAR_UFP */
1710 		if (data->internal_file->fp_type == PHAR_MOD) {
1711 			php_stream_close(data->internal_file->fp);
1712 		}
1713 
1714 		data->internal_file->fp = NULL;
1715 		data->internal_file->fp_type = PHAR_UFP;
1716 		data->internal_file->offset_abs = data->internal_file->offset = php_stream_tell(p_obj->fp);
1717 		data->fp = NULL;
1718 		php_stream_copy_to_stream_ex(fp, p_obj->fp, PHP_STREAM_COPY_ALL, &contents_len);
1719 		data->internal_file->uncompressed_filesize = data->internal_file->compressed_filesize =
1720 			php_stream_tell(p_obj->fp) - data->internal_file->offset;
1721 	}
1722 
1723 	if (close_fp) {
1724 		php_stream_close(fp);
1725 	}
1726 
1727 	add_assoc_str(p_obj->ret, str_key, opened);
1728 
1729 	if (save) {
1730 		efree(save);
1731 	}
1732 
1733 	if (temp) {
1734 		efree(temp);
1735 	}
1736 
1737 	data->internal_file->compressed_filesize = data->internal_file->uncompressed_filesize = contents_len;
1738 	phar_entry_delref(data);
1739 
1740 	return ZEND_HASH_APPLY_KEEP;
1741 }
1742 /* }}} */
1743 
1744 /* {{{ proto array Phar::buildFromDirectory(string base_dir[, string regex])
1745  * Construct a phar archive from an existing directory, recursively.
1746  * Optional second parameter is a regular expression for filtering directory contents.
1747  *
1748  * Return value is an array mapping phar index to actual files added.
1749  */
PHP_METHOD(Phar,buildFromDirectory)1750 PHP_METHOD(Phar, buildFromDirectory)
1751 {
1752 	char *dir, *error, *regex = NULL;
1753 	size_t dir_len, regex_len = 0;
1754 	zend_bool apply_reg = 0;
1755 	zval arg, arg2, iter, iteriter, regexiter;
1756 	struct _phar_t pass;
1757 
1758 	PHAR_ARCHIVE_OBJECT();
1759 
1760 	if (PHAR_G(readonly) && !phar_obj->archive->is_data) {
1761 		zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0,
1762 			"Cannot write to archive - write operations restricted by INI setting");
1763 		return;
1764 	}
1765 
1766 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "p|s", &dir, &dir_len, &regex, &regex_len) == FAILURE) {
1767 		RETURN_FALSE;
1768 	}
1769 
1770 	if (ZEND_SIZE_T_UINT_OVFL(dir_len)) {
1771 		RETURN_FALSE;
1772 	}
1773 
1774 	if (SUCCESS != object_init_ex(&iter, spl_ce_RecursiveDirectoryIterator)) {
1775 		zval_ptr_dtor(&iter);
1776 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Unable to instantiate directory iterator for %s", phar_obj->archive->fname);
1777 		RETURN_FALSE;
1778 	}
1779 
1780 	ZVAL_STRINGL(&arg, dir, dir_len);
1781 	ZVAL_LONG(&arg2, SPL_FILE_DIR_SKIPDOTS|SPL_FILE_DIR_UNIXPATHS);
1782 
1783 	zend_call_method_with_2_params(&iter, spl_ce_RecursiveDirectoryIterator,
1784 			&spl_ce_RecursiveDirectoryIterator->constructor, "__construct", NULL, &arg, &arg2);
1785 
1786 	zval_ptr_dtor(&arg);
1787 	if (EG(exception)) {
1788 		zval_ptr_dtor(&iter);
1789 		RETURN_FALSE;
1790 	}
1791 
1792 	if (SUCCESS != object_init_ex(&iteriter, spl_ce_RecursiveIteratorIterator)) {
1793 		zval_ptr_dtor(&iter);
1794 		zval_ptr_dtor(&iteriter);
1795 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Unable to instantiate directory iterator for %s", phar_obj->archive->fname);
1796 		RETURN_FALSE;
1797 	}
1798 
1799 	zend_call_method_with_1_params(&iteriter, spl_ce_RecursiveIteratorIterator,
1800 			&spl_ce_RecursiveIteratorIterator->constructor, "__construct", NULL, &iter);
1801 
1802 	if (EG(exception)) {
1803 		zval_ptr_dtor(&iter);
1804 		zval_ptr_dtor(&iteriter);
1805 		RETURN_FALSE;
1806 	}
1807 
1808 	zval_ptr_dtor(&iter);
1809 
1810 	if (regex_len > 0) {
1811 		apply_reg = 1;
1812 
1813 		if (SUCCESS != object_init_ex(&regexiter, spl_ce_RegexIterator)) {
1814 			zval_ptr_dtor(&iteriter);
1815 			zval_dtor(&regexiter);
1816 			zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Unable to instantiate regex iterator for %s", phar_obj->archive->fname);
1817 			RETURN_FALSE;
1818 		}
1819 
1820 		ZVAL_STRINGL(&arg2, regex, regex_len);
1821 
1822 		zend_call_method_with_2_params(&regexiter, spl_ce_RegexIterator,
1823 			&spl_ce_RegexIterator->constructor, "__construct", NULL, &iteriter, &arg2);
1824 		zval_ptr_dtor(&arg2);
1825 	}
1826 
1827 	array_init(return_value);
1828 
1829 	pass.c = apply_reg ? Z_OBJCE(regexiter) : Z_OBJCE(iteriter);
1830 	pass.p = phar_obj;
1831 	pass.b = dir;
1832 	pass.l = (uint)dir_len;
1833 	pass.count = 0;
1834 	pass.ret = return_value;
1835 	pass.fp = php_stream_fopen_tmpfile();
1836 	if (pass.fp == NULL) {
1837 		zend_throw_exception_ex(phar_ce_PharException, 0, "phar \"%s\" unable to create temporary file", phar_obj->archive->fname);
1838 		return;
1839 	}
1840 
1841 	if (phar_obj->archive->is_persistent && FAILURE == phar_copy_on_write(&(phar_obj->archive))) {
1842 		zval_ptr_dtor(&iteriter);
1843 		if (apply_reg) {
1844 			zval_ptr_dtor(&regexiter);
1845 		}
1846 		php_stream_close(pass.fp);
1847 		zend_throw_exception_ex(phar_ce_PharException, 0, "phar \"%s\" is persistent, unable to copy on write", phar_obj->archive->fname);
1848 		return;
1849 	}
1850 
1851 	if (SUCCESS == spl_iterator_apply((apply_reg ? &regexiter : &iteriter), (spl_iterator_apply_func_t) phar_build, (void *) &pass)) {
1852 		zval_ptr_dtor(&iteriter);
1853 
1854 		if (apply_reg) {
1855 			zval_ptr_dtor(&regexiter);
1856 		}
1857 
1858 		phar_obj->archive->ufp = pass.fp;
1859 		phar_flush(phar_obj->archive, 0, 0, 0, &error);
1860 
1861 		if (error) {
1862 			zend_throw_exception_ex(phar_ce_PharException, 0, "%s", error);
1863 			efree(error);
1864 		}
1865 
1866 	} else {
1867 		zval_ptr_dtor(&iteriter);
1868 		if (apply_reg) {
1869 			zval_ptr_dtor(&regexiter);
1870 		}
1871 		php_stream_close(pass.fp);
1872 	}
1873 }
1874 /* }}} */
1875 
1876 /* {{{ proto array Phar::buildFromIterator(Iterator iter[, string base_directory])
1877  * Construct a phar archive from an iterator.  The iterator must return a series of strings
1878  * that are full paths to files that should be added to the phar.  The iterator key should
1879  * be the path that the file will have within the phar archive.
1880  *
1881  * If base directory is specified, then the key will be ignored, and instead the portion of
1882  * the current value minus the base directory will be used
1883  *
1884  * Returned is an array mapping phar index to actual file added
1885  */
PHP_METHOD(Phar,buildFromIterator)1886 PHP_METHOD(Phar, buildFromIterator)
1887 {
1888 	zval *obj;
1889 	char *error;
1890 	size_t base_len = 0;
1891 	char *base = NULL;
1892 	struct _phar_t pass;
1893 
1894 	PHAR_ARCHIVE_OBJECT();
1895 
1896 	if (PHAR_G(readonly) && !phar_obj->archive->is_data) {
1897 		zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0,
1898 			"Cannot write out phar archive, phar is read-only");
1899 		return;
1900 	}
1901 
1902 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|s", &obj, zend_ce_traversable, &base, &base_len) == FAILURE) {
1903 		RETURN_FALSE;
1904 	}
1905 
1906 	if (ZEND_SIZE_T_UINT_OVFL(base_len)) {
1907 		RETURN_FALSE;
1908 	}
1909 
1910 	if (phar_obj->archive->is_persistent && FAILURE == phar_copy_on_write(&(phar_obj->archive))) {
1911 		zend_throw_exception_ex(phar_ce_PharException, 0, "phar \"%s\" is persistent, unable to copy on write", phar_obj->archive->fname);
1912 		return;
1913 	}
1914 
1915 	array_init(return_value);
1916 
1917 	pass.c = Z_OBJCE_P(obj);
1918 	pass.p = phar_obj;
1919 	pass.b = base;
1920 	pass.l = (uint)base_len;
1921 	pass.ret = return_value;
1922 	pass.count = 0;
1923 	pass.fp = php_stream_fopen_tmpfile();
1924 	if (pass.fp == NULL) {
1925 		zend_throw_exception_ex(phar_ce_PharException, 0, "phar \"%s\": unable to create temporary file", phar_obj->archive->fname);
1926 		return;
1927 	}
1928 
1929 	if (SUCCESS == spl_iterator_apply(obj, (spl_iterator_apply_func_t) phar_build, (void *) &pass)) {
1930 		phar_obj->archive->ufp = pass.fp;
1931 		phar_flush(phar_obj->archive, 0, 0, 0, &error);
1932 		if (error) {
1933 			zend_throw_exception_ex(phar_ce_PharException, 0, "%s", error);
1934 			efree(error);
1935 		}
1936 	} else {
1937 		php_stream_close(pass.fp);
1938 	}
1939 }
1940 /* }}} */
1941 
1942 /* {{{ proto int Phar::count()
1943  * Returns the number of entries in the Phar archive
1944  */
PHP_METHOD(Phar,count)1945 PHP_METHOD(Phar, count)
1946 {
1947 	/* mode can be ignored, maximum depth is 1 */
1948 	zend_long mode;
1949 	PHAR_ARCHIVE_OBJECT();
1950 
1951 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &mode) == FAILURE) {
1952 		RETURN_FALSE;
1953 	}
1954 
1955 	RETURN_LONG(zend_hash_num_elements(&phar_obj->archive->manifest));
1956 }
1957 /* }}} */
1958 
1959 /* {{{ proto bool Phar::isFileFormat(int format)
1960  * Returns true if the phar archive is based on the tar/zip/phar file format depending
1961  * on whether Phar::TAR, Phar::ZIP or Phar::PHAR was passed in
1962  */
PHP_METHOD(Phar,isFileFormat)1963 PHP_METHOD(Phar, isFileFormat)
1964 {
1965 	zend_long type;
1966 	PHAR_ARCHIVE_OBJECT();
1967 
1968 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &type) == FAILURE) {
1969 		RETURN_FALSE;
1970 	}
1971 
1972 	switch (type) {
1973 		case PHAR_FORMAT_TAR:
1974 			RETURN_BOOL(phar_obj->archive->is_tar);
1975 		case PHAR_FORMAT_ZIP:
1976 			RETURN_BOOL(phar_obj->archive->is_zip);
1977 		case PHAR_FORMAT_PHAR:
1978 			RETURN_BOOL(!phar_obj->archive->is_tar && !phar_obj->archive->is_zip);
1979 		default:
1980 			zend_throw_exception_ex(phar_ce_PharException, 0, "Unknown file format specified");
1981 	}
1982 }
1983 /* }}} */
1984 
phar_copy_file_contents(phar_entry_info * entry,php_stream * fp)1985 static int phar_copy_file_contents(phar_entry_info *entry, php_stream *fp) /* {{{ */
1986 {
1987 	char *error;
1988 	zend_off_t offset;
1989 	phar_entry_info *link;
1990 
1991 	if (FAILURE == phar_open_entry_fp(entry, &error, 1)) {
1992 		if (error) {
1993 			zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0,
1994 				"Cannot convert phar archive \"%s\", unable to open entry \"%s\" contents: %s", entry->phar->fname, entry->filename, error);
1995 			efree(error);
1996 		} else {
1997 			zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0,
1998 				"Cannot convert phar archive \"%s\", unable to open entry \"%s\" contents", entry->phar->fname, entry->filename);
1999 		}
2000 		return FAILURE;
2001 	}
2002 
2003 	/* copy old contents in entirety */
2004 	phar_seek_efp(entry, 0, SEEK_SET, 0, 1);
2005 	offset = php_stream_tell(fp);
2006 	link = phar_get_link_source(entry);
2007 
2008 	if (!link) {
2009 		link = entry;
2010 	}
2011 
2012 	if (SUCCESS != php_stream_copy_to_stream_ex(phar_get_efp(link, 0), fp, link->uncompressed_filesize, NULL)) {
2013 		zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0,
2014 			"Cannot convert phar archive \"%s\", unable to copy entry \"%s\" contents", entry->phar->fname, entry->filename);
2015 		return FAILURE;
2016 	}
2017 
2018 	if (entry->fp_type == PHAR_MOD) {
2019 		/* save for potential restore on error */
2020 		entry->cfp = entry->fp;
2021 		entry->fp = NULL;
2022 	}
2023 
2024 	/* set new location of file contents */
2025 	entry->fp_type = PHAR_FP;
2026 	entry->offset = offset;
2027 	return SUCCESS;
2028 }
2029 /* }}} */
2030 
phar_rename_archive(phar_archive_data ** sphar,char * ext,zend_bool compress)2031 static zend_object *phar_rename_archive(phar_archive_data **sphar, char *ext, zend_bool compress) /* {{{ */
2032 {
2033 	const char *oldname = NULL;
2034 	phar_archive_data *phar = *sphar;
2035 	char *oldpath = NULL;
2036 	char *basename = NULL, *basepath = NULL;
2037 	char *newname = NULL, *newpath = NULL;
2038 	zval ret, arg1;
2039 	zend_class_entry *ce;
2040 	char *error = NULL;
2041 	const char *pcr_error;
2042 	int ext_len = ext ? strlen(ext) : 0;
2043 	size_t new_len, oldname_len;
2044 	phar_archive_data *pphar = NULL;
2045 	php_stream_statbuf ssb;
2046 
2047 	if (!ext) {
2048 		if (phar->is_zip) {
2049 
2050 			if (phar->is_data) {
2051 				ext = "zip";
2052 			} else {
2053 				ext = "phar.zip";
2054 			}
2055 
2056 		} else if (phar->is_tar) {
2057 
2058 			switch (phar->flags) {
2059 				case PHAR_FILE_COMPRESSED_GZ:
2060 					if (phar->is_data) {
2061 						ext = "tar.gz";
2062 					} else {
2063 						ext = "phar.tar.gz";
2064 					}
2065 					break;
2066 				case PHAR_FILE_COMPRESSED_BZ2:
2067 					if (phar->is_data) {
2068 						ext = "tar.bz2";
2069 					} else {
2070 						ext = "phar.tar.bz2";
2071 					}
2072 					break;
2073 				default:
2074 					if (phar->is_data) {
2075 						ext = "tar";
2076 					} else {
2077 						ext = "phar.tar";
2078 					}
2079 			}
2080 		} else {
2081 
2082 			switch (phar->flags) {
2083 				case PHAR_FILE_COMPRESSED_GZ:
2084 					ext = "phar.gz";
2085 					break;
2086 				case PHAR_FILE_COMPRESSED_BZ2:
2087 					ext = "phar.bz2";
2088 					break;
2089 				default:
2090 					ext = "phar";
2091 			}
2092 		}
2093 	} else if (phar_path_check(&ext, &ext_len, &pcr_error) > pcr_is_ok) {
2094 
2095 		if (phar->is_data) {
2096 			zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "data phar converted from \"%s\" has invalid extension %s", phar->fname, ext);
2097 		} else {
2098 			zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "phar converted from \"%s\" has invalid extension %s", phar->fname, ext);
2099 		}
2100 		return NULL;
2101 	}
2102 
2103 	if (ext[0] == '.') {
2104 		++ext;
2105 	}
2106 
2107 	oldpath = estrndup(phar->fname, phar->fname_len);
2108 	if ((oldname = zend_memrchr(phar->fname, '/', phar->fname_len))) {
2109 		++oldname;
2110 	} else {
2111 		oldname = phar->fname;
2112 	}
2113 	oldname_len = strlen(oldname);
2114 
2115 	basename = estrndup(oldname, oldname_len);
2116 	spprintf(&newname, 0, "%s.%s", strtok(basename, "."), ext);
2117 	efree(basename);
2118 
2119 	basepath = estrndup(oldpath, (strlen(oldpath) - oldname_len));
2120 	new_len = spprintf(&newpath, 0, "%s%s", basepath, newname);
2121 	if (ZEND_SIZE_T_INT_OVFL(new_len)) {
2122 		efree(oldpath);
2123 		efree(basepath);
2124 		efree(newpath);
2125 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "New name is too long");
2126 		return NULL;
2127 	}
2128 	phar->fname_len = (int)new_len;
2129 	phar->fname = newpath;
2130 	phar->ext = newpath + phar->fname_len - strlen(ext) - 1;
2131 	efree(basepath);
2132 	efree(newname);
2133 
2134 	if (PHAR_G(manifest_cached) && NULL != (pphar = zend_hash_str_find_ptr(&cached_phars, newpath, phar->fname_len))) {
2135 		efree(oldpath);
2136 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Unable to add newly converted phar \"%s\" to the list of phars, new phar name is in phar.cache_list", phar->fname);
2137 		return NULL;
2138 	}
2139 
2140 	if (NULL != (pphar = zend_hash_str_find_ptr(&(PHAR_G(phar_fname_map)), newpath, phar->fname_len))) {
2141 		if (pphar->fname_len == phar->fname_len && !memcmp(pphar->fname, phar->fname, phar->fname_len)) {
2142 			if (!zend_hash_num_elements(&phar->manifest)) {
2143 				pphar->is_tar = phar->is_tar;
2144 				pphar->is_zip = phar->is_zip;
2145 				pphar->is_data = phar->is_data;
2146 				pphar->flags = phar->flags;
2147 				pphar->fp = phar->fp;
2148 				phar->fp = NULL;
2149 				phar_destroy_phar_data(phar);
2150 				*sphar = NULL;
2151 				phar = pphar;
2152 				phar->refcount++;
2153 				newpath = oldpath;
2154 				goto its_ok;
2155 			}
2156 		}
2157 
2158 		efree(oldpath);
2159 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Unable to add newly converted phar \"%s\" to the list of phars, a phar with that name already exists", phar->fname);
2160 		return NULL;
2161 	}
2162 its_ok:
2163 	if (SUCCESS == php_stream_stat_path(newpath, &ssb)) {
2164 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "phar \"%s\" exists and must be unlinked prior to conversion", newpath);
2165 		efree(oldpath);
2166 		return NULL;
2167 	}
2168 	if (!phar->is_data) {
2169 		if (SUCCESS != phar_detect_phar_fname_ext(newpath, phar->fname_len, (const char **) &(phar->ext), &(phar->ext_len), 1, 1, 1)) {
2170 			efree(oldpath);
2171 			zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "phar \"%s\" has invalid extension %s", phar->fname, ext);
2172 			return NULL;
2173 		}
2174 
2175 		if (phar->alias) {
2176 			if (phar->is_temporary_alias) {
2177 				phar->alias = NULL;
2178 				phar->alias_len = 0;
2179 			} else {
2180 				phar->alias = estrndup(newpath, strlen(newpath));
2181 				phar->alias_len = (int)strlen(newpath);
2182 				phar->is_temporary_alias = 1;
2183 				zend_hash_str_update_ptr(&(PHAR_G(phar_alias_map)), newpath, phar->fname_len, phar);
2184 			}
2185 		}
2186 
2187 	} else {
2188 
2189 		if (SUCCESS != phar_detect_phar_fname_ext(newpath, phar->fname_len, (const char **) &(phar->ext), &(phar->ext_len), 0, 1, 1)) {
2190 			efree(oldpath);
2191 			zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "data phar \"%s\" has invalid extension %s", phar->fname, ext);
2192 			return NULL;
2193 		}
2194 
2195 		phar->alias = NULL;
2196 		phar->alias_len = 0;
2197 	}
2198 
2199 	if ((!pphar || phar == pphar) && NULL == zend_hash_str_update_ptr(&(PHAR_G(phar_fname_map)), newpath, phar->fname_len, phar)) {
2200 		efree(oldpath);
2201 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Unable to add newly converted phar \"%s\" to the list of phars", phar->fname);
2202 		return NULL;
2203 	}
2204 
2205 	phar_flush(phar, 0, 0, 1, &error);
2206 
2207 	if (error) {
2208 		zend_hash_str_del(&(PHAR_G(phar_fname_map)), newpath, phar->fname_len);
2209 		*sphar = NULL;
2210 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "%s", error);
2211 		efree(error);
2212 		efree(oldpath);
2213 		return NULL;
2214 	}
2215 
2216 	efree(oldpath);
2217 
2218 	if (phar->is_data) {
2219 		ce = phar_ce_data;
2220 	} else {
2221 		ce = phar_ce_archive;
2222 	}
2223 
2224 	ZVAL_NULL(&ret);
2225 	if (SUCCESS != object_init_ex(&ret, ce)) {
2226 		zval_dtor(&ret);
2227 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Unable to instantiate phar object when converting archive \"%s\"", phar->fname);
2228 		return NULL;
2229 	}
2230 
2231 	ZVAL_STRINGL(&arg1, phar->fname, phar->fname_len);
2232 
2233 	zend_call_method_with_1_params(&ret, ce, &ce->constructor, "__construct", NULL, &arg1);
2234 	zval_ptr_dtor(&arg1);
2235 	return Z_OBJ(ret);
2236 }
2237 /* }}} */
2238 
phar_convert_to_other(phar_archive_data * source,int convert,char * ext,uint32_t flags)2239 static zend_object *phar_convert_to_other(phar_archive_data *source, int convert, char *ext, uint32_t flags) /* {{{ */
2240 {
2241 	phar_archive_data *phar;
2242 	phar_entry_info *entry, newentry;
2243 	zend_object *ret;
2244 
2245 	/* invalidate phar cache */
2246 	PHAR_G(last_phar) = NULL;
2247 	PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
2248 
2249 	phar = (phar_archive_data *) ecalloc(1, sizeof(phar_archive_data));
2250 	/* set whole-archive compression and type from parameter */
2251 	phar->flags = flags;
2252 	phar->is_data = source->is_data;
2253 
2254 	switch (convert) {
2255 		case PHAR_FORMAT_TAR:
2256 			phar->is_tar = 1;
2257 			break;
2258 		case PHAR_FORMAT_ZIP:
2259 			phar->is_zip = 1;
2260 			break;
2261 		default:
2262 			phar->is_data = 0;
2263 			break;
2264 	}
2265 
2266 	zend_hash_init(&(phar->manifest), sizeof(phar_entry_info),
2267 		zend_get_hash_value, destroy_phar_manifest_entry, 0);
2268 	zend_hash_init(&phar->mounted_dirs, sizeof(char *),
2269 		zend_get_hash_value, NULL, 0);
2270 	zend_hash_init(&phar->virtual_dirs, sizeof(char *),
2271 		zend_get_hash_value, NULL, 0);
2272 
2273 	phar->fp = php_stream_fopen_tmpfile();
2274 	if (phar->fp == NULL) {
2275 		zend_throw_exception_ex(phar_ce_PharException, 0, "unable to create temporary file");
2276 		return NULL;
2277 	}
2278 	phar->fname = source->fname;
2279 	phar->fname_len = source->fname_len;
2280 	phar->is_temporary_alias = source->is_temporary_alias;
2281 	phar->alias = source->alias;
2282 
2283 	if (Z_TYPE(source->metadata) != IS_UNDEF) {
2284 		ZVAL_DUP(&phar->metadata, &source->metadata);
2285 		phar->metadata_len = 0;
2286 	}
2287 
2288 	/* first copy each file's uncompressed contents to a temporary file and set per-file flags */
2289 	ZEND_HASH_FOREACH_PTR(&source->manifest, entry) {
2290 
2291 		newentry = *entry;
2292 
2293 		if (newentry.link) {
2294 			newentry.link = estrdup(newentry.link);
2295 			goto no_copy;
2296 		}
2297 
2298 		if (newentry.tmp) {
2299 			newentry.tmp = estrdup(newentry.tmp);
2300 			goto no_copy;
2301 		}
2302 
2303 		newentry.metadata_str.s = NULL;
2304 
2305 		if (FAILURE == phar_copy_file_contents(&newentry, phar->fp)) {
2306 			zend_hash_destroy(&(phar->manifest));
2307 			php_stream_close(phar->fp);
2308 			efree(phar);
2309 			/* exception already thrown */
2310 			return NULL;
2311 		}
2312 no_copy:
2313 		newentry.filename = estrndup(newentry.filename, newentry.filename_len);
2314 
2315 		if (Z_TYPE(newentry.metadata) != IS_UNDEF) {
2316 			zval_copy_ctor(&newentry.metadata);
2317 			newentry.metadata_str.s = NULL;
2318 		}
2319 
2320 		newentry.is_zip = phar->is_zip;
2321 		newentry.is_tar = phar->is_tar;
2322 
2323 		if (newentry.is_tar) {
2324 			newentry.tar_type = (entry->is_dir ? TAR_DIR : TAR_FILE);
2325 		}
2326 
2327 		newentry.is_modified = 1;
2328 		newentry.phar = phar;
2329 		newentry.old_flags = newentry.flags & ~PHAR_ENT_COMPRESSION_MASK; /* remove compression from old_flags */
2330 		phar_set_inode(&newentry);
2331 		zend_hash_str_add_mem(&(phar->manifest), newentry.filename, newentry.filename_len, (void*)&newentry, sizeof(phar_entry_info));
2332 		phar_add_virtual_dirs(phar, newentry.filename, newentry.filename_len);
2333 	} ZEND_HASH_FOREACH_END();
2334 
2335 	if ((ret = phar_rename_archive(&phar, ext, 0))) {
2336 		return ret;
2337 	} else {
2338 		if(phar != NULL) {
2339 			zend_hash_destroy(&(phar->manifest));
2340 			zend_hash_destroy(&(phar->mounted_dirs));
2341 			zend_hash_destroy(&(phar->virtual_dirs));
2342 			if (phar->fp) {
2343 				php_stream_close(phar->fp);
2344 			}
2345 			efree(phar->fname);
2346 			efree(phar);
2347 		}
2348 		return NULL;
2349 	}
2350 }
2351 /* }}} */
2352 
2353 /* {{{ proto object Phar::convertToExecutable([int format[, int compression [, string file_ext]]])
2354  * Convert a phar.tar or phar.zip archive to the phar file format. The
2355  * optional parameter allows the user to determine the new
2356  * filename extension (default is phar).
2357  */
PHP_METHOD(Phar,convertToExecutable)2358 PHP_METHOD(Phar, convertToExecutable)
2359 {
2360 	char *ext = NULL;
2361 	int is_data;
2362 	size_t ext_len = 0;
2363 	uint32_t flags;
2364 	zend_object *ret;
2365 	/* a number that is not 0, 1 or 2 (Which is also Greg's birthday, so there) */
2366 	zend_long format = 9021976, method = 9021976;
2367 	PHAR_ARCHIVE_OBJECT();
2368 
2369 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|lls", &format, &method, &ext, &ext_len) == FAILURE) {
2370 		return;
2371 	}
2372 
2373 	if (PHAR_G(readonly)) {
2374 		zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0,
2375 			"Cannot write out executable phar archive, phar is read-only");
2376 		return;
2377 	}
2378 
2379 	switch (format) {
2380 		case 9021976:
2381 		case PHAR_FORMAT_SAME: /* null is converted to 0 */
2382 			/* by default, use the existing format */
2383 			if (phar_obj->archive->is_tar) {
2384 				format = PHAR_FORMAT_TAR;
2385 			} else if (phar_obj->archive->is_zip) {
2386 				format = PHAR_FORMAT_ZIP;
2387 			} else {
2388 				format = PHAR_FORMAT_PHAR;
2389 			}
2390 			break;
2391 		case PHAR_FORMAT_PHAR:
2392 		case PHAR_FORMAT_TAR:
2393 		case PHAR_FORMAT_ZIP:
2394 			break;
2395 		default:
2396 			zend_throw_exception_ex(spl_ce_BadMethodCallException, 0,
2397 				"Unknown file format specified, please pass one of Phar::PHAR, Phar::TAR or Phar::ZIP");
2398 			return;
2399 	}
2400 
2401 	switch (method) {
2402 		case 9021976:
2403 			flags = phar_obj->archive->flags & PHAR_FILE_COMPRESSION_MASK;
2404 			break;
2405 		case 0:
2406 			flags = PHAR_FILE_COMPRESSED_NONE;
2407 			break;
2408 		case PHAR_ENT_COMPRESSED_GZ:
2409 			if (format == PHAR_FORMAT_ZIP) {
2410 				zend_throw_exception_ex(spl_ce_BadMethodCallException, 0,
2411 					"Cannot compress entire archive with gzip, zip archives do not support whole-archive compression");
2412 				return;
2413 			}
2414 
2415 			if (!PHAR_G(has_zlib)) {
2416 				zend_throw_exception_ex(spl_ce_BadMethodCallException, 0,
2417 					"Cannot compress entire archive with gzip, enable ext/zlib in php.ini");
2418 				return;
2419 			}
2420 
2421 			flags = PHAR_FILE_COMPRESSED_GZ;
2422 			break;
2423 		case PHAR_ENT_COMPRESSED_BZ2:
2424 			if (format == PHAR_FORMAT_ZIP) {
2425 				zend_throw_exception_ex(spl_ce_BadMethodCallException, 0,
2426 					"Cannot compress entire archive with bz2, zip archives do not support whole-archive compression");
2427 				return;
2428 			}
2429 
2430 			if (!PHAR_G(has_bz2)) {
2431 				zend_throw_exception_ex(spl_ce_BadMethodCallException, 0,
2432 					"Cannot compress entire archive with bz2, enable ext/bz2 in php.ini");
2433 				return;
2434 			}
2435 
2436 			flags = PHAR_FILE_COMPRESSED_BZ2;
2437 			break;
2438 		default:
2439 			zend_throw_exception_ex(spl_ce_BadMethodCallException, 0,
2440 				"Unknown compression specified, please pass one of Phar::GZ or Phar::BZ2");
2441 			return;
2442 	}
2443 
2444 	is_data = phar_obj->archive->is_data;
2445 	phar_obj->archive->is_data = 0;
2446 	ret = phar_convert_to_other(phar_obj->archive, (int)format, ext, flags);
2447 	phar_obj->archive->is_data = is_data;
2448 
2449 	if (ret) {
2450 		ZVAL_OBJ(return_value, ret);
2451 	} else {
2452 		RETURN_NULL();
2453 	}
2454 }
2455 /* }}} */
2456 
2457 /* {{{ proto object Phar::convertToData([int format[, int compression [, string file_ext]]])
2458  * Convert an archive to a non-executable .tar or .zip.
2459  * The optional parameter allows the user to determine the new
2460  * filename extension (default is .zip or .tar).
2461  */
PHP_METHOD(Phar,convertToData)2462 PHP_METHOD(Phar, convertToData)
2463 {
2464 	char *ext = NULL;
2465 	int is_data;
2466 	size_t ext_len = 0;
2467 	uint32_t flags;
2468 	zend_object *ret;
2469 	/* a number that is not 0, 1 or 2 (Which is also Greg's birthday so there) */
2470 	zend_long format = 9021976, method = 9021976;
2471 	PHAR_ARCHIVE_OBJECT();
2472 
2473 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|lls", &format, &method, &ext, &ext_len) == FAILURE) {
2474 		return;
2475 	}
2476 
2477 	switch (format) {
2478 		case 9021976:
2479 		case PHAR_FORMAT_SAME: /* null is converted to 0 */
2480 			/* by default, use the existing format */
2481 			if (phar_obj->archive->is_tar) {
2482 				format = PHAR_FORMAT_TAR;
2483 			} else if (phar_obj->archive->is_zip) {
2484 				format = PHAR_FORMAT_ZIP;
2485 			} else {
2486 				zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0,
2487 					"Cannot write out data phar archive, use Phar::TAR or Phar::ZIP");
2488 				return;
2489 			}
2490 			break;
2491 		case PHAR_FORMAT_PHAR:
2492 			zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0,
2493 				"Cannot write out data phar archive, use Phar::TAR or Phar::ZIP");
2494 			return;
2495 		case PHAR_FORMAT_TAR:
2496 		case PHAR_FORMAT_ZIP:
2497 			break;
2498 		default:
2499 			zend_throw_exception_ex(spl_ce_BadMethodCallException, 0,
2500 				"Unknown file format specified, please pass one of Phar::TAR or Phar::ZIP");
2501 			return;
2502 	}
2503 
2504 	switch (method) {
2505 		case 9021976:
2506 			flags = phar_obj->archive->flags & PHAR_FILE_COMPRESSION_MASK;
2507 			break;
2508 		case 0:
2509 			flags = PHAR_FILE_COMPRESSED_NONE;
2510 			break;
2511 		case PHAR_ENT_COMPRESSED_GZ:
2512 			if (format == PHAR_FORMAT_ZIP) {
2513 				zend_throw_exception_ex(spl_ce_BadMethodCallException, 0,
2514 					"Cannot compress entire archive with gzip, zip archives do not support whole-archive compression");
2515 				return;
2516 			}
2517 
2518 			if (!PHAR_G(has_zlib)) {
2519 				zend_throw_exception_ex(spl_ce_BadMethodCallException, 0,
2520 					"Cannot compress entire archive with gzip, enable ext/zlib in php.ini");
2521 				return;
2522 			}
2523 
2524 			flags = PHAR_FILE_COMPRESSED_GZ;
2525 			break;
2526 		case PHAR_ENT_COMPRESSED_BZ2:
2527 			if (format == PHAR_FORMAT_ZIP) {
2528 				zend_throw_exception_ex(spl_ce_BadMethodCallException, 0,
2529 					"Cannot compress entire archive with bz2, zip archives do not support whole-archive compression");
2530 				return;
2531 			}
2532 
2533 			if (!PHAR_G(has_bz2)) {
2534 				zend_throw_exception_ex(spl_ce_BadMethodCallException, 0,
2535 					"Cannot compress entire archive with bz2, enable ext/bz2 in php.ini");
2536 				return;
2537 			}
2538 
2539 			flags = PHAR_FILE_COMPRESSED_BZ2;
2540 			break;
2541 		default:
2542 			zend_throw_exception_ex(spl_ce_BadMethodCallException, 0,
2543 				"Unknown compression specified, please pass one of Phar::GZ or Phar::BZ2");
2544 			return;
2545 	}
2546 
2547 	is_data = phar_obj->archive->is_data;
2548 	phar_obj->archive->is_data = 1;
2549 	ret = phar_convert_to_other(phar_obj->archive, (int)format, ext, flags);
2550 	phar_obj->archive->is_data = is_data;
2551 
2552 	if (ret) {
2553 		ZVAL_OBJ(return_value, ret);
2554 	} else {
2555 		RETURN_NULL();
2556 	}
2557 }
2558 /* }}} */
2559 
2560 /* {{{ proto int|false Phar::isCompressed()
2561  * Returns Phar::GZ or PHAR::BZ2 if the entire archive is compressed
2562  * (.tar.gz/tar.bz2 and so on), or FALSE otherwise.
2563  */
PHP_METHOD(Phar,isCompressed)2564 PHP_METHOD(Phar, isCompressed)
2565 {
2566 	PHAR_ARCHIVE_OBJECT();
2567 
2568 	if (zend_parse_parameters_none() == FAILURE) {
2569 		return;
2570 	}
2571 
2572 	if (phar_obj->archive->flags & PHAR_FILE_COMPRESSED_GZ) {
2573 		RETURN_LONG(PHAR_ENT_COMPRESSED_GZ);
2574 	}
2575 
2576 	if (phar_obj->archive->flags & PHAR_FILE_COMPRESSED_BZ2) {
2577 		RETURN_LONG(PHAR_ENT_COMPRESSED_BZ2);
2578 	}
2579 
2580 	RETURN_FALSE;
2581 }
2582 /* }}} */
2583 
2584 /* {{{ proto bool Phar::isWritable()
2585  * Returns true if phar.readonly=0 or phar is a PharData AND the actual file is writable.
2586  */
PHP_METHOD(Phar,isWritable)2587 PHP_METHOD(Phar, isWritable)
2588 {
2589 	php_stream_statbuf ssb;
2590 	PHAR_ARCHIVE_OBJECT();
2591 
2592 	if (zend_parse_parameters_none() == FAILURE) {
2593 		return;
2594 	}
2595 
2596 	if (!phar_obj->archive->is_writeable) {
2597 		RETURN_FALSE;
2598 	}
2599 
2600 	if (SUCCESS != php_stream_stat_path(phar_obj->archive->fname, &ssb)) {
2601 		if (phar_obj->archive->is_brandnew) {
2602 			/* assume it works if the file doesn't exist yet */
2603 			RETURN_TRUE;
2604 		}
2605 		RETURN_FALSE;
2606 	}
2607 
2608 	RETURN_BOOL((ssb.sb.st_mode & (S_IWOTH | S_IWGRP | S_IWUSR)) != 0);
2609 }
2610 /* }}} */
2611 
2612 /* {{{ proto bool Phar::delete(string entry)
2613  * Deletes a named file within the archive.
2614  */
PHP_METHOD(Phar,delete)2615 PHP_METHOD(Phar, delete)
2616 {
2617 	char *fname;
2618 	size_t fname_len;
2619 	char *error;
2620 	phar_entry_info *entry;
2621 	PHAR_ARCHIVE_OBJECT();
2622 
2623 	if (PHAR_G(readonly) && !phar_obj->archive->is_data) {
2624 		zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0,
2625 			"Cannot write out phar archive, phar is read-only");
2626 		return;
2627 	}
2628 
2629 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "p", &fname, &fname_len) == FAILURE) {
2630 		RETURN_FALSE;
2631 	}
2632 
2633 	if (phar_obj->archive->is_persistent && FAILURE == phar_copy_on_write(&(phar_obj->archive))) {
2634 		zend_throw_exception_ex(phar_ce_PharException, 0, "phar \"%s\" is persistent, unable to copy on write", phar_obj->archive->fname);
2635 		return;
2636 	}
2637 	if (zend_hash_str_exists(&phar_obj->archive->manifest, fname, (uint) fname_len)) {
2638 		if (NULL != (entry = zend_hash_str_find_ptr(&phar_obj->archive->manifest, fname, (uint) fname_len))) {
2639 			if (entry->is_deleted) {
2640 				/* entry is deleted, but has not been flushed to disk yet */
2641 				RETURN_TRUE;
2642 			} else {
2643 				entry->is_deleted = 1;
2644 				entry->is_modified = 1;
2645 				phar_obj->archive->is_modified = 1;
2646 			}
2647 		}
2648 	} else {
2649 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Entry %s does not exist and cannot be deleted", fname);
2650 		RETURN_FALSE;
2651 	}
2652 
2653 	phar_flush(phar_obj->archive, NULL, 0, 0, &error);
2654 	if (error) {
2655 		zend_throw_exception_ex(phar_ce_PharException, 0, "%s", error);
2656 		efree(error);
2657 	}
2658 
2659 	RETURN_TRUE;
2660 }
2661 /* }}} */
2662 
2663 /* {{{ proto int Phar::getAlias()
2664  * Returns the alias for the Phar or NULL.
2665  */
PHP_METHOD(Phar,getAlias)2666 PHP_METHOD(Phar, getAlias)
2667 {
2668 	PHAR_ARCHIVE_OBJECT();
2669 
2670 	if (zend_parse_parameters_none() == FAILURE) {
2671 		return;
2672 	}
2673 
2674 	if (phar_obj->archive->alias && phar_obj->archive->alias != phar_obj->archive->fname) {
2675 		RETURN_STRINGL(phar_obj->archive->alias, phar_obj->archive->alias_len);
2676 	}
2677 }
2678 /* }}} */
2679 
2680 /* {{{ proto int Phar::getPath()
2681  * Returns the real path to the phar archive on disk
2682  */
PHP_METHOD(Phar,getPath)2683 PHP_METHOD(Phar, getPath)
2684 {
2685 	PHAR_ARCHIVE_OBJECT();
2686 
2687 	if (zend_parse_parameters_none() == FAILURE) {
2688 		return;
2689 	}
2690 
2691 	RETURN_STRINGL(phar_obj->archive->fname, phar_obj->archive->fname_len);
2692 }
2693 /* }}} */
2694 
2695 /* {{{ proto bool Phar::setAlias(string alias)
2696  * Sets the alias for a Phar archive. The default value is the full path
2697  * to the archive.
2698  */
PHP_METHOD(Phar,setAlias)2699 PHP_METHOD(Phar, setAlias)
2700 {
2701 	char *alias, *error, *oldalias;
2702 	phar_archive_data *fd_ptr;
2703 	size_t alias_len, oldalias_len;
2704 	int old_temp, readd = 0;
2705 
2706 	PHAR_ARCHIVE_OBJECT();
2707 
2708 	if (PHAR_G(readonly) && !phar_obj->archive->is_data) {
2709 		zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0,
2710 			"Cannot write out phar archive, phar is read-only");
2711 		RETURN_FALSE;
2712 	}
2713 
2714 	/* invalidate phar cache */
2715 	PHAR_G(last_phar) = NULL;
2716 	PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
2717 
2718 	if (phar_obj->archive->is_data) {
2719 		if (phar_obj->archive->is_tar) {
2720 			zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0,
2721 				"A Phar alias cannot be set in a plain tar archive");
2722 		} else {
2723 			zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0,
2724 				"A Phar alias cannot be set in a plain zip archive");
2725 		}
2726 		RETURN_FALSE;
2727 	}
2728 
2729 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &alias, &alias_len) == SUCCESS) {
2730 		if (ZEND_SIZE_T_INT_OVFL(alias_len)) {
2731 			RETURN_FALSE;
2732 		}
2733 		if (alias_len == (size_t)phar_obj->archive->alias_len && memcmp(phar_obj->archive->alias, alias, alias_len) == 0) {
2734 			RETURN_TRUE;
2735 		}
2736 		if (alias_len && NULL != (fd_ptr = zend_hash_str_find_ptr(&(PHAR_G(phar_alias_map)), alias, alias_len))) {
2737 			spprintf(&error, 0, "alias \"%s\" is already used for archive \"%s\" and cannot be used for other archives", alias, fd_ptr->fname);
2738 			if (SUCCESS == phar_free_alias(fd_ptr, alias, (int)alias_len)) {
2739 				efree(error);
2740 				goto valid_alias;
2741 			}
2742 			zend_throw_exception_ex(phar_ce_PharException, 0, "%s", error);
2743 			efree(error);
2744 			RETURN_FALSE;
2745 		}
2746 		if (!phar_validate_alias(alias, (int)alias_len)) {
2747 			zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0,
2748 				"Invalid alias \"%s\" specified for phar \"%s\"", alias, phar_obj->archive->fname);
2749 			RETURN_FALSE;
2750 		}
2751 valid_alias:
2752 		if (phar_obj->archive->is_persistent && FAILURE == phar_copy_on_write(&(phar_obj->archive))) {
2753 			zend_throw_exception_ex(phar_ce_PharException, 0, "phar \"%s\" is persistent, unable to copy on write", phar_obj->archive->fname);
2754 			return;
2755 		}
2756 		if (phar_obj->archive->alias_len && NULL != (fd_ptr = zend_hash_str_find_ptr(&(PHAR_G(phar_alias_map)), phar_obj->archive->alias, phar_obj->archive->alias_len))) {
2757 			zend_hash_str_del(&(PHAR_G(phar_alias_map)), phar_obj->archive->alias, phar_obj->archive->alias_len);
2758 			readd = 1;
2759 		}
2760 
2761 		oldalias = phar_obj->archive->alias;
2762 		oldalias_len = phar_obj->archive->alias_len;
2763 		old_temp = phar_obj->archive->is_temporary_alias;
2764 
2765 		if (alias_len) {
2766 			phar_obj->archive->alias = estrndup(alias, alias_len);
2767 		} else {
2768 			phar_obj->archive->alias = NULL;
2769 		}
2770 
2771 		phar_obj->archive->alias_len = (int)alias_len;
2772 		phar_obj->archive->is_temporary_alias = 0;
2773 		phar_flush(phar_obj->archive, NULL, 0, 0, &error);
2774 
2775 		if (error) {
2776 			phar_obj->archive->alias = oldalias;
2777 			phar_obj->archive->alias_len = (int)oldalias_len;
2778 			phar_obj->archive->is_temporary_alias = old_temp;
2779 			zend_throw_exception_ex(phar_ce_PharException, 0, "%s", error);
2780 			if (readd) {
2781 				zend_hash_str_add_ptr(&(PHAR_G(phar_alias_map)), oldalias, oldalias_len, phar_obj->archive);
2782 			}
2783 			efree(error);
2784 			RETURN_FALSE;
2785 		}
2786 
2787 		zend_hash_str_add_ptr(&(PHAR_G(phar_alias_map)), alias, alias_len, phar_obj->archive);
2788 
2789 		if (oldalias) {
2790 			efree(oldalias);
2791 		}
2792 
2793 		RETURN_TRUE;
2794 	}
2795 
2796 	RETURN_FALSE;
2797 }
2798 /* }}} */
2799 
2800 /* {{{ proto string Phar::getVersion()
2801  * Return version info of Phar archive
2802  */
PHP_METHOD(Phar,getVersion)2803 PHP_METHOD(Phar, getVersion)
2804 {
2805 	PHAR_ARCHIVE_OBJECT();
2806 
2807 	if (zend_parse_parameters_none() == FAILURE) {
2808 		return;
2809 	}
2810 
2811 	RETURN_STRING(phar_obj->archive->version);
2812 }
2813 /* }}} */
2814 
2815 /* {{{ proto void Phar::startBuffering()
2816  * Do not flush a writeable phar (save its contents) until explicitly requested
2817  */
PHP_METHOD(Phar,startBuffering)2818 PHP_METHOD(Phar, startBuffering)
2819 {
2820 	PHAR_ARCHIVE_OBJECT();
2821 
2822 	if (zend_parse_parameters_none() == FAILURE) {
2823 		return;
2824 	}
2825 
2826 	phar_obj->archive->donotflush = 1;
2827 }
2828 /* }}} */
2829 
2830 /* {{{ proto bool Phar::isBuffering()
2831  * Returns whether write operations are flushing to disk immediately.
2832  */
PHP_METHOD(Phar,isBuffering)2833 PHP_METHOD(Phar, isBuffering)
2834 {
2835 	PHAR_ARCHIVE_OBJECT();
2836 
2837 	if (zend_parse_parameters_none() == FAILURE) {
2838 		return;
2839 	}
2840 
2841 	RETURN_BOOL(phar_obj->archive->donotflush);
2842 }
2843 /* }}} */
2844 
2845 /* {{{ proto bool Phar::stopBuffering()
2846  * Saves the contents of a modified archive to disk.
2847  */
PHP_METHOD(Phar,stopBuffering)2848 PHP_METHOD(Phar, stopBuffering)
2849 {
2850 	char *error;
2851 
2852 	PHAR_ARCHIVE_OBJECT();
2853 
2854 	if (zend_parse_parameters_none() == FAILURE) {
2855 		return;
2856 	}
2857 
2858 	if (PHAR_G(readonly) && !phar_obj->archive->is_data) {
2859 		zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0,
2860 			"Cannot write out phar archive, phar is read-only");
2861 		return;
2862 	}
2863 
2864 	phar_obj->archive->donotflush = 0;
2865 	phar_flush(phar_obj->archive, 0, 0, 0, &error);
2866 
2867 	if (error) {
2868 		zend_throw_exception_ex(phar_ce_PharException, 0, "%s", error);
2869 		efree(error);
2870 	}
2871 }
2872 /* }}} */
2873 
2874 /* {{{ proto bool Phar::setStub(string|stream stub [, int len])
2875  * Change the stub in a phar, phar.tar or phar.zip archive to something other
2876  * than the default. The stub *must* end with a call to __HALT_COMPILER().
2877  */
PHP_METHOD(Phar,setStub)2878 PHP_METHOD(Phar, setStub)
2879 {
2880 	zval *zstub;
2881 	char *stub, *error;
2882 	size_t stub_len;
2883 	zend_long len = -1;
2884 	php_stream *stream;
2885 	PHAR_ARCHIVE_OBJECT();
2886 
2887 	if (PHAR_G(readonly) && !phar_obj->archive->is_data) {
2888 		zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0,
2889 			"Cannot change stub, phar is read-only");
2890 		return;
2891 	}
2892 
2893 	if (phar_obj->archive->is_data) {
2894 		if (phar_obj->archive->is_tar) {
2895 			zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0,
2896 				"A Phar stub cannot be set in a plain tar archive");
2897 		} else {
2898 			zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0,
2899 				"A Phar stub cannot be set in a plain zip archive");
2900 		}
2901 		return;
2902 	}
2903 
2904 	if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "r|l", &zstub, &len) == SUCCESS) {
2905 		if ((php_stream_from_zval_no_verify(stream, zstub)) != NULL) {
2906 			if (len > 0) {
2907 				len = -len;
2908 			} else {
2909 				len = -1;
2910 			}
2911 			if (phar_obj->archive->is_persistent && FAILURE == phar_copy_on_write(&(phar_obj->archive))) {
2912 				zend_throw_exception_ex(phar_ce_PharException, 0, "phar \"%s\" is persistent, unable to copy on write", phar_obj->archive->fname);
2913 				return;
2914 			}
2915 			phar_flush(phar_obj->archive, (char *) zstub, len, 0, &error);
2916 			if (error) {
2917 				zend_throw_exception_ex(phar_ce_PharException, 0, "%s", error);
2918 				efree(error);
2919 			}
2920 			RETURN_TRUE;
2921 		} else {
2922 			zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0,
2923 				"Cannot change stub, unable to read from input stream");
2924 		}
2925 	} else if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &stub, &stub_len) == SUCCESS) {
2926 		if (phar_obj->archive->is_persistent && FAILURE == phar_copy_on_write(&(phar_obj->archive))) {
2927 			zend_throw_exception_ex(phar_ce_PharException, 0, "phar \"%s\" is persistent, unable to copy on write", phar_obj->archive->fname);
2928 			return;
2929 		}
2930 		phar_flush(phar_obj->archive, stub, stub_len, 0, &error);
2931 
2932 		if (error) {
2933 			zend_throw_exception_ex(phar_ce_PharException, 0, "%s", error);
2934 			efree(error);
2935 		}
2936 
2937 		RETURN_TRUE;
2938 	}
2939 
2940 	RETURN_FALSE;
2941 }
2942 /* }}} */
2943 
2944 /* {{{ proto bool Phar::setDefaultStub([string index[, string webindex]])
2945  * In a pure phar archive, sets a stub that can be used to run the archive
2946  * regardless of whether the phar extension is available. The first parameter
2947  * is the CLI startup filename, which defaults to "index.php". The second
2948  * parameter is the web startup filename and also defaults to "index.php"
2949  * (falling back to CLI behaviour).
2950  * Both parameters are optional.
2951  * In a phar.zip or phar.tar archive, the default stub is used only to
2952  * identify the archive to the extension as a Phar object. This allows the
2953  * extension to treat phar.zip and phar.tar types as honorary phars. Since
2954  * files cannot be loaded via this kind of stub, no parameters are accepted
2955  * when the Phar object is zip- or tar-based.
2956  */
PHP_METHOD(Phar,setDefaultStub)2957 PHP_METHOD(Phar, setDefaultStub)
2958 {
2959 	char *index = NULL, *webindex = NULL, *error = NULL;
2960 	zend_string *stub = NULL;
2961 	size_t index_len = 0, webindex_len = 0;
2962 	int created_stub = 0;
2963 	PHAR_ARCHIVE_OBJECT();
2964 
2965 	if (phar_obj->archive->is_data) {
2966 		if (phar_obj->archive->is_tar) {
2967 			zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0,
2968 				"A Phar stub cannot be set in a plain tar archive");
2969 		} else {
2970 			zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0,
2971 				"A Phar stub cannot be set in a plain zip archive");
2972 		}
2973 		return;
2974 	}
2975 
2976 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s!s", &index, &index_len, &webindex, &webindex_len) == FAILURE) {
2977 		RETURN_FALSE;
2978 	}
2979 
2980 	if (ZEND_NUM_ARGS() > 0 && (phar_obj->archive->is_tar || phar_obj->archive->is_zip)) {
2981 		php_error_docref(NULL, E_WARNING, "method accepts no arguments for a tar- or zip-based phar stub, %d given", ZEND_NUM_ARGS());
2982 		RETURN_FALSE;
2983 	}
2984 
2985 	if (PHAR_G(readonly)) {
2986 		zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0,
2987 			"Cannot change stub: phar.readonly=1");
2988 		RETURN_FALSE;
2989 	}
2990 
2991 	if (!phar_obj->archive->is_tar && !phar_obj->archive->is_zip) {
2992 		stub = phar_create_default_stub(index, webindex, &error);
2993 
2994 		if (error) {
2995 			zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0, "%s", error);
2996 			efree(error);
2997 			if (stub) {
2998 				zend_string_free(stub);
2999 			}
3000 			RETURN_FALSE;
3001 		}
3002 
3003 		created_stub = 1;
3004 	}
3005 
3006 	if (phar_obj->archive->is_persistent && FAILURE == phar_copy_on_write(&(phar_obj->archive))) {
3007 		zend_throw_exception_ex(phar_ce_PharException, 0, "phar \"%s\" is persistent, unable to copy on write", phar_obj->archive->fname);
3008 		return;
3009 	}
3010 	phar_flush(phar_obj->archive, stub ? ZSTR_VAL(stub) : 0, stub ? ZSTR_LEN(stub) : 0, 1, &error);
3011 
3012 	if (created_stub) {
3013 		zend_string_free(stub);
3014 	}
3015 
3016 	if (error) {
3017 		zend_throw_exception_ex(phar_ce_PharException, 0, "%s", error);
3018 		efree(error);
3019 		RETURN_FALSE;
3020 	}
3021 
3022 	RETURN_TRUE;
3023 }
3024 /* }}} */
3025 
3026 /* {{{ proto array Phar::setSignatureAlgorithm(int sigtype[, string privatekey])
3027  * Sets the signature algorithm for a phar and applies it. The signature
3028  * algorithm must be one of Phar::MD5, Phar::SHA1, Phar::SHA256,
3029  * Phar::SHA512, or Phar::OPENSSL. Note that zip- based phar archives
3030  * cannot support signatures.
3031  */
PHP_METHOD(Phar,setSignatureAlgorithm)3032 PHP_METHOD(Phar, setSignatureAlgorithm)
3033 {
3034 	zend_long algo;
3035 	char *error, *key = NULL;
3036 	size_t key_len = 0;
3037 
3038 	PHAR_ARCHIVE_OBJECT();
3039 
3040 	if (PHAR_G(readonly) && !phar_obj->archive->is_data) {
3041 		zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0,
3042 			"Cannot set signature algorithm, phar is read-only");
3043 		return;
3044 	}
3045 
3046 	if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "l|s", &algo, &key, &key_len) != SUCCESS) {
3047 		return;
3048 	}
3049 	if (ZEND_SIZE_T_INT_OVFL(key_len)) {
3050 		zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0,
3051 					"Cannot set signature algorithm, key too long");
3052 		return;
3053 	}
3054 
3055 	switch (algo) {
3056 		case PHAR_SIG_SHA256:
3057 		case PHAR_SIG_SHA512:
3058 #ifndef PHAR_HASH_OK
3059 			zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0,
3060 				"SHA-256 and SHA-512 signatures are only supported if the hash extension is enabled and built non-shared");
3061 			return;
3062 #endif
3063 		case PHAR_SIG_MD5:
3064 		case PHAR_SIG_SHA1:
3065 		case PHAR_SIG_OPENSSL:
3066 			if (phar_obj->archive->is_persistent && FAILURE == phar_copy_on_write(&(phar_obj->archive))) {
3067 				zend_throw_exception_ex(phar_ce_PharException, 0, "phar \"%s\" is persistent, unable to copy on write", phar_obj->archive->fname);
3068 				return;
3069 			}
3070 			phar_obj->archive->sig_flags = (php_uint32)algo;
3071 			phar_obj->archive->is_modified = 1;
3072 			PHAR_G(openssl_privatekey) = key;
3073 			PHAR_G(openssl_privatekey_len) = (int)key_len;
3074 
3075 			phar_flush(phar_obj->archive, 0, 0, 0, &error);
3076 			if (error) {
3077 				zend_throw_exception_ex(phar_ce_PharException, 0, "%s", error);
3078 				efree(error);
3079 			}
3080 			break;
3081 		default:
3082 			zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0,
3083 				"Unknown signature algorithm specified");
3084 	}
3085 }
3086 /* }}} */
3087 
3088 /* {{{ proto array|false Phar::getSignature()
3089  * Returns a hash signature, or FALSE if the archive is unsigned.
3090  */
PHP_METHOD(Phar,getSignature)3091 PHP_METHOD(Phar, getSignature)
3092 {
3093 	PHAR_ARCHIVE_OBJECT();
3094 
3095 	if (zend_parse_parameters_none() == FAILURE) {
3096 		return;
3097 	}
3098 
3099 	if (phar_obj->archive->signature) {
3100 		zend_string *unknown;
3101 
3102 		array_init(return_value);
3103 		add_assoc_stringl(return_value, "hash", phar_obj->archive->signature, phar_obj->archive->sig_len);
3104 		switch(phar_obj->archive->sig_flags) {
3105 			case PHAR_SIG_MD5:
3106 				add_assoc_stringl(return_value, "hash_type", "MD5", 3);
3107 				break;
3108 			case PHAR_SIG_SHA1:
3109 				add_assoc_stringl(return_value, "hash_type", "SHA-1", 5);
3110 				break;
3111 			case PHAR_SIG_SHA256:
3112 				add_assoc_stringl(return_value, "hash_type", "SHA-256", 7);
3113 				break;
3114 			case PHAR_SIG_SHA512:
3115 				add_assoc_stringl(return_value, "hash_type", "SHA-512", 7);
3116 				break;
3117 			case PHAR_SIG_OPENSSL:
3118 				add_assoc_stringl(return_value, "hash_type", "OpenSSL", 7);
3119 				break;
3120 			default:
3121 				unknown = strpprintf(0, "Unknown (%u)", phar_obj->archive->sig_flags);
3122 				add_assoc_str(return_value, "hash_type", unknown);
3123 				break;
3124 		}
3125 	} else {
3126 		RETURN_FALSE;
3127 	}
3128 }
3129 /* }}} */
3130 
3131 /* {{{ proto bool Phar::getModified()
3132  * Return whether phar was modified
3133  */
PHP_METHOD(Phar,getModified)3134 PHP_METHOD(Phar, getModified)
3135 {
3136 	PHAR_ARCHIVE_OBJECT();
3137 
3138 	if (zend_parse_parameters_none() == FAILURE) {
3139 		return;
3140 	}
3141 
3142 	RETURN_BOOL(phar_obj->archive->is_modified);
3143 }
3144 /* }}} */
3145 
phar_set_compression(zval * zv,void * argument)3146 static int phar_set_compression(zval *zv, void *argument) /* {{{ */
3147 {
3148 	phar_entry_info *entry = (phar_entry_info *)Z_PTR_P(zv);
3149 	uint32_t compress = *(uint32_t *)argument;
3150 
3151 	if (entry->is_deleted) {
3152 		return ZEND_HASH_APPLY_KEEP;
3153 	}
3154 
3155 	entry->old_flags = entry->flags;
3156 	entry->flags &= ~PHAR_ENT_COMPRESSION_MASK;
3157 	entry->flags |= compress;
3158 	entry->is_modified = 1;
3159 	return ZEND_HASH_APPLY_KEEP;
3160 }
3161 /* }}} */
3162 
phar_test_compression(zval * zv,void * argument)3163 static int phar_test_compression(zval *zv, void *argument) /* {{{ */
3164 {
3165 	phar_entry_info *entry = (phar_entry_info *)Z_PTR_P(zv);
3166 
3167 	if (entry->is_deleted) {
3168 		return ZEND_HASH_APPLY_KEEP;
3169 	}
3170 
3171 	if (!PHAR_G(has_bz2)) {
3172 		if (entry->flags & PHAR_ENT_COMPRESSED_BZ2) {
3173 			*(int *) argument = 0;
3174 		}
3175 	}
3176 
3177 	if (!PHAR_G(has_zlib)) {
3178 		if (entry->flags & PHAR_ENT_COMPRESSED_GZ) {
3179 			*(int *) argument = 0;
3180 		}
3181 	}
3182 
3183 	return ZEND_HASH_APPLY_KEEP;
3184 }
3185 /* }}} */
3186 
pharobj_set_compression(HashTable * manifest,uint32_t compress)3187 static void pharobj_set_compression(HashTable *manifest, uint32_t compress) /* {{{ */
3188 {
3189 	zend_hash_apply_with_argument(manifest, phar_set_compression, &compress);
3190 }
3191 /* }}} */
3192 
pharobj_cancompress(HashTable * manifest)3193 static int pharobj_cancompress(HashTable *manifest) /* {{{ */
3194 {
3195 	int test;
3196 
3197 	test = 1;
3198 	zend_hash_apply_with_argument(manifest, phar_test_compression, &test);
3199 	return test;
3200 }
3201 /* }}} */
3202 
3203 /* {{{ proto object Phar::compress(int method[, string extension])
3204  * Compress a .tar, or .phar.tar with whole-file compression
3205  * The parameter can be one of Phar::GZ or Phar::BZ2 to specify
3206  * the kind of compression desired
3207  */
PHP_METHOD(Phar,compress)3208 PHP_METHOD(Phar, compress)
3209 {
3210 	zend_long method;
3211 	char *ext = NULL;
3212 	size_t ext_len = 0;
3213 	uint32_t flags;
3214 	zend_object *ret;
3215 	PHAR_ARCHIVE_OBJECT();
3216 
3217 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|s", &method, &ext, &ext_len) == FAILURE) {
3218 		return;
3219 	}
3220 
3221 	if (PHAR_G(readonly) && !phar_obj->archive->is_data) {
3222 		zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0,
3223 			"Cannot compress phar archive, phar is read-only");
3224 		return;
3225 	}
3226 
3227 	if (phar_obj->archive->is_zip) {
3228 		zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0,
3229 			"Cannot compress zip-based archives with whole-archive compression");
3230 		return;
3231 	}
3232 
3233 	switch (method) {
3234 		case 0:
3235 			flags = PHAR_FILE_COMPRESSED_NONE;
3236 			break;
3237 		case PHAR_ENT_COMPRESSED_GZ:
3238 			if (!PHAR_G(has_zlib)) {
3239 				zend_throw_exception_ex(spl_ce_BadMethodCallException, 0,
3240 					"Cannot compress entire archive with gzip, enable ext/zlib in php.ini");
3241 				return;
3242 			}
3243 			flags = PHAR_FILE_COMPRESSED_GZ;
3244 			break;
3245 
3246 		case PHAR_ENT_COMPRESSED_BZ2:
3247 			if (!PHAR_G(has_bz2)) {
3248 				zend_throw_exception_ex(spl_ce_BadMethodCallException, 0,
3249 					"Cannot compress entire archive with bz2, enable ext/bz2 in php.ini");
3250 				return;
3251 			}
3252 			flags = PHAR_FILE_COMPRESSED_BZ2;
3253 			break;
3254 		default:
3255 			zend_throw_exception_ex(spl_ce_BadMethodCallException, 0,
3256 				"Unknown compression specified, please pass one of Phar::GZ or Phar::BZ2");
3257 			return;
3258 	}
3259 
3260 	if (phar_obj->archive->is_tar) {
3261 		ret = phar_convert_to_other(phar_obj->archive, PHAR_FORMAT_TAR, ext, flags);
3262 	} else {
3263 		ret = phar_convert_to_other(phar_obj->archive, PHAR_FORMAT_PHAR, ext, flags);
3264 	}
3265 
3266 	if (ret) {
3267 		ZVAL_OBJ(return_value, ret);
3268 	} else {
3269 		RETURN_NULL();
3270 	}
3271 }
3272 /* }}} */
3273 
3274 /* {{{ proto object Phar::decompress([string extension])
3275  * Decompress a .tar, or .phar.tar with whole-file compression
3276  */
PHP_METHOD(Phar,decompress)3277 PHP_METHOD(Phar, decompress)
3278 {
3279 	char *ext = NULL;
3280 	size_t ext_len = 0;
3281 	zend_object *ret;
3282 	PHAR_ARCHIVE_OBJECT();
3283 
3284 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s", &ext, &ext_len) == FAILURE) {
3285 		return;
3286 	}
3287 
3288 	if (PHAR_G(readonly) && !phar_obj->archive->is_data) {
3289 		zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0,
3290 			"Cannot decompress phar archive, phar is read-only");
3291 		return;
3292 	}
3293 
3294 	if (phar_obj->archive->is_zip) {
3295 		zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0,
3296 			"Cannot decompress zip-based archives with whole-archive compression");
3297 		return;
3298 	}
3299 
3300 	if (phar_obj->archive->is_tar) {
3301 		ret = phar_convert_to_other(phar_obj->archive, PHAR_FORMAT_TAR, ext, PHAR_FILE_COMPRESSED_NONE);
3302 	} else {
3303 		ret = phar_convert_to_other(phar_obj->archive, PHAR_FORMAT_PHAR, ext, PHAR_FILE_COMPRESSED_NONE);
3304 	}
3305 
3306 	if (ret) {
3307 		ZVAL_OBJ(return_value, ret);
3308 	} else {
3309 		RETURN_NULL();
3310 	}
3311 }
3312 /* }}} */
3313 
3314 /* {{{ proto object Phar::compressFiles(int method)
3315  * Compress all files within a phar or zip archive using the specified compression
3316  * The parameter can be one of Phar::GZ or Phar::BZ2 to specify
3317  * the kind of compression desired
3318  */
PHP_METHOD(Phar,compressFiles)3319 PHP_METHOD(Phar, compressFiles)
3320 {
3321 	char *error;
3322 	uint32_t flags;
3323 	zend_long method;
3324 	PHAR_ARCHIVE_OBJECT();
3325 
3326 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &method) == FAILURE) {
3327 		return;
3328 	}
3329 
3330 	if (PHAR_G(readonly) && !phar_obj->archive->is_data) {
3331 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0,
3332 			"Phar is readonly, cannot change compression");
3333 		return;
3334 	}
3335 
3336 	switch (method) {
3337 		case PHAR_ENT_COMPRESSED_GZ:
3338 			if (!PHAR_G(has_zlib)) {
3339 				zend_throw_exception_ex(spl_ce_BadMethodCallException, 0,
3340 					"Cannot compress files within archive with gzip, enable ext/zlib in php.ini");
3341 				return;
3342 			}
3343 			flags = PHAR_ENT_COMPRESSED_GZ;
3344 			break;
3345 
3346 		case PHAR_ENT_COMPRESSED_BZ2:
3347 			if (!PHAR_G(has_bz2)) {
3348 				zend_throw_exception_ex(spl_ce_BadMethodCallException, 0,
3349 					"Cannot compress files within archive with bz2, enable ext/bz2 in php.ini");
3350 				return;
3351 			}
3352 			flags = PHAR_ENT_COMPRESSED_BZ2;
3353 			break;
3354 		default:
3355 			zend_throw_exception_ex(spl_ce_BadMethodCallException, 0,
3356 				"Unknown compression specified, please pass one of Phar::GZ or Phar::BZ2");
3357 			return;
3358 	}
3359 
3360 	if (phar_obj->archive->is_tar) {
3361 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0,
3362 			"Cannot compress with Gzip compression, tar archives cannot compress individual files, use compress() to compress the whole archive");
3363 		return;
3364 	}
3365 
3366 	if (!pharobj_cancompress(&phar_obj->archive->manifest)) {
3367 		if (flags == PHAR_FILE_COMPRESSED_GZ) {
3368 			zend_throw_exception_ex(spl_ce_BadMethodCallException, 0,
3369 				"Cannot compress all files as Gzip, some are compressed as bzip2 and cannot be decompressed");
3370 		} else {
3371 			zend_throw_exception_ex(spl_ce_BadMethodCallException, 0,
3372 				"Cannot compress all files as Bzip2, some are compressed as gzip and cannot be decompressed");
3373 		}
3374 		return;
3375 	}
3376 
3377 	if (phar_obj->archive->is_persistent && FAILURE == phar_copy_on_write(&(phar_obj->archive))) {
3378 		zend_throw_exception_ex(phar_ce_PharException, 0, "phar \"%s\" is persistent, unable to copy on write", phar_obj->archive->fname);
3379 		return;
3380 	}
3381 	pharobj_set_compression(&phar_obj->archive->manifest, flags);
3382 	phar_obj->archive->is_modified = 1;
3383 	phar_flush(phar_obj->archive, 0, 0, 0, &error);
3384 
3385 	if (error) {
3386 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "%s", error);
3387 		efree(error);
3388 	}
3389 }
3390 /* }}} */
3391 
3392 /* {{{ proto bool Phar::decompressFiles()
3393  * decompress every file
3394  */
PHP_METHOD(Phar,decompressFiles)3395 PHP_METHOD(Phar, decompressFiles)
3396 {
3397 	char *error;
3398 	PHAR_ARCHIVE_OBJECT();
3399 
3400 	if (zend_parse_parameters_none() == FAILURE) {
3401 		return;
3402 	}
3403 
3404 	if (PHAR_G(readonly) && !phar_obj->archive->is_data) {
3405 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0,
3406 			"Phar is readonly, cannot change compression");
3407 		return;
3408 	}
3409 
3410 	if (!pharobj_cancompress(&phar_obj->archive->manifest)) {
3411 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0,
3412 			"Cannot decompress all files, some are compressed as bzip2 or gzip and cannot be decompressed");
3413 		return;
3414 	}
3415 
3416 	if (phar_obj->archive->is_tar) {
3417 		RETURN_TRUE;
3418 	} else {
3419 		if (phar_obj->archive->is_persistent && FAILURE == phar_copy_on_write(&(phar_obj->archive))) {
3420 			zend_throw_exception_ex(phar_ce_PharException, 0, "phar \"%s\" is persistent, unable to copy on write", phar_obj->archive->fname);
3421 			return;
3422 		}
3423 		pharobj_set_compression(&phar_obj->archive->manifest, PHAR_ENT_COMPRESSED_NONE);
3424 	}
3425 
3426 	phar_obj->archive->is_modified = 1;
3427 	phar_flush(phar_obj->archive, 0, 0, 0, &error);
3428 
3429 	if (error) {
3430 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "%s", error);
3431 		efree(error);
3432 	}
3433 
3434 	RETURN_TRUE;
3435 }
3436 /* }}} */
3437 
3438 /* {{{ proto bool Phar::copy(string oldfile, string newfile)
3439  * copy a file internal to the phar archive to another new file within the phar
3440  */
PHP_METHOD(Phar,copy)3441 PHP_METHOD(Phar, copy)
3442 {
3443 	char *oldfile, *newfile, *error;
3444 	const char *pcr_error;
3445 	size_t oldfile_len, newfile_len;
3446 	phar_entry_info *oldentry, newentry = {0}, *temp;
3447 	int tmp_len = 0;
3448 
3449 	PHAR_ARCHIVE_OBJECT();
3450 
3451 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "pp", &oldfile, &oldfile_len, &newfile, &newfile_len) == FAILURE) {
3452 		return;
3453 	}
3454 	if (ZEND_SIZE_T_INT_OVFL(newfile_len)) {
3455 		RETURN_FALSE;
3456 	}
3457 	if (PHAR_G(readonly) && !phar_obj->archive->is_data) {
3458 		zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0,
3459 			"Cannot copy \"%s\" to \"%s\", phar is read-only", oldfile, newfile);
3460 		RETURN_FALSE;
3461 	}
3462 
3463 	if (oldfile_len >= sizeof(".phar")-1 && !memcmp(oldfile, ".phar", sizeof(".phar")-1)) {
3464 		/* can't copy a meta file */
3465 		zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0,
3466 			"file \"%s\" cannot be copied to file \"%s\", cannot copy Phar meta-file in %s", oldfile, newfile, phar_obj->archive->fname);
3467 		RETURN_FALSE;
3468 	}
3469 
3470 	if (newfile_len >= sizeof(".phar")-1 && !memcmp(newfile, ".phar", sizeof(".phar")-1)) {
3471 		/* can't copy a meta file */
3472 		zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0,
3473 			"file \"%s\" cannot be copied to file \"%s\", cannot copy to Phar meta-file in %s", oldfile, newfile, phar_obj->archive->fname);
3474 		RETURN_FALSE;
3475 	}
3476 
3477 	if (!zend_hash_str_exists(&phar_obj->archive->manifest, oldfile, (uint) oldfile_len) || NULL == (oldentry = zend_hash_str_find_ptr(&phar_obj->archive->manifest, oldfile, (uint) oldfile_len)) || oldentry->is_deleted) {
3478 		zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0,
3479 			"file \"%s\" cannot be copied to file \"%s\", file does not exist in %s", oldfile, newfile, phar_obj->archive->fname);
3480 		RETURN_FALSE;
3481 	}
3482 
3483 	if (zend_hash_str_exists(&phar_obj->archive->manifest, newfile, (uint) newfile_len)) {
3484 		if (NULL != (temp = zend_hash_str_find_ptr(&phar_obj->archive->manifest, newfile, (uint) newfile_len)) || !temp->is_deleted) {
3485 			zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0,
3486 				"file \"%s\" cannot be copied to file \"%s\", file must not already exist in phar %s", oldfile, newfile, phar_obj->archive->fname);
3487 			RETURN_FALSE;
3488 		}
3489 	}
3490 
3491 	tmp_len = (int)newfile_len;
3492 	if (phar_path_check(&newfile, &tmp_len, &pcr_error) > pcr_is_ok) {
3493 		zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0,
3494 				"file \"%s\" contains invalid characters %s, cannot be copied from \"%s\" in phar %s", newfile, pcr_error, oldfile, phar_obj->archive->fname);
3495 		RETURN_FALSE;
3496 	}
3497 	newfile_len = tmp_len;
3498 
3499 	if (phar_obj->archive->is_persistent) {
3500 		if (FAILURE == phar_copy_on_write(&(phar_obj->archive))) {
3501 			zend_throw_exception_ex(phar_ce_PharException, 0, "phar \"%s\" is persistent, unable to copy on write", phar_obj->archive->fname);
3502 			return;
3503 		}
3504 		/* re-populate with copied-on-write entry */
3505 		oldentry = zend_hash_str_find_ptr(&phar_obj->archive->manifest, oldfile, (uint) oldfile_len);
3506 	}
3507 
3508 	memcpy((void *) &newentry, oldentry, sizeof(phar_entry_info));
3509 
3510 	if (Z_TYPE(newentry.metadata) != IS_UNDEF) {
3511 		zval_copy_ctor(&newentry.metadata);
3512 		newentry.metadata_str.s = NULL;
3513 	}
3514 
3515 	newentry.filename = estrndup(newfile, newfile_len);
3516 	newentry.filename_len = (int)newfile_len;
3517 	newentry.fp_refcount = 0;
3518 
3519 	if (oldentry->fp_type != PHAR_FP) {
3520 		if (FAILURE == phar_copy_entry_fp(oldentry, &newentry, &error)) {
3521 			efree(newentry.filename);
3522 			php_stream_close(newentry.fp);
3523 			zend_throw_exception_ex(phar_ce_PharException, 0, "%s", error);
3524 			efree(error);
3525 			return;
3526 		}
3527 	}
3528 
3529 	zend_hash_str_add_mem(&oldentry->phar->manifest, newfile, newfile_len, &newentry, sizeof(phar_entry_info));
3530 	phar_obj->archive->is_modified = 1;
3531 	phar_flush(phar_obj->archive, 0, 0, 0, &error);
3532 
3533 	if (error) {
3534 		zend_throw_exception_ex(phar_ce_PharException, 0, "%s", error);
3535 		efree(error);
3536 	}
3537 
3538 	RETURN_TRUE;
3539 }
3540 /* }}} */
3541 
3542 /* {{{ proto int Phar::offsetExists(string entry)
3543  * determines whether a file exists in the phar
3544  */
PHP_METHOD(Phar,offsetExists)3545 PHP_METHOD(Phar, offsetExists)
3546 {
3547 	char *fname;
3548 	size_t fname_len;
3549 	phar_entry_info *entry;
3550 
3551 	PHAR_ARCHIVE_OBJECT();
3552 
3553 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "p", &fname, &fname_len) == FAILURE) {
3554 		return;
3555 	}
3556 	if (ZEND_SIZE_T_INT_OVFL(fname_len)) {
3557 		RETURN_FALSE;
3558 	}
3559 
3560 	if (zend_hash_str_exists(&phar_obj->archive->manifest, fname, (uint) fname_len)) {
3561 		if (NULL != (entry = zend_hash_str_find_ptr(&phar_obj->archive->manifest, fname, (uint) fname_len))) {
3562 			if (entry->is_deleted) {
3563 				/* entry is deleted, but has not been flushed to disk yet */
3564 				RETURN_FALSE;
3565 			}
3566 		}
3567 
3568 		if (fname_len >= sizeof(".phar")-1 && !memcmp(fname, ".phar", sizeof(".phar")-1)) {
3569 			/* none of these are real files, so they don't exist */
3570 			RETURN_FALSE;
3571 		}
3572 		RETURN_TRUE;
3573 	} else {
3574 		if (zend_hash_str_exists(&phar_obj->archive->virtual_dirs, fname, (uint) fname_len)) {
3575 			RETURN_TRUE;
3576 		}
3577 		RETURN_FALSE;
3578 	}
3579 }
3580 /* }}} */
3581 
3582 /* {{{ proto int Phar::offsetGet(string entry)
3583  * get a PharFileInfo object for a specific file
3584  */
PHP_METHOD(Phar,offsetGet)3585 PHP_METHOD(Phar, offsetGet)
3586 {
3587 	char *fname, *error;
3588 	size_t fname_len;
3589 	zval zfname;
3590 	phar_entry_info *entry;
3591 	zend_string *sfname;
3592 	PHAR_ARCHIVE_OBJECT();
3593 
3594 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "p", &fname, &fname_len) == FAILURE) {
3595 		return;
3596 	}
3597 
3598 	if (ZEND_SIZE_T_INT_OVFL(fname_len)) {
3599 		RETURN_FALSE;
3600 	}
3601 
3602 	/* security is 0 here so that we can get a better error message than "entry doesn't exist" */
3603 	if (!(entry = phar_get_entry_info_dir(phar_obj->archive, fname, (int)fname_len, 1, &error, 0))) {
3604 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Entry %s does not exist%s%s", fname, error?", ":"", error?error:"");
3605 	} else {
3606 		if (fname_len == sizeof(".phar/stub.php")-1 && !memcmp(fname, ".phar/stub.php", sizeof(".phar/stub.php")-1)) {
3607 			zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Cannot get stub \".phar/stub.php\" directly in phar \"%s\", use getStub", phar_obj->archive->fname);
3608 			return;
3609 		}
3610 
3611 		if (fname_len == sizeof(".phar/alias.txt")-1 && !memcmp(fname, ".phar/alias.txt", sizeof(".phar/alias.txt")-1)) {
3612 			zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Cannot get alias \".phar/alias.txt\" directly in phar \"%s\", use getAlias", phar_obj->archive->fname);
3613 			return;
3614 		}
3615 
3616 		if (fname_len >= sizeof(".phar")-1 && !memcmp(fname, ".phar", sizeof(".phar")-1)) {
3617 			zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Cannot directly get any files or directories in magic \".phar\" directory");
3618 			return;
3619 		}
3620 
3621 		if (entry->is_temp_dir) {
3622 			efree(entry->filename);
3623 			efree(entry);
3624 		}
3625 
3626 		sfname = strpprintf(0, "phar://%s/%s", phar_obj->archive->fname, fname);
3627 		ZVAL_NEW_STR(&zfname, sfname);
3628 		spl_instantiate_arg_ex1(phar_obj->spl.info_class, return_value, &zfname);
3629 		zval_ptr_dtor(&zfname);
3630 	}
3631 }
3632 /* }}} */
3633 
3634 /* {{{ add a file within the phar archive from a string or resource
3635  */
phar_add_file(phar_archive_data ** pphar,char * filename,int filename_len,char * cont_str,size_t cont_len,zval * zresource)3636 static void phar_add_file(phar_archive_data **pphar, char *filename, int filename_len, char *cont_str, size_t cont_len, zval *zresource)
3637 {
3638 	int start_pos=0;
3639 	char *error;
3640 	size_t contents_len;
3641 	phar_entry_data *data;
3642 	php_stream *contents_file = NULL;
3643 	php_stream_statbuf ssb;
3644 
3645 	if (filename_len >= (int)sizeof(".phar")-1) {
3646 		start_pos = ('/' == filename[0] ? 1 : 0); /* account for any leading slash: multiple-leads handled elsewhere */
3647 		if (!memcmp(&filename[start_pos], ".phar", sizeof(".phar")-1) && (filename[start_pos+5] == '/' || filename[start_pos+5] == '\\' || filename[start_pos+5] == '\0')) {
3648 			zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Cannot create any files in magic \".phar\" directory");
3649 			return;
3650 		}
3651 	}
3652 
3653 	if (!(data = phar_get_or_create_entry_data((*pphar)->fname, (*pphar)->fname_len, filename, filename_len, "w+b", 0, &error, 1))) {
3654 		if (error) {
3655 			zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Entry %s does not exist and cannot be created: %s", filename, error);
3656 			efree(error);
3657 		} else {
3658 			zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Entry %s does not exist and cannot be created", filename);
3659 		}
3660 		return;
3661 	} else {
3662 		if (error) {
3663 			efree(error);
3664 		}
3665 
3666 		if (!data->internal_file->is_dir) {
3667 			if (cont_str) {
3668 				contents_len = php_stream_write(data->fp, cont_str, cont_len);
3669 				if (contents_len != cont_len) {
3670 					zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Entry %s could not be written to", filename);
3671 					return;
3672 				}
3673 			} else {
3674 				if (!(php_stream_from_zval_no_verify(contents_file, zresource))) {
3675 					zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Entry %s could not be written to", filename);
3676 					return;
3677 				}
3678 				php_stream_copy_to_stream_ex(contents_file, data->fp, PHP_STREAM_COPY_ALL, &contents_len);
3679 			}
3680 			data->internal_file->compressed_filesize = data->internal_file->uncompressed_filesize = contents_len;
3681 		}
3682 
3683 		if (contents_file != NULL && php_stream_stat(contents_file, &ssb) != -1) {
3684 			data->internal_file->flags = ssb.sb.st_mode & PHAR_ENT_PERM_MASK ;
3685 		} else {
3686 #ifndef _WIN32
3687 			mode_t mask;
3688 			mask = umask(0);
3689 			umask(mask);
3690 			data->internal_file->flags &= ~mask;
3691 #endif
3692 		}
3693 
3694 		/* check for copy-on-write */
3695 		if (pphar[0] != data->phar) {
3696 			*pphar = data->phar;
3697 		}
3698 		phar_entry_delref(data);
3699 		phar_flush(*pphar, 0, 0, 0, &error);
3700 
3701 		if (error) {
3702 			zend_throw_exception_ex(phar_ce_PharException, 0, "%s", error);
3703 			efree(error);
3704 		}
3705 	}
3706 }
3707 /* }}} */
3708 
3709 /* {{{ create a directory within the phar archive
3710  */
phar_mkdir(phar_archive_data ** pphar,char * dirname,int dirname_len)3711 static void phar_mkdir(phar_archive_data **pphar, char *dirname, int dirname_len)
3712 {
3713 	char *error;
3714 	phar_entry_data *data;
3715 
3716 	if (!(data = phar_get_or_create_entry_data((*pphar)->fname, (*pphar)->fname_len, dirname, dirname_len, "w+b", 2, &error, 1))) {
3717 		if (error) {
3718 			zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Directory %s does not exist and cannot be created: %s", dirname, error);
3719 			efree(error);
3720 		} else {
3721 			zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Directory %s does not exist and cannot be created", dirname);
3722 		}
3723 
3724 		return;
3725 	} else {
3726 		if (error) {
3727 			efree(error);
3728 		}
3729 
3730 		/* check for copy on write */
3731 		if (data->phar != *pphar) {
3732 			*pphar = data->phar;
3733 		}
3734 		phar_entry_delref(data);
3735 		phar_flush(*pphar, 0, 0, 0, &error);
3736 
3737 		if (error) {
3738 			zend_throw_exception_ex(phar_ce_PharException, 0, "%s", error);
3739 			efree(error);
3740 		}
3741 	}
3742 }
3743 /* }}} */
3744 
3745 /* {{{ proto int Phar::offsetSet(string entry, string value)
3746  * set the contents of an internal file to those of an external file
3747  */
PHP_METHOD(Phar,offsetSet)3748 PHP_METHOD(Phar, offsetSet)
3749 {
3750 	char *fname, *cont_str = NULL;
3751 	size_t fname_len, cont_len;
3752 	zval *zresource;
3753 	PHAR_ARCHIVE_OBJECT();
3754 
3755 	if (PHAR_G(readonly) && !phar_obj->archive->is_data) {
3756 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Write operations disabled by the php.ini setting phar.readonly");
3757 		return;
3758 	}
3759 
3760 	if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "pr", &fname, &fname_len, &zresource) == FAILURE
3761 	&& zend_parse_parameters(ZEND_NUM_ARGS(), "ps", &fname, &fname_len, &cont_str, &cont_len) == FAILURE) {
3762 		return;
3763 	}
3764 	if (ZEND_SIZE_T_INT_OVFL(fname_len)) {
3765 		RETURN_FALSE;
3766 	}
3767 	if (fname_len == sizeof(".phar/stub.php")-1 && !memcmp(fname, ".phar/stub.php", sizeof(".phar/stub.php")-1)) {
3768 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Cannot set stub \".phar/stub.php\" directly in phar \"%s\", use setStub", phar_obj->archive->fname);
3769 		return;
3770 	}
3771 
3772 	if (fname_len == sizeof(".phar/alias.txt")-1 && !memcmp(fname, ".phar/alias.txt", sizeof(".phar/alias.txt")-1)) {
3773 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Cannot set alias \".phar/alias.txt\" directly in phar \"%s\", use setAlias", phar_obj->archive->fname);
3774 		return;
3775 	}
3776 
3777 	if (fname_len >= sizeof(".phar")-1 && !memcmp(fname, ".phar", sizeof(".phar")-1)) {
3778 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Cannot set any files or directories in magic \".phar\" directory");
3779 		return;
3780 	}
3781 
3782 	phar_add_file(&(phar_obj->archive), fname, (int)fname_len, cont_str, cont_len, zresource);
3783 }
3784 /* }}} */
3785 
3786 /* {{{ proto int Phar::offsetUnset(string entry)
3787  * remove a file from a phar
3788  */
PHP_METHOD(Phar,offsetUnset)3789 PHP_METHOD(Phar, offsetUnset)
3790 {
3791 	char *fname, *error;
3792 	size_t fname_len;
3793 	phar_entry_info *entry;
3794 	PHAR_ARCHIVE_OBJECT();
3795 
3796 	if (PHAR_G(readonly) && !phar_obj->archive->is_data) {
3797 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Write operations disabled by the php.ini setting phar.readonly");
3798 		return;
3799 	}
3800 
3801 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "p", &fname, &fname_len) == FAILURE) {
3802 		return;
3803 	}
3804 	if (ZEND_SIZE_T_INT_OVFL(fname_len)) {
3805 		RETURN_FALSE;
3806 	}
3807 
3808 	if (zend_hash_str_exists(&phar_obj->archive->manifest, fname, (uint) fname_len)) {
3809 		if (NULL != (entry = zend_hash_str_find_ptr(&phar_obj->archive->manifest, fname, (uint) fname_len))) {
3810 			if (entry->is_deleted) {
3811 				/* entry is deleted, but has not been flushed to disk yet */
3812 				return;
3813 			}
3814 
3815 			if (phar_obj->archive->is_persistent) {
3816 				if (FAILURE == phar_copy_on_write(&(phar_obj->archive))) {
3817 					zend_throw_exception_ex(phar_ce_PharException, 0, "phar \"%s\" is persistent, unable to copy on write", phar_obj->archive->fname);
3818 					return;
3819 				}
3820 				/* re-populate entry after copy on write */
3821 				entry = zend_hash_str_find_ptr(&phar_obj->archive->manifest, fname, (uint) fname_len);
3822 			}
3823 			entry->is_modified = 0;
3824 			entry->is_deleted = 1;
3825 			/* we need to "flush" the stream to save the newly deleted file on disk */
3826 			phar_flush(phar_obj->archive, 0, 0, 0, &error);
3827 
3828 			if (error) {
3829 				zend_throw_exception_ex(phar_ce_PharException, 0, "%s", error);
3830 				efree(error);
3831 			}
3832 
3833 			RETURN_TRUE;
3834 		}
3835 	} else {
3836 		RETURN_FALSE;
3837 	}
3838 }
3839 /* }}} */
3840 
3841 /* {{{ proto string Phar::addEmptyDir(string dirname)
3842  * Adds an empty directory to the phar archive
3843  */
PHP_METHOD(Phar,addEmptyDir)3844 PHP_METHOD(Phar, addEmptyDir)
3845 {
3846 	char *dirname;
3847 	size_t dirname_len;
3848 
3849 	PHAR_ARCHIVE_OBJECT();
3850 
3851 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "p", &dirname, &dirname_len) == FAILURE) {
3852 		return;
3853 	}
3854 	if (ZEND_SIZE_T_INT_OVFL(dirname_len)) {
3855 		RETURN_FALSE;
3856 	}
3857 
3858 	if (dirname_len >= sizeof(".phar")-1 && !memcmp(dirname, ".phar", sizeof(".phar")-1)) {
3859 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Cannot create a directory in magic \".phar\" directory");
3860 		return;
3861 	}
3862 
3863 	phar_mkdir(&phar_obj->archive, dirname, (int)dirname_len);
3864 }
3865 /* }}} */
3866 
3867 /* {{{ proto string Phar::addFile(string filename[, string localname])
3868  * Adds a file to the archive using the filename, or the second parameter as the name within the archive
3869  */
PHP_METHOD(Phar,addFile)3870 PHP_METHOD(Phar, addFile)
3871 {
3872 	char *fname, *localname = NULL;
3873 	size_t fname_len, localname_len = 0;
3874 	php_stream *resource;
3875 	zval zresource;
3876 
3877 	PHAR_ARCHIVE_OBJECT();
3878 
3879 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "p|s", &fname, &fname_len, &localname, &localname_len) == FAILURE) {
3880 		return;
3881 	}
3882 	if (ZEND_SIZE_T_INT_OVFL(fname_len)) {
3883 		RETURN_FALSE;
3884 	}
3885 
3886 	if (!strstr(fname, "://") && php_check_open_basedir(fname)) {
3887 		zend_throw_exception_ex(spl_ce_RuntimeException, 0, "phar error: unable to open file \"%s\" to add to phar archive, open_basedir restrictions prevent this", fname);
3888 		return;
3889 	}
3890 
3891 	if (!(resource = php_stream_open_wrapper(fname, "rb", 0, NULL))) {
3892 		zend_throw_exception_ex(spl_ce_RuntimeException, 0, "phar error: unable to open file \"%s\" to add to phar archive", fname);
3893 		return;
3894 	}
3895 
3896 	if (localname) {
3897 		fname = localname;
3898 		fname_len = localname_len;
3899 	}
3900 
3901 	php_stream_to_zval(resource, &zresource);
3902 	phar_add_file(&(phar_obj->archive), fname, (int)fname_len, NULL, 0, &zresource);
3903 	zval_ptr_dtor(&zresource);
3904 }
3905 /* }}} */
3906 
3907 /* {{{ proto string Phar::addFromString(string localname, string contents)
3908  * Adds a file to the archive using its contents as a string
3909  */
PHP_METHOD(Phar,addFromString)3910 PHP_METHOD(Phar, addFromString)
3911 {
3912 	char *localname, *cont_str;
3913 	size_t localname_len, cont_len;
3914 
3915 	PHAR_ARCHIVE_OBJECT();
3916 
3917 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ps", &localname, &localname_len, &cont_str, &cont_len) == FAILURE) {
3918 		return;
3919 	}
3920 	if (ZEND_SIZE_T_INT_OVFL(localname_len)) {
3921 		RETURN_FALSE;
3922 	}
3923 
3924 	phar_add_file(&(phar_obj->archive), localname, (int)localname_len, cont_str, cont_len, NULL);
3925 }
3926 /* }}} */
3927 
3928 /* {{{ proto string Phar::getStub()
3929  * Returns the stub at the head of a phar archive as a string.
3930  */
PHP_METHOD(Phar,getStub)3931 PHP_METHOD(Phar, getStub)
3932 {
3933 	size_t len;
3934 	zend_string *buf;
3935 	php_stream *fp;
3936 	php_stream_filter *filter = NULL;
3937 	phar_entry_info *stub;
3938 
3939 	PHAR_ARCHIVE_OBJECT();
3940 
3941 	if (zend_parse_parameters_none() == FAILURE) {
3942 		return;
3943 	}
3944 
3945 	if (phar_obj->archive->is_tar || phar_obj->archive->is_zip) {
3946 
3947 		if (NULL != (stub = zend_hash_str_find_ptr(&(phar_obj->archive->manifest), ".phar/stub.php", sizeof(".phar/stub.php")-1))) {
3948 			if (phar_obj->archive->fp && !phar_obj->archive->is_brandnew && !(stub->flags & PHAR_ENT_COMPRESSION_MASK)) {
3949 				fp = phar_obj->archive->fp;
3950 			} else {
3951 				if (!(fp = php_stream_open_wrapper(phar_obj->archive->fname, "rb", 0, NULL))) {
3952 					zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0, "phar error: unable to open phar \"%s\"", phar_obj->archive->fname);
3953 					return;
3954 				}
3955 				if (stub->flags & PHAR_ENT_COMPRESSION_MASK) {
3956 					char *filter_name;
3957 
3958 					if ((filter_name = phar_decompress_filter(stub, 0)) != NULL) {
3959 						filter = php_stream_filter_create(filter_name, NULL, php_stream_is_persistent(fp));
3960 					} else {
3961 						filter = NULL;
3962 					}
3963 					if (!filter) {
3964 						zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0, "phar error: unable to read stub of phar \"%s\" (cannot create %s filter)", phar_obj->archive->fname, phar_decompress_filter(stub, 1));
3965 						return;
3966 					}
3967 					php_stream_filter_append(&fp->readfilters, filter);
3968 				}
3969 			}
3970 
3971 			if (!fp)  {
3972 				zend_throw_exception_ex(spl_ce_RuntimeException, 0,
3973 					"Unable to read stub");
3974 				return;
3975 			}
3976 
3977 			php_stream_seek(fp, stub->offset_abs, SEEK_SET);
3978 			len = stub->uncompressed_filesize;
3979 			goto carry_on;
3980 		} else {
3981 			RETURN_EMPTY_STRING();
3982 		}
3983 	}
3984 	len = phar_obj->archive->halt_offset;
3985 
3986 	if (phar_obj->archive->fp && !phar_obj->archive->is_brandnew) {
3987 		fp = phar_obj->archive->fp;
3988 	} else {
3989 		fp = php_stream_open_wrapper(phar_obj->archive->fname, "rb", 0, NULL);
3990 	}
3991 
3992 	if (!fp)  {
3993 		zend_throw_exception_ex(spl_ce_RuntimeException, 0,
3994 			"Unable to read stub");
3995 		return;
3996 	}
3997 
3998 	php_stream_rewind(fp);
3999 carry_on:
4000 	buf = zend_string_alloc(len, 0);
4001 
4002 	if (len != php_stream_read(fp, ZSTR_VAL(buf), len)) {
4003 		if (fp != phar_obj->archive->fp) {
4004 			php_stream_close(fp);
4005 		}
4006 		zend_throw_exception_ex(spl_ce_RuntimeException, 0,
4007 			"Unable to read stub");
4008 		zend_string_release(buf);
4009 		return;
4010 	}
4011 
4012 	if (filter) {
4013 		php_stream_filter_flush(filter, 1);
4014 		php_stream_filter_remove(filter, 1);
4015 	}
4016 
4017 	if (fp != phar_obj->archive->fp) {
4018 		php_stream_close(fp);
4019 	}
4020 
4021 	ZSTR_VAL(buf)[len] = '\0';
4022 	ZSTR_LEN(buf) = len;
4023 	RETVAL_STR(buf);
4024 }
4025 /* }}}*/
4026 
4027 /* {{{ proto int Phar::hasMetaData()
4028  * Returns TRUE if the phar has global metadata, FALSE otherwise.
4029  */
PHP_METHOD(Phar,hasMetadata)4030 PHP_METHOD(Phar, hasMetadata)
4031 {
4032 	PHAR_ARCHIVE_OBJECT();
4033 
4034 	RETURN_BOOL(Z_TYPE(phar_obj->archive->metadata) != IS_UNDEF);
4035 }
4036 /* }}} */
4037 
4038 /* {{{ proto int Phar::getMetaData()
4039  * Returns the global metadata of the phar
4040  */
PHP_METHOD(Phar,getMetadata)4041 PHP_METHOD(Phar, getMetadata)
4042 {
4043 	PHAR_ARCHIVE_OBJECT();
4044 
4045 	if (zend_parse_parameters_none() == FAILURE) {
4046 		return;
4047 	}
4048 
4049 	if (Z_TYPE(phar_obj->archive->metadata) != IS_UNDEF) {
4050 		if (phar_obj->archive->is_persistent) {
4051 			char *buf = estrndup((char *) Z_PTR(phar_obj->archive->metadata), phar_obj->archive->metadata_len);
4052 			/* assume success, we would have failed before */
4053 			phar_parse_metadata(&buf, return_value, phar_obj->archive->metadata_len);
4054 			efree(buf);
4055 		} else {
4056 			ZVAL_COPY(return_value, &phar_obj->archive->metadata);
4057 		}
4058 	}
4059 }
4060 /* }}} */
4061 
4062 /* {{{ proto int Phar::setMetaData(mixed $metadata)
4063  * Sets the global metadata of the phar
4064  */
PHP_METHOD(Phar,setMetadata)4065 PHP_METHOD(Phar, setMetadata)
4066 {
4067 	char *error;
4068 	zval *metadata;
4069 
4070 	PHAR_ARCHIVE_OBJECT();
4071 
4072 	if (PHAR_G(readonly) && !phar_obj->archive->is_data) {
4073 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Write operations disabled by the php.ini setting phar.readonly");
4074 		return;
4075 	}
4076 
4077 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &metadata) == FAILURE) {
4078 		return;
4079 	}
4080 
4081 	if (phar_obj->archive->is_persistent && FAILURE == phar_copy_on_write(&(phar_obj->archive))) {
4082 		zend_throw_exception_ex(phar_ce_PharException, 0, "phar \"%s\" is persistent, unable to copy on write", phar_obj->archive->fname);
4083 		return;
4084 	}
4085 	if (Z_TYPE(phar_obj->archive->metadata) != IS_UNDEF) {
4086 		zval_ptr_dtor(&phar_obj->archive->metadata);
4087 		ZVAL_UNDEF(&phar_obj->archive->metadata);
4088 	}
4089 
4090 	ZVAL_COPY(&phar_obj->archive->metadata, metadata);
4091 	phar_obj->archive->is_modified = 1;
4092 	phar_flush(phar_obj->archive, 0, 0, 0, &error);
4093 
4094 	if (error) {
4095 		zend_throw_exception_ex(phar_ce_PharException, 0, "%s", error);
4096 		efree(error);
4097 	}
4098 }
4099 /* }}} */
4100 
4101 /* {{{ proto int Phar::delMetadata()
4102  * Deletes the global metadata of the phar
4103  */
PHP_METHOD(Phar,delMetadata)4104 PHP_METHOD(Phar, delMetadata)
4105 {
4106 	char *error;
4107 
4108 	PHAR_ARCHIVE_OBJECT();
4109 
4110 	if (PHAR_G(readonly) && !phar_obj->archive->is_data) {
4111 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Write operations disabled by the php.ini setting phar.readonly");
4112 		return;
4113 	}
4114 
4115 	if (Z_TYPE(phar_obj->archive->metadata) != IS_UNDEF) {
4116 		zval_ptr_dtor(&phar_obj->archive->metadata);
4117 		ZVAL_UNDEF(&phar_obj->archive->metadata);
4118 		phar_obj->archive->is_modified = 1;
4119 		phar_flush(phar_obj->archive, 0, 0, 0, &error);
4120 
4121 		if (error) {
4122 			zend_throw_exception_ex(phar_ce_PharException, 0, "%s", error);
4123 			efree(error);
4124 			RETURN_FALSE;
4125 		} else {
4126 			RETURN_TRUE;
4127 		}
4128 
4129 	} else {
4130 		RETURN_TRUE;
4131 	}
4132 }
4133 /* }}} */
4134 
phar_extract_file(zend_bool overwrite,phar_entry_info * entry,char * dest,int dest_len,char ** error)4135 static int phar_extract_file(zend_bool overwrite, phar_entry_info *entry, char *dest, int dest_len, char **error) /* {{{ */
4136 {
4137 	php_stream_statbuf ssb;
4138 	size_t len;
4139 	php_stream *fp;
4140 	char *fullpath;
4141 	const char *slash;
4142 	mode_t mode;
4143 	cwd_state new_state;
4144 	char *filename;
4145 	size_t filename_len;
4146 
4147 	if (entry->is_mounted) {
4148 		/* silently ignore mounted entries */
4149 		return SUCCESS;
4150 	}
4151 
4152 	if (entry->filename_len >= sizeof(".phar")-1 && !memcmp(entry->filename, ".phar", sizeof(".phar")-1)) {
4153 		return SUCCESS;
4154 	}
4155 	/* strip .. from path and restrict it to be under dest directory */
4156 	new_state.cwd = (char*)emalloc(2);
4157 	new_state.cwd[0] = DEFAULT_SLASH;
4158 	new_state.cwd[1] = '\0';
4159 	new_state.cwd_length = 1;
4160 	if (virtual_file_ex(&new_state, entry->filename, NULL, CWD_EXPAND) != 0 ||
4161 			new_state.cwd_length <= 1) {
4162 		if (EINVAL == errno && entry->filename_len > 50) {
4163 			char *tmp = estrndup(entry->filename, 50);
4164 			spprintf(error, 4096, "Cannot extract \"%s...\" to \"%s...\", extracted filename is too long for filesystem", tmp, dest);
4165 			efree(tmp);
4166 		} else {
4167 			spprintf(error, 4096, "Cannot extract \"%s\", internal error", entry->filename);
4168 		}
4169 		efree(new_state.cwd);
4170 		return FAILURE;
4171 	}
4172 	filename = new_state.cwd + 1;
4173 	filename_len = new_state.cwd_length - 1;
4174 #ifdef PHP_WIN32
4175 	/* unixify the path back, otherwise non zip formats might be broken */
4176 	{
4177 		int cnt = filename_len;
4178 
4179 		do {
4180 			if ('\\' == filename[cnt]) {
4181 				filename[cnt] = '/';
4182 			}
4183 		} while (cnt-- >= 0);
4184 	}
4185 #endif
4186 
4187 	len = spprintf(&fullpath, 0, "%s/%s", dest, filename);
4188 
4189 	if (len >= MAXPATHLEN) {
4190 		char *tmp;
4191 		/* truncate for error message */
4192 		fullpath[50] = '\0';
4193 		if (entry->filename_len > 50) {
4194 			tmp = estrndup(entry->filename, 50);
4195 			spprintf(error, 4096, "Cannot extract \"%s...\" to \"%s...\", extracted filename is too long for filesystem", tmp, fullpath);
4196 			efree(tmp);
4197 		} else {
4198 			spprintf(error, 4096, "Cannot extract \"%s\" to \"%s...\", extracted filename is too long for filesystem", entry->filename, fullpath);
4199 		}
4200 		efree(fullpath);
4201 		efree(new_state.cwd);
4202 		return FAILURE;
4203 	}
4204 
4205 	if (!len) {
4206 		spprintf(error, 4096, "Cannot extract \"%s\", internal error", entry->filename);
4207 		efree(fullpath);
4208 		efree(new_state.cwd);
4209 		return FAILURE;
4210 	}
4211 
4212 	if (php_check_open_basedir(fullpath)) {
4213 		spprintf(error, 4096, "Cannot extract \"%s\" to \"%s\", openbasedir/safe mode restrictions in effect", entry->filename, fullpath);
4214 		efree(fullpath);
4215 		efree(new_state.cwd);
4216 		return FAILURE;
4217 	}
4218 
4219 	/* let see if the path already exists */
4220 	if (!overwrite && SUCCESS == php_stream_stat_path(fullpath, &ssb)) {
4221 		spprintf(error, 4096, "Cannot extract \"%s\" to \"%s\", path already exists", entry->filename, fullpath);
4222 		efree(fullpath);
4223 		efree(new_state.cwd);
4224 		return FAILURE;
4225 	}
4226 
4227 	/* perform dirname */
4228 	slash = zend_memrchr(filename, '/', filename_len);
4229 
4230 	if (slash) {
4231 		fullpath[dest_len + (slash - filename) + 1] = '\0';
4232 	} else {
4233 		fullpath[dest_len] = '\0';
4234 	}
4235 
4236 	if (FAILURE == php_stream_stat_path(fullpath, &ssb)) {
4237 		if (entry->is_dir) {
4238 			if (!php_stream_mkdir(fullpath, entry->flags & PHAR_ENT_PERM_MASK,  PHP_STREAM_MKDIR_RECURSIVE, NULL)) {
4239 				spprintf(error, 4096, "Cannot extract \"%s\", could not create directory \"%s\"", entry->filename, fullpath);
4240 				efree(fullpath);
4241 				efree(new_state.cwd);
4242 				return FAILURE;
4243 			}
4244 		} else {
4245 			if (!php_stream_mkdir(fullpath, 0777,  PHP_STREAM_MKDIR_RECURSIVE, NULL)) {
4246 				spprintf(error, 4096, "Cannot extract \"%s\", could not create directory \"%s\"", entry->filename, fullpath);
4247 				efree(fullpath);
4248 				efree(new_state.cwd);
4249 				return FAILURE;
4250 			}
4251 		}
4252 	}
4253 
4254 	if (slash) {
4255 		fullpath[dest_len + (slash - filename) + 1] = '/';
4256 	} else {
4257 		fullpath[dest_len] = '/';
4258 	}
4259 
4260 	filename = NULL;
4261 	efree(new_state.cwd);
4262 	/* it is a standalone directory, job done */
4263 	if (entry->is_dir) {
4264 		efree(fullpath);
4265 		return SUCCESS;
4266 	}
4267 
4268 	fp = php_stream_open_wrapper(fullpath, "w+b", REPORT_ERRORS, NULL);
4269 
4270 	if (!fp) {
4271 		spprintf(error, 4096, "Cannot extract \"%s\", could not open for writing \"%s\"", entry->filename, fullpath);
4272 		efree(fullpath);
4273 		return FAILURE;
4274 	}
4275 
4276 	if (!phar_get_efp(entry, 0)) {
4277 		if (FAILURE == phar_open_entry_fp(entry, error, 1)) {
4278 			if (error) {
4279 				spprintf(error, 4096, "Cannot extract \"%s\" to \"%s\", unable to open internal file pointer: %s", entry->filename, fullpath, *error);
4280 			} else {
4281 				spprintf(error, 4096, "Cannot extract \"%s\" to \"%s\", unable to open internal file pointer", entry->filename, fullpath);
4282 			}
4283 			efree(fullpath);
4284 			php_stream_close(fp);
4285 			return FAILURE;
4286 		}
4287 	}
4288 
4289 	if (FAILURE == phar_seek_efp(entry, 0, SEEK_SET, 0, 0)) {
4290 		spprintf(error, 4096, "Cannot extract \"%s\" to \"%s\", unable to seek internal file pointer", entry->filename, fullpath);
4291 		efree(fullpath);
4292 		php_stream_close(fp);
4293 		return FAILURE;
4294 	}
4295 
4296 	if (SUCCESS != php_stream_copy_to_stream_ex(phar_get_efp(entry, 0), fp, entry->uncompressed_filesize, NULL)) {
4297 		spprintf(error, 4096, "Cannot extract \"%s\" to \"%s\", copying contents failed", entry->filename, fullpath);
4298 		efree(fullpath);
4299 		php_stream_close(fp);
4300 		return FAILURE;
4301 	}
4302 
4303 	php_stream_close(fp);
4304 	mode = (mode_t) entry->flags & PHAR_ENT_PERM_MASK;
4305 
4306 	if (FAILURE == VCWD_CHMOD(fullpath, mode)) {
4307 		spprintf(error, 4096, "Cannot extract \"%s\" to \"%s\", setting file permissions failed", entry->filename, fullpath);
4308 		efree(fullpath);
4309 		return FAILURE;
4310 	}
4311 
4312 	efree(fullpath);
4313 	return SUCCESS;
4314 }
4315 /* }}} */
4316 
4317 /* {{{ proto bool Phar::extractTo(string pathto[[, mixed files], bool overwrite])
4318  * Extract one or more file from a phar archive, optionally overwriting existing files
4319  */
PHP_METHOD(Phar,extractTo)4320 PHP_METHOD(Phar, extractTo)
4321 {
4322 	char *error = NULL;
4323 	php_stream *fp;
4324 	php_stream_statbuf ssb;
4325 	phar_entry_info *entry;
4326 	char *pathto, *filename;
4327 	size_t pathto_len, filename_len;
4328 	int ret, i;
4329 	int nelems;
4330 	zval *zval_files = NULL;
4331 	zend_bool overwrite = 0;
4332 
4333 	PHAR_ARCHIVE_OBJECT();
4334 
4335 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "p|z!b", &pathto, &pathto_len, &zval_files, &overwrite) == FAILURE) {
4336 		return;
4337 	}
4338 
4339 	fp = php_stream_open_wrapper(phar_obj->archive->fname, "rb", IGNORE_URL|STREAM_MUST_SEEK, NULL);
4340 
4341 	if (!fp) {
4342 		zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0,
4343 			"Invalid argument, %s cannot be found", phar_obj->archive->fname);
4344 		return;
4345 	}
4346 
4347 	php_stream_close(fp);
4348 
4349 	if (pathto_len < 1) {
4350 		zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0,
4351 			"Invalid argument, extraction path must be non-zero length");
4352 		return;
4353 	}
4354 
4355 	if (pathto_len >= MAXPATHLEN) {
4356 		char *tmp = estrndup(pathto, 50);
4357 		/* truncate for error message */
4358 		zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, "Cannot extract to \"%s...\", destination directory is too long for filesystem", tmp);
4359 		efree(tmp);
4360 		return;
4361 	}
4362 
4363 	if (php_stream_stat_path(pathto, &ssb) < 0) {
4364 		ret = php_stream_mkdir(pathto, 0777,  PHP_STREAM_MKDIR_RECURSIVE, NULL);
4365 		if (!ret) {
4366 			zend_throw_exception_ex(spl_ce_RuntimeException, 0,
4367 				"Unable to create path \"%s\" for extraction", pathto);
4368 			return;
4369 		}
4370 	} else if (!(ssb.sb.st_mode & S_IFDIR)) {
4371 		zend_throw_exception_ex(spl_ce_RuntimeException, 0,
4372 			"Unable to use path \"%s\" for extraction, it is a file, must be a directory", pathto);
4373 		return;
4374 	}
4375 
4376 	if (zval_files) {
4377 		switch (Z_TYPE_P(zval_files)) {
4378 			case IS_NULL:
4379 				goto all_files;
4380 			case IS_STRING:
4381 				filename = Z_STRVAL_P(zval_files);
4382 				filename_len = Z_STRLEN_P(zval_files);
4383 				break;
4384 			case IS_ARRAY:
4385 				nelems = zend_hash_num_elements(Z_ARRVAL_P(zval_files));
4386 				if (nelems == 0 ) {
4387 					RETURN_FALSE;
4388 				}
4389 				for (i = 0; i < nelems; i++) {
4390 					zval *zval_file;
4391 					if ((zval_file = zend_hash_index_find(Z_ARRVAL_P(zval_files), i)) != NULL) {
4392 						switch (Z_TYPE_P(zval_file)) {
4393 							case IS_STRING:
4394 								break;
4395 							default:
4396 								zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0,
4397 									"Invalid argument, array of filenames to extract contains non-string value");
4398 								return;
4399 						}
4400 						if (NULL == (entry = zend_hash_find_ptr(&phar_obj->archive->manifest, Z_STR_P(zval_file)))) {
4401 							zend_throw_exception_ex(phar_ce_PharException, 0,
4402 								"Phar Error: attempted to extract non-existent file \"%s\" from phar \"%s\"", Z_STRVAL_P(zval_file), phar_obj->archive->fname);
4403 						}
4404 						if (FAILURE == phar_extract_file(overwrite, entry, pathto, (int)pathto_len, &error)) {
4405 							zend_throw_exception_ex(phar_ce_PharException, 0,
4406 								"Extraction from phar \"%s\" failed: %s", phar_obj->archive->fname, error);
4407 							efree(error);
4408 							return;
4409 						}
4410 					}
4411 				}
4412 				RETURN_TRUE;
4413 			default:
4414 				zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0,
4415 					"Invalid argument, expected a filename (string) or array of filenames");
4416 				return;
4417 		}
4418 
4419 		if (NULL == (entry = zend_hash_str_find_ptr(&phar_obj->archive->manifest, filename, filename_len))) {
4420 			zend_throw_exception_ex(phar_ce_PharException, 0,
4421 				"Phar Error: attempted to extract non-existent file \"%s\" from phar \"%s\"", filename, phar_obj->archive->fname);
4422 			return;
4423 		}
4424 
4425 		if (FAILURE == phar_extract_file(overwrite, entry, pathto, (int)pathto_len, &error)) {
4426 			zend_throw_exception_ex(phar_ce_PharException, 0,
4427 				"Extraction from phar \"%s\" failed: %s", phar_obj->archive->fname, error);
4428 			efree(error);
4429 			return;
4430 		}
4431 	} else {
4432 		phar_archive_data *phar;
4433 all_files:
4434 		phar = phar_obj->archive;
4435 		/* Extract all files */
4436 		if (!zend_hash_num_elements(&(phar->manifest))) {
4437 			RETURN_TRUE;
4438 		}
4439 
4440 		ZEND_HASH_FOREACH_PTR(&phar->manifest, entry) {
4441 			if (FAILURE == phar_extract_file(overwrite, entry, pathto, (int)pathto_len, &error)) {
4442 				zend_throw_exception_ex(phar_ce_PharException, 0,
4443 					"Extraction from phar \"%s\" failed: %s", phar->fname, error);
4444 				efree(error);
4445 				return;
4446 			}
4447 		} ZEND_HASH_FOREACH_END();
4448 	}
4449 	RETURN_TRUE;
4450 }
4451 /* }}} */
4452 
4453 
4454 /* {{{ proto void PharFileInfo::__construct(string entry)
4455  * Construct a Phar entry object
4456  */
PHP_METHOD(PharFileInfo,__construct)4457 PHP_METHOD(PharFileInfo, __construct)
4458 {
4459 	char *fname, *arch, *entry, *error;
4460 	size_t fname_len;
4461 	int arch_len, entry_len;
4462 	phar_entry_object *entry_obj;
4463 	phar_entry_info *entry_info;
4464 	phar_archive_data *phar_data;
4465 	zval *zobj = getThis(), arg1;
4466 
4467 	if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "p", &fname, &fname_len) == FAILURE) {
4468 		return;
4469 	}
4470 
4471 	entry_obj = (phar_entry_object*)((char*)Z_OBJ_P(zobj) - Z_OBJ_P(zobj)->handlers->offset);
4472 
4473 	if (entry_obj->entry) {
4474 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Cannot call constructor twice");
4475 		return;
4476 	}
4477 
4478 	if (fname_len < 7 || memcmp(fname, "phar://", 7) || phar_split_fname(fname, (int)fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0) == FAILURE) {
4479 		zend_throw_exception_ex(spl_ce_RuntimeException, 0,
4480 			"'%s' is not a valid phar archive URL (must have at least phar://filename.phar)", fname);
4481 		return;
4482 	}
4483 
4484 	if (phar_open_from_filename(arch, arch_len, NULL, 0, REPORT_ERRORS, &phar_data, &error) == FAILURE) {
4485 		efree(arch);
4486 		efree(entry);
4487 		if (error) {
4488 			zend_throw_exception_ex(spl_ce_RuntimeException, 0,
4489 				"Cannot open phar file '%s': %s", fname, error);
4490 			efree(error);
4491 		} else {
4492 			zend_throw_exception_ex(spl_ce_RuntimeException, 0,
4493 				"Cannot open phar file '%s'", fname);
4494 		}
4495 		return;
4496 	}
4497 
4498 	if ((entry_info = phar_get_entry_info_dir(phar_data, entry, entry_len, 1, &error, 1)) == NULL) {
4499 		zend_throw_exception_ex(spl_ce_RuntimeException, 0,
4500 			"Cannot access phar file entry '%s' in archive '%s'%s%s", entry, arch, error ? ", " : "", error ? error : "");
4501 		efree(arch);
4502 		efree(entry);
4503 		return;
4504 	}
4505 
4506 	efree(arch);
4507 	efree(entry);
4508 
4509 	entry_obj->entry = entry_info;
4510 
4511 	ZVAL_STRINGL(&arg1, fname, fname_len);
4512 
4513 	zend_call_method_with_1_params(zobj, Z_OBJCE_P(zobj),
4514 		&spl_ce_SplFileInfo->constructor, "__construct", NULL, &arg1);
4515 
4516 	zval_ptr_dtor(&arg1);
4517 }
4518 /* }}} */
4519 
4520 #define PHAR_ENTRY_OBJECT() \
4521 	zval *zobj = getThis(); \
4522 	phar_entry_object *entry_obj = (phar_entry_object*)((char*)Z_OBJ_P(zobj) - Z_OBJ_P(zobj)->handlers->offset); \
4523 	if (!entry_obj->entry) { \
4524 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, \
4525 			"Cannot call method on an uninitialized PharFileInfo object"); \
4526 		return; \
4527 	}
4528 
4529 /* {{{ proto void PharFileInfo::__destruct()
4530  * clean up directory-based entry objects
4531  */
PHP_METHOD(PharFileInfo,__destruct)4532 PHP_METHOD(PharFileInfo, __destruct)
4533 {
4534 	zval *zobj = getThis();
4535 	phar_entry_object *entry_obj = (phar_entry_object*)((char*)Z_OBJ_P(zobj) - Z_OBJ_P(zobj)->handlers->offset);
4536 
4537 	if (entry_obj->entry && entry_obj->entry->is_temp_dir) {
4538 		if (entry_obj->entry->filename) {
4539 			efree(entry_obj->entry->filename);
4540 			entry_obj->entry->filename = NULL;
4541 		}
4542 
4543 		efree(entry_obj->entry);
4544 		entry_obj->entry = NULL;
4545 	}
4546 }
4547 /* }}} */
4548 
4549 /* {{{ proto int PharFileInfo::getCompressedSize()
4550  * Returns the compressed size
4551  */
PHP_METHOD(PharFileInfo,getCompressedSize)4552 PHP_METHOD(PharFileInfo, getCompressedSize)
4553 {
4554 	PHAR_ENTRY_OBJECT();
4555 
4556 	if (zend_parse_parameters_none() == FAILURE) {
4557 		return;
4558 	}
4559 
4560 	RETURN_LONG(entry_obj->entry->compressed_filesize);
4561 }
4562 /* }}} */
4563 
4564 /* {{{ proto bool PharFileInfo::isCompressed([int compression_type])
4565  * Returns whether the entry is compressed, and whether it is compressed with Phar::GZ or Phar::BZ2 if specified
4566  */
PHP_METHOD(PharFileInfo,isCompressed)4567 PHP_METHOD(PharFileInfo, isCompressed)
4568 {
4569 	/* a number that is not Phar::GZ or Phar::BZ2 */
4570 	zend_long method = 9021976;
4571 	PHAR_ENTRY_OBJECT();
4572 
4573 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &method) == FAILURE) {
4574 		return;
4575 	}
4576 
4577 	switch (method) {
4578 		case 9021976:
4579 			RETURN_BOOL(entry_obj->entry->flags & PHAR_ENT_COMPRESSION_MASK);
4580 		case PHAR_ENT_COMPRESSED_GZ:
4581 			RETURN_BOOL(entry_obj->entry->flags & PHAR_ENT_COMPRESSED_GZ);
4582 		case PHAR_ENT_COMPRESSED_BZ2:
4583 			RETURN_BOOL(entry_obj->entry->flags & PHAR_ENT_COMPRESSED_BZ2);
4584 		default:
4585 			zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, \
4586 				"Unknown compression type specified"); \
4587 	}
4588 }
4589 /* }}} */
4590 
4591 /* {{{ proto int PharFileInfo::getCRC32()
4592  * Returns CRC32 code or throws an exception if not CRC checked
4593  */
PHP_METHOD(PharFileInfo,getCRC32)4594 PHP_METHOD(PharFileInfo, getCRC32)
4595 {
4596 	PHAR_ENTRY_OBJECT();
4597 
4598 	if (zend_parse_parameters_none() == FAILURE) {
4599 		return;
4600 	}
4601 
4602 	if (entry_obj->entry->is_dir) {
4603 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, \
4604 			"Phar entry is a directory, does not have a CRC"); \
4605 		return;
4606 	}
4607 
4608 	if (entry_obj->entry->is_crc_checked) {
4609 		RETURN_LONG(entry_obj->entry->crc32);
4610 	} else {
4611 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, \
4612 			"Phar entry was not CRC checked"); \
4613 	}
4614 }
4615 /* }}} */
4616 
4617 /* {{{ proto int PharFileInfo::isCRCChecked()
4618  * Returns whether file entry is CRC checked
4619  */
PHP_METHOD(PharFileInfo,isCRCChecked)4620 PHP_METHOD(PharFileInfo, isCRCChecked)
4621 {
4622 	PHAR_ENTRY_OBJECT();
4623 
4624 	if (zend_parse_parameters_none() == FAILURE) {
4625 		return;
4626 	}
4627 
4628 	RETURN_BOOL(entry_obj->entry->is_crc_checked);
4629 }
4630 /* }}} */
4631 
4632 /* {{{ proto int PharFileInfo::getPharFlags()
4633  * Returns the Phar file entry flags
4634  */
PHP_METHOD(PharFileInfo,getPharFlags)4635 PHP_METHOD(PharFileInfo, getPharFlags)
4636 {
4637 	PHAR_ENTRY_OBJECT();
4638 
4639 	if (zend_parse_parameters_none() == FAILURE) {
4640 		return;
4641 	}
4642 
4643 	RETURN_LONG(entry_obj->entry->flags & ~(PHAR_ENT_PERM_MASK|PHAR_ENT_COMPRESSION_MASK));
4644 }
4645 /* }}} */
4646 
4647 /* {{{ proto int PharFileInfo::chmod()
4648  * set the file permissions for the Phar.  This only allows setting execution bit, read/write
4649  */
PHP_METHOD(PharFileInfo,chmod)4650 PHP_METHOD(PharFileInfo, chmod)
4651 {
4652 	char *error;
4653 	zend_long perms;
4654 	PHAR_ENTRY_OBJECT();
4655 
4656 	if (entry_obj->entry->is_temp_dir) {
4657 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, \
4658 			"Phar entry \"%s\" is a temporary directory (not an actual entry in the archive), cannot chmod", entry_obj->entry->filename); \
4659 		return;
4660 	}
4661 
4662 	if (PHAR_G(readonly) && !entry_obj->entry->phar->is_data) {
4663 		zend_throw_exception_ex(phar_ce_PharException, 0, "Cannot modify permissions for file \"%s\" in phar \"%s\", write operations are prohibited", entry_obj->entry->filename, entry_obj->entry->phar->fname);
4664 		return;
4665 	}
4666 
4667 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &perms) == FAILURE) {
4668 		return;
4669 	}
4670 
4671 	if (entry_obj->entry->is_persistent) {
4672 		phar_archive_data *phar = entry_obj->entry->phar;
4673 
4674 		if (FAILURE == phar_copy_on_write(&phar)) {
4675 			zend_throw_exception_ex(phar_ce_PharException, 0, "phar \"%s\" is persistent, unable to copy on write", phar->fname);
4676 			return;
4677 		}
4678 		/* re-populate after copy-on-write */
4679 		entry_obj->entry = zend_hash_str_find_ptr(&phar->manifest, entry_obj->entry->filename, entry_obj->entry->filename_len);
4680 	}
4681 	/* clear permissions */
4682 	entry_obj->entry->flags &= ~PHAR_ENT_PERM_MASK;
4683 	perms &= 0777;
4684 	entry_obj->entry->flags |= perms;
4685 	entry_obj->entry->old_flags = entry_obj->entry->flags;
4686 	entry_obj->entry->phar->is_modified = 1;
4687 	entry_obj->entry->is_modified = 1;
4688 
4689 	/* hackish cache in php_stat needs to be cleared */
4690 	/* if this code fails to work, check main/streams/streams.c, _php_stream_stat_path */
4691 	if (BG(CurrentLStatFile)) {
4692 		efree(BG(CurrentLStatFile));
4693 	}
4694 
4695 	if (BG(CurrentStatFile)) {
4696 		efree(BG(CurrentStatFile));
4697 	}
4698 
4699 	BG(CurrentLStatFile) = NULL;
4700 	BG(CurrentStatFile) = NULL;
4701 	phar_flush(entry_obj->entry->phar, 0, 0, 0, &error);
4702 
4703 	if (error) {
4704 		zend_throw_exception_ex(phar_ce_PharException, 0, "%s", error);
4705 		efree(error);
4706 	}
4707 }
4708 /* }}} */
4709 
4710 /* {{{ proto int PharFileInfo::hasMetaData()
4711  * Returns the metadata of the entry
4712  */
PHP_METHOD(PharFileInfo,hasMetadata)4713 PHP_METHOD(PharFileInfo, hasMetadata)
4714 {
4715 	PHAR_ENTRY_OBJECT();
4716 
4717 	if (zend_parse_parameters_none() == FAILURE) {
4718 		return;
4719 	}
4720 
4721 	RETURN_BOOL(Z_TYPE(entry_obj->entry->metadata) != IS_UNDEF);
4722 }
4723 /* }}} */
4724 
4725 /* {{{ proto int PharFileInfo::getMetaData()
4726  * Returns the metadata of the entry
4727  */
PHP_METHOD(PharFileInfo,getMetadata)4728 PHP_METHOD(PharFileInfo, getMetadata)
4729 {
4730 	PHAR_ENTRY_OBJECT();
4731 
4732 	if (zend_parse_parameters_none() == FAILURE) {
4733 		return;
4734 	}
4735 
4736 	if (Z_TYPE(entry_obj->entry->metadata) != IS_UNDEF) {
4737 		if (entry_obj->entry->is_persistent) {
4738 			char *buf = estrndup((char *) Z_PTR(entry_obj->entry->metadata), entry_obj->entry->metadata_len);
4739 			/* assume success, we would have failed before */
4740 			phar_parse_metadata(&buf, return_value, entry_obj->entry->metadata_len);
4741 			efree(buf);
4742 		} else {
4743 			ZVAL_COPY(return_value, &entry_obj->entry->metadata);
4744 		}
4745 	}
4746 }
4747 /* }}} */
4748 
4749 /* {{{ proto int PharFileInfo::setMetaData(mixed $metadata)
4750  * Sets the metadata of the entry
4751  */
PHP_METHOD(PharFileInfo,setMetadata)4752 PHP_METHOD(PharFileInfo, setMetadata)
4753 {
4754 	char *error;
4755 	zval *metadata;
4756 
4757 	PHAR_ENTRY_OBJECT();
4758 
4759 	if (PHAR_G(readonly) && !entry_obj->entry->phar->is_data) {
4760 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Write operations disabled by the php.ini setting phar.readonly");
4761 		return;
4762 	}
4763 
4764 	if (entry_obj->entry->is_temp_dir) {
4765 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, \
4766 			"Phar entry is a temporary directory (not an actual entry in the archive), cannot set metadata"); \
4767 		return;
4768 	}
4769 
4770 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &metadata) == FAILURE) {
4771 		return;
4772 	}
4773 
4774 	if (entry_obj->entry->is_persistent) {
4775 		phar_archive_data *phar = entry_obj->entry->phar;
4776 
4777 		if (FAILURE == phar_copy_on_write(&phar)) {
4778 			zend_throw_exception_ex(phar_ce_PharException, 0, "phar \"%s\" is persistent, unable to copy on write", phar->fname);
4779 			return;
4780 		}
4781 		/* re-populate after copy-on-write */
4782 		entry_obj->entry = zend_hash_str_find_ptr(&phar->manifest, entry_obj->entry->filename, entry_obj->entry->filename_len);
4783 	}
4784 	if (Z_TYPE(entry_obj->entry->metadata) != IS_UNDEF) {
4785 		zval_ptr_dtor(&entry_obj->entry->metadata);
4786 		ZVAL_UNDEF(&entry_obj->entry->metadata);
4787 	}
4788 
4789 	ZVAL_COPY(&entry_obj->entry->metadata, metadata);
4790 
4791 	entry_obj->entry->is_modified = 1;
4792 	entry_obj->entry->phar->is_modified = 1;
4793 	phar_flush(entry_obj->entry->phar, 0, 0, 0, &error);
4794 
4795 	if (error) {
4796 		zend_throw_exception_ex(phar_ce_PharException, 0, "%s", error);
4797 		efree(error);
4798 	}
4799 }
4800 /* }}} */
4801 
4802 /* {{{ proto bool PharFileInfo::delMetaData()
4803  * Deletes the metadata of the entry
4804  */
PHP_METHOD(PharFileInfo,delMetadata)4805 PHP_METHOD(PharFileInfo, delMetadata)
4806 {
4807 	char *error;
4808 
4809 	PHAR_ENTRY_OBJECT();
4810 
4811 	if (zend_parse_parameters_none() == FAILURE) {
4812 		return;
4813 	}
4814 
4815 	if (PHAR_G(readonly) && !entry_obj->entry->phar->is_data) {
4816 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Write operations disabled by the php.ini setting phar.readonly");
4817 		return;
4818 	}
4819 
4820 	if (entry_obj->entry->is_temp_dir) {
4821 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, \
4822 			"Phar entry is a temporary directory (not an actual entry in the archive), cannot delete metadata"); \
4823 		return;
4824 	}
4825 
4826 	if (Z_TYPE(entry_obj->entry->metadata) != IS_UNDEF) {
4827 		if (entry_obj->entry->is_persistent) {
4828 			phar_archive_data *phar = entry_obj->entry->phar;
4829 
4830 			if (FAILURE == phar_copy_on_write(&phar)) {
4831 				zend_throw_exception_ex(phar_ce_PharException, 0, "phar \"%s\" is persistent, unable to copy on write", phar->fname);
4832 				return;
4833 			}
4834 			/* re-populate after copy-on-write */
4835 			entry_obj->entry = zend_hash_str_find_ptr(&phar->manifest, entry_obj->entry->filename, entry_obj->entry->filename_len);
4836 		}
4837 		zval_ptr_dtor(&entry_obj->entry->metadata);
4838 		ZVAL_UNDEF(&entry_obj->entry->metadata);
4839 		entry_obj->entry->is_modified = 1;
4840 		entry_obj->entry->phar->is_modified = 1;
4841 
4842 		phar_flush(entry_obj->entry->phar, 0, 0, 0, &error);
4843 
4844 		if (error) {
4845 			zend_throw_exception_ex(phar_ce_PharException, 0, "%s", error);
4846 			efree(error);
4847 			RETURN_FALSE;
4848 		} else {
4849 			RETURN_TRUE;
4850 		}
4851 
4852 	} else {
4853 		RETURN_TRUE;
4854 	}
4855 }
4856 /* }}} */
4857 
4858 /* {{{ proto string PharFileInfo::getContent()
4859  * return the complete file contents of the entry (like file_get_contents)
4860  */
PHP_METHOD(PharFileInfo,getContent)4861 PHP_METHOD(PharFileInfo, getContent)
4862 {
4863 	char *error;
4864 	php_stream *fp;
4865 	phar_entry_info *link;
4866 	zend_string *str;
4867 
4868 	PHAR_ENTRY_OBJECT();
4869 
4870 	if (zend_parse_parameters_none() == FAILURE) {
4871 		return;
4872 	}
4873 
4874 	if (entry_obj->entry->is_dir) {
4875 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0,
4876 			"Phar error: Cannot retrieve contents, \"%s\" in phar \"%s\" is a directory", entry_obj->entry->filename, entry_obj->entry->phar->fname);
4877 		return;
4878 	}
4879 
4880 	link = phar_get_link_source(entry_obj->entry);
4881 
4882 	if (!link) {
4883 		link = entry_obj->entry;
4884 	}
4885 
4886 	if (SUCCESS != phar_open_entry_fp(link, &error, 0)) {
4887 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0,
4888 			"Phar error: Cannot retrieve contents, \"%s\" in phar \"%s\": %s", entry_obj->entry->filename, entry_obj->entry->phar->fname, error);
4889 		efree(error);
4890 		return;
4891 	}
4892 
4893 	if (!(fp = phar_get_efp(link, 0))) {
4894 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0,
4895 			"Phar error: Cannot retrieve contents of \"%s\" in phar \"%s\"", entry_obj->entry->filename, entry_obj->entry->phar->fname);
4896 		return;
4897 	}
4898 
4899 	phar_seek_efp(link, 0, SEEK_SET, 0, 0);
4900 	str = php_stream_copy_to_mem(fp, link->uncompressed_filesize, 0);
4901 	if (str) {
4902 		RETURN_STR(str);
4903 	} else {
4904 		RETURN_EMPTY_STRING();
4905 	}
4906 }
4907 /* }}} */
4908 
4909 /* {{{ proto int PharFileInfo::compress(int compression_type)
4910  * Instructs the Phar class to compress the current file using zlib or bzip2 compression
4911  */
PHP_METHOD(PharFileInfo,compress)4912 PHP_METHOD(PharFileInfo, compress)
4913 {
4914 	zend_long method;
4915 	char *error;
4916 	PHAR_ENTRY_OBJECT();
4917 
4918 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &method) == FAILURE) {
4919 		return;
4920 	}
4921 
4922 	if (entry_obj->entry->is_tar) {
4923 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0,
4924 			"Cannot compress with Gzip compression, not possible with tar-based phar archives");
4925 		return;
4926 	}
4927 
4928 	if (entry_obj->entry->is_dir) {
4929 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, \
4930 			"Phar entry is a directory, cannot set compression"); \
4931 		return;
4932 	}
4933 
4934 	if (PHAR_G(readonly) && !entry_obj->entry->phar->is_data) {
4935 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0,
4936 			"Phar is readonly, cannot change compression");
4937 		return;
4938 	}
4939 
4940 	if (entry_obj->entry->is_deleted) {
4941 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0,
4942 			"Cannot compress deleted file");
4943 		return;
4944 	}
4945 
4946 	if (entry_obj->entry->is_persistent) {
4947 		phar_archive_data *phar = entry_obj->entry->phar;
4948 
4949 		if (FAILURE == phar_copy_on_write(&phar)) {
4950 			zend_throw_exception_ex(phar_ce_PharException, 0, "phar \"%s\" is persistent, unable to copy on write", phar->fname);
4951 			return;
4952 		}
4953 		/* re-populate after copy-on-write */
4954 		entry_obj->entry = zend_hash_str_find_ptr(&phar->manifest, entry_obj->entry->filename, entry_obj->entry->filename_len);
4955 	}
4956 	switch (method) {
4957 		case PHAR_ENT_COMPRESSED_GZ:
4958 			if (entry_obj->entry->flags & PHAR_ENT_COMPRESSED_GZ) {
4959 				RETURN_TRUE;
4960 			}
4961 
4962 			if ((entry_obj->entry->flags & PHAR_ENT_COMPRESSED_BZ2) != 0) {
4963 				if (!PHAR_G(has_bz2)) {
4964 					zend_throw_exception_ex(spl_ce_BadMethodCallException, 0,
4965 						"Cannot compress with gzip compression, file is already compressed with bzip2 compression and bz2 extension is not enabled, cannot decompress");
4966 					return;
4967 				}
4968 
4969 				/* decompress this file indirectly */
4970 				if (SUCCESS != phar_open_entry_fp(entry_obj->entry, &error, 1)) {
4971 					zend_throw_exception_ex(spl_ce_BadMethodCallException, 0,
4972 						"Phar error: Cannot decompress bzip2-compressed file \"%s\" in phar \"%s\" in order to compress with gzip: %s", entry_obj->entry->filename, entry_obj->entry->phar->fname, error);
4973 					efree(error);
4974 					return;
4975 				}
4976 			}
4977 
4978 			if (!PHAR_G(has_zlib)) {
4979 				zend_throw_exception_ex(spl_ce_BadMethodCallException, 0,
4980 					"Cannot compress with gzip compression, zlib extension is not enabled");
4981 				return;
4982 			}
4983 
4984 			entry_obj->entry->old_flags = entry_obj->entry->flags;
4985 			entry_obj->entry->flags &= ~PHAR_ENT_COMPRESSION_MASK;
4986 			entry_obj->entry->flags |= PHAR_ENT_COMPRESSED_GZ;
4987 			break;
4988 		case PHAR_ENT_COMPRESSED_BZ2:
4989 			if (entry_obj->entry->flags & PHAR_ENT_COMPRESSED_BZ2) {
4990 				RETURN_TRUE;
4991 			}
4992 
4993 			if ((entry_obj->entry->flags & PHAR_ENT_COMPRESSED_GZ) != 0) {
4994 				if (!PHAR_G(has_zlib)) {
4995 					zend_throw_exception_ex(spl_ce_BadMethodCallException, 0,
4996 						"Cannot compress with bzip2 compression, file is already compressed with gzip compression and zlib extension is not enabled, cannot decompress");
4997 					return;
4998 				}
4999 
5000 				/* decompress this file indirectly */
5001 				if (SUCCESS != phar_open_entry_fp(entry_obj->entry, &error, 1)) {
5002 					zend_throw_exception_ex(spl_ce_BadMethodCallException, 0,
5003 						"Phar error: Cannot decompress gzip-compressed file \"%s\" in phar \"%s\" in order to compress with bzip2: %s", entry_obj->entry->filename, entry_obj->entry->phar->fname, error);
5004 					efree(error);
5005 					return;
5006 				}
5007 			}
5008 
5009 			if (!PHAR_G(has_bz2)) {
5010 				zend_throw_exception_ex(spl_ce_BadMethodCallException, 0,
5011 					"Cannot compress with bzip2 compression, bz2 extension is not enabled");
5012 				return;
5013 			}
5014 			entry_obj->entry->old_flags = entry_obj->entry->flags;
5015 			entry_obj->entry->flags &= ~PHAR_ENT_COMPRESSION_MASK;
5016 			entry_obj->entry->flags |= PHAR_ENT_COMPRESSED_BZ2;
5017 			break;
5018 		default:
5019 			zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, \
5020 				"Unknown compression type specified"); \
5021 	}
5022 
5023 	entry_obj->entry->phar->is_modified = 1;
5024 	entry_obj->entry->is_modified = 1;
5025 	phar_flush(entry_obj->entry->phar, 0, 0, 0, &error);
5026 
5027 	if (error) {
5028 		zend_throw_exception_ex(phar_ce_PharException, 0, "%s", error);
5029 		efree(error);
5030 	}
5031 
5032 	RETURN_TRUE;
5033 }
5034 /* }}} */
5035 
5036 /* {{{ proto int PharFileInfo::decompress()
5037  * Instructs the Phar class to decompress the current file
5038  */
PHP_METHOD(PharFileInfo,decompress)5039 PHP_METHOD(PharFileInfo, decompress)
5040 {
5041 	char *error;
5042 	PHAR_ENTRY_OBJECT();
5043 
5044 	if (zend_parse_parameters_none() == FAILURE) {
5045 		return;
5046 	}
5047 
5048 	if (entry_obj->entry->is_dir) {
5049 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, \
5050 			"Phar entry is a directory, cannot set compression"); \
5051 		return;
5052 	}
5053 
5054 	if ((entry_obj->entry->flags & PHAR_ENT_COMPRESSION_MASK) == 0) {
5055 		RETURN_TRUE;
5056 	}
5057 
5058 	if (PHAR_G(readonly) && !entry_obj->entry->phar->is_data) {
5059 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0,
5060 			"Phar is readonly, cannot decompress");
5061 		return;
5062 	}
5063 
5064 	if (entry_obj->entry->is_deleted) {
5065 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0,
5066 			"Cannot compress deleted file");
5067 		return;
5068 	}
5069 
5070 	if ((entry_obj->entry->flags & PHAR_ENT_COMPRESSED_GZ) != 0 && !PHAR_G(has_zlib)) {
5071 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0,
5072 			"Cannot decompress Gzip-compressed file, zlib extension is not enabled");
5073 		return;
5074 	}
5075 
5076 	if ((entry_obj->entry->flags & PHAR_ENT_COMPRESSED_BZ2) != 0 && !PHAR_G(has_bz2)) {
5077 		zend_throw_exception_ex(spl_ce_BadMethodCallException, 0,
5078 			"Cannot decompress Bzip2-compressed file, bz2 extension is not enabled");
5079 		return;
5080 	}
5081 
5082 	if (entry_obj->entry->is_persistent) {
5083 		phar_archive_data *phar = entry_obj->entry->phar;
5084 
5085 		if (FAILURE == phar_copy_on_write(&phar)) {
5086 			zend_throw_exception_ex(phar_ce_PharException, 0, "phar \"%s\" is persistent, unable to copy on write", phar->fname);
5087 			return;
5088 		}
5089 		/* re-populate after copy-on-write */
5090 		entry_obj->entry = zend_hash_str_find_ptr(&phar->manifest, entry_obj->entry->filename, entry_obj->entry->filename_len);
5091 	}
5092 	if (!entry_obj->entry->fp) {
5093 		if (FAILURE == phar_open_archive_fp(entry_obj->entry->phar)) {
5094 			zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Cannot decompress entry \"%s\", phar error: Cannot open phar archive \"%s\" for reading", entry_obj->entry->filename, entry_obj->entry->phar->fname);
5095 			return;
5096 		}
5097 		entry_obj->entry->fp_type = PHAR_FP;
5098 	}
5099 
5100 	entry_obj->entry->old_flags = entry_obj->entry->flags;
5101 	entry_obj->entry->flags &= ~PHAR_ENT_COMPRESSION_MASK;
5102 	entry_obj->entry->phar->is_modified = 1;
5103 	entry_obj->entry->is_modified = 1;
5104 	phar_flush(entry_obj->entry->phar, 0, 0, 0, &error);
5105 
5106 	if (error) {
5107 		zend_throw_exception_ex(phar_ce_PharException, 0, "%s", error);
5108 		efree(error);
5109 	}
5110 	RETURN_TRUE;
5111 }
5112 /* }}} */
5113 
5114 /* {{{ phar methods */
5115 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar___construct, 0, 0, 1)
5116 	ZEND_ARG_INFO(0, filename)
5117 	ZEND_ARG_INFO(0, flags)
5118 	ZEND_ARG_INFO(0, alias)
5119 ZEND_END_ARG_INFO()
5120 
5121 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_createDS, 0, 0, 0)
5122 	ZEND_ARG_INFO(0, index)
5123 	ZEND_ARG_INFO(0, webindex)
5124 ZEND_END_ARG_INFO()
5125 
5126 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_cancompress, 0, 0, 0)
5127 	ZEND_ARG_INFO(0, method)
5128 ZEND_END_ARG_INFO()
5129 
5130 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_isvalidpharfilename, 0, 0, 1)
5131 	ZEND_ARG_INFO(0, filename)
5132 	ZEND_ARG_INFO(0, executable)
5133 ZEND_END_ARG_INFO()
5134 
5135 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_loadPhar, 0, 0, 1)
5136 	ZEND_ARG_INFO(0, filename)
5137 	ZEND_ARG_INFO(0, alias)
5138 ZEND_END_ARG_INFO()
5139 
5140 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_mapPhar, 0, 0, 0)
5141 	ZEND_ARG_INFO(0, alias)
5142 	ZEND_ARG_INFO(0, offset)
5143 ZEND_END_ARG_INFO()
5144 
5145 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_mount, 0, 0, 2)
5146 	ZEND_ARG_INFO(0, inphar)
5147 	ZEND_ARG_INFO(0, externalfile)
5148 ZEND_END_ARG_INFO()
5149 
5150 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_mungServer, 0, 0, 1)
5151 	ZEND_ARG_INFO(0, munglist)
5152 ZEND_END_ARG_INFO()
5153 
5154 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_webPhar, 0, 0, 0)
5155 	ZEND_ARG_INFO(0, alias)
5156 	ZEND_ARG_INFO(0, index)
5157 	ZEND_ARG_INFO(0, f404)
5158 	ZEND_ARG_INFO(0, mimetypes)
5159 	ZEND_ARG_INFO(0, rewrites)
5160 ZEND_END_ARG_INFO()
5161 
5162 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_running, 0, 0, 0)
5163 	ZEND_ARG_INFO(0, retphar)
5164 ZEND_END_ARG_INFO()
5165 
5166 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_ua, 0, 0, 1)
5167 	ZEND_ARG_INFO(0, archive)
5168 ZEND_END_ARG_INFO()
5169 
5170 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_build, 0, 0, 1)
5171 	ZEND_ARG_INFO(0, iterator)
5172 	ZEND_ARG_INFO(0, base_directory)
5173 ZEND_END_ARG_INFO()
5174 
5175 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_conv, 0, 0, 0)
5176 	ZEND_ARG_INFO(0, format)
5177 	ZEND_ARG_INFO(0, compression_type)
5178 	ZEND_ARG_INFO(0, file_ext)
5179 ZEND_END_ARG_INFO()
5180 
5181 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_comps, 0, 0, 1)
5182 	ZEND_ARG_INFO(0, compression_type)
5183 	ZEND_ARG_INFO(0, file_ext)
5184 ZEND_END_ARG_INFO()
5185 
5186 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_decomp, 0, 0, 0)
5187 	ZEND_ARG_INFO(0, file_ext)
5188 ZEND_END_ARG_INFO()
5189 
5190 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_comp, 0, 0, 1)
5191 	ZEND_ARG_INFO(0, compression_type)
5192 ZEND_END_ARG_INFO()
5193 
5194 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_compo, 0, 0, 0)
5195 	ZEND_ARG_INFO(0, compression_type)
5196 ZEND_END_ARG_INFO()
5197 
5198 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_copy, 0, 0, 2)
5199 	ZEND_ARG_INFO(0, newfile)
5200 	ZEND_ARG_INFO(0, oldfile)
5201 ZEND_END_ARG_INFO()
5202 
5203 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_delete, 0, 0, 1)
5204 	ZEND_ARG_INFO(0, entry)
5205 ZEND_END_ARG_INFO()
5206 
5207 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_fromdir, 0, 0, 1)
5208 	ZEND_ARG_INFO(0, base_dir)
5209 	ZEND_ARG_INFO(0, regex)
5210 ZEND_END_ARG_INFO()
5211 
5212 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_offsetExists, 0, 0, 1)
5213 	ZEND_ARG_INFO(0, entry)
5214 ZEND_END_ARG_INFO()
5215 
5216 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_offsetSet, 0, 0, 2)
5217 	ZEND_ARG_INFO(0, entry)
5218 	ZEND_ARG_INFO(0, value)
5219 ZEND_END_ARG_INFO()
5220 
5221 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_setAlias, 0, 0, 1)
5222 	ZEND_ARG_INFO(0, alias)
5223 ZEND_END_ARG_INFO()
5224 
5225 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_setMetadata, 0, 0, 1)
5226 	ZEND_ARG_INFO(0, metadata)
5227 ZEND_END_ARG_INFO()
5228 
5229 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_setSigAlgo, 0, 0, 1)
5230 	ZEND_ARG_INFO(0, algorithm)
5231 	ZEND_ARG_INFO(0, privatekey)
5232 ZEND_END_ARG_INFO()
5233 
5234 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_setStub, 0, 0, 1)
5235 	ZEND_ARG_INFO(0, newstub)
5236 	ZEND_ARG_INFO(0, maxlen)
5237 ZEND_END_ARG_INFO()
5238 
5239 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_emptydir, 0, 0, 0)
5240 	ZEND_ARG_INFO(0, dirname)
5241 ZEND_END_ARG_INFO()
5242 
5243 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_extract, 0, 0, 1)
5244 	ZEND_ARG_INFO(0, pathto)
5245 	ZEND_ARG_INFO(0, files)
5246 	ZEND_ARG_INFO(0, overwrite)
5247 ZEND_END_ARG_INFO()
5248 
5249 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_addfile, 0, 0, 1)
5250 	ZEND_ARG_INFO(0, filename)
5251 	ZEND_ARG_INFO(0, localname)
5252 ZEND_END_ARG_INFO()
5253 
5254 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_fromstring, 0, 0, 1)
5255 	ZEND_ARG_INFO(0, localname)
5256 	ZEND_ARG_INFO(0, contents)
5257 ZEND_END_ARG_INFO()
5258 
5259 ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_isff, 0, 0, 1)
5260 	ZEND_ARG_INFO(0, fileformat)
5261 ZEND_END_ARG_INFO()
5262 
5263 ZEND_BEGIN_ARG_INFO(arginfo_phar__void, 0)
5264 ZEND_END_ARG_INFO()
5265 
5266 
5267 zend_function_entry php_archive_methods[] = {
5268 	PHP_ME(Phar, __construct,           arginfo_phar___construct,  ZEND_ACC_PUBLIC)
5269 	PHP_ME(Phar, __destruct,            arginfo_phar__void,        ZEND_ACC_PUBLIC)
5270 	PHP_ME(Phar, addEmptyDir,           arginfo_phar_emptydir,     ZEND_ACC_PUBLIC)
5271 	PHP_ME(Phar, addFile,               arginfo_phar_addfile,      ZEND_ACC_PUBLIC)
5272 	PHP_ME(Phar, addFromString,         arginfo_phar_fromstring,   ZEND_ACC_PUBLIC)
5273 	PHP_ME(Phar, buildFromDirectory,    arginfo_phar_fromdir,      ZEND_ACC_PUBLIC)
5274 	PHP_ME(Phar, buildFromIterator,     arginfo_phar_build,        ZEND_ACC_PUBLIC)
5275 	PHP_ME(Phar, compressFiles,         arginfo_phar_comp,         ZEND_ACC_PUBLIC)
5276 	PHP_ME(Phar, decompressFiles,       arginfo_phar__void,        ZEND_ACC_PUBLIC)
5277 	PHP_ME(Phar, compress,              arginfo_phar_comps,        ZEND_ACC_PUBLIC)
5278 	PHP_ME(Phar, decompress,            arginfo_phar_decomp,       ZEND_ACC_PUBLIC)
5279 	PHP_ME(Phar, convertToExecutable,   arginfo_phar_conv,         ZEND_ACC_PUBLIC)
5280 	PHP_ME(Phar, convertToData,         arginfo_phar_conv,         ZEND_ACC_PUBLIC)
5281 	PHP_ME(Phar, copy,                  arginfo_phar_copy,         ZEND_ACC_PUBLIC)
5282 	PHP_ME(Phar, count,                 arginfo_phar__void,        ZEND_ACC_PUBLIC)
5283 	PHP_ME(Phar, delete,                arginfo_phar_delete,       ZEND_ACC_PUBLIC)
5284 	PHP_ME(Phar, delMetadata,           arginfo_phar__void,        ZEND_ACC_PUBLIC)
5285 	PHP_ME(Phar, extractTo,             arginfo_phar_extract,      ZEND_ACC_PUBLIC)
5286 	PHP_ME(Phar, getAlias,              arginfo_phar__void,        ZEND_ACC_PUBLIC)
5287 	PHP_ME(Phar, getPath,               arginfo_phar__void,        ZEND_ACC_PUBLIC)
5288 	PHP_ME(Phar, getMetadata,           arginfo_phar__void,        ZEND_ACC_PUBLIC)
5289 	PHP_ME(Phar, getModified,           arginfo_phar__void,        ZEND_ACC_PUBLIC)
5290 	PHP_ME(Phar, getSignature,          arginfo_phar__void,        ZEND_ACC_PUBLIC)
5291 	PHP_ME(Phar, getStub,               arginfo_phar__void,        ZEND_ACC_PUBLIC)
5292 	PHP_ME(Phar, getVersion,            arginfo_phar__void,        ZEND_ACC_PUBLIC)
5293 	PHP_ME(Phar, hasMetadata,           arginfo_phar__void,        ZEND_ACC_PUBLIC)
5294 	PHP_ME(Phar, isBuffering,           arginfo_phar__void,        ZEND_ACC_PUBLIC)
5295 	PHP_ME(Phar, isCompressed,          arginfo_phar__void,        ZEND_ACC_PUBLIC)
5296 	PHP_ME(Phar, isFileFormat,          arginfo_phar_isff,         ZEND_ACC_PUBLIC)
5297 	PHP_ME(Phar, isWritable,            arginfo_phar__void,        ZEND_ACC_PUBLIC)
5298 	PHP_ME(Phar, offsetExists,          arginfo_phar_offsetExists, ZEND_ACC_PUBLIC)
5299 	PHP_ME(Phar, offsetGet,             arginfo_phar_offsetExists, ZEND_ACC_PUBLIC)
5300 	PHP_ME(Phar, offsetSet,             arginfo_phar_offsetSet,    ZEND_ACC_PUBLIC)
5301 	PHP_ME(Phar, offsetUnset,           arginfo_phar_offsetExists, ZEND_ACC_PUBLIC)
5302 	PHP_ME(Phar, setAlias,              arginfo_phar_setAlias,     ZEND_ACC_PUBLIC)
5303 	PHP_ME(Phar, setDefaultStub,        arginfo_phar_createDS,     ZEND_ACC_PUBLIC)
5304 	PHP_ME(Phar, setMetadata,           arginfo_phar_setMetadata,  ZEND_ACC_PUBLIC)
5305 	PHP_ME(Phar, setSignatureAlgorithm, arginfo_phar_setSigAlgo,   ZEND_ACC_PUBLIC)
5306 	PHP_ME(Phar, setStub,               arginfo_phar_setStub,      ZEND_ACC_PUBLIC)
5307 	PHP_ME(Phar, startBuffering,        arginfo_phar__void,        ZEND_ACC_PUBLIC)
5308 	PHP_ME(Phar, stopBuffering,         arginfo_phar__void,        ZEND_ACC_PUBLIC)
5309 	/* static member functions */
5310 	PHP_ME(Phar, apiVersion,            arginfo_phar__void,        ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
5311 	PHP_ME(Phar, canCompress,           arginfo_phar_cancompress,  ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
5312 	PHP_ME(Phar, canWrite,              arginfo_phar__void,        ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
5313 	PHP_ME(Phar, createDefaultStub,     arginfo_phar_createDS,     ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
5314 	PHP_ME(Phar, getSupportedCompression,arginfo_phar__void,       ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
5315 	PHP_ME(Phar, getSupportedSignatures,arginfo_phar__void,        ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
5316 	PHP_ME(Phar, interceptFileFuncs,    arginfo_phar__void,        ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
5317 	PHP_ME(Phar, isValidPharFilename,   arginfo_phar_isvalidpharfilename, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
5318 	PHP_ME(Phar, loadPhar,              arginfo_phar_loadPhar,     ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
5319 	PHP_ME(Phar, mapPhar,               arginfo_phar_mapPhar,      ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
5320 	PHP_ME(Phar, running,               arginfo_phar_running,      ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
5321 	PHP_ME(Phar, mount,                 arginfo_phar_mount,        ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
5322 	PHP_ME(Phar, mungServer,            arginfo_phar_mungServer,   ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
5323 	PHP_ME(Phar, unlinkArchive,         arginfo_phar_ua,           ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
5324 	PHP_ME(Phar, webPhar,               arginfo_phar_webPhar,      ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
5325 	PHP_FE_END
5326 };
5327 
5328 
5329 ZEND_BEGIN_ARG_INFO_EX(arginfo_data___construct, 0, 0, 1)
5330     ZEND_ARG_INFO(0, filename)
5331     ZEND_ARG_INFO(0, flags)
5332     ZEND_ARG_INFO(0, alias)
5333     ZEND_ARG_INFO(0, fileformat)
5334 ZEND_END_ARG_INFO()
5335 
5336 zend_function_entry php_data_methods[] = {
5337     PHP_ME(Phar, __construct,           arginfo_data___construct,  ZEND_ACC_PUBLIC)
5338     PHP_ME(Phar, __destruct,            arginfo_phar__void,        ZEND_ACC_PUBLIC)
5339     PHP_ME(Phar, addEmptyDir,           arginfo_phar_emptydir,     ZEND_ACC_PUBLIC)
5340     PHP_ME(Phar, addFile,               arginfo_phar_addfile,      ZEND_ACC_PUBLIC)
5341     PHP_ME(Phar, addFromString,         arginfo_phar_fromstring,   ZEND_ACC_PUBLIC)
5342     PHP_ME(Phar, buildFromDirectory,    arginfo_phar_fromdir,      ZEND_ACC_PUBLIC)
5343     PHP_ME(Phar, buildFromIterator,     arginfo_phar_build,        ZEND_ACC_PUBLIC)
5344     PHP_ME(Phar, compressFiles,         arginfo_phar_comp,         ZEND_ACC_PUBLIC)
5345     PHP_ME(Phar, decompressFiles,       arginfo_phar__void,        ZEND_ACC_PUBLIC)
5346     PHP_ME(Phar, compress,              arginfo_phar_comps,        ZEND_ACC_PUBLIC)
5347     PHP_ME(Phar, decompress,            arginfo_phar_decomp,       ZEND_ACC_PUBLIC)
5348     PHP_ME(Phar, convertToExecutable,   arginfo_phar_conv,         ZEND_ACC_PUBLIC)
5349     PHP_ME(Phar, convertToData,         arginfo_phar_conv,         ZEND_ACC_PUBLIC)
5350     PHP_ME(Phar, copy,                  arginfo_phar_copy,         ZEND_ACC_PUBLIC)
5351     PHP_ME(Phar, count,                 arginfo_phar__void,        ZEND_ACC_PUBLIC)
5352     PHP_ME(Phar, delete,                arginfo_phar_delete,       ZEND_ACC_PUBLIC)
5353     PHP_ME(Phar, delMetadata,           arginfo_phar__void,        ZEND_ACC_PUBLIC)
5354     PHP_ME(Phar, extractTo,             arginfo_phar_extract,      ZEND_ACC_PUBLIC)
5355     PHP_ME(Phar, getAlias,              arginfo_phar__void,        ZEND_ACC_PUBLIC)
5356     PHP_ME(Phar, getPath,               arginfo_phar__void,        ZEND_ACC_PUBLIC)
5357     PHP_ME(Phar, getMetadata,           arginfo_phar__void,        ZEND_ACC_PUBLIC)
5358     PHP_ME(Phar, getModified,           arginfo_phar__void,        ZEND_ACC_PUBLIC)
5359     PHP_ME(Phar, getSignature,          arginfo_phar__void,        ZEND_ACC_PUBLIC)
5360     PHP_ME(Phar, getStub,               arginfo_phar__void,        ZEND_ACC_PUBLIC)
5361     PHP_ME(Phar, getVersion,            arginfo_phar__void,        ZEND_ACC_PUBLIC)
5362     PHP_ME(Phar, hasMetadata,           arginfo_phar__void,        ZEND_ACC_PUBLIC)
5363     PHP_ME(Phar, isBuffering,           arginfo_phar__void,        ZEND_ACC_PUBLIC)
5364     PHP_ME(Phar, isCompressed,          arginfo_phar__void,        ZEND_ACC_PUBLIC)
5365     PHP_ME(Phar, isFileFormat,          arginfo_phar_isff,         ZEND_ACC_PUBLIC)
5366     PHP_ME(Phar, isWritable,            arginfo_phar__void,        ZEND_ACC_PUBLIC)
5367     PHP_ME(Phar, offsetExists,          arginfo_phar_offsetExists, ZEND_ACC_PUBLIC)
5368     PHP_ME(Phar, offsetGet,             arginfo_phar_offsetExists, ZEND_ACC_PUBLIC)
5369     PHP_ME(Phar, offsetSet,             arginfo_phar_offsetSet,    ZEND_ACC_PUBLIC)
5370     PHP_ME(Phar, offsetUnset,           arginfo_phar_offsetExists, ZEND_ACC_PUBLIC)
5371     PHP_ME(Phar, setAlias,              arginfo_phar_setAlias,     ZEND_ACC_PUBLIC)
5372     PHP_ME(Phar, setDefaultStub,        arginfo_phar_createDS,     ZEND_ACC_PUBLIC)
5373     PHP_ME(Phar, setMetadata,           arginfo_phar_setMetadata,  ZEND_ACC_PUBLIC)
5374     PHP_ME(Phar, setSignatureAlgorithm, arginfo_phar_setSigAlgo,   ZEND_ACC_PUBLIC)
5375     PHP_ME(Phar, setStub,               arginfo_phar_setStub,      ZEND_ACC_PUBLIC)
5376     PHP_ME(Phar, startBuffering,        arginfo_phar__void,        ZEND_ACC_PUBLIC)
5377     PHP_ME(Phar, stopBuffering,         arginfo_phar__void,        ZEND_ACC_PUBLIC)
5378     /* static member functions */
5379     PHP_ME(Phar, apiVersion,            arginfo_phar__void,        ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
5380     PHP_ME(Phar, canCompress,           arginfo_phar_cancompress,  ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
5381     PHP_ME(Phar, canWrite,              arginfo_phar__void,        ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
5382     PHP_ME(Phar, createDefaultStub,     arginfo_phar_createDS,     ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
5383     PHP_ME(Phar, getSupportedCompression,arginfo_phar__void,       ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
5384     PHP_ME(Phar, getSupportedSignatures,arginfo_phar__void,        ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
5385     PHP_ME(Phar, interceptFileFuncs,    arginfo_phar__void,        ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
5386     PHP_ME(Phar, isValidPharFilename,   arginfo_phar_isvalidpharfilename, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
5387     PHP_ME(Phar, loadPhar,              arginfo_phar_loadPhar,     ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
5388     PHP_ME(Phar, mapPhar,               arginfo_phar_mapPhar,      ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
5389     PHP_ME(Phar, running,               arginfo_phar_running,      ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
5390     PHP_ME(Phar, mount,                 arginfo_phar_mount,        ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
5391     PHP_ME(Phar, mungServer,            arginfo_phar_mungServer,   ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
5392     PHP_ME(Phar, unlinkArchive,         arginfo_phar_ua,           ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
5393     PHP_ME(Phar, webPhar,               arginfo_phar_webPhar,      ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
5394     PHP_FE_END
5395 };
5396 
5397 ZEND_BEGIN_ARG_INFO_EX(arginfo_entry___construct, 0, 0, 1)
5398 	ZEND_ARG_INFO(0, filename)
5399 ZEND_END_ARG_INFO()
5400 
5401 ZEND_BEGIN_ARG_INFO_EX(arginfo_entry_chmod, 0, 0, 1)
5402 	ZEND_ARG_INFO(0, perms)
5403 ZEND_END_ARG_INFO()
5404 
5405 zend_function_entry php_entry_methods[] = {
5406 	PHP_ME(PharFileInfo, __construct,        arginfo_entry___construct,  ZEND_ACC_PUBLIC)
5407 	PHP_ME(PharFileInfo, __destruct,         arginfo_phar__void,         ZEND_ACC_PUBLIC)
5408 	PHP_ME(PharFileInfo, chmod,              arginfo_entry_chmod,        ZEND_ACC_PUBLIC)
5409 	PHP_ME(PharFileInfo, compress,           arginfo_phar_comp,          ZEND_ACC_PUBLIC)
5410 	PHP_ME(PharFileInfo, decompress,         arginfo_phar__void,         ZEND_ACC_PUBLIC)
5411 	PHP_ME(PharFileInfo, delMetadata,        arginfo_phar__void,         ZEND_ACC_PUBLIC)
5412 	PHP_ME(PharFileInfo, getCompressedSize,  arginfo_phar__void,         ZEND_ACC_PUBLIC)
5413 	PHP_ME(PharFileInfo, getCRC32,           arginfo_phar__void,         ZEND_ACC_PUBLIC)
5414 	PHP_ME(PharFileInfo, getContent,         arginfo_phar__void,         ZEND_ACC_PUBLIC)
5415 	PHP_ME(PharFileInfo, getMetadata,        arginfo_phar__void,         ZEND_ACC_PUBLIC)
5416 	PHP_ME(PharFileInfo, getPharFlags,       arginfo_phar__void,         ZEND_ACC_PUBLIC)
5417 	PHP_ME(PharFileInfo, hasMetadata,        arginfo_phar__void,         ZEND_ACC_PUBLIC)
5418 	PHP_ME(PharFileInfo, isCompressed,       arginfo_phar_compo,         ZEND_ACC_PUBLIC)
5419 	PHP_ME(PharFileInfo, isCRCChecked,       arginfo_phar__void,         ZEND_ACC_PUBLIC)
5420 	PHP_ME(PharFileInfo, setMetadata,        arginfo_phar_setMetadata,   ZEND_ACC_PUBLIC)
5421 	PHP_FE_END
5422 };
5423 
5424 zend_function_entry phar_exception_methods[] = {
5425 	PHP_FE_END
5426 };
5427 /* }}} */
5428 
5429 #define REGISTER_PHAR_CLASS_CONST_LONG(class_name, const_name, value) \
5430 	zend_declare_class_constant_long(class_name, const_name, sizeof(const_name)-1, (zend_long)value);
5431 
phar_object_init(void)5432 void phar_object_init(void) /* {{{ */
5433 {
5434 	zend_class_entry ce;
5435 
5436 	INIT_CLASS_ENTRY(ce, "PharException", phar_exception_methods);
5437 	phar_ce_PharException = zend_register_internal_class_ex(&ce, zend_ce_exception);
5438 
5439 	INIT_CLASS_ENTRY(ce, "Phar", php_archive_methods);
5440 	phar_ce_archive = zend_register_internal_class_ex(&ce, spl_ce_RecursiveDirectoryIterator);
5441 
5442 	zend_class_implements(phar_ce_archive, 2, spl_ce_Countable, zend_ce_arrayaccess);
5443 
5444 	INIT_CLASS_ENTRY(ce, "PharData", php_data_methods);
5445 	phar_ce_data = zend_register_internal_class_ex(&ce, spl_ce_RecursiveDirectoryIterator);
5446 
5447 	zend_class_implements(phar_ce_data, 2, spl_ce_Countable, zend_ce_arrayaccess);
5448 
5449 	INIT_CLASS_ENTRY(ce, "PharFileInfo", php_entry_methods);
5450 	phar_ce_entry = zend_register_internal_class_ex(&ce, spl_ce_SplFileInfo);
5451 
5452 	REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "BZ2", PHAR_ENT_COMPRESSED_BZ2)
5453 	REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "GZ", PHAR_ENT_COMPRESSED_GZ)
5454 	REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "NONE", PHAR_ENT_COMPRESSED_NONE)
5455 	REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "PHAR", PHAR_FORMAT_PHAR)
5456 	REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "TAR", PHAR_FORMAT_TAR)
5457 	REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "ZIP", PHAR_FORMAT_ZIP)
5458 	REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "COMPRESSED", PHAR_ENT_COMPRESSION_MASK)
5459 	REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "PHP", PHAR_MIME_PHP)
5460 	REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "PHPS", PHAR_MIME_PHPS)
5461 	REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "MD5", PHAR_SIG_MD5)
5462 	REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "OPENSSL", PHAR_SIG_OPENSSL)
5463 	REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "SHA1", PHAR_SIG_SHA1)
5464 	REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "SHA256", PHAR_SIG_SHA256)
5465 	REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "SHA512", PHAR_SIG_SHA512)
5466 }
5467 /* }}} */
5468 
5469 /*
5470  * Local variables:
5471  * tab-width: 4
5472  * c-basic-offset: 4
5473  * End:
5474  * vim600: noet sw=4 ts=4 fdm=marker
5475  * vim<600: noet sw=4 ts=4
5476  */
5477