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