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