This source file includes following definitions.
- ZEND_DECLARE_MODULE_GLOBALS
- ZEND_INI_MH
- phar_split_cache_list
- ZEND_INI_MH
- PHP_INI_BEGIN
- phar_archive_delref
- destroy_phar_data_only
- phar_unalias_apply
- phar_tmpclose_apply
- destroy_phar_data
- destroy_phar_manifest_entry
- phar_entry_delref
- phar_entry_remove
- phar_open_parsed_phar
- phar_parse_metadata
- phar_parse_pharfile
- phar_open_or_create_filename
- phar_create_or_parse_filename
- phar_open_from_filename
- phar_strnstr
- phar_open_from_fp
- phar_analyze_path
- phar_check_str
- phar_detect_phar_fname_ext
- php_check_dots
- in_character_class
- tsrm_strtok_r
- phar_fix_filepath
- phar_split_fname
- phar_open_executed_filename
- phar_postprocess_file
- phar_set_32
- phar_flush_clean_deleted_apply
- phar_create_default_stub
- phar_flush
- phar_zend_stream_reader
- phar_zend_stream_fsizer
- phar_resolve_path
- phar_compile_file
- PHP_GINIT_FUNCTION
- PHP_GSHUTDOWN_FUNCTION
- PHP_MINIT_FUNCTION
- PHP_MSHUTDOWN_FUNCTION
- phar_request_initialize
- PHP_RSHUTDOWN_FUNCTION
- PHP_MINFO_FUNCTION
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 #define PHAR_MAIN 1
23 #include "phar_internal.h"
24 #include "SAPI.h"
25 #include "func_interceptors.h"
26
27 static void destroy_phar_data(void *pDest);
28
29 ZEND_DECLARE_MODULE_GLOBALS(phar)
30 char *(*phar_save_resolve_path)(const char *filename, int filename_len TSRMLS_DC);
31
32
33
34
35 static int phar_set_writeable_bit(void *pDest, void *argument TSRMLS_DC)
36 {
37 zend_bool keep = *(zend_bool *)argument;
38 phar_archive_data *phar = *(phar_archive_data **)pDest;
39
40 if (!phar->is_data) {
41 phar->is_writeable = !keep;
42 }
43
44 return ZEND_HASH_APPLY_KEEP;
45 }
46
47
48
49 ZEND_INI_MH(phar_ini_modify_handler)
50 {
51 zend_bool old, ini;
52
53 if (entry->name_length == 14) {
54 old = PHAR_G(readonly_orig);
55 } else {
56 old = PHAR_G(require_hash_orig);
57 }
58
59 if (new_value_length == 2 && !strcasecmp("on", new_value)) {
60 ini = (zend_bool) 1;
61 }
62 else if (new_value_length == 3 && !strcasecmp("yes", new_value)) {
63 ini = (zend_bool) 1;
64 }
65 else if (new_value_length == 4 && !strcasecmp("true", new_value)) {
66 ini = (zend_bool) 1;
67 }
68 else {
69 ini = (zend_bool) atoi(new_value);
70 }
71
72
73 if (stage == ZEND_INI_STAGE_STARTUP) {
74 if (entry->name_length == 14) {
75 PHAR_G(readonly_orig) = ini;
76 } else {
77 PHAR_G(require_hash_orig) = ini;
78 }
79 } else if (old && !ini) {
80 return FAILURE;
81 }
82
83 if (entry->name_length == 14) {
84 PHAR_G(readonly) = ini;
85 if (PHAR_GLOBALS->request_init && PHAR_GLOBALS->phar_fname_map.arBuckets) {
86 zend_hash_apply_with_argument(&(PHAR_GLOBALS->phar_fname_map), phar_set_writeable_bit, (void *)&ini TSRMLS_CC);
87 }
88 } else {
89 PHAR_G(require_hash) = ini;
90 }
91
92 return SUCCESS;
93 }
94
95
96
97 HashTable cached_phars;
98 HashTable cached_alias;
99
100 static void phar_split_cache_list(TSRMLS_D)
101 {
102 char *tmp;
103 char *key, *lasts, *end;
104 char ds[2];
105 phar_archive_data *phar;
106 uint i = 0;
107
108 if (!PHAR_GLOBALS->cache_list || !(PHAR_GLOBALS->cache_list[0])) {
109 return;
110 }
111
112 ds[0] = DEFAULT_DIR_SEPARATOR;
113 ds[1] = '\0';
114 tmp = estrdup(PHAR_GLOBALS->cache_list);
115
116
117 PHAR_GLOBALS->request_init = 1;
118 if (zend_hash_init(&EG(regular_list), 0, NULL, NULL, 0) == SUCCESS) {
119 EG(regular_list).nNextFreeElement=1;
120 }
121
122 PHAR_G(has_bz2) = zend_hash_exists(&module_registry, "bz2", sizeof("bz2"));
123 PHAR_G(has_zlib) = zend_hash_exists(&module_registry, "zlib", sizeof("zlib"));
124
125 zend_hash_init(&cached_phars, sizeof(phar_archive_data*), zend_get_hash_value, destroy_phar_data, 1);
126 zend_hash_init(&cached_alias, sizeof(phar_archive_data*), zend_get_hash_value, NULL, 1);
127
128 zend_hash_init(&(PHAR_GLOBALS->phar_fname_map), sizeof(phar_archive_data*), zend_get_hash_value, destroy_phar_data, 1);
129 zend_hash_init(&(PHAR_GLOBALS->phar_alias_map), sizeof(phar_archive_data*), zend_get_hash_value, NULL, 1);
130 PHAR_GLOBALS->manifest_cached = 1;
131 PHAR_GLOBALS->persist = 1;
132
133 for (key = php_strtok_r(tmp, ds, &lasts);
134 key;
135 key = php_strtok_r(NULL, ds, &lasts)) {
136 end = strchr(key, DEFAULT_DIR_SEPARATOR);
137
138 if (end) {
139 if (SUCCESS == phar_open_from_filename(key, end - key, NULL, 0, 0, &phar, NULL TSRMLS_CC)) {
140 finish_up:
141 phar->phar_pos = i++;
142 php_stream_close(phar->fp);
143 phar->fp = NULL;
144 } else {
145 finish_error:
146 PHAR_GLOBALS->persist = 0;
147 PHAR_GLOBALS->manifest_cached = 0;
148 efree(tmp);
149 zend_hash_destroy(&(PHAR_G(phar_fname_map)));
150 PHAR_GLOBALS->phar_fname_map.arBuckets = 0;
151 zend_hash_destroy(&(PHAR_G(phar_alias_map)));
152 PHAR_GLOBALS->phar_alias_map.arBuckets = 0;
153 zend_hash_destroy(&cached_phars);
154 zend_hash_destroy(&cached_alias);
155 zend_hash_graceful_reverse_destroy(&EG(regular_list));
156 memset(&EG(regular_list), 0, sizeof(HashTable));
157
158 PHAR_GLOBALS->request_init = 0;
159 return;
160 }
161 } else {
162 if (SUCCESS == phar_open_from_filename(key, strlen(key), NULL, 0, 0, &phar, NULL TSRMLS_CC)) {
163 goto finish_up;
164 } else {
165 goto finish_error;
166 }
167 }
168 }
169
170 PHAR_GLOBALS->persist = 0;
171 PHAR_GLOBALS->request_init = 0;
172
173 zend_hash_destroy(&cached_phars);
174 zend_hash_destroy(&cached_alias);
175 cached_phars = PHAR_GLOBALS->phar_fname_map;
176 cached_alias = PHAR_GLOBALS->phar_alias_map;
177 PHAR_GLOBALS->phar_fname_map.arBuckets = 0;
178 PHAR_GLOBALS->phar_alias_map.arBuckets = 0;
179 zend_hash_graceful_reverse_destroy(&EG(regular_list));
180 memset(&EG(regular_list), 0, sizeof(HashTable));
181 efree(tmp);
182 }
183
184
185 ZEND_INI_MH(phar_ini_cache_list)
186 {
187 PHAR_G(cache_list) = new_value;
188
189 if (stage == ZEND_INI_STAGE_STARTUP) {
190 phar_split_cache_list(TSRMLS_C);
191 }
192
193 return SUCCESS;
194 }
195
196
197 PHP_INI_BEGIN()
198 STD_PHP_INI_BOOLEAN("phar.readonly", "1", PHP_INI_ALL, phar_ini_modify_handler, readonly, zend_phar_globals, phar_globals)
199 STD_PHP_INI_BOOLEAN("phar.require_hash", "1", PHP_INI_ALL, phar_ini_modify_handler, require_hash, zend_phar_globals, phar_globals)
200 STD_PHP_INI_ENTRY("phar.cache_list", "", PHP_INI_SYSTEM, phar_ini_cache_list, cache_list, zend_phar_globals, phar_globals)
201 PHP_INI_END()
202
203
204
205
206
207 void phar_destroy_phar_data(phar_archive_data *phar TSRMLS_DC)
208 {
209 if (phar->alias && phar->alias != phar->fname) {
210 pefree(phar->alias, phar->is_persistent);
211 phar->alias = NULL;
212 }
213
214 if (phar->fname) {
215 pefree(phar->fname, phar->is_persistent);
216 phar->fname = NULL;
217 }
218
219 if (phar->signature) {
220 pefree(phar->signature, phar->is_persistent);
221 phar->signature = NULL;
222 }
223
224 if (phar->manifest.arBuckets) {
225 zend_hash_destroy(&phar->manifest);
226 phar->manifest.arBuckets = NULL;
227 }
228
229 if (phar->mounted_dirs.arBuckets) {
230 zend_hash_destroy(&phar->mounted_dirs);
231 phar->mounted_dirs.arBuckets = NULL;
232 }
233
234 if (phar->virtual_dirs.arBuckets) {
235 zend_hash_destroy(&phar->virtual_dirs);
236 phar->virtual_dirs.arBuckets = NULL;
237 }
238
239 if (phar->metadata) {
240 if (phar->is_persistent) {
241 if (phar->metadata_len) {
242
243 free(phar->metadata);
244 } else {
245 zval_internal_ptr_dtor(&phar->metadata);
246 }
247 } else {
248 zval_ptr_dtor(&phar->metadata);
249 }
250 phar->metadata_len = 0;
251 phar->metadata = 0;
252 }
253
254 if (phar->fp) {
255 php_stream_close(phar->fp);
256 phar->fp = 0;
257 }
258
259 if (phar->ufp) {
260 php_stream_close(phar->ufp);
261 phar->ufp = 0;
262 }
263
264 pefree(phar, phar->is_persistent);
265 }
266
267
268
269
270
271 int phar_archive_delref(phar_archive_data *phar TSRMLS_DC)
272 {
273 if (phar->is_persistent) {
274 return 0;
275 }
276
277 if (--phar->refcount < 0) {
278 if (PHAR_GLOBALS->request_done
279 || zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), phar->fname, phar->fname_len) != SUCCESS) {
280 phar_destroy_phar_data(phar TSRMLS_CC);
281 }
282 return 1;
283 } else if (!phar->refcount) {
284
285 PHAR_G(last_phar) = NULL;
286 PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
287
288 if (phar->fp && !(phar->flags & PHAR_FILE_COMPRESSION_MASK)) {
289
290
291
292
293 php_stream_close(phar->fp);
294 phar->fp = NULL;
295 }
296
297 if (!zend_hash_num_elements(&phar->manifest)) {
298
299
300 if (zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), phar->fname, phar->fname_len) != SUCCESS) {
301 phar_destroy_phar_data(phar TSRMLS_CC);
302 }
303 return 1;
304 }
305 }
306 return 0;
307 }
308
309
310
311
312
313 static void destroy_phar_data_only(void *pDest)
314 {
315 phar_archive_data *phar_data = *(phar_archive_data **) pDest;
316 TSRMLS_FETCH();
317
318 if (EG(exception) || --phar_data->refcount < 0) {
319 phar_destroy_phar_data(phar_data TSRMLS_CC);
320 }
321 }
322
323
324
325
326
327 static int phar_unalias_apply(void *pDest, void *argument TSRMLS_DC)
328 {
329 return *(void**)pDest == argument ? ZEND_HASH_APPLY_REMOVE : ZEND_HASH_APPLY_KEEP;
330 }
331
332
333
334
335
336 static int phar_tmpclose_apply(void *pDest TSRMLS_DC)
337 {
338 phar_entry_info *entry = (phar_entry_info *) pDest;
339
340 if (entry->fp_type != PHAR_TMP) {
341 return ZEND_HASH_APPLY_KEEP;
342 }
343
344 if (entry->fp && !entry->fp_refcount) {
345 php_stream_close(entry->fp);
346 entry->fp = NULL;
347 }
348
349 return ZEND_HASH_APPLY_KEEP;
350 }
351
352
353
354
355
356 static void destroy_phar_data(void *pDest)
357 {
358 phar_archive_data *phar_data = *(phar_archive_data **) pDest;
359 TSRMLS_FETCH();
360
361 if (PHAR_GLOBALS->request_ends) {
362
363
364 zend_hash_apply(&(phar_data->manifest), phar_tmpclose_apply TSRMLS_CC);
365 destroy_phar_data_only(pDest);
366 return;
367 }
368
369 zend_hash_apply_with_argument(&(PHAR_GLOBALS->phar_alias_map), phar_unalias_apply, phar_data TSRMLS_CC);
370
371 if (--phar_data->refcount < 0) {
372 phar_destroy_phar_data(phar_data TSRMLS_CC);
373 }
374 }
375
376
377
378
379
380 void destroy_phar_manifest_entry(void *pDest)
381 {
382 phar_entry_info *entry = (phar_entry_info *)pDest;
383 TSRMLS_FETCH();
384
385 if (entry->cfp) {
386 php_stream_close(entry->cfp);
387 entry->cfp = 0;
388 }
389
390 if (entry->fp) {
391 php_stream_close(entry->fp);
392 entry->fp = 0;
393 }
394
395 if (entry->metadata) {
396 if (entry->is_persistent) {
397 if (entry->metadata_len) {
398
399 free(entry->metadata);
400 } else {
401 zval_internal_ptr_dtor(&entry->metadata);
402 }
403 } else {
404 zval_ptr_dtor(&entry->metadata);
405 }
406 entry->metadata_len = 0;
407 entry->metadata = 0;
408 }
409
410 if (entry->metadata_str.c) {
411 smart_str_free(&entry->metadata_str);
412 entry->metadata_str.c = 0;
413 }
414
415 pefree(entry->filename, entry->is_persistent);
416
417 if (entry->link) {
418 pefree(entry->link, entry->is_persistent);
419 entry->link = 0;
420 }
421
422 if (entry->tmp) {
423 pefree(entry->tmp, entry->is_persistent);
424 entry->tmp = 0;
425 }
426 }
427
428
429 int phar_entry_delref(phar_entry_data *idata TSRMLS_DC)
430 {
431 int ret = 0;
432
433 if (idata->internal_file && !idata->internal_file->is_persistent) {
434 if (--idata->internal_file->fp_refcount < 0) {
435 idata->internal_file->fp_refcount = 0;
436 }
437
438 if (idata->fp && idata->fp != idata->phar->fp && idata->fp != idata->phar->ufp && idata->fp != idata->internal_file->fp) {
439 php_stream_close(idata->fp);
440 }
441
442 if (idata->internal_file->is_temp_dir) {
443 destroy_phar_manifest_entry((void *)idata->internal_file);
444 efree(idata->internal_file);
445 }
446 }
447
448 phar_archive_delref(idata->phar TSRMLS_CC);
449 efree(idata);
450 return ret;
451 }
452
453
454
455
456
457 void phar_entry_remove(phar_entry_data *idata, char **error TSRMLS_DC)
458 {
459 phar_archive_data *phar;
460
461 phar = idata->phar;
462
463 if (idata->internal_file->fp_refcount < 2) {
464 if (idata->fp && idata->fp != idata->phar->fp && idata->fp != idata->phar->ufp && idata->fp != idata->internal_file->fp) {
465 php_stream_close(idata->fp);
466 }
467 zend_hash_del(&idata->phar->manifest, idata->internal_file->filename, idata->internal_file->filename_len);
468 idata->phar->refcount--;
469 efree(idata);
470 } else {
471 idata->internal_file->is_deleted = 1;
472 phar_entry_delref(idata TSRMLS_CC);
473 }
474
475 if (!phar->donotflush) {
476 phar_flush(phar, 0, 0, 0, error TSRMLS_CC);
477 }
478 }
479
480
481 #define MAPPHAR_ALLOC_FAIL(msg) \
482 if (fp) {\
483 php_stream_close(fp);\
484 }\
485 if (error) {\
486 spprintf(error, 0, msg, fname);\
487 }\
488 return FAILURE;
489
490 #define MAPPHAR_FAIL(msg) \
491 efree(savebuf);\
492 if (mydata) {\
493 phar_destroy_phar_data(mydata TSRMLS_CC);\
494 }\
495 if (signature) {\
496 pefree(signature, PHAR_G(persist));\
497 }\
498 MAPPHAR_ALLOC_FAIL(msg)
499
500 #ifdef WORDS_BIGENDIAN
501 # define PHAR_GET_32(buffer, var) \
502 var = ((((unsigned char*)(buffer))[3]) << 24) \
503 | ((((unsigned char*)(buffer))[2]) << 16) \
504 | ((((unsigned char*)(buffer))[1]) << 8) \
505 | (((unsigned char*)(buffer))[0]); \
506 (buffer) += 4
507 # define PHAR_GET_16(buffer, var) \
508 var = ((((unsigned char*)(buffer))[1]) << 8) \
509 | (((unsigned char*)(buffer))[0]); \
510 (buffer) += 2
511 #else
512 # define PHAR_GET_32(buffer, var) \
513 memcpy(&var, buffer, sizeof(var)); \
514 buffer += 4
515 # define PHAR_GET_16(buffer, var) \
516 var = *(php_uint16*)(buffer); \
517 buffer += 2
518 #endif
519 #define PHAR_ZIP_16(var) ((php_uint16)((((php_uint16)var[0]) & 0xff) | \
520 (((php_uint16)var[1]) & 0xff) << 8))
521 #define PHAR_ZIP_32(var) ((php_uint32)((((php_uint32)var[0]) & 0xff) | \
522 (((php_uint32)var[1]) & 0xff) << 8 | \
523 (((php_uint32)var[2]) & 0xff) << 16 | \
524 (((php_uint32)var[3]) & 0xff) << 24))
525
526
527
528
529 int phar_open_parsed_phar(char *fname, int fname_len, char *alias, int alias_len, int is_data, int options, phar_archive_data** pphar, char **error TSRMLS_DC)
530 {
531 phar_archive_data *phar;
532 #ifdef PHP_WIN32
533 char *unixfname;
534 #endif
535
536 if (error) {
537 *error = NULL;
538 }
539 #ifdef PHP_WIN32
540 unixfname = estrndup(fname, fname_len);
541 phar_unixify_path_separators(unixfname, fname_len);
542
543 if (SUCCESS == phar_get_archive(&phar, unixfname, fname_len, alias, alias_len, error TSRMLS_CC)
544 && ((alias && fname_len == phar->fname_len
545 && !strncmp(unixfname, phar->fname, fname_len)) || !alias)
546 ) {
547 phar_entry_info *stub;
548 efree(unixfname);
549 #else
550 if (SUCCESS == phar_get_archive(&phar, fname, fname_len, alias, alias_len, error TSRMLS_CC)
551 && ((alias && fname_len == phar->fname_len
552 && !strncmp(fname, phar->fname, fname_len)) || !alias)
553 ) {
554 phar_entry_info *stub;
555 #endif
556
557
558
559
560
561
562 if (!is_data) {
563
564 if (!phar->halt_offset && !phar->is_brandnew && (phar->is_tar || phar->is_zip)) {
565 if (PHAR_G(readonly) && FAILURE == zend_hash_find(&(phar->manifest), ".phar/stub.php", sizeof(".phar/stub.php")-1, (void **)&stub)) {
566 if (error) {
567 spprintf(error, 0, "'%s' is not a phar archive. Use PharData::__construct() for a standard zip or tar archive", fname);
568 }
569 return FAILURE;
570 }
571 }
572 }
573
574 if (pphar) {
575 *pphar = phar;
576 }
577
578 return SUCCESS;
579 } else {
580 #ifdef PHP_WIN32
581 efree(unixfname);
582 #endif
583 if (pphar) {
584 *pphar = NULL;
585 }
586
587 if (phar && error && !(options & REPORT_ERRORS)) {
588 efree(error);
589 }
590
591 return FAILURE;
592 }
593 }
594
595
596
597
598
599
600
601
602
603
604 int phar_parse_metadata(char **buffer, zval **metadata, php_uint32 zip_metadata_len TSRMLS_DC)
605 {
606 php_unserialize_data_t var_hash;
607
608 if (zip_metadata_len) {
609 const unsigned char *p;
610 unsigned char *p_buff = (unsigned char *)estrndup(*buffer, zip_metadata_len);
611 p = p_buff;
612 ALLOC_ZVAL(*metadata);
613 INIT_ZVAL(**metadata);
614 PHP_VAR_UNSERIALIZE_INIT(var_hash);
615
616 if (!php_var_unserialize(metadata, &p, p + zip_metadata_len, &var_hash TSRMLS_CC)) {
617 efree(p_buff);
618 PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
619 zval_ptr_dtor(metadata);
620 *metadata = NULL;
621 return FAILURE;
622 }
623 efree(p_buff);
624 PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
625
626 if (PHAR_G(persist)) {
627
628 zval_ptr_dtor(metadata);
629 *metadata = (zval *) pemalloc(zip_metadata_len, 1);
630 memcpy(*metadata, *buffer, zip_metadata_len);
631 return SUCCESS;
632 }
633 } else {
634 *metadata = NULL;
635 }
636
637 return SUCCESS;
638 }
639
640
641
642
643
644
645
646
647
648
649
650 static int phar_parse_pharfile(php_stream *fp, char *fname, int fname_len, char *alias, int alias_len, long halt_offset, phar_archive_data** pphar, php_uint32 compression, char **error TSRMLS_DC)
651 {
652 char b32[4], *buffer, *endbuffer, *savebuf;
653 phar_archive_data *mydata = NULL;
654 phar_entry_info entry;
655 php_uint32 manifest_len, manifest_count, manifest_flags, manifest_index, tmp_len, sig_flags;
656 php_uint16 manifest_ver;
657 php_uint32 len;
658 long offset;
659 int sig_len, register_alias = 0, temp_alias = 0;
660 char *signature = NULL;
661
662 if (pphar) {
663 *pphar = NULL;
664 }
665
666 if (error) {
667 *error = NULL;
668 }
669
670
671 if (-1 == php_stream_seek(fp, halt_offset, SEEK_SET)) {
672 MAPPHAR_ALLOC_FAIL("cannot seek to __HALT_COMPILER(); location in phar \"%s\"")
673 }
674
675 buffer = b32;
676
677 if (3 != php_stream_read(fp, buffer, 3)) {
678 MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated manifest at stub end)")
679 }
680
681 if ((*buffer == ' ' || *buffer == '\n') && *(buffer + 1) == '?' && *(buffer + 2) == '>') {
682 int nextchar;
683 halt_offset += 3;
684 if (EOF == (nextchar = php_stream_getc(fp))) {
685 MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated manifest at stub end)")
686 }
687
688 if ((char) nextchar == '\r') {
689
690 if (EOF == (nextchar = php_stream_getc(fp)) || (char)nextchar != '\n') {
691 MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated manifest at stub end)")
692 }
693 ++halt_offset;
694 }
695
696 if ((char) nextchar == '\n') {
697 ++halt_offset;
698 }
699 }
700
701
702 if (-1 == php_stream_seek(fp, halt_offset, SEEK_SET)) {
703 MAPPHAR_ALLOC_FAIL("cannot seek to __HALT_COMPILER(); location in phar \"%s\"")
704 }
705
706
707 buffer = b32;
708
709 if (4 != php_stream_read(fp, buffer, 4)) {
710 MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated manifest at manifest length)")
711 }
712
713 PHAR_GET_32(buffer, manifest_len);
714
715 if (manifest_len > 1048576 * 100) {
716
717 MAPPHAR_ALLOC_FAIL("manifest cannot be larger than 100 MB in phar \"%s\"")
718 }
719
720 buffer = (char *)emalloc(manifest_len);
721 savebuf = buffer;
722 endbuffer = buffer + manifest_len;
723
724 if (manifest_len < 10 || manifest_len != php_stream_read(fp, buffer, manifest_len)) {
725 MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest header)")
726 }
727
728
729 PHAR_GET_32(buffer, manifest_count);
730
731 if (manifest_count == 0) {
732 MAPPHAR_FAIL("in phar \"%s\", manifest claims to have zero entries. Phars must have at least 1 entry");
733 }
734
735
736 manifest_ver = (((unsigned char)buffer[0]) << 8)
737 + ((unsigned char)buffer[1]);
738 buffer += 2;
739
740 if ((manifest_ver & PHAR_API_VER_MASK) < PHAR_API_MIN_READ) {
741 efree(savebuf);
742 php_stream_close(fp);
743 if (error) {
744 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);
745 }
746 return FAILURE;
747 }
748
749 PHAR_GET_32(buffer, manifest_flags);
750
751 manifest_flags &= ~PHAR_HDR_COMPRESSION_MASK;
752 manifest_flags &= ~PHAR_FILE_COMPRESSION_MASK;
753
754 manifest_flags |= compression;
755
756
757
758 if (manifest_flags & PHAR_HDR_SIGNATURE) {
759 char sig_buf[8], *sig_ptr = sig_buf;
760 off_t read_len;
761 size_t end_of_phar;
762
763 if (-1 == php_stream_seek(fp, -8, SEEK_END)
764 || (read_len = php_stream_tell(fp)) < 20
765 || 8 != php_stream_read(fp, sig_buf, 8)
766 || memcmp(sig_buf+4, "GBMB", 4)) {
767 efree(savebuf);
768 php_stream_close(fp);
769 if (error) {
770 spprintf(error, 0, "phar \"%s\" has a broken signature", fname);
771 }
772 return FAILURE;
773 }
774
775 PHAR_GET_32(sig_ptr, sig_flags);
776
777 switch(sig_flags) {
778 case PHAR_SIG_OPENSSL: {
779 php_uint32 signature_len;
780 char *sig;
781 off_t whence;
782
783
784 if (-1 == php_stream_seek(fp, -12, SEEK_CUR)
785 || 4 != php_stream_read(fp, sig_buf, 4)) {
786 efree(savebuf);
787 php_stream_close(fp);
788 if (error) {
789 spprintf(error, 0, "phar \"%s\" openssl signature length could not be read", fname);
790 }
791 return FAILURE;
792 }
793
794 sig_ptr = sig_buf;
795 PHAR_GET_32(sig_ptr, signature_len);
796 sig = (char *) emalloc(signature_len);
797 whence = signature_len + 4;
798 whence = -whence;
799
800 if (-1 == php_stream_seek(fp, whence, SEEK_CUR)
801 || !(end_of_phar = php_stream_tell(fp))
802 || signature_len != php_stream_read(fp, sig, signature_len)) {
803 efree(savebuf);
804 efree(sig);
805 php_stream_close(fp);
806 if (error) {
807 spprintf(error, 0, "phar \"%s\" openssl signature could not be read", fname);
808 }
809 return FAILURE;
810 }
811
812 if (FAILURE == phar_verify_signature(fp, end_of_phar, PHAR_SIG_OPENSSL, sig, signature_len, fname, &signature, &sig_len, error TSRMLS_CC)) {
813 efree(savebuf);
814 efree(sig);
815 php_stream_close(fp);
816 if (error) {
817 char *save = *error;
818 spprintf(error, 0, "phar \"%s\" openssl signature could not be verified: %s", fname, *error);
819 efree(save);
820 }
821 return FAILURE;
822 }
823 efree(sig);
824 }
825 break;
826 #if PHAR_HASH_OK
827 case PHAR_SIG_SHA512: {
828 unsigned char digest[64];
829
830 php_stream_seek(fp, -(8 + 64), SEEK_END);
831 read_len = php_stream_tell(fp);
832
833 if (php_stream_read(fp, (char*)digest, sizeof(digest)) != sizeof(digest)) {
834 efree(savebuf);
835 php_stream_close(fp);
836 if (error) {
837 spprintf(error, 0, "phar \"%s\" has a broken signature", fname);
838 }
839 return FAILURE;
840 }
841
842 if (FAILURE == phar_verify_signature(fp, read_len, PHAR_SIG_SHA512, (char *)digest, 64, fname, &signature, &sig_len, error TSRMLS_CC)) {
843 efree(savebuf);
844 php_stream_close(fp);
845 if (error) {
846 char *save = *error;
847 spprintf(error, 0, "phar \"%s\" SHA512 signature could not be verified: %s", fname, *error);
848 efree(save);
849 }
850 return FAILURE;
851 }
852 break;
853 }
854 case PHAR_SIG_SHA256: {
855 unsigned char digest[32];
856
857 php_stream_seek(fp, -(8 + 32), SEEK_END);
858 read_len = php_stream_tell(fp);
859
860 if (php_stream_read(fp, (char*)digest, sizeof(digest)) != sizeof(digest)) {
861 efree(savebuf);
862 php_stream_close(fp);
863 if (error) {
864 spprintf(error, 0, "phar \"%s\" has a broken signature", fname);
865 }
866 return FAILURE;
867 }
868
869 if (FAILURE == phar_verify_signature(fp, read_len, PHAR_SIG_SHA256, (char *)digest, 32, fname, &signature, &sig_len, error TSRMLS_CC)) {
870 efree(savebuf);
871 php_stream_close(fp);
872 if (error) {
873 char *save = *error;
874 spprintf(error, 0, "phar \"%s\" SHA256 signature could not be verified: %s", fname, *error);
875 efree(save);
876 }
877 return FAILURE;
878 }
879 break;
880 }
881 #else
882 case PHAR_SIG_SHA512:
883 case PHAR_SIG_SHA256:
884 efree(savebuf);
885 php_stream_close(fp);
886
887 if (error) {
888 spprintf(error, 0, "phar \"%s\" has a unsupported signature", fname);
889 }
890 return FAILURE;
891 #endif
892 case PHAR_SIG_SHA1: {
893 unsigned char digest[20];
894
895 php_stream_seek(fp, -(8 + 20), SEEK_END);
896 read_len = php_stream_tell(fp);
897
898 if (php_stream_read(fp, (char*)digest, sizeof(digest)) != sizeof(digest)) {
899 efree(savebuf);
900 php_stream_close(fp);
901 if (error) {
902 spprintf(error, 0, "phar \"%s\" has a broken signature", fname);
903 }
904 return FAILURE;
905 }
906
907 if (FAILURE == phar_verify_signature(fp, read_len, PHAR_SIG_SHA1, (char *)digest, 20, fname, &signature, &sig_len, error TSRMLS_CC)) {
908 efree(savebuf);
909 php_stream_close(fp);
910 if (error) {
911 char *save = *error;
912 spprintf(error, 0, "phar \"%s\" SHA1 signature could not be verified: %s", fname, *error);
913 efree(save);
914 }
915 return FAILURE;
916 }
917 break;
918 }
919 case PHAR_SIG_MD5: {
920 unsigned char digest[16];
921
922 php_stream_seek(fp, -(8 + 16), SEEK_END);
923 read_len = php_stream_tell(fp);
924
925 if (php_stream_read(fp, (char*)digest, sizeof(digest)) != sizeof(digest)) {
926 efree(savebuf);
927 php_stream_close(fp);
928 if (error) {
929 spprintf(error, 0, "phar \"%s\" has a broken signature", fname);
930 }
931 return FAILURE;
932 }
933
934 if (FAILURE == phar_verify_signature(fp, read_len, PHAR_SIG_MD5, (char *)digest, 16, fname, &signature, &sig_len, error TSRMLS_CC)) {
935 efree(savebuf);
936 php_stream_close(fp);
937 if (error) {
938 char *save = *error;
939 spprintf(error, 0, "phar \"%s\" MD5 signature could not be verified: %s", fname, *error);
940 efree(save);
941 }
942 return FAILURE;
943 }
944 break;
945 }
946 default:
947 efree(savebuf);
948 php_stream_close(fp);
949
950 if (error) {
951 spprintf(error, 0, "phar \"%s\" has a broken or unsupported signature", fname);
952 }
953 return FAILURE;
954 }
955 } else if (PHAR_G(require_hash)) {
956 efree(savebuf);
957 php_stream_close(fp);
958
959 if (error) {
960 spprintf(error, 0, "phar \"%s\" does not have a signature", fname);
961 }
962 return FAILURE;
963 } else {
964 sig_flags = 0;
965 sig_len = 0;
966 }
967
968
969 PHAR_GET_32(buffer, tmp_len);
970
971 if (buffer + tmp_len > endbuffer) {
972 MAPPHAR_FAIL("internal corruption of phar \"%s\" (buffer overrun)");
973 }
974
975 if (manifest_len < 10 + tmp_len) {
976 MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest header)")
977 }
978
979
980 if (tmp_len) {
981
982 if (alias && alias_len && (alias_len != (int)tmp_len || strncmp(alias, buffer, tmp_len)))
983 {
984 buffer[tmp_len] = '\0';
985 php_stream_close(fp);
986
987 if (signature) {
988 efree(signature);
989 }
990
991 if (error) {
992 spprintf(error, 0, "cannot load phar \"%s\" with implicit alias \"%s\" under different alias \"%s\"", fname, buffer, alias);
993 }
994
995 efree(savebuf);
996 return FAILURE;
997 }
998
999 alias_len = tmp_len;
1000 alias = buffer;
1001 buffer += tmp_len;
1002 register_alias = 1;
1003 } else if (!alias_len || !alias) {
1004
1005 alias = NULL;
1006 alias_len = 0;
1007 register_alias = 0;
1008 } else if (alias_len) {
1009 register_alias = 1;
1010 temp_alias = 1;
1011 }
1012
1013
1014 if (manifest_count > ((manifest_len - 10 - tmp_len) / (5 * 4 + 1))) {
1015
1016 MAPPHAR_FAIL("internal corruption of phar \"%s\" (too many manifest entries for size of manifest)")
1017 }
1018
1019 mydata = pecalloc(1, sizeof(phar_archive_data), PHAR_G(persist));
1020 mydata->is_persistent = PHAR_G(persist);
1021
1022
1023 PHAR_GET_32(buffer, len);
1024 if (mydata->is_persistent) {
1025 mydata->metadata_len = len;
1026 if(!len) {
1027
1028 PHAR_GET_32(buffer, len);
1029 }
1030 }
1031 if(len > endbuffer - buffer) {
1032 MAPPHAR_FAIL("internal corruption of phar \"%s\" (trying to read past buffer end)");
1033 }
1034 if (phar_parse_metadata(&buffer, &mydata->metadata, len TSRMLS_CC) == FAILURE) {
1035 MAPPHAR_FAIL("unable to read phar metadata in .phar file \"%s\"");
1036 }
1037 buffer += len;
1038
1039
1040 zend_hash_init(&mydata->manifest, manifest_count,
1041 zend_get_hash_value, destroy_phar_manifest_entry, (zend_bool)mydata->is_persistent);
1042 zend_hash_init(&mydata->mounted_dirs, 5,
1043 zend_get_hash_value, NULL, (zend_bool)mydata->is_persistent);
1044 zend_hash_init(&mydata->virtual_dirs, manifest_count * 2,
1045 zend_get_hash_value, NULL, (zend_bool)mydata->is_persistent);
1046 mydata->fname = pestrndup(fname, fname_len, mydata->is_persistent);
1047 #ifdef PHP_WIN32
1048 phar_unixify_path_separators(mydata->fname, fname_len);
1049 #endif
1050 mydata->fname_len = fname_len;
1051 offset = halt_offset + manifest_len + 4;
1052 memset(&entry, 0, sizeof(phar_entry_info));
1053 entry.phar = mydata;
1054 entry.fp_type = PHAR_FP;
1055 entry.is_persistent = mydata->is_persistent;
1056
1057 for (manifest_index = 0; manifest_index < manifest_count; ++manifest_index) {
1058 if (buffer + 4 > endbuffer) {
1059 MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest entry)")
1060 }
1061
1062 PHAR_GET_32(buffer, entry.filename_len);
1063
1064 if (entry.filename_len == 0) {
1065 MAPPHAR_FAIL("zero-length filename encountered in phar \"%s\"");
1066 }
1067
1068 if (entry.is_persistent) {
1069 entry.manifest_pos = manifest_index;
1070 }
1071
1072 if (entry.filename_len + 20 > endbuffer - buffer) {
1073 MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest entry)");
1074 }
1075
1076 if ((manifest_ver & PHAR_API_VER_MASK) >= PHAR_API_MIN_DIR && buffer[entry.filename_len - 1] == '/') {
1077 entry.is_dir = 1;
1078 } else {
1079 entry.is_dir = 0;
1080 }
1081
1082 phar_add_virtual_dirs(mydata, buffer, entry.filename_len TSRMLS_CC);
1083 entry.filename = pestrndup(buffer, entry.filename_len, entry.is_persistent);
1084 buffer += entry.filename_len;
1085 PHAR_GET_32(buffer, entry.uncompressed_filesize);
1086 PHAR_GET_32(buffer, entry.timestamp);
1087
1088 if (offset == halt_offset + (int)manifest_len + 4) {
1089 mydata->min_timestamp = entry.timestamp;
1090 mydata->max_timestamp = entry.timestamp;
1091 } else {
1092 if (mydata->min_timestamp > entry.timestamp) {
1093 mydata->min_timestamp = entry.timestamp;
1094 } else if (mydata->max_timestamp < entry.timestamp) {
1095 mydata->max_timestamp = entry.timestamp;
1096 }
1097 }
1098
1099 PHAR_GET_32(buffer, entry.compressed_filesize);
1100 PHAR_GET_32(buffer, entry.crc32);
1101 PHAR_GET_32(buffer, entry.flags);
1102
1103 if (entry.is_dir) {
1104 entry.filename_len--;
1105 entry.flags |= PHAR_ENT_PERM_DEF_DIR;
1106 }
1107
1108 PHAR_GET_32(buffer, len);
1109 if (entry.is_persistent) {
1110 entry.metadata_len = len;
1111 } else {
1112 entry.metadata_len = 0;
1113 }
1114 if (len > endbuffer - buffer) {
1115 pefree(entry.filename, entry.is_persistent);
1116 MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest entry)");
1117 }
1118 if (phar_parse_metadata(&buffer, &entry.metadata, len TSRMLS_CC) == FAILURE) {
1119 pefree(entry.filename, entry.is_persistent);
1120 MAPPHAR_FAIL("unable to read file metadata in .phar file \"%s\"");
1121 }
1122 buffer += len;
1123
1124 entry.offset = entry.offset_abs = offset;
1125 offset += entry.compressed_filesize;
1126
1127 switch (entry.flags & PHAR_ENT_COMPRESSION_MASK) {
1128 case PHAR_ENT_COMPRESSED_GZ:
1129 if (!PHAR_G(has_zlib)) {
1130 if (entry.metadata) {
1131 if (entry.is_persistent) {
1132 free(entry.metadata);
1133 } else {
1134 zval_ptr_dtor(&entry.metadata);
1135 }
1136 }
1137 pefree(entry.filename, entry.is_persistent);
1138 MAPPHAR_FAIL("zlib extension is required for gz compressed .phar file \"%s\"");
1139 }
1140 break;
1141 case PHAR_ENT_COMPRESSED_BZ2:
1142 if (!PHAR_G(has_bz2)) {
1143 if (entry.metadata) {
1144 if (entry.is_persistent) {
1145 free(entry.metadata);
1146 } else {
1147 zval_ptr_dtor(&entry.metadata);
1148 }
1149 }
1150 pefree(entry.filename, entry.is_persistent);
1151 MAPPHAR_FAIL("bz2 extension is required for bzip2 compressed .phar file \"%s\"");
1152 }
1153 break;
1154 default:
1155 if (entry.uncompressed_filesize != entry.compressed_filesize) {
1156 if (entry.metadata) {
1157 if (entry.is_persistent) {
1158 free(entry.metadata);
1159 } else {
1160 zval_ptr_dtor(&entry.metadata);
1161 }
1162 }
1163 pefree(entry.filename, entry.is_persistent);
1164 MAPPHAR_FAIL("internal corruption of phar \"%s\" (compressed and uncompressed size does not match for uncompressed entry)");
1165 }
1166 break;
1167 }
1168
1169 manifest_flags |= (entry.flags & PHAR_ENT_COMPRESSION_MASK);
1170
1171 entry.is_crc_checked = (manifest_flags & PHAR_HDR_SIGNATURE ? 1 : 0);
1172 phar_set_inode(&entry TSRMLS_CC);
1173 zend_hash_add(&mydata->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL);
1174 }
1175
1176 snprintf(mydata->version, sizeof(mydata->version), "%u.%u.%u", manifest_ver >> 12, (manifest_ver >> 8) & 0xF, (manifest_ver >> 4) & 0xF);
1177 mydata->internal_file_start = halt_offset + manifest_len + 4;
1178 mydata->halt_offset = halt_offset;
1179 mydata->flags = manifest_flags;
1180 endbuffer = strrchr(mydata->fname, '/');
1181
1182 if (endbuffer) {
1183 mydata->ext = memchr(endbuffer, '.', (mydata->fname + fname_len) - endbuffer);
1184 if (mydata->ext == endbuffer) {
1185 mydata->ext = memchr(endbuffer + 1, '.', (mydata->fname + fname_len) - endbuffer - 1);
1186 }
1187 if (mydata->ext) {
1188 mydata->ext_len = (mydata->fname + mydata->fname_len) - mydata->ext;
1189 }
1190 }
1191
1192 mydata->alias = alias ?
1193 pestrndup(alias, alias_len, mydata->is_persistent) :
1194 pestrndup(mydata->fname, fname_len, mydata->is_persistent);
1195 mydata->alias_len = alias ? alias_len : fname_len;
1196 mydata->sig_flags = sig_flags;
1197 mydata->fp = fp;
1198 mydata->sig_len = sig_len;
1199 mydata->signature = signature;
1200 phar_request_initialize(TSRMLS_C);
1201
1202 if (register_alias) {
1203 phar_archive_data **fd_ptr;
1204
1205 mydata->is_temporary_alias = temp_alias;
1206
1207 if (!phar_validate_alias(mydata->alias, mydata->alias_len)) {
1208 signature = NULL;
1209 fp = NULL;
1210 MAPPHAR_FAIL("Cannot open archive \"%s\", invalid alias");
1211 }
1212
1213 if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void **)&fd_ptr)) {
1214 if (SUCCESS != phar_free_alias(*fd_ptr, alias, alias_len TSRMLS_CC)) {
1215 signature = NULL;
1216 fp = NULL;
1217 MAPPHAR_FAIL("Cannot open archive \"%s\", alias is already in use by existing archive");
1218 }
1219 }
1220
1221 zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void*)&mydata, sizeof(phar_archive_data*), NULL);
1222 } else {
1223 mydata->is_temporary_alias = 1;
1224 }
1225
1226 zend_hash_add(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len, (void*)&mydata, sizeof(phar_archive_data*), NULL);
1227 efree(savebuf);
1228
1229 if (pphar) {
1230 *pphar = mydata;
1231 }
1232
1233 return SUCCESS;
1234 }
1235
1236
1237
1238
1239
1240 int phar_open_or_create_filename(char *fname, int fname_len, char *alias, int alias_len, int is_data, int options, phar_archive_data** pphar, char **error TSRMLS_DC)
1241 {
1242 const char *ext_str, *z;
1243 char *my_error;
1244 int ext_len;
1245 phar_archive_data **test, *unused = NULL;
1246
1247 test = &unused;
1248
1249 if (error) {
1250 *error = NULL;
1251 }
1252
1253
1254 if (phar_detect_phar_fname_ext(fname, fname_len, &ext_str, &ext_len, !is_data, 0, 1 TSRMLS_CC) == SUCCESS) {
1255 goto check_file;
1256 }
1257
1258
1259 if (FAILURE == phar_detect_phar_fname_ext(fname, fname_len, &ext_str, &ext_len, !is_data, 1, 1 TSRMLS_CC)) {
1260 if (error) {
1261 if (ext_len == -2) {
1262 spprintf(error, 0, "Cannot create a phar archive from a URL like \"%s\". Phar objects can only be created from local files", fname);
1263 } else {
1264 spprintf(error, 0, "Cannot create phar '%s', file extension (or combination) not recognised or the directory does not exist", fname);
1265 }
1266 }
1267 return FAILURE;
1268 }
1269 check_file:
1270 if (phar_open_parsed_phar(fname, fname_len, alias, alias_len, is_data, options, test, &my_error TSRMLS_CC) == SUCCESS) {
1271 if (pphar) {
1272 *pphar = *test;
1273 }
1274
1275 if ((*test)->is_data && !(*test)->is_tar && !(*test)->is_zip) {
1276 if (error) {
1277 spprintf(error, 0, "Cannot open '%s' as a PharData object. Use Phar::__construct() for executable archives", fname);
1278 }
1279 return FAILURE;
1280 }
1281
1282 if (PHAR_G(readonly) && !(*test)->is_data && ((*test)->is_tar || (*test)->is_zip)) {
1283 phar_entry_info *stub;
1284 if (FAILURE == zend_hash_find(&((*test)->manifest), ".phar/stub.php", sizeof(".phar/stub.php")-1, (void **)&stub)) {
1285 spprintf(error, 0, "'%s' is not a phar archive. Use PharData::__construct() for a standard zip or tar archive", fname);
1286 return FAILURE;
1287 }
1288 }
1289
1290 if (!PHAR_G(readonly) || (*test)->is_data) {
1291 (*test)->is_writeable = 1;
1292 }
1293 return SUCCESS;
1294 } else if (my_error) {
1295 if (error) {
1296 *error = my_error;
1297 } else {
1298 efree(my_error);
1299 }
1300 return FAILURE;
1301 }
1302
1303 if (ext_len > 3 && (z = memchr(ext_str, 'z', ext_len)) && ((ext_str + ext_len) - z >= 2) && !memcmp(z + 1, "ip", 2)) {
1304
1305 return phar_open_or_create_zip(fname, fname_len, alias, alias_len, is_data, options, pphar, error TSRMLS_CC);
1306 }
1307
1308 if (ext_len > 3 && (z = memchr(ext_str, 't', ext_len)) && ((ext_str + ext_len) - z >= 2) && !memcmp(z + 1, "ar", 2)) {
1309
1310 return phar_open_or_create_tar(fname, fname_len, alias, alias_len, is_data, options, pphar, error TSRMLS_CC);
1311 }
1312
1313 return phar_create_or_parse_filename(fname, fname_len, alias, alias_len, is_data, options, pphar, error TSRMLS_CC);
1314 }
1315
1316
1317 int phar_create_or_parse_filename(char *fname, int fname_len, char *alias, int alias_len, int is_data, int options, phar_archive_data** pphar, char **error TSRMLS_DC)
1318 {
1319 phar_archive_data *mydata;
1320 php_stream *fp;
1321 char *actual = NULL, *p;
1322
1323 if (!pphar) {
1324 pphar = &mydata;
1325 }
1326 #if PHP_API_VERSION < 20100412
1327 if (PG(safe_mode) && (!php_checkuid(fname, NULL, CHECKUID_ALLOW_ONLY_FILE))) {
1328 return FAILURE;
1329 }
1330 #endif
1331 if (php_check_open_basedir(fname TSRMLS_CC)) {
1332 return FAILURE;
1333 }
1334
1335
1336 fp = php_stream_open_wrapper(fname, "rb", IGNORE_URL|STREAM_MUST_SEEK|0, &actual);
1337
1338 if (actual) {
1339 fname = actual;
1340 fname_len = strlen(actual);
1341 }
1342
1343 if (fp) {
1344 if (phar_open_from_fp(fp, fname, fname_len, alias, alias_len, options, pphar, is_data, error TSRMLS_CC) == SUCCESS) {
1345 if ((*pphar)->is_data || !PHAR_G(readonly)) {
1346 (*pphar)->is_writeable = 1;
1347 }
1348 if (actual) {
1349 efree(actual);
1350 }
1351 return SUCCESS;
1352 } else {
1353
1354 if (actual) {
1355 efree(actual);
1356 }
1357 return FAILURE;
1358 }
1359 }
1360
1361 if (actual) {
1362 efree(actual);
1363 }
1364
1365 if (PHAR_G(readonly) && !is_data) {
1366 if (options & REPORT_ERRORS) {
1367 if (error) {
1368 spprintf(error, 0, "creating archive \"%s\" disabled by the php.ini setting phar.readonly", fname);
1369 }
1370 }
1371 return FAILURE;
1372 }
1373
1374
1375 mydata = ecalloc(1, sizeof(phar_archive_data));
1376 mydata->fname = expand_filepath(fname, NULL TSRMLS_CC);
1377 fname_len = strlen(mydata->fname);
1378 #ifdef PHP_WIN32
1379 phar_unixify_path_separators(mydata->fname, fname_len);
1380 #endif
1381 p = strrchr(mydata->fname, '/');
1382
1383 if (p) {
1384 mydata->ext = memchr(p, '.', (mydata->fname + fname_len) - p);
1385 if (mydata->ext == p) {
1386 mydata->ext = memchr(p + 1, '.', (mydata->fname + fname_len) - p - 1);
1387 }
1388 if (mydata->ext) {
1389 mydata->ext_len = (mydata->fname + fname_len) - mydata->ext;
1390 }
1391 }
1392
1393 if (pphar) {
1394 *pphar = mydata;
1395 }
1396
1397 zend_hash_init(&mydata->manifest, sizeof(phar_entry_info),
1398 zend_get_hash_value, destroy_phar_manifest_entry, 0);
1399 zend_hash_init(&mydata->mounted_dirs, sizeof(char *),
1400 zend_get_hash_value, NULL, 0);
1401 zend_hash_init(&mydata->virtual_dirs, sizeof(char *),
1402 zend_get_hash_value, NULL, (zend_bool)mydata->is_persistent);
1403 mydata->fname_len = fname_len;
1404 snprintf(mydata->version, sizeof(mydata->version), "%s", PHP_PHAR_API_VERSION);
1405 mydata->is_temporary_alias = alias ? 0 : 1;
1406 mydata->internal_file_start = -1;
1407 mydata->fp = NULL;
1408 mydata->is_writeable = 1;
1409 mydata->is_brandnew = 1;
1410 phar_request_initialize(TSRMLS_C);
1411 zend_hash_add(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len, (void*)&mydata, sizeof(phar_archive_data*), NULL);
1412
1413 if (is_data) {
1414 alias = NULL;
1415 alias_len = 0;
1416 mydata->is_data = 1;
1417
1418 mydata->is_tar = 1;
1419 } else {
1420 phar_archive_data **fd_ptr;
1421
1422 if (alias && SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void **)&fd_ptr)) {
1423 if (SUCCESS != phar_free_alias(*fd_ptr, alias, alias_len TSRMLS_CC)) {
1424 if (error) {
1425 spprintf(error, 4096, "phar error: phar \"%s\" cannot set alias \"%s\", already in use by another phar archive", mydata->fname, alias);
1426 }
1427
1428 zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len);
1429
1430 if (pphar) {
1431 *pphar = NULL;
1432 }
1433
1434 return FAILURE;
1435 }
1436 }
1437
1438 mydata->alias = alias ? estrndup(alias, alias_len) : estrndup(mydata->fname, fname_len);
1439 mydata->alias_len = alias ? alias_len : fname_len;
1440 }
1441
1442 if (alias_len && alias) {
1443 if (FAILURE == zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void*)&mydata, sizeof(phar_archive_data*), NULL)) {
1444 if (options & REPORT_ERRORS) {
1445 if (error) {
1446 spprintf(error, 0, "archive \"%s\" cannot be associated with alias \"%s\", already in use", fname, alias);
1447 }
1448 }
1449
1450 zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len);
1451
1452 if (pphar) {
1453 *pphar = NULL;
1454 }
1455
1456 return FAILURE;
1457 }
1458 }
1459
1460 return SUCCESS;
1461 }
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471 int phar_open_from_filename(char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, char **error TSRMLS_DC)
1472 {
1473 php_stream *fp;
1474 char *actual;
1475 int ret, is_data = 0;
1476
1477 if (error) {
1478 *error = NULL;
1479 }
1480
1481 if (!strstr(fname, ".phar")) {
1482 is_data = 1;
1483 }
1484
1485 if (phar_open_parsed_phar(fname, fname_len, alias, alias_len, is_data, options, pphar, error TSRMLS_CC) == SUCCESS) {
1486 return SUCCESS;
1487 } else if (error && *error) {
1488 return FAILURE;
1489 }
1490 #if PHP_API_VERSION < 20100412
1491 if (PG(safe_mode) && (!php_checkuid(fname, NULL, CHECKUID_ALLOW_ONLY_FILE))) {
1492 return FAILURE;
1493 }
1494 #endif
1495 if (php_check_open_basedir(fname TSRMLS_CC)) {
1496 return FAILURE;
1497 }
1498
1499 fp = php_stream_open_wrapper(fname, "rb", IGNORE_URL|STREAM_MUST_SEEK, &actual);
1500
1501 if (!fp) {
1502 if (options & REPORT_ERRORS) {
1503 if (error) {
1504 spprintf(error, 0, "unable to open phar for reading \"%s\"", fname);
1505 }
1506 }
1507 if (actual) {
1508 efree(actual);
1509 }
1510 return FAILURE;
1511 }
1512
1513 if (actual) {
1514 fname = actual;
1515 fname_len = strlen(actual);
1516 }
1517
1518 ret = phar_open_from_fp(fp, fname, fname_len, alias, alias_len, options, pphar, is_data, error TSRMLS_CC);
1519
1520 if (actual) {
1521 efree(actual);
1522 }
1523
1524 return ret;
1525 }
1526
1527
1528 static inline char *phar_strnstr(const char *buf, int buf_len, const char *search, int search_len)
1529 {
1530 const char *c;
1531 int so_far = 0;
1532
1533 if (buf_len < search_len) {
1534 return NULL;
1535 }
1536
1537 c = buf - 1;
1538
1539 do {
1540 if (!(c = memchr(c + 1, search[0], buf_len - search_len - so_far))) {
1541 return (char *) NULL;
1542 }
1543
1544 so_far = c - buf;
1545
1546 if (so_far >= (buf_len - search_len)) {
1547 return (char *) NULL;
1548 }
1549
1550 if (!memcmp(c, search, search_len)) {
1551 return (char *) c;
1552 }
1553 } while (1);
1554 }
1555
1556
1557
1558
1559
1560
1561
1562 static int phar_open_from_fp(php_stream* fp, char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, int is_data, char **error TSRMLS_DC)
1563 {
1564 const char token[] = "__HALT_COMPILER();";
1565 const char zip_magic[] = "PK\x03\x04";
1566 const char gz_magic[] = "\x1f\x8b\x08";
1567 const char bz_magic[] = "BZh";
1568 char *pos, test = '\0';
1569 const int window_size = 1024;
1570 char buffer[1024 + sizeof(token)];
1571 const long readsize = sizeof(buffer) - sizeof(token);
1572 const long tokenlen = sizeof(token) - 1;
1573 long halt_offset;
1574 size_t got;
1575 php_uint32 compression = PHAR_FILE_COMPRESSED_NONE;
1576
1577 if (error) {
1578 *error = NULL;
1579 }
1580
1581 if (-1 == php_stream_rewind(fp)) {
1582 MAPPHAR_ALLOC_FAIL("cannot rewind phar \"%s\"")
1583 }
1584
1585 buffer[sizeof(buffer)-1] = '\0';
1586 memset(buffer, 32, sizeof(token));
1587 halt_offset = 0;
1588
1589
1590
1591 while(!php_stream_eof(fp)) {
1592 if ((got = php_stream_read(fp, buffer+tokenlen, readsize)) < (size_t) tokenlen) {
1593 MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated entry)")
1594 }
1595
1596 if (!test) {
1597 test = '\1';
1598 pos = buffer+tokenlen;
1599 if (!memcmp(pos, gz_magic, 3)) {
1600 char err = 0;
1601 php_stream_filter *filter;
1602 php_stream *temp;
1603
1604 zval filterparams;
1605
1606 if (!PHAR_G(has_zlib)) {
1607 MAPPHAR_ALLOC_FAIL("unable to decompress gzipped phar archive \"%s\" to temporary file, enable zlib extension in php.ini")
1608 }
1609 array_init(&filterparams);
1610
1611 #ifndef MAX_WBITS
1612 #define MAX_WBITS 15
1613 #endif
1614 add_assoc_long(&filterparams, "window", MAX_WBITS + 32);
1615
1616
1617 if (!(temp = php_stream_fopen_tmpfile())) {
1618 MAPPHAR_ALLOC_FAIL("unable to create temporary file for decompression of gzipped phar archive \"%s\"")
1619 }
1620
1621 php_stream_rewind(fp);
1622 filter = php_stream_filter_create("zlib.inflate", &filterparams, php_stream_is_persistent(fp) TSRMLS_CC);
1623
1624 if (!filter) {
1625 err = 1;
1626 add_assoc_long(&filterparams, "window", MAX_WBITS);
1627 filter = php_stream_filter_create("zlib.inflate", &filterparams, php_stream_is_persistent(fp) TSRMLS_CC);
1628 zval_dtor(&filterparams);
1629
1630 if (!filter) {
1631 php_stream_close(temp);
1632 MAPPHAR_ALLOC_FAIL("unable to decompress gzipped phar archive \"%s\", ext/zlib is buggy in PHP versions older than 5.2.6")
1633 }
1634 } else {
1635 zval_dtor(&filterparams);
1636 }
1637
1638 php_stream_filter_append(&temp->writefilters, filter);
1639
1640 if (SUCCESS != php_stream_copy_to_stream_ex(fp, temp, PHP_STREAM_COPY_ALL, NULL)) {
1641 if (err) {
1642 php_stream_close(temp);
1643 MAPPHAR_ALLOC_FAIL("unable to decompress gzipped phar archive \"%s\", ext/zlib is buggy in PHP versions older than 5.2.6")
1644 }
1645 php_stream_close(temp);
1646 MAPPHAR_ALLOC_FAIL("unable to decompress gzipped phar archive \"%s\" to temporary file")
1647 }
1648
1649 php_stream_filter_flush(filter, 1);
1650 php_stream_filter_remove(filter, 1 TSRMLS_CC);
1651 php_stream_close(fp);
1652 fp = temp;
1653 php_stream_rewind(fp);
1654 compression = PHAR_FILE_COMPRESSED_GZ;
1655
1656
1657 test = '\0';
1658 continue;
1659 } else if (!memcmp(pos, bz_magic, 3)) {
1660 php_stream_filter *filter;
1661 php_stream *temp;
1662
1663 if (!PHAR_G(has_bz2)) {
1664 MAPPHAR_ALLOC_FAIL("unable to decompress bzipped phar archive \"%s\" to temporary file, enable bz2 extension in php.ini")
1665 }
1666
1667
1668 if (!(temp = php_stream_fopen_tmpfile())) {
1669 MAPPHAR_ALLOC_FAIL("unable to create temporary file for decompression of bzipped phar archive \"%s\"")
1670 }
1671
1672 php_stream_rewind(fp);
1673 filter = php_stream_filter_create("bzip2.decompress", NULL, php_stream_is_persistent(fp) TSRMLS_CC);
1674
1675 if (!filter) {
1676 php_stream_close(temp);
1677 MAPPHAR_ALLOC_FAIL("unable to decompress bzipped phar archive \"%s\", filter creation failed")
1678 }
1679
1680 php_stream_filter_append(&temp->writefilters, filter);
1681
1682 if (SUCCESS != php_stream_copy_to_stream_ex(fp, temp, PHP_STREAM_COPY_ALL, NULL)) {
1683 php_stream_close(temp);
1684 MAPPHAR_ALLOC_FAIL("unable to decompress bzipped phar archive \"%s\" to temporary file")
1685 }
1686
1687 php_stream_filter_flush(filter, 1);
1688 php_stream_filter_remove(filter, 1 TSRMLS_CC);
1689 php_stream_close(fp);
1690 fp = temp;
1691 php_stream_rewind(fp);
1692 compression = PHAR_FILE_COMPRESSED_BZ2;
1693
1694
1695 test = '\0';
1696 continue;
1697 }
1698
1699 if (!memcmp(pos, zip_magic, 4)) {
1700 php_stream_seek(fp, 0, SEEK_END);
1701 return phar_parse_zipfile(fp, fname, fname_len, alias, alias_len, pphar, error TSRMLS_CC);
1702 }
1703
1704 if (got > 512) {
1705 if (phar_is_tar(pos, fname)) {
1706 php_stream_rewind(fp);
1707 return phar_parse_tarfile(fp, fname, fname_len, alias, alias_len, pphar, is_data, compression, error TSRMLS_CC);
1708 }
1709 }
1710 }
1711
1712 if (got > 0 && (pos = phar_strnstr(buffer, got + sizeof(token), token, sizeof(token)-1)) != NULL) {
1713 halt_offset += (pos - buffer);
1714 return phar_parse_pharfile(fp, fname, fname_len, alias, alias_len, halt_offset, pphar, compression, error TSRMLS_CC);
1715 }
1716
1717 halt_offset += got;
1718 memmove(buffer, buffer + window_size, tokenlen);
1719 }
1720
1721 MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (__HALT_COMPILER(); not found)")
1722 }
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734 static int phar_analyze_path(const char *fname, const char *ext, int ext_len, int for_create TSRMLS_DC)
1735 {
1736 php_stream_statbuf ssb;
1737 char *realpath;
1738 char *filename = estrndup(fname, (ext - fname) + ext_len);
1739
1740 if ((realpath = expand_filepath(filename, NULL TSRMLS_CC))) {
1741 #ifdef PHP_WIN32
1742 phar_unixify_path_separators(realpath, strlen(realpath));
1743 #endif
1744 if (zend_hash_exists(&(PHAR_GLOBALS->phar_fname_map), realpath, strlen(realpath))) {
1745 efree(realpath);
1746 efree(filename);
1747 return SUCCESS;
1748 }
1749
1750 if (PHAR_G(manifest_cached) && zend_hash_exists(&cached_phars, realpath, strlen(realpath))) {
1751 efree(realpath);
1752 efree(filename);
1753 return SUCCESS;
1754 }
1755 efree(realpath);
1756 }
1757
1758 if (SUCCESS == php_stream_stat_path((char *) filename, &ssb)) {
1759
1760 efree(filename);
1761
1762 if (ssb.sb.st_mode & S_IFDIR) {
1763 return FAILURE;
1764 }
1765
1766 if (for_create == 1) {
1767 return FAILURE;
1768 }
1769
1770 return SUCCESS;
1771 } else {
1772 char *slash;
1773
1774 if (!for_create) {
1775 efree(filename);
1776 return FAILURE;
1777 }
1778
1779 slash = (char *) strrchr(filename, '/');
1780
1781 if (slash) {
1782 *slash = '\0';
1783 }
1784
1785 if (SUCCESS != php_stream_stat_path((char *) filename, &ssb)) {
1786 if (!slash) {
1787 if (!(realpath = expand_filepath(filename, NULL TSRMLS_CC))) {
1788 efree(filename);
1789 return FAILURE;
1790 }
1791 #ifdef PHP_WIN32
1792 phar_unixify_path_separators(realpath, strlen(realpath));
1793 #endif
1794 slash = strstr(realpath, filename);
1795 if (slash) {
1796 slash += ((ext - fname) + ext_len);
1797 *slash = '\0';
1798 }
1799 slash = strrchr(realpath, '/');
1800
1801 if (slash) {
1802 *slash = '\0';
1803 } else {
1804 efree(realpath);
1805 efree(filename);
1806 return FAILURE;
1807 }
1808
1809 if (SUCCESS != php_stream_stat_path(realpath, &ssb)) {
1810 efree(realpath);
1811 efree(filename);
1812 return FAILURE;
1813 }
1814
1815 efree(realpath);
1816
1817 if (ssb.sb.st_mode & S_IFDIR) {
1818 efree(filename);
1819 return SUCCESS;
1820 }
1821 }
1822
1823 efree(filename);
1824 return FAILURE;
1825 }
1826
1827 efree(filename);
1828
1829 if (ssb.sb.st_mode & S_IFDIR) {
1830 return SUCCESS;
1831 }
1832
1833 return FAILURE;
1834 }
1835 }
1836
1837
1838
1839 static int phar_check_str(const char *fname, const char *ext_str, int ext_len, int executable, int for_create TSRMLS_DC)
1840 {
1841 char test[51];
1842 const char *pos;
1843
1844 if (ext_len >= 50) {
1845 return FAILURE;
1846 }
1847
1848 if (executable == 1) {
1849
1850 memcpy(test, ext_str - 1, ext_len + 1);
1851 test[ext_len + 1] = '\0';
1852
1853
1854 pos = strstr(test, ".phar");
1855
1856 if (pos && (*(pos - 1) != '/')
1857 && (pos += 5) && (*pos == '\0' || *pos == '/' || *pos == '.')) {
1858 return phar_analyze_path(fname, ext_str, ext_len, for_create TSRMLS_CC);
1859 } else {
1860 return FAILURE;
1861 }
1862 }
1863
1864
1865 if (!executable) {
1866 pos = strstr(ext_str, ".phar");
1867 if (!(pos && (*(pos - 1) != '/')
1868 && (pos += 5) && (*pos == '\0' || *pos == '/' || *pos == '.')) && *(ext_str + 1) != '.' && *(ext_str + 1) != '/' && *(ext_str + 1) != '\0') {
1869 return phar_analyze_path(fname, ext_str, ext_len, for_create TSRMLS_CC);
1870 }
1871 } else {
1872 if (*(ext_str + 1) != '.' && *(ext_str + 1) != '/' && *(ext_str + 1) != '\0') {
1873 return phar_analyze_path(fname, ext_str, ext_len, for_create TSRMLS_CC);
1874 }
1875 }
1876
1877 return FAILURE;
1878 }
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894 int phar_detect_phar_fname_ext(const char *filename, int filename_len, const char **ext_str, int *ext_len, int executable, int for_create, int is_complete TSRMLS_DC)
1895 {
1896 const char *pos, *slash;
1897
1898 *ext_str = NULL;
1899 *ext_len = 0;
1900
1901 if (!filename_len || filename_len == 1) {
1902 return FAILURE;
1903 }
1904
1905 phar_request_initialize(TSRMLS_C);
1906
1907 pos = memchr(filename, '/', filename_len);
1908
1909 if (pos && pos != filename) {
1910
1911 if (*(pos - 1) == ':' && (pos - filename) < filename_len - 1 && *(pos + 1) == '/') {
1912 *ext_len = -2;
1913 *ext_str = NULL;
1914 return FAILURE;
1915 }
1916 if (zend_hash_exists(&(PHAR_GLOBALS->phar_alias_map), (char *) filename, pos - filename)) {
1917 *ext_str = pos;
1918 *ext_len = -1;
1919 return FAILURE;
1920 }
1921
1922 if (PHAR_G(manifest_cached) && zend_hash_exists(&cached_alias, (char *) filename, pos - filename)) {
1923 *ext_str = pos;
1924 *ext_len = -1;
1925 return FAILURE;
1926 }
1927 }
1928
1929 if (zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map)) || PHAR_G(manifest_cached)) {
1930 phar_archive_data **pphar;
1931
1932 if (is_complete) {
1933 if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), (char *) filename, filename_len, (void **)&pphar)) {
1934 *ext_str = filename + (filename_len - (*pphar)->ext_len);
1935 woohoo:
1936 *ext_len = (*pphar)->ext_len;
1937
1938 if (executable == 2) {
1939 return SUCCESS;
1940 }
1941
1942 if (executable == 1 && !(*pphar)->is_data) {
1943 return SUCCESS;
1944 }
1945
1946 if (!executable && (*pphar)->is_data) {
1947 return SUCCESS;
1948 }
1949
1950 return FAILURE;
1951 }
1952
1953 if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_find(&cached_phars, (char *) filename, filename_len, (void **)&pphar)) {
1954 *ext_str = filename + (filename_len - (*pphar)->ext_len);
1955 goto woohoo;
1956 }
1957 } else {
1958 char *str_key;
1959 uint keylen;
1960 ulong unused;
1961
1962 for (zend_hash_internal_pointer_reset(&(PHAR_GLOBALS->phar_fname_map));
1963 HASH_KEY_NON_EXISTENT != zend_hash_get_current_key_ex(&(PHAR_GLOBALS->phar_fname_map), &str_key, &keylen, &unused, 0, NULL);
1964 zend_hash_move_forward(&(PHAR_GLOBALS->phar_fname_map))
1965 ) {
1966 if (keylen > (uint) filename_len) {
1967 continue;
1968 }
1969
1970 if (!memcmp(filename, str_key, keylen) && ((uint)filename_len == keylen
1971 || filename[keylen] == '/' || filename[keylen] == '\0')) {
1972 if (FAILURE == zend_hash_get_current_data(&(PHAR_GLOBALS->phar_fname_map), (void **) &pphar)) {
1973 break;
1974 }
1975 *ext_str = filename + (keylen - (*pphar)->ext_len);
1976 goto woohoo;
1977 }
1978 }
1979
1980 if (PHAR_G(manifest_cached)) {
1981 for (zend_hash_internal_pointer_reset(&cached_phars);
1982 HASH_KEY_NON_EXISTENT != zend_hash_get_current_key_ex(&cached_phars, &str_key, &keylen, &unused, 0, NULL);
1983 zend_hash_move_forward(&cached_phars)
1984 ) {
1985 if (keylen > (uint) filename_len) {
1986 continue;
1987 }
1988
1989 if (!memcmp(filename, str_key, keylen) && ((uint)filename_len == keylen
1990 || filename[keylen] == '/' || filename[keylen] == '\0')) {
1991 if (FAILURE == zend_hash_get_current_data(&cached_phars, (void **) &pphar)) {
1992 break;
1993 }
1994 *ext_str = filename + (keylen - (*pphar)->ext_len);
1995 goto woohoo;
1996 }
1997 }
1998 }
1999 }
2000 }
2001
2002 pos = memchr(filename + 1, '.', filename_len);
2003 next_extension:
2004 if (!pos) {
2005 return FAILURE;
2006 }
2007
2008 while (pos != filename && (*(pos - 1) == '/' || *(pos - 1) == '\0')) {
2009 pos = memchr(pos + 1, '.', filename_len - (pos - filename) + 1);
2010 if (!pos) {
2011 return FAILURE;
2012 }
2013 }
2014
2015 slash = memchr(pos, '/', filename_len - (pos - filename));
2016
2017 if (!slash) {
2018
2019 *ext_str = pos;
2020 *ext_len = strlen(pos);
2021
2022
2023 switch (phar_check_str(filename, *ext_str, *ext_len, executable, for_create TSRMLS_CC)) {
2024 case SUCCESS:
2025 return SUCCESS;
2026 case FAILURE:
2027
2028 return FAILURE;
2029 }
2030 }
2031
2032
2033 *ext_str = pos;
2034 *ext_len = slash - pos;
2035
2036 switch (phar_check_str(filename, *ext_str, *ext_len, executable, for_create TSRMLS_CC)) {
2037 case SUCCESS:
2038 return SUCCESS;
2039 case FAILURE:
2040
2041 pos = strchr(pos + 1, '.');
2042 if (pos) {
2043 *ext_str = NULL;
2044 *ext_len = 0;
2045 }
2046 goto next_extension;
2047 }
2048
2049 return FAILURE;
2050 }
2051
2052
2053 static int php_check_dots(const char *element, int n)
2054 {
2055 for(n--; n >= 0; --n) {
2056 if (element[n] != '.') {
2057 return 1;
2058 }
2059 }
2060 return 0;
2061 }
2062
2063
2064 #define IS_DIRECTORY_UP(element, len) \
2065 (len >= 2 && !php_check_dots(element, len))
2066
2067 #define IS_DIRECTORY_CURRENT(element, len) \
2068 (len == 1 && element[0] == '.')
2069
2070 #define IS_BACKSLASH(c) ((c) == '/')
2071
2072 #ifdef COMPILE_DL_PHAR
2073
2074 static inline int in_character_class(char ch, const char *delim)
2075 {
2076 while (*delim) {
2077 if (*delim == ch) {
2078 return 1;
2079 }
2080 ++delim;
2081 }
2082 return 0;
2083 }
2084
2085
2086 char *tsrm_strtok_r(char *s, const char *delim, char **last)
2087 {
2088 char *token;
2089
2090 if (s == NULL) {
2091 s = *last;
2092 }
2093
2094 while (*s && in_character_class(*s, delim)) {
2095 ++s;
2096 }
2097
2098 if (!*s) {
2099 return NULL;
2100 }
2101
2102 token = s;
2103
2104 while (*s && !in_character_class(*s, delim)) {
2105 ++s;
2106 }
2107
2108 if (!*s) {
2109 *last = s;
2110 } else {
2111 *s = '\0';
2112 *last = s + 1;
2113 }
2114
2115 return token;
2116 }
2117
2118 #endif
2119
2120
2121
2122
2123 char *phar_fix_filepath(char *path, int *new_len, int use_cwd TSRMLS_DC)
2124 {
2125 char *newpath;
2126 int newpath_len;
2127 char *ptr;
2128 char *tok;
2129 int ptr_length, path_length = *new_len;
2130
2131 if (PHAR_G(cwd_len) && use_cwd && path_length > 2 && path[0] == '.' && path[1] == '/') {
2132 newpath_len = PHAR_G(cwd_len);
2133 newpath = emalloc(strlen(path) + newpath_len + 1);
2134 memcpy(newpath, PHAR_G(cwd), newpath_len);
2135 } else {
2136 newpath = emalloc(strlen(path) + 2);
2137 newpath[0] = '/';
2138 newpath_len = 1;
2139 }
2140
2141 ptr = path;
2142
2143 if (*ptr == '/') {
2144 ++ptr;
2145 }
2146
2147 tok = ptr;
2148
2149 do {
2150 ptr = memchr(ptr, '/', path_length - (ptr - path));
2151 } while (ptr && ptr - tok == 0 && *ptr == '/' && ++ptr && ++tok);
2152
2153 if (!ptr && (path_length - (tok - path))) {
2154 switch (path_length - (tok - path)) {
2155 case 1:
2156 if (*tok == '.') {
2157 efree(path);
2158 *new_len = 1;
2159 efree(newpath);
2160 return estrndup("/", 1);
2161 }
2162 break;
2163 case 2:
2164 if (tok[0] == '.' && tok[1] == '.') {
2165 efree(path);
2166 *new_len = 1;
2167 efree(newpath);
2168 return estrndup("/", 1);
2169 }
2170 }
2171 efree(newpath);
2172 return path;
2173 }
2174
2175 while (ptr) {
2176 ptr_length = ptr - tok;
2177 last_time:
2178 if (IS_DIRECTORY_UP(tok, ptr_length)) {
2179 #define PREVIOUS newpath[newpath_len - 1]
2180
2181 while (newpath_len > 1 && !IS_BACKSLASH(PREVIOUS)) {
2182 newpath_len--;
2183 }
2184
2185 if (newpath[0] != '/') {
2186 newpath[newpath_len] = '\0';
2187 } else if (newpath_len > 1) {
2188 --newpath_len;
2189 }
2190 } else if (!IS_DIRECTORY_CURRENT(tok, ptr_length)) {
2191 if (newpath_len > 1) {
2192 newpath[newpath_len++] = '/';
2193 memcpy(newpath + newpath_len, tok, ptr_length+1);
2194 } else {
2195 memcpy(newpath + newpath_len, tok, ptr_length+1);
2196 }
2197
2198 newpath_len += ptr_length;
2199 }
2200
2201 if (ptr == path + path_length) {
2202 break;
2203 }
2204
2205 tok = ++ptr;
2206
2207 do {
2208 ptr = memchr(ptr, '/', path_length - (ptr - path));
2209 } while (ptr && ptr - tok == 0 && *ptr == '/' && ++ptr && ++tok);
2210
2211 if (!ptr && (path_length - (tok - path))) {
2212 ptr_length = path_length - (tok - path);
2213 ptr = path + path_length;
2214 goto last_time;
2215 }
2216 }
2217
2218 efree(path);
2219 *new_len = newpath_len;
2220 newpath[newpath_len] = '\0';
2221 return erealloc(newpath, newpath_len + 1);
2222 }
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237 int phar_split_fname(const char *filename, int filename_len, char **arch, int *arch_len, char **entry, int *entry_len, int executable, int for_create TSRMLS_DC)
2238 {
2239 const char *ext_str;
2240 #ifdef PHP_WIN32
2241 char *save;
2242 #endif
2243 int ext_len;
2244
2245 if (CHECK_NULL_PATH(filename, filename_len)) {
2246 return FAILURE;
2247 }
2248
2249 if (!strncasecmp(filename, "phar://", 7)) {
2250 filename += 7;
2251 filename_len -= 7;
2252 }
2253
2254 ext_len = 0;
2255 #ifdef PHP_WIN32
2256 save = filename;
2257 filename = estrndup(filename, filename_len);
2258 phar_unixify_path_separators(filename, filename_len);
2259 #endif
2260 if (phar_detect_phar_fname_ext(filename, filename_len, &ext_str, &ext_len, executable, for_create, 0 TSRMLS_CC) == FAILURE) {
2261 if (ext_len != -1) {
2262 if (!ext_str) {
2263
2264 #ifdef PHP_WIN32
2265 *arch = save;
2266 #else
2267 *arch = filename;
2268 #endif
2269 }
2270
2271 #ifdef PHP_WIN32
2272 efree(filename);
2273 #endif
2274 return FAILURE;
2275 }
2276
2277 ext_len = 0;
2278
2279 }
2280
2281 *arch_len = ext_str - filename + ext_len;
2282 *arch = estrndup(filename, *arch_len);
2283
2284 if (ext_str[ext_len]) {
2285 *entry_len = filename_len - *arch_len;
2286 *entry = estrndup(ext_str+ext_len, *entry_len);
2287 #ifdef PHP_WIN32
2288 phar_unixify_path_separators(*entry, *entry_len);
2289 #endif
2290 *entry = phar_fix_filepath(*entry, entry_len, 0 TSRMLS_CC);
2291 } else {
2292 *entry_len = 1;
2293 *entry = estrndup("/", 1);
2294 }
2295
2296 #ifdef PHP_WIN32
2297 efree(filename);
2298 #endif
2299
2300 return SUCCESS;
2301 }
2302
2303
2304
2305
2306
2307
2308 int phar_open_executed_filename(char *alias, int alias_len, char **error TSRMLS_DC)
2309 {
2310 char *fname;
2311 zval *halt_constant;
2312 php_stream *fp;
2313 int fname_len;
2314 char *actual = NULL;
2315 int ret;
2316
2317 if (error) {
2318 *error = NULL;
2319 }
2320
2321 fname = (char*)zend_get_executed_filename(TSRMLS_C);
2322 fname_len = strlen(fname);
2323
2324 if (phar_open_parsed_phar(fname, fname_len, alias, alias_len, 0, REPORT_ERRORS, NULL, 0 TSRMLS_CC) == SUCCESS) {
2325 return SUCCESS;
2326 }
2327
2328 if (!strcmp(fname, "[no active file]")) {
2329 if (error) {
2330 spprintf(error, 0, "cannot initialize a phar outside of PHP execution");
2331 }
2332 return FAILURE;
2333 }
2334
2335 MAKE_STD_ZVAL(halt_constant);
2336
2337 if (0 == zend_get_constant("__COMPILER_HALT_OFFSET__", 24, halt_constant TSRMLS_CC)) {
2338 FREE_ZVAL(halt_constant);
2339 if (error) {
2340 spprintf(error, 0, "__HALT_COMPILER(); must be declared in a phar");
2341 }
2342 return FAILURE;
2343 }
2344
2345 FREE_ZVAL(halt_constant);
2346
2347 #if PHP_API_VERSION < 20100412
2348 if (PG(safe_mode) && (!php_checkuid(fname, NULL, CHECKUID_ALLOW_ONLY_FILE))) {
2349 return FAILURE;
2350 }
2351 #endif
2352
2353 if (php_check_open_basedir(fname TSRMLS_CC)) {
2354 return FAILURE;
2355 }
2356
2357 fp = php_stream_open_wrapper(fname, "rb", IGNORE_URL|STREAM_MUST_SEEK|REPORT_ERRORS, &actual);
2358
2359 if (!fp) {
2360 if (error) {
2361 spprintf(error, 0, "unable to open phar for reading \"%s\"", fname);
2362 }
2363 if (actual) {
2364 efree(actual);
2365 }
2366 return FAILURE;
2367 }
2368
2369 if (actual) {
2370 fname = actual;
2371 fname_len = strlen(actual);
2372 }
2373
2374 ret = phar_open_from_fp(fp, fname, fname_len, alias, alias_len, REPORT_ERRORS, NULL, 0, error TSRMLS_CC);
2375
2376 if (actual) {
2377 efree(actual);
2378 }
2379
2380 return ret;
2381 }
2382
2383
2384
2385
2386
2387 int phar_postprocess_file(phar_entry_data *idata, php_uint32 crc32, char **error, int process_zip TSRMLS_DC)
2388 {
2389 php_uint32 crc = ~0;
2390 int len = idata->internal_file->uncompressed_filesize;
2391 php_stream *fp = idata->fp;
2392 phar_entry_info *entry = idata->internal_file;
2393
2394 if (error) {
2395 *error = NULL;
2396 }
2397
2398 if (entry->is_zip && process_zip > 0) {
2399
2400 phar_zip_file_header local;
2401 phar_zip_data_desc desc;
2402
2403 if (SUCCESS != phar_open_archive_fp(idata->phar TSRMLS_CC)) {
2404 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);
2405 return FAILURE;
2406 }
2407 php_stream_seek(phar_get_entrypfp(idata->internal_file TSRMLS_CC), entry->header_offset, SEEK_SET);
2408
2409 if (sizeof(local) != php_stream_read(phar_get_entrypfp(idata->internal_file TSRMLS_CC), (char *) &local, sizeof(local))) {
2410
2411 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);
2412 return FAILURE;
2413 }
2414
2415
2416 if (((PHAR_ZIP_16(local.flags)) & 0x8) == 0x8) {
2417 php_stream_seek(phar_get_entrypfp(idata->internal_file TSRMLS_CC),
2418 entry->header_offset + sizeof(local) +
2419 PHAR_ZIP_16(local.filename_len) +
2420 PHAR_ZIP_16(local.extra_len) +
2421 entry->compressed_filesize, SEEK_SET);
2422 if (sizeof(desc) != php_stream_read(phar_get_entrypfp(idata->internal_file TSRMLS_CC),
2423 (char *) &desc, sizeof(desc))) {
2424 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);
2425 return FAILURE;
2426 }
2427 if (desc.signature[0] == 'P' && desc.signature[1] == 'K') {
2428 memcpy(&(local.crc32), &(desc.crc32), 12);
2429 } else {
2430
2431 memcpy(&(local.crc32), &desc, 12);
2432 }
2433 }
2434
2435 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)) {
2436 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);
2437 return FAILURE;
2438 }
2439
2440
2441 entry->offset = entry->offset_abs =
2442 sizeof(local) + entry->header_offset + PHAR_ZIP_16(local.filename_len) + PHAR_ZIP_16(local.extra_len);
2443
2444 if (idata->zero && idata->zero != entry->offset_abs) {
2445 idata->zero = entry->offset_abs;
2446 }
2447 }
2448
2449 if (process_zip == 1) {
2450 return SUCCESS;
2451 }
2452
2453 php_stream_seek(fp, idata->zero, SEEK_SET);
2454
2455 while (len--) {
2456 CRC32(crc, php_stream_getc(fp));
2457 }
2458
2459 php_stream_seek(fp, idata->zero, SEEK_SET);
2460
2461 if (~crc == crc32) {
2462 entry->is_crc_checked = 1;
2463 return SUCCESS;
2464 } else {
2465 spprintf(error, 0, "phar error: internal corruption of phar \"%s\" (crc32 mismatch on file \"%s\")", idata->phar->fname, entry->filename);
2466 return FAILURE;
2467 }
2468 }
2469
2470
2471 static inline void phar_set_32(char *buffer, int var)
2472 {
2473 #ifdef WORDS_BIGENDIAN
2474 *((buffer) + 3) = (unsigned char) (((var) >> 24) & 0xFF);
2475 *((buffer) + 2) = (unsigned char) (((var) >> 16) & 0xFF);
2476 *((buffer) + 1) = (unsigned char) (((var) >> 8) & 0xFF);
2477 *((buffer) + 0) = (unsigned char) ((var) & 0xFF);
2478 #else
2479 memcpy(buffer, &var, sizeof(var));
2480 #endif
2481 }
2482
2483 static int phar_flush_clean_deleted_apply(void *data TSRMLS_DC)
2484 {
2485 phar_entry_info *entry = (phar_entry_info *)data;
2486
2487 if (entry->fp_refcount <= 0 && entry->is_deleted) {
2488 return ZEND_HASH_APPLY_REMOVE;
2489 } else {
2490 return ZEND_HASH_APPLY_KEEP;
2491 }
2492 }
2493
2494
2495 #include "stub.h"
2496
2497 char *phar_create_default_stub(const char *index_php, const char *web_index, size_t *len, char **error TSRMLS_DC)
2498 {
2499 char *stub = NULL;
2500 int index_len, web_len;
2501 size_t dummy;
2502
2503 if (!len) {
2504 len = &dummy;
2505 }
2506
2507 if (error) {
2508 *error = NULL;
2509 }
2510
2511 if (!index_php) {
2512 index_php = "index.php";
2513 }
2514
2515 if (!web_index) {
2516 web_index = "index.php";
2517 }
2518
2519 index_len = strlen(index_php);
2520 web_len = strlen(web_index);
2521
2522 if (index_len > 400) {
2523
2524 if (error) {
2525 spprintf(error, 0, "Illegal filename passed in for stub creation, was %d characters long, and only 400 or less is allowed", index_len);
2526 return NULL;
2527 }
2528 }
2529
2530 if (web_len > 400) {
2531
2532 if (error) {
2533 spprintf(error, 0, "Illegal web filename passed in for stub creation, was %d characters long, and only 400 or less is allowed", web_len);
2534 return NULL;
2535 }
2536 }
2537
2538 phar_get_stub(index_php, web_index, len, &stub, index_len+1, web_len+1 TSRMLS_CC);
2539 return stub;
2540 }
2541
2542
2543
2544
2545
2546
2547
2548
2549 int phar_flush(phar_archive_data *phar, char *user_stub, long len, int convert, char **error TSRMLS_DC)
2550 {
2551 char halt_stub[] = "__HALT_COMPILER();";
2552 char *newstub, *tmp;
2553 phar_entry_info *entry, *newentry;
2554 int halt_offset, restore_alias_len, global_flags = 0, closeoldfile;
2555 char *pos, has_dirs = 0;
2556 char manifest[18], entry_buffer[24];
2557 off_t manifest_ftell;
2558 long offset;
2559 size_t wrote;
2560 php_uint32 manifest_len, mytime, loc, new_manifest_count;
2561 php_uint32 newcrc32;
2562 php_stream *file, *oldfile, *newfile, *stubfile;
2563 php_stream_filter *filter;
2564 php_serialize_data_t metadata_hash;
2565 smart_str main_metadata_str = {0};
2566 int free_user_stub, free_fp = 1, free_ufp = 1;
2567 int manifest_hack = 0;
2568
2569 if (phar->is_persistent) {
2570 if (error) {
2571 spprintf(error, 0, "internal error: attempt to flush cached zip-based phar \"%s\"", phar->fname);
2572 }
2573 return EOF;
2574 }
2575
2576 if (error) {
2577 *error = NULL;
2578 }
2579
2580 if (!zend_hash_num_elements(&phar->manifest) && !user_stub) {
2581 return EOF;
2582 }
2583
2584 zend_hash_clean(&phar->virtual_dirs);
2585
2586 if (phar->is_zip) {
2587 return phar_zip_flush(phar, user_stub, len, convert, error TSRMLS_CC);
2588 }
2589
2590 if (phar->is_tar) {
2591 return phar_tar_flush(phar, user_stub, len, convert, error TSRMLS_CC);
2592 }
2593
2594 if (PHAR_G(readonly)) {
2595 return EOF;
2596 }
2597
2598 if (phar->fp && !phar->is_brandnew) {
2599 oldfile = phar->fp;
2600 closeoldfile = 0;
2601 php_stream_rewind(oldfile);
2602 } else {
2603 oldfile = php_stream_open_wrapper(phar->fname, "rb", 0, NULL);
2604 closeoldfile = oldfile != NULL;
2605 }
2606 newfile = php_stream_fopen_tmpfile();
2607 if (!newfile) {
2608 if (error) {
2609 spprintf(error, 0, "unable to create temporary file");
2610 }
2611 if (closeoldfile) {
2612 php_stream_close(oldfile);
2613 }
2614 return EOF;
2615 }
2616
2617 if (user_stub) {
2618 if (len < 0) {
2619
2620 if (!(php_stream_from_zval_no_verify(stubfile, (zval **)user_stub))) {
2621 if (closeoldfile) {
2622 php_stream_close(oldfile);
2623 }
2624 php_stream_close(newfile);
2625 if (error) {
2626 spprintf(error, 0, "unable to access resource to copy stub to new phar \"%s\"", phar->fname);
2627 }
2628 return EOF;
2629 }
2630 if (len == -1) {
2631 len = PHP_STREAM_COPY_ALL;
2632 } else {
2633 len = -len;
2634 }
2635 user_stub = 0;
2636
2637 if (!(len = php_stream_copy_to_mem(stubfile, &user_stub, len, 0)) || !user_stub) {
2638 if (closeoldfile) {
2639 php_stream_close(oldfile);
2640 }
2641 php_stream_close(newfile);
2642 if (error) {
2643 spprintf(error, 0, "unable to read resource to copy stub to new phar \"%s\"", phar->fname);
2644 }
2645 return EOF;
2646 }
2647 free_user_stub = 1;
2648 } else {
2649 free_user_stub = 0;
2650 }
2651 tmp = estrndup(user_stub, len);
2652 if ((pos = php_stristr(tmp, halt_stub, len, sizeof(halt_stub) - 1)) == NULL) {
2653 efree(tmp);
2654 if (closeoldfile) {
2655 php_stream_close(oldfile);
2656 }
2657 php_stream_close(newfile);
2658 if (error) {
2659 spprintf(error, 0, "illegal stub for phar \"%s\"", phar->fname);
2660 }
2661 if (free_user_stub) {
2662 efree(user_stub);
2663 }
2664 return EOF;
2665 }
2666 pos = user_stub + (pos - tmp);
2667 efree(tmp);
2668 len = pos - user_stub + 18;
2669 if ((size_t)len != php_stream_write(newfile, user_stub, len)
2670 || 5 != php_stream_write(newfile, " ?>\r\n", 5)) {
2671 if (closeoldfile) {
2672 php_stream_close(oldfile);
2673 }
2674 php_stream_close(newfile);
2675 if (error) {
2676 spprintf(error, 0, "unable to create stub from string in new phar \"%s\"", phar->fname);
2677 }
2678 if (free_user_stub) {
2679 efree(user_stub);
2680 }
2681 return EOF;
2682 }
2683 phar->halt_offset = len + 5;
2684 if (free_user_stub) {
2685 efree(user_stub);
2686 }
2687 } else {
2688 size_t written;
2689
2690 if (!user_stub && phar->halt_offset && oldfile && !phar->is_brandnew) {
2691 php_stream_copy_to_stream_ex(oldfile, newfile, phar->halt_offset, &written);
2692 newstub = NULL;
2693 } else {
2694
2695 newstub = phar_create_default_stub(NULL, NULL, &(phar->halt_offset), NULL TSRMLS_CC);
2696 written = php_stream_write(newfile, newstub, phar->halt_offset);
2697 }
2698 if (phar->halt_offset != written) {
2699 if (closeoldfile) {
2700 php_stream_close(oldfile);
2701 }
2702 php_stream_close(newfile);
2703 if (error) {
2704 if (newstub) {
2705 spprintf(error, 0, "unable to create stub in new phar \"%s\"", phar->fname);
2706 } else {
2707 spprintf(error, 0, "unable to copy stub of old phar to new phar \"%s\"", phar->fname);
2708 }
2709 }
2710 if (newstub) {
2711 efree(newstub);
2712 }
2713 return EOF;
2714 }
2715 if (newstub) {
2716 efree(newstub);
2717 }
2718 }
2719 manifest_ftell = php_stream_tell(newfile);
2720 halt_offset = manifest_ftell;
2721
2722
2723
2724
2725 zend_hash_apply(&phar->manifest, phar_flush_clean_deleted_apply TSRMLS_CC);
2726
2727
2728 main_metadata_str.c = 0;
2729 if (phar->metadata) {
2730 PHP_VAR_SERIALIZE_INIT(metadata_hash);
2731 php_var_serialize(&main_metadata_str, &phar->metadata, &metadata_hash TSRMLS_CC);
2732 PHP_VAR_SERIALIZE_DESTROY(metadata_hash);
2733 } else {
2734 main_metadata_str.len = 0;
2735 }
2736 new_manifest_count = 0;
2737 offset = 0;
2738 for (zend_hash_internal_pointer_reset(&phar->manifest);
2739 zend_hash_has_more_elements(&phar->manifest) == SUCCESS;
2740 zend_hash_move_forward(&phar->manifest)) {
2741 if (zend_hash_get_current_data(&phar->manifest, (void **)&entry) == FAILURE) {
2742 continue;
2743 }
2744 if (entry->cfp) {
2745
2746 php_stream_close(entry->cfp);
2747 entry->cfp = 0;
2748 }
2749 if (entry->is_deleted || entry->is_mounted) {
2750
2751 continue;
2752 }
2753 if (!entry->is_modified && entry->fp_refcount) {
2754
2755 switch (entry->fp_type) {
2756 case PHAR_FP:
2757 free_fp = 0;
2758 break;
2759 case PHAR_UFP:
2760 free_ufp = 0;
2761 default:
2762 break;
2763 }
2764 }
2765
2766 ++new_manifest_count;
2767 phar_add_virtual_dirs(phar, entry->filename, entry->filename_len TSRMLS_CC);
2768
2769 if (entry->is_dir) {
2770
2771 has_dirs = 1;
2772 }
2773 if (entry->metadata) {
2774 if (entry->metadata_str.c) {
2775 smart_str_free(&entry->metadata_str);
2776 }
2777 entry->metadata_str.c = 0;
2778 entry->metadata_str.len = 0;
2779 PHP_VAR_SERIALIZE_INIT(metadata_hash);
2780 php_var_serialize(&entry->metadata_str, &entry->metadata, &metadata_hash TSRMLS_CC);
2781 PHP_VAR_SERIALIZE_DESTROY(metadata_hash);
2782 } else {
2783 if (entry->metadata_str.c) {
2784 smart_str_free(&entry->metadata_str);
2785 }
2786 entry->metadata_str.c = 0;
2787 entry->metadata_str.len = 0;
2788 }
2789
2790
2791 offset += 4 + entry->filename_len + sizeof(entry_buffer) + entry->metadata_str.len + (entry->is_dir ? 1 : 0);
2792
2793
2794 if ((oldfile && !entry->is_modified) || entry->is_dir) {
2795 if (entry->fp_type == PHAR_UFP) {
2796
2797 entry->fp_type = PHAR_FP;
2798 }
2799 continue;
2800 }
2801 if (!phar_get_efp(entry, 0 TSRMLS_CC)) {
2802
2803 newentry = phar_open_jit(phar, entry, error TSRMLS_CC);
2804 if (!newentry) {
2805
2806 efree(*error);
2807 *error = NULL;
2808 continue;
2809 }
2810 entry = newentry;
2811 }
2812 file = phar_get_efp(entry, 0 TSRMLS_CC);
2813 if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 1 TSRMLS_CC)) {
2814 if (closeoldfile) {
2815 php_stream_close(oldfile);
2816 }
2817 php_stream_close(newfile);
2818 if (error) {
2819 spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
2820 }
2821 return EOF;
2822 }
2823 newcrc32 = ~0;
2824 mytime = entry->uncompressed_filesize;
2825 for (loc = 0;loc < mytime; ++loc) {
2826 CRC32(newcrc32, php_stream_getc(file));
2827 }
2828 entry->crc32 = ~newcrc32;
2829 entry->is_crc_checked = 1;
2830 if (!(entry->flags & PHAR_ENT_COMPRESSION_MASK)) {
2831
2832 entry->compressed_filesize = entry->uncompressed_filesize;
2833 continue;
2834 }
2835 filter = php_stream_filter_create(phar_compress_filter(entry, 0), NULL, 0 TSRMLS_CC);
2836 if (!filter) {
2837 if (closeoldfile) {
2838 php_stream_close(oldfile);
2839 }
2840 php_stream_close(newfile);
2841 if (entry->flags & PHAR_ENT_COMPRESSED_GZ) {
2842 if (error) {
2843 spprintf(error, 0, "unable to gzip compress file \"%s\" to new phar \"%s\"", entry->filename, phar->fname);
2844 }
2845 } else {
2846 if (error) {
2847 spprintf(error, 0, "unable to bzip2 compress file \"%s\" to new phar \"%s\"", entry->filename, phar->fname);
2848 }
2849 }
2850 return EOF;
2851 }
2852
2853
2854
2855
2856 entry->cfp = php_stream_fopen_tmpfile();
2857 if (!entry->cfp) {
2858 if (error) {
2859 spprintf(error, 0, "unable to create temporary file");
2860 }
2861 if (closeoldfile) {
2862 php_stream_close(oldfile);
2863 }
2864 php_stream_close(newfile);
2865 return EOF;
2866 }
2867 php_stream_flush(file);
2868 if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC)) {
2869 if (closeoldfile) {
2870 php_stream_close(oldfile);
2871 }
2872 php_stream_close(newfile);
2873 if (error) {
2874 spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
2875 }
2876 return EOF;
2877 }
2878 php_stream_filter_append((&entry->cfp->writefilters), filter);
2879 if (SUCCESS != php_stream_copy_to_stream_ex(file, entry->cfp, entry->uncompressed_filesize, NULL)) {
2880 if (closeoldfile) {
2881 php_stream_close(oldfile);
2882 }
2883 php_stream_close(newfile);
2884 if (error) {
2885 spprintf(error, 0, "unable to copy compressed file contents of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
2886 }
2887 return EOF;
2888 }
2889 php_stream_filter_flush(filter, 1);
2890 php_stream_flush(entry->cfp);
2891 php_stream_filter_remove(filter, 1 TSRMLS_CC);
2892 php_stream_seek(entry->cfp, 0, SEEK_END);
2893 entry->compressed_filesize = (php_uint32) php_stream_tell(entry->cfp);
2894
2895 php_stream_rewind(entry->cfp);
2896 entry->old_flags = entry->flags;
2897 entry->is_modified = 1;
2898 global_flags |= (entry->flags & PHAR_ENT_COMPRESSION_MASK);
2899 }
2900 global_flags |= PHAR_HDR_SIGNATURE;
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912 restore_alias_len = phar->alias_len;
2913 if (phar->is_temporary_alias) {
2914 phar->alias_len = 0;
2915 }
2916
2917 manifest_len = offset + phar->alias_len + sizeof(manifest) + main_metadata_str.len;
2918 phar_set_32(manifest, manifest_len);
2919
2920 if(manifest[0] == '\r' || manifest[0] == '\n') {
2921 manifest_len++;
2922 phar_set_32(manifest, manifest_len);
2923 manifest_hack = 1;
2924 }
2925 phar_set_32(manifest+4, new_manifest_count);
2926 if (has_dirs) {
2927 *(manifest + 8) = (unsigned char) (((PHAR_API_VERSION) >> 8) & 0xFF);
2928 *(manifest + 9) = (unsigned char) (((PHAR_API_VERSION) & 0xF0));
2929 } else {
2930 *(manifest + 8) = (unsigned char) (((PHAR_API_VERSION_NODIR) >> 8) & 0xFF);
2931 *(manifest + 9) = (unsigned char) (((PHAR_API_VERSION_NODIR) & 0xF0));
2932 }
2933 phar_set_32(manifest+10, global_flags);
2934 phar_set_32(manifest+14, phar->alias_len);
2935
2936
2937 if (sizeof(manifest) != php_stream_write(newfile, manifest, sizeof(manifest))
2938 || (size_t)phar->alias_len != php_stream_write(newfile, phar->alias, phar->alias_len)) {
2939
2940 if (closeoldfile) {
2941 php_stream_close(oldfile);
2942 }
2943
2944 php_stream_close(newfile);
2945 phar->alias_len = restore_alias_len;
2946
2947 if (error) {
2948 spprintf(error, 0, "unable to write manifest header of new phar \"%s\"", phar->fname);
2949 }
2950
2951 return EOF;
2952 }
2953
2954 phar->alias_len = restore_alias_len;
2955
2956 phar_set_32(manifest, main_metadata_str.len);
2957 if (4 != php_stream_write(newfile, manifest, 4) || (main_metadata_str.len
2958 && main_metadata_str.len != php_stream_write(newfile, main_metadata_str.c, main_metadata_str.len))) {
2959 smart_str_free(&main_metadata_str);
2960
2961 if (closeoldfile) {
2962 php_stream_close(oldfile);
2963 }
2964
2965 php_stream_close(newfile);
2966 phar->alias_len = restore_alias_len;
2967
2968 if (error) {
2969 spprintf(error, 0, "unable to write manifest meta-data of new phar \"%s\"", phar->fname);
2970 }
2971
2972 return EOF;
2973 }
2974 smart_str_free(&main_metadata_str);
2975
2976
2977 manifest_ftell = php_stream_tell(newfile);
2978
2979
2980 for (zend_hash_internal_pointer_reset(&phar->manifest);
2981 zend_hash_has_more_elements(&phar->manifest) == SUCCESS;
2982 zend_hash_move_forward(&phar->manifest)) {
2983
2984 if (zend_hash_get_current_data(&phar->manifest, (void **)&entry) == FAILURE) {
2985 continue;
2986 }
2987
2988 if (entry->is_deleted || entry->is_mounted) {
2989
2990 continue;
2991 }
2992
2993 if (entry->is_dir) {
2994
2995 phar_set_32(entry_buffer, entry->filename_len + 1);
2996 } else {
2997 phar_set_32(entry_buffer, entry->filename_len);
2998 }
2999
3000 if (4 != php_stream_write(newfile, entry_buffer, 4)
3001 || entry->filename_len != php_stream_write(newfile, entry->filename, entry->filename_len)
3002 || (entry->is_dir && 1 != php_stream_write(newfile, "/", 1))) {
3003 if (closeoldfile) {
3004 php_stream_close(oldfile);
3005 }
3006 php_stream_close(newfile);
3007 if (error) {
3008 if (entry->is_dir) {
3009 spprintf(error, 0, "unable to write filename of directory \"%s\" to manifest of new phar \"%s\"", entry->filename, phar->fname);
3010 } else {
3011 spprintf(error, 0, "unable to write filename of file \"%s\" to manifest of new phar \"%s\"", entry->filename, phar->fname);
3012 }
3013 }
3014 return EOF;
3015 }
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026 mytime = time(NULL);
3027 phar_set_32(entry_buffer, entry->uncompressed_filesize);
3028 phar_set_32(entry_buffer+4, mytime);
3029 phar_set_32(entry_buffer+8, entry->compressed_filesize);
3030 phar_set_32(entry_buffer+12, entry->crc32);
3031 phar_set_32(entry_buffer+16, entry->flags);
3032 phar_set_32(entry_buffer+20, entry->metadata_str.len);
3033
3034 if (sizeof(entry_buffer) != php_stream_write(newfile, entry_buffer, sizeof(entry_buffer))
3035 || entry->metadata_str.len != php_stream_write(newfile, entry->metadata_str.c, entry->metadata_str.len)) {
3036 if (closeoldfile) {
3037 php_stream_close(oldfile);
3038 }
3039
3040 php_stream_close(newfile);
3041
3042 if (error) {
3043 spprintf(error, 0, "unable to write temporary manifest of file \"%s\" to manifest of new phar \"%s\"", entry->filename, phar->fname);
3044 }
3045
3046 return EOF;
3047 }
3048 }
3049
3050 if(manifest_hack) {
3051 if(1 != php_stream_write(newfile, manifest, 1)) {
3052 if (closeoldfile) {
3053 php_stream_close(oldfile);
3054 }
3055
3056 php_stream_close(newfile);
3057
3058 if (error) {
3059 spprintf(error, 0, "unable to write manifest padding byte");
3060 }
3061
3062 return EOF;
3063 }
3064 }
3065
3066
3067 offset = php_stream_tell(newfile);
3068 for (zend_hash_internal_pointer_reset(&phar->manifest);
3069 zend_hash_has_more_elements(&phar->manifest) == SUCCESS;
3070 zend_hash_move_forward(&phar->manifest)) {
3071
3072 if (zend_hash_get_current_data(&phar->manifest, (void **)&entry) == FAILURE) {
3073 continue;
3074 }
3075
3076 if (entry->is_deleted || entry->is_dir || entry->is_mounted) {
3077 continue;
3078 }
3079
3080 if (entry->cfp) {
3081 file = entry->cfp;
3082 php_stream_rewind(file);
3083 } else {
3084 file = phar_get_efp(entry, 0 TSRMLS_CC);
3085 if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC)) {
3086 if (closeoldfile) {
3087 php_stream_close(oldfile);
3088 }
3089 php_stream_close(newfile);
3090 if (error) {
3091 spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
3092 }
3093 return EOF;
3094 }
3095 }
3096
3097 if (!file) {
3098 if (closeoldfile) {
3099 php_stream_close(oldfile);
3100 }
3101 php_stream_close(newfile);
3102 if (error) {
3103 spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
3104 }
3105 return EOF;
3106 }
3107
3108
3109 entry->offset = entry->offset_abs = offset;
3110 offset += entry->compressed_filesize;
3111 if (php_stream_copy_to_stream_ex(file, newfile, entry->compressed_filesize, &wrote) == FAILURE) {
3112 if (closeoldfile) {
3113 php_stream_close(oldfile);
3114 }
3115
3116 php_stream_close(newfile);
3117
3118 if (error) {
3119 spprintf(error, 0, "unable to write contents of file \"%s\" to new phar \"%s\"", entry->filename, phar->fname);
3120 }
3121
3122 return EOF;
3123 }
3124
3125 entry->is_modified = 0;
3126
3127 if (entry->cfp) {
3128 php_stream_close(entry->cfp);
3129 entry->cfp = NULL;
3130 }
3131
3132 if (entry->fp_type == PHAR_MOD) {
3133
3134 if (entry->fp_refcount == 0 && entry->fp != phar->fp && entry->fp != phar->ufp) {
3135 php_stream_close(entry->fp);
3136 }
3137
3138 entry->fp = NULL;
3139 entry->fp_type = PHAR_FP;
3140 } else if (entry->fp_type == PHAR_UFP) {
3141 entry->fp_type = PHAR_FP;
3142 }
3143 }
3144
3145
3146 if (global_flags & PHAR_HDR_SIGNATURE) {
3147 char sig_buf[4];
3148
3149 php_stream_rewind(newfile);
3150
3151 if (phar->signature) {
3152 efree(phar->signature);
3153 phar->signature = NULL;
3154 }
3155
3156 switch(phar->sig_flags) {
3157 #ifndef PHAR_HASH_OK
3158 case PHAR_SIG_SHA512:
3159 case PHAR_SIG_SHA256:
3160 if (closeoldfile) {
3161 php_stream_close(oldfile);
3162 }
3163 php_stream_close(newfile);
3164 if (error) {
3165 spprintf(error, 0, "unable to write contents of file \"%s\" to new phar \"%s\" with requested hash type", entry->filename, phar->fname);
3166 }
3167 return EOF;
3168 #endif
3169 default: {
3170 char *digest = NULL;
3171 int digest_len;
3172
3173 if (FAILURE == phar_create_signature(phar, newfile, &digest, &digest_len, error TSRMLS_CC)) {
3174 if (error) {
3175 char *save = *error;
3176 spprintf(error, 0, "phar error: unable to write signature: %s", save);
3177 efree(save);
3178 }
3179 if (digest) {
3180 efree(digest);
3181 }
3182 if (closeoldfile) {
3183 php_stream_close(oldfile);
3184 }
3185 php_stream_close(newfile);
3186 return EOF;
3187 }
3188
3189 php_stream_write(newfile, digest, digest_len);
3190 efree(digest);
3191 if (phar->sig_flags == PHAR_SIG_OPENSSL) {
3192 phar_set_32(sig_buf, digest_len);
3193 php_stream_write(newfile, sig_buf, 4);
3194 }
3195 break;
3196 }
3197 }
3198 phar_set_32(sig_buf, phar->sig_flags);
3199 php_stream_write(newfile, sig_buf, 4);
3200 php_stream_write(newfile, "GBMB", 4);
3201 }
3202
3203
3204
3205
3206 if (phar->fp && free_fp) {
3207 php_stream_close(phar->fp);
3208 }
3209
3210 if (phar->ufp) {
3211 if (free_ufp) {
3212 php_stream_close(phar->ufp);
3213 }
3214 phar->ufp = NULL;
3215 }
3216
3217 if (closeoldfile) {
3218 php_stream_close(oldfile);
3219 }
3220
3221 phar->internal_file_start = halt_offset + manifest_len + 4;
3222 phar->halt_offset = halt_offset;
3223 phar->is_brandnew = 0;
3224
3225 php_stream_rewind(newfile);
3226
3227 if (phar->donotflush) {
3228
3229 phar->fp = newfile;
3230 } else {
3231 phar->fp = php_stream_open_wrapper(phar->fname, "w+b", IGNORE_URL|STREAM_MUST_SEEK|REPORT_ERRORS, NULL);
3232 if (!phar->fp) {
3233 phar->fp = newfile;
3234 if (error) {
3235 spprintf(error, 4096, "unable to open new phar \"%s\" for writing", phar->fname);
3236 }
3237 return EOF;
3238 }
3239
3240 if (phar->flags & PHAR_FILE_COMPRESSED_GZ) {
3241
3242 zval filterparams;
3243
3244 array_init(&filterparams);
3245 add_assoc_long(&filterparams, "window", MAX_WBITS+16);
3246 filter = php_stream_filter_create("zlib.deflate", &filterparams, php_stream_is_persistent(phar->fp) TSRMLS_CC);
3247 zval_dtor(&filterparams);
3248
3249 if (!filter) {
3250 if (error) {
3251 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);
3252 }
3253 return EOF;
3254 }
3255
3256 php_stream_filter_append(&phar->fp->writefilters, filter);
3257 php_stream_copy_to_stream_ex(newfile, phar->fp, PHP_STREAM_COPY_ALL, NULL);
3258 php_stream_filter_flush(filter, 1);
3259 php_stream_filter_remove(filter, 1 TSRMLS_CC);
3260 php_stream_close(phar->fp);
3261
3262 phar->fp = newfile;
3263 } else if (phar->flags & PHAR_FILE_COMPRESSED_BZ2) {
3264 filter = php_stream_filter_create("bzip2.compress", NULL, php_stream_is_persistent(phar->fp) TSRMLS_CC);
3265 php_stream_filter_append(&phar->fp->writefilters, filter);
3266 php_stream_copy_to_stream_ex(newfile, phar->fp, PHP_STREAM_COPY_ALL, NULL);
3267 php_stream_filter_flush(filter, 1);
3268 php_stream_filter_remove(filter, 1 TSRMLS_CC);
3269 php_stream_close(phar->fp);
3270
3271 phar->fp = newfile;
3272 } else {
3273 php_stream_copy_to_stream_ex(newfile, phar->fp, PHP_STREAM_COPY_ALL, NULL);
3274
3275 php_stream_close(newfile);
3276 }
3277 }
3278
3279 if (-1 == php_stream_seek(phar->fp, phar->halt_offset, SEEK_SET)) {
3280 if (error) {
3281 spprintf(error, 0, "unable to seek to __HALT_COMPILER(); in new phar \"%s\"", phar->fname);
3282 }
3283 return EOF;
3284 }
3285
3286 return EOF;
3287 }
3288
3289
3290 #ifdef COMPILE_DL_PHAR
3291 ZEND_GET_MODULE(phar)
3292 #endif
3293
3294
3295
3296
3297
3298 zend_function_entry phar_functions[] = {
3299 PHP_FE_END
3300 };
3301
3302
3303 static size_t phar_zend_stream_reader(void *handle, char *buf, size_t len TSRMLS_DC)
3304 {
3305 return php_stream_read(phar_get_pharfp((phar_archive_data*)handle TSRMLS_CC), buf, len);
3306 }
3307
3308
3309 static size_t phar_zend_stream_fsizer(void *handle TSRMLS_DC)
3310 {
3311 return ((phar_archive_data*)handle)->halt_offset + 32;
3312 }
3313
3314 zend_op_array *(*phar_orig_compile_file)(zend_file_handle *file_handle, int type TSRMLS_DC);
3315 #define phar_orig_zend_open zend_stream_open_function
3316
3317 static char *phar_resolve_path(const char *filename, int filename_len TSRMLS_DC)
3318 {
3319 return phar_find_in_include_path((char *) filename, filename_len, NULL TSRMLS_CC);
3320 }
3321
3322 static zend_op_array *phar_compile_file(zend_file_handle *file_handle, int type TSRMLS_DC)
3323 {
3324 zend_op_array *res;
3325 char *name = NULL;
3326 int failed;
3327 phar_archive_data *phar;
3328
3329 if (!file_handle || !file_handle->filename) {
3330 return phar_orig_compile_file(file_handle, type TSRMLS_CC);
3331 }
3332 if (strstr(file_handle->filename, ".phar") && !strstr(file_handle->filename, "://")) {
3333 if (SUCCESS == phar_open_from_filename((char*)file_handle->filename, strlen(file_handle->filename), NULL, 0, 0, &phar, NULL TSRMLS_CC)) {
3334 if (phar->is_zip || phar->is_tar) {
3335 zend_file_handle f = *file_handle;
3336
3337
3338 spprintf(&name, 4096, "phar://%s/%s", file_handle->filename, ".phar/stub.php");
3339 if (SUCCESS == phar_orig_zend_open((const char *)name, file_handle TSRMLS_CC)) {
3340 efree(name);
3341 name = NULL;
3342 file_handle->filename = f.filename;
3343 if (file_handle->opened_path) {
3344 efree(file_handle->opened_path);
3345 }
3346 file_handle->opened_path = f.opened_path;
3347 file_handle->free_filename = f.free_filename;
3348 } else {
3349 *file_handle = f;
3350 }
3351 } else if (phar->flags & PHAR_FILE_COMPRESSION_MASK) {
3352
3353 file_handle->type = ZEND_HANDLE_STREAM;
3354
3355 file_handle->handle.stream.handle = phar;
3356 file_handle->handle.stream.reader = phar_zend_stream_reader;
3357 file_handle->handle.stream.closer = NULL;
3358 file_handle->handle.stream.fsizer = phar_zend_stream_fsizer;
3359 file_handle->handle.stream.isatty = 0;
3360 phar->is_persistent ?
3361 php_stream_rewind(PHAR_GLOBALS->cached_fp[phar->phar_pos].fp) :
3362 php_stream_rewind(phar->fp);
3363 memset(&file_handle->handle.stream.mmap, 0, sizeof(file_handle->handle.stream.mmap));
3364 }
3365 }
3366 }
3367
3368 zend_try {
3369 failed = 0;
3370 CG(zend_lineno) = 0;
3371 res = phar_orig_compile_file(file_handle, type TSRMLS_CC);
3372 } zend_catch {
3373 failed = 1;
3374 res = NULL;
3375 } zend_end_try();
3376
3377 if (name) {
3378 efree(name);
3379 }
3380
3381 if (failed) {
3382 zend_bailout();
3383 }
3384
3385 return res;
3386 }
3387
3388
3389 typedef zend_op_array* (zend_compile_t)(zend_file_handle*, int TSRMLS_DC);
3390 typedef zend_compile_t* (compile_hook)(zend_compile_t *ptr);
3391
3392 PHP_GINIT_FUNCTION(phar)
3393 {
3394 phar_mime_type mime;
3395
3396 memset(phar_globals, 0, sizeof(zend_phar_globals));
3397 phar_globals->readonly = 1;
3398
3399 zend_hash_init(&phar_globals->mime_types, 0, NULL, NULL, 1);
3400
3401 #define PHAR_SET_MIME(mimetype, ret, fileext) \
3402 mime.mime = mimetype; \
3403 mime.len = sizeof((mimetype))+1; \
3404 mime.type = ret; \
3405 zend_hash_add(&phar_globals->mime_types, fileext, sizeof(fileext)-1, (void *)&mime, sizeof(phar_mime_type), NULL); \
3406
3407 PHAR_SET_MIME("text/html", PHAR_MIME_PHPS, "phps")
3408 PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "c")
3409 PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "cc")
3410 PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "cpp")
3411 PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "c++")
3412 PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "dtd")
3413 PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "h")
3414 PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "log")
3415 PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "rng")
3416 PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "txt")
3417 PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "xsd")
3418 PHAR_SET_MIME("", PHAR_MIME_PHP, "php")
3419 PHAR_SET_MIME("", PHAR_MIME_PHP, "inc")
3420 PHAR_SET_MIME("video/avi", PHAR_MIME_OTHER, "avi")
3421 PHAR_SET_MIME("image/bmp", PHAR_MIME_OTHER, "bmp")
3422 PHAR_SET_MIME("text/css", PHAR_MIME_OTHER, "css")
3423 PHAR_SET_MIME("image/gif", PHAR_MIME_OTHER, "gif")
3424 PHAR_SET_MIME("text/html", PHAR_MIME_OTHER, "htm")
3425 PHAR_SET_MIME("text/html", PHAR_MIME_OTHER, "html")
3426 PHAR_SET_MIME("text/html", PHAR_MIME_OTHER, "htmls")
3427 PHAR_SET_MIME("image/x-ico", PHAR_MIME_OTHER, "ico")
3428 PHAR_SET_MIME("image/jpeg", PHAR_MIME_OTHER, "jpe")
3429 PHAR_SET_MIME("image/jpeg", PHAR_MIME_OTHER, "jpg")
3430 PHAR_SET_MIME("image/jpeg", PHAR_MIME_OTHER, "jpeg")
3431 PHAR_SET_MIME("application/x-javascript", PHAR_MIME_OTHER, "js")
3432 PHAR_SET_MIME("audio/midi", PHAR_MIME_OTHER, "midi")
3433 PHAR_SET_MIME("audio/midi", PHAR_MIME_OTHER, "mid")
3434 PHAR_SET_MIME("audio/mod", PHAR_MIME_OTHER, "mod")
3435 PHAR_SET_MIME("movie/quicktime", PHAR_MIME_OTHER, "mov")
3436 PHAR_SET_MIME("audio/mp3", PHAR_MIME_OTHER, "mp3")
3437 PHAR_SET_MIME("video/mpeg", PHAR_MIME_OTHER, "mpg")
3438 PHAR_SET_MIME("video/mpeg", PHAR_MIME_OTHER, "mpeg")
3439 PHAR_SET_MIME("application/pdf", PHAR_MIME_OTHER, "pdf")
3440 PHAR_SET_MIME("image/png", PHAR_MIME_OTHER, "png")
3441 PHAR_SET_MIME("application/shockwave-flash", PHAR_MIME_OTHER, "swf")
3442 PHAR_SET_MIME("image/tiff", PHAR_MIME_OTHER, "tif")
3443 PHAR_SET_MIME("image/tiff", PHAR_MIME_OTHER, "tiff")
3444 PHAR_SET_MIME("audio/wav", PHAR_MIME_OTHER, "wav")
3445 PHAR_SET_MIME("image/xbm", PHAR_MIME_OTHER, "xbm")
3446 PHAR_SET_MIME("text/xml", PHAR_MIME_OTHER, "xml")
3447
3448 phar_restore_orig_functions(TSRMLS_C);
3449 }
3450
3451
3452 PHP_GSHUTDOWN_FUNCTION(phar)
3453 {
3454 zend_hash_destroy(&phar_globals->mime_types);
3455 }
3456
3457
3458 PHP_MINIT_FUNCTION(phar)
3459 {
3460 REGISTER_INI_ENTRIES();
3461
3462 phar_orig_compile_file = zend_compile_file;
3463 zend_compile_file = phar_compile_file;
3464
3465 phar_save_resolve_path = zend_resolve_path;
3466 zend_resolve_path = phar_resolve_path;
3467
3468 phar_object_init(TSRMLS_C);
3469
3470 phar_intercept_functions_init(TSRMLS_C);
3471 phar_save_orig_functions(TSRMLS_C);
3472
3473 return php_register_url_stream_wrapper("phar", &php_stream_phar_wrapper TSRMLS_CC);
3474 }
3475
3476
3477 PHP_MSHUTDOWN_FUNCTION(phar)
3478 {
3479 php_unregister_url_stream_wrapper("phar" TSRMLS_CC);
3480
3481 phar_intercept_functions_shutdown(TSRMLS_C);
3482
3483 if (zend_compile_file == phar_compile_file) {
3484 zend_compile_file = phar_orig_compile_file;
3485 }
3486
3487 if (PHAR_G(manifest_cached)) {
3488 zend_hash_destroy(&(cached_phars));
3489 zend_hash_destroy(&(cached_alias));
3490 }
3491
3492 return SUCCESS;
3493 }
3494
3495
3496 void phar_request_initialize(TSRMLS_D)
3497 {
3498 if (!PHAR_GLOBALS->request_init)
3499 {
3500 PHAR_G(last_phar) = NULL;
3501 PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
3502 PHAR_G(has_bz2) = zend_hash_exists(&module_registry, "bz2", sizeof("bz2"));
3503 PHAR_G(has_zlib) = zend_hash_exists(&module_registry, "zlib", sizeof("zlib"));
3504 PHAR_GLOBALS->request_init = 1;
3505 PHAR_GLOBALS->request_ends = 0;
3506 PHAR_GLOBALS->request_done = 0;
3507 zend_hash_init(&(PHAR_GLOBALS->phar_fname_map), 5, zend_get_hash_value, destroy_phar_data, 0);
3508 zend_hash_init(&(PHAR_GLOBALS->phar_persist_map), 5, zend_get_hash_value, NULL, 0);
3509 zend_hash_init(&(PHAR_GLOBALS->phar_alias_map), 5, zend_get_hash_value, NULL, 0);
3510
3511 if (PHAR_G(manifest_cached)) {
3512 phar_archive_data **pphar;
3513 phar_entry_fp *stuff = (phar_entry_fp *) ecalloc(zend_hash_num_elements(&cached_phars), sizeof(phar_entry_fp));
3514
3515 for (zend_hash_internal_pointer_reset(&cached_phars);
3516 zend_hash_get_current_data(&cached_phars, (void **)&pphar) == SUCCESS;
3517 zend_hash_move_forward(&cached_phars)) {
3518 stuff[pphar[0]->phar_pos].manifest = (phar_entry_fp_info *) ecalloc( zend_hash_num_elements(&(pphar[0]->manifest)), sizeof(phar_entry_fp_info));
3519 }
3520
3521 PHAR_GLOBALS->cached_fp = stuff;
3522 }
3523
3524 PHAR_GLOBALS->phar_SERVER_mung_list = 0;
3525 PHAR_G(cwd) = NULL;
3526 PHAR_G(cwd_len) = 0;
3527 PHAR_G(cwd_init) = 0;
3528 }
3529 }
3530
3531
3532 PHP_RSHUTDOWN_FUNCTION(phar)
3533 {
3534 int i;
3535
3536 PHAR_GLOBALS->request_ends = 1;
3537
3538 if (PHAR_GLOBALS->request_init)
3539 {
3540 phar_release_functions(TSRMLS_C);
3541 zend_hash_destroy(&(PHAR_GLOBALS->phar_alias_map));
3542 PHAR_GLOBALS->phar_alias_map.arBuckets = NULL;
3543 zend_hash_destroy(&(PHAR_GLOBALS->phar_fname_map));
3544 PHAR_GLOBALS->phar_fname_map.arBuckets = NULL;
3545 zend_hash_destroy(&(PHAR_GLOBALS->phar_persist_map));
3546 PHAR_GLOBALS->phar_persist_map.arBuckets = NULL;
3547 PHAR_GLOBALS->phar_SERVER_mung_list = 0;
3548
3549 if (PHAR_GLOBALS->cached_fp) {
3550 for (i = 0; i < zend_hash_num_elements(&cached_phars); ++i) {
3551 if (PHAR_GLOBALS->cached_fp[i].fp) {
3552 php_stream_close(PHAR_GLOBALS->cached_fp[i].fp);
3553 }
3554 if (PHAR_GLOBALS->cached_fp[i].ufp) {
3555 php_stream_close(PHAR_GLOBALS->cached_fp[i].ufp);
3556 }
3557 efree(PHAR_GLOBALS->cached_fp[i].manifest);
3558 }
3559 efree(PHAR_GLOBALS->cached_fp);
3560 PHAR_GLOBALS->cached_fp = 0;
3561 }
3562
3563 PHAR_GLOBALS->request_init = 0;
3564
3565 if (PHAR_G(cwd)) {
3566 efree(PHAR_G(cwd));
3567 }
3568
3569 PHAR_G(cwd) = NULL;
3570 PHAR_G(cwd_len) = 0;
3571 PHAR_G(cwd_init) = 0;
3572 }
3573
3574 PHAR_GLOBALS->request_done = 1;
3575 return SUCCESS;
3576 }
3577
3578
3579 PHP_MINFO_FUNCTION(phar)
3580 {
3581 phar_request_initialize(TSRMLS_C);
3582 php_info_print_table_start();
3583 php_info_print_table_header(2, "Phar: PHP Archive support", "enabled");
3584 php_info_print_table_row(2, "Phar EXT version", PHP_PHAR_VERSION);
3585 php_info_print_table_row(2, "Phar API version", PHP_PHAR_API_VERSION);
3586 php_info_print_table_row(2, "SVN revision", "$Id: 14b80e175ed4d5bf11c890e1f30ea8225935b16c $");
3587 php_info_print_table_row(2, "Phar-based phar archives", "enabled");
3588 php_info_print_table_row(2, "Tar-based phar archives", "enabled");
3589 php_info_print_table_row(2, "ZIP-based phar archives", "enabled");
3590
3591 if (PHAR_G(has_zlib)) {
3592 php_info_print_table_row(2, "gzip compression", "enabled");
3593 } else {
3594 php_info_print_table_row(2, "gzip compression", "disabled (install ext/zlib)");
3595 }
3596
3597 if (PHAR_G(has_bz2)) {
3598 php_info_print_table_row(2, "bzip2 compression", "enabled");
3599 } else {
3600 php_info_print_table_row(2, "bzip2 compression", "disabled (install pecl/bz2)");
3601 }
3602 #ifdef PHAR_HAVE_OPENSSL
3603 php_info_print_table_row(2, "Native OpenSSL support", "enabled");
3604 #else
3605 if (zend_hash_exists(&module_registry, "openssl", sizeof("openssl"))) {
3606 php_info_print_table_row(2, "OpenSSL support", "enabled");
3607 } else {
3608 php_info_print_table_row(2, "OpenSSL support", "disabled (install ext/openssl)");
3609 }
3610 #endif
3611 php_info_print_table_end();
3612
3613 php_info_print_box_start(0);
3614 PUTS("Phar based on pear/PHP_Archive, original concept by Davey Shafik.");
3615 PUTS(!sapi_module.phpinfo_as_text?"<br />":"\n");
3616 PUTS("Phar fully realized by Gregory Beaver and Marcus Boerger.");
3617 PUTS(!sapi_module.phpinfo_as_text?"<br />":"\n");
3618 PUTS("Portions of tar implementation Copyright (c) 2003-2009 Tim Kientzle.");
3619 php_info_print_box_end();
3620
3621 DISPLAY_INI_ENTRIES();
3622 }
3623
3624
3625
3626
3627 static const zend_module_dep phar_deps[] = {
3628 ZEND_MOD_OPTIONAL("apc")
3629 ZEND_MOD_OPTIONAL("bz2")
3630 ZEND_MOD_OPTIONAL("openssl")
3631 ZEND_MOD_OPTIONAL("zlib")
3632 ZEND_MOD_OPTIONAL("standard")
3633 #if defined(HAVE_HASH) && !defined(COMPILE_DL_HASH)
3634 ZEND_MOD_REQUIRED("hash")
3635 #endif
3636 #if HAVE_SPL
3637 ZEND_MOD_REQUIRED("spl")
3638 #endif
3639 ZEND_MOD_END
3640 };
3641
3642 zend_module_entry phar_module_entry = {
3643 STANDARD_MODULE_HEADER_EX, NULL,
3644 phar_deps,
3645 "Phar",
3646 phar_functions,
3647 PHP_MINIT(phar),
3648 PHP_MSHUTDOWN(phar),
3649 NULL,
3650 PHP_RSHUTDOWN(phar),
3651 PHP_MINFO(phar),
3652 PHP_PHAR_VERSION,
3653 PHP_MODULE_GLOBALS(phar),
3654 PHP_GINIT(phar),
3655 PHP_GSHUTDOWN(phar),
3656 NULL,
3657 STANDARD_MODULE_PROPERTIES_EX
3658 };
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668