php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
phar.c
Go to the documentation of this file.
1/*
2 +----------------------------------------------------------------------+
3 | phar php single-file executable PHP extension |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 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 | https://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#define PHAR_MAIN 1
21#include "phar_internal.h"
22#include "php_phar.h"
23#include "SAPI.h"
24#include "func_interceptors.h"
25#include "ext/standard/crc32.h"
27#include "ext/standard/php_string.h" /* For php_stristr() */
28#include "ext/standard/info.h"
29#include "zend_smart_str.h"
30
31static void destroy_phar_data(zval *zv);
32
34static zend_string *(*phar_save_resolve_path)(zend_string *filename);
35
39static int phar_set_writeable_bit(zval *zv, void *argument) /* {{{ */
40{
41 bool keep = *(bool *)argument;
43
44 if (!phar->is_data) {
45 phar->is_writeable = !keep;
46 }
47
49}
50/* }}} */
51
52/* if the original value is 0 (disabled), then allow setting/unsetting at will. Otherwise only allow 1 (enabled), and error on disabling */
53ZEND_INI_MH(phar_ini_modify_handler) /* {{{ */
54{
55 bool old, ini;
56
57 if (ZSTR_LEN(entry->name) == sizeof("phar.readonly")-1) {
58 old = PHAR_G(readonly_orig);
59 } else {
61 }
62
64
65 /* do not allow unsetting in runtime */
66 if (stage == ZEND_INI_STAGE_STARTUP) {
67 if (ZSTR_LEN(entry->name) == sizeof("phar.readonly")-1) {
69 } else {
71 }
72 } else if (old && !ini) {
73 return FAILURE;
74 }
75
76 if (ZSTR_LEN(entry->name) == sizeof("phar.readonly")-1) {
79 zend_hash_apply_with_argument(&(PHAR_G(phar_fname_map)), phar_set_writeable_bit, (void *)&ini);
80 }
81 } else {
83 }
84
85 return SUCCESS;
86}
87/* }}}*/
88
89/* this global stores the global cached pre-parsed manifests */
92
93static void phar_split_cache_list(void) /* {{{ */
94{
95 char *tmp;
96 char *key, *lasts, *end;
97 char ds[2];
99 uint32_t i = 0;
100
101 if (!PHAR_G(cache_list) || !(PHAR_G(cache_list)[0])) {
102 return;
103 }
104
105 ds[0] = DEFAULT_DIR_SEPARATOR;
106 ds[1] = '\0';
107 tmp = estrdup(PHAR_G(cache_list));
108
109 /* fake request startup */
110 PHAR_G(request_init) = 1;
112 EG(regular_list).nNextFreeElement=1; /* we don't want resource id 0 */
113
114 PHAR_G(has_bz2) = zend_hash_str_exists(&module_registry, "bz2", sizeof("bz2")-1);
115 PHAR_G(has_zlib) = zend_hash_str_exists(&module_registry, "zlib", sizeof("zlib")-1);
116 /* these two are dummies and will be destroyed later */
117 zend_hash_init(&cached_phars, sizeof(phar_archive_data*), zend_get_hash_value, destroy_phar_data, 1);
118 zend_hash_init(&cached_alias, sizeof(phar_archive_data*), zend_get_hash_value, NULL, 1);
119 /* these two are real and will be copied over cached_phars/cached_alias later */
120 zend_hash_init(&(PHAR_G(phar_fname_map)), sizeof(phar_archive_data*), zend_get_hash_value, destroy_phar_data, 1);
121 zend_hash_init(&(PHAR_G(phar_alias_map)), sizeof(phar_archive_data*), zend_get_hash_value, NULL, 1);
123 PHAR_G(persist) = 1;
124
125 for (key = php_strtok_r(tmp, ds, &lasts);
126 key;
127 key = php_strtok_r(NULL, ds, &lasts)) {
128 size_t len;
130 if (end) {
131 len = end - key;
132 } else {
133 len = strlen(key);
134 }
135
136 if (SUCCESS == phar_open_from_filename(key, len, NULL, 0, 0, &phar, NULL)) {
137 phar->phar_pos = i++;
138 php_stream_close(phar->fp);
139 phar->fp = NULL;
140 } else {
141 PHAR_G(persist) = 0;
143 efree(tmp);
151 memset(&EG(regular_list), 0, sizeof(HashTable));
152 /* free cached manifests */
153 PHAR_G(request_init) = 0;
154 return;
155 }
156 }
157
158 PHAR_G(persist) = 0;
159 PHAR_G(request_init) = 0;
160 /* destroy dummy values from before */
168 memset(&EG(regular_list), 0, sizeof(HashTable));
169 efree(tmp);
170}
171/* }}} */
172
173ZEND_INI_MH(phar_ini_cache_list) /* {{{ */
174{
175 PHAR_G(cache_list) = ZSTR_VAL(new_value);
176
177 if (stage == ZEND_INI_STAGE_STARTUP) {
178 phar_split_cache_list();
179 }
180
181 return SUCCESS;
182}
183/* }}} */
184
186 STD_PHP_INI_BOOLEAN("phar.readonly", "1", PHP_INI_ALL, phar_ini_modify_handler, readonly, zend_phar_globals, phar_globals)
187 STD_PHP_INI_BOOLEAN("phar.require_hash", "1", PHP_INI_ALL, phar_ini_modify_handler, require_hash, zend_phar_globals, phar_globals)
188 STD_PHP_INI_ENTRY("phar.cache_list", "", PHP_INI_SYSTEM, phar_ini_cache_list, cache_list, zend_phar_globals, phar_globals)
190
196{
197 if (phar->alias && phar->alias != phar->fname) {
198 pefree(phar->alias, phar->is_persistent);
199 phar->alias = NULL;
200 }
201
202 if (phar->fname) {
203 pefree(phar->fname, phar->is_persistent);
204 phar->fname = NULL;
205 }
206
207 if (phar->signature) {
208 pefree(phar->signature, phar->is_persistent);
209 phar->signature = NULL;
210 }
211
212 if (HT_IS_INITIALIZED(&phar->manifest)) {
213 zend_hash_destroy(&phar->manifest);
214 HT_INVALIDATE(&phar->manifest);
215 }
216
217 if (HT_IS_INITIALIZED(&phar->mounted_dirs)) {
218 zend_hash_destroy(&phar->mounted_dirs);
219 HT_INVALIDATE(&phar->mounted_dirs);
220 }
221
222 if (HT_IS_INITIALIZED(&phar->virtual_dirs)) {
223 zend_hash_destroy(&phar->virtual_dirs);
224 HT_INVALIDATE(&phar->virtual_dirs);
225 }
226
227 phar_metadata_tracker_free(&phar->metadata_tracker, phar->is_persistent);
228
229 if (phar->fp) {
230 php_stream_close(phar->fp);
231 phar->fp = 0;
232 }
233
234 if (phar->ufp) {
235 php_stream_close(phar->ufp);
236 phar->ufp = 0;
237 }
238
239 pefree(phar, phar->is_persistent);
240}
241/* }}}*/
242
247{
248 if (phar->is_persistent) {
249 return 0;
250 }
251
252 if (--phar->refcount < 0) {
256 }
257 return 1;
258 } else if (!phar->refcount) {
259 /* invalidate phar cache */
262
263 if (phar->fp && (!(phar->flags & PHAR_FILE_COMPRESSION_MASK) || !phar->alias)) {
264 /* close open file handle - allows removal or rename of
265 the file on windows, which has greedy locking
266 only close if the archive was not already compressed. If it
267 was compressed, then the fp does not refer to the original file.
268 We're also closing compressed files to save resources,
269 but only if the archive isn't aliased. */
270 php_stream_close(phar->fp);
271 phar->fp = NULL;
272 }
273
274 if (!zend_hash_num_elements(&phar->manifest)) {
275 /* this is a new phar that has perhaps had an alias/metadata set, but has never
276 been flushed */
277 if (zend_hash_str_del(&(PHAR_G(phar_fname_map)), phar->fname, phar->fname_len) != SUCCESS) {
279 }
280 return 1;
281 }
282 }
283 return 0;
284}
285/* }}}*/
286
290static void destroy_phar_data_only(zval *zv) /* {{{ */
291{
293
294 if (EG(exception) || --phar_data->refcount < 0) {
295 phar_destroy_phar_data(phar_data);
296 }
297}
298/* }}}*/
299
303static int phar_unalias_apply(zval *zv, void *argument) /* {{{ */
304{
306}
307/* }}} */
308
312static int phar_tmpclose_apply(zval *zv) /* {{{ */
313{
315
316 if (entry->fp_type != PHAR_TMP) {
318 }
319
320 if (entry->fp && !entry->fp_refcount) {
321 php_stream_close(entry->fp);
322 entry->fp = NULL;
323 }
324
326}
327/* }}} */
328
332static void destroy_phar_data(zval *zv) /* {{{ */
333{
335
336 if (PHAR_G(request_ends)) {
337 /* first, iterate over the manifest and close all PHAR_TMP entry fp handles,
338 this prevents unnecessary unfreed stream resources */
339 zend_hash_apply(&(phar_data->manifest), phar_tmpclose_apply);
340 destroy_phar_data_only(zv);
341 return;
342 }
343
344 zend_hash_apply_with_argument(&(PHAR_G(phar_alias_map)), phar_unalias_apply, phar_data);
345
346 if (--phar_data->refcount < 0) {
347 phar_destroy_phar_data(phar_data);
348 }
349}
350/* }}}*/
351
356{
357
358 if (entry->cfp) {
359 php_stream_close(entry->cfp);
360 entry->cfp = 0;
361 }
362
363 if (entry->fp) {
364 php_stream_close(entry->fp);
365 entry->fp = 0;
366 }
367
369
370 pefree(entry->filename, entry->is_persistent);
371
372 if (entry->link) {
373 pefree(entry->link, entry->is_persistent);
374 entry->link = 0;
375 }
376
377 if (entry->tmp) {
378 pefree(entry->tmp, entry->is_persistent);
379 entry->tmp = 0;
380 }
381}
382/* }}} */
383
385{
386 phar_entry_info *entry = Z_PTR_P(zv);
388 pefree(entry, entry->is_persistent);
389}
390/* }}} */
391
392void phar_entry_delref(phar_entry_data *idata) /* {{{ */
393{
394 if (idata->internal_file && !idata->internal_file->is_persistent) {
395 if (--idata->internal_file->fp_refcount < 0) {
396 idata->internal_file->fp_refcount = 0;
397 }
398
399 if (idata->fp && idata->fp != idata->phar->fp && idata->fp != idata->phar->ufp && idata->fp != idata->internal_file->fp) {
400 php_stream_close(idata->fp);
401 }
402 /* if phar_get_or_create_entry_data returns a sub-directory, we have to free it */
403 if (idata->internal_file->is_temp_dir) {
405 efree(idata->internal_file);
406 }
407 }
408
410 efree(idata);
411}
412/* }}} */
413
417void phar_entry_remove(phar_entry_data *idata, char **error) /* {{{ */
418{
419 phar_archive_data *phar;
420
421 phar = idata->phar;
422
423 if (idata->internal_file->fp_refcount < 2) {
424 if (idata->fp && idata->fp != idata->phar->fp && idata->fp != idata->phar->ufp && idata->fp != idata->internal_file->fp) {
425 php_stream_close(idata->fp);
426 }
428 idata->phar->refcount--;
429 efree(idata);
430 } else {
431 idata->internal_file->is_deleted = 1;
432 phar_entry_delref(idata);
433 }
434
435 if (!phar->donotflush) {
436 phar_flush(phar, error);
437 }
438}
439/* }}} */
440
441#define MAPPHAR_ALLOC_FAIL(msg) \
442 if (fp) {\
443 php_stream_close(fp);\
444 }\
445 if (error) {\
446 spprintf(error, 0, msg, fname);\
447 }\
448 return FAILURE;
449
450#define MAPPHAR_FAIL(msg) \
451 efree(savebuf);\
452 if (mydata) {\
453 phar_destroy_phar_data(mydata);\
454 }\
455 if (signature) {\
456 pefree(signature, PHAR_G(persist));\
457 }\
458 MAPPHAR_ALLOC_FAIL(msg)
459
460#ifdef WORDS_BIGENDIAN
461# define PHAR_GET_32(buffer, var) \
462 var = ((uint32_t)(((unsigned char*)(buffer))[3]) << 24) \
463 | ((uint32_t)(((unsigned char*)(buffer))[2]) << 16) \
464 | ((uint32_t)(((unsigned char*)(buffer))[1]) << 8) \
465 | ((uint32_t)((unsigned char*)(buffer))[0]); \
466 (buffer) += 4
467# define PHAR_GET_16(buffer, var) \
468 var = ((uint16_t)(((unsigned char*)(buffer))[1]) << 8) \
469 | ((uint16_t)((unsigned char*)(buffer))[0]); \
470 (buffer) += 2
471#else
472# define PHAR_GET_32(buffer, var) \
473 memcpy(&var, buffer, sizeof(var)); \
474 buffer += 4
475# define PHAR_GET_16(buffer, var) \
476 var = *(uint16_t*)(buffer); \
477 buffer += 2
478#endif
479#define PHAR_ZIP_16(var) ((uint16_t)((((uint16_t)var[0]) & 0xff) | \
480 (((uint16_t)var[1]) & 0xff) << 8))
481#define PHAR_ZIP_32(var) ((uint32_t)((((uint32_t)var[0]) & 0xff) | \
482 (((uint32_t)var[1]) & 0xff) << 8 | \
483 (((uint32_t)var[2]) & 0xff) << 16 | \
484 (((uint32_t)var[3]) & 0xff) << 24))
485
489static zend_result phar_open_parsed_phar(char *fname, size_t fname_len, char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data** pphar, char **error) /* {{{ */
490{
491 phar_archive_data *phar;
492#ifdef PHP_WIN32
493 char *save_fname;
494 ALLOCA_FLAG(fname_use_heap)
495#endif
496
497 if (error) {
498 *error = NULL;
499 }
500#ifdef PHP_WIN32
501 save_fname = fname;
502 if (memchr(fname, '\\', fname_len)) {
503 fname = do_alloca(fname_len + 1, fname_use_heap);
504 memcpy(fname, save_fname, fname_len);
505 fname[fname_len] = '\0';
506 phar_unixify_path_separators(fname, fname_len);
507 }
508#endif
509 if (SUCCESS == phar_get_archive(&phar, fname, fname_len, alias, alias_len, error)
510 && ((alias && fname_len == phar->fname_len
511 && !strncmp(fname, phar->fname, fname_len)) || !alias)
512 ) {
513 phar_entry_info *stub;
514#ifdef PHP_WIN32
515 if (fname != save_fname) {
516 free_alloca(fname, fname_use_heap);
517 fname = save_fname;
518 }
519#endif
520 /* logic above is as follows:
521 If an explicit alias was requested, ensure the filename passed in
522 matches the phar's filename.
523 If no alias was passed in, then it can match either and be valid
524 */
525
526 if (!is_data) {
527 /* prevent any ".phar" without a stub getting through */
528 if (!phar->halt_offset && !phar->is_brandnew && (phar->is_tar || phar->is_zip)) {
529 if (PHAR_G(readonly) && NULL == (stub = zend_hash_str_find_ptr(&(phar->manifest), ".phar/stub.php", sizeof(".phar/stub.php")-1))) {
530 if (error) {
531 spprintf(error, 0, "'%s' is not a phar archive. Use PharData::__construct() for a standard zip or tar archive", fname);
532 }
533 return FAILURE;
534 }
535 }
536 }
537
538 if (pphar) {
539 *pphar = phar;
540 }
541
542 return SUCCESS;
543 } else {
544#ifdef PHP_WIN32
545 if (fname != save_fname) {
546 free_alloca(fname, fname_use_heap);
547 fname = save_fname;
548 }
549#endif
550 if (pphar) {
551 *pphar = NULL;
552 }
553
554 if (phar && error && !(options & REPORT_ERRORS)) {
555 efree(error);
556 }
557
558 return FAILURE;
559 }
560}
561/* }}}*/
562
568{
569 php_serialize_data_t metadata_hash;
570 smart_str metadata_str = {0};
571 if (tracker->str || Z_ISUNDEF(tracker->val)) {
572 /* Already has serialized the value or there is no value */
573 return;
574 }
575 /* Assert it should not be possible to create raw zvals in a persistent phar (i.e. from cache_list) */
577
578 PHP_VAR_SERIALIZE_INIT(metadata_hash);
579 php_var_serialize(&metadata_str, &tracker->val, &metadata_hash);
580 PHP_VAR_SERIALIZE_DESTROY(metadata_hash);
581 if (!metadata_str.s) {
582 return;
583 }
584 tracker->str = metadata_str.s;
585}
586/* }}} */
587
593zend_result phar_metadata_tracker_unserialize_or_copy(phar_metadata_tracker *tracker, zval *metadata, bool persistent, HashTable *unserialize_options, const char* method_name) /* {{{ */
594{
595 const bool has_unserialize_options = unserialize_options != NULL && zend_hash_num_elements(unserialize_options) > 0;
596 /* It should be impossible to create a zval in a persistent phar/entry. */
597 ZEND_ASSERT(!persistent || Z_ISUNDEF(tracker->val));
598
599 if (Z_ISUNDEF(tracker->val) || has_unserialize_options) {
600 if (EG(exception)) {
601 /* Because other parts of the phar code haven't been updated to check for exceptions after doing something that may throw,
602 * check for exceptions before potentially serializing/unserializing instead. */
603 return FAILURE;
604 }
605 /* Persistent phars should always be unserialized. */
606 const char *start;
607 /* Assert it should not be possible to create raw data in a persistent phar (i.e. from cache_list) */
608
609 /* Precondition: This has serialized data, either from setMetadata or the phar file. */
610 ZEND_ASSERT(tracker->str != NULL);
611 ZVAL_NULL(metadata);
612 start = ZSTR_VAL(tracker->str);
613
614 php_unserialize_with_options(metadata, start, ZSTR_LEN(tracker->str), unserialize_options, method_name);
615 if (EG(exception)) {
616 zval_ptr_dtor(metadata);
617 ZVAL_UNDEF(metadata);
618 return FAILURE;
619 }
620 return SUCCESS;
621 } else {
622 /* TODO: what is the current/expected behavior when fetching an object set with setMetadata then getting it
623 * with getMetadata() and modifying a property? Previously, it was underdefined, and probably unimportant to support. */
624 ZVAL_COPY(metadata, &tracker->val);
625 }
626
627 return SUCCESS;
628}
629/* }}}*/
630
635{
636 ZEND_ASSERT(!persistent || Z_ISUNDEF(tracker->val));
637 return !Z_ISUNDEF(tracker->val) || tracker->str != NULL;
638}
639/* }}} */
640
645{
646 /* Free the string before the zval in case the zval's destructor modifies the metadata */
647 if (tracker->str) {
648 zend_string_release(tracker->str);
649 tracker->str = NULL;
650 }
651 if (!Z_ISUNDEF(tracker->val)) {
652 /* Here, copy the original zval to a different pointer without incrementing the refcount in case something uses the original while it's being freed. */
653 zval zval_copy;
654
656 ZVAL_COPY_VALUE(&zval_copy, &tracker->val);
657 ZVAL_UNDEF(&tracker->val);
658 zval_ptr_dtor(&zval_copy);
659 }
660}
661/* }}} */
662
667{
668 ZEND_ASSERT(dest != source);
670
671 if (!Z_ISUNDEF(source->val)) {
673 ZVAL_COPY(&dest->val, &source->val);
674 }
675 if (source->str) {
676 dest->str = zend_string_copy(source->str);
677 }
678}
679/* }}} */
680
685{
686 Z_TRY_ADDREF_P(&tracker->val);
687 if (tracker->str) {
688 /* Duplicate the string, as the original may have been persistent. */
689 tracker->str = zend_string_dup(tracker->str, false);
690 }
691}
692/* }}} */
693
702void phar_parse_metadata_lazy(const char *buffer, phar_metadata_tracker *tracker, uint32_t zip_metadata_len, bool persistent) /* {{{ */
703{
705 if (zip_metadata_len) {
706 /* lazy init metadata */
707 tracker->str = zend_string_init(buffer, zip_metadata_len, persistent);
708 }
709}
710/* }}}*/
711
716#define MANIFEST_FIXED_LEN 18
717
718#define SAFE_PHAR_GET_32(buffer, endbuffer, var) \
719 if (UNEXPECTED(buffer + 4 > endbuffer)) { \
720 MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest header)"); \
721 } \
722 PHAR_GET_32(buffer, var);
723
733static zend_result phar_parse_pharfile(php_stream *fp, char *fname, size_t fname_len, char *alias, size_t alias_len, zend_long halt_offset, phar_archive_data** pphar, uint32_t compression, char **error) /* {{{ */
734{
735 char b32[4], *buffer, *endbuffer, *savebuf;
736 phar_archive_data *mydata = NULL;
737 phar_entry_info entry;
738 uint32_t manifest_len, manifest_count, manifest_flags, manifest_index, tmp_len, sig_flags;
739 uint16_t manifest_ver;
740 uint32_t len;
742 size_t sig_len;
743 int register_alias = 0, temp_alias = 0;
744 char *signature = NULL;
745 zend_string *str;
746
747 if (pphar) {
748 *pphar = NULL;
749 }
750
751 if (error) {
752 *error = NULL;
753 }
754
755 /* check for ?>\n and increment accordingly */
756 if (-1 == php_stream_seek(fp, halt_offset, SEEK_SET)) {
757 MAPPHAR_ALLOC_FAIL("cannot seek to __HALT_COMPILER(); location in phar \"%s\"")
758 }
759
760 buffer = b32;
761
762 if (3 != php_stream_read(fp, buffer, 3)) {
763 MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated manifest at stub end)")
764 }
765
766 if ((*buffer == ' ' || *buffer == '\n') && *(buffer + 1) == '?' && *(buffer + 2) == '>') {
767 int nextchar;
768 halt_offset += 3;
769 if (EOF == (nextchar = php_stream_getc(fp))) {
770 MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated manifest at stub end)")
771 }
772
773 if ((char) nextchar == '\r') {
774 /* if we have an \r we require an \n as well */
775 if (EOF == (nextchar = php_stream_getc(fp)) || (char)nextchar != '\n') {
776 MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated manifest at stub end)")
777 }
778 ++halt_offset;
779 }
780
781 if ((char) nextchar == '\n') {
782 ++halt_offset;
783 }
784 }
785
786 /* make sure we are at the right location to read the manifest */
787 if (-1 == php_stream_seek(fp, halt_offset, SEEK_SET)) {
788 MAPPHAR_ALLOC_FAIL("cannot seek to __HALT_COMPILER(); location in phar \"%s\"")
789 }
790
791 /* read in manifest */
792 buffer = b32;
793
794 if (4 != php_stream_read(fp, buffer, 4)) {
795 MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated manifest at manifest length)")
796 }
797
798 PHAR_GET_32(buffer, manifest_len);
799
800 if (manifest_len > 1048576 * 100) {
801 /* prevent serious memory issues by limiting manifest to at most 100 MB in length */
802 MAPPHAR_ALLOC_FAIL("manifest cannot be larger than 100 MB in phar \"%s\"")
803 }
804
805 buffer = (char *)emalloc(manifest_len);
806 savebuf = buffer;
807 endbuffer = buffer + manifest_len;
808
809 if (manifest_len < MANIFEST_FIXED_LEN || manifest_len != php_stream_read(fp, buffer, manifest_len)) {
810 MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest header)")
811 }
812
813 /* extract the number of entries */
814 SAFE_PHAR_GET_32(buffer, endbuffer, manifest_count);
815
816 if (manifest_count == 0) {
817 MAPPHAR_FAIL("in phar \"%s\", manifest claims to have zero entries. Phars must have at least 1 entry");
818 }
819
820 /* extract API version, lowest nibble currently unused */
821 manifest_ver = (((unsigned char)buffer[0]) << 8)
822 + ((unsigned char)buffer[1]);
823 buffer += 2;
824
825 if ((manifest_ver & PHAR_API_VER_MASK) < PHAR_API_MIN_READ) {
826 efree(savebuf);
828 if (error) {
829 spprintf(error, 0, "phar \"%s\" is API version %1.u.%1.u.%1.u, and cannot be processed", fname, manifest_ver >> 12, (manifest_ver >> 8) & 0xF, (manifest_ver >> 4) & 0x0F);
830 }
831 return FAILURE;
832 }
833
834 SAFE_PHAR_GET_32(buffer, endbuffer, manifest_flags);
835
836 manifest_flags &= ~PHAR_HDR_COMPRESSION_MASK;
837 manifest_flags &= ~PHAR_FILE_COMPRESSION_MASK;
838 /* remember whether this entire phar was compressed with gz/bzip2 */
839 manifest_flags |= compression;
840
841 /* The lowest nibble contains the phar wide flags. The compression flags can */
842 /* be ignored on reading because it is being generated anyways. */
843 if (manifest_flags & PHAR_HDR_SIGNATURE) {
844 char sig_buf[8], *sig_ptr = sig_buf;
845 zend_off_t read_len;
846 size_t end_of_phar;
847
848 if (-1 == php_stream_seek(fp, -8, SEEK_END)
849 || (read_len = php_stream_tell(fp)) < 20
850 || 8 != php_stream_read(fp, sig_buf, 8)
851 || memcmp(sig_buf+4, "GBMB", 4)) {
852 efree(savebuf);
854 if (error) {
855 spprintf(error, 0, "phar \"%s\" has a broken signature", fname);
856 }
857 return FAILURE;
858 }
859
860 PHAR_GET_32(sig_ptr, sig_flags);
861
862 switch(sig_flags) {
865 case PHAR_SIG_OPENSSL: {
866 uint32_t signature_len;
867 char *sig;
868 zend_off_t whence;
869
870 /* we store the signature followed by the signature length */
871 if (-1 == php_stream_seek(fp, -12, SEEK_CUR)
872 || 4 != php_stream_read(fp, sig_buf, 4)) {
873 efree(savebuf);
875 if (error) {
876 spprintf(error, 0, "phar \"%s\" openssl signature length could not be read", fname);
877 }
878 return FAILURE;
879 }
880
881 sig_ptr = sig_buf;
882 PHAR_GET_32(sig_ptr, signature_len);
883 sig = (char *) emalloc(signature_len);
884 whence = signature_len + 4;
885 whence = -whence;
886
887 if (-1 == php_stream_seek(fp, whence, SEEK_CUR)
888 || !(end_of_phar = php_stream_tell(fp))
889 || signature_len != php_stream_read(fp, sig, signature_len)) {
890 efree(savebuf);
891 efree(sig);
893 if (error) {
894 spprintf(error, 0, "phar \"%s\" openssl signature could not be read", fname);
895 }
896 return FAILURE;
897 }
898
899 if (FAILURE == phar_verify_signature(fp, end_of_phar, sig_flags, sig, signature_len, fname, &signature, &sig_len, error)) {
900 efree(savebuf);
901 efree(sig);
903 if (error) {
904 char *save = *error;
905 spprintf(error, 0, "phar \"%s\" openssl signature could not be verified: %s", fname, *error);
906 efree(save);
907 }
908 return FAILURE;
909 }
910 efree(sig);
911 }
912 break;
913 case PHAR_SIG_SHA512: {
914 unsigned char digest[64];
915
916 php_stream_seek(fp, -(8 + 64), SEEK_END);
917 read_len = php_stream_tell(fp);
918
919 if (php_stream_read(fp, (char*)digest, sizeof(digest)) != sizeof(digest)) {
920 efree(savebuf);
922 if (error) {
923 spprintf(error, 0, "phar \"%s\" has a broken signature", fname);
924 }
925 return FAILURE;
926 }
927
928 if (FAILURE == phar_verify_signature(fp, read_len, PHAR_SIG_SHA512, (char *)digest, 64, fname, &signature, &sig_len, error)) {
929 efree(savebuf);
931 if (error) {
932 char *save = *error;
933 spprintf(error, 0, "phar \"%s\" SHA512 signature could not be verified: %s", fname, *error);
934 efree(save);
935 }
936 return FAILURE;
937 }
938 break;
939 }
940 case PHAR_SIG_SHA256: {
941 unsigned char digest[32];
942
943 php_stream_seek(fp, -(8 + 32), SEEK_END);
944 read_len = php_stream_tell(fp);
945
946 if (php_stream_read(fp, (char*)digest, sizeof(digest)) != sizeof(digest)) {
947 efree(savebuf);
949 if (error) {
950 spprintf(error, 0, "phar \"%s\" has a broken signature", fname);
951 }
952 return FAILURE;
953 }
954
955 if (FAILURE == phar_verify_signature(fp, read_len, PHAR_SIG_SHA256, (char *)digest, 32, fname, &signature, &sig_len, error)) {
956 efree(savebuf);
958 if (error) {
959 char *save = *error;
960 spprintf(error, 0, "phar \"%s\" SHA256 signature could not be verified: %s", fname, *error);
961 efree(save);
962 }
963 return FAILURE;
964 }
965 break;
966 }
967 case PHAR_SIG_SHA1: {
968 unsigned char digest[20];
969
970 php_stream_seek(fp, -(8 + 20), SEEK_END);
971 read_len = php_stream_tell(fp);
972
973 if (php_stream_read(fp, (char*)digest, sizeof(digest)) != sizeof(digest)) {
974 efree(savebuf);
976 if (error) {
977 spprintf(error, 0, "phar \"%s\" has a broken signature", fname);
978 }
979 return FAILURE;
980 }
981
982 if (FAILURE == phar_verify_signature(fp, read_len, PHAR_SIG_SHA1, (char *)digest, 20, fname, &signature, &sig_len, error)) {
983 efree(savebuf);
985 if (error) {
986 char *save = *error;
987 spprintf(error, 0, "phar \"%s\" SHA1 signature could not be verified: %s", fname, *error);
988 efree(save);
989 }
990 return FAILURE;
991 }
992 break;
993 }
994 case PHAR_SIG_MD5: {
995 unsigned char digest[16];
996
997 php_stream_seek(fp, -(8 + 16), SEEK_END);
998 read_len = php_stream_tell(fp);
999
1000 if (php_stream_read(fp, (char*)digest, sizeof(digest)) != sizeof(digest)) {
1001 efree(savebuf);
1002 php_stream_close(fp);
1003 if (error) {
1004 spprintf(error, 0, "phar \"%s\" has a broken signature", fname);
1005 }
1006 return FAILURE;
1007 }
1008
1009 if (FAILURE == phar_verify_signature(fp, read_len, PHAR_SIG_MD5, (char *)digest, 16, fname, &signature, &sig_len, error)) {
1010 efree(savebuf);
1011 php_stream_close(fp);
1012 if (error) {
1013 char *save = *error;
1014 spprintf(error, 0, "phar \"%s\" MD5 signature could not be verified: %s", fname, *error);
1015 efree(save);
1016 }
1017 return FAILURE;
1018 }
1019 break;
1020 }
1021 default:
1022 efree(savebuf);
1023 php_stream_close(fp);
1024
1025 if (error) {
1026 spprintf(error, 0, "phar \"%s\" has a broken or unsupported signature", fname);
1027 }
1028 return FAILURE;
1029 }
1030 } else if (PHAR_G(require_hash)) {
1031 efree(savebuf);
1032 php_stream_close(fp);
1033
1034 if (error) {
1035 spprintf(error, 0, "phar \"%s\" does not have a signature", fname);
1036 }
1037 return FAILURE;
1038 } else {
1039 sig_flags = 0;
1040 sig_len = 0;
1041 }
1042
1043 /* extract alias */
1044 SAFE_PHAR_GET_32(buffer, endbuffer, tmp_len);
1045
1046 if (buffer + tmp_len > endbuffer) {
1047 MAPPHAR_FAIL("internal corruption of phar \"%s\" (buffer overrun)");
1048 }
1049
1050 if (manifest_len < MANIFEST_FIXED_LEN + tmp_len) {
1051 MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest header)")
1052 }
1053
1054 /* tmp_len = 0 says alias length is 0, which means the alias is not stored in the phar */
1055 if (tmp_len) {
1056 /* if the alias is stored we enforce it (implicit overrides explicit) */
1057 if (alias && alias_len && (alias_len != tmp_len || strncmp(alias, buffer, tmp_len)))
1058 {
1059 php_stream_close(fp);
1060
1061 if (signature) {
1062 efree(signature);
1063 }
1064
1065 if (error) {
1066 spprintf(error, 0, "cannot load phar \"%s\" with implicit alias \"%.*s\" under different alias \"%s\"", fname, tmp_len, buffer, alias);
1067 }
1068
1069 efree(savebuf);
1070 return FAILURE;
1071 }
1072
1073 alias_len = tmp_len;
1074 alias = buffer;
1075 buffer += tmp_len;
1076 register_alias = 1;
1077 } else if (!alias_len || !alias) {
1078 /* if we neither have an explicit nor an implicit alias, we use the filename */
1079 alias = NULL;
1080 alias_len = 0;
1081 register_alias = 0;
1082 } else if (alias_len) {
1083 register_alias = 1;
1084 temp_alias = 1;
1085 }
1086
1087 /* we have 5 32-bit items plus 1 byte at least */
1088 if (manifest_count > ((manifest_len - MANIFEST_FIXED_LEN - tmp_len) / (5 * 4 + 1))) {
1089 /* prevent serious memory issues */
1090 MAPPHAR_FAIL("internal corruption of phar \"%s\" (too many manifest entries for size of manifest)")
1091 }
1092
1093 mydata = pecalloc(1, sizeof(phar_archive_data), PHAR_G(persist));
1094 mydata->is_persistent = PHAR_G(persist);
1095 HT_INVALIDATE(&mydata->manifest);
1096 HT_INVALIDATE(&mydata->mounted_dirs);
1097 HT_INVALIDATE(&mydata->virtual_dirs);
1098
1099 /* check whether we have meta data, zero check works regardless of byte order */
1100 SAFE_PHAR_GET_32(buffer, endbuffer, len);
1101 if (mydata->is_persistent) {
1102 if (!len) {
1103 /* FIXME: not sure why this is needed but removing it breaks tests */
1104 SAFE_PHAR_GET_32(buffer, endbuffer, len);
1105 }
1106 }
1107 if(len > (size_t)(endbuffer - buffer)) {
1108 MAPPHAR_FAIL("internal corruption of phar \"%s\" (trying to read past buffer end)");
1109 }
1110 /* Don't implicitly call unserialize() on potentially untrusted input unless getMetadata() is called directly. */
1112 buffer += len;
1113
1114 /* set up our manifest */
1115 zend_hash_init(&mydata->manifest, manifest_count,
1116 zend_get_hash_value, destroy_phar_manifest_entry, (bool)mydata->is_persistent);
1117 zend_hash_init(&mydata->mounted_dirs, 5,
1118 zend_get_hash_value, NULL, (bool)mydata->is_persistent);
1119 zend_hash_init(&mydata->virtual_dirs, manifest_count * 2,
1120 zend_get_hash_value, NULL, (bool)mydata->is_persistent);
1121 mydata->fname = pestrndup(fname, fname_len, mydata->is_persistent);
1122#ifdef PHP_WIN32
1123 phar_unixify_path_separators(mydata->fname, fname_len);
1124#endif
1125 mydata->fname_len = fname_len;
1126 offset = halt_offset + manifest_len + 4;
1127 memset(&entry, 0, sizeof(phar_entry_info));
1128 entry.phar = mydata;
1129 entry.fp_type = PHAR_FP;
1130 entry.is_persistent = mydata->is_persistent;
1131
1132 for (manifest_index = 0; manifest_index < manifest_count; ++manifest_index) {
1133 if (buffer + 28 > endbuffer) {
1134 MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest entry)")
1135 }
1136
1138
1139 if (entry.filename_len == 0) {
1140 MAPPHAR_FAIL("zero-length filename encountered in phar \"%s\"");
1141 }
1142
1143 if (entry.is_persistent) {
1144 entry.manifest_pos = manifest_index;
1145 }
1146
1147 if (entry.filename_len > (size_t)(endbuffer - buffer - 24)) {
1148 MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest entry)");
1149 }
1150
1151 if ((manifest_ver & PHAR_API_VER_MASK) >= PHAR_API_MIN_DIR && buffer[entry.filename_len - 1] == '/') {
1152 entry.is_dir = 1;
1153 } else {
1154 entry.is_dir = 0;
1155 }
1156
1158 entry.filename = pestrndup(buffer, entry.filename_len, entry.is_persistent);
1159 buffer += entry.filename_len;
1162
1163 if (offset == halt_offset + manifest_len + 4) {
1164 mydata->min_timestamp = entry.timestamp;
1165 mydata->max_timestamp = entry.timestamp;
1166 } else {
1167 if (mydata->min_timestamp > entry.timestamp) {
1168 mydata->min_timestamp = entry.timestamp;
1169 } else if (mydata->max_timestamp < entry.timestamp) {
1170 mydata->max_timestamp = entry.timestamp;
1171 }
1172 }
1173
1175 PHAR_GET_32(buffer, entry.crc32);
1176 PHAR_GET_32(buffer, entry.flags);
1177
1178 if (entry.is_dir) {
1179 entry.filename_len--;
1181 }
1182
1184 if (len > (size_t)(endbuffer - buffer)) {
1185 pefree(entry.filename, entry.is_persistent);
1186 MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest entry)");
1187 }
1188 /* Don't implicitly call unserialize() on potentially untrusted input unless getMetadata() is called directly. */
1189 /* The same local variable entry is reused in a loop, so reset the state before reading data. */
1191 entry.metadata_tracker.str = NULL;
1193 buffer += len;
1194
1195 entry.offset = entry.offset_abs = offset;
1196 offset += entry.compressed_filesize;
1197
1198 switch (entry.flags & PHAR_ENT_COMPRESSION_MASK) {
1200 if (!PHAR_G(has_zlib)) {
1202 pefree(entry.filename, entry.is_persistent);
1203 MAPPHAR_FAIL("zlib extension is required for gz compressed .phar file \"%s\"");
1204 }
1205 break;
1207 if (!PHAR_G(has_bz2)) {
1209 pefree(entry.filename, entry.is_persistent);
1210 MAPPHAR_FAIL("bz2 extension is required for bzip2 compressed .phar file \"%s\"");
1211 }
1212 break;
1213 default:
1214 if (entry.uncompressed_filesize != entry.compressed_filesize) {
1216 pefree(entry.filename, entry.is_persistent);
1217 MAPPHAR_FAIL("internal corruption of phar \"%s\" (compressed and uncompressed size does not match for uncompressed entry)");
1218 }
1219 break;
1220 }
1221
1222 manifest_flags |= (entry.flags & PHAR_ENT_COMPRESSION_MASK);
1223 /* if signature matched, no need to check CRC32 for each file */
1224 entry.is_crc_checked = (manifest_flags & PHAR_HDR_SIGNATURE ? 1 : 0);
1225 phar_set_inode(&entry);
1226 if (mydata->is_persistent) {
1227 str = zend_string_init_interned(entry.filename, entry.filename_len, 1);
1228 } else {
1229 str = zend_string_init(entry.filename, entry.filename_len, 0);
1230 }
1231 zend_hash_add_mem(&mydata->manifest, str, (void*)&entry, sizeof(phar_entry_info));
1232 zend_string_release(str);
1233 }
1234
1235 snprintf(mydata->version, sizeof(mydata->version), "%u.%u.%u", manifest_ver >> 12, (manifest_ver >> 8) & 0xF, (manifest_ver >> 4) & 0xF);
1236 mydata->halt_offset = halt_offset;
1237 mydata->flags = manifest_flags;
1238 endbuffer = strrchr(mydata->fname, '/');
1239
1240 if (endbuffer) {
1241 mydata->ext = memchr(endbuffer, '.', (mydata->fname + fname_len) - endbuffer);
1242 if (mydata->ext == endbuffer) {
1243 mydata->ext = memchr(endbuffer + 1, '.', (mydata->fname + fname_len) - endbuffer - 1);
1244 }
1245 if (mydata->ext) {
1246 mydata->ext_len = (mydata->fname + mydata->fname_len) - mydata->ext;
1247 }
1248 }
1249
1250 mydata->alias = alias ?
1251 pestrndup(alias, alias_len, mydata->is_persistent) :
1252 pestrndup(mydata->fname, fname_len, mydata->is_persistent);
1253 mydata->alias_len = alias ? alias_len : fname_len;
1254 mydata->sig_flags = sig_flags;
1255 mydata->fp = fp;
1256 mydata->sig_len = sig_len;
1257 mydata->signature = signature;
1259
1260 if (register_alias) {
1261 phar_archive_data *fd_ptr;
1262
1263 mydata->is_temporary_alias = temp_alias;
1264
1265 if (!phar_validate_alias(mydata->alias, mydata->alias_len)) {
1266 signature = NULL;
1267 fp = NULL;
1268 MAPPHAR_FAIL("Cannot open archive \"%s\", invalid alias");
1269 }
1270
1271 if (NULL != (fd_ptr = zend_hash_str_find_ptr(&(PHAR_G(phar_alias_map)), alias, alias_len))) {
1272 if (SUCCESS != phar_free_alias(fd_ptr, alias, alias_len)) {
1273 signature = NULL;
1274 fp = NULL;
1275 MAPPHAR_FAIL("Cannot open archive \"%s\", alias is already in use by existing archive");
1276 }
1277 }
1278
1279 if (mydata->is_persistent) {
1280 str = zend_string_init_interned(alias, alias_len, 1);
1281 } else {
1282 str = zend_string_init(alias, alias_len, 0);
1283 }
1284 zend_hash_add_ptr(&(PHAR_G(phar_alias_map)), str, mydata);
1285 zend_string_release(str);
1286 } else {
1287 mydata->is_temporary_alias = 1;
1288 }
1289
1290 if (mydata->is_persistent) {
1291 str = zend_string_init_interned(mydata->fname, fname_len, 1);
1292 } else {
1293 str = zend_string_init(mydata->fname, fname_len, 0);
1294 }
1295 zend_hash_add_ptr(&(PHAR_G(phar_fname_map)), str, mydata);
1296 zend_string_release(str);
1297 efree(savebuf);
1298
1299 if (pphar) {
1300 *pphar = mydata;
1301 }
1302
1303 return SUCCESS;
1304}
1305/* }}} */
1306
1310zend_result phar_open_or_create_filename(char *fname, size_t fname_len, char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data** pphar, char **error) /* {{{ */
1311{
1312 const char *ext_str, *z;
1313 char *my_error;
1314 size_t ext_len;
1315 phar_archive_data **test, *unused = NULL;
1316
1317 test = &unused;
1318
1319 if (error) {
1320 *error = NULL;
1321 }
1322
1323 /* first try to open an existing file */
1324 if (phar_detect_phar_fname_ext(fname, fname_len, &ext_str, &ext_len, !is_data, 0, 1) == SUCCESS) {
1325 goto check_file;
1326 }
1327
1328 /* next try to create a new file */
1329 if (FAILURE == phar_detect_phar_fname_ext(fname, fname_len, &ext_str, &ext_len, !is_data, 1, 1)) {
1330 if (error) {
1331 if (ext_len == -2) {
1332 spprintf(error, 0, "Cannot create a phar archive from a URL like \"%s\". Phar objects can only be created from local files", fname);
1333 } else {
1334 spprintf(error, 0, "Cannot create phar '%s', file extension (or combination) not recognised or the directory does not exist", fname);
1335 }
1336 }
1337 return FAILURE;
1338 }
1339check_file:
1340 if (phar_open_parsed_phar(fname, fname_len, alias, alias_len, is_data, options, test, &my_error) == SUCCESS) {
1341 if (pphar) {
1342 *pphar = *test;
1343 }
1344
1345 if ((*test)->is_data && !(*test)->is_tar && !(*test)->is_zip) {
1346 if (error) {
1347 spprintf(error, 0, "Cannot open '%s' as a PharData object. Use Phar::__construct() for executable archives", fname);
1348 }
1349 return FAILURE;
1350 }
1351
1352 if (PHAR_G(readonly) && !(*test)->is_data && ((*test)->is_tar || (*test)->is_zip)) {
1353 phar_entry_info *stub;
1354 if (NULL == (stub = zend_hash_str_find_ptr(&((*test)->manifest), ".phar/stub.php", sizeof(".phar/stub.php")-1))) {
1355 spprintf(error, 0, "'%s' is not a phar archive. Use PharData::__construct() for a standard zip or tar archive", fname);
1356 return FAILURE;
1357 }
1358 }
1359
1360 if (!PHAR_G(readonly) || (*test)->is_data) {
1361 (*test)->is_writeable = 1;
1362 }
1363 return SUCCESS;
1364 } else if (my_error) {
1365 if (error) {
1366 *error = my_error;
1367 } else {
1368 efree(my_error);
1369 }
1370 return FAILURE;
1371 }
1372
1373 if (ext_len > 3 && (z = memchr(ext_str, 'z', ext_len)) && ((ext_str + ext_len) - z >= 2) && !memcmp(z + 1, "ip", 2)) {
1374 /* assume zip-based phar */
1375 return phar_open_or_create_zip(fname, fname_len, alias, alias_len, is_data, options, pphar, error);
1376 }
1377
1378 if (ext_len > 3 && (z = memchr(ext_str, 't', ext_len)) && ((ext_str + ext_len) - z >= 2) && !memcmp(z + 1, "ar", 2)) {
1379 /* assume tar-based phar */
1380 return phar_open_or_create_tar(fname, fname_len, alias, alias_len, is_data, options, pphar, error);
1381 }
1382
1383 return phar_create_or_parse_filename(fname, fname_len, alias, alias_len, is_data, options, pphar, error);
1384}
1385/* }}} */
1386
1387static zend_result phar_open_from_fp(php_stream* fp, char *fname, size_t fname_len, char *alias, size_t alias_len, uint32_t options, phar_archive_data** pphar, char **error);
1388
1389zend_result phar_create_or_parse_filename(char *fname, size_t fname_len, char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data** pphar, char **error) /* {{{ */
1390{
1391 phar_archive_data *mydata;
1392 php_stream *fp;
1393 zend_string *actual = NULL;
1394 char *p;
1395
1396 if (!pphar) {
1397 pphar = &mydata;
1398 }
1399 if (php_check_open_basedir(fname)) {
1400 return FAILURE;
1401 }
1402
1403 /* first open readonly so it won't be created if not present */
1404 fp = php_stream_open_wrapper(fname, "rb", IGNORE_URL|STREAM_MUST_SEEK|0, &actual);
1405
1406 if (actual) {
1407 fname = ZSTR_VAL(actual);
1408 fname_len = ZSTR_LEN(actual);
1409 }
1410
1411 if (fp) {
1412 if (phar_open_from_fp(fp, fname, fname_len, alias, alias_len, options, pphar, error) == SUCCESS) {
1413 if ((*pphar)->is_data || !PHAR_G(readonly)) {
1414 (*pphar)->is_writeable = 1;
1415 }
1416 if (actual) {
1417 zend_string_release_ex(actual, 0);
1418 }
1419 return SUCCESS;
1420 } else {
1421 /* file exists, but is either corrupt or not a phar archive */
1422 if (actual) {
1423 zend_string_release_ex(actual, 0);
1424 }
1425 return FAILURE;
1426 }
1427 }
1428
1429 if (actual) {
1430 zend_string_release_ex(actual, 0);
1431 }
1432
1433 if (PHAR_G(readonly) && !is_data) {
1434 if (options & REPORT_ERRORS) {
1435 if (error) {
1436 spprintf(error, 0, "creating archive \"%s\" disabled by the php.ini setting phar.readonly", fname);
1437 }
1438 }
1439 return FAILURE;
1440 }
1441
1442 /* set up our manifest */
1443 mydata = ecalloc(1, sizeof(phar_archive_data));
1444 mydata->fname = expand_filepath(fname, NULL);
1445 if (mydata->fname == NULL) {
1446 efree(mydata);
1447 return FAILURE;
1448 }
1449 fname_len = strlen(mydata->fname);
1450#ifdef PHP_WIN32
1451 phar_unixify_path_separators(mydata->fname, fname_len);
1452#endif
1453 p = strrchr(mydata->fname, '/');
1454
1455 if (p) {
1456 mydata->ext = memchr(p, '.', (mydata->fname + fname_len) - p);
1457 if (mydata->ext == p) {
1458 mydata->ext = memchr(p + 1, '.', (mydata->fname + fname_len) - p - 1);
1459 }
1460 if (mydata->ext) {
1461 mydata->ext_len = (mydata->fname + fname_len) - mydata->ext;
1462 }
1463 }
1464
1465 if (pphar) {
1466 *pphar = mydata;
1467 }
1468
1469 zend_hash_init(&mydata->manifest, sizeof(phar_entry_info),
1470 zend_get_hash_value, destroy_phar_manifest_entry, 0);
1471 zend_hash_init(&mydata->mounted_dirs, sizeof(char *),
1472 zend_get_hash_value, NULL, 0);
1473 zend_hash_init(&mydata->virtual_dirs, sizeof(char *),
1474 zend_get_hash_value, NULL, (bool)mydata->is_persistent);
1475 mydata->fname_len = fname_len;
1476 snprintf(mydata->version, sizeof(mydata->version), "%s", PHP_PHAR_API_VERSION);
1477 mydata->is_temporary_alias = alias ? 0 : 1;
1478 mydata->fp = NULL;
1479 mydata->is_writeable = 1;
1480 mydata->is_brandnew = 1;
1482 zend_hash_str_add_ptr(&(PHAR_G(phar_fname_map)), mydata->fname, fname_len, mydata);
1483
1484 if (is_data) {
1485 alias = NULL;
1486 alias_len = 0;
1487 mydata->is_data = 1;
1488 /* assume tar format, PharData can specify other */
1489 mydata->is_tar = 1;
1490 } else {
1491 phar_archive_data *fd_ptr;
1492
1493 if (alias && NULL != (fd_ptr = zend_hash_str_find_ptr(&(PHAR_G(phar_alias_map)), alias, alias_len))) {
1494 if (SUCCESS != phar_free_alias(fd_ptr, alias, alias_len)) {
1495 if (error) {
1496 spprintf(error, 4096, "phar error: phar \"%s\" cannot set alias \"%s\", already in use by another phar archive", mydata->fname, alias);
1497 }
1498
1499 zend_hash_str_del(&(PHAR_G(phar_fname_map)), mydata->fname, fname_len);
1500
1501 if (pphar) {
1502 *pphar = NULL;
1503 }
1504
1505 return FAILURE;
1506 }
1507 }
1508
1509 ZEND_ASSERT(!mydata->is_persistent);
1510 mydata->alias = alias ? estrndup(alias, alias_len) : estrndup(mydata->fname, fname_len);
1511 mydata->alias_len = alias ? alias_len : fname_len;
1512 }
1513
1514 if (alias_len && alias) {
1515 if (NULL == zend_hash_str_add_ptr(&(PHAR_G(phar_alias_map)), alias, alias_len, mydata)) {
1516 if (options & REPORT_ERRORS) {
1517 if (error) {
1518 spprintf(error, 0, "archive \"%s\" cannot be associated with alias \"%s\", already in use", fname, alias);
1519 }
1520 }
1521
1522 zend_hash_str_del(&(PHAR_G(phar_fname_map)), mydata->fname, fname_len);
1523
1524 if (pphar) {
1525 *pphar = NULL;
1526 }
1527
1528 return FAILURE;
1529 }
1530 }
1531
1532 return SUCCESS;
1533}
1534/* }}}*/
1535
1543zend_result phar_open_from_filename(char *fname, size_t fname_len, char *alias, size_t alias_len, uint32_t options, phar_archive_data** pphar, char **error) /* {{{ */
1544{
1545 php_stream *fp;
1546 zend_string *actual;
1547 bool is_data = false;
1548
1549 if (error) {
1550 *error = NULL;
1551 }
1552
1553 if (!strstr(fname, ".phar")) {
1554 is_data = true;
1555 }
1556
1557 if (phar_open_parsed_phar(fname, fname_len, alias, alias_len, is_data, options, pphar, error) == SUCCESS) {
1558 return SUCCESS;
1559 } else if (error && *error) {
1560 return FAILURE;
1561 }
1562 if (php_check_open_basedir(fname)) {
1563 return FAILURE;
1564 }
1565
1566 fp = php_stream_open_wrapper(fname, "rb", IGNORE_URL|STREAM_MUST_SEEK, &actual);
1567
1568 if (!fp) {
1569 if (options & REPORT_ERRORS) {
1570 if (error) {
1571 spprintf(error, 0, "unable to open phar for reading \"%s\"", fname);
1572 }
1573 }
1574 if (actual) {
1575 zend_string_release_ex(actual, 0);
1576 }
1577 return FAILURE;
1578 }
1579
1580 if (actual) {
1581 fname = ZSTR_VAL(actual);
1582 fname_len = ZSTR_LEN(actual);
1583 }
1584
1585 zend_result ret = phar_open_from_fp(fp, fname, fname_len, alias, alias_len, options, pphar, error);
1586
1587 if (actual) {
1588 zend_string_release_ex(actual, 0);
1589 }
1590
1591 return ret;
1592}
1593/* }}}*/
1594
1595static inline char *phar_strnstr(const char *buf, int buf_len, const char *search, int search_len) /* {{{ */
1596{
1597 const char *c;
1598 ptrdiff_t so_far = 0;
1599
1600 if (buf_len < search_len) {
1601 return NULL;
1602 }
1603
1604 c = buf - 1;
1605
1606 do {
1607 if (!(c = memchr(c + 1, search[0], buf_len - search_len - so_far))) {
1608 return (char *) NULL;
1609 }
1610
1611 so_far = c - buf;
1612
1613 if (so_far >= (buf_len - search_len)) {
1614 return (char *) NULL;
1615 }
1616
1617 if (!memcmp(c, search, search_len)) {
1618 return (char *) c;
1619 }
1620 } while (1);
1621}
1622/* }}} */
1623
1629static zend_result phar_open_from_fp(php_stream* fp, char *fname, size_t fname_len, char *alias, size_t alias_len, uint32_t options, phar_archive_data** pphar, char **error) /* {{{ */
1630{
1631 static const char token[] = "__HALT_COMPILER();";
1632 static const char zip_magic[] = "PK\x03\x04";
1633 static const char gz_magic[] = "\x1f\x8b\x08";
1634 static const char bz_magic[] = "BZh";
1635 char *pos, test = '\0';
1636 int recursion_count = 3; // arbitrary limit to avoid too deep or even infinite recursion
1637 const int window_size = 1024;
1638 char buffer[1024 + sizeof(token)]; /* a 1024 byte window + the size of the halt_compiler token (moving window) */
1639 const zend_long readsize = sizeof(buffer) - sizeof(token);
1640 const zend_long tokenlen = sizeof(token) - 1;
1641 zend_long halt_offset;
1642 size_t got;
1643 uint32_t compression = PHAR_FILE_COMPRESSED_NONE;
1644
1645 if (error) {
1646 *error = NULL;
1647 }
1648
1649 if (-1 == php_stream_rewind(fp)) {
1650 MAPPHAR_ALLOC_FAIL("cannot rewind phar \"%s\"")
1651 }
1652
1653 buffer[sizeof(buffer)-1] = '\0';
1654 memset(buffer, 32, sizeof(token));
1655 halt_offset = 0;
1656
1657 /* Maybe it's better to compile the file instead of just searching, */
1658 /* but we only want the offset. So we want a .re scanner to find it. */
1659 while(!php_stream_eof(fp)) {
1660 if ((got = php_stream_read(fp, buffer+tokenlen, readsize)) < (size_t) tokenlen) {
1661 MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated entry)")
1662 }
1663
1664 if (!test && recursion_count) {
1665 test = '\1';
1666 pos = buffer+tokenlen;
1667 if (!memcmp(pos, gz_magic, 3)) {
1668 char err = 0;
1669 php_stream_filter *filter;
1670 php_stream *temp;
1671 /* to properly decompress, we have to tell zlib to look for a zlib or gzip header */
1672 zval filterparams;
1673
1674 if (!PHAR_G(has_zlib)) {
1675 MAPPHAR_ALLOC_FAIL("unable to decompress gzipped phar archive \"%s\" to temporary file, enable zlib extension in php.ini")
1676 }
1677 array_init(&filterparams);
1678/* this is defined in zlib's zconf.h */
1679#ifndef MAX_WBITS
1680#define MAX_WBITS 15
1681#endif
1682 add_assoc_long_ex(&filterparams, "window", sizeof("window") - 1, MAX_WBITS + 32);
1683
1684 /* entire file is gzip-compressed, uncompress to temporary file */
1685 if (!(temp = php_stream_fopen_tmpfile())) {
1686 MAPPHAR_ALLOC_FAIL("unable to create temporary file for decompression of gzipped phar archive \"%s\"")
1687 }
1688
1690 filter = php_stream_filter_create("zlib.inflate", &filterparams, php_stream_is_persistent(fp));
1691
1692 if (!filter) {
1693 err = 1;
1694 add_assoc_long_ex(&filterparams, "window", sizeof("window") - 1, MAX_WBITS);
1695 filter = php_stream_filter_create("zlib.inflate", &filterparams, php_stream_is_persistent(fp));
1696 zend_array_destroy(Z_ARR(filterparams));
1697
1698 if (!filter) {
1699 php_stream_close(temp);
1700 MAPPHAR_ALLOC_FAIL("unable to decompress gzipped phar archive \"%s\", ext/zlib is buggy in PHP versions older than 5.2.6")
1701 }
1702 } else {
1703 zend_array_destroy(Z_ARR(filterparams));
1704 }
1705
1706 php_stream_filter_append(&temp->writefilters, filter);
1707
1709 if (err) {
1710 php_stream_close(temp);
1711 MAPPHAR_ALLOC_FAIL("unable to decompress gzipped phar archive \"%s\", ext/zlib is buggy in PHP versions older than 5.2.6")
1712 }
1713 php_stream_close(temp);
1714 MAPPHAR_ALLOC_FAIL("unable to decompress gzipped phar archive \"%s\" to temporary file")
1715 }
1716
1717 php_stream_filter_flush(filter, 1);
1718 php_stream_filter_remove(filter, 1);
1719 php_stream_close(fp);
1720 fp = temp;
1722 compression = PHAR_FILE_COMPRESSED_GZ;
1723
1724 /* now, start over */
1725 test = '\0';
1726 if (!--recursion_count) {
1727 MAPPHAR_ALLOC_FAIL("unable to decompress gzipped phar archive \"%s\"");
1728 break;
1729 }
1730 continue;
1731 } else if (!memcmp(pos, bz_magic, 3)) {
1732 php_stream_filter *filter;
1733 php_stream *temp;
1734
1735 if (!PHAR_G(has_bz2)) {
1736 MAPPHAR_ALLOC_FAIL("unable to decompress bzipped phar archive \"%s\" to temporary file, enable bz2 extension in php.ini")
1737 }
1738
1739 /* entire file is bzip-compressed, uncompress to temporary file */
1740 if (!(temp = php_stream_fopen_tmpfile())) {
1741 MAPPHAR_ALLOC_FAIL("unable to create temporary file for decompression of bzipped phar archive \"%s\"")
1742 }
1743
1745 filter = php_stream_filter_create("bzip2.decompress", NULL, php_stream_is_persistent(fp));
1746
1747 if (!filter) {
1748 php_stream_close(temp);
1749 MAPPHAR_ALLOC_FAIL("unable to decompress bzipped phar archive \"%s\", filter creation failed")
1750 }
1751
1752 php_stream_filter_append(&temp->writefilters, filter);
1753
1755 php_stream_close(temp);
1756 MAPPHAR_ALLOC_FAIL("unable to decompress bzipped phar archive \"%s\" to temporary file")
1757 }
1758
1759 php_stream_filter_flush(filter, 1);
1760 php_stream_filter_remove(filter, 1);
1761 php_stream_close(fp);
1762 fp = temp;
1764 compression = PHAR_FILE_COMPRESSED_BZ2;
1765
1766 /* now, start over */
1767 test = '\0';
1768 if (!--recursion_count) {
1769 MAPPHAR_ALLOC_FAIL("unable to decompress bzipped phar archive \"%s\"");
1770 break;
1771 }
1772 continue;
1773 }
1774
1775 if (!memcmp(pos, zip_magic, 4)) {
1776 php_stream_seek(fp, 0, SEEK_END);
1777 return phar_parse_zipfile(fp, fname, fname_len, alias, alias_len, pphar, error);
1778 }
1779
1780 if (got >= 512) {
1781 if (phar_is_tar(pos, fname)) {
1783 return phar_parse_tarfile(fp, fname, fname_len, alias, alias_len, pphar, compression, error);
1784 }
1785 }
1786 }
1787
1788 if (got > 0 && (pos = phar_strnstr(buffer, got + sizeof(token), token, sizeof(token)-1)) != NULL) {
1789 halt_offset += (pos - buffer); /* no -tokenlen+tokenlen here */
1790 return phar_parse_pharfile(fp, fname, fname_len, alias, alias_len, halt_offset, pphar, compression, error);
1791 }
1792
1793 halt_offset += got;
1794 memmove(buffer, buffer + window_size, tokenlen); /* move the memory buffer by the size of the window */
1795 }
1796
1797 MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (__HALT_COMPILER(); not found)")
1798}
1799/* }}} */
1800
1801/*
1802 * given the location of the file extension and the start of the file path,
1803 * determine the end of the portion of the path (i.e. /path/to/file.ext/blah
1804 * grabs "/path/to/file.ext" as does the straight /path/to/file.ext),
1805 * stat it to determine if it exists.
1806 * if so, check to see if it is a directory and fail if so
1807 * if not, check to see if its dirname() exists (i.e. "/path/to") and is a directory
1808 * succeed if we are creating the file, otherwise fail.
1809 */
1810static zend_result phar_analyze_path(const char *fname, const char *ext, size_t ext_len, int for_create) /* {{{ */
1811{
1813 char *realpath;
1814 char *filename = estrndup(fname, (ext - fname) + ext_len);
1815
1816 if ((realpath = expand_filepath(filename, NULL))) {
1817#ifdef PHP_WIN32
1818 phar_unixify_path_separators(realpath, strlen(realpath));
1819#endif
1820 if (zend_hash_str_exists(&(PHAR_G(phar_fname_map)), realpath, strlen(realpath))) {
1821 efree(realpath);
1822 efree(filename);
1823 return SUCCESS;
1824 }
1825
1826 if (PHAR_G(manifest_cached) && zend_hash_str_exists(&cached_phars, realpath, strlen(realpath))) {
1827 efree(realpath);
1828 efree(filename);
1829 return SUCCESS;
1830 }
1831 efree(realpath);
1832 }
1833
1834 if (SUCCESS == php_stream_stat_path((char *) filename, &ssb)) {
1835
1836 efree(filename);
1837
1838 if (ssb.sb.st_mode & S_IFDIR) {
1839 return FAILURE;
1840 }
1841
1842 if (for_create == 1) {
1843 return FAILURE;
1844 }
1845
1846 return SUCCESS;
1847 } else {
1848 char *slash;
1849
1850 if (!for_create) {
1851 efree(filename);
1852 return FAILURE;
1853 }
1854
1855 slash = (char *) strrchr(filename, '/');
1856
1857 if (slash) {
1858 *slash = '\0';
1859 }
1860
1861 if (SUCCESS != php_stream_stat_path((char *) filename, &ssb)) {
1862 if (!slash) {
1863 if (!(realpath = expand_filepath(filename, NULL))) {
1864 efree(filename);
1865 return FAILURE;
1866 }
1867#ifdef PHP_WIN32
1868 phar_unixify_path_separators(realpath, strlen(realpath));
1869#endif
1870 slash = strstr(realpath, filename);
1871 if (slash) {
1872 slash += ((ext - fname) + ext_len);
1873 *slash = '\0';
1874 }
1875 slash = strrchr(realpath, '/');
1876
1877 if (slash) {
1878 *slash = '\0';
1879 } else {
1880 efree(realpath);
1881 efree(filename);
1882 return FAILURE;
1883 }
1884
1885 if (SUCCESS != php_stream_stat_path(realpath, &ssb)) {
1886 efree(realpath);
1887 efree(filename);
1888 return FAILURE;
1889 }
1890
1891 efree(realpath);
1892
1893 if (ssb.sb.st_mode & S_IFDIR) {
1894 efree(filename);
1895 return SUCCESS;
1896 }
1897 }
1898
1899 efree(filename);
1900 return FAILURE;
1901 }
1902
1903 efree(filename);
1904
1905 if (ssb.sb.st_mode & S_IFDIR) {
1906 return SUCCESS;
1907 }
1908
1909 return FAILURE;
1910 }
1911}
1912/* }}} */
1913
1914/* check for ".phar" in extension */
1915static zend_result phar_check_str(const char *fname, const char *ext_str, size_t ext_len, int executable, int for_create) /* {{{ */
1916{
1917 const char *pos;
1918
1919 if (ext_len >= 50) {
1920 return FAILURE;
1921 }
1922 if (executable == 1) {
1923 /* executable phars must contain ".phar" as a valid extension (phar://.pharmy/oops is invalid) */
1924 /* (phar://hi/there/.phar/oops is also invalid) */
1925 pos = strstr(ext_str, ".phar");
1926
1927 if (!pos
1928 || (pos != ext_str && (*(pos - 1) == '/'))
1929 || (ext_len - (pos - ext_str)) < 5
1930 || !(pos += 5)
1931 || !(*pos == '\0' || *pos == '/' || *pos == '.')) {
1932 return FAILURE;
1933 }
1934 return phar_analyze_path(fname, ext_str, ext_len, for_create);
1935 }
1936
1937 /* data phars need only contain a single non-"." to be valid */
1938 if (!executable) {
1939 pos = strstr(ext_str, ".phar");
1940 if (!(pos && (*(pos - 1) != '/')
1941 && (pos += 5) && (*pos == '\0' || *pos == '/' || *pos == '.')) && *(ext_str + 1) != '.' && *(ext_str + 1) != '/' && *(ext_str + 1) != '\0') {
1942 return phar_analyze_path(fname, ext_str, ext_len, for_create);
1943 }
1944 } else {
1945 if (*(ext_str + 1) != '.' && *(ext_str + 1) != '/' && *(ext_str + 1) != '\0') {
1946 return phar_analyze_path(fname, ext_str, ext_len, for_create);
1947 }
1948 }
1949
1950 return FAILURE;
1951}
1952/* }}} */
1953
1954/*
1955 * if executable is 1, only returns SUCCESS if the extension is one of the tar/zip .phar extensions
1956 * if executable is 0, it returns SUCCESS only if the filename does *not* contain ".phar" anywhere, and treats
1957 * the first extension as the filename extension
1958 *
1959 * if an extension is found, it sets ext_str to the location of the file extension in filename,
1960 * and ext_len to the length of the extension.
1961 * for urls like "phar://alias/oops" it instead sets ext_len to -1 and returns FAILURE, which tells
1962 * the calling function to use "alias" as the phar alias
1963 *
1964 * the last parameter should be set to tell the thing to assume that filename is the full path, and only to check the
1965 * extension rules, not to iterate.
1966 */
1967zend_result phar_detect_phar_fname_ext(const char *filename, size_t filename_len, const char **ext_str, size_t *ext_len, int executable, int for_create, int is_complete) /* {{{ */
1968{
1969 const char *pos, *slash;
1970
1971 *ext_str = NULL;
1972 *ext_len = 0;
1973
1974 if (filename_len <= 1) {
1975 return FAILURE;
1976 }
1977
1979 /* first check for alias in first segment */
1980 pos = memchr(filename, '/', filename_len);
1981
1982 if (pos && pos != filename) {
1983 /* check for url like http:// or phar:// */
1984 if (*(pos - 1) == ':' && (size_t)(pos - filename) < filename_len - 1 && *(pos + 1) == '/') {
1985 *ext_len = -2;
1986 *ext_str = NULL;
1987 return FAILURE;
1988 }
1989 if (zend_hash_str_exists(&(PHAR_G(phar_alias_map)), (char *) filename, pos - filename)) {
1990 *ext_str = pos;
1991 *ext_len = -1;
1992 return FAILURE;
1993 }
1994
1995 if (PHAR_G(manifest_cached) && zend_hash_str_exists(&cached_alias, (char *) filename, pos - filename)) {
1996 *ext_str = pos;
1997 *ext_len = -1;
1998 return FAILURE;
1999 }
2000 }
2001
2002 if (zend_hash_num_elements(&(PHAR_G(phar_fname_map))) || PHAR_G(manifest_cached)) {
2003 phar_archive_data *pphar;
2004
2005 if (is_complete) {
2006 if (NULL != (pphar = zend_hash_str_find_ptr(&(PHAR_G(phar_fname_map)), (char *) filename, filename_len))) {
2007 *ext_str = filename + (filename_len - pphar->ext_len);
2008woohoo:
2009 *ext_len = pphar->ext_len;
2010
2011 if (executable == 2) {
2012 return SUCCESS;
2013 }
2014
2015 if (executable == 1 && !pphar->is_data) {
2016 return SUCCESS;
2017 }
2018
2019 if (!executable && pphar->is_data) {
2020 return SUCCESS;
2021 }
2022
2023 return FAILURE;
2024 }
2025
2026 if (PHAR_G(manifest_cached) && NULL != (pphar = zend_hash_str_find_ptr(&cached_phars, (char *) filename, filename_len))) {
2027 *ext_str = filename + (filename_len - pphar->ext_len);
2028 goto woohoo;
2029 }
2030 } else {
2031 zend_string *str_key;
2032
2034 if (ZSTR_LEN(str_key) > filename_len) {
2035 continue;
2036 }
2037
2038 if (!memcmp(filename, ZSTR_VAL(str_key), ZSTR_LEN(str_key)) && (filename_len == ZSTR_LEN(str_key)
2039 || filename[ZSTR_LEN(str_key)] == '/' || filename[ZSTR_LEN(str_key)] == '\0')) {
2040 *ext_str = filename + (ZSTR_LEN(str_key) - pphar->ext_len);
2041 goto woohoo;
2042 }
2044
2045 if (PHAR_G(manifest_cached)) {
2047 if (ZSTR_LEN(str_key) > filename_len) {
2048 continue;
2049 }
2050
2051 if (!memcmp(filename, ZSTR_VAL(str_key), ZSTR_LEN(str_key)) && (filename_len == ZSTR_LEN(str_key)
2052 || filename[ZSTR_LEN(str_key)] == '/' || filename[ZSTR_LEN(str_key)] == '\0')) {
2053 *ext_str = filename + (ZSTR_LEN(str_key) - pphar->ext_len);
2054 goto woohoo;
2055 }
2057 }
2058 }
2059 }
2060
2061 // TODO Use some sort of loop here instead of a goto
2062 pos = memchr(filename + 1, '.', filename_len);
2063next_extension:
2064 if (!pos) {
2065 return FAILURE;
2066 }
2067
2068 while (pos != filename && (*(pos - 1) == '/' || *(pos - 1) == '\0')) {
2069 pos = memchr(pos + 1, '.', filename_len - (pos - filename) - 1);
2070 if (!pos) {
2071 return FAILURE;
2072 }
2073 }
2074
2075 slash = memchr(pos, '/', filename_len - (pos - filename));
2076
2077 if (!slash) {
2078 /* this is a url like "phar://blah.phar" with no directory */
2079 *ext_str = pos;
2080 *ext_len = strlen(pos);
2081
2082 /* file extension must contain "phar" */
2083 return phar_check_str(filename, *ext_str, *ext_len, executable, for_create);
2084 }
2085
2086 /* we've found an extension that ends at a directory separator */
2087 *ext_str = pos;
2088 *ext_len = slash - pos;
2089
2090 if (phar_check_str(filename, *ext_str, *ext_len, executable, for_create) == SUCCESS) {
2091 return SUCCESS;
2092 }
2093
2094 /* look for more extensions */
2095 pos = strchr(pos + 1, '.');
2096 if (pos) {
2097 *ext_str = NULL;
2098 *ext_len = 0;
2099 goto next_extension;
2100 }
2101
2102 return FAILURE;
2103}
2104/* }}} */
2105
2106static bool php_check_dots(const char *element, size_t n) /* {{{ */
2107{
2108 for(n-- ; n != SIZE_MAX; --n) {
2109 if (element[n] != '.') {
2110 return 1;
2111 }
2112 }
2113 return 0;
2114}
2115/* }}} */
2116
2117#define IS_DIRECTORY_UP(element, len) \
2118 (len >= 2 && !php_check_dots(element, len))
2119
2120#define IS_DIRECTORY_CURRENT(element, len) \
2121 (len == 1 && element[0] == '.')
2122
2123#define IS_BACKSLASH(c) ((c) == '/')
2124
2128char *phar_fix_filepath(char *path, size_t *new_len, int use_cwd) /* {{{ */
2129{
2130 char *newpath;
2131 size_t newpath_len;
2132 char *ptr;
2133 char *tok;
2134 size_t ptr_length, path_length = *new_len;
2135
2136 if (PHAR_G(cwd_len) && use_cwd && path_length > 2 && path[0] == '.' && path[1] == '/') {
2137 newpath_len = PHAR_G(cwd_len);
2138 newpath = emalloc(strlen(path) + newpath_len + 1);
2139 memcpy(newpath, PHAR_G(cwd), newpath_len);
2140 } else {
2141 newpath = emalloc(strlen(path) + 2);
2142 newpath[0] = '/';
2143 newpath_len = 1;
2144 }
2145
2146 ptr = path;
2147
2148 if (*ptr == '/') {
2149 ++ptr;
2150 }
2151
2152 tok = ptr;
2153
2154 do {
2155 ptr = memchr(ptr, '/', path_length - (ptr - path));
2156 } while (ptr && ptr - tok == 0 && *ptr == '/' && ++ptr && ++tok);
2157
2158 if (!ptr && (path_length - (tok - path))) {
2159 switch (path_length - (tok - path)) {
2160 case 1:
2161 if (*tok == '.') {
2162 efree(path);
2163 *new_len = 1;
2164 efree(newpath);
2165 return estrndup("/", 1);
2166 }
2167 break;
2168 case 2:
2169 if (tok[0] == '.' && tok[1] == '.') {
2170 efree(path);
2171 *new_len = 1;
2172 efree(newpath);
2173 return estrndup("/", 1);
2174 }
2175 }
2176 efree(newpath);
2177 return path;
2178 }
2179
2180 while (ptr) {
2181 ptr_length = ptr - tok;
2182last_time:
2183 if (IS_DIRECTORY_UP(tok, ptr_length)) {
2184 while (newpath_len > 1 && !IS_BACKSLASH(newpath[newpath_len - 1])) {
2185 newpath_len--;
2186 }
2187
2188 if (newpath[0] != '/') {
2189 newpath[newpath_len] = '\0';
2190 } else if (newpath_len > 1) {
2191 --newpath_len;
2192 }
2193 } else if (!IS_DIRECTORY_CURRENT(tok, ptr_length)) {
2194 if (newpath_len > 1) {
2195 newpath[newpath_len++] = '/';
2196 memcpy(newpath + newpath_len, tok, ptr_length+1);
2197 } else {
2198 memcpy(newpath + newpath_len, tok, ptr_length+1);
2199 }
2200
2201 newpath_len += ptr_length;
2202 }
2203
2204 if (ptr == path + path_length) {
2205 break;
2206 }
2207
2208 tok = ++ptr;
2209
2210 do {
2211 ptr = memchr(ptr, '/', path_length - (ptr - path));
2212 } while (ptr && ptr - tok == 0 && *ptr == '/' && ++ptr && ++tok);
2213
2214 if (!ptr && (path_length - (tok - path))) {
2215 ptr_length = path_length - (tok - path);
2216 ptr = path + path_length;
2217 goto last_time;
2218 }
2219 }
2220
2221 efree(path);
2222 *new_len = newpath_len;
2223 newpath[newpath_len] = '\0';
2224 return erealloc(newpath, newpath_len + 1);
2225}
2226/* }}} */
2227
2240zend_result phar_split_fname(const char *filename, size_t filename_len, char **arch, size_t *arch_len, char **entry, size_t *entry_len, int executable, int for_create) /* {{{ */
2241{
2242 const char *ext_str;
2243#ifdef PHP_WIN32
2244 char *save;
2245#endif
2246 size_t ext_len;
2247
2248 if (CHECK_NULL_PATH(filename, filename_len)) {
2249 return FAILURE;
2250 }
2251
2252 if (!strncasecmp(filename, "phar://", 7)) {
2253 filename += 7;
2254 filename_len -= 7;
2255 }
2256
2257 ext_len = 0;
2258#ifdef PHP_WIN32
2259 save = (char *)filename;
2260 if (memchr(filename, '\\', filename_len)) {
2261 filename = estrndup(filename, filename_len);
2262 phar_unixify_path_separators((char *)filename, filename_len);
2263 }
2264#endif
2265 if (phar_detect_phar_fname_ext(filename, filename_len, &ext_str, &ext_len, executable, for_create, 0) == FAILURE) {
2266 if (ext_len != -1) {
2267 if (!ext_str) {
2268 /* no / detected, restore arch for error message */
2269#ifdef PHP_WIN32
2270 *arch = save;
2271#else
2272 *arch = (char*)filename;
2273#endif
2274 }
2275
2276#ifdef PHP_WIN32
2277 if (filename != save) {
2278 efree((char *)filename);
2279 }
2280#endif
2281 return FAILURE;
2282 }
2283
2284 ext_len = 0;
2285 /* no extension detected - instead we are dealing with an alias */
2286 }
2287
2288 *arch_len = ext_str - filename + ext_len;
2289 *arch = estrndup(filename, *arch_len);
2290
2291 if (ext_str[ext_len]) {
2292 *entry_len = filename_len - *arch_len;
2293 *entry = estrndup(ext_str+ext_len, *entry_len);
2294#ifdef PHP_WIN32
2295 phar_unixify_path_separators(*entry, *entry_len);
2296#endif
2297 *entry = phar_fix_filepath(*entry, entry_len, 0);
2298 } else {
2299 *entry_len = 1;
2300 *entry = estrndup("/", 1);
2301 }
2302
2303#ifdef PHP_WIN32
2304 if (filename != save) {
2305 efree((char *)filename);
2306 }
2307#endif
2308
2309 return SUCCESS;
2310}
2311/* }}} */
2312
2317zend_result phar_open_executed_filename(char *alias, size_t alias_len, char **error) /* {{{ */
2318{
2319 if (error) {
2320 *error = NULL;
2321 }
2322
2324
2325 if (!fname) {
2326 if (error) {
2327 spprintf(error, 0, "cannot initialize a phar outside of PHP execution");
2328 }
2329 return FAILURE;
2330 }
2331
2332 if (phar_open_parsed_phar(ZSTR_VAL(fname), ZSTR_LEN(fname), alias, alias_len, 0, REPORT_ERRORS, NULL, 0) == SUCCESS) {
2333 return SUCCESS;
2334 }
2335
2336 if (0 == zend_get_constant_str("__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__")-1)) {
2337 if (error) {
2338 spprintf(error, 0, "__HALT_COMPILER(); must be declared in a phar");
2339 }
2340 return FAILURE;
2341 }
2342
2343 if (php_check_open_basedir(ZSTR_VAL(fname))) {
2344 return FAILURE;
2345 }
2346
2347 zend_string *actual = NULL;
2348 php_stream *fp;
2350
2351 if (!fp) {
2352 if (error) {
2353 spprintf(error, 0, "unable to open phar for reading \"%s\"", ZSTR_VAL(fname));
2354 }
2355 if (actual) {
2356 zend_string_release_ex(actual, 0);
2357 }
2358 return FAILURE;
2359 }
2360
2361 if (actual) {
2362 fname = actual;
2363 }
2364
2365 zend_result ret = phar_open_from_fp(fp, ZSTR_VAL(fname), ZSTR_LEN(fname), alias, alias_len, REPORT_ERRORS, NULL, error);
2366
2367 if (actual) {
2368 zend_string_release_ex(actual, 0);
2369 }
2370
2371 return ret;
2372}
2373/* }}} */
2374
2378zend_result phar_postprocess_file(phar_entry_data *idata, uint32_t crc32, char **error, int process_zip) /* {{{ */
2379{
2380 php_stream *fp = idata->fp;
2381 phar_entry_info *entry = idata->internal_file;
2382
2383 if (error) {
2384 *error = NULL;
2385 }
2386
2387 if (entry->is_zip && process_zip > 0) {
2388 /* verify local file header */
2390 phar_zip_data_desc desc;
2391
2392 if (SUCCESS != phar_open_archive_fp(idata->phar)) {
2393 spprintf(error, 0, "phar error: unable to open zip-based phar archive \"%s\" to verify local file header for file \"%s\"", idata->phar->fname, entry->filename);
2394 return FAILURE;
2395 }
2396 php_stream_seek(phar_get_entrypfp(idata->internal_file), entry->header_offset, SEEK_SET);
2397
2398 if (sizeof(local) != php_stream_read(phar_get_entrypfp(idata->internal_file), (char *) &local, sizeof(local))) {
2399
2400 spprintf(error, 0, "phar error: internal corruption of zip-based phar \"%s\" (cannot read local file header for file \"%s\")", idata->phar->fname, entry->filename);
2401 return FAILURE;
2402 }
2403
2404 /* check for data descriptor */
2405 if (((PHAR_ZIP_16(local.flags)) & 0x8) == 0x8) {
2406 php_stream_seek(phar_get_entrypfp(idata->internal_file),
2407 entry->header_offset + sizeof(local) +
2408 PHAR_ZIP_16(local.filename_len) +
2409 PHAR_ZIP_16(local.extra_len) +
2411 if (sizeof(desc) != php_stream_read(phar_get_entrypfp(idata->internal_file),
2412 (char *) &desc, sizeof(desc))) {
2413 spprintf(error, 0, "phar error: internal corruption of zip-based phar \"%s\" (cannot read local data descriptor for file \"%s\")", idata->phar->fname, entry->filename);
2414 return FAILURE;
2415 }
2416 if (desc.signature[0] == 'P' && desc.signature[1] == 'K') {
2417 memcpy(&(local.crc32), &(desc.crc32), 12);
2418 } else {
2419 /* old data descriptors have no signature */
2420 memcpy(&(local.crc32), &desc, 12);
2421 }
2422 }
2423 /* verify local header */
2424 if (entry->filename_len != PHAR_ZIP_16(local.filename_len) || entry->crc32 != PHAR_ZIP_32(local.crc32) || entry->uncompressed_filesize != PHAR_ZIP_32(local.uncompsize) || entry->compressed_filesize != PHAR_ZIP_32(local.compsize)) {
2425 spprintf(error, 0, "phar error: internal corruption of zip-based phar \"%s\" (local header of file \"%s\" does not match central directory)", idata->phar->fname, entry->filename);
2426 return FAILURE;
2427 }
2428
2429 /* construct actual offset to file start - local extra_len can be different from central extra_len */
2430 entry->offset = entry->offset_abs =
2431 sizeof(local) + entry->header_offset + PHAR_ZIP_16(local.filename_len) + PHAR_ZIP_16(local.extra_len);
2432
2433 if (idata->zero && idata->zero != entry->offset_abs) {
2434 idata->zero = entry->offset_abs;
2435 }
2436 }
2437
2438 if (process_zip == 1) {
2439 return SUCCESS;
2440 }
2441
2442 php_stream_seek(fp, idata->zero, SEEK_SET);
2443
2444 uint32_t crc = php_crc32_bulk_init();
2446
2447 php_stream_seek(fp, idata->zero, SEEK_SET);
2448
2449 if (SUCCESS == ret && php_crc32_bulk_end(crc) == crc32) {
2450 entry->is_crc_checked = 1;
2451 return SUCCESS;
2452 } else {
2453 spprintf(error, 0, "phar error: internal corruption of phar \"%s\" (crc32 mismatch on file \"%s\")", idata->phar->fname, entry->filename);
2454 return FAILURE;
2455 }
2456}
2457/* }}} */
2458
2459static inline void phar_set_32(char *buffer, uint32_t var) /* {{{ */
2460{
2461#ifdef WORDS_BIGENDIAN
2462 *((buffer) + 3) = (unsigned char) (((var) >> 24) & 0xFF);
2463 *((buffer) + 2) = (unsigned char) (((var) >> 16) & 0xFF);
2464 *((buffer) + 1) = (unsigned char) (((var) >> 8) & 0xFF);
2465 *((buffer) + 0) = (unsigned char) ((var) & 0xFF);
2466#else
2467 memcpy(buffer, &var, sizeof(var));
2468#endif
2469} /* }}} */
2470
2471static int phar_flush_clean_deleted_apply(zval *zv) /* {{{ */
2472{
2474
2475 if (entry->fp_refcount <= 0 && entry->is_deleted) {
2477 } else {
2478 return ZEND_HASH_APPLY_KEEP;
2479 }
2480}
2481/* }}} */
2482
2483#include "stub.h" /* Generated phar_get_stub() function from makestub.php script */
2484
2485zend_string *phar_create_default_stub(const char *index_php, const char *web_index, char **error) /* {{{ */
2486{
2487 size_t index_len, web_len;
2488
2489 if (error) {
2490 *error = NULL;
2491 }
2492
2493 if (!index_php) {
2494 index_php = "index.php";
2495 }
2496
2497 if (!web_index) {
2498 web_index = "index.php";
2499 }
2500
2501 index_len = strlen(index_php);
2502 web_len = strlen(web_index);
2503
2504 if (index_len > 400) {
2505 /* ridiculous size not allowed for index.php startup filename */
2506 if (error) {
2507 spprintf(error, 0, "Illegal filename passed in for stub creation, was %zd characters long, and only 400 or less is allowed", index_len);
2508 return NULL;
2509 }
2510 }
2511
2512 if (web_len > 400) {
2513 /* ridiculous size not allowed for index.php startup filename */
2514 if (error) {
2515 spprintf(error, 0, "Illegal web filename passed in for stub creation, was %zd characters long, and only 400 or less is allowed", web_len);
2516 return NULL;
2517 }
2518 }
2519
2520 return phar_get_stub(index_php, web_index, index_len+1, web_len+1);
2521}
2522/* }}} */
2523
2525 phar_flush_ex(phar, NULL, false, error);
2526}
2527
2533void phar_flush_ex(phar_archive_data *phar, zend_string *user_stub, bool is_default_stub, char **error) /* {{{ */
2534{
2535 static const char halt_stub[] = "__HALT_COMPILER();";
2536
2537 phar_entry_info *entry, *newentry;
2538 size_t halt_offset;
2539 int restore_alias_len, global_flags = 0;
2540 bool must_close_old_file = false;
2541 bool has_dirs = false;
2542 char manifest[18], entry_buffer[24];
2543 zend_off_t manifest_ftell;
2545 size_t wrote;
2546 uint32_t manifest_len, mytime, new_manifest_count;
2547 uint32_t newcrc32;
2548 php_stream *file, *oldfile, *newfile;
2549 php_stream_filter *filter;
2550 php_serialize_data_t metadata_hash;
2551 smart_str main_metadata_str = {0};
2552 bool free_fp = true;
2553 bool free_ufp = true;
2554 bool manifest_hack = false;
2555 php_stream *shared_cfp = NULL;
2556
2557 if (phar->is_persistent) {
2558 if (error) {
2559 spprintf(error, 0, "internal error: attempt to flush cached zip-based phar \"%s\"", phar->fname);
2560 }
2561 return;
2562 }
2563
2564 if (error) {
2565 *error = NULL;
2566 }
2567
2568 if (!zend_hash_num_elements(&phar->manifest) && !user_stub) {
2569 return;
2570 }
2571
2573
2574 if (phar->is_zip) {
2575 phar_zip_flush(phar, user_stub, is_default_stub, error);
2576 return;
2577 }
2578
2579 if (phar->is_tar) {
2580 phar_tar_flush(phar, user_stub, is_default_stub, error);
2581 return;
2582 }
2583
2584 if (PHAR_G(readonly)) {
2585 return;
2586 }
2587
2588 if (phar->fp && !phar->is_brandnew) {
2589 oldfile = phar->fp;
2590 must_close_old_file = false;
2591 php_stream_rewind(oldfile);
2592 } else {
2593 oldfile = php_stream_open_wrapper(phar->fname, "rb", 0, NULL);
2594 must_close_old_file = oldfile != NULL;
2595 }
2596 newfile = php_stream_fopen_tmpfile();
2597 if (!newfile) {
2598 if (error) {
2599 spprintf(error, 0, "unable to create temporary file");
2600 }
2601 if (must_close_old_file) {
2602 php_stream_close(oldfile);
2603 }
2604 return;
2605 }
2606
2607 if (user_stub) {
2608 char *pos = php_stristr(ZSTR_VAL(user_stub), halt_stub, ZSTR_LEN(user_stub), strlen(halt_stub));
2609
2610 if (pos == NULL) {
2611 if (must_close_old_file) {
2612 php_stream_close(oldfile);
2613 }
2614 php_stream_close(newfile);
2615 if (error) {
2616 spprintf(error, 0, "illegal stub for phar \"%s\" (__HALT_COMPILER(); is missing)", phar->fname);
2617 }
2618 return;
2619 }
2620
2621 size_t len = pos - ZSTR_VAL(user_stub) + strlen(halt_stub);
2622 const char end_sequence[] = " ?>\r\n";
2623 size_t end_sequence_len = strlen(end_sequence);
2624
2625 if (
2626 len != php_stream_write(newfile, ZSTR_VAL(user_stub), len)
2627 || end_sequence_len != php_stream_write(newfile, end_sequence, end_sequence_len)
2628 ) {
2629 if (must_close_old_file) {
2630 php_stream_close(oldfile);
2631 }
2632 php_stream_close(newfile);
2633 if (error) {
2634 spprintf(error, 0, "unable to create stub from string in new phar \"%s\"", phar->fname);
2635 }
2636 return;
2637 }
2638 phar->halt_offset = len + end_sequence_len;
2639 } else {
2640 size_t written;
2641 zend_string *new_stub = NULL;
2642
2643 if (!user_stub && phar->halt_offset && oldfile && !phar->is_brandnew) {
2644 php_stream_copy_to_stream_ex(oldfile, newfile, phar->halt_offset, &written);
2645 } else {
2646 /* this is either a brand new phar or a default stub overwrite */
2647 new_stub = phar_create_default_stub(NULL, NULL, NULL);
2648 phar->halt_offset = ZSTR_LEN(new_stub);
2649 written = php_stream_write(newfile, ZSTR_VAL(new_stub), phar->halt_offset);
2650 }
2651 if (phar->halt_offset != written) {
2652 if (must_close_old_file) {
2653 php_stream_close(oldfile);
2654 }
2655 php_stream_close(newfile);
2656 if (error) {
2657 if (new_stub) {
2658 spprintf(error, 0, "unable to create stub in new phar \"%s\"", phar->fname);
2659 } else {
2660 spprintf(error, 0, "unable to copy stub of old phar to new phar \"%s\"", phar->fname);
2661 }
2662 }
2663 if (new_stub) {
2664 zend_string_free(new_stub);
2665 }
2666 return;
2667 }
2668 if (new_stub) {
2669 zend_string_free(new_stub);
2670 }
2671 }
2672 manifest_ftell = php_stream_tell(newfile);
2673 halt_offset = manifest_ftell;
2674
2675 /* Check whether we can get rid of some of the deleted entries which are
2676 * unused. However some might still be in use so even after this clean-up
2677 * we need to skip entries marked is_deleted. */
2678 zend_hash_apply(&phar->manifest, phar_flush_clean_deleted_apply);
2679
2680 /* compress as necessary, calculate crcs, serialize meta-data, manifest size, and file sizes */
2681 main_metadata_str.s = NULL;
2682 if (phar->metadata_tracker.str) {
2683 smart_str_appendl(&main_metadata_str, ZSTR_VAL(phar->metadata_tracker.str), ZSTR_LEN(phar->metadata_tracker.str));
2684 } else if (!Z_ISUNDEF(phar->metadata_tracker.val)) {
2685 PHP_VAR_SERIALIZE_INIT(metadata_hash);
2686 php_var_serialize(&main_metadata_str, &phar->metadata_tracker.val, &metadata_hash);
2687 PHP_VAR_SERIALIZE_DESTROY(metadata_hash);
2688 }
2689 new_manifest_count = 0;
2690 offset = 0;
2691 ZEND_HASH_MAP_FOREACH_PTR(&phar->manifest, entry) {
2692 if (entry->cfp) {
2693 /* did we forget to get rid of cfp last time? */
2694 php_stream_close(entry->cfp);
2695 entry->cfp = 0;
2696 }
2697 if (entry->is_deleted || entry->is_mounted) {
2698 /* remove this from the new phar */
2699 continue;
2700 }
2701 if (!entry->is_modified && entry->fp_refcount) {
2702 /* open file pointers refer to this fp, do not free the stream */
2703 switch (entry->fp_type) {
2704 case PHAR_FP:
2705 free_fp = false;
2706 break;
2707 case PHAR_UFP:
2708 free_ufp = false;
2709 default:
2710 break;
2711 }
2712 }
2713 /* after excluding deleted files, calculate manifest size in bytes and number of entries */
2714 ++new_manifest_count;
2715 phar_add_virtual_dirs(phar, entry->filename, entry->filename_len);
2716
2717 if (entry->is_dir) {
2718 /* we use this to calculate API version, 1.1.1 is used for phars with directories */
2719 has_dirs = true;
2720 }
2721 if (!Z_ISUNDEF(entry->metadata_tracker.val) && !entry->metadata_tracker.str) {
2722 ZEND_ASSERT(!entry->is_persistent);
2723 /* Assume serialization will succeed. TODO: Set error and throw if EG(exception) != NULL */
2724 smart_str buf = {0};
2725 PHP_VAR_SERIALIZE_INIT(metadata_hash);
2726 php_var_serialize(&buf, &entry->metadata_tracker.val, &metadata_hash);
2727 PHP_VAR_SERIALIZE_DESTROY(metadata_hash);
2728 entry->metadata_tracker.str = buf.s;
2729 }
2730
2731 /* 32 bits for filename length, length of filename, manifest + metadata, and add 1 for trailing / if a directory */
2732 offset += 4 + entry->filename_len + sizeof(entry_buffer) + (entry->metadata_tracker.str ? ZSTR_LEN(entry->metadata_tracker.str) : 0) + (entry->is_dir ? 1 : 0);
2733
2734 /* compress and rehash as necessary */
2735 if ((oldfile && !entry->is_modified) || entry->is_dir) {
2736 if (entry->fp_type == PHAR_UFP) {
2737 /* reset so we can copy the compressed data over */
2738 entry->fp_type = PHAR_FP;
2739 }
2740 continue;
2741 }
2742 if (!phar_get_efp(entry, 0)) {
2743 /* re-open internal file pointer just-in-time */
2744 newentry = phar_open_jit(phar, entry, error);
2745 if (!newentry) {
2746 /* major problem re-opening, so we ignore this file and the error */
2747 efree(*error);
2748 *error = NULL;
2749 continue;
2750 }
2751 entry = newentry;
2752 }
2753 file = phar_get_efp(entry, 0);
2754 if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 1)) {
2755 if (must_close_old_file) {
2756 php_stream_close(oldfile);
2757 }
2758 php_stream_close(newfile);
2759 if (error) {
2760 spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
2761 }
2762 return;
2763 }
2764 newcrc32 = php_crc32_bulk_init();
2766 entry->crc32 = php_crc32_bulk_end(newcrc32);
2767 entry->is_crc_checked = 1;
2768 if (!(entry->flags & PHAR_ENT_COMPRESSION_MASK)) {
2769 /* not compressed */
2771 continue;
2772 }
2773 filter = php_stream_filter_create(phar_compress_filter(entry, 0), NULL, 0);
2774 if (!filter) {
2775 if (must_close_old_file) {
2776 php_stream_close(oldfile);
2777 }
2778 php_stream_close(newfile);
2779 if (entry->flags & PHAR_ENT_COMPRESSED_GZ) {
2780 if (error) {
2781 spprintf(error, 0, "unable to gzip compress file \"%s\" to new phar \"%s\"", entry->filename, phar->fname);
2782 }
2783 } else {
2784 if (error) {
2785 spprintf(error, 0, "unable to bzip2 compress file \"%s\" to new phar \"%s\"", entry->filename, phar->fname);
2786 }
2787 }
2788 return;
2789 }
2790
2791 /* create new file that holds the compressed versions */
2792 /* work around inability to specify freedom in write and strictness
2793 in read count */
2794 if (shared_cfp == NULL) {
2795 shared_cfp = php_stream_fopen_tmpfile();
2796 }
2797 entry->cfp = shared_cfp;
2798 if (!entry->cfp) {
2799 if (error) {
2800 spprintf(error, 0, "unable to create temporary file");
2801 }
2802 if (must_close_old_file) {
2803 php_stream_close(oldfile);
2804 }
2805 php_stream_close(newfile);
2806 goto cleanup;
2807 }
2808 /* for real phars, header_offset is unused; we misuse it here to store the offset in the temp file */
2809 ZEND_ASSERT(entry->header_offset == 0);
2810 entry->header_offset = php_stream_tell(entry->cfp);
2812 if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0)) {
2813 if (must_close_old_file) {
2814 php_stream_close(oldfile);
2815 }
2816 php_stream_close(newfile);
2817 if (error) {
2818 spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
2819 }
2820 goto cleanup;
2821 }
2822 php_stream_filter_append((&entry->cfp->writefilters), filter);
2824 if (must_close_old_file) {
2825 php_stream_close(oldfile);
2826 }
2827 php_stream_close(newfile);
2828 if (error) {
2829 spprintf(error, 0, "unable to copy compressed file contents of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
2830 }
2831 goto cleanup;
2832 }
2833 php_stream_filter_flush(filter, 1);
2834 php_stream_flush(entry->cfp);
2835 php_stream_filter_remove(filter, 1);
2836 php_stream_seek(entry->cfp, 0, SEEK_END);
2837 entry->compressed_filesize = ((uint32_t) php_stream_tell(entry->cfp)) - entry->header_offset;
2838 /* generate crc on compressed file */
2839 entry->old_flags = entry->flags;
2840 entry->is_modified = 1;
2841 global_flags |= (entry->flags & PHAR_ENT_COMPRESSION_MASK);
2843 global_flags |= PHAR_HDR_SIGNATURE;
2844
2845 /* write out manifest pre-header */
2846 /* 4: manifest length
2847 * 4: manifest entry count
2848 * 2: phar version
2849 * 4: phar global flags
2850 * 4: alias length
2851 * ?: the alias itself
2852 * 4: phar metadata length
2853 * ?: phar metadata
2854 */
2855 restore_alias_len = phar->alias_len;
2856 if (phar->is_temporary_alias) {
2857 phar->alias_len = 0;
2858 }
2859
2860 manifest_len = offset + phar->alias_len + sizeof(manifest) + (main_metadata_str.s ? ZSTR_LEN(main_metadata_str.s) : 0);
2861 phar_set_32(manifest, manifest_len);
2862 /* Hack - see bug #65028, add padding byte to the end of the manifest */
2863 if(manifest[0] == '\r' || manifest[0] == '\n') {
2864 manifest_len++;
2865 phar_set_32(manifest, manifest_len);
2866 manifest_hack = true;
2867 }
2868 phar_set_32(manifest+4, new_manifest_count);
2869 if (has_dirs) {
2870 *(manifest + 8) = (unsigned char) (((PHAR_API_VERSION) >> 8) & 0xFF);
2871 *(manifest + 9) = (unsigned char) (((PHAR_API_VERSION) & 0xF0));
2872 } else {
2873 *(manifest + 8) = (unsigned char) (((PHAR_API_VERSION_NODIR) >> 8) & 0xFF);
2874 *(manifest + 9) = (unsigned char) (((PHAR_API_VERSION_NODIR) & 0xF0));
2875 }
2876 phar_set_32(manifest+10, global_flags);
2877 phar_set_32(manifest+14, phar->alias_len);
2878
2879 /* write the manifest header */
2880 if (sizeof(manifest) != php_stream_write(newfile, manifest, sizeof(manifest))
2881 || (size_t)phar->alias_len != php_stream_write(newfile, phar->alias, phar->alias_len)) {
2882
2883 if (must_close_old_file) {
2884 php_stream_close(oldfile);
2885 }
2886
2887 php_stream_close(newfile);
2888 phar->alias_len = restore_alias_len;
2889
2890 if (error) {
2891 spprintf(error, 0, "unable to write manifest header of new phar \"%s\"", phar->fname);
2892 }
2893
2894 goto cleanup;
2895 }
2896
2897 phar->alias_len = restore_alias_len;
2898
2899 phar_set_32(manifest, main_metadata_str.s ? ZSTR_LEN(main_metadata_str.s) : 0);
2900 if (4 != php_stream_write(newfile, manifest, 4) || ((main_metadata_str.s ? ZSTR_LEN(main_metadata_str.s) : 0)
2901 && ZSTR_LEN(main_metadata_str.s) != php_stream_write(newfile, ZSTR_VAL(main_metadata_str.s), ZSTR_LEN(main_metadata_str.s)))) {
2902 smart_str_free(&main_metadata_str);
2903
2904 if (must_close_old_file) {
2905 php_stream_close(oldfile);
2906 }
2907
2908 php_stream_close(newfile);
2909 phar->alias_len = restore_alias_len;
2910
2911 if (error) {
2912 spprintf(error, 0, "unable to write manifest meta-data of new phar \"%s\"", phar->fname);
2913 }
2914
2915 goto cleanup;
2916 }
2917 smart_str_free(&main_metadata_str);
2918
2919 /* re-calculate the manifest location to simplify later code */
2920 manifest_ftell = php_stream_tell(newfile);
2921
2922 /* now write the manifest */
2923 ZEND_HASH_MAP_FOREACH_PTR(&phar->manifest, entry) {
2924 const zend_string *metadata_str;
2925 if (entry->is_deleted || entry->is_mounted) {
2926 /* remove this from the new phar if deleted, ignore if mounted */
2927 continue;
2928 }
2929
2930 if (entry->is_dir) {
2931 /* add 1 for trailing slash */
2932 phar_set_32(entry_buffer, entry->filename_len + 1);
2933 } else {
2934 phar_set_32(entry_buffer, entry->filename_len);
2935 }
2936
2937 if (4 != php_stream_write(newfile, entry_buffer, 4)
2938 || entry->filename_len != php_stream_write(newfile, entry->filename, entry->filename_len)
2939 || (entry->is_dir && 1 != php_stream_write(newfile, "/", 1))) {
2940 if (must_close_old_file) {
2941 php_stream_close(oldfile);
2942 }
2943 php_stream_close(newfile);
2944 if (error) {
2945 if (entry->is_dir) {
2946 spprintf(error, 0, "unable to write filename of directory \"%s\" to manifest of new phar \"%s\"", entry->filename, phar->fname);
2947 } else {
2948 spprintf(error, 0, "unable to write filename of file \"%s\" to manifest of new phar \"%s\"", entry->filename, phar->fname);
2949 }
2950 }
2951 goto cleanup;
2952 }
2953
2954 /* set the manifest meta-data:
2955 4: uncompressed filesize
2956 4: creation timestamp
2957 4: compressed filesize
2958 4: crc32
2959 4: flags
2960 4: metadata-len
2961 +: metadata
2962 */
2963 mytime = time(NULL);
2964 phar_set_32(entry_buffer, entry->uncompressed_filesize);
2965 phar_set_32(entry_buffer+4, mytime);
2966 phar_set_32(entry_buffer+8, entry->compressed_filesize);
2967 phar_set_32(entry_buffer+12, entry->crc32);
2968 phar_set_32(entry_buffer+16, entry->flags);
2969 metadata_str = entry->metadata_tracker.str;
2970 phar_set_32(entry_buffer+20, metadata_str ? ZSTR_LEN(metadata_str) : 0);
2971
2972 if (sizeof(entry_buffer) != php_stream_write(newfile, entry_buffer, sizeof(entry_buffer))
2973 || (metadata_str &&
2974 ZSTR_LEN(metadata_str) != php_stream_write(newfile, ZSTR_VAL(metadata_str), ZSTR_LEN(metadata_str)))) {
2975 if (must_close_old_file) {
2976 php_stream_close(oldfile);
2977 }
2978
2979 php_stream_close(newfile);
2980
2981 if (error) {
2982 spprintf(error, 0, "unable to write temporary manifest of file \"%s\" to manifest of new phar \"%s\"", entry->filename, phar->fname);
2983 }
2984
2985 goto cleanup;
2986 }
2988 /* Hack - see bug #65028, add padding byte to the end of the manifest */
2989 if (manifest_hack) {
2990 if(1 != php_stream_write(newfile, manifest, 1)) {
2991 if (must_close_old_file) {
2992 php_stream_close(oldfile);
2993 }
2994
2995 php_stream_close(newfile);
2996
2997 if (error) {
2998 spprintf(error, 0, "unable to write manifest padding byte");
2999 }
3000
3001 goto cleanup;
3002 }
3003 }
3004
3005 /* now copy the actual file data to the new phar */
3006 offset = php_stream_tell(newfile);
3007 ZEND_HASH_MAP_FOREACH_PTR(&phar->manifest, entry) {
3008 if (entry->is_deleted || entry->is_dir || entry->is_mounted) {
3009 continue;
3010 }
3011
3012 if (entry->cfp) {
3013 file = entry->cfp;
3015 } else {
3016 file = phar_get_efp(entry, 0);
3017 if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0)) {
3018 if (must_close_old_file) {
3019 php_stream_close(oldfile);
3020 }
3021 php_stream_close(newfile);
3022 if (error) {
3023 spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
3024 }
3025 goto cleanup;
3026 }
3027 }
3028
3029 if (!file) {
3030 if (must_close_old_file) {
3031 php_stream_close(oldfile);
3032 }
3033 php_stream_close(newfile);
3034 if (error) {
3035 spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
3036 }
3037 goto cleanup;
3038 }
3039
3040 /* this will have changed for all files that have either changed compression or been modified */
3041 entry->offset = entry->offset_abs = offset;
3042 offset += entry->compressed_filesize;
3043 if (php_stream_copy_to_stream_ex(file, newfile, entry->compressed_filesize, &wrote) == FAILURE) {
3044 if (must_close_old_file) {
3045 php_stream_close(oldfile);
3046 }
3047
3048 php_stream_close(newfile);
3049
3050 if (error) {
3051 spprintf(error, 0, "unable to write contents of file \"%s\" to new phar \"%s\"", entry->filename, phar->fname);
3052 }
3053
3054 goto cleanup;
3055 }
3056
3057 entry->is_modified = 0;
3058
3059 if (entry->cfp) {
3060 entry->cfp = NULL;
3061 entry->header_offset = 0;
3062 }
3063
3064 if (entry->fp_type == PHAR_MOD) {
3065 /* this fp is in use by a phar_entry_data returned by phar_get_entry_data, it will be closed when the phar_entry_data is phar_entry_delref'ed */
3066 if (entry->fp_refcount == 0 && entry->fp != phar->fp && entry->fp != phar->ufp) {
3067 php_stream_close(entry->fp);
3068 }
3069
3070 entry->fp = NULL;
3071 entry->fp_type = PHAR_FP;
3072 } else if (entry->fp_type == PHAR_UFP) {
3073 entry->fp_type = PHAR_FP;
3074 }
3076
3077 if (shared_cfp != NULL) {
3078 php_stream_close(shared_cfp);
3079 shared_cfp = NULL;
3080 }
3081
3082 /* append signature */
3083 if (global_flags & PHAR_HDR_SIGNATURE) {
3084 char sig_buf[4];
3085
3086 php_stream_rewind(newfile);
3087
3088 if (phar->signature) {
3089 efree(phar->signature);
3090 phar->signature = NULL;
3091 }
3092
3093 switch(phar->sig_flags) {
3094 default: {
3095 char *digest = NULL;
3096 size_t digest_len;
3097
3098 if (FAILURE == phar_create_signature(phar, newfile, &digest, &digest_len, error)) {
3099 if (error) {
3100 char *save = *error;
3101 spprintf(error, 0, "phar error: unable to write signature: %s", save);
3102 efree(save);
3103 }
3104 if (digest) {
3105 efree(digest);
3106 }
3107 if (must_close_old_file) {
3108 php_stream_close(oldfile);
3109 }
3110 php_stream_close(newfile);
3111 return;
3112 }
3113
3114 php_stream_write(newfile, digest, digest_len);
3115 efree(digest);
3116 if (phar->sig_flags == PHAR_SIG_OPENSSL ||
3119 phar_set_32(sig_buf, digest_len);
3120 php_stream_write(newfile, sig_buf, 4);
3121 }
3122 break;
3123 }
3124 }
3125 phar_set_32(sig_buf, phar->sig_flags);
3126 php_stream_write(newfile, sig_buf, 4);
3127 php_stream_write(newfile, "GBMB", 4);
3128 }
3129
3130 /* finally, close the temp file, rename the original phar,
3131 move the temp to the old phar, unlink the old phar, and reload it into memory
3132 */
3133 if (phar->fp && free_fp) {
3134 php_stream_close(phar->fp);
3135 }
3136
3137 if (phar->ufp) {
3138 if (free_ufp) {
3139 php_stream_close(phar->ufp);
3140 }
3141 phar->ufp = NULL;
3142 }
3143
3144 if (must_close_old_file) {
3145 php_stream_close(oldfile);
3146 }
3147
3148 phar->halt_offset = halt_offset;
3149 phar->is_brandnew = 0;
3150
3151 php_stream_rewind(newfile);
3152
3153 if (phar->donotflush) {
3154 /* deferred flush */
3155 phar->fp = newfile;
3156 } else {
3158 if (!phar->fp) {
3159 phar->fp = newfile;
3160 if (error) {
3161 spprintf(error, 4096, "unable to open new phar \"%s\" for writing", phar->fname);
3162 }
3163 return;
3164 }
3165
3166 if (phar->flags & PHAR_FILE_COMPRESSED_GZ) {
3167 /* to properly compress, we have to tell zlib to add a zlib header */
3168 zval filterparams;
3169
3170 array_init(&filterparams);
3171 add_assoc_long(&filterparams, "window", MAX_WBITS+16);
3172 filter = php_stream_filter_create("zlib.deflate", &filterparams, php_stream_is_persistent(phar->fp));
3173 zend_array_destroy(Z_ARR(filterparams));
3174
3175 if (!filter) {
3176 if (error) {
3177 spprintf(error, 4096, "unable to compress all contents of phar \"%s\" using zlib, PHP versions older than 5.2.6 have a buggy zlib", phar->fname);
3178 }
3179 return;
3180 }
3181
3182 php_stream_filter_append(&phar->fp->writefilters, filter);
3184 php_stream_filter_flush(filter, 1);
3185 php_stream_filter_remove(filter, 1);
3186 php_stream_close(phar->fp);
3187 /* use the temp stream as our base */
3188 phar->fp = newfile;
3189 } else if (phar->flags & PHAR_FILE_COMPRESSED_BZ2) {
3190 filter = php_stream_filter_create("bzip2.compress", NULL, php_stream_is_persistent(phar->fp));
3191 php_stream_filter_append(&phar->fp->writefilters, filter);
3193 php_stream_filter_flush(filter, 1);
3194 php_stream_filter_remove(filter, 1);
3195 php_stream_close(phar->fp);
3196 /* use the temp stream as our base */
3197 phar->fp = newfile;
3198 } else {
3200 /* we could also reopen the file in "rb" mode but there is no need for that */
3201 php_stream_close(newfile);
3202 }
3203 }
3204
3205 if (-1 == php_stream_seek(phar->fp, phar->halt_offset, SEEK_SET)) {
3206 if (error) {
3207 spprintf(error, 0, "unable to seek to __HALT_COMPILER(); in new phar \"%s\"", phar->fname);
3208 }
3209 }
3210
3211 return;
3212
3213cleanup:
3214 if (shared_cfp != NULL) {
3215 php_stream_close(shared_cfp);
3216 }
3217 ZEND_HASH_MAP_FOREACH_PTR(&phar->manifest, entry) {
3218 if (entry->cfp) {
3219 entry->cfp = NULL;
3220 entry->header_offset = 0;
3221 }
3223}
3224/* }}} */
3225
3226#ifdef COMPILE_DL_PHAR
3227#ifdef ZTS
3229#endif
3230ZEND_GET_MODULE(phar)
3231#endif
3232
3233static ssize_t phar_zend_stream_reader(void *handle, char *buf, size_t len) /* {{{ */
3234{
3235 return php_stream_read(phar_get_pharfp((phar_archive_data*)handle), buf, len);
3236}
3237/* }}} */
3238
3239static size_t phar_zend_stream_fsizer(void *handle) /* {{{ */
3240{
3241 return ((phar_archive_data*)handle)->halt_offset + 32;
3242} /* }}} */
3243
3244zend_op_array *(*phar_orig_compile_file)(zend_file_handle *file_handle, int type);
3245
3246static zend_string *phar_resolve_path(zend_string *filename)
3247{
3249 if (!ret) {
3250 ret = phar_save_resolve_path(filename);
3251 }
3252 return ret;
3253}
3254
3255static zend_op_array *phar_compile_file(zend_file_handle *file_handle, int type) /* {{{ */
3256{
3259 int failed;
3260 phar_archive_data *phar;
3261
3262 if (!file_handle || !file_handle->filename) {
3263 return phar_orig_compile_file(file_handle, type);
3264 }
3265 if (strstr(ZSTR_VAL(file_handle->filename), ".phar") && !strstr(ZSTR_VAL(file_handle->filename), "://")) {
3266 if (SUCCESS == phar_open_from_filename(ZSTR_VAL(file_handle->filename), ZSTR_LEN(file_handle->filename), NULL, 0, 0, &phar, NULL)) {
3267 if (phar->is_zip || phar->is_tar) {
3269
3270 /* zip or tar-based phar */
3271 name = zend_strpprintf(4096, "phar://%s/%s", ZSTR_VAL(file_handle->filename), ".phar/stub.php");
3274 zend_string_release(f.filename);
3275 f.filename = file_handle->filename;
3276 if (f.opened_path) {
3277 zend_string_release(f.opened_path);
3278 }
3279 f.opened_path = file_handle->opened_path;
3280
3281 switch (file_handle->type) {
3282 case ZEND_HANDLE_STREAM:
3283 if (file_handle->handle.stream.closer && file_handle->handle.stream.handle) {
3284 file_handle->handle.stream.closer(file_handle->handle.stream.handle);
3285 }
3286 file_handle->handle.stream.handle = NULL;
3287 break;
3288 default:
3289 break;
3290 }
3291 *file_handle = f;
3292 }
3293 } else if (phar->flags & PHAR_FILE_COMPRESSION_MASK) {
3294 /* compressed phar */
3295 file_handle->type = ZEND_HANDLE_STREAM;
3296 /* we do our own reading directly from the phar, don't change the next line */
3297 file_handle->handle.stream.handle = phar;
3298 file_handle->handle.stream.reader = phar_zend_stream_reader;
3299 file_handle->handle.stream.closer = NULL;
3300 file_handle->handle.stream.fsizer = phar_zend_stream_fsizer;
3301 file_handle->handle.stream.isatty = 0;
3302 phar->is_persistent ?
3304 php_stream_rewind(phar->fp);
3305 }
3306 }
3307 }
3308
3309 zend_try {
3310 failed = 0;
3311 CG(zend_lineno) = 0;
3312 res = phar_orig_compile_file(file_handle, type);
3313 } zend_catch {
3314 failed = 1;
3315 res = NULL;
3316 } zend_end_try();
3317
3318 if (name) {
3319 zend_string_release(name);
3320 }
3321
3322 if (failed) {
3323 zend_bailout();
3324 }
3325
3326 return res;
3327}
3328/* }}} */
3329
3330static void mime_type_dtor(zval *zv)
3331{
3332 free(Z_PTR_P(zv));
3333}
3334
3335PHP_GINIT_FUNCTION(phar) /* {{{ */
3336{
3337#if defined(COMPILE_DL_PHAR) && defined(ZTS)
3339#endif
3340 phar_mime_type mime;
3341
3342 memset(phar_globals, 0, sizeof(zend_phar_globals));
3343 HT_INVALIDATE(&phar_globals->phar_persist_map);
3344 HT_INVALIDATE(&phar_globals->phar_fname_map);
3345 HT_INVALIDATE(&phar_globals->phar_alias_map);
3346 phar_globals->readonly = 1;
3347
3348 zend_hash_init(&phar_globals->mime_types, 0, NULL, mime_type_dtor, 1);
3349
3350#define PHAR_SET_MIME(mimetype, ret, fileext) \
3351 mime.mime = mimetype; \
3352 mime.len = sizeof((mimetype))+1; \
3353 mime.type = ret; \
3354 zend_hash_str_add_mem(&phar_globals->mime_types, fileext, sizeof(fileext)-1, (void *)&mime, sizeof(phar_mime_type)); \
3355
3356 PHAR_SET_MIME("text/html", PHAR_MIME_PHPS, "phps")
3357 PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "c")
3358 PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "cc")
3359 PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "cpp")
3360 PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "c++")
3361 PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "dtd")
3362 PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "h")
3363 PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "log")
3364 PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "rng")
3365 PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "txt")
3366 PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "xsd")
3367 PHAR_SET_MIME("", PHAR_MIME_PHP, "php")
3368 PHAR_SET_MIME("", PHAR_MIME_PHP, "inc")
3369 PHAR_SET_MIME("video/avi", PHAR_MIME_OTHER, "avi")
3370 PHAR_SET_MIME("image/bmp", PHAR_MIME_OTHER, "bmp")
3371 PHAR_SET_MIME("text/css", PHAR_MIME_OTHER, "css")
3372 PHAR_SET_MIME("image/gif", PHAR_MIME_OTHER, "gif")
3373 PHAR_SET_MIME("text/html", PHAR_MIME_OTHER, "htm")
3374 PHAR_SET_MIME("text/html", PHAR_MIME_OTHER, "html")
3375 PHAR_SET_MIME("text/html", PHAR_MIME_OTHER, "htmls")
3376 PHAR_SET_MIME("image/x-ico", PHAR_MIME_OTHER, "ico")
3377 PHAR_SET_MIME("image/jpeg", PHAR_MIME_OTHER, "jpe")
3378 PHAR_SET_MIME("image/jpeg", PHAR_MIME_OTHER, "jpg")
3379 PHAR_SET_MIME("image/jpeg", PHAR_MIME_OTHER, "jpeg")
3380 PHAR_SET_MIME("application/x-javascript", PHAR_MIME_OTHER, "js")
3381 PHAR_SET_MIME("audio/midi", PHAR_MIME_OTHER, "midi")
3382 PHAR_SET_MIME("audio/midi", PHAR_MIME_OTHER, "mid")
3383 PHAR_SET_MIME("audio/mod", PHAR_MIME_OTHER, "mod")
3384 PHAR_SET_MIME("movie/quicktime", PHAR_MIME_OTHER, "mov")
3385 PHAR_SET_MIME("audio/mp3", PHAR_MIME_OTHER, "mp3")
3386 PHAR_SET_MIME("video/mpeg", PHAR_MIME_OTHER, "mpg")
3387 PHAR_SET_MIME("video/mpeg", PHAR_MIME_OTHER, "mpeg")
3388 PHAR_SET_MIME("application/pdf", PHAR_MIME_OTHER, "pdf")
3389 PHAR_SET_MIME("image/png", PHAR_MIME_OTHER, "png")
3390 PHAR_SET_MIME("application/shockwave-flash", PHAR_MIME_OTHER, "swf")
3391 PHAR_SET_MIME("image/tiff", PHAR_MIME_OTHER, "tif")
3392 PHAR_SET_MIME("image/tiff", PHAR_MIME_OTHER, "tiff")
3393 PHAR_SET_MIME("audio/wav", PHAR_MIME_OTHER, "wav")
3394 PHAR_SET_MIME("image/xbm", PHAR_MIME_OTHER, "xbm")
3395 PHAR_SET_MIME("text/xml", PHAR_MIME_OTHER, "xml")
3396
3398}
3399/* }}} */
3400
3401PHP_GSHUTDOWN_FUNCTION(phar) /* {{{ */
3402{
3403 zend_hash_destroy(&phar_globals->mime_types);
3404}
3405/* }}} */
3406
3407PHP_MINIT_FUNCTION(phar) /* {{{ */
3408{
3410
3412 zend_compile_file = phar_compile_file;
3413
3414 phar_save_resolve_path = zend_resolve_path;
3415 zend_resolve_path = phar_resolve_path;
3416
3418
3421
3423}
3424/* }}} */
3425
3426PHP_MSHUTDOWN_FUNCTION(phar) /* {{{ */
3427{
3429
3431
3432 if (zend_compile_file == phar_compile_file) {
3434 }
3435
3440
3442 return SUCCESS;
3443}
3444/* }}} */
3445
3446void phar_request_initialize(void) /* {{{ */
3447{
3448 if (!PHAR_G(request_init))
3449 {
3452 PHAR_G(has_bz2) = zend_hash_str_exists(&module_registry, "bz2", sizeof("bz2")-1);
3453 PHAR_G(has_zlib) = zend_hash_str_exists(&module_registry, "zlib", sizeof("zlib")-1);
3454 PHAR_G(request_init) = 1;
3455 PHAR_G(request_ends) = 0;
3456 PHAR_G(request_done) = 0;
3457 zend_hash_init(&(PHAR_G(phar_fname_map)), 5, zend_get_hash_value, destroy_phar_data, 0);
3458 zend_hash_init(&(PHAR_G(phar_persist_map)), 5, zend_get_hash_value, NULL, 0);
3459 zend_hash_init(&(PHAR_G(phar_alias_map)), 5, zend_get_hash_value, NULL, 0);
3460
3461 if (PHAR_G(manifest_cached)) {
3462 phar_archive_data *pphar;
3463 phar_entry_fp *stuff = (phar_entry_fp *) ecalloc(zend_hash_num_elements(&cached_phars), sizeof(phar_entry_fp));
3464
3466 stuff[pphar->phar_pos].manifest = (phar_entry_fp_info *) ecalloc( zend_hash_num_elements(&(pphar->manifest)), sizeof(phar_entry_fp_info));
3468
3469 PHAR_G(cached_fp) = stuff;
3470 }
3471
3473 PHAR_G(cwd) = NULL;
3474 PHAR_G(cwd_len) = 0;
3475 PHAR_G(cwd_init) = 0;
3476 }
3477}
3478/* }}} */
3479
3480PHP_RSHUTDOWN_FUNCTION(phar) /* {{{ */
3481{
3482 PHAR_G(request_ends) = 1;
3483
3485 {
3494
3495 if (PHAR_G(cached_fp)) {
3496 for (uint32_t i = 0; i < zend_hash_num_elements(&cached_phars); ++i) {
3497 if (PHAR_G(cached_fp)[i].fp) {
3499 }
3500 if (PHAR_G(cached_fp)[i].ufp) {
3502 }
3503 efree(PHAR_G(cached_fp)[i].manifest);
3504 }
3506 PHAR_G(cached_fp) = 0;
3507 }
3508
3509 PHAR_G(request_init) = 0;
3510
3511 if (PHAR_G(cwd)) {
3512 efree(PHAR_G(cwd));
3513 }
3514
3515 PHAR_G(cwd) = NULL;
3516 PHAR_G(cwd_len) = 0;
3517 PHAR_G(cwd_init) = 0;
3518 }
3519
3521 return SUCCESS;
3522}
3523/* }}} */
3524
3525PHP_MINFO_FUNCTION(phar) /* {{{ */
3526{
3529 php_info_print_table_row(2, "Phar: PHP Archive support", "enabled");
3531 php_info_print_table_row(2, "Phar-based phar archives", "enabled");
3532 php_info_print_table_row(2, "Tar-based phar archives", "enabled");
3533 php_info_print_table_row(2, "ZIP-based phar archives", "enabled");
3534
3536 php_info_print_table_row(2, "gzip compression", "enabled");
3537 } else {
3538 php_info_print_table_row(2, "gzip compression", "disabled (install ext/zlib)");
3539 }
3540
3542 php_info_print_table_row(2, "bzip2 compression", "enabled");
3543 } else {
3544 php_info_print_table_row(2, "bzip2 compression", "disabled (install ext/bz2)");
3545 }
3546#ifdef PHAR_HAVE_OPENSSL
3547 php_info_print_table_row(2, "Native OpenSSL support", "enabled");
3548#else
3549 if (zend_hash_str_exists(&module_registry, "openssl", sizeof("openssl")-1)) {
3550 php_info_print_table_row(2, "OpenSSL support", "enabled");
3551 } else {
3552 php_info_print_table_row(2, "OpenSSL support", "disabled (install ext/openssl)");
3553 }
3554#endif
3556
3558 PUTS("Phar based on pear/PHP_Archive, original concept by Davey Shafik.");
3559 PUTS(!sapi_module.phpinfo_as_text?"<br />":"\n");
3560 PUTS("Phar fully realized by Gregory Beaver and Marcus Boerger.");
3561 PUTS(!sapi_module.phpinfo_as_text?"<br />":"\n");
3562 PUTS("Portions of tar implementation Copyright (c) 2003-2009 Tim Kientzle.");
3564
3566}
3567/* }}} */
3568
3569/* {{{ phar_module_entry */
3570static const zend_module_dep phar_deps[] = {
3571 ZEND_MOD_OPTIONAL("apc")
3572 ZEND_MOD_OPTIONAL("bz2")
3573 ZEND_MOD_OPTIONAL("openssl")
3574 ZEND_MOD_OPTIONAL("zlib")
3575 ZEND_MOD_OPTIONAL("standard")
3576 ZEND_MOD_REQUIRED("hash")
3577 ZEND_MOD_REQUIRED("spl")
3579};
3580
3583 phar_deps,
3584 "Phar",
3585 NULL,
3586 PHP_MINIT(phar),
3587 PHP_MSHUTDOWN(phar),
3588 NULL,
3589 PHP_RSHUTDOWN(phar),
3590 PHP_MINFO(phar),
3592 PHP_MODULE_GLOBALS(phar), /* globals descriptor */
3593 PHP_GINIT(phar), /* globals ctor */
3594 PHP_GSHUTDOWN(phar), /* globals dtor */
3595 NULL, /* post deactivate */
3597};
3598/* }}} */
SAPI_API sapi_module_struct sapi_module
Definition SAPI.c:65
size_t len
Definition apprentice.c:174
file_private const char ext[]
bool exception
Definition assert.c:30
file(string $filename, int $flags=0, $context=null)
strrchr(string $haystack, string $needle, bool $before_needle=false)
crc32(string $string)
strstr(string $haystack, string $needle, bool $before_needle=false)
strchr(string $haystack, string $needle, bool $before_needle=false)
realpath(string $path)
zend_long ptrdiff_t
PHPAPI zend_result php_crc32_stream_bulk_update(uint32_t *crc, php_stream *fp, size_t nr)
Definition crc32.c:131
#define php_crc32_bulk_init()
Definition crc32.h:26
#define php_crc32_bulk_end(c)
Definition crc32.h:27
error($message)
Definition ext_skel.php:22
zend_ffi_type * type
Definition ffi.c:3812
zval * zv
Definition ffi.c:3975
DL_HANDLE handle
Definition ffi.c:3028
zend_long n
Definition ffi.c:4979
zend_string * res
Definition ffi.c:4692
void * ptr
Definition ffi.c:3814
memcpy(ptr1, ptr2, size)
char * err
Definition ffi.c:3029
buf start
Definition ffi.c:4687
ffi persistent
Definition ffi.c:3633
zend_ffi_ctype_name_buf buf
Definition ffi.c:4685
const SEEK_CUR
Definition file.stub.php:16
const SEEK_END
Definition file.stub.php:21
PHPAPI int php_check_open_basedir(const char *path)
PHPAPI char * expand_filepath(const char *filepath, char *real_path)
void phar_restore_orig_functions(void)
zend_long offset
void phar_release_functions(void)
size_t filename_len
#define SIZE_MAX
Definition funcs.c:51
#define SEEK_SET
Definition gd_io_file.c:20
#define NULL
Definition gdcache.h:45
#define SUCCESS
Definition hash_sha3.c:261
foreach($dp as $el) foreach( $dp as $el) if( $pass2< 2) echo ""
PHPAPI php_stream_filter * php_stream_filter_create(const char *filtername, zval *filterparams, uint8_t persistent)
Definition filter.c:220
PHPAPI php_stream_filter * php_stream_filter_remove(php_stream_filter *filter, int call_dtor)
Definition filter.c:483
#define memmove(a, b, c)
void phar_flush_ex(phar_archive_data *phar, zend_string *user_stub, bool is_default_stub, char **error)
Definition phar.c:2533
HashTable cached_phars
Definition phar.c:90
zend_result phar_detect_phar_fname_ext(const char *filename, size_t filename_len, const char **ext_str, size_t *ext_len, int executable, int for_create, int is_complete)
Definition phar.c:1967
ini
Definition phar.c:63
php_info_print_table_start()
Definition info.c:1064
#define SAFE_PHAR_GET_32(buffer, endbuffer, var)
Definition phar.c:718
#define PHAR_ZIP_32(var)
Definition phar.c:481
zend_module_entry phar_module_entry
Definition phar.c:3581
#define PHAR_ZIP_16(var)
Definition phar.c:479
#define PHAR_SET_MIME(mimetype, ret, fileext)
Definition phar.c:3350
bool phar_metadata_tracker_has_data(const phar_metadata_tracker *tracker, bool persistent)
Definition phar.c:634
void phar_metadata_tracker_free(phar_metadata_tracker *tracker, bool persistent)
Definition phar.c:644
php_info_print_box_end()
Definition info.c:1100
void phar_entry_remove(phar_entry_data *idata, char **error)
Definition phar.c:417
memset(phar_globals, 0, sizeof(zend_phar_globals))
char * phar_fix_filepath(char *path, size_t *new_len, int use_cwd)
Definition phar.c:2128
phar_globals readonly
Definition phar.c:3346
zend_result phar_postprocess_file(phar_entry_data *idata, uint32_t crc32, char **error, int process_zip)
Definition phar.c:2378
void phar_metadata_tracker_clone(phar_metadata_tracker *tracker)
Definition phar.c:684
bool phar_archive_delref(phar_archive_data *phar)
Definition phar.c:246
#define IS_BACKSLASH(c)
Definition phar.c:2123
phar_object_init()
#define MANIFEST_FIXED_LEN
Definition phar.c:716
phar_intercept_functions_shutdown()
zend_result phar_metadata_tracker_unserialize_or_copy(phar_metadata_tracker *tracker, zval *metadata, bool persistent, HashTable *unserialize_options, const char *method_name)
Definition phar.c:593
void phar_destroy_phar_data(phar_archive_data *phar)
Definition phar.c:195
void phar_flush(phar_archive_data *phar, char **error)
Definition phar.c:2524
#define MAPPHAR_ALLOC_FAIL(msg)
Definition phar.c:441
zend_result phar_split_fname(const char *filename, size_t filename_len, char **arch, size_t *arch_len, char **entry, size_t *entry_len, int executable, int for_create)
Definition phar.c:2240
zend_result phar_create_or_parse_filename(char *fname, size_t fname_len, char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data **pphar, char **error)
Definition phar.c:1389
DISPLAY_INI_ENTRIES()
void phar_metadata_tracker_copy(phar_metadata_tracker *dest, const phar_metadata_tracker *source, bool persistent)
Definition phar.c:666
phar_intercept_functions_init()
zend_result phar_open_or_create_filename(char *fname, size_t fname_len, char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data **pphar, char **error)
Definition phar.c:1310
void phar_request_initialize(void)
Definition phar.c:3446
void phar_metadata_tracker_try_ensure_has_serialized_data(phar_metadata_tracker *tracker, bool persistent)
Definition phar.c:567
#define PHAR_GET_32(buffer, var)
Definition phar.c:472
#define IS_DIRECTORY_CURRENT(element, len)
Definition phar.c:2120
zend_result phar_open_executed_filename(char *alias, size_t alias_len, char **error)
Definition phar.c:2317
void destroy_phar_manifest_entry_int(phar_entry_info *entry)
Definition phar.c:355
#define MAX_WBITS
void destroy_phar_manifest_entry(zval *zv)
Definition phar.c:384
php_info_print_box_start(0)
#define IS_DIRECTORY_UP(element, len)
Definition phar.c:2117
phar_save_orig_functions()
HashTable cached_alias
Definition phar.c:91
#define MAPPHAR_FAIL(msg)
Definition phar.c:450
zend_string * phar_create_default_stub(const char *index_php, const char *web_index, char **error)
Definition phar.c:2485
php_info_print_table_end()
Definition info.c:1074
zend_op_array *(* phar_orig_compile_file)(zend_file_handle *file_handle, int type)
Definition phar.c:3244
return php_register_url_stream_wrapper("phar", &php_stream_phar_wrapper)
UNREGISTER_INI_ENTRIES()
void phar_parse_metadata_lazy(const char *buffer, phar_metadata_tracker *tracker, uint32_t zip_metadata_len, bool persistent)
Definition phar.c:702
php_info_print_table_row(2, "Phar: PHP Archive support", "enabled")
void phar_entry_delref(phar_entry_data *idata)
Definition phar.c:392
zend_result phar_open_from_filename(char *fname, size_t fname_len, char *alias, size_t alias_len, uint32_t options, phar_archive_data **pphar, char **error)
Definition phar.c:1543
HT_INVALIDATE & phar_globals
Definition phar.c:3343
#define PHAR_FILE_COMPRESSED_NONE
char * cache_list
#define PHAR_API_MIN_READ
void phar_add_virtual_dirs(phar_archive_data *phar, char *filename, size_t filename_len)
Definition util.c:2039
int phar_parse_zipfile(php_stream *fp, char *fname, size_t fname_len, char *alias, size_t alias_len, phar_archive_data **pphar, char **error)
Definition zip.c:229
char * last_alias
#define PHAR_SIG_OPENSSL_SHA512
char * phar_compress_filter(phar_entry_info *entry, int return_unknown)
Definition util.c:1217
@ PHAR_MOD
@ PHAR_TMP
@ PHAR_FP
@ PHAR_UFP
#define PHAR_FILE_COMPRESSED_BZ2
struct _phar_metadata_tracker phar_metadata_tracker
bool request_init
#define PHAR_MIME_PHPS
#define PHAR_ENT_COMPRESSED_GZ
struct _phar_entry_fp phar_entry_fp
bool has_zlib
int phar_seek_efp(phar_entry_info *entry, zend_off_t offset, int whence, zend_off_t position, int follow_links)
Definition util.c:140
#define PHAR_SIG_OPENSSL_SHA256
#define PHAR_FILE_COMPRESSED_GZ
HashTable phar_alias_map
#define PHP_PHAR_API_VERSION
#define PHAR_API_VERSION_NODIR
phar_archive_data * last_phar
struct _phar_entry_fp_info phar_entry_fp_info
#define PHAR_MIME_OTHER
bool readonly_orig
zend_result phar_parse_tarfile(php_stream *fp, char *fname, size_t fname_len, char *alias, size_t alias_len, phar_archive_data **pphar, uint32_t compression, char **error)
Definition tar.c:205
#define PHAR_ENT_PERM_DEF_DIR
bool require_hash
bool has_bz2
int phar_SERVER_mung_list
#define PHAR_HDR_SIGNATURE
#define PHAR_HDR_COMPRESSION_MASK
HashTable phar_fname_map
char * cwd
php_stream * phar_get_efp(phar_entry_info *entry, int follow_links)
Definition util.c:97
#define PHAR_SIG_SHA1
#define PHAR_G(v)
HashTable phar_persist_map
struct _phar_archive_data phar_archive_data
bool manifest_cached
uint32_t cwd_len
#define PHAR_ENT_COMPRESSION_MASK
bool request_ends
#define PHAR_MIME_PHP
zend_result phar_create_signature(phar_archive_data *phar, php_stream *fp, char **signature, size_t *signature_length, char **error)
Definition util.c:1857
#define PHAR_SIG_OPENSSL
#define PHAR_API_MIN_DIR
zend_result phar_open_archive_fp(phar_archive_data *phar)
Definition util.c:753
void phar_tar_flush(phar_archive_data *phar, zend_string *user_stub, bool is_default_stub, char **error)
Definition tar.c:962
#define PHAR_ENT_COMPRESSED_BZ2
#define PHAR_SIG_SHA512
zend_result phar_free_alias(phar_archive_data *phar, char *alias, size_t alias_len)
Definition util.c:990
zend_result phar_verify_signature(php_stream *fp, size_t end_of_phar, uint32_t sig_type, char *sig, size_t sig_len, char *fname, char **signature, size_t *signature_len, char **error)
Definition util.c:1543
void phar_zip_flush(phar_archive_data *archive, zend_string *user_stub, bool is_default_stub, char **error)
Definition zip.c:1254
struct _phar_entry_info phar_entry_info
#define PHAR_SIG_SHA256
bool persist
zend_string * phar_find_in_include_path(zend_string *file, phar_archive_data **pphar)
Definition util.c:266
struct _phar_entry_data phar_entry_data
bool require_hash_orig
phar_entry_fp * cached_fp
struct _phar_mime_type phar_mime_type
#define PHAR_FILE_COMPRESSION_MASK
bool cwd_init
#define PHAR_API_VERSION
char * last_phar_name
zend_result phar_get_archive(phar_archive_data **archive, char *fname, size_t fname_len, char *alias, size_t alias_len, char **error)
Definition util.c:1013
#define PHAR_SIG_MD5
zend_result phar_open_or_create_tar(char *fname, size_t fname_len, char *alias, size_t alias_len, int is_data, uint32_t options, phar_archive_data **pphar, char **error)
Definition tar.c:130
int phar_open_or_create_zip(char *fname, size_t fname_len, char *alias, size_t alias_len, int is_data, uint32_t options, phar_archive_data **pphar, char **error)
Definition zip.c:827
phar_entry_info * phar_open_jit(phar_archive_data *phar, phar_entry_info *entry, char **error)
Definition util.c:961
bool phar_is_tar(char *buf, char *fname)
Definition tar.c:103
#define PHAR_API_VER_MASK
bool request_done
struct _phar_zip_file_header phar_zip_file_header
struct _phar_zip_file_datadesc phar_zip_data_desc
#define PHP_GINIT
Definition php.h:397
#define PHP_MSHUTDOWN_FUNCTION
Definition php.h:401
#define PHP_MINFO
Definition php.h:396
#define PHP_MINIT_FUNCTION
Definition php.h:400
#define PHP_MSHUTDOWN
Definition php.h:393
#define PHP_MINFO_FUNCTION
Definition php.h:404
#define PHP_GINIT_FUNCTION
Definition php.h:405
#define PHP_RSHUTDOWN
Definition php.h:395
#define PHP_RSHUTDOWN_FUNCTION
Definition php.h:403
#define PHP_GSHUTDOWN_FUNCTION
Definition php.h:406
#define PHP_MINIT
Definition php.h:392
#define PHP_MODULE_GLOBALS
Definition php.h:408
#define PHP_GSHUTDOWN
Definition php.h:398
time()
unsigned const char * end
Definition php_ffi.h:51
unsigned const char * pos
Definition php_ffi.h:52
#define PHP_INI_ALL
Definition php_ini.h:45
#define PHP_INI_BEGIN
Definition php_ini.h:52
#define STD_PHP_INI_ENTRY
Definition php_ini.h:64
#define STD_PHP_INI_BOOLEAN
Definition php_ini.h:66
#define PHP_INI_SYSTEM
Definition php_ini.h:43
#define PHP_INI_END
Definition php_ini.h:53
PHP_JSON_API size_t int options
Definition php_json.h:102
#define PUTS(str)
#define PHP_PHAR_VERSION
Definition php_phar.h:23
PHPAPI char * php_strtok_r(char *s, const char *delim, char **last)
Definition reentrancy.c:263
unsigned char key[REFLECTION_KEY_LEN]
#define php_stream_filter_append(chain, filter)
#define php_stream_filter_flush(filter, finish)
#define php_stream_fopen_tmpfile()
#define php_stream_stat_path(path, ssb)
struct _php_stream php_stream
Definition php_streams.h:96
#define REPORT_ERRORS
#define php_stream_read(stream, buf, count)
struct _php_stream_filter php_stream_filter
Definition php_streams.h:99
#define php_stream_rewind(stream)
#define PHP_STREAM_COPY_ALL
#define php_stream_getc(stream)
#define php_stream_seek(stream, offset, whence)
#define php_stream_flush(stream)
#define php_stream_eof(stream)
#define php_stream_close(stream)
#define php_stream_tell(stream)
#define php_stream_is_persistent(stream)
#define php_stream_open_wrapper(path, mode, options, opened)
PHPAPI zend_result php_unregister_url_stream_wrapper(const char *protocol)
Definition streams.c:1927
#define php_stream_copy_to_stream_ex(src, dest, maxlen, len)
#define STREAM_MUST_SEEK
#define IGNORE_URL
struct _php_stream_statbuf php_stream_statbuf
#define php_stream_write(stream, buf, count)
PHPAPI char * php_stristr(const char *s, const char *t, size_t s_len, size_t t_len)
Definition string.c:1672
struct php_serialize_data * php_serialize_data_t
Definition php_var.h:31
PHPAPI void php_unserialize_with_options(zval *return_value, const char *buf, const size_t buf_len, HashTable *options, const char *function_name)
Definition var.c:1380
#define PHP_VAR_SERIALIZE_INIT(d)
Definition php_var.h:50
PHPAPI void php_var_serialize(smart_str *buf, zval *struc, php_serialize_data_t *data)
Definition var.c:1319
#define PHP_VAR_SERIALIZE_DESTROY(d)
Definition php_var.h:53
p
Definition session.c:1105
#define spprintf
Definition spprintf.h:29
const php_stream_wrapper php_stream_phar_wrapper
Definition stream.c:51
phar_metadata_tracker metadata_tracker
uint32_t is_temporary_alias
phar_archive_data * phar
phar_entry_info * internal_file
zend_off_t zero
php_stream * fp
phar_entry_fp_info * manifest
uint32_t timestamp
zend_long header_offset
uint32_t is_modified
uint32_t is_crc_checked
uint32_t flags
uint32_t is_deleted
uint32_t is_dir
char * filename
uint32_t manifest_pos
uint32_t compressed_filesize
php_stream * fp
int fp_refcount
uint32_t is_temp_dir
uint32_t old_flags
uint32_t is_zip
phar_metadata_tracker metadata_tracker
uint32_t is_mounted
enum phar_fp_type fp_type
php_stream * cfp
uint32_t crc32
char * tmp
uint32_t uncompressed_filesize
phar_archive_data * phar
uint32_t is_persistent
uint32_t filename_len
char * link
zend_long offset
zend_long offset_abs
php_stream_filter_chain writefilters
zend_string * filename
Definition zend_stream.h:58
zend_string * opened_path
Definition zend_stream.h:59
zend_stream stream
Definition zend_stream.h:56
union _zend_file_handle::@045057025306333206016200356074063117305134322373 handle
zend_stream_closer_t closer
Definition zend_stream.h:50
void * handle
Definition zend_stream.h:46
zend_stream_fsizer_t fsizer
Definition zend_stream.h:49
zend_stream_reader_t reader
Definition zend_stream.h:48
Definition file.h:177
zend_string * s
test($x, $y=0)
Definition test.php:21
ZEND_API zend_string * zend_strpprintf(size_t max_len, const char *format,...)
Definition zend.c:353
ZEND_API zend_result(* zend_stream_open_function)(zend_file_handle *handle)
Definition zend.c:87
ZEND_API zend_string *(* zend_resolve_path)(zend_string *filename)
Definition zend.c:94
#define ZEND_TSRMLS_CACHE_UPDATE()
Definition zend.h:69
#define zend_catch
Definition zend.h:277
#define zend_try
Definition zend.h:270
#define zend_end_try()
Definition zend.h:280
#define ZEND_TSRMLS_CACHE_DEFINE()
Definition zend.h:68
#define zend_bailout()
Definition zend.h:268
ZEND_API HashTable module_registry
Definition zend_API.c:41
ZEND_API void add_assoc_long_ex(zval *arg, const char *key, size_t key_len, zend_long n)
Definition zend_API.c:1928
#define CHECK_NULL_PATH(p, l)
Definition zend_API.h:950
#define ZEND_DECLARE_MODULE_GLOBALS(module_name)
Definition zend_API.h:268
#define ZEND_GET_MODULE(name)
Definition zend_API.h:241
#define array_init(arg)
Definition zend_API.h:537
#define estrndup(s, length)
Definition zend_alloc.h:165
#define ecalloc(nmemb, size)
Definition zend_alloc.h:158
#define pestrndup(s, length, persistent)
Definition zend_alloc.h:207
#define efree(ptr)
Definition zend_alloc.h:155
#define estrdup(s)
Definition zend_alloc.h:164
#define pefree(ptr, persistent)
Definition zend_alloc.h:191
#define erealloc(ptr, size)
Definition zend_alloc.h:159
#define pecalloc(nmemb, size, persistent)
Definition zend_alloc.h:200
#define emalloc(size)
Definition zend_alloc.h:151
struct _zval_struct zval
strlen(string $string)
strncmp(string $string1, string $string2, int $length)
zend_string_release_ex(func->internal_function.function_name, 0)
ZEND_API zend_op_array *(* zend_compile_file)(zend_file_handle *file_handle, int type)
struct _zend_op_array zend_op_array
#define strncasecmp(s1, s2, n)
#define snprintf
ZEND_API zval * zend_get_constant_str(const char *name, size_t name_len)
ZEND_API zend_string * zend_get_executed_filename_ex(void)
#define CG(v)
#define EG(v)
ZEND_API void ZEND_FASTCALL zend_hash_destroy(HashTable *ht)
Definition zend_hash.c:1727
ZEND_API void ZEND_FASTCALL zend_hash_apply(HashTable *ht, apply_func_t apply_func)
Definition zend_hash.c:2059
ZEND_API void ZEND_FASTCALL zend_hash_apply_with_argument(HashTable *ht, apply_func_arg_t apply_func, void *argument)
Definition zend_hash.c:2099
ZEND_API void ZEND_FASTCALL zend_hash_clean(HashTable *ht)
Definition zend_hash.c:1869
ZEND_API void ZEND_FASTCALL zend_hash_graceful_reverse_destroy(HashTable *ht)
Definition zend_hash.c:2015
ZEND_API void ZEND_FASTCALL zend_array_destroy(HashTable *ht)
Definition zend_hash.c:1808
ZEND_API zend_result ZEND_FASTCALL zend_hash_str_del(HashTable *ht, const char *str, size_t len)
Definition zend_hash.c:1661
#define zend_hash_init(ht, nSize, pHashFunction, pDestructor, persistent)
Definition zend_hash.h:108
#define ZEND_HASH_MAP_FOREACH_PTR(ht, _ptr)
Definition zend_hash.h:1326
#define HT_IS_INITIALIZED(ht)
Definition zend_hash.h:56
#define ZEND_HASH_APPLY_REMOVE
Definition zend_hash.h:147
#define HT_INVALIDATE(ht)
Definition zend_hash.h:52
#define ZEND_HASH_APPLY_KEEP
Definition zend_hash.h:146
#define ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(ht, _key, _ptr)
Definition zend_hash.h:1433
#define ZEND_HASH_FOREACH_END()
Definition zend_hash.h:1086
ZEND_API bool zend_ini_parse_bool(zend_string *str)
Definition zend_ini.c:573
#define ZEND_INI_STAGE_STARTUP
Definition zend_ini.h:227
#define REGISTER_INI_ENTRIES()
Definition zend_ini.h:203
#define ZEND_INI_MH(name)
Definition zend_ini.h:30
struct _zend_file_handle zend_file_handle
ZEND_API void zend_init_rsrc_list(void)
Definition zend_list.c:202
int32_t zend_long
Definition zend_long.h:42
int32_t zend_off_t
Definition zend_long.h:44
struct _zend_string zend_string
#define ZEND_MOD_END
#define ZEND_MOD_OPTIONAL(name)
struct _zend_module_dep zend_module_dep
struct _zend_module_entry zend_module_entry
#define ZEND_MOD_REQUIRED(name)
#define STANDARD_MODULE_PROPERTIES_EX
#define STANDARD_MODULE_HEADER_EX
#define ALLOCA_FLAG(name)
#define do_alloca(p, use_heap)
#define ZEND_ASSERT(c)
#define free_alloca(p, use_heap)
ZEND_API void zend_stream_init_filename_ex(zend_file_handle *handle, zend_string *filename)
Definition zend_stream.c:76
@ ZEND_HANDLE_STREAM
Definition zend_stream.h:42
ZEND_API zend_string_init_interned_func_t zend_string_init_interned
Definition zend_string.c:31
#define ZSTR_VAL(zstr)
Definition zend_string.h:68
#define ZSTR_LEN(zstr)
Definition zend_string.h:69
#define Z_TRY_ADDREF_P(pz)
#define ZVAL_UNDEF(z)
#define ZVAL_NULL(z)
struct _zend_array HashTable
Definition zend_types.h:386
#define Z_ISUNDEF(zval)
Definition zend_types.h:956
#define Z_PTR_P(zval_p)
@ FAILURE
Definition zend_types.h:61
#define ZVAL_COPY(z, v)
#define Z_ARR(zval)
Definition zend_types.h:983
ZEND_RESULT_CODE zend_result
Definition zend_types.h:64
#define ZVAL_COPY_VALUE(z, v)
ZEND_API void zval_ptr_dtor(zval *zval_ptr)
#define DEFAULT_DIR_SEPARATOR
zend_string * name
zval * ret