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