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