summaryrefslogtreecommitdiff
path: root/ext/phar
diff options
context:
space:
mode:
authorSVN Migration <svn@php.net>2008-05-12 21:03:49 +0000
committerSVN Migration <svn@php.net>2008-05-12 21:03:49 +0000
commit16b4d8e0e1108564fa042520171d9091af708d83 (patch)
treeed242b98e845ea9c045ad6e10b9e9a083b569dd5 /ext/phar
parente35c45791383ac9337adcd37255895f396001557 (diff)
downloadphp-git-16b4d8e0e1108564fa042520171d9091af708d83.tar.gz
This commit was manufactured by cvs2svn to create branch 'PHP_5_3'.
Diffstat (limited to 'ext/phar')
-rw-r--r--ext/phar/CREDITS2
-rw-r--r--ext/phar/LICENSE95
-rwxr-xr-xext/phar/Makefile.frag25
-rw-r--r--ext/phar/TODO114
-rwxr-xr-xext/phar/cgidebug11
-rw-r--r--ext/phar/config.m415
-rw-r--r--ext/phar/config.w3214
-rw-r--r--ext/phar/dirstream.c587
-rw-r--r--ext/phar/dirstream.h47
-rw-r--r--ext/phar/func_interceptors.c1081
-rw-r--r--ext/phar/func_interceptors.h34
-rw-r--r--ext/phar/gdbhelp122
-rw-r--r--ext/phar/makestub.php109
-rw-r--r--ext/phar/package.php108
-rw-r--r--ext/phar/package.xml924
-rw-r--r--ext/phar/phar.c3091
-rwxr-xr-xext/phar/phar.phar1229
-rwxr-xr-xext/phar/phar/clicommand.inc377
-rwxr-xr-xext/phar/phar/phar.php57
-rwxr-xr-xext/phar/phar/pharcommand.inc1442
-rwxr-xr-xext/phar/phar_internal.h470
-rwxr-xr-xext/phar/phar_object.c4650
-rwxr-xr-xext/phar/phar_path_check.c187
-rwxr-xr-xext/phar/phar_path_check.re97
-rw-r--r--ext/phar/pharzip.h247
-rw-r--r--ext/phar/php_phar.h47
-rw-r--r--ext/phar/shortarc.php295
-rw-r--r--ext/phar/stream.c845
-rw-r--r--ext/phar/stream.h49
-rw-r--r--ext/phar/stub.h33
-rw-r--r--ext/phar/tar.c831
-rw-r--r--ext/phar/tar.h90
-rw-r--r--ext/phar/tests/001.phpt12
-rw-r--r--ext/phar/tests/002.phpt17
-rw-r--r--ext/phar/tests/003.phpt13
-rwxr-xr-xext/phar/tests/003a.phpt14
-rw-r--r--ext/phar/tests/004.phpt14
-rw-r--r--ext/phar/tests/005.phpt14
-rw-r--r--ext/phar/tests/006.phpt14
-rw-r--r--ext/phar/tests/007.phpt14
-rw-r--r--ext/phar/tests/008.phpt21
-rw-r--r--ext/phar/tests/009.phpt23
-rw-r--r--ext/phar/tests/010.phpt29
-rw-r--r--ext/phar/tests/011.phpt30
-rw-r--r--ext/phar/tests/012.phpt28
-rw-r--r--ext/phar/tests/013.phpt23
-rw-r--r--ext/phar/tests/014.phpt23
-rw-r--r--ext/phar/tests/015.phpt23
-rwxr-xr-xext/phar/tests/015b.phpt23
-rw-r--r--ext/phar/tests/016.phpt39
-rwxr-xr-xext/phar/tests/016b.phpt24
-rw-r--r--ext/phar/tests/017.phpt26
-rw-r--r--ext/phar/tests/018.phpt33
-rw-r--r--ext/phar/tests/019.phpt34
-rwxr-xr-xext/phar/tests/019b.phpt65
-rwxr-xr-xext/phar/tests/019c.phpt73
-rw-r--r--ext/phar/tests/020.phpt136
-rw-r--r--ext/phar/tests/021.phpt85
-rw-r--r--ext/phar/tests/022.phpt110
-rwxr-xr-xext/phar/tests/023.phpt32
-rwxr-xr-xext/phar/tests/024.phpt32
-rwxr-xr-xext/phar/tests/025.phpt32
-rwxr-xr-xext/phar/tests/026.phpt34
-rwxr-xr-xext/phar/tests/027.phpt94
-rwxr-xr-xext/phar/tests/028.phpt47
-rwxr-xr-xext/phar/tests/029.phpt50
-rwxr-xr-xext/phar/tests/030.phpt38
-rwxr-xr-xext/phar/tests/031.phpt31
-rwxr-xr-xext/phar/tests/032.phpt29
-rw-r--r--ext/phar/tests/033.phpt47
-rw-r--r--ext/phar/tests/033a.phpt36
-rw-r--r--ext/phar/tests/addfuncs.phpt41
-rw-r--r--ext/phar/tests/alias_acrobatics.phpt46
-rw-r--r--ext/phar/tests/badparameters.phpt210
-rw-r--r--ext/phar/tests/bug13727.phpt4135
-rw-r--r--ext/phar/tests/bug13786.phpt32
-rwxr-xr-xext/phar/tests/create_new_and_modify.phpt48
-rw-r--r--ext/phar/tests/create_new_phar.phpt21
-rwxr-xr-xext/phar/tests/create_new_phar_b.phpt27
-rwxr-xr-xext/phar/tests/create_new_phar_c.phpt29
-rwxr-xr-xext/phar/tests/create_path_error.phpt62
-rw-r--r--ext/phar/tests/delete.phpt31
-rw-r--r--ext/phar/tests/delete_in_phar.phpt48
-rwxr-xr-xext/phar/tests/delete_in_phar_b.phpt46
-rw-r--r--ext/phar/tests/delete_in_phar_confirm.phpt51
-rw-r--r--ext/phar/tests/dir.phpt92
-rw-r--r--ext/phar/tests/fgc_edgecases.phpt95
-rw-r--r--ext/phar/tests/file_get_contents.phpt30
-rw-r--r--ext/phar/tests/files/extracted.inc1
-rw-r--r--ext/phar/tests/files/frontcontroller.pharbin0 -> 331 bytes
-rw-r--r--ext/phar/tests/files/frontcontroller.phar.inc13
-rw-r--r--ext/phar/tests/files/frontcontroller10.pharbin0 -> 591 bytes
-rw-r--r--ext/phar/tests/files/frontcontroller10.phar.inc20
-rw-r--r--ext/phar/tests/files/frontcontroller11.pharbin0 -> 578 bytes
-rw-r--r--ext/phar/tests/files/frontcontroller11.phar.inc20
-rw-r--r--ext/phar/tests/files/frontcontroller12.pharbin0 -> 581 bytes
-rw-r--r--ext/phar/tests/files/frontcontroller12.phar.inc20
-rw-r--r--ext/phar/tests/files/frontcontroller13.pharbin0 -> 330 bytes
-rw-r--r--ext/phar/tests/files/frontcontroller13.phar.inc14
-rw-r--r--ext/phar/tests/files/frontcontroller14.pharbin0 -> 448 bytes
-rw-r--r--ext/phar/tests/files/frontcontroller14.phar.inc19
-rw-r--r--ext/phar/tests/files/frontcontroller16.pharbin0 -> 330 bytes
-rw-r--r--ext/phar/tests/files/frontcontroller16.phar.inc16
-rw-r--r--ext/phar/tests/files/frontcontroller17.pharbin0 -> 315 bytes
-rw-r--r--ext/phar/tests/files/frontcontroller17.phar.inc16
-rw-r--r--ext/phar/tests/files/frontcontroller18.pharbin0 -> 331 bytes
-rw-r--r--ext/phar/tests/files/frontcontroller18.phar.inc19
-rw-r--r--ext/phar/tests/files/frontcontroller19.pharbin0 -> 560 bytes
-rw-r--r--ext/phar/tests/files/frontcontroller19.phar.inc25
-rw-r--r--ext/phar/tests/files/frontcontroller2.pharbin0 -> 297 bytes
-rw-r--r--ext/phar/tests/files/frontcontroller2.phar.inc12
-rw-r--r--ext/phar/tests/files/frontcontroller3.pharbin0 -> 446 bytes
-rw-r--r--ext/phar/tests/files/frontcontroller3.phar.inc18
-rw-r--r--ext/phar/tests/files/frontcontroller4.pharbin0 -> 442 bytes
-rw-r--r--ext/phar/tests/files/frontcontroller4.phar.inc18
-rw-r--r--ext/phar/tests/files/frontcontroller5.pharbin0 -> 327 bytes
-rw-r--r--ext/phar/tests/files/frontcontroller5.phar.inc12
-rw-r--r--ext/phar/tests/files/frontcontroller6.pharbin0 -> 329 bytes
-rw-r--r--ext/phar/tests/files/frontcontroller6.phar.inc12
-rw-r--r--ext/phar/tests/files/frontcontroller7.pharbin0 -> 330 bytes
-rw-r--r--ext/phar/tests/files/frontcontroller7.phar.inc12
-rw-r--r--ext/phar/tests/files/frontcontroller8.pharbin0 -> 8968 bytes
-rw-r--r--ext/phar/tests/files/frontcontroller8.phar.inc19
-rw-r--r--ext/phar/tests/files/frontcontroller9.pharbin0 -> 448 bytes
-rw-r--r--ext/phar/tests/files/frontcontroller9.phar.inc14
-rw-r--r--ext/phar/tests/files/md5.pharbin0 -> 107 bytes
-rw-r--r--ext/phar/tests/files/nophar.pharbin0 -> 7017 bytes
-rw-r--r--ext/phar/tests/files/nophar.phar.inc10
-rw-r--r--ext/phar/tests/files/phar_oo_test.inc49
-rw-r--r--ext/phar/tests/files/phar_test.inc76
-rw-r--r--ext/phar/tests/files/sha1.pharbin0 -> 111 bytes
-rw-r--r--ext/phar/tests/files/sha256.pharbin0 -> 123 bytes
-rw-r--r--ext/phar/tests/files/sha512.pharbin0 -> 155 bytes
-rw-r--r--ext/phar/tests/files/zfapp.tgzbin0 -> 1725 bytes
-rw-r--r--ext/phar/tests/fopen.phpt43
-rw-r--r--ext/phar/tests/fopen5.2.phpt43
-rw-r--r--ext/phar/tests/fopen_edgecases.phpt124
-rw-r--r--ext/phar/tests/fopen_edgecases2.phpt43
-rw-r--r--ext/phar/tests/frontcontroller1.phpt15
-rw-r--r--ext/phar/tests/frontcontroller10.phpt22
-rw-r--r--ext/phar/tests/frontcontroller11.phpt18
-rw-r--r--ext/phar/tests/frontcontroller12.phpt18
-rw-r--r--ext/phar/tests/frontcontroller13.phpt18
-rw-r--r--ext/phar/tests/frontcontroller14.phpt15
-rw-r--r--ext/phar/tests/frontcontroller15.phpt18
-rw-r--r--ext/phar/tests/frontcontroller16.phpt15
-rw-r--r--ext/phar/tests/frontcontroller17.phpt16
-rw-r--r--ext/phar/tests/frontcontroller18.phpt16
-rw-r--r--ext/phar/tests/frontcontroller19.phpt16
-rw-r--r--ext/phar/tests/frontcontroller2.phpt14
-rw-r--r--ext/phar/tests/frontcontroller20.phpt16
-rw-r--r--ext/phar/tests/frontcontroller21.phpt22
-rw-r--r--ext/phar/tests/frontcontroller22.phpt19
-rw-r--r--ext/phar/tests/frontcontroller23.phpt15
-rw-r--r--ext/phar/tests/frontcontroller24.phpt14
-rw-r--r--ext/phar/tests/frontcontroller25.phpt15
-rw-r--r--ext/phar/tests/frontcontroller26.phpt14
-rw-r--r--ext/phar/tests/frontcontroller27.phpt14
-rw-r--r--ext/phar/tests/frontcontroller28.phpt14
-rw-r--r--ext/phar/tests/frontcontroller29.phpt14
-rw-r--r--ext/phar/tests/frontcontroller3.phpt17
-rw-r--r--ext/phar/tests/frontcontroller30.phpt12
-rw-r--r--ext/phar/tests/frontcontroller31.phpt13
-rw-r--r--ext/phar/tests/frontcontroller32.phpt13
-rw-r--r--ext/phar/tests/frontcontroller33.phpt13
-rw-r--r--ext/phar/tests/frontcontroller34.phpt16
-rw-r--r--ext/phar/tests/frontcontroller4.phpt13
-rw-r--r--ext/phar/tests/frontcontroller5.phpt14
-rw-r--r--ext/phar/tests/frontcontroller6.phpt21
-rw-r--r--ext/phar/tests/frontcontroller7.phpt14
-rw-r--r--ext/phar/tests/frontcontroller8.phpt21
-rw-r--r--ext/phar/tests/frontcontroller9.phpt17
-rw-r--r--ext/phar/tests/include_path.phpt34
-rw-r--r--ext/phar/tests/ini_set.phpt28
-rw-r--r--ext/phar/tests/ini_set_off.phpt85
-rw-r--r--ext/phar/tests/invalid_alias.phpt45
-rw-r--r--ext/phar/tests/invalid_setstubalias.phpt47
-rw-r--r--ext/phar/tests/metadata_read.phpt61
-rwxr-xr-xext/phar/tests/metadata_write.phpt62
-rwxr-xr-xext/phar/tests/metadata_write_commit.phpt79
-rw-r--r--ext/phar/tests/mkdir.phpt41
-rw-r--r--ext/phar/tests/mounteddir.phpt109
-rw-r--r--ext/phar/tests/nophar.phpt14
-rw-r--r--ext/phar/tests/nophar_web.phpt11
-rw-r--r--ext/phar/tests/open_for_write_existing.phpt31
-rwxr-xr-xext/phar/tests/open_for_write_existing_b.phpt42
-rwxr-xr-xext/phar/tests/open_for_write_existing_c.phpt36
-rw-r--r--ext/phar/tests/open_for_write_newfile.phpt33
-rwxr-xr-xext/phar/tests/open_for_write_newfile_b.phpt49
-rwxr-xr-xext/phar/tests/open_for_write_newfile_c.phpt43
-rw-r--r--ext/phar/tests/opendir.phpt42
-rw-r--r--ext/phar/tests/opendir_edgecases.phpt46
-rwxr-xr-xext/phar/tests/phar_begin_setstub_commit.phpt50
-rw-r--r--ext/phar/tests/phar_buildfromdirectory1.phpt28
-rw-r--r--ext/phar/tests/phar_buildfromdirectory2.phpt27
-rw-r--r--ext/phar/tests/phar_buildfromdirectory3.phpt27
-rw-r--r--ext/phar/tests/phar_buildfromdirectory4.phpt50
-rw-r--r--ext/phar/tests/phar_buildfromdirectory5.phpt50
-rw-r--r--ext/phar/tests/phar_buildfromdirectory6.phpt40
-rw-r--r--ext/phar/tests/phar_buildfromiterator1.phpt28
-rw-r--r--ext/phar/tests/phar_buildfromiterator10.phpt98
-rw-r--r--ext/phar/tests/phar_buildfromiterator2.phpt26
-rw-r--r--ext/phar/tests/phar_buildfromiterator3.phpt54
-rw-r--r--ext/phar/tests/phar_buildfromiterator4.phpt64
-rw-r--r--ext/phar/tests/phar_buildfromiterator5.phpt59
-rw-r--r--ext/phar/tests/phar_buildfromiterator6.phpt60
-rw-r--r--ext/phar/tests/phar_buildfromiterator7.phpt60
-rw-r--r--ext/phar/tests/phar_buildfromiterator8.phpt96
-rw-r--r--ext/phar/tests/phar_buildfromiterator9.phpt65
-rw-r--r--ext/phar/tests/phar_bz2.phpt63
-rw-r--r--ext/phar/tests/phar_commitwrite.phpt42
-rw-r--r--ext/phar/tests/phar_convert_again.phpt218
-rw-r--r--ext/phar/tests/phar_convert_repeated.phpt149
-rw-r--r--ext/phar/tests/phar_convert_repeated_b.phpt117
-rw-r--r--ext/phar/tests/phar_convert_tar.phpt57
-rw-r--r--ext/phar/tests/phar_convert_tar2.phpt64
-rw-r--r--ext/phar/tests/phar_convert_tar3.phpt65
-rw-r--r--ext/phar/tests/phar_convert_zip.phpt56
-rw-r--r--ext/phar/tests/phar_copy.phpt72
-rw-r--r--ext/phar/tests/phar_create_in_cwd.phpt45
-rw-r--r--ext/phar/tests/phar_createdefaultstub.phpt929
-rw-r--r--ext/phar/tests/phar_ctx_001.phpt100
-rw-r--r--ext/phar/tests/phar_decompress.phpt69
-rw-r--r--ext/phar/tests/phar_dir_iterate.phpt32
-rw-r--r--ext/phar/tests/phar_extract.phpt131
-rw-r--r--ext/phar/tests/phar_get_supported_signatures_001.phpt22
-rw-r--r--ext/phar/tests/phar_get_supported_signatures_002.phpt26
-rw-r--r--ext/phar/tests/phar_get_supportedcomp1.phpt22
-rw-r--r--ext/phar/tests/phar_get_supportedcomp2.phpt20
-rw-r--r--ext/phar/tests/phar_get_supportedcomp3.phpt20
-rw-r--r--ext/phar/tests/phar_get_supportedcomp4.phpt16
-rw-r--r--ext/phar/tests/phar_gobyebye.phpt44
-rw-r--r--ext/phar/tests/phar_gzip.phpt54
-rw-r--r--ext/phar/tests/phar_isvalidpharfilename.phpt140
-rw-r--r--ext/phar/tests/phar_magic.phpt31
-rw-r--r--ext/phar/tests/phar_metadata_read.phpt95
-rw-r--r--ext/phar/tests/phar_metadata_write.phpt71
-rw-r--r--ext/phar/tests/phar_mount.phpt63
-rwxr-xr-xext/phar/tests/phar_offset_get_error.phpt37
-rwxr-xr-xext/phar/tests/phar_oo_001.phpt54
-rwxr-xr-xext/phar/tests/phar_oo_002.phpt137
-rwxr-xr-xext/phar/tests/phar_oo_003.phpt45
-rwxr-xr-xext/phar/tests/phar_oo_004.phpt126
-rwxr-xr-xext/phar/tests/phar_oo_005.phpt60
-rwxr-xr-xext/phar/tests/phar_oo_006.phpt52
-rwxr-xr-xext/phar/tests/phar_oo_007.phpt87
-rwxr-xr-xext/phar/tests/phar_oo_008.phpt119
-rwxr-xr-xext/phar/tests/phar_oo_009.phpt56
-rwxr-xr-xext/phar/tests/phar_oo_010.phpt55
-rw-r--r--ext/phar/tests/phar_oo_011.phpt34
-rwxr-xr-xext/phar/tests/phar_oo_011b.phpt39
-rw-r--r--ext/phar/tests/phar_oo_012.phpt37
-rw-r--r--ext/phar/tests/phar_oo_012_confirm.phpt40
-rwxr-xr-xext/phar/tests/phar_oo_012b.phpt42
-rw-r--r--ext/phar/tests/phar_oo_compressallbz2.phpt66
-rw-r--r--ext/phar/tests/phar_oo_compressallgz.phpt71
-rw-r--r--ext/phar/tests/phar_oo_compressed_001.phpt68
-rwxr-xr-xext/phar/tests/phar_oo_compressed_001b.phpt68
-rwxr-xr-xext/phar/tests/phar_oo_compressed_002.phpt73
-rwxr-xr-xext/phar/tests/phar_oo_compressed_002b.phpt73
-rw-r--r--ext/phar/tests/phar_oo_getcontents.phpt39
-rw-r--r--ext/phar/tests/phar_oo_getcontentsgz.phpt34
-rw-r--r--ext/phar/tests/phar_oo_getmodified.phpt36
-rw-r--r--ext/phar/tests/phar_oo_iswriteable.phpt84
-rw-r--r--ext/phar/tests/phar_oo_nosig.phpt24
-rw-r--r--ext/phar/tests/phar_oo_uncompressall.phpt80
-rw-r--r--ext/phar/tests/phar_running.phpt29
-rw-r--r--ext/phar/tests/phar_setalias.phpt36
-rw-r--r--ext/phar/tests/phar_setalias2.phpt51
-rw-r--r--ext/phar/tests/phar_setdefaultstub.phpt944
-rw-r--r--ext/phar/tests/phar_setsignaturealgo1.phpt69
-rw-r--r--ext/phar/tests/phar_setsignaturealgo2.phpt79
-rw-r--r--ext/phar/tests/phar_stub.phpt92
-rwxr-xr-xext/phar/tests/phar_stub_error.phpt56
-rwxr-xr-xext/phar/tests/phar_stub_write.phpt64
-rwxr-xr-xext/phar/tests/phar_stub_write_file.phpt65
-rw-r--r--ext/phar/tests/phar_unlinkarchive.phpt108
-rw-r--r--ext/phar/tests/pharfileinfo_chmod.phpt33
-rw-r--r--ext/phar/tests/pharfileinfo_compression.phpt94
-rw-r--r--ext/phar/tests/pharfileinfo_construct.phpt54
-rw-r--r--ext/phar/tests/pharfileinfo_destruct.phpt25
-rw-r--r--ext/phar/tests/pharfileinfo_getcrc32.phpt49
-rw-r--r--ext/phar/tests/pharfileinfo_setmetadata.phpt65
-rw-r--r--ext/phar/tests/phpinfo_001.phpt59
-rw-r--r--ext/phar/tests/phpinfo_002.phpt37
-rw-r--r--ext/phar/tests/phpinfo_003.phpt37
-rw-r--r--ext/phar/tests/phpinfo_004.phpt66
-rw-r--r--ext/phar/tests/readfile.phpt30
-rw-r--r--ext/phar/tests/readfile_edgecases.phpt62
-rw-r--r--ext/phar/tests/refcount1.phpt62
-rwxr-xr-xext/phar/tests/refcount1_5_2.phpt64
-rw-r--r--ext/phar/tests/rename.phpt32
-rw-r--r--ext/phar/tests/security.phpt36
-rw-r--r--ext/phar/tests/stat.phpt215
-rw-r--r--ext/phar/tests/stat2.phpt60
-rw-r--r--ext/phar/tests/stat2_5.3.phpt60
-rw-r--r--ext/phar/tests/tar/033.phpt50
-rw-r--r--ext/phar/tests/tar/033a.phpt45
-rw-r--r--ext/phar/tests/tar/alias_acrobatics.phpt46
-rw-r--r--ext/phar/tests/tar/badalias.phpt25
-rw-r--r--ext/phar/tests/tar/badchecksum.phpt30
-rw-r--r--ext/phar/tests/tar/bignames.phpt35
-rw-r--r--ext/phar/tests/tar/create_new_and_modify.phpt45
-rw-r--r--ext/phar/tests/tar/create_new_phar_b.phpt27
-rw-r--r--ext/phar/tests/tar/delete.phpt32
-rw-r--r--ext/phar/tests/tar/delete_in_phar.phpt49
-rw-r--r--ext/phar/tests/tar/delete_in_phar_b.phpt49
-rw-r--r--ext/phar/tests/tar/delete_in_phar_confirm.phpt52
-rw-r--r--ext/phar/tests/tar/dir.phpt43
-rw-r--r--ext/phar/tests/tar/exists_as_phar.phpt38
-rw-r--r--ext/phar/tests/tar/files/badalias1.phar.tarbin0 -> 3072 bytes
-rw-r--r--ext/phar/tests/tar/files/badalias2.phar.tarbin0 -> 3072 bytes
-rw-r--r--ext/phar/tests/tar/files/badalias3.phar.tarbin0 -> 3072 bytes
-rw-r--r--ext/phar/tests/tar/files/badalias4.phar.tarbin0 -> 3072 bytes
-rw-r--r--ext/phar/tests/tar/files/badalias5.phar.tarbin0 -> 3584 bytes
-rw-r--r--ext/phar/tests/tar/files/biglink.tarbin0 -> 10240 bytes
-rw-r--r--ext/phar/tests/tar/files/corrupt_tarmaker.php.inc177
-rw-r--r--ext/phar/tests/tar/files/frontcontroller.phar.inc13
-rw-r--r--ext/phar/tests/tar/files/frontcontroller.phar.tarbin0 -> 6144 bytes
-rw-r--r--ext/phar/tests/tar/files/frontcontroller10.phar.inc20
-rw-r--r--ext/phar/tests/tar/files/frontcontroller10.phar.tarbin0 -> 3072 bytes
-rw-r--r--ext/phar/tests/tar/files/frontcontroller11.phar.inc20
-rw-r--r--ext/phar/tests/tar/files/frontcontroller11.phar.tarbin0 -> 3072 bytes
-rw-r--r--ext/phar/tests/tar/files/frontcontroller12.phar.inc20
-rw-r--r--ext/phar/tests/tar/files/frontcontroller12.phar.tarbin0 -> 3072 bytes
-rw-r--r--ext/phar/tests/tar/files/frontcontroller2.phar.inc12
-rw-r--r--ext/phar/tests/tar/files/frontcontroller2.phar.tarbin0 -> 5120 bytes
-rw-r--r--ext/phar/tests/tar/files/frontcontroller3.phar.inc18
-rw-r--r--ext/phar/tests/tar/files/frontcontroller3.phar.tarbin0 -> 5120 bytes
-rw-r--r--ext/phar/tests/tar/files/frontcontroller4.phar.inc18
-rw-r--r--ext/phar/tests/tar/files/frontcontroller4.phar.tarbin0 -> 5120 bytes
-rw-r--r--ext/phar/tests/tar/files/frontcontroller5.phar.inc12
-rw-r--r--ext/phar/tests/tar/files/frontcontroller5.phar.tarbin0 -> 5120 bytes
-rw-r--r--ext/phar/tests/tar/files/frontcontroller6.phar.inc12
-rw-r--r--ext/phar/tests/tar/files/frontcontroller6.phar.tarbin0 -> 5120 bytes
-rw-r--r--ext/phar/tests/tar/files/frontcontroller7.phar.inc12
-rw-r--r--ext/phar/tests/tar/files/frontcontroller7.phar.tarbin0 -> 5120 bytes
-rw-r--r--ext/phar/tests/tar/files/frontcontroller8.phar.inc13
-rw-r--r--ext/phar/tests/tar/files/frontcontroller8.phar.tarbin0 -> 6144 bytes
-rw-r--r--ext/phar/tests/tar/files/frontcontroller9.phar.inc14
-rw-r--r--ext/phar/tests/tar/files/frontcontroller9.phar.tarbin0 -> 6144 bytes
-rw-r--r--ext/phar/tests/tar/files/links.tarbin0 -> 10240 bytes
-rw-r--r--ext/phar/tests/tar/files/make_invalid_tar.php.inc9
-rw-r--r--ext/phar/tests/tar/files/subdirlink.tarbin0 -> 10240 bytes
-rw-r--r--ext/phar/tests/tar/files/tarmaker.php.inc169
-rw-r--r--ext/phar/tests/tar/files/tinylink.tarbin0 -> 10240 bytes
-rw-r--r--ext/phar/tests/tar/files/trunc.tarbin0 -> 800 bytes
-rw-r--r--ext/phar/tests/tar/frontcontroller1.phar.phpt15
-rw-r--r--ext/phar/tests/tar/frontcontroller10.phar.phpt22
-rw-r--r--ext/phar/tests/tar/frontcontroller11.phar.phpt18
-rw-r--r--ext/phar/tests/tar/frontcontroller12.phar.phpt18
-rw-r--r--ext/phar/tests/tar/frontcontroller13.phar.phpt18
-rw-r--r--ext/phar/tests/tar/frontcontroller14.phar.phpt15
-rw-r--r--ext/phar/tests/tar/frontcontroller15.phar.phpt18
-rw-r--r--ext/phar/tests/tar/frontcontroller16.phar.phpt15
-rw-r--r--ext/phar/tests/tar/frontcontroller17.phar.phpt16
-rw-r--r--ext/phar/tests/tar/frontcontroller18.phar.phpt16
-rw-r--r--ext/phar/tests/tar/frontcontroller19.phar.phpt16
-rw-r--r--ext/phar/tests/tar/frontcontroller2.phar.phpt14
-rw-r--r--ext/phar/tests/tar/frontcontroller20.phar.phpt16
-rw-r--r--ext/phar/tests/tar/frontcontroller21.phar.phpt22
-rw-r--r--ext/phar/tests/tar/frontcontroller3.phar.phpt17
-rw-r--r--ext/phar/tests/tar/frontcontroller4.phar.phpt13
-rw-r--r--ext/phar/tests/tar/frontcontroller5.phar.phpt14
-rw-r--r--ext/phar/tests/tar/frontcontroller6.phar.phpt21
-rw-r--r--ext/phar/tests/tar/frontcontroller7.phar.phpt14
-rw-r--r--ext/phar/tests/tar/frontcontroller8.phar.phpt21
-rw-r--r--ext/phar/tests/tar/frontcontroller9.phar.phpt17
-rw-r--r--ext/phar/tests/tar/links.phpt33
-rw-r--r--ext/phar/tests/tar/links2.phpt35
-rw-r--r--ext/phar/tests/tar/links3.phpt19
-rw-r--r--ext/phar/tests/tar/links4.phpt19
-rw-r--r--ext/phar/tests/tar/links5.phpt19
-rw-r--r--ext/phar/tests/tar/open_for_write_existing.phpt42
-rwxr-xr-xext/phar/tests/tar/open_for_write_existing_b.phpt56
-rwxr-xr-xext/phar/tests/tar/open_for_write_existing_c.phpt50
-rw-r--r--ext/phar/tests/tar/open_for_write_newfile.phpt44
-rwxr-xr-xext/phar/tests/tar/open_for_write_newfile_b.phpt61
-rwxr-xr-xext/phar/tests/tar/open_for_write_newfile_c.phpt54
-rwxr-xr-xext/phar/tests/tar/phar_begin_setstub_commit.phpt51
-rw-r--r--ext/phar/tests/tar/phar_buildfromiterator4.phpt66
-rw-r--r--ext/phar/tests/tar/phar_buildfromiterator5.phpt59
-rw-r--r--ext/phar/tests/tar/phar_buildfromiterator6.phpt60
-rw-r--r--ext/phar/tests/tar/phar_buildfromiterator7.phpt60
-rw-r--r--ext/phar/tests/tar/phar_buildfromiterator8.phpt73
-rw-r--r--ext/phar/tests/tar/phar_buildfromiterator9.phpt65
-rw-r--r--ext/phar/tests/tar/phar_commitwrite.phpt44
-rw-r--r--ext/phar/tests/tar/phar_convert_phar.phpt58
-rw-r--r--ext/phar/tests/tar/phar_convert_phar2.phpt62
-rw-r--r--ext/phar/tests/tar/phar_convert_phar3.phpt62
-rw-r--r--ext/phar/tests/tar/phar_copy.phpt56
-rw-r--r--ext/phar/tests/tar/phar_magic.phpt33
-rw-r--r--ext/phar/tests/tar/phar_setalias.phpt51
-rw-r--r--ext/phar/tests/tar/phar_setalias2.phpt53
-rw-r--r--ext/phar/tests/tar/phar_setdefaultstub.phpt80
-rw-r--r--ext/phar/tests/tar/phar_stub.phpt75
-rwxr-xr-xext/phar/tests/tar/phar_stub_error.phpt57
-rw-r--r--ext/phar/tests/tar/refcount1.phpt74
-rwxr-xr-xext/phar/tests/tar/refcount1_5_2.phpt64
-rw-r--r--ext/phar/tests/tar/rename.phpt42
-rw-r--r--ext/phar/tests/tar/tar_001.phpt31
-rw-r--r--ext/phar/tests/tar/tar_002.phpt34
-rw-r--r--ext/phar/tests/tar/tar_003.phpt74
-rw-r--r--ext/phar/tests/tar/tar_004.phpt38
-rw-r--r--ext/phar/tests/tar/tar_bz2.phpt54
-rw-r--r--ext/phar/tests/tar/tar_gzip.phpt51
-rw-r--r--ext/phar/tests/tar/tar_makebz2.phpt40
-rw-r--r--ext/phar/tests/tar/tar_makegz.phpt41
-rw-r--r--ext/phar/tests/tar/tar_nostub.phpt48
-rw-r--r--ext/phar/tests/tar/truncated.phpt22
-rw-r--r--ext/phar/tests/test_alias_unset.phpt45
-rw-r--r--ext/phar/tests/test_signaturealgos.phpt30
-rw-r--r--ext/phar/tests/test_unset.phpt42
-rw-r--r--ext/phar/tests/webphar_compilefail.phpt17
-rw-r--r--ext/phar/tests/withphar.phpt14
-rw-r--r--ext/phar/tests/withphar_web.phpt14
-rw-r--r--ext/phar/tests/zf_test.phpt49
-rw-r--r--ext/phar/tests/zip/033.phpt56
-rw-r--r--ext/phar/tests/zip/033a.phpt45
-rw-r--r--ext/phar/tests/zip/alias_acrobatics.phpt46
-rw-r--r--ext/phar/tests/zip/all.phpt62
-rw-r--r--ext/phar/tests/zip/badalias.phpt25
-rw-r--r--ext/phar/tests/zip/corrupt_001.phpt23
-rw-r--r--ext/phar/tests/zip/corrupt_002.phpt17
-rw-r--r--ext/phar/tests/zip/corrupt_003.phpt17
-rw-r--r--ext/phar/tests/zip/corrupt_004.phpt17
-rw-r--r--ext/phar/tests/zip/corrupt_005.phpt17
-rw-r--r--ext/phar/tests/zip/corrupt_006.phpt17
-rw-r--r--ext/phar/tests/zip/corrupt_007.phpt17
-rw-r--r--ext/phar/tests/zip/corrupt_008.phpt101
-rw-r--r--ext/phar/tests/zip/create_new_and_modify.phpt45
-rw-r--r--ext/phar/tests/zip/create_new_phar_b.phpt27
-rw-r--r--ext/phar/tests/zip/delete.phpt31
-rw-r--r--ext/phar/tests/zip/delete_in_phar.phpt49
-rw-r--r--ext/phar/tests/zip/delete_in_phar_b.phpt48
-rw-r--r--ext/phar/tests/zip/delete_in_phar_confirm.phpt53
-rw-r--r--ext/phar/tests/zip/dir.phpt43
-rw-r--r--ext/phar/tests/zip/exists_as_phar.phpt38
-rw-r--r--ext/phar/tests/zip/files/badalias1.phar.zipbin0 -> 353 bytes
-rw-r--r--ext/phar/tests/zip/files/badalias2.phar.zipbin0 -> 353 bytes
-rw-r--r--ext/phar/tests/zip/files/badalias3.phar.zipbin0 -> 353 bytes
-rw-r--r--ext/phar/tests/zip/files/badalias4.phar.zipbin0 -> 353 bytes
-rw-r--r--ext/phar/tests/zip/files/badalias5.phar.zipbin0 -> 353 bytes
-rw-r--r--ext/phar/tests/zip/files/cdir_offset.zipbin0 -> 191 bytes
-rw-r--r--ext/phar/tests/zip/files/compress_unsup1.zipbin0 -> 105 bytes
-rw-r--r--ext/phar/tests/zip/files/compress_unsup10.zipbin0 -> 105 bytes
-rw-r--r--ext/phar/tests/zip/files/compress_unsup14.zipbin0 -> 105 bytes
-rw-r--r--ext/phar/tests/zip/files/compress_unsup18.zipbin0 -> 105 bytes
-rw-r--r--ext/phar/tests/zip/files/compress_unsup19.zipbin0 -> 105 bytes
-rw-r--r--ext/phar/tests/zip/files/compress_unsup2.zipbin0 -> 105 bytes
-rw-r--r--ext/phar/tests/zip/files/compress_unsup3.zipbin0 -> 105 bytes
-rw-r--r--ext/phar/tests/zip/files/compress_unsup4.zipbin0 -> 105 bytes
-rw-r--r--ext/phar/tests/zip/files/compress_unsup5.zipbin0 -> 105 bytes
-rw-r--r--ext/phar/tests/zip/files/compress_unsup6.zipbin0 -> 105 bytes
-rw-r--r--ext/phar/tests/zip/files/compress_unsup7.zipbin0 -> 105 bytes
-rw-r--r--ext/phar/tests/zip/files/compress_unsup9.zipbin0 -> 105 bytes
-rw-r--r--ext/phar/tests/zip/files/compress_unsup97.zipbin0 -> 105 bytes
-rw-r--r--ext/phar/tests/zip/files/compress_unsup98.zipbin0 -> 105 bytes
-rw-r--r--ext/phar/tests/zip/files/compress_unsupunknown.zipbin0 -> 105 bytes
-rw-r--r--ext/phar/tests/zip/files/corrupt2.php.inc60
-rw-r--r--ext/phar/tests/zip/files/corrupt_count1.php.inc11
-rw-r--r--ext/phar/tests/zip/files/corrupt_zipmaker.php.inc317
-rw-r--r--ext/phar/tests/zip/files/count1.zipbin0 -> 191 bytes
-rw-r--r--ext/phar/tests/zip/files/count2.zipbin0 -> 191 bytes
-rw-r--r--ext/phar/tests/zip/files/encrypted.zipbin0 -> 191 bytes
-rw-r--r--ext/phar/tests/zip/files/filecomment.zipbin0 -> 191 bytes
-rw-r--r--ext/phar/tests/zip/files/frontcontroller.phar.inc13
-rw-r--r--ext/phar/tests/zip/files/frontcontroller.phar.zipbin0 -> 625 bytes
-rw-r--r--ext/phar/tests/zip/files/frontcontroller10.phar.inc20
-rw-r--r--ext/phar/tests/zip/files/frontcontroller10.phar.zipbin0 -> 471 bytes
-rw-r--r--ext/phar/tests/zip/files/frontcontroller11.phar.inc20
-rw-r--r--ext/phar/tests/zip/files/frontcontroller11.phar.zipbin0 -> 461 bytes
-rw-r--r--ext/phar/tests/zip/files/frontcontroller12.phar.inc20
-rw-r--r--ext/phar/tests/zip/files/frontcontroller12.phar.zipbin0 -> 465 bytes
-rw-r--r--ext/phar/tests/zip/files/frontcontroller2.phar.inc12
-rw-r--r--ext/phar/tests/zip/files/frontcontroller2.phar.zipbin0 -> 531 bytes
-rw-r--r--ext/phar/tests/zip/files/frontcontroller3.phar.inc18
-rw-r--r--ext/phar/tests/zip/files/frontcontroller3.phar.zipbin0 -> 826 bytes
-rw-r--r--ext/phar/tests/zip/files/frontcontroller4.phar.inc18
-rw-r--r--ext/phar/tests/zip/files/frontcontroller4.phar.zipbin0 -> 822 bytes
-rw-r--r--ext/phar/tests/zip/files/frontcontroller5.phar.inc12
-rw-r--r--ext/phar/tests/zip/files/frontcontroller5.phar.zipbin0 -> 554 bytes
-rw-r--r--ext/phar/tests/zip/files/frontcontroller6.phar.inc12
-rw-r--r--ext/phar/tests/zip/files/frontcontroller6.phar.zipbin0 -> 559 bytes
-rw-r--r--ext/phar/tests/zip/files/frontcontroller7.phar.inc12
-rw-r--r--ext/phar/tests/zip/files/frontcontroller7.phar.zipbin0 -> 559 bytes
-rw-r--r--ext/phar/tests/zip/files/frontcontroller8.phar.inc13
-rw-r--r--ext/phar/tests/zip/files/frontcontroller8.phar.zipbin0 -> 684 bytes
-rw-r--r--ext/phar/tests/zip/files/frontcontroller9.phar.inc14
-rw-r--r--ext/phar/tests/zip/files/frontcontroller9.phar.zipbin0 -> 697 bytes
-rw-r--r--ext/phar/tests/zip/files/make_invalid_tar.php.inc12
-rw-r--r--ext/phar/tests/zip/files/metadata.phar.inc11
-rw-r--r--ext/phar/tests/zip/files/metadata.phar.zipbin0 -> 779 bytes
-rw-r--r--ext/phar/tests/zip/files/nozipend.zipbin0 -> 169 bytes
-rw-r--r--ext/phar/tests/zip/files/odt.odtbin0 -> 8873 bytes
-rw-r--r--ext/phar/tests/zip/files/stdin.zipbin0 -> 186 bytes
-rw-r--r--ext/phar/tests/zip/files/truncfilename.zipbin0 -> 190 bytes
-rw-r--r--ext/phar/tests/zip/files/zip.zipbin0 -> 619 bytes
-rw-r--r--ext/phar/tests/zip/files/zipmaker.php.inc70
-rw-r--r--ext/phar/tests/zip/frontcontroller1.phar.phpt15
-rw-r--r--ext/phar/tests/zip/frontcontroller10.phar.phpt22
-rw-r--r--ext/phar/tests/zip/frontcontroller11.phar.phpt18
-rw-r--r--ext/phar/tests/zip/frontcontroller12.phar.phpt18
-rw-r--r--ext/phar/tests/zip/frontcontroller13.phar.phpt18
-rw-r--r--ext/phar/tests/zip/frontcontroller14.phar.phpt15
-rw-r--r--ext/phar/tests/zip/frontcontroller15.phar.phpt18
-rw-r--r--ext/phar/tests/zip/frontcontroller16.phar.phpt15
-rw-r--r--ext/phar/tests/zip/frontcontroller17.phar.phpt16
-rw-r--r--ext/phar/tests/zip/frontcontroller18.phar.phpt16
-rw-r--r--ext/phar/tests/zip/frontcontroller19.phar.phpt16
-rw-r--r--ext/phar/tests/zip/frontcontroller2.phar.phpt14
-rw-r--r--ext/phar/tests/zip/frontcontroller20.phar.phpt16
-rw-r--r--ext/phar/tests/zip/frontcontroller21.phar.phpt22
-rw-r--r--ext/phar/tests/zip/frontcontroller3.phar.phpt17
-rw-r--r--ext/phar/tests/zip/frontcontroller4.phar.phpt13
-rw-r--r--ext/phar/tests/zip/frontcontroller5.phar.phpt14
-rw-r--r--ext/phar/tests/zip/frontcontroller6.phar.phpt21
-rw-r--r--ext/phar/tests/zip/frontcontroller7.phar.phpt14
-rw-r--r--ext/phar/tests/zip/frontcontroller8.phar.phpt21
-rw-r--r--ext/phar/tests/zip/frontcontroller9.phar.phpt17
-rw-r--r--ext/phar/tests/zip/getalias.phpt59
-rw-r--r--ext/phar/tests/zip/largezip.phpt29
-rw-r--r--ext/phar/tests/zip/metadata_write_commit.phpt85
-rw-r--r--ext/phar/tests/zip/notphar.phpt23
-rw-r--r--ext/phar/tests/zip/odt.phpt34
-rw-r--r--ext/phar/tests/zip/open_for_write_existing.phpt39
-rwxr-xr-xext/phar/tests/zip/open_for_write_existing_b.phpt52
-rwxr-xr-xext/phar/tests/zip/open_for_write_existing_c.phpt46
-rw-r--r--ext/phar/tests/zip/open_for_write_newfile.phpt42
-rwxr-xr-xext/phar/tests/zip/open_for_write_newfile_b.phpt60
-rwxr-xr-xext/phar/tests/zip/open_for_write_newfile_c.phpt54
-rwxr-xr-xext/phar/tests/zip/phar_begin_setstub_commit.phpt68
-rw-r--r--ext/phar/tests/zip/phar_buildfromiterator4.phpt66
-rw-r--r--ext/phar/tests/zip/phar_buildfromiterator5.phpt59
-rw-r--r--ext/phar/tests/zip/phar_buildfromiterator6.phpt60
-rw-r--r--ext/phar/tests/zip/phar_buildfromiterator7.phpt60
-rw-r--r--ext/phar/tests/zip/phar_buildfromiterator8.phpt73
-rw-r--r--ext/phar/tests/zip/phar_buildfromiterator9.phpt65
-rw-r--r--ext/phar/tests/zip/phar_commitwrite.phpt44
-rw-r--r--ext/phar/tests/zip/phar_convert_phar.phpt57
-rw-r--r--ext/phar/tests/zip/phar_copy.phpt55
-rw-r--r--ext/phar/tests/zip/phar_magic.phpt33
-rw-r--r--ext/phar/tests/zip/phar_oo_compressallbz2.phpt70
-rw-r--r--ext/phar/tests/zip/phar_oo_compressallgz.phpt58
-rw-r--r--ext/phar/tests/zip/phar_setalias.phpt62
-rw-r--r--ext/phar/tests/zip/phar_setalias2.phpt49
-rw-r--r--ext/phar/tests/zip/phar_setdefaultstub.phpt80
-rw-r--r--ext/phar/tests/zip/phar_stub.phpt75
-rwxr-xr-xext/phar/tests/zip/phar_stub_error.phpt58
-rw-r--r--ext/phar/tests/zip/refcount1.phpt70
-rwxr-xr-xext/phar/tests/zip/refcount1_5_2.phpt64
-rw-r--r--ext/phar/tests/zip/rename.phpt34
-rw-r--r--ext/phar/tests/zip/unixzip.phpt26
-rw-r--r--ext/phar/util.c1296
-rw-r--r--ext/phar/zip.c1100
555 files changed, 43985 insertions, 0 deletions
diff --git a/ext/phar/CREDITS b/ext/phar/CREDITS
new file mode 100644
index 0000000000..b54c6e8e3b
--- /dev/null
+++ b/ext/phar/CREDITS
@@ -0,0 +1,2 @@
+PHP Archive
+Gregory Beaver, Marcus Boerger
diff --git a/ext/phar/LICENSE b/ext/phar/LICENSE
new file mode 100644
index 0000000000..50770e3a03
--- /dev/null
+++ b/ext/phar/LICENSE
@@ -0,0 +1,95 @@
+--------------------------------------------------------------------
+ The PHP License, version 3.01
+Copyright (c) 1999 - 2005 The PHP Group. All rights reserved.
+--------------------------------------------------------------------
+
+Redistribution and use in source and binary forms, with or without
+modification, is permitted provided that the following conditions
+are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ 3. The name "PHP" must not be used to endorse or promote products
+ derived from this software without prior written permission. For
+ written permission, please contact group@php.net.
+
+ 4. Products derived from this software may not be called "PHP", nor
+ may "PHP" appear in their name, without prior written permission
+ from group@php.net. You may indicate that your software works in
+ conjunction with PHP by saying "Foo for PHP" instead of calling
+ it "PHP Foo" or "phpfoo"
+
+ 5. The PHP Group may publish revised and/or new versions of the
+ license from time to time. Each version will be given a
+ distinguishing version number.
+ Once covered code has been published under a particular version
+ of the license, you may always continue to use it under the terms
+ of that version. You may also choose to use such covered code
+ under the terms of any subsequent version of the license
+ published by the PHP Group. No one other than the PHP Group has
+ the right to modify the terms applicable to covered code created
+ under this License.
+
+ 6. Redistributions of any form whatsoever must retain the following
+ acknowledgment:
+ "This product includes PHP software, freely available from
+ <http://www.php.net/software/>".
+
+THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND
+ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP
+DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+OF THE POSSIBILITY OF SUCH DAMAGE.
+
+--------------------------------------------------------------------
+
+This software consists of voluntary contributions made by many
+individuals on behalf of the PHP Group.
+
+The PHP Group can be contacted via Email at group@php.net.
+
+For more information on the PHP Group and the PHP project,
+please see <http://www.php.net>.
+
+PHP includes the Zend Engine, freely available at
+<http://www.zend.com>.
+
+---------------------------------------------------------------------
+phar_tar_octal() based on an implementation Copyright (c) 2003-2007 Tim Kientzle
+from libarchive, licensed with this license:
+
+ Copyright (c) 2003-2007 Tim Kientzle
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/ext/phar/Makefile.frag b/ext/phar/Makefile.frag
new file mode 100755
index 0000000000..d693e8dd86
--- /dev/null
+++ b/ext/phar/Makefile.frag
@@ -0,0 +1,25 @@
+
+$(srcdir)/phar_path_check.c: $(srcdir)/phar_path_check.re
+ $(RE2C) -b -o $(srcdir)/phar_path_check.c $(srcdir)/phar_path_check.re
+
+pharcmd: $(builddir)/phar.php $(builddir)/phar.phar
+
+$(builddir)/phar.php: $(srcdir)/build_precommand.php $(srcdir)/phar/*.inc $(srcdir)/phar/*.php $(SAPI_CLI_PATH)
+ if test -x "$(PHP_EXECUTABLE)"; then \
+ export PHP="$(PHP_EXECUTABLE)"; \
+ else \
+ export PHP="$(top_builddir)/$(SAPI_CLI_PATH)"; \
+ fi; \
+ $$PHP $(srcdir)/build_precommand.php > $(builddir)/phar.php
+
+$(builddir)/phar.phar: $(builddir)/phar.php $(srcdir)/phar/*.inc $(srcdir)/phar/*.php $(SAPI_CLI_PATH)
+ if test -x "$(PHP_EXECUTABLE)"; then \
+ export PHP="$(PHP_EXECUTABLE)"; \
+ export BANG="$(PHP_EXECUTABLE)"; \
+ else \
+ export PHP="$(top_builddir)/$(SAPI_CLI_PATH)"; \
+ export BANG="$(INSTALL_ROOT)$(bindir)/$(program_prefix)php$(program_suffix)$(EXEEXT)"; \
+ fi; \
+ $$PHP -d phar.readonly=0 $(srcdir)/phar.php pack -f $(builddir)/phar.phar -a pharcommand -c auto -x CVS -p 0 -s $(srcdir)/phar/phar.php -h sha1 -b "$$BANG" $(srcdir)/phar/
+ @chmod +x $(builddir)/phar.phar
+
diff --git a/ext/phar/TODO b/ext/phar/TODO
new file mode 100644
index 0000000000..db001407e2
--- /dev/null
+++ b/ext/phar/TODO
@@ -0,0 +1,114 @@
+Version 1.0.0
+
+ X make permissions in the lowest bits of flags to simplify using them [Greg]
+ X implement ini handler for phar.readonly and phar.require_hash that allows
+ enabling it on PHP_INI_ALL if it is disabled in the system, but does not
+ allow disabling it if it is enabled in the system [Greg]
+ X implement reading in metadata in manifest as <len32><metadata...> [Marcus]
+ X implement writing out of metadata to new manifest [Marcus]
+ X if SPL is disabled, enable only static methods of class Phar and disable
+ class PharFileInfo completely [Marcus]
+ X implement in-phar locking, so that a file that is opened for reading can't
+ have a handle opened for writing [Marcus/Greg]
+ X docs on file format/manifest description [Greg]
+ X docs on uses [Greg]
+ X stream context for specifying compression of a file [Marcus]
+ X stream context for specifying meta-data [Greg]
+ X Phar->begin()/Phar->commit() for specifying a new stub to the phar,
+ and deferring flush until all modifications are complete [Greg]
+ X Phar->getStub() for retrieving the stub of the phar [Marcus]
+ X add setUncompressed(), setCompressedGZ() and setCompressedBZ2() to
+ PharFileInfo class [Greg]
+ X add uncompressAllFiles(), compressAllFilesGZ() and compressAllFilesBZ2()
+ to Phar class [Greg]
+ X add PharFileInfo::setMetaData($metadata) [Marcus]
+ X add PharFileInfo::getMetaData() [Marcus]
+ X always throw exceptions from the Phar object, and E_RECOVERABLE_ERROR from
+ streams interface [Greg]
+ X Phar archive metadata Phar::setMetaData($metadata) Phar::getMetaData()
+ [Greg]
+ X support rename() in stream wrapper [Greg]
+ X update docs to reflect changes in error handling [Greg]
+ X fix 011.phpt, 029.phpt for uncaught exceptions causing bad cleanup
+ [Marcus/Greg]
+
+Version 1.1.0
+
+ X Ability to connect a phar file 'phar://whatever' to a directory. That way
+ all access to that phar archive are directed to the extracted directory.
+ This allows to have the installed files and the archive keep the same
+ includes. [Marcus]
+ X add SHA-2 (256, 512) support [Marcus]
+ X setSignatureAlgorithm() and Phar::MD5 Phar::SHA1 Phar::SHA256 Phar::SHA512
+ Phar::PGP to choose the kind of signature to use (PGP falls back to SHA1)
+ [Greg]
+
+Version 1.2.0
+
+ X add PharFileInfo::hasMetadata(), PharFileInfo::delMetadata() [Marcus]
+ X add Phar::hasMetadata(), Phar::delMetadata() [Marcus]
+ X fix Phar::CanWrite() [Marcus]
+ X add preliminary phar command (phar.php) [Marcus]
+ X add phar command (phar.phar) [Marcus]
+ X list all available compression methods using
+ Phar::getSupportedCompression() [Marcus]
+ X Remove RINIT [Marcus]
+
+Version 1.2.1
+
+ X Add Phar::getAlias() [Marcus]
+ X Add Phar::setAlias() [Greg]
+ X Make -a optional in pack subcommand of phar.phar [Marcus]
+ X Make Phar::loadPhar() and Phar::mapPhar() ignore extracted archives
+
+Version 2.0.0
+
+ X implement webPhar() rewrite as a callback that returns FALSE to deny
+ access, or a string representing a file within the archive to access. If
+ unknown, the callback should return the original request uri [Greg]
+ X rework filename detection so that alias is always checked first [Greg]
+ X make aliases containing '/' or '\' invalid [Greg]
+ X implement manual mounting of external phar archives to locations inside a
+ phar path, $phar->mount('/path/to/external.phar', 'internal/path');
+ this would traverse external.phar's manifest, and add each entry as a
+ virtual entry just like automatic mounting of internal phars [Greg]
+ X implement manual mounting of external paths to a directory inside a phar
+ path. Because the mapping would be to an external directory, write access
+ would be allowed always. This allows storing sqlite databases, cache, or
+ template files in a location external to the phar. Copy of the files
+ would need to be performed in an installation step, phar would not attempt
+ to do this for performance and security reasons. [Greg]
+ X implement opendir support for mounted paths [Greg]
+ X make convertToZip/convertToTar rename files [Steph]
+ X make convertTo*() with full file compression rename to append .gz or .bz2
+ [Steph]
+ X don't automatically add a stub to .zip or .tar files [Steph]
+ X don't allow a stub or alias to be added to a .zip/.tar that does not have
+ ".phar" in the filename (or already have stub/alias) [Steph]
+ X allow read/write on .tar/.zip files that do not contain a stub or alias [Steph/Greg]
+ X prevent manual addition of stub via $a['.phar/stub.php'] = '<?php my stub'; [Greg]
+ X investigate potential collision between SPL's DirectoryIterator flags and
+ those in phar_archive_data [Steph]
+ X compression should work for non-phar archives [Steph]
+ X implement initial support for simple zip/tar archives (PharData) [Steph]
+ X make createDefaultStub() setDefaultStub() and have it file format-specific
+ [Steph]
+ X convertTo*() should always use the default stub [Steph]
+ X ability to store empty directories [Greg]
+ X tar support [Greg]
+ X zip support [Greg]
+ X Phar::copy($from, $to); [Greg]
+ X Phar::delete($what) [Greg]
+ X Phar::buildFromIterator(Iterator $it[, string $base_directory]) [Greg]
+ X Layout: Option to compress all content rather than single files. (tar/phar
+ only) [Greg]
+ X clean crap paths like phar://blah.phar/file//../to\\here.php [Greg]
+
+Version 2.1.0
+ * implement write support for mounted files even if phar.readonly=1
+ * implement automatic "mounting" of internal phar archives so that
+ phar:///path/to/archive.phar/internal.phar/file opens internal.phar and
+ maps its manifest inside archive.phar. The manifest entry inside
+ archive.phar would be named "internal.phar/file". Write access to internal
+ files inside an internal phar would be denied, as the entire archive must
+ be added or removed at the same time.
diff --git a/ext/phar/cgidebug b/ext/phar/cgidebug
new file mode 100755
index 0000000000..bacf6910a6
--- /dev/null
+++ b/ext/phar/cgidebug
@@ -0,0 +1,11 @@
+#!/bin/sh
+export SCRIPT_NAME=/frontcontroller34.php
+export PATH_INFO=/start/index.php
+export SCRIPT_FILENAME=/home/cellog/workspace/php5/ext/phar/tests/frontcontroller34.php
+export PATH_TRANSLATED=/home/cellog/workspace/php5/ext/phar/tests/frontcontroller34.php
+export REDIRECT_STATUS=1
+export REQUEST_METHOD=GET
+export REQUEST_URI=/frontcontroller34.php/start/index.php
+cd /home/cellog/workspace/php5/
+ddd sapi/cgi/php-cgi &
+cd /home/cellog/workspace/php5/ext/phar
diff --git a/ext/phar/config.m4 b/ext/phar/config.m4
new file mode 100644
index 0000000000..d3e4d5a54f
--- /dev/null
+++ b/ext/phar/config.m4
@@ -0,0 +1,15 @@
+dnl $Id$
+dnl config.m4 for extension phar
+
+PHP_ARG_ENABLE(phar, for phar archive support,
+[ --enable-phar Enable phar support])
+
+if test "$PHP_PHAR" != "no"; then
+ PHP_NEW_EXTENSION(phar, util.c tar.c zip.c stream.c func_interceptors.c dirstream.c phar.c phar_object.c phar_path_check.c, $ext_shared)
+ PHP_ADD_BUILD_DIR($ext_builddir/lib, 1)
+ PHP_SUBST(PHAR_SHARED_LIBADD)
+ PHP_ADD_EXTENSION_DEP(phar, zlib, true)
+ PHP_ADD_EXTENSION_DEP(phar, bz2, true)
+ PHP_ADD_EXTENSION_DEP(phar, spl, true)
+ PHP_ADD_MAKEFILE_FRAGMENT
+fi
diff --git a/ext/phar/config.w32 b/ext/phar/config.w32
new file mode 100644
index 0000000000..35127a7b13
--- /dev/null
+++ b/ext/phar/config.w32
@@ -0,0 +1,14 @@
+// $Id$
+// vim:ft=javascript
+
+ARG_ENABLE("phar", "enable phar support", "no");
+
+if (PHP_PHAR != "no") {
+ EXTENSION("phar", "dirstream.c func_interceptors.c phar.c phar_object.c phar_path_check.c stream.c tar.c util.c zip.c");
+ if (PHP_PHAR_SHARED) {
+ ADD_FLAG("CFLAGS_PHAR", "/D COMPILE_DL_PHAR ");
+ }
+ ADD_EXTENSION_DEP('phar', 'bz2', true);
+ ADD_EXTENSION_DEP('phar', 'spl', true);
+ ADD_EXTENSION_DEP('phar', 'zlib', true);
+}
diff --git a/ext/phar/dirstream.c b/ext/phar/dirstream.c
new file mode 100644
index 0000000000..11088ead5b
--- /dev/null
+++ b/ext/phar/dirstream.c
@@ -0,0 +1,587 @@
+/*
+ +----------------------------------------------------------------------+
+ | phar:// stream wrapper support |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 2005-2008 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt. |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gregory Beaver <cellog@php.net> |
+ | Marcus Boerger <helly@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#define PHAR_DIRSTREAM 1
+#include "phar_internal.h"
+#include "dirstream.h"
+
+BEGIN_EXTERN_C()
+void phar_dostat(phar_archive_data *phar, phar_entry_info *data, php_stream_statbuf *ssb,
+ zend_bool is_dir, char *alias, int alias_len TSRMLS_DC);
+END_EXTERN_C()
+
+php_stream_ops phar_dir_ops = {
+ phar_dir_write, /* write */
+ phar_dir_read, /* read */
+ phar_dir_close, /* close */
+ phar_dir_flush, /* flush */
+ "phar dir",
+ phar_dir_seek, /* seek */
+ NULL, /* cast */
+ NULL, /* stat */
+ NULL, /* set option */
+};
+
+/**
+ * Used for closedir($fp) where $fp is an opendir('phar://...') directory handle
+ */
+static int phar_dir_close(php_stream *stream, int close_handle TSRMLS_DC) /* {{{ */
+{
+ HashTable *data = (HashTable *)stream->abstract;
+
+ if (data && data->arBuckets)
+ {
+ zend_hash_destroy(data);
+ data->arBuckets = 0;
+ FREE_HASHTABLE(data);
+ stream->abstract = NULL;
+ }
+ return 0;
+}
+/* }}} */
+
+/**
+ * Used for seeking on a phar directory handle
+ */
+static int phar_dir_seek(php_stream *stream, off_t offset, int whence, off_t *newoffset TSRMLS_DC) /* {{{ */
+{
+ HashTable *data = (HashTable *)stream->abstract;
+
+ if (!data)
+ {
+ return -1;
+ }
+ if (whence == SEEK_END) {
+ whence = SEEK_SET;
+ offset = zend_hash_num_elements(data) + offset;
+ }
+ if (whence == SEEK_SET) {
+ zend_hash_internal_pointer_reset(data);
+ }
+
+ if (offset < 0) {
+ return -1;
+ } else {
+ *newoffset = 0;
+ while (*newoffset < offset && zend_hash_move_forward(data) == SUCCESS) {
+ ++(*newoffset);
+ }
+ return 0;
+ }
+}
+/* }}} */
+
+/**
+ * Used for readdir() on an opendir()ed phar directory handle
+ */
+static size_t phar_dir_read(php_stream *stream, char *buf, size_t count TSRMLS_DC) /* {{{ */
+{
+ size_t to_read;
+ HashTable *data = (HashTable *)stream->abstract;
+ char *key;
+ uint keylen;
+ ulong unused;
+
+ if (FAILURE == zend_hash_has_more_elements(data)) {
+ return 0;
+ }
+ if (HASH_KEY_NON_EXISTANT == zend_hash_get_current_key_ex(data, &key, &keylen, &unused, 0, NULL)) {
+ return 0;
+ }
+ zend_hash_move_forward(data);
+ to_read = MIN(keylen, count);
+ if (to_read == 0 || count < keylen) {
+ return 0;
+ }
+ memset(buf, 0, sizeof(php_stream_dirent));
+ memcpy(((php_stream_dirent *) buf)->d_name, key, to_read);
+ ((php_stream_dirent *) buf)->d_name[to_read + 1] = '\0';
+
+ return sizeof(php_stream_dirent);
+}
+/* }}} */
+
+/**
+ * Dummy: Used for writing to a phar directory (i.e. not used)
+ */
+static size_t phar_dir_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC) /* {{{ */
+{
+ return 0;
+}
+/* }}} */
+
+/**
+ * Dummy: Used for flushing writes to a phar directory (i.e. not used)
+ */
+static int phar_dir_flush(php_stream *stream TSRMLS_DC) /* {{{ */
+{
+ return EOF;
+}
+/* }}} */
+
+/**
+ * add an empty element with a char * key to a hash table, avoiding duplicates
+ *
+ * This is used to get a unique listing of virtual directories within a phar,
+ * for iterating over opendir()ed phar directories.
+ */
+static int phar_add_empty(HashTable *ht, char *arKey, uint nKeyLength) /* {{{ */
+{
+ void *dummy = (void *) 1;
+
+ return zend_hash_update(ht, arKey, nKeyLength, &dummy, sizeof(void *), NULL);
+}
+/* }}} */
+
+/**
+ * Used for sorting directories alphabetically
+ */
+static int phar_compare_dir_name(const void *a, const void *b TSRMLS_DC) /* {{{ */
+{
+ Bucket *f;
+ Bucket *s;
+ int result;
+
+ f = *((Bucket **) a);
+ s = *((Bucket **) b);
+
+#if (PHP_MAJOR_VERSION < 6)
+ result = zend_binary_strcmp(f->arKey, f->nKeyLength, s->arKey, s->nKeyLength);
+#else
+ result = zend_binary_strcmp(f->key.arKey.s, f->nKeyLength, s->key.arKey.s, s->nKeyLength);
+#endif
+
+ if (result < 0) {
+ return -1;
+ } else if (result > 0) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+/* }}} */
+
+/**
+ * Create a opendir() directory stream handle by iterating over each of the
+ * files in a phar and retrieving its relative path. From this, construct
+ * a list of files/directories that are "in" the directory represented by dir
+ */
+static php_stream *phar_make_dirstream(char *dir, HashTable *manifest TSRMLS_DC) /* {{{ */
+{
+ HashTable *data;
+ int dirlen = strlen(dir);
+ char *save, *found, *key;
+ uint keylen;
+ ulong unused;
+ char *entry;
+ ALLOC_HASHTABLE(data);
+ zend_hash_init(data, 64, zend_get_hash_value, NULL, 0);
+
+ if (*dir == '/' && dirlen == 1 && (manifest->nNumOfElements == 0)) {
+ /* make empty root directory for empty phar */
+ efree(dir);
+ return php_stream_alloc(&phar_dir_ops, data, NULL, "r");
+ }
+ zend_hash_internal_pointer_reset(manifest);
+ while (FAILURE != zend_hash_has_more_elements(manifest)) {
+ if (HASH_KEY_NON_EXISTANT == zend_hash_get_current_key_ex(manifest, &key, &keylen, &unused, 0, NULL)) {
+ break;
+ }
+ if (keylen <= (uint)dirlen) {
+ if (keylen < (uint)dirlen || !strncmp(key, dir, dirlen)) {
+ if (SUCCESS != zend_hash_move_forward(manifest)) {
+ break;
+ }
+ continue;
+ }
+ }
+ if (*dir == '/') {
+ /* root directory */
+ if (NULL != (found = (char *) memchr(key, '/', keylen))) {
+ /* the entry has a path separator and is a subdirectory */
+ entry = (char *) safe_emalloc(found - key, 1, 1);
+ memcpy(entry, key, found - key);
+ keylen = found - key;
+ entry[keylen] = '\0';
+ } else {
+ entry = (char *) safe_emalloc(keylen, 1, 1);
+ memcpy(entry, key, keylen);
+ entry[keylen] = '\0';
+ }
+ goto PHAR_ADD_ENTRY;
+ } else {
+ if (0 != memcmp(key, dir, dirlen)) {
+ /* entry in directory not found */
+ if (SUCCESS != zend_hash_move_forward(manifest)) {
+ break;
+ }
+ continue;
+ } else {
+ if (key[dirlen] != '/') {
+ if (SUCCESS != zend_hash_move_forward(manifest)) {
+ break;
+ }
+ continue;
+ }
+ }
+ }
+ save = key;
+ save += dirlen + 1; /* seek to just past the path separator */
+ if (NULL != (found = (char *) memchr(save, '/', keylen - dirlen - 1))) {
+ /* is subdirectory */
+ save -= dirlen + 1;
+ entry = (char *) safe_emalloc(found - save + dirlen, 1, 1);
+ memcpy(entry, save + dirlen + 1, found - save - dirlen - 1);
+ keylen = found - save - dirlen - 1;
+ entry[keylen] = '\0';
+ } else {
+ /* is file */
+ save -= dirlen + 1;
+ entry = (char *) safe_emalloc(keylen - dirlen, 1, 1);
+ memcpy(entry, save + dirlen + 1, keylen - dirlen - 1);
+ entry[keylen - dirlen - 1] = '\0';
+ keylen = keylen - dirlen - 1;
+ }
+PHAR_ADD_ENTRY:
+ if (keylen) {
+ phar_add_empty(data, entry, keylen);
+ }
+ efree(entry);
+ if (SUCCESS != zend_hash_move_forward(manifest)) {
+ break;
+ }
+ }
+ if (FAILURE != zend_hash_has_more_elements(data)) {
+ efree(dir);
+ if (zend_hash_sort(data, zend_qsort, phar_compare_dir_name, 0 TSRMLS_CC) == FAILURE) {
+ FREE_HASHTABLE(data);
+ return NULL;
+ }
+ return php_stream_alloc(&phar_dir_ops, data, NULL, "r");
+ } else {
+ efree(dir);
+ return php_stream_alloc(&phar_dir_ops, data, NULL, "r");
+ }
+}
+/* }}}*/
+
+/**
+ * Open a directory handle within a phar archive
+ */
+php_stream *phar_wrapper_open_dir(php_stream_wrapper *wrapper, char *path, char *mode,
+ int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC) /* {{{ */
+{
+ php_url *resource = NULL;
+ php_stream *ret;
+ char *internal_file, *key, *error;
+ uint keylen;
+ ulong unused;
+ phar_archive_data *phar;
+ phar_entry_info *entry = NULL;
+ uint host_len;
+
+ if ((resource = phar_open_url(wrapper, path, mode, options TSRMLS_CC)) == NULL) {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar url \"%s\" is unknown", path);
+ return NULL;
+ }
+
+ /* we must have at the very least phar://alias.phar/ */
+ if (!resource->scheme || !resource->host || !resource->path) {
+ if (resource->host && !resource->path) {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: no directory in \"%s\", must have at least phar://%s/ for root directory (always use full path to a new phar)", path, resource->host);
+ php_url_free(resource);
+ return NULL;
+ }
+ php_url_free(resource);
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: invalid url \"%s\", must have at least phar://%s/", path, path);
+ return NULL;
+ }
+
+ if (strcasecmp("phar", resource->scheme)) {
+ php_url_free(resource);
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: not a phar url \"%s\"", path);
+ return NULL;
+ }
+
+ host_len = strlen(resource->host);
+ phar_request_initialize(TSRMLS_C);
+
+ internal_file = resource->path + 1; /* strip leading "/" */
+ if (FAILURE == phar_get_archive(&phar, resource->host, host_len, NULL, 0, &error TSRMLS_CC)) {
+ if (error) {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, error);
+ efree(error);
+ } else {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar file \"%s\" is unknown", resource->host);
+ }
+ php_url_free(resource);
+ return NULL;
+ }
+ if (error) {
+ efree(error);
+ }
+ if (*internal_file == '\0') {
+ /* root directory requested */
+ internal_file = estrndup(internal_file - 1, 1);
+ ret = phar_make_dirstream(internal_file, &phar->manifest TSRMLS_CC);
+ php_url_free(resource);
+ return ret;
+ }
+ if (!phar->manifest.arBuckets) {
+ php_url_free(resource);
+ return NULL;
+ }
+ if (SUCCESS == zend_hash_find(&phar->manifest, internal_file, strlen(internal_file), (void**)&entry) && !entry->is_dir) {
+ php_url_free(resource);
+ return NULL;
+ } else if (entry && entry->is_dir) {
+ if (entry->is_mounted) {
+ php_url_free(resource);
+ return php_stream_opendir(entry->tmp, options, context);
+ }
+ internal_file = estrdup(internal_file);
+ php_url_free(resource);
+ return phar_make_dirstream(internal_file, &phar->manifest TSRMLS_CC);
+ } else {
+ int i_len = strlen(internal_file);
+
+ /* search for directory */
+ zend_hash_internal_pointer_reset(&phar->manifest);
+ while (FAILURE != zend_hash_has_more_elements(&phar->manifest)) {
+ if (HASH_KEY_NON_EXISTANT !=
+ zend_hash_get_current_key_ex(
+ &phar->manifest, &key, &keylen, &unused, 0, NULL)) {
+ if (keylen > (uint)i_len && 0 == memcmp(key, internal_file, i_len)) {
+ /* directory found */
+ internal_file = estrndup(internal_file,
+ i_len);
+ php_url_free(resource);
+ return phar_make_dirstream(internal_file, &phar->manifest TSRMLS_CC);
+ }
+ }
+ if (SUCCESS != zend_hash_move_forward(&phar->manifest)) {
+ break;
+ }
+ }
+ }
+
+ php_url_free(resource);
+ return NULL;
+}
+/* }}} */
+
+/**
+ * Make a new directory within a phar archive
+ */
+int phar_wrapper_mkdir(php_stream_wrapper *wrapper, char *url_from, int mode, int options, php_stream_context *context TSRMLS_DC) /* {{{ */
+{
+ phar_entry_info entry, *e;
+ phar_archive_data *phar = NULL;
+ char *error, *arch, *entry2;
+ int arch_len, entry_len;
+ php_url *resource = NULL;
+ uint host_len;
+
+ /* pre-readonly check, we need to know if this is a data phar */
+ if (FAILURE == phar_split_fname(url_from, strlen(url_from), &arch, &arch_len, &entry2, &entry_len, 2, 2 TSRMLS_CC)) {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\", no phar archive specified", url_from);
+ return FAILURE;
+ }
+ if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL TSRMLS_CC)) {
+ phar = NULL;
+ }
+ efree(arch);
+ efree(entry2);
+ if (PHAR_G(readonly) && (!phar || !phar->is_data)) {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\", write operations disabled", url_from);
+ return FAILURE;
+ }
+
+ if ((resource = phar_open_url(wrapper, url_from, "w", options TSRMLS_CC)) == NULL) {
+ return FAILURE;
+ }
+
+ /* we must have at the very least phar://alias.phar/internalfile.php */
+ if (!resource->scheme || !resource->host || !resource->path) {
+ php_url_free(resource);
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: invalid url \"%s\"", url_from);
+ return FAILURE;
+ }
+
+ if (strcasecmp("phar", resource->scheme)) {
+ php_url_free(resource);
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: not a phar stream url \"%s\"", url_from);
+ return FAILURE;
+ }
+
+ host_len = strlen(resource->host);
+ phar_request_initialize(TSRMLS_C);
+
+ if (FAILURE == phar_get_archive(&phar, resource->host, host_len, NULL, 0, &error TSRMLS_CC)) {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\" in phar \"%s\", error retrieving phar information: %s", resource->path+1, resource->host, error);
+ efree(error);
+ php_url_free(resource);
+ return FAILURE;
+ }
+
+ if ((e = phar_get_entry_info_dir(phar, resource->path + 1, strlen(resource->path + 1), 2, &error TSRMLS_CC))) {
+ /* directory exists, or is a subdirectory of an existing file */
+ if (e->is_temp_dir) {
+ efree(e->filename);
+ efree(e);
+ }
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\" in phar \"%s\", directory already exists", resource->path+1, resource->host);
+ php_url_free(resource);
+ return FAILURE;
+ }
+ if (error) {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\" in phar \"%s\", %s", resource->path+1, resource->host, error);
+ efree(error);
+ php_url_free(resource);
+ return FAILURE;
+ }
+ if ((e = phar_get_entry_info_dir(phar, resource->path + 1, strlen(resource->path + 1), 0, &error TSRMLS_CC))) {
+ /* entry exists as a file */
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\" in phar \"%s\", file already exists", resource->path+1, resource->host);
+ php_url_free(resource);
+ return FAILURE;
+ }
+ if (error) {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\" in phar \"%s\", %s", resource->path+1, resource->host, error);
+ efree(error);
+ php_url_free(resource);
+ return FAILURE;
+ }
+
+ memset((void *) &entry, 0, sizeof(phar_entry_info));
+
+ /* strip leading "/" */
+ if (phar->is_zip) {
+ entry.is_zip = 1;
+ }
+ entry.filename = estrdup(resource->path + 1);
+ if (phar->is_tar) {
+ entry.is_tar = 1;
+ entry.tar_type = TAR_DIR;
+ }
+ entry.filename_len = strlen(resource->path + 1);
+ php_url_free(resource);
+ entry.is_dir = 1;
+ entry.phar = phar;
+ entry.is_modified = 1;
+ entry.is_crc_checked = 1;
+ entry.flags = PHAR_ENT_PERM_DEF_DIR;
+ entry.old_flags = PHAR_ENT_PERM_DEF_DIR;
+ if (SUCCESS != zend_hash_add(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL)) {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\" in phar \"%s\", adding to manifest failed", entry.filename, phar->fname);
+ efree(error);
+ efree(entry.filename);
+ return FAILURE;
+ }
+ phar_flush(phar, 0, 0, 0, &error TSRMLS_CC);
+ if (error) {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\" in phar \"%s\", %s", entry.filename, phar->fname, error);
+ zend_hash_del(&phar->manifest, entry.filename, entry.filename_len);
+ efree(error);
+ return FAILURE;
+ }
+ return SUCCESS;
+}
+/* }}} */
+
+/**
+ * Remove a directory within a phar archive
+ */
+int phar_wrapper_rmdir(php_stream_wrapper *wrapper, char *url, int options, php_stream_context *context TSRMLS_DC) /* {{{ */
+{
+ phar_entry_info *entry;
+ phar_archive_data *phar = NULL;
+ char *error, *arch, *entry2;
+ int arch_len, entry_len;
+ php_url *resource = NULL;
+ uint host_len;
+
+ /* pre-readonly check, we need to know if this is a data phar */
+ if (FAILURE == phar_split_fname(url, strlen(url), &arch, &arch_len, &entry2, &entry_len, 2, 2 TSRMLS_CC)) {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot remove directory \"%s\", no phar archive specified, or phar archive does not exist", url);
+ return FAILURE;
+ }
+ if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL TSRMLS_CC)) {
+ phar = NULL;
+ }
+ efree(arch);
+ efree(entry2);
+ if (PHAR_G(readonly) && (!phar || !phar->is_data)) {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot rmdir directory \"%s\", write operations disabled", url);
+ return FAILURE;
+ }
+
+ if ((resource = phar_open_url(wrapper, url, "w", options TSRMLS_CC)) == NULL) {
+ return FAILURE;
+ }
+
+ /* we must have at the very least phar://alias.phar/internalfile.php */
+ if (!resource->scheme || !resource->host || !resource->path) {
+ php_url_free(resource);
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: invalid url \"%s\"", url);
+ return FAILURE;
+ }
+
+ if (strcasecmp("phar", resource->scheme)) {
+ php_url_free(resource);
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: not a phar stream url \"%s\"", url);
+ return FAILURE;
+ }
+
+ host_len = strlen(resource->host);
+ phar_request_initialize(TSRMLS_C);
+
+ if (FAILURE == phar_get_archive(&phar, resource->host, host_len, NULL, 0, &error TSRMLS_CC)) {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot remove directory \"%s\" in phar \"%s\", error retrieving phar information: %s", resource->path+1, resource->host, error);
+ efree(error);
+ php_url_free(resource);
+ return FAILURE;
+ }
+
+ if (!(entry = phar_get_entry_info_dir(phar, resource->path + 1, strlen(resource->path) - 1, 2, &error TSRMLS_CC))) {
+ if (error) {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot remove directory \"%s\" in phar \"%s\", %s", resource->path+1, resource->host, error);
+ efree(error);
+ } else {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot remove directory \"%s\" in phar \"%s\", directory does not exist", resource->path+1, resource->host);
+ }
+ php_url_free(resource);
+ return FAILURE;
+ }
+
+ /* now for the easy part */
+ entry->is_deleted = 1;
+ entry->is_modified = 1;
+ phar_flush(phar, 0, 0, 0, &error TSRMLS_CC);
+ if (error) {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\" in phar \"%s\", %s", entry->filename, phar->fname, error);
+ zend_hash_del(&phar->manifest, entry->filename, entry->filename_len);
+ php_url_free(resource);
+ efree(error);
+ return FAILURE;
+ }
+ php_url_free(resource);
+ return SUCCESS;
+}
+/* }}} */
diff --git a/ext/phar/dirstream.h b/ext/phar/dirstream.h
new file mode 100644
index 0000000000..e7d0b40b58
--- /dev/null
+++ b/ext/phar/dirstream.h
@@ -0,0 +1,47 @@
+/*
+ +----------------------------------------------------------------------+
+ | phar php single-file executable PHP extension |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 2006-2007 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt. |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gregory Beaver <cellog@php.net> |
+ | Marcus Boerger <helly@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+BEGIN_EXTERN_C()
+int phar_wrapper_mkdir(php_stream_wrapper *wrapper, char *url_from, int mode, int options, php_stream_context *context TSRMLS_DC);
+int phar_wrapper_rmdir(php_stream_wrapper *wrapper, char *url, int options, php_stream_context *context TSRMLS_DC);
+
+#ifdef PHAR_DIRSTREAM
+php_url* phar_open_url(php_stream_wrapper *wrapper, char *filename, char *mode, int options TSRMLS_DC);
+
+/* directory handlers */
+static size_t phar_dir_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC);
+static size_t phar_dir_read( php_stream *stream, char *buf, size_t count TSRMLS_DC);
+static int phar_dir_close(php_stream *stream, int close_handle TSRMLS_DC);
+static int phar_dir_flush(php_stream *stream TSRMLS_DC);
+static int phar_dir_seek( php_stream *stream, off_t offset, int whence, off_t *newoffset TSRMLS_DC);
+#else
+php_stream* phar_wrapper_open_dir(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC);
+#endif
+END_EXTERN_C()
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
diff --git a/ext/phar/func_interceptors.c b/ext/phar/func_interceptors.c
new file mode 100644
index 0000000000..b92d61a422
--- /dev/null
+++ b/ext/phar/func_interceptors.c
@@ -0,0 +1,1081 @@
+/*
+ +----------------------------------------------------------------------+
+ | phar php single-file executable PHP extension |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 2005-2008 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt. |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gregory Beaver <cellog@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#include "phar_internal.h"
+
+#define PHAR_FUNC(name) \
+ static PHP_NAMED_FUNCTION(name)
+
+PHAR_FUNC(phar_opendir) /* {{{ */
+{
+ char *filename;
+ int filename_len;
+ zval *zcontext = NULL;
+
+ if (!zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map))) {
+ goto skip_phar;
+ }
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z", &filename, &filename_len, &zcontext) == FAILURE) {
+ return;
+ }
+
+ if (!IS_ABSOLUTE_PATH(filename, filename_len) && !strstr(filename, "://")) {
+ char *arch, *entry, *fname;
+ int arch_len, entry_len, fname_len;
+ fname = zend_get_executed_filename(TSRMLS_C);
+
+ /* we are checking for existence of a file within the relative path. Chances are good that this is
+ retrieving something from within the phar archive */
+
+ if (strncasecmp(fname, "phar://", 7)) {
+ goto skip_phar;
+ }
+ fname_len = strlen(fname);
+ if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
+ php_stream_context *context = NULL;
+ php_stream *stream;
+ char *name;
+
+ efree(entry);
+ entry = estrndup(filename, filename_len);
+ /* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
+ entry_len = filename_len;
+ /* retrieving a file within the current directory, so use this if possible */
+ entry = phar_fix_filepath(entry, &entry_len, 1 TSRMLS_CC);
+
+ if (entry[0] == '/') {
+ spprintf(&name, 4096, "phar://%s%s", arch, entry);
+ } else {
+ spprintf(&name, 4096, "phar://%s/%s", arch, entry);
+ }
+ efree(entry);
+ efree(arch);
+ if (zcontext) {
+ context = php_stream_context_from_zval(zcontext, 0);
+ }
+ stream = php_stream_opendir(name, REPORT_ERRORS, context);
+ efree(name);
+ if (!stream) {
+ RETURN_FALSE;
+ }
+ php_stream_to_zval(stream, return_value);
+ return;
+ }
+ }
+skip_phar:
+ PHAR_G(orig_opendir)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
+ return;
+}
+/* }}} */
+
+PHAR_FUNC(phar_file_get_contents) /* {{{ */
+{
+ char *filename;
+ int filename_len;
+ char *contents;
+ zend_bool use_include_path = 0;
+ php_stream *stream;
+ int len, newlen;
+ long offset = -1;
+ long maxlen = PHP_STREAM_COPY_ALL;
+ zval *zcontext = NULL;
+
+ if (!zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map))) {
+ goto skip_phar;
+ }
+ /* Parse arguments */
+ if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "s|br!ll", &filename, &filename_len, &use_include_path, &zcontext, &offset, &maxlen) == FAILURE) {
+ return;
+ }
+ if (use_include_path || (!IS_ABSOLUTE_PATH(filename, filename_len) && !strstr(filename, "://"))) {
+ char *arch, *entry, *fname;
+ int arch_len, entry_len, fname_len;
+ php_stream_context *context = NULL;
+
+ fname = zend_get_executed_filename(TSRMLS_C);
+
+ if (strncasecmp(fname, "phar://", 7)) {
+ goto skip_phar;
+ }
+ fname_len = strlen(fname);
+ if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
+ char *name;
+ phar_archive_data **pphar;
+
+ efree(entry);
+ entry = filename;
+ /* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
+ entry_len = filename_len;
+
+ if (ZEND_NUM_ARGS() == 5 && maxlen < 0) {
+ efree(arch);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "length must be greater than or equal to zero");
+ RETURN_FALSE;
+ }
+
+ /* retrieving a file defaults to within the current directory, so use this if possible */
+ if (FAILURE == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar))) {
+ efree(arch);
+ goto skip_phar;
+ }
+ if (use_include_path) {
+ if ((entry = phar_find_in_include_path(entry, entry_len, NULL TSRMLS_CC))) {
+ name = entry;
+ goto phar_it;
+ } else {
+ /* this file is not in the phar, use the original path */
+ efree(arch);
+ goto skip_phar;
+ }
+ } else {
+ entry = phar_fix_filepath(estrndup(entry, entry_len), &entry_len, 1 TSRMLS_CC);
+ if (entry[0] == '/') {
+ if (!zend_hash_exists(&((*pphar)->manifest), entry + 1, entry_len - 1)) {
+ /* this file is not in the phar, use the original path */
+notfound:
+ efree(arch);
+ efree(entry);
+ goto skip_phar;
+ }
+ } else {
+ if (!zend_hash_exists(&((*pphar)->manifest), entry, entry_len)) {
+ goto notfound;
+ }
+ }
+ /* auto-convert to phar:// */
+ if (entry[0] == '/') {
+ spprintf(&name, 4096, "phar://%s%s", arch, entry);
+ } else {
+ spprintf(&name, 4096, "phar://%s/%s", arch, entry);
+ }
+ if (entry != filename) {
+ efree(entry);
+ }
+ }
+
+phar_it:
+ efree(arch);
+ if (zcontext) {
+ context = php_stream_context_from_zval(zcontext, 0);
+ }
+ stream = php_stream_open_wrapper_ex(name, "rb", 0 | REPORT_ERRORS, NULL, context);
+ efree(name);
+
+ if (!stream) {
+ RETURN_FALSE;
+ }
+
+ if (offset > 0 && php_stream_seek(stream, offset, SEEK_SET) < 0) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to seek to position %ld in the stream", offset);
+ php_stream_close(stream);
+ RETURN_FALSE;
+ }
+
+ /* uses mmap if possible */
+ if ((len = php_stream_copy_to_mem(stream, &contents, maxlen, 0)) > 0) {
+#if PHP_MAJOR_VERSION < 6
+ if (PG(magic_quotes_runtime)) {
+ contents = php_addslashes(contents, len, &newlen, 1 TSRMLS_CC); /* 1 = free source string */
+ len = newlen;
+ }
+#endif
+ RETVAL_STRINGL(contents, len, 0);
+ } else if (len == 0) {
+ RETVAL_EMPTY_STRING();
+ } else {
+ RETVAL_FALSE;
+ }
+
+ php_stream_close(stream);
+ return;
+ }
+ }
+skip_phar:
+ PHAR_G(orig_file_get_contents)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
+ return;
+}
+/* }}} */
+
+PHAR_FUNC(phar_readfile) /* {{{ */
+{
+ char *filename;
+ int filename_len;
+ int size = 0;
+ zend_bool use_include_path = 0;
+ zval *zcontext = NULL;
+ php_stream *stream;
+
+ if (!zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map))) {
+ goto skip_phar;
+ }
+ if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "s|br!", &filename, &filename_len, &use_include_path, &zcontext) == FAILURE) {
+ goto skip_phar;
+ }
+ if (use_include_path || (!IS_ABSOLUTE_PATH(filename, filename_len) && !strstr(filename, "://"))) {
+ char *arch, *entry, *fname;
+ int arch_len, entry_len, fname_len;
+ php_stream_context *context = NULL;
+ char *name;
+ phar_archive_data **pphar;
+ fname = zend_get_executed_filename(TSRMLS_C);
+
+ if (strncasecmp(fname, "phar://", 7)) {
+ goto skip_phar;
+ }
+ fname_len = strlen(fname);
+ if (FAILURE == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
+ goto skip_phar;
+ }
+
+ efree(entry);
+ entry = filename;
+ /* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
+ entry_len = filename_len;
+ /* retrieving a file defaults to within the current directory, so use this if possible */
+ if (FAILURE == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar))) {
+ efree(arch);
+ goto skip_phar;
+ }
+ if (use_include_path) {
+ if (!(entry = phar_find_in_include_path(entry, entry_len, NULL TSRMLS_CC))) {
+ /* this file is not in the phar, use the original path */
+ efree(arch);
+ goto skip_phar;
+ } else {
+ name = entry;
+ }
+ } else {
+ entry = phar_fix_filepath(estrndup(entry, entry_len), &entry_len, 1 TSRMLS_CC);
+ if (entry[0] == '/') {
+ if (!zend_hash_exists(&((*pphar)->manifest), entry + 1, entry_len - 1)) {
+ /* this file is not in the phar, use the original path */
+notfound:
+ efree(entry);
+ efree(arch);
+ goto skip_phar;
+ }
+ } else {
+ if (!zend_hash_exists(&((*pphar)->manifest), entry, entry_len)) {
+ goto notfound;
+ }
+ }
+ /* auto-convert to phar:// */
+ if (entry[0] == '/') {
+ spprintf(&name, 4096, "phar://%s%s", arch, entry);
+ } else {
+ spprintf(&name, 4096, "phar://%s/%s", arch, entry);
+ }
+ efree(entry);
+ }
+
+ efree(arch);
+ context = php_stream_context_from_zval(zcontext, 0);
+ stream = php_stream_open_wrapper_ex(name, "rb", 0 | REPORT_ERRORS, NULL, context);
+ efree(name);
+ if (stream == NULL) {
+ RETURN_FALSE;
+ }
+ size = php_stream_passthru(stream);
+ php_stream_close(stream);
+ RETURN_LONG(size);
+ }
+
+skip_phar:
+ PHAR_G(orig_readfile)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
+ return;
+
+}
+/* }}} */
+
+PHAR_FUNC(phar_fopen) /* {{{ */
+{
+ char *filename, *mode;
+ int filename_len, mode_len;
+ zend_bool use_include_path = 0;
+ zval *zcontext = NULL;
+ php_stream *stream;
+
+ if (!zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map))) {
+ /* no need to check, include_path not even specified in fopen/ no active phars */
+ goto skip_phar;
+ }
+ if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "ss|br", &filename, &filename_len, &mode, &mode_len, &use_include_path, &zcontext) == FAILURE) {
+ goto skip_phar;
+ }
+ if (use_include_path || (!IS_ABSOLUTE_PATH(filename, filename_len) && !strstr(filename, "://"))) {
+ char *arch, *entry, *fname;
+ int arch_len, entry_len, fname_len;
+ php_stream_context *context = NULL;
+ char *name;
+ phar_archive_data **pphar;
+ fname = zend_get_executed_filename(TSRMLS_C);
+
+ if (strncasecmp(fname, "phar://", 7)) {
+ goto skip_phar;
+ }
+ fname_len = strlen(fname);
+ if (FAILURE == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
+ goto skip_phar;
+ }
+
+ efree(entry);
+ entry = filename;
+ /* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
+ entry_len = filename_len;
+ /* retrieving a file defaults to within the current directory, so use this if possible */
+ if (FAILURE == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar))) {
+ efree(arch);
+ goto skip_phar;
+ }
+ if (use_include_path) {
+ if (!(entry = phar_find_in_include_path(entry, entry_len, NULL TSRMLS_CC))) {
+ /* this file is not in the phar, use the original path */
+ efree(arch);
+ goto skip_phar;
+ } else {
+ name = entry;
+ }
+ } else {
+ entry = phar_fix_filepath(estrndup(entry, entry_len), &entry_len, 1 TSRMLS_CC);
+ if (entry[0] == '/') {
+ if (!zend_hash_exists(&((*pphar)->manifest), entry + 1, entry_len - 1)) {
+ /* this file is not in the phar, use the original path */
+notfound:
+ efree(entry);
+ efree(arch);
+ goto skip_phar;
+ }
+ } else {
+ if (!zend_hash_exists(&((*pphar)->manifest), entry, entry_len)) {
+ /* this file is not in the phar, use the original path */
+ goto notfound;
+ }
+ }
+ /* auto-convert to phar:// */
+ if (entry[0] == '/') {
+ spprintf(&name, 4096, "phar://%s%s", arch, entry);
+ } else {
+ spprintf(&name, 4096, "phar://%s/%s", arch, entry);
+ }
+ efree(entry);
+ }
+
+ efree(arch);
+ context = php_stream_context_from_zval(zcontext, 0);
+ stream = php_stream_open_wrapper_ex(name, mode, 0 | REPORT_ERRORS, NULL, context);
+ efree(name);
+ if (stream == NULL) {
+ RETURN_FALSE;
+ }
+ php_stream_to_zval(stream, return_value);
+ if (zcontext) {
+ zend_list_addref(Z_RESVAL_P(zcontext));
+ }
+ return;
+ }
+skip_phar:
+ PHAR_G(orig_fopen)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
+ return;
+}
+/* }}} */
+
+#ifndef S_ISDIR
+#define S_ISDIR(mode) (((mode)&S_IFMT) == S_IFDIR)
+#endif
+#ifndef S_ISREG
+#define S_ISREG(mode) (((mode)&S_IFMT) == S_IFREG)
+#endif
+#ifndef S_ISLNK
+#define S_ISLNK(mode) (((mode)&S_IFMT) == S_IFLNK)
+#endif
+
+#define S_IXROOT ( S_IXUSR | S_IXGRP | S_IXOTH )
+
+#define IS_LINK_OPERATION(__t) ((__t) == FS_TYPE || (__t) == FS_IS_LINK || (__t) == FS_LSTAT)
+#define IS_EXISTS_CHECK(__t) ((__t) == FS_EXISTS || (__t) == FS_IS_W || (__t) == FS_IS_R || (__t) == FS_IS_X || (__t) == FS_IS_FILE || (__t) == FS_IS_DIR || (__t) == FS_IS_LINK)
+#define IS_ABLE_CHECK(__t) ((__t) == FS_IS_R || (__t) == FS_IS_W || (__t) == FS_IS_X)
+#define IS_ACCESS_CHECK(__t) (IS_ABLE_CHECK(type) || (__t) == FS_EXISTS)
+
+/* {{{ php_stat
+ */
+void phar_fancy_stat(struct stat *stat_sb, int type, zval *return_value TSRMLS_DC)
+{
+ zval *stat_dev, *stat_ino, *stat_mode, *stat_nlink, *stat_uid, *stat_gid, *stat_rdev,
+ *stat_size, *stat_atime, *stat_mtime, *stat_ctime, *stat_blksize, *stat_blocks;
+ int rmask=S_IROTH, wmask=S_IWOTH, xmask=S_IXOTH; /* access rights defaults to other */
+ char *stat_sb_names[13] = {
+ "dev", "ino", "mode", "nlink", "uid", "gid", "rdev",
+ "size", "atime", "mtime", "ctime", "blksize", "blocks"
+ };
+
+#ifndef NETWARE
+ if (type >= FS_IS_W && type <= FS_IS_X) {
+ if(stat_sb->st_uid==getuid()) {
+ rmask=S_IRUSR;
+ wmask=S_IWUSR;
+ xmask=S_IXUSR;
+ } else if(stat_sb->st_gid==getgid()) {
+ rmask=S_IRGRP;
+ wmask=S_IWGRP;
+ xmask=S_IXGRP;
+ } else {
+ int groups, n, i;
+ gid_t *gids;
+
+ groups = getgroups(0, NULL);
+ if(groups > 0) {
+ gids=(gid_t *)safe_emalloc(groups, sizeof(gid_t), 0);
+ n=getgroups(groups, gids);
+ for(i=0;i<n;++i){
+ if(stat_sb->st_gid==gids[i]) {
+ rmask=S_IRGRP;
+ wmask=S_IWGRP;
+ xmask=S_IXGRP;
+ break;
+ }
+ }
+ efree(gids);
+ }
+ }
+ }
+#endif
+
+ switch (type) {
+ case FS_PERMS:
+ RETURN_LONG((long)stat_sb->st_mode);
+ case FS_INODE:
+ RETURN_LONG((long)stat_sb->st_ino);
+ case FS_SIZE:
+ RETURN_LONG((long)stat_sb->st_size);
+ case FS_OWNER:
+ RETURN_LONG((long)stat_sb->st_uid);
+ case FS_GROUP:
+ RETURN_LONG((long)stat_sb->st_gid);
+ case FS_ATIME:
+#ifdef NETWARE
+ RETURN_LONG((long)stat_sb->st_atime.tv_sec);
+#else
+ RETURN_LONG((long)stat_sb->st_atime);
+#endif
+ case FS_MTIME:
+#ifdef NETWARE
+ RETURN_LONG((long)stat_sb->st_mtime.tv_sec);
+#else
+ RETURN_LONG((long)stat_sb->st_mtime);
+#endif
+ case FS_CTIME:
+#ifdef NETWARE
+ RETURN_LONG((long)stat_sb->st_ctime.tv_sec);
+#else
+ RETURN_LONG((long)stat_sb->st_ctime);
+#endif
+ case FS_TYPE:
+ if (S_ISLNK(stat_sb->st_mode)) {
+ RETURN_STRING("link", 1);
+ }
+ switch(stat_sb->st_mode & S_IFMT) {
+ case S_IFDIR: RETURN_STRING("dir", 1);
+ case S_IFREG: RETURN_STRING("file", 1);
+ }
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Unknown file type (%d)", stat_sb->st_mode&S_IFMT);
+ RETURN_STRING("unknown", 1);
+ case FS_IS_W:
+ RETURN_BOOL((stat_sb->st_mode & wmask) != 0);
+ case FS_IS_R:
+ RETURN_BOOL((stat_sb->st_mode&rmask)!=0);
+ case FS_IS_X:
+ RETURN_BOOL((stat_sb->st_mode&xmask)!=0 && !S_ISDIR(stat_sb->st_mode));
+ case FS_IS_FILE:
+ RETURN_BOOL(S_ISREG(stat_sb->st_mode));
+ case FS_IS_DIR:
+ RETURN_BOOL(S_ISDIR(stat_sb->st_mode));
+ case FS_IS_LINK:
+ RETURN_BOOL(S_ISLNK(stat_sb->st_mode));
+ case FS_EXISTS:
+ RETURN_TRUE; /* the false case was done earlier */
+ case FS_LSTAT:
+ /* FALLTHROUGH */
+ case FS_STAT:
+ array_init(return_value);
+
+ MAKE_LONG_ZVAL_INCREF(stat_dev, stat_sb->st_dev);
+ MAKE_LONG_ZVAL_INCREF(stat_ino, stat_sb->st_ino);
+ MAKE_LONG_ZVAL_INCREF(stat_mode, stat_sb->st_mode);
+ MAKE_LONG_ZVAL_INCREF(stat_nlink, stat_sb->st_nlink);
+ MAKE_LONG_ZVAL_INCREF(stat_uid, stat_sb->st_uid);
+ MAKE_LONG_ZVAL_INCREF(stat_gid, stat_sb->st_gid);
+#ifdef HAVE_ST_RDEV
+ MAKE_LONG_ZVAL_INCREF(stat_rdev, stat_sb->st_rdev);
+#else
+ MAKE_LONG_ZVAL_INCREF(stat_rdev, -1);
+#endif
+ MAKE_LONG_ZVAL_INCREF(stat_size, stat_sb->st_size);
+#ifdef NETWARE
+ MAKE_LONG_ZVAL_INCREF(stat_atime, (stat_sb->st_atime).tv_sec);
+ MAKE_LONG_ZVAL_INCREF(stat_mtime, (stat_sb->st_mtime).tv_sec);
+ MAKE_LONG_ZVAL_INCREF(stat_ctime, (stat_sb->st_ctime).tv_sec);
+#else
+ MAKE_LONG_ZVAL_INCREF(stat_atime, stat_sb->st_atime);
+ MAKE_LONG_ZVAL_INCREF(stat_mtime, stat_sb->st_mtime);
+ MAKE_LONG_ZVAL_INCREF(stat_ctime, stat_sb->st_ctime);
+#endif
+#ifdef HAVE_ST_BLKSIZE
+ MAKE_LONG_ZVAL_INCREF(stat_blksize, stat_sb->st_blksize);
+#else
+ MAKE_LONG_ZVAL_INCREF(stat_blksize,-1);
+#endif
+#ifdef HAVE_ST_BLOCKS
+ MAKE_LONG_ZVAL_INCREF(stat_blocks, stat_sb->st_blocks);
+#else
+ MAKE_LONG_ZVAL_INCREF(stat_blocks,-1);
+#endif
+ /* Store numeric indexes in propper order */
+ zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_dev, sizeof(zval *), NULL);
+ zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_ino, sizeof(zval *), NULL);
+ zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_mode, sizeof(zval *), NULL);
+ zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_nlink, sizeof(zval *), NULL);
+ zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_uid, sizeof(zval *), NULL);
+ zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_gid, sizeof(zval *), NULL);
+
+ zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_rdev, sizeof(zval *), NULL);
+ zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_size, sizeof(zval *), NULL);
+ zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_atime, sizeof(zval *), NULL);
+ zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_mtime, sizeof(zval *), NULL);
+ zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_ctime, sizeof(zval *), NULL);
+ zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_blksize, sizeof(zval *), NULL);
+ zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_blocks, sizeof(zval *), NULL);
+
+ /* Store string indexes referencing the same zval*/
+ zend_hash_update(HASH_OF(return_value), stat_sb_names[0], strlen(stat_sb_names[0])+1, (void *) &stat_dev, sizeof(zval *), NULL);
+ zend_hash_update(HASH_OF(return_value), stat_sb_names[1], strlen(stat_sb_names[1])+1, (void *) &stat_ino, sizeof(zval *), NULL);
+ zend_hash_update(HASH_OF(return_value), stat_sb_names[2], strlen(stat_sb_names[2])+1, (void *) &stat_mode, sizeof(zval *), NULL);
+ zend_hash_update(HASH_OF(return_value), stat_sb_names[3], strlen(stat_sb_names[3])+1, (void *) &stat_nlink, sizeof(zval *), NULL);
+ zend_hash_update(HASH_OF(return_value), stat_sb_names[4], strlen(stat_sb_names[4])+1, (void *) &stat_uid, sizeof(zval *), NULL);
+ zend_hash_update(HASH_OF(return_value), stat_sb_names[5], strlen(stat_sb_names[5])+1, (void *) &stat_gid, sizeof(zval *), NULL);
+ zend_hash_update(HASH_OF(return_value), stat_sb_names[6], strlen(stat_sb_names[6])+1, (void *) &stat_rdev, sizeof(zval *), NULL);
+ zend_hash_update(HASH_OF(return_value), stat_sb_names[7], strlen(stat_sb_names[7])+1, (void *) &stat_size, sizeof(zval *), NULL);
+ zend_hash_update(HASH_OF(return_value), stat_sb_names[8], strlen(stat_sb_names[8])+1, (void *) &stat_atime, sizeof(zval *), NULL);
+ zend_hash_update(HASH_OF(return_value), stat_sb_names[9], strlen(stat_sb_names[9])+1, (void *) &stat_mtime, sizeof(zval *), NULL);
+ zend_hash_update(HASH_OF(return_value), stat_sb_names[10], strlen(stat_sb_names[10])+1, (void *) &stat_ctime, sizeof(zval *), NULL);
+ zend_hash_update(HASH_OF(return_value), stat_sb_names[11], strlen(stat_sb_names[11])+1, (void *) &stat_blksize, sizeof(zval *), NULL);
+ zend_hash_update(HASH_OF(return_value), stat_sb_names[12], strlen(stat_sb_names[12])+1, (void *) &stat_blocks, sizeof(zval *), NULL);
+
+ return;
+ }
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Didn't understand stat call");
+ RETURN_FALSE;
+}
+/* }}} */
+
+void phar_file_stat(const char *filename, php_stat_len filename_length, int type, void (*orig_stat_func)(INTERNAL_FUNCTION_PARAMETERS), INTERNAL_FUNCTION_PARAMETERS) /* {{{ */
+{
+ if (!filename_length) {
+ RETURN_FALSE;
+ }
+
+ if (!IS_ABSOLUTE_PATH(filename, filename_length) && !strstr(filename, "://")) {
+ char *arch, *entry, *fname;
+ int arch_len, entry_len, fname_len;
+ struct stat sb = {0};
+ phar_entry_info *data = NULL;
+ char *tmp;
+ int tmp_len;
+
+ fname = zend_get_executed_filename(TSRMLS_C);
+
+ /* we are checking for existence of a file within the relative path. Chances are good that this is
+ retrieving something from within the phar archive */
+
+ if (strncasecmp(fname, "phar://", 7)) {
+ goto skip_phar;
+ }
+ fname_len = strlen(fname);
+ if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
+ phar_archive_data **pphar;
+
+ efree(entry);
+ entry = estrndup(filename, filename_length);
+ /* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
+ entry_len = (int) filename_length;
+ if (FAILURE == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar))) {
+ efree(arch);
+ goto skip_phar;
+ }
+ entry = phar_fix_filepath(entry, &entry_len, 1 TSRMLS_CC);
+ if (entry[0] == '/') {
+ if (SUCCESS == zend_hash_find(&((*pphar)->manifest), entry + 1, entry_len - 1, (void **) &data)) {
+ efree(entry);
+ goto stat_entry;
+ }
+ goto notfound;
+ }
+ if (SUCCESS == zend_hash_find(&((*pphar)->manifest), entry, entry_len, (void **) &data)) {
+ efree(entry);
+ goto stat_entry;
+ } else {
+ char *save, *save2, *actual;
+ int save_len, save2_len, actual_len;
+
+notfound:
+ save = PHAR_G(cwd);
+ save2 = entry;
+ actual = entry[0] == '/' ? (entry + 1) : entry;
+ save_len = PHAR_G(cwd_len);
+ save2_len = entry_len;
+ actual_len = entry[0] == '/' ? (entry_len - 1) : entry_len;
+ /* this file is not in the current directory, use the original path */
+ entry = estrndup(filename, filename_length);
+ entry_len = filename_length;
+ PHAR_G(cwd) = "/";
+ PHAR_G(cwd_len) = 0;
+ /* clean path without cwd */
+ entry = phar_fix_filepath(entry, &entry_len, 1 TSRMLS_CC);
+ if (SUCCESS == zend_hash_find(&((*pphar)->manifest), entry + 1, entry_len - 1, (void **) &data)) {
+ PHAR_G(cwd) = save;
+ PHAR_G(cwd_len) = save_len;
+ efree(entry);
+ efree(save2);
+ goto stat_entry;
+ } else {
+ phar_archive_data *phar = *pphar;
+ char *key;
+ uint keylen;
+ ulong unused;
+
+ PHAR_G(cwd) = save;
+ PHAR_G(cwd_len) = save_len;
+ /* original not found either, this is possibly a directory relative to cwd */
+ zend_hash_internal_pointer_reset(&phar->manifest);
+ while (FAILURE != zend_hash_has_more_elements(&phar->manifest)) {
+ if (HASH_KEY_NON_EXISTANT !=
+ zend_hash_get_current_key_ex(
+ &phar->manifest, &key, &keylen, &unused, 0, NULL)) {
+ if (!memcmp(actual, key, actual_len)) {
+ efree(save2);
+ efree(entry);
+ /* directory found, all dirs have the same stat */
+ if (key[actual_len] == '/') {
+ sb.st_size = 0;
+ sb.st_mode = 0777;
+ sb.st_mode |= S_IFDIR; /* regular directory */
+#ifdef NETWARE
+ sb.st_mtime.tv_sec = phar->max_timestamp;
+ sb.st_atime.tv_sec = phar->max_timestamp;
+ sb.st_ctime.tv_sec = phar->max_timestamp;
+#else
+ sb.st_mtime = phar->max_timestamp;
+ sb.st_atime = phar->max_timestamp;
+ sb.st_ctime = phar->max_timestamp;
+#endif
+ goto statme_baby;
+ }
+ }
+ }
+ if (SUCCESS != zend_hash_move_forward(&phar->manifest)) {
+ break;
+ }
+ }
+ }
+ efree(entry);
+ efree(save2);
+ efree(arch);
+ /* Error Occured */
+ if (!IS_EXISTS_CHECK(type)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%sstat failed for %s", IS_LINK_OPERATION(type) ? "L" : "", filename);
+ }
+ RETURN_FALSE;
+ }
+stat_entry:
+ if (!data->is_dir) {
+ sb.st_size = data->uncompressed_filesize;
+ sb.st_mode = data->flags & PHAR_ENT_PERM_MASK;
+ if (data->link) {
+ sb.st_mode |= S_IFREG|S_IFLNK; /* regular file */
+ } else {
+ sb.st_mode |= S_IFREG; /* regular file */
+ }
+ /* timestamp is just the timestamp when this was added to the phar */
+#ifdef NETWARE
+ sb.st_mtime.tv_sec = data->timestamp;
+ sb.st_atime.tv_sec = data->timestamp;
+ sb.st_ctime.tv_sec = data->timestamp;
+#else
+ sb.st_mtime = data->timestamp;
+ sb.st_atime = data->timestamp;
+ sb.st_ctime = data->timestamp;
+#endif
+ } else {
+ sb.st_size = 0;
+ sb.st_mode = data->flags & PHAR_ENT_PERM_MASK;
+ sb.st_mode |= S_IFDIR; /* regular directory */
+ if (data->link) {
+ sb.st_mode |= S_IFLNK;
+ }
+ /* timestamp is just the timestamp when this was added to the phar */
+#ifdef NETWARE
+ sb.st_mtime.tv_sec = data->timestamp;
+ sb.st_atime.tv_sec = data->timestamp;
+ sb.st_ctime.tv_sec = data->timestamp;
+#else
+ sb.st_mtime = data->timestamp;
+ sb.st_atime = data->timestamp;
+ sb.st_ctime = data->timestamp;
+#endif
+ }
+
+statme_baby:
+ efree(arch);
+ if (!(*pphar)->is_writeable) {
+ sb.st_mode = (sb.st_mode & 0555) | (sb.st_mode & ~0777);
+ }
+
+ sb.st_nlink = 1;
+ sb.st_rdev = -1;
+ if (data) {
+ tmp_len = data->filename_len + (*pphar)->alias_len;
+ } else {
+ tmp_len = (*pphar)->alias_len + 1;
+ }
+ tmp = (char *) emalloc(tmp_len);
+ memcpy(tmp, (*pphar)->alias, (*pphar)->alias_len);
+ if (data) {
+ memcpy(tmp + (*pphar)->alias_len, data->filename, data->filename_len);
+ } else {
+ *(tmp + (*pphar)->alias_len) = '/';
+ }
+ /* this is only for APC, so use /dev/null device - no chance of conflict there! */
+ sb.st_dev = 0xc;
+ /* generate unique inode number for alias/filename, so no phars will conflict */
+ sb.st_ino = (unsigned short)zend_get_hash_value(tmp, tmp_len);
+ efree(tmp);
+#ifndef PHP_WIN32
+ sb.st_blksize = -1;
+ sb.st_blocks = -1;
+#endif
+ phar_fancy_stat(&sb, type, return_value TSRMLS_CC);
+ return;
+ }
+ }
+skip_phar:
+ orig_stat_func(INTERNAL_FUNCTION_PARAM_PASSTHRU);
+ return;
+}
+/* }}} */
+
+#define PharFileFunction(fname, funcnum, orig) \
+void fname(INTERNAL_FUNCTION_PARAMETERS) { \
+ char *filename; \
+ int filename_len; \
+ \
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len) == FAILURE) { \
+ return; \
+ } \
+ \
+ phar_file_stat(filename, (php_stat_len) filename_len, funcnum, PHAR_G(orig), INTERNAL_FUNCTION_PARAM_PASSTHRU); \
+}
+/* }}} */
+
+/* {{{ proto int fileperms(string filename)
+ Get file permissions */
+PharFileFunction(phar_fileperms, FS_PERMS, orig_fileperms)
+/* }}} */
+
+/* {{{ proto int fileinode(string filename)
+ Get file inode */
+PharFileFunction(phar_fileinode, FS_INODE, orig_fileinode)
+/* }}} */
+
+/* {{{ proto int filesize(string filename)
+ Get file size */
+PharFileFunction(phar_filesize, FS_SIZE, orig_filesize)
+/* }}} */
+
+/* {{{ proto int fileowner(string filename)
+ Get file owner */
+PharFileFunction(phar_fileowner, FS_OWNER, orig_fileowner)
+/* }}} */
+
+/* {{{ proto int filegroup(string filename)
+ Get file group */
+PharFileFunction(phar_filegroup, FS_GROUP, orig_filegroup)
+/* }}} */
+
+/* {{{ proto int fileatime(string filename)
+ Get last access time of file */
+PharFileFunction(phar_fileatime, FS_ATIME, orig_fileatime)
+/* }}} */
+
+/* {{{ proto int filemtime(string filename)
+ Get last modification time of file */
+PharFileFunction(phar_filemtime, FS_MTIME, orig_filemtime)
+/* }}} */
+
+/* {{{ proto int filectime(string filename)
+ Get inode modification time of file */
+PharFileFunction(phar_filectime, FS_CTIME, orig_filectime)
+/* }}} */
+
+/* {{{ proto string filetype(string filename)
+ Get file type */
+PharFileFunction(phar_filetype, FS_TYPE, orig_filetype)
+/* }}} */
+
+/* {{{ proto bool is_writable(string filename)
+ Returns true if file can be written */
+PharFileFunction(phar_is_writable, FS_IS_W, orig_is_writable)
+/* }}} */
+
+/* {{{ proto bool is_readable(string filename)
+ Returns true if file can be read */
+PharFileFunction(phar_is_readable, FS_IS_R, orig_is_readable)
+/* }}} */
+
+/* {{{ proto bool is_executable(string filename)
+ Returns true if file is executable */
+PharFileFunction(phar_is_executable, FS_IS_X, orig_is_executable)
+/* }}} */
+
+/* {{{ proto bool is_executable(string filename)
+ Returns true if file is executable */
+PharFileFunction(phar_file_exists, FS_EXISTS, orig_file_exists)
+/* }}} */
+
+/* {{{ proto bool is_executable(string filename)
+ Returns true if file is executable */
+PharFileFunction(phar_is_dir, FS_IS_DIR, orig_is_dir)
+/* }}} */
+
+PHAR_FUNC(phar_is_file) /* {{{ */
+{
+ char *filename;
+ int filename_len;
+
+ if (!zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map))) {
+ goto skip_phar;
+ }
+ if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len) == FAILURE) {
+ goto skip_phar;
+ }
+ if (!IS_ABSOLUTE_PATH(filename, filename_len) && !strstr(filename, "://")) {
+ char *arch, *entry, *fname;
+ int arch_len, entry_len, fname_len;
+ fname = zend_get_executed_filename(TSRMLS_C);
+
+ /* we are checking for existence of a file within the relative path. Chances are good that this is
+ retrieving something from within the phar archive */
+
+ if (strncasecmp(fname, "phar://", 7)) {
+ goto skip_phar;
+ }
+ fname_len = strlen(fname);
+ if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
+ phar_archive_data **pphar;
+
+ efree(entry);
+ entry = filename;
+ /* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
+ entry_len = filename_len;
+ /* retrieving a file within the current directory, so use this if possible */
+ if (SUCCESS == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar))) {
+ phar_entry_info *etemp;
+
+ entry = phar_fix_filepath(estrndup(entry, entry_len), &entry_len, 1 TSRMLS_CC);
+ if (entry[0] == '/') {
+ if (SUCCESS == zend_hash_find(&((*pphar)->manifest), entry + 1, entry_len - 1, (void **) &etemp)) {
+ /* this file is not in the current directory, use the original path */
+found_it:
+ efree(entry);
+ efree(arch);
+ RETURN_BOOL(!etemp->is_dir);
+ }
+ } else {
+ if (SUCCESS == zend_hash_find(&((*pphar)->manifest), entry, entry_len, (void **) &etemp)) {
+ goto found_it;
+ }
+ }
+ }
+ efree(entry);
+ efree(arch);
+ RETURN_FALSE;
+ }
+ }
+skip_phar:
+ PHAR_G(orig_is_file)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
+ return;
+}
+/* }}} */
+
+PHAR_FUNC(phar_is_link) /* {{{ */
+{
+ char *filename;
+ int filename_len;
+
+ if (!zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map))) {
+ goto skip_phar;
+ }
+ if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len) == FAILURE) {
+ goto skip_phar;
+ }
+ if (!IS_ABSOLUTE_PATH(filename, filename_len) && !strstr(filename, "://")) {
+ char *arch, *entry, *fname;
+ int arch_len, entry_len, fname_len;
+ fname = zend_get_executed_filename(TSRMLS_C);
+
+ /* we are checking for existence of a file within the relative path. Chances are good that this is
+ retrieving something from within the phar archive */
+
+ if (strncasecmp(fname, "phar://", 7)) {
+ goto skip_phar;
+ }
+ fname_len = strlen(fname);
+ if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
+ phar_archive_data **pphar;
+
+ efree(entry);
+ entry = filename;
+ /* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
+ entry_len = filename_len;
+ /* retrieving a file within the current directory, so use this if possible */
+ if (SUCCESS == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar))) {
+ phar_entry_info *etemp;
+
+ entry = phar_fix_filepath(estrndup(entry, entry_len), &entry_len, 1 TSRMLS_CC);
+ if (entry[0] == '/') {
+ if (SUCCESS == zend_hash_find(&((*pphar)->manifest), entry + 1, entry_len - 1, (void **) &etemp)) {
+ /* this file is not in the current directory, use the original path */
+found_it:
+ efree(entry);
+ efree(arch);
+ RETURN_BOOL(etemp->link);
+ }
+ } else {
+ if (SUCCESS == zend_hash_find(&((*pphar)->manifest), entry, entry_len, (void **) &etemp)) {
+ goto found_it;
+ }
+ }
+ }
+ efree(entry);
+ efree(arch);
+ RETURN_FALSE;
+ }
+ }
+skip_phar:
+ PHAR_G(orig_file_exists)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
+ return;
+}
+/* }}} */
+
+/* {{{ proto array lstat(string filename)
+ Give information about a file or symbolic link */
+PharFileFunction(phar_lstat, FS_LSTAT, orig_lstat)
+/* }}} */
+
+/* {{{ proto array stat(string filename)
+ Give information about a file */
+PharFileFunction(phar_stat, FS_STAT, orig_stat)
+/* }}} */
+
+/* {{{ void phar_intercept_functions(TSRMLS_D) */
+#define PHAR_INTERCEPT(func) \
+ PHAR_G(orig_##func) = NULL; \
+ if (SUCCESS == zend_hash_find(CG(function_table), #func, sizeof(#func), (void **)&orig)) { \
+ PHAR_G(orig_##func) = orig->internal_function.handler; \
+ orig->internal_function.handler = phar_##func; \
+ }
+
+void phar_intercept_functions(TSRMLS_D)
+{
+ zend_function *orig;
+
+ if (!PHAR_G(request_init)) {
+ PHAR_G(cwd) = NULL;
+ PHAR_G(cwd_len) = 0;
+ } else if (PHAR_G(orig_fopen)) {
+ /* don't double-intercept */
+ return;
+ }
+ PHAR_INTERCEPT(fopen);
+ PHAR_INTERCEPT(file_get_contents);
+ PHAR_INTERCEPT(is_file);
+ PHAR_INTERCEPT(is_link);
+ PHAR_INTERCEPT(is_dir);
+ PHAR_INTERCEPT(opendir);
+ PHAR_INTERCEPT(file_exists);
+ PHAR_INTERCEPT(fileperms);
+ PHAR_INTERCEPT(fileinode);
+ PHAR_INTERCEPT(filesize);
+ PHAR_INTERCEPT(fileowner);
+ PHAR_INTERCEPT(filegroup);
+ PHAR_INTERCEPT(fileatime);
+ PHAR_INTERCEPT(filemtime);
+ PHAR_INTERCEPT(filectime);
+ PHAR_INTERCEPT(filetype);
+ PHAR_INTERCEPT(is_writable);
+ PHAR_INTERCEPT(is_readable);
+ PHAR_INTERCEPT(is_executable);
+ PHAR_INTERCEPT(lstat);
+ PHAR_INTERCEPT(stat);
+ PHAR_INTERCEPT(readfile);
+}
+/* }}} */
+
+/* {{{ void phar_release_functions(TSRMLS_D) */
+#define PHAR_RELEASE(func) \
+ if (PHAR_G(orig_##func) && SUCCESS == zend_hash_find(CG(function_table), #func, sizeof(#func), (void **)&orig)) { \
+ orig->internal_function.handler = PHAR_G(orig_##func); \
+ } \
+ PHAR_G(orig_##func) = NULL;
+
+void phar_release_functions(TSRMLS_D)
+{
+ zend_function *orig;
+
+ PHAR_RELEASE(fopen);
+ PHAR_RELEASE(file_get_contents);
+ PHAR_RELEASE(is_file);
+ PHAR_RELEASE(is_dir);
+ PHAR_RELEASE(opendir);
+ PHAR_RELEASE(file_exists);
+ PHAR_RELEASE(fileperms);
+ PHAR_RELEASE(fileinode);
+ PHAR_RELEASE(filesize);
+ PHAR_RELEASE(fileowner);
+ PHAR_RELEASE(filegroup);
+ PHAR_RELEASE(fileatime);
+ PHAR_RELEASE(filemtime);
+ PHAR_RELEASE(filectime);
+ PHAR_RELEASE(filetype);
+ PHAR_RELEASE(is_writable);
+ PHAR_RELEASE(is_readable);
+ PHAR_RELEASE(is_executable);
+ PHAR_RELEASE(lstat);
+ PHAR_RELEASE(stat);
+ PHAR_RELEASE(readfile);
+}
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
diff --git a/ext/phar/func_interceptors.h b/ext/phar/func_interceptors.h
new file mode 100644
index 0000000000..b48be591ed
--- /dev/null
+++ b/ext/phar/func_interceptors.h
@@ -0,0 +1,34 @@
+/*
+ +----------------------------------------------------------------------+
+ | phar php single-file executable PHP extension |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 2006-2007 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt. |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gregory Beaver <cellog@php.net> |
+ | Marcus Boerger <helly@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+BEGIN_EXTERN_C()
+void phar_intercept_functions(TSRMLS_D);
+void phar_release_functions(TSRMLS_D);
+END_EXTERN_C()
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
diff --git a/ext/phar/gdbhelp b/ext/phar/gdbhelp
new file mode 100644
index 0000000000..5411858671
--- /dev/null
+++ b/ext/phar/gdbhelp
@@ -0,0 +1,122 @@
+define ___pharglobals
+ if basic_functions_module.zts
+ set $tsrm_ls = ts_resource_ex(0, 0)
+ set $pharglobals = ((zend_phar_globals) (*((void ***) $tsrm_ls))[phar_globals_id-1])
+ else
+ set $pharglobals = phar_globals
+ end
+end
+
+define ____print_pharht
+ set $ht = $arg0
+ set $p = $ht.pListHead
+
+ while $p != 0
+ set $i = $ind
+ while $i > 0
+ printf " "
+ set $i = $i - 1
+ end
+
+ set $temp = *(phar_archive_data*)$p->pDataPtr
+ ____print_str $temp.fname $temp.fname_len
+ printf " => "
+
+ if $arg1 == 0
+
+ printf "%i (alias ", $temp.refcount
+ ____print_str $temp.alias $temp.alias_len
+ printf ")\n"
+ end
+
+ set $p = $p->pListNext
+ end
+end
+
+define print_phar
+ set $ind = 1
+ ___pharglobals
+ printf "{"
+ ____print_pharht $pharglobals.phar_fname_map 0
+ printf "}\n"
+end
+
+document display_phar_globals
+ display phar globals
+end
+
+define display_phar_globals
+ ___pharglobals
+ graph display $phar_globals.$arg0
+end
+
+define print_pharfp
+ ___pharglobals
+ set $ht = $pharglobals.phar_fname_map
+ set $p = $ht.pListHead
+ set $fpcount = 0
+
+ while $p != 0
+ set $pharname = (*(phar_archive_data*)$p->pDataPtr).fname
+ set $pharrefcount = (*(phar_archive_data*)$p->pDataPtr).refcount
+ if (*(phar_archive_data*)$p->pDataPtr).fp != 0
+ set $fpcount = $fpcount + 1
+ printf "phar %s is open (%i)\n", $pharname, $pharrefcount
+ end
+ set $manifest = (*(phar_archive_data*)$p->pDataPtr).manifest
+ set $m = $manifest.pListHead
+ while $m != 0
+ if (*(phar_entry_info *)$m->pData).fp
+ set $fpcount = $fpcount + 1
+ set $a = (*(phar_entry_info *)$m->pData).fp_refcount
+ printf "phar %s file %s is open (%i)\n", $pharname, (*(phar_entry_info *)$m->pData).filename, $a
+ end
+ set $m = $m->pListNext
+ end
+
+ set $p = $p->pListNext
+ end
+ printf "Open file pointers: %d\n", $fpcount
+end
+
+document print_pharfp
+ displays all open file pointers in phar, and the phars plus entries that are open with reference counts
+end
+
+define dump_entry
+ ___pharglobals
+ set $ht = $pharglobals.phar_fname_map
+ set $p = $ht.pListHead
+ set $done = 0
+ while $p != 0
+ set $t = (*(phar_archive_data*)$p->pDataPtr)
+ if $t.fname[0] == $arg0[0] || $t.alias[0] == $arg0[0]
+ set $manifest = (*(phar_archive_data*)$p->pDataPtr).manifest
+ set $m = $manifest.pListHead
+ while $m != 0
+ if (*(phar_entry_info *)$m->pData).filename[0] == $arg1[0]
+ if $argc == 3
+ output *((phar_entry_info *)$m->pData)->fp
+ end
+ if $argc == 2
+ output *(phar_entry_info *)$m->pData
+ end
+ printf "\n"
+ set $done = 1
+ loop_break
+ end
+ set $m = $m->pListNext
+ end
+ end
+ if $done == 1
+ loop_break
+ end
+ set $p = $p->pListNext
+ end
+end
+
+document dump_entry
+ dump_entry "pharname"|"pharalias" "filename" [1]
+ display phar_entry_info for a file within a phar. If the optional third param
+ is passed in, displays the php_stream that is the file's fp
+end \ No newline at end of file
diff --git a/ext/phar/makestub.php b/ext/phar/makestub.php
new file mode 100644
index 0000000000..44e0b96337
--- /dev/null
+++ b/ext/phar/makestub.php
@@ -0,0 +1,109 @@
+<?php
+$s = str_replace("\r", '', file_get_contents(dirname(__FILE__) . '/shortarc.php'));
+
+$s .= "\nExtract_Phar::go();\n__HALT_COMPILER();";
+$news = '';
+foreach (token_get_all($s) as $token) {
+ if (is_array($token)) {
+ if ($token[0] == T_COMMENT) {
+ $token[1] = '';
+ }
+ if ($token[0] == T_WHITESPACE) {
+ $n = str_repeat("\n", substr_count($token[1], "\n"));
+ $token[1] = strlen($n) ? $n : ' ';
+ }
+ $news .= $token[1];
+ } else {
+ $news .= $token;
+ }
+}
+$s = $news . ' ?>';
+$slen = strlen($s) - strlen('index.php') - strlen("000");
+$s = str_replace('\\', '\\\\', $s);
+$s = str_replace('"', '\\"', $s);
+$s = str_replace("\n", '\n', $s);
+// now we need to find the location of web index file
+$webs = substr($s, 0, strpos($s, "000"));
+$s = substr($s, strlen($webs) + strlen("000"));
+$s1 = substr($s, 0, strpos($s, 'index.php'));
+$s2 = substr($s, strlen($s1) + strlen('index.php'));
+$s2 = substr($s2, 0, strpos($s2, 'XXXX'));
+$s3 = substr($s, strlen($s2) + 4 + strlen($s1) + strlen('index.php'));
+
+$stub = '/*
+ +----------------------------------------------------------------------+
+ | phar php single-file executable PHP extension generated stub |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 2005-' . date('Y') . ' The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt. |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gregory Beaver <cellog@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+static inline void phar_get_stub(const char *index_php, const char *web, size_t *len, char **stub, const int name_len, const int web_len TSRMLS_DC)
+{
+';
+$s1split = str_split($s1, 2046);
+$s3split = str_split($s3, 2046);
+$took = false;
+foreach ($s1split as $i => $chunk) {
+ if ($took) {
+ $s1split[$i] = substr($chunk, 1);
+ $took = false;
+ }
+ if ($chunk[strlen($chunk) - 1] == '\\') {
+ $s1split[$i] .= $s1split[$i + 1][0];
+ $took = true;
+ }
+}
+foreach ($s3split as $i => $chunk) {
+ if ($took) {
+ $s3split[$i] = substr($chunk, 1);
+ $took = false;
+ }
+ if ($chunk[strlen($chunk) - 1] == '\\') {
+ $s3split[$i] .= $s3split[$i + 1][0];
+ $took = true;
+ }
+}
+$stub .= "\tstatic const char newstub0[] = \"" . $webs . '";
+';
+foreach ($s1split as $i => $chunk) {
+ $s1count = $i + 1;
+ $stub .= "\tstatic const char newstub1_" . $i . '[] = "' . $chunk . '";
+';
+}
+$stub .= "\tstatic const char newstub2[] = \"" . $s2 . "\";
+";
+foreach ($s3split as $i => $chunk) {
+ $s3count = $i + 1;
+ $stub .= "\tstatic const char newstub3_" . $i . '[] = "' . $chunk . '";
+';
+}
+$stub .= "\n\tstatic const int newstub_len = " . $slen . ";
+
+\t*len = spprintf(stub, name_len + web_len + newstub_len, \"%s%s" . str_repeat('%s', $s1count) . '%s%s%d'
+ . str_repeat('%s', $s3count) . '", newstub0, web';
+foreach ($s1split as $i => $unused) {
+ $stub .= ', newstub1_' . $i;
+}
+$stub .= ', index_php, newstub2';
+$stub .= ", name_len + web_len + newstub_len";
+foreach ($s3split as $i => $unused) {
+ $stub .= ', newstub3_' . $i;
+}
+$stub .= ");
+}";
+
+file_put_contents(dirname(__FILE__) . '/stub.h', $stub."\n");
+?>
diff --git a/ext/phar/package.php b/ext/phar/package.php
new file mode 100644
index 0000000000..f4d63ae21d
--- /dev/null
+++ b/ext/phar/package.php
@@ -0,0 +1,108 @@
+<?php
+
+$notes = '
+BC BREAKING RELEASE
+ BC breaks:
+ * Phar object Compression API is rewritten. Use Phar::compress() and decompress(),
+ Phar::compressFiles()/decompressFiles() and PharFileInfo->compress()/decompress().
+ * phar.extract_list and Phar::getExtractList() are removed
+
+Major feature functionality release
+ * new default stub allows running of phar-based phars without phar extension [Greg/Steph]
+ * add support for tar-based and zip-based phar archives [Greg]
+ * add Phar::isFileFormat() [Greg]
+ * add Phar::convertToExecutable(), Phar::convertToData() [Greg]
+ * add Phar::compress() [Greg]
+ * rename Phar::compressAllFiles() to compressFiles(), uncompressAllFiles() to
+ decompressFiles() [Greg]
+ * conversion to compressed or to other file formats automatically copies the archive
+ to a new extension (i.e. ".phar" to ".phar.tar" or ".tar" to ".tar.gz") [Steph]
+ * add Phar::webPhar() for running a web-based application unmodified
+ directly from a phar archive [Greg]
+ * file functions (fopen-based and stat-based) can be instructed to only look for
+ relative paths within a phar via Phar::interceptFileFuncs()
+ * add PharData class to allow manipulation/creation of non-executable tar and zip archives. [Steph]
+ non-executable tar/zip manipulation is allowed even when phar.readonly=1 [Greg]
+ * paths with . and .. work (phar://blah.phar/a/../b.php => phar://blah.phar/b.php) [Greg]
+ * add support for mkdir()/rmdir() and support for empty directories to phar file format [Greg]
+ * add option to compress the entire phar file for phar/tar file format [Greg]
+ * implement Phar::isCompressed() returning 0, Phar::GZ or Phar::BZ2 [Greg]
+ * implement Phar::copy(string $from, string $to) [Greg]
+ * implement Phar::running(), returns path or URL to currently executed phar
+ * implement Phar::buildFromIterator(Iterator $it[, string $base_directory]) [Greg]
+ * implement Phar::buildFromDirectory(string $base_directory[, string $regex]) [Steph]
+ * implement Phar::mount() for mounting external paths or files to locations inside a phar [Greg]
+ * add Phar::delete() [Greg]
+ * implement Phar::unlinkArchive() [Greg]
+
+Security addition
+ * aliases are validated so that they contain no directory separators as intended
+ * on conversion to other formats, user-supplied aliases are validated
+
+Changes since 2.0.0a2: many bugfixes, removal of phar.extract_list, compression API refactored,
+ conversion API refactored
+';
+
+if (!class_exists("Phar") && !extension_loaded("Phar")) {
+ die("Extension phar not present");
+}
+error_reporting(E_ALL & ~E_DEPRECATED);
+
+require_once 'PEAR/PackageFileManager2.php';
+
+PEAR::setErrorHandling(PEAR_ERROR_DIE);
+
+$options = array(
+ 'filelistgenerator' => 'CVS',
+ 'changelogoldtonew' => false,
+ 'simpleoutput' => true,
+ 'baseinstalldir' => '/',
+ 'packagedirectory' => dirname(__FILE__),
+ 'packagefile' => 'package.xml',
+ 'clearcontents' => true,
+ 'ignore' => array('package*.php', 'package*.xml'),
+ 'dir_roles' => array(
+ 'docs' => 'doc',
+ 'examples' => 'doc',
+ 'tests' => 'test',
+ 'phar' => 'src',
+ ),
+ 'exceptions' => array(
+ 'CREDITS' => 'doc',
+ 'EXPERIMENTAL' => 'doc',
+ 'LICENSE' => 'doc',
+ 'Makefile.frag' => 'src',
+ 'phar_path_check.re' => 'src',
+ 'TODO' => 'doc',
+ 'phar.phar' => 'script',
+ ),
+);
+
+$package = PEAR_PackageFileManager2::importOptions(dirname(__FILE__) . '/package.xml', $options);
+
+$package->clearDeps();
+$package->setPhpDep('5.2.0');
+$package->setPearInstallerDep('1.4.3');
+$package->addPackageDepWithChannel('optional', 'bz2', 'pecl.php.net', false, false, false, false, 'bz2');
+// all this false business sets the <providesextension> tag that allows us to have hash built
+// in statically
+$package->addPackageDepWithChannel('optional', 'hash', 'pecl.php.net', false, false, false, false, 'hash');
+$package->addExtensionDep('optional', 'spl');
+$package->addExtensionDep('optional', 'zlib');
+$package->setPackageType('extsrc');
+$package->addRelease();
+$package->setReleaseVersion(phpversion('phar'));
+$package->setAPIVersion(Phar::apiVersion());
+$package->setReleaseStability('beta');
+$package->setAPIStability('beta');
+$package->setNotes("\n$notes\n");
+//$package->addGlobalReplacement('package-info', '@package_version@', 'version');
+$package->generateContents();
+
+if (isset($_GET['make']) || (isset($_SERVER['argv']) && @$_SERVER['argv'][1] == 'make')) {
+ $package->writePackageFile();
+} else {
+ $package->debugPackageFile();
+}
+
+?>
diff --git a/ext/phar/package.xml b/ext/phar/package.xml
new file mode 100644
index 0000000000..d2d3dcdfd3
--- /dev/null
+++ b/ext/phar/package.xml
@@ -0,0 +1,924 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<package packagerversion="1.7.1" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd">
+ <name>phar</name>
+ <channel>pecl.php.net</channel>
+ <summary>allows running of complete applications out of .phar files (like Java .jar files)</summary>
+ <description>This is the extension version of PEAR&apos;s PHP_Archive package. Support for
+zlib, bz2 and crc32 is achieved without any dependency other than the external
+zlib or bz2 extension.
+
+.phar files can be read using the phar stream, or with the Phar class. If the SPL extension
+is available, a Phar object can be used as an array to iterate over a phar&apos;s contents
+or to read files directly from the phar.
+
+Phar supports tar and zip file formats as well as the native phar file format, and can also be
+used to create data-only tar and zip archives with the PharData class, even if
+write access is disabled by the phar.readonly ini variable.
+
+Executable phar archives can be created using the streams API or with the Phar class, if
+the phar.readonly ini variable is set to false.
+
+Full support for MD5 and SHA1 signatures is possible. Signatures can be required
+if the ini variable phar.require_hash is set to true. When PECL extension hash is
+available then SHA-256 and SHA-512 signatures are supported as well.
+
+Phar is APC-compatible, the latest APC will cache files within a phar archive, resulting in
+a 6x speedup measured running phpMyAdmin as a phar archive.</description>
+ <lead>
+ <name>Greg Beaver</name>
+ <user>cellog</user>
+ <email>cellog@php.net</email>
+ <active>yes</active>
+ </lead>
+ <lead>
+ <name>Marcus Boerger</name>
+ <user>helly</user>
+ <email>helly@php.net</email>
+ <active>yes</active>
+ </lead>
+ <developer>
+ <name>Steph Fox</name>
+ <user>sfox</user>
+ <email>sfox@php.net</email>
+ <active>yes</active>
+ </developer>
+ <date>2008-05-12</date>
+ <time>15:42:58</time>
+ <version>
+ <release>2.0.0b1</release>
+ <api>1.1.1</api>
+ </version>
+ <stability>
+ <release>beta</release>
+ <api>beta</api>
+ </stability>
+ <license uri="http://www.php.net/license">PHP License</license>
+ <notes>
+
+BC BREAKING RELEASE
+ BC breaks:
+ * Phar object Compression API is rewritten. Use Phar::compress() and decompress(),
+ Phar::compressFiles()/decompressFiles() and PharFileInfo-&gt;compress()/decompress().
+ * phar.extract_list and Phar::getExtractList() are removed
+
+Major feature functionality release
+ * new default stub allows running of phar-based phars without phar extension [Greg/Steph]
+ * add support for tar-based and zip-based phar archives [Greg]
+ * add Phar::isFileFormat() [Greg]
+ * add Phar::convertToExecutable(), Phar::convertToData() [Greg]
+ * add Phar::compress() [Greg]
+ * rename Phar::compressAllFiles() to compressFiles(), uncompressAllFiles() to
+ decompressFiles() [Greg]
+ * conversion to compressed or to other file formats automatically copies the archive
+ to a new extension (i.e. &quot;.phar&quot; to &quot;.phar.tar&quot; or &quot;.tar&quot; to &quot;.tar.gz&quot;) [Steph]
+ * add Phar::webPhar() for running a web-based application unmodified
+ directly from a phar archive [Greg]
+ * file functions (fopen-based and stat-based) can be instructed to only look for
+ relative paths within a phar via Phar::interceptFileFuncs()
+ * add PharData class to allow manipulation/creation of non-executable tar and zip archives. [Steph]
+ non-executable tar/zip manipulation is allowed even when phar.readonly=1 [Greg]
+ * paths with . and .. work (phar://blah.phar/a/../b.php =&gt; phar://blah.phar/b.php) [Greg]
+ * add support for mkdir()/rmdir() and support for empty directories to phar file format [Greg]
+ * add option to compress the entire phar file for phar/tar file format [Greg]
+ * implement Phar::isCompressed() returning 0, Phar::GZ or Phar::BZ2 [Greg]
+ * implement Phar::copy(string $from, string $to) [Greg]
+ * implement Phar::running(), returns path or URL to currently executed phar
+ * implement Phar::buildFromIterator(Iterator $it[, string $base_directory]) [Greg]
+ * implement Phar::buildFromDirectory(string $base_directory[, string $regex]) [Steph]
+ * implement Phar::mount() for mounting external paths or files to locations inside a phar [Greg]
+ * add Phar::delete() [Greg]
+ * implement Phar::unlinkArchive() [Greg]
+
+Security addition
+ * aliases are validated so that they contain no directory separators as intended
+ * on conversion to other formats, user-supplied aliases are validated
+
+Changes since 2.0.0a2: many bugfixes, removal of phar.extract_list, compression API refactored,
+ conversion API refactored
+
+ </notes>
+ <contents>
+ <dir baseinstalldir="/" name="/">
+ <dir name="phar">
+ <file name="clicommand.inc" role="src" />
+ <file name="directorygraphiterator.inc" role="src" />
+ <file name="directorytreeiterator.inc" role="src" />
+ <file name="invertedregexiterator.inc" role="src" />
+ <file name="phar.inc" role="src" />
+ <file name="phar.php" role="src" />
+ <file name="pharcommand.inc" role="src" />
+ </dir> <!-- /phar -->
+ <dir name="tests">
+ <dir name="files">
+ <file name="extracted.inc" role="test" />
+ <file name="frontcontroller.phar" role="test" />
+ <file name="frontcontroller.phar.inc" role="test" />
+ <file name="frontcontroller2.phar" role="test" />
+ <file name="frontcontroller2.phar.inc" role="test" />
+ <file name="frontcontroller3.phar" role="test" />
+ <file name="frontcontroller3.phar.inc" role="test" />
+ <file name="frontcontroller4.phar" role="test" />
+ <file name="frontcontroller4.phar.inc" role="test" />
+ <file name="frontcontroller5.phar" role="test" />
+ <file name="frontcontroller5.phar.inc" role="test" />
+ <file name="frontcontroller6.phar" role="test" />
+ <file name="frontcontroller6.phar.inc" role="test" />
+ <file name="frontcontroller7.phar" role="test" />
+ <file name="frontcontroller7.phar.inc" role="test" />
+ <file name="frontcontroller8.phar" role="test" />
+ <file name="frontcontroller8.phar.inc" role="test" />
+ <file name="frontcontroller9.phar" role="test" />
+ <file name="frontcontroller9.phar.inc" role="test" />
+ <file name="frontcontroller10.phar" role="test" />
+ <file name="frontcontroller10.phar.inc" role="test" />
+ <file name="frontcontroller11.phar" role="test" />
+ <file name="frontcontroller11.phar.inc" role="test" />
+ <file name="frontcontroller12.phar" role="test" />
+ <file name="frontcontroller12.phar.inc" role="test" />
+ <file name="frontcontroller13.phar" role="test" />
+ <file name="frontcontroller13.phar.inc" role="test" />
+ <file name="frontcontroller14.phar" role="test" />
+ <file name="frontcontroller14.phar.inc" role="test" />
+ <file name="frontcontroller16.phar" role="test" />
+ <file name="frontcontroller16.phar.inc" role="test" />
+ <file name="frontcontroller17.phar" role="test" />
+ <file name="frontcontroller17.phar.inc" role="test" />
+ <file name="frontcontroller18.phar" role="test" />
+ <file name="frontcontroller18.phar.inc" role="test" />
+ <file name="frontcontroller19.phar" role="test" />
+ <file name="frontcontroller19.phar.inc" role="test" />
+ <file name="md5.phar" role="test" />
+ <file name="nophar.phar" role="test" />
+ <file name="nophar.phar.inc" role="test" />
+ <file name="phar_oo_test.inc" role="test" />
+ <file name="phar_test.inc" role="test" />
+ <file name="sha1.phar" role="test" />
+ <file name="sha256.phar" role="test" />
+ <file name="sha512.phar" role="test" />
+ <file name="zfapp.tgz" role="test" />
+ </dir> <!-- /tests/files -->
+ <dir name="tar">
+ <dir name="files">
+ <file name="badalias1.phar.tar" role="test" />
+ <file name="badalias2.phar.tar" role="test" />
+ <file name="badalias3.phar.tar" role="test" />
+ <file name="badalias4.phar.tar" role="test" />
+ <file name="badalias5.phar.tar" role="test" />
+ <file name="biglink.tar" role="test" />
+ <file name="corrupt_tarmaker.php.inc" role="test" />
+ <file name="frontcontroller.phar.inc" role="test" />
+ <file name="frontcontroller.phar.tar" role="test" />
+ <file name="frontcontroller2.phar.inc" role="test" />
+ <file name="frontcontroller2.phar.tar" role="test" />
+ <file name="frontcontroller3.phar.inc" role="test" />
+ <file name="frontcontroller3.phar.tar" role="test" />
+ <file name="frontcontroller4.phar.inc" role="test" />
+ <file name="frontcontroller4.phar.tar" role="test" />
+ <file name="frontcontroller5.phar.inc" role="test" />
+ <file name="frontcontroller5.phar.tar" role="test" />
+ <file name="frontcontroller6.phar.inc" role="test" />
+ <file name="frontcontroller6.phar.tar" role="test" />
+ <file name="frontcontroller7.phar.inc" role="test" />
+ <file name="frontcontroller7.phar.tar" role="test" />
+ <file name="frontcontroller8.phar.inc" role="test" />
+ <file name="frontcontroller8.phar.tar" role="test" />
+ <file name="frontcontroller9.phar.inc" role="test" />
+ <file name="frontcontroller9.phar.tar" role="test" />
+ <file name="frontcontroller10.phar.inc" role="test" />
+ <file name="frontcontroller10.phar.tar" role="test" />
+ <file name="frontcontroller11.phar.inc" role="test" />
+ <file name="frontcontroller11.phar.tar" role="test" />
+ <file name="frontcontroller12.phar.inc" role="test" />
+ <file name="frontcontroller12.phar.tar" role="test" />
+ <file name="links.tar" role="test" />
+ <file name="make_invalid_tar.php.inc" role="test" />
+ <file name="subdirlink.tar" role="test" />
+ <file name="tarmaker.php.inc" role="test" />
+ <file name="tinylink.tar" role="test" />
+ <file name="trunc.tar" role="test" />
+ </dir> <!-- /tests/tar/files -->
+ <file name="033.phpt" role="test" />
+ <file name="033a.phpt" role="test" />
+ <file name="alias_acrobatics.phpt" role="test" />
+ <file name="badalias.phpt" role="test" />
+ <file name="badchecksum.phpt" role="test" />
+ <file name="bignames.phpt" role="test" />
+ <file name="create_new_and_modify.phpt" role="test" />
+ <file name="create_new_phar_b.phpt" role="test" />
+ <file name="delete.phpt" role="test" />
+ <file name="delete_in_phar.phpt" role="test" />
+ <file name="delete_in_phar_b.phpt" role="test" />
+ <file name="delete_in_phar_confirm.phpt" role="test" />
+ <file name="dir.phpt" role="test" />
+ <file name="exists_as_phar.phpt" role="test" />
+ <file name="frontcontroller1.phar.phpt" role="test" />
+ <file name="frontcontroller2.phar.phpt" role="test" />
+ <file name="frontcontroller3.phar.phpt" role="test" />
+ <file name="frontcontroller4.phar.phpt" role="test" />
+ <file name="frontcontroller5.phar.phpt" role="test" />
+ <file name="frontcontroller6.phar.phpt" role="test" />
+ <file name="frontcontroller7.phar.phpt" role="test" />
+ <file name="frontcontroller8.phar.phpt" role="test" />
+ <file name="frontcontroller9.phar.phpt" role="test" />
+ <file name="frontcontroller10.phar.phpt" role="test" />
+ <file name="frontcontroller11.phar.phpt" role="test" />
+ <file name="frontcontroller12.phar.phpt" role="test" />
+ <file name="frontcontroller13.phar.phpt" role="test" />
+ <file name="frontcontroller14.phar.phpt" role="test" />
+ <file name="frontcontroller15.phar.phpt" role="test" />
+ <file name="frontcontroller16.phar.phpt" role="test" />
+ <file name="frontcontroller17.phar.phpt" role="test" />
+ <file name="frontcontroller18.phar.phpt" role="test" />
+ <file name="frontcontroller19.phar.phpt" role="test" />
+ <file name="frontcontroller20.phar.phpt" role="test" />
+ <file name="frontcontroller21.phar.phpt" role="test" />
+ <file name="links.phpt" role="test" />
+ <file name="links2.phpt" role="test" />
+ <file name="links3.phpt" role="test" />
+ <file name="links4.phpt" role="test" />
+ <file name="links5.phpt" role="test" />
+ <file name="open_for_write_existing.phpt" role="test" />
+ <file name="open_for_write_existing_b.phpt" role="test" />
+ <file name="open_for_write_existing_c.phpt" role="test" />
+ <file name="open_for_write_newfile.phpt" role="test" />
+ <file name="open_for_write_newfile_b.phpt" role="test" />
+ <file name="open_for_write_newfile_c.phpt" role="test" />
+ <file name="phar_begin_setstub_commit.phpt" role="test" />
+ <file name="phar_buildfromiterator4.phpt" role="test" />
+ <file name="phar_buildfromiterator5.phpt" role="test" />
+ <file name="phar_buildfromiterator6.phpt" role="test" />
+ <file name="phar_buildfromiterator7.phpt" role="test" />
+ <file name="phar_buildfromiterator8.phpt" role="test" />
+ <file name="phar_buildfromiterator9.phpt" role="test" />
+ <file name="phar_commitwrite.phpt" role="test" />
+ <file name="phar_convert_phar.phpt" role="test" />
+ <file name="phar_convert_phar2.phpt" role="test" />
+ <file name="phar_convert_phar3.phpt" role="test" />
+ <file name="phar_copy.phpt" role="test" />
+ <file name="phar_magic.phpt" role="test" />
+ <file name="phar_setalias.phpt" role="test" />
+ <file name="phar_setalias2.phpt" role="test" />
+ <file name="phar_setdefaultstub.phpt" role="test" />
+ <file name="phar_stub.phpt" role="test" />
+ <file name="phar_stub_error.phpt" role="test" />
+ <file name="refcount1.phpt" role="test" />
+ <file name="refcount1_5_2.phpt" role="test" />
+ <file name="rename.phpt" role="test" />
+ <file name="tar_001.phpt" role="test" />
+ <file name="tar_002.phpt" role="test" />
+ <file name="tar_003.phpt" role="test" />
+ <file name="tar_004.phpt" role="test" />
+ <file name="tar_bz2.phpt" role="test" />
+ <file name="tar_gzip.phpt" role="test" />
+ <file name="tar_makebz2.phpt" role="test" />
+ <file name="tar_makegz.phpt" role="test" />
+ <file name="tar_nostub.phpt" role="test" />
+ <file name="truncated.phpt" role="test" />
+ </dir> <!-- /tests/tar -->
+ <dir name="zip">
+ <dir name="files">
+ <file name="badalias1.phar.zip" role="test" />
+ <file name="badalias2.phar.zip" role="test" />
+ <file name="badalias3.phar.zip" role="test" />
+ <file name="badalias4.phar.zip" role="test" />
+ <file name="badalias5.phar.zip" role="test" />
+ <file name="cdir_offset.zip" role="test" />
+ <file name="compress_unsup1.zip" role="test" />
+ <file name="compress_unsup2.zip" role="test" />
+ <file name="compress_unsup3.zip" role="test" />
+ <file name="compress_unsup4.zip" role="test" />
+ <file name="compress_unsup5.zip" role="test" />
+ <file name="compress_unsup6.zip" role="test" />
+ <file name="compress_unsup7.zip" role="test" />
+ <file name="compress_unsup9.zip" role="test" />
+ <file name="compress_unsup10.zip" role="test" />
+ <file name="compress_unsup14.zip" role="test" />
+ <file name="compress_unsup18.zip" role="test" />
+ <file name="compress_unsup19.zip" role="test" />
+ <file name="compress_unsup97.zip" role="test" />
+ <file name="compress_unsup98.zip" role="test" />
+ <file name="compress_unsupunknown.zip" role="test" />
+ <file name="corrupt2.php.inc" role="test" />
+ <file name="corrupt_count1.php.inc" role="test" />
+ <file name="corrupt_zipmaker.php.inc" role="test" />
+ <file name="count1.zip" role="test" />
+ <file name="count2.zip" role="test" />
+ <file name="encrypted.zip" role="test" />
+ <file name="filecomment.zip" role="test" />
+ <file name="frontcontroller.phar.inc" role="test" />
+ <file name="frontcontroller.phar.zip" role="test" />
+ <file name="frontcontroller2.phar.inc" role="test" />
+ <file name="frontcontroller2.phar.zip" role="test" />
+ <file name="frontcontroller3.phar.inc" role="test" />
+ <file name="frontcontroller3.phar.zip" role="test" />
+ <file name="frontcontroller4.phar.inc" role="test" />
+ <file name="frontcontroller4.phar.zip" role="test" />
+ <file name="frontcontroller5.phar.inc" role="test" />
+ <file name="frontcontroller5.phar.zip" role="test" />
+ <file name="frontcontroller6.phar.inc" role="test" />
+ <file name="frontcontroller6.phar.zip" role="test" />
+ <file name="frontcontroller7.phar.inc" role="test" />
+ <file name="frontcontroller7.phar.zip" role="test" />
+ <file name="frontcontroller8.phar.inc" role="test" />
+ <file name="frontcontroller8.phar.zip" role="test" />
+ <file name="frontcontroller9.phar.inc" role="test" />
+ <file name="frontcontroller9.phar.zip" role="test" />
+ <file name="frontcontroller10.phar.inc" role="test" />
+ <file name="frontcontroller10.phar.zip" role="test" />
+ <file name="frontcontroller11.phar.inc" role="test" />
+ <file name="frontcontroller11.phar.zip" role="test" />
+ <file name="frontcontroller12.phar.inc" role="test" />
+ <file name="frontcontroller12.phar.zip" role="test" />
+ <file name="make_invalid_tar.php.inc" role="test" />
+ <file name="metadata.phar.inc" role="test" />
+ <file name="metadata.phar.zip" role="test" />
+ <file name="nozipend.zip" role="test" />
+ <file name="odt.odt" role="test" />
+ <file name="stdin.zip" role="test" />
+ <file name="truncfilename.zip" role="test" />
+ <file name="zip.zip" role="test" />
+ <file name="zipmaker.php.inc" role="test" />
+ </dir> <!-- /tests/zip/files -->
+ <file name="033.phpt" role="test" />
+ <file name="033a.phpt" role="test" />
+ <file name="alias_acrobatics.phpt" role="test" />
+ <file name="all.phpt" role="test" />
+ <file name="badalias.phpt" role="test" />
+ <file name="corrupt_001.phpt" role="test" />
+ <file name="corrupt_002.phpt" role="test" />
+ <file name="corrupt_003.phpt" role="test" />
+ <file name="corrupt_004.phpt" role="test" />
+ <file name="corrupt_005.phpt" role="test" />
+ <file name="corrupt_006.phpt" role="test" />
+ <file name="corrupt_007.phpt" role="test" />
+ <file name="corrupt_008.phpt" role="test" />
+ <file name="create_new_and_modify.phpt" role="test" />
+ <file name="create_new_phar_b.phpt" role="test" />
+ <file name="delete.phpt" role="test" />
+ <file name="delete_in_phar.phpt" role="test" />
+ <file name="delete_in_phar_b.phpt" role="test" />
+ <file name="delete_in_phar_confirm.phpt" role="test" />
+ <file name="dir.phpt" role="test" />
+ <file name="exists_as_phar.phpt" role="test" />
+ <file name="frontcontroller1.phar.phpt" role="test" />
+ <file name="frontcontroller2.phar.phpt" role="test" />
+ <file name="frontcontroller3.phar.phpt" role="test" />
+ <file name="frontcontroller4.phar.phpt" role="test" />
+ <file name="frontcontroller5.phar.phpt" role="test" />
+ <file name="frontcontroller6.phar.phpt" role="test" />
+ <file name="frontcontroller7.phar.phpt" role="test" />
+ <file name="frontcontroller8.phar.phpt" role="test" />
+ <file name="frontcontroller9.phar.phpt" role="test" />
+ <file name="frontcontroller10.phar.phpt" role="test" />
+ <file name="frontcontroller11.phar.phpt" role="test" />
+ <file name="frontcontroller12.phar.phpt" role="test" />
+ <file name="frontcontroller13.phar.phpt" role="test" />
+ <file name="frontcontroller14.phar.phpt" role="test" />
+ <file name="frontcontroller15.phar.phpt" role="test" />
+ <file name="frontcontroller16.phar.phpt" role="test" />
+ <file name="frontcontroller17.phar.phpt" role="test" />
+ <file name="frontcontroller18.phar.phpt" role="test" />
+ <file name="frontcontroller19.phar.phpt" role="test" />
+ <file name="frontcontroller20.phar.phpt" role="test" />
+ <file name="frontcontroller21.phar.phpt" role="test" />
+ <file name="getalias.phpt" role="test" />
+ <file name="largezip.phpt" role="test" />
+ <file name="metadata_write_commit.phpt" role="test" />
+ <file name="notphar.phpt" role="test" />
+ <file name="odt.phpt" role="test" />
+ <file name="open_for_write_existing.phpt" role="test" />
+ <file name="open_for_write_existing_b.phpt" role="test" />
+ <file name="open_for_write_existing_c.phpt" role="test" />
+ <file name="open_for_write_newfile.phpt" role="test" />
+ <file name="open_for_write_newfile_b.phpt" role="test" />
+ <file name="open_for_write_newfile_c.phpt" role="test" />
+ <file name="phar_begin_setstub_commit.phpt" role="test" />
+ <file name="phar_buildfromiterator4.phpt" role="test" />
+ <file name="phar_buildfromiterator5.phpt" role="test" />
+ <file name="phar_buildfromiterator6.phpt" role="test" />
+ <file name="phar_buildfromiterator7.phpt" role="test" />
+ <file name="phar_buildfromiterator8.phpt" role="test" />
+ <file name="phar_buildfromiterator9.phpt" role="test" />
+ <file name="phar_commitwrite.phpt" role="test" />
+ <file name="phar_convert_phar.phpt" role="test" />
+ <file name="phar_copy.phpt" role="test" />
+ <file name="phar_magic.phpt" role="test" />
+ <file name="phar_oo_compressallbz2.phpt" role="test" />
+ <file name="phar_oo_compressallgz.phpt" role="test" />
+ <file name="phar_setalias.phpt" role="test" />
+ <file name="phar_setalias2.phpt" role="test" />
+ <file name="phar_setdefaultstub.phpt" role="test" />
+ <file name="phar_stub.phpt" role="test" />
+ <file name="phar_stub_error.phpt" role="test" />
+ <file name="refcount1.phpt" role="test" />
+ <file name="refcount1_5_2.phpt" role="test" />
+ <file name="rename.phpt" role="test" />
+ <file name="unixzip.phpt" role="test" />
+ </dir> <!-- /tests/zip -->
+ <file name="001.phpt" role="test" />
+ <file name="002.phpt" role="test" />
+ <file name="003.phpt" role="test" />
+ <file name="003a.phpt" role="test" />
+ <file name="004.phpt" role="test" />
+ <file name="005.phpt" role="test" />
+ <file name="006.phpt" role="test" />
+ <file name="007.phpt" role="test" />
+ <file name="008.phpt" role="test" />
+ <file name="009.phpt" role="test" />
+ <file name="010.phpt" role="test" />
+ <file name="011.phpt" role="test" />
+ <file name="012.phpt" role="test" />
+ <file name="013.phpt" role="test" />
+ <file name="014.phpt" role="test" />
+ <file name="015.phpt" role="test" />
+ <file name="015b.phpt" role="test" />
+ <file name="016.phpt" role="test" />
+ <file name="016b.phpt" role="test" />
+ <file name="017.phpt" role="test" />
+ <file name="018.phpt" role="test" />
+ <file name="019.phpt" role="test" />
+ <file name="019b.phpt" role="test" />
+ <file name="019c.phpt" role="test" />
+ <file name="020.phpt" role="test" />
+ <file name="021.phpt" role="test" />
+ <file name="022.phpt" role="test" />
+ <file name="023.phpt" role="test" />
+ <file name="024.phpt" role="test" />
+ <file name="025.phpt" role="test" />
+ <file name="026.phpt" role="test" />
+ <file name="027.phpt" role="test" />
+ <file name="028.phpt" role="test" />
+ <file name="029.phpt" role="test" />
+ <file name="030.phpt" role="test" />
+ <file name="031.phpt" role="test" />
+ <file name="032.phpt" role="test" />
+ <file name="033.phpt" role="test" />
+ <file name="033a.phpt" role="test" />
+ <file name="addfuncs.phpt" role="test" />
+ <file name="alias_acrobatics.phpt" role="test" />
+ <file name="badparameters.phpt" role="test" />
+ <file name="bug13727.phpt" role="test" />
+ <file name="bug13786.phpt" role="test" />
+ <file name="create_new_and_modify.phpt" role="test" />
+ <file name="create_new_phar.phpt" role="test" />
+ <file name="create_new_phar_b.phpt" role="test" />
+ <file name="create_new_phar_c.phpt" role="test" />
+ <file name="create_path_error.phpt" role="test" />
+ <file name="delete.phpt" role="test" />
+ <file name="delete_in_phar.phpt" role="test" />
+ <file name="delete_in_phar_b.phpt" role="test" />
+ <file name="delete_in_phar_confirm.phpt" role="test" />
+ <file name="dir.phpt" role="test" />
+ <file name="fgc_edgecases.phpt" role="test" />
+ <file name="file_get_contents.phpt" role="test" />
+ <file name="fopen.phpt" role="test" />
+ <file name="fopen5.2.phpt" role="test" />
+ <file name="fopen_edgecases.phpt" role="test" />
+ <file name="fopen_edgecases2.phpt" role="test" />
+ <file name="frontcontroller1.phpt" role="test" />
+ <file name="frontcontroller2.phpt" role="test" />
+ <file name="frontcontroller3.phpt" role="test" />
+ <file name="frontcontroller4.phpt" role="test" />
+ <file name="frontcontroller5.phpt" role="test" />
+ <file name="frontcontroller6.phpt" role="test" />
+ <file name="frontcontroller7.phpt" role="test" />
+ <file name="frontcontroller8.phpt" role="test" />
+ <file name="frontcontroller9.phpt" role="test" />
+ <file name="frontcontroller10.phpt" role="test" />
+ <file name="frontcontroller11.phpt" role="test" />
+ <file name="frontcontroller12.phpt" role="test" />
+ <file name="frontcontroller13.phpt" role="test" />
+ <file name="frontcontroller14.phpt" role="test" />
+ <file name="frontcontroller15.phpt" role="test" />
+ <file name="frontcontroller16.phpt" role="test" />
+ <file name="frontcontroller17.phpt" role="test" />
+ <file name="frontcontroller18.phpt" role="test" />
+ <file name="frontcontroller19.phpt" role="test" />
+ <file name="frontcontroller20.phpt" role="test" />
+ <file name="frontcontroller21.phpt" role="test" />
+ <file name="frontcontroller22.phpt" role="test" />
+ <file name="frontcontroller23.phpt" role="test" />
+ <file name="frontcontroller24.phpt" role="test" />
+ <file name="frontcontroller25.phpt" role="test" />
+ <file name="frontcontroller26.phpt" role="test" />
+ <file name="frontcontroller27.phpt" role="test" />
+ <file name="frontcontroller28.phpt" role="test" />
+ <file name="frontcontroller29.phpt" role="test" />
+ <file name="frontcontroller30.phpt" role="test" />
+ <file name="frontcontroller31.phpt" role="test" />
+ <file name="frontcontroller32.phpt" role="test" />
+ <file name="frontcontroller33.phpt" role="test" />
+ <file name="frontcontroller34.phpt" role="test" />
+ <file name="include_path.phpt" role="test" />
+ <file name="ini_set.phpt" role="test" />
+ <file name="ini_set_off.phpt" role="test" />
+ <file name="invalid_alias.phpt" role="test" />
+ <file name="invalid_setstubalias.phpt" role="test" />
+ <file name="metadata_read.phpt" role="test" />
+ <file name="metadata_write.phpt" role="test" />
+ <file name="metadata_write_commit.phpt" role="test" />
+ <file name="mkdir.phpt" role="test" />
+ <file name="mounteddir.phpt" role="test" />
+ <file name="nophar.phpt" role="test" />
+ <file name="nophar_web.phpt" role="test" />
+ <file name="opendir.phpt" role="test" />
+ <file name="opendir_edgecases.phpt" role="test" />
+ <file name="open_for_write_existing.phpt" role="test" />
+ <file name="open_for_write_existing_b.phpt" role="test" />
+ <file name="open_for_write_existing_c.phpt" role="test" />
+ <file name="open_for_write_newfile.phpt" role="test" />
+ <file name="open_for_write_newfile_b.phpt" role="test" />
+ <file name="open_for_write_newfile_c.phpt" role="test" />
+ <file name="pharfileinfo_chmod.phpt" role="test" />
+ <file name="pharfileinfo_compression.phpt" role="test" />
+ <file name="pharfileinfo_construct.phpt" role="test" />
+ <file name="pharfileinfo_destruct.phpt" role="test" />
+ <file name="pharfileinfo_getcrc32.phpt" role="test" />
+ <file name="pharfileinfo_setmetadata.phpt" role="test" />
+ <file name="phar_begin_setstub_commit.phpt" role="test" />
+ <file name="phar_buildfromdirectory1.phpt" role="test" />
+ <file name="phar_buildfromdirectory2.phpt" role="test" />
+ <file name="phar_buildfromdirectory3.phpt" role="test" />
+ <file name="phar_buildfromdirectory4.phpt" role="test" />
+ <file name="phar_buildfromdirectory5.phpt" role="test" />
+ <file name="phar_buildfromdirectory6.phpt" role="test" />
+ <file name="phar_buildfromiterator1.phpt" role="test" />
+ <file name="phar_buildfromiterator2.phpt" role="test" />
+ <file name="phar_buildfromiterator3.phpt" role="test" />
+ <file name="phar_buildfromiterator4.phpt" role="test" />
+ <file name="phar_buildfromiterator5.phpt" role="test" />
+ <file name="phar_buildfromiterator6.phpt" role="test" />
+ <file name="phar_buildfromiterator7.phpt" role="test" />
+ <file name="phar_buildfromiterator8.phpt" role="test" />
+ <file name="phar_buildfromiterator9.phpt" role="test" />
+ <file name="phar_buildfromiterator10.phpt" role="test" />
+ <file name="phar_bz2.phpt" role="test" />
+ <file name="phar_commitwrite.phpt" role="test" />
+ <file name="phar_convert_again.phpt" role="test" />
+ <file name="phar_convert_repeated.phpt" role="test" />
+ <file name="phar_convert_repeated_b.phpt" role="test" />
+ <file name="phar_convert_tar.phpt" role="test" />
+ <file name="phar_convert_tar2.phpt" role="test" />
+ <file name="phar_convert_tar3.phpt" role="test" />
+ <file name="phar_convert_zip.phpt" role="test" />
+ <file name="phar_copy.phpt" role="test" />
+ <file name="phar_createdefaultstub.phpt" role="test" />
+ <file name="phar_create_in_cwd.phpt" role="test" />
+ <file name="phar_ctx_001.phpt" role="test" />
+ <file name="phar_decompress.phpt" role="test" />
+ <file name="phar_dir_iterate.phpt" role="test" />
+ <file name="phar_extract.phpt" role="test" />
+ <file name="phar_get_supportedcomp1.phpt" role="test" />
+ <file name="phar_get_supportedcomp2.phpt" role="test" />
+ <file name="phar_get_supportedcomp3.phpt" role="test" />
+ <file name="phar_get_supportedcomp4.phpt" role="test" />
+ <file name="phar_get_supported_signatures_001.phpt" role="test" />
+ <file name="phar_get_supported_signatures_002.phpt" role="test" />
+ <file name="phar_gobyebye.phpt" role="test" />
+ <file name="phar_gzip.phpt" role="test" />
+ <file name="phar_isvalidpharfilename.phpt" role="test" />
+ <file name="phar_magic.phpt" role="test" />
+ <file name="phar_metadata_read.phpt" role="test" />
+ <file name="phar_metadata_write.phpt" role="test" />
+ <file name="phar_mount.phpt" role="test" />
+ <file name="phar_offset_get_error.phpt" role="test" />
+ <file name="phar_oo_001.phpt" role="test" />
+ <file name="phar_oo_002.phpt" role="test" />
+ <file name="phar_oo_003.phpt" role="test" />
+ <file name="phar_oo_004.phpt" role="test" />
+ <file name="phar_oo_005.phpt" role="test" />
+ <file name="phar_oo_006.phpt" role="test" />
+ <file name="phar_oo_007.phpt" role="test" />
+ <file name="phar_oo_008.phpt" role="test" />
+ <file name="phar_oo_009.phpt" role="test" />
+ <file name="phar_oo_010.phpt" role="test" />
+ <file name="phar_oo_011.phpt" role="test" />
+ <file name="phar_oo_011b.phpt" role="test" />
+ <file name="phar_oo_012.phpt" role="test" />
+ <file name="phar_oo_012b.phpt" role="test" />
+ <file name="phar_oo_012_confirm.phpt" role="test" />
+ <file name="phar_oo_compressallbz2.phpt" role="test" />
+ <file name="phar_oo_compressallgz.phpt" role="test" />
+ <file name="phar_oo_compressed_001.phpt" role="test" />
+ <file name="phar_oo_compressed_001b.phpt" role="test" />
+ <file name="phar_oo_compressed_002.phpt" role="test" />
+ <file name="phar_oo_compressed_002b.phpt" role="test" />
+ <file name="phar_oo_getcontents.phpt" role="test" />
+ <file name="phar_oo_getcontentsgz.phpt" role="test" />
+ <file name="phar_oo_getmodified.phpt" role="test" />
+ <file name="phar_oo_iswriteable.phpt" role="test" />
+ <file name="phar_oo_nosig.phpt" role="test" />
+ <file name="phar_oo_uncompressall.phpt" role="test" />
+ <file name="phar_running.phpt" role="test" />
+ <file name="phar_setalias.phpt" role="test" />
+ <file name="phar_setalias2.phpt" role="test" />
+ <file name="phar_setdefaultstub.phpt" role="test" />
+ <file name="phar_setsignaturealgo1.phpt" role="test" />
+ <file name="phar_setsignaturealgo2.phpt" role="test" />
+ <file name="phar_stub.phpt" role="test" />
+ <file name="phar_stub_error.phpt" role="test" />
+ <file name="phar_stub_write.phpt" role="test" />
+ <file name="phar_stub_write_file.phpt" role="test" />
+ <file name="phar_unlinkarchive.phpt" role="test" />
+ <file name="phpinfo_001.phpt" role="test" />
+ <file name="phpinfo_002.phpt" role="test" />
+ <file name="phpinfo_003.phpt" role="test" />
+ <file name="phpinfo_004.phpt" role="test" />
+ <file name="readfile.phpt" role="test" />
+ <file name="readfile_edgecases.phpt" role="test" />
+ <file name="refcount1.phpt" role="test" />
+ <file name="refcount1_5_2.phpt" role="test" />
+ <file name="rename.phpt" role="test" />
+ <file name="security.phpt" role="test" />
+ <file name="stat.phpt" role="test" />
+ <file name="stat2.phpt" role="test" />
+ <file name="stat2_5.3.phpt" role="test" />
+ <file name="test_alias_unset.phpt" role="test" />
+ <file name="test_signaturealgos.phpt" role="test" />
+ <file name="test_unset.phpt" role="test" />
+ <file name="webphar_compilefail.phpt" role="test" />
+ <file name="withphar.phpt" role="test" />
+ <file name="withphar_web.phpt" role="test" />
+ <file name="zf_test.phpt" role="test" />
+ </dir> <!-- /tests -->
+ <file name="build_precommand.php" role="php" />
+ <file name="cgidebug" role="data" />
+ <file name="config.m4" role="src" />
+ <file name="config.w32" role="src" />
+ <file name="CREDITS" role="doc" />
+ <file name="dirstream.c" role="src" />
+ <file name="dirstream.h" role="src" />
+ <file name="func_interceptors.c" role="src" />
+ <file name="func_interceptors.h" role="src" />
+ <file name="gdbhelp" role="data" />
+ <file name="LICENSE" role="doc" />
+ <file name="Makefile.frag" role="src" />
+ <file name="makestub.php" role="php" />
+ <file name="phar.c" role="src" />
+ <file name="phar.phar" role="script" />
+ <file name="pharzip.h" role="src" />
+ <file name="phar_internal.h" role="src" />
+ <file name="phar_object.c" role="src" />
+ <file name="phar_path_check.c" role="src" />
+ <file name="phar_path_check.re" role="src" />
+ <file name="php_phar.h" role="src" />
+ <file name="shortarc.php" role="php" />
+ <file name="stream.c" role="src" />
+ <file name="stream.h" role="src" />
+ <file name="stub.h" role="src" />
+ <file name="tar.c" role="src" />
+ <file name="tar.h" role="src" />
+ <file name="TODO" role="doc" />
+ <file name="util.c" role="src" />
+ <file name="zip.c" role="src" />
+ </dir> <!-- / -->
+ </contents>
+ <dependencies>
+ <required>
+ <php>
+ <min>5.2.0</min>
+ </php>
+ <pearinstaller>
+ <min>1.4.3</min>
+ </pearinstaller>
+ </required>
+ <optional>
+ <package>
+ <name>bz2</name>
+ <channel>pecl.php.net</channel>
+ <providesextension>bz2</providesextension>
+ </package>
+ <package>
+ <name>hash</name>
+ <channel>pecl.php.net</channel>
+ <providesextension>hash</providesextension>
+ </package>
+ <extension>
+ <name>spl</name>
+ </extension>
+ <extension>
+ <name>zlib</name>
+ </extension>
+ </optional>
+ </dependencies>
+ <providesextension>phar</providesextension>
+ <extsrcrelease />
+ <changelog>
+ <release>
+ <version>
+ <release>2.0.0b1</release>
+ <api>1.1.1</api>
+ </version>
+ <stability>
+ <release>beta</release>
+ <api>beta</api>
+ </stability>
+ <date>2008-05-12</date>
+ <license uri="http://www.php.net/license">PHP License</license>
+ <notes>
+
+BC BREAKING RELEASE
+ BC breaks:
+ * Phar object Compression API is rewritten. Use Phar::compress() and decompress(),
+ Phar::compressFiles()/decompressFiles() and PharFileInfo-&gt;compress()/decompress().
+ * phar.extract_list and Phar::getExtractList() are removed
+
+Major feature functionality release
+ * new default stub allows running of phar-based phars without phar extension [Greg/Steph]
+ * add support for tar-based and zip-based phar archives [Greg]
+ * add Phar::isFileFormat() [Greg]
+ * add Phar::convertToExecutable(), Phar::convertToData() [Greg]
+ * add Phar::compress() [Greg]
+ * rename Phar::compressAllFiles() to compressFiles(), uncompressAllFiles() to
+ decompressFiles() [Greg]
+ * conversion to compressed or to other file formats automatically copies the archive
+ to a new extension (i.e. &quot;.phar&quot; to &quot;.phar.tar&quot; or &quot;.tar&quot; to &quot;.tar.gz&quot;) [Steph]
+ * add Phar::webPhar() for running a web-based application unmodified
+ directly from a phar archive [Greg]
+ * file functions (fopen-based and stat-based) can be instructed to only look for
+ relative paths within a phar via Phar::interceptFileFuncs()
+ * add PharData class to allow manipulation/creation of non-executable tar and zip archives. [Steph]
+ non-executable tar/zip manipulation is allowed even when phar.readonly=1 [Greg]
+ * paths with . and .. work (phar://blah.phar/a/../b.php =&gt; phar://blah.phar/b.php) [Greg]
+ * add support for mkdir()/rmdir() and support for empty directories to phar file format [Greg]
+ * add option to compress the entire phar file for phar/tar file format [Greg]
+ * implement Phar::isCompressed() returning 0, Phar::GZ or Phar::BZ2 [Greg]
+ * implement Phar::copy(string $from, string $to) [Greg]
+ * implement Phar::running(), returns path or URL to currently executed phar
+ * implement Phar::buildFromIterator(Iterator $it[, string $base_directory]) [Greg]
+ * implement Phar::buildFromDirectory(string $base_directory[, string $regex]) [Steph]
+ * implement Phar::mount() for mounting external paths or files to locations inside a phar [Greg]
+ * add Phar::delete() [Greg]
+ * implement Phar::unlinkArchive() [Greg]
+
+Security addition
+ * aliases are validated so that they contain no directory separators as intended
+ * on conversion to other formats, user-supplied aliases are validated
+
+Changes since 2.0.0a2: many bugfixes, removal of phar.extract_list, compression API refactored,
+ conversion API refactored
+
+ </notes>
+ </release>
+ <release>
+ <version>
+ <release>2.0.0a2</release>
+ <api>1.1.1</api>
+ </version>
+ <stability>
+ <release>alpha</release>
+ <api>alpha</api>
+ </stability>
+ <date>2008-03-27</date>
+ <license uri="http://www.php.net/license">PHP License</license>
+ <notes>Major feature functionality release
+ * new default stub allows running of phar-based phars without phar extension [Greg/Steph]
+ * add support for tar-based and zip-based phar archives [Greg]
+ * add Phar::isTar(), Phar::isZip(), and Phar::isPhar() [Greg]
+ * add Phar::convertToTar(), Phar::convertToZip(), and Phar::convertToPhar() [Greg]
+ * add Phar::compress() [Greg]
+ * conversion to compressed or to other file formats automatically copies the archive
+ to a new extension (i.e. &quot;.phar&quot; to &quot;.phar.tar&quot; or &quot;.tar&quot; to &quot;.tar.gz&quot;) [Steph]
+ * add Phar::webPhar() for running a web-based application unmodified
+ directly from a phar archive [Greg]
+ * file functions (fopen-based and stat-based) can be instructed to only look for
+ relative paths within a phar via Phar::interceptFileFuncs()
+ * add PharData class to allow manipulation/creation of non-executable tar and zip archives. [Steph]
+ non-executable tar/zip manipulation is allowed even when phar.readonly=1 [Greg]
+ * paths with . and .. work (phar://blah.phar/a/../b.php =&gt; phar://blah.phar/b.php) [Greg]
+ * add support for mkdir()/rmdir() and support for empty directories to phar file format [Greg]
+ * add option to compress the entire phar file for phar/tar file format [Greg]
+ * implement Phar::isCompressed() returning 0, Phar::GZ or Phar::BZ2 [Greg]
+ * implement Phar::copy(string $from, string $to) [Greg]
+ * implement Phar::buildFromIterator(Iterator $it[, string $base_directory]) [Greg]
+ * implement Phar::mount() for mounting external paths or files to locations inside a phar [Greg]
+ * add Phar::delete() [Greg]
+
+Changes since 2.0.0a1: fix build in PHP 5.2</notes>
+ </release>
+ <release>
+ <version>
+ <release>2.0.0a1</release>
+ <api>1.1.1</api>
+ </version>
+ <stability>
+ <release>alpha</release>
+ <api>alpha</api>
+ </stability>
+ <date>2008-03-26</date>
+ <license uri="http://www.php.net/license">PHP License</license>
+ <notes>Major feature functionality release
+ * new default stub allows running of phar-based phars without phar extension [Greg/Steph]
+ * add support for tar-based and zip-based phar archives [Greg]
+ * add Phar::isTar(), Phar::isZip(), and Phar::isPhar() [Greg]
+ * add Phar::convertToTar(), Phar::convertToZip(), and Phar::convertToPhar() [Greg]
+ * add Phar::compress() [Greg]
+ * conversion to compressed or to other file formats automatically copies the archive
+ to a new extension (i.e. &quot;.phar&quot; to &quot;.phar.tar&quot; or &quot;.tar&quot; to &quot;.tar.gz&quot;) [Steph]
+ * add Phar::webPhar() for running a web-based application unmodified
+ directly from a phar archive [Greg]
+ * file functions (fopen-based and stat-based) can be instructed to only look for
+ relative paths within a phar via Phar::interceptFileFuncs()
+ * add PharData class to allow manipulation/creation of non-executable tar and zip archives. [Steph]
+ non-executable tar/zip manipulation is allowed even when phar.readonly=1 [Greg]
+ * paths with . and .. work (phar://blah.phar/a/../b.php =&gt; phar://blah.phar/b.php) [Greg]
+ * add support for mkdir()/rmdir() and support for empty directories to phar file format [Greg]
+ * add option to compress the entire phar file for phar/tar file format [Greg]
+ * implement Phar::isCompressed() returning 0, Phar::GZ or Phar::BZ2 [Greg]
+ * implement Phar::copy(string $from, string $to) [Greg]
+ * implement Phar::buildFromIterator(Iterator $it[, string $base_directory]) [Greg]
+ * implement Phar::mount() for mounting external paths or files to locations inside a phar [Greg]
+ * add Phar::delete() [Greg]</notes>
+ </release>
+ <release>
+ <version>
+ <release>1.2.1</release>
+ <api>1.1.0</api>
+ </version>
+ <stability>
+ <release>stable</release>
+ <api>stable</api>
+ </stability>
+ <date>2007-08-24</date>
+ <license uri="http://www.php.net/license">PHP License</license>
+ <notes>* add Phar::setAlias() [Greg]
+* fix too many open file handles issue [Greg]
+* fix rename [Greg]
+* add Phar::getAlias() [Marcus]
+* Made -a optional in pack subcommand of phar.phar [Marcus]
+* Fix issue with apache module and extracted archives [Marcus]
+* Send all error messages to stderr in phar.phar [Marcus]
+* Added new subcommands add and delete to phar.phar [Marcus]
+* Made Phar::loadPhar() and Phar::mapPhar() ignore extracted archives [Marcus]
+* Fix issue with compressed entries and uncompressing entries [Marcus]
+* Verify stubs before writing [Marcus]
+* Always use longest stub end to avoid issues with length field [Marcus]</notes>
+ </release>
+ <release>
+ <version>
+ <release>1.2.0</release>
+ <api>1.1.0</api>
+ </version>
+ <stability>
+ <release>stable</release>
+ <api>stable</api>
+ </stability>
+ <date>2007-05-18</date>
+ <license uri="http://www.php.net/license">PHP License</license>
+ <notes>* add PharFileInfo::hasMetadata(), PharFileInfo::delMetadata() [Marcus]
+* add Phar::hasMetadata(), Phar::delMetadata() [Marcus]
+* fix Phar::CanWrite() [Marcus]
+* add preliminary phar command (phar.php) [Marcus]
+* add phar command (phar.phar) [Marcus]
+* list all available compression methods using Phar::getSupportedCompression() [Marcus]
+* remove RINIT [Marcus]</notes>
+ </release>
+ <release>
+ <version>
+ <release>1.1.0</release>
+ <api>1.1.0</api>
+ </version>
+ <stability>
+ <release>stable</release>
+ <api>stable</api>
+ </stability>
+ <date>2007-04-12</date>
+ <license uri="http://www.php.net/license">PHP License</license>
+ <notes>* implement ability connect a phar file &apos;phar://whatever&apos; to a directory. That way all
+ access to that phar archive are directed to the extracted directory. This
+ allows to have the installed files and the archive keep the same includes.
+ [Marcus]
+* implement SHA-2 (256, 512) support [Marcus]
+* implement setSignatureAlgorithm() and Phar::MD5 Phar::SHA1 Phar::SHA256 Phar::SHA512 Phar::PGP to
+ choose the kind of signature to use (PGP falls back to SHA1) [Greg]</notes>
+ </release>
+ <release>
+ <version>
+ <release>1.0.1</release>
+ <api>1.0.1</api>
+ </version>
+ <stability>
+ <release>stable</release>
+ <api>stable</api>
+ </stability>
+ <date>2007-03-28</date>
+ <license uri="http://www.php.net/license">PHP License</license>
+ <notes>* Fix return value of unlink() and rename() when used for phar archievs. [Marcus]</notes>
+ </release>
+ <release>
+ <version>
+ <release>1.0.0</release>
+ <api>1.0.0</api>
+ </version>
+ <stability>
+ <release>stable</release>
+ <api>stable</api>
+ </stability>
+ <date>2007-03-26</date>
+ <license uri="http://www.php.net/license">PHP License</license>
+ <notes>*BACKWARDS COMPATIBILITY BREAK*
+Rename Phar-&gt;begin/isFlushingToPhar/commit to startBuffering/isBuffering/stopBuffering
+Note that isBuffering() returns the opposite value to isFlushingToPhar()</notes>
+ </release>
+ </changelog>
+</package>
diff --git a/ext/phar/phar.c b/ext/phar/phar.c
new file mode 100644
index 0000000000..ab2cb08ac4
--- /dev/null
+++ b/ext/phar/phar.c
@@ -0,0 +1,3091 @@
+/*
+ +----------------------------------------------------------------------+
+ | phar php single-file executable PHP extension |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 2005-2008 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt. |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gregory Beaver <cellog@php.net> |
+ | Marcus Boerger <helly@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#define PHAR_MAIN 1
+#include "phar_internal.h"
+#include "SAPI.h"
+#include "func_interceptors.h"
+
+ZEND_DECLARE_MODULE_GLOBALS(phar)
+int phar_has_bz2;
+int phar_has_zlib;
+#if PHP_VERSION_ID >= 50300
+char *(*phar_save_resolve_path)(const char *filename, int filename_len TSRMLS_DC);
+#endif
+
+/**
+ * set's phar->is_writeable based on the current INI value
+ */
+static int phar_set_writeable_bit(void *pDest, void *argument TSRMLS_DC) /* {{{ */
+{
+ zend_bool keep = *(zend_bool *)argument;
+ phar_archive_data *phar = *(phar_archive_data **)pDest;
+
+ if (!phar->is_data) {
+ phar->is_writeable = !keep;
+ }
+ return ZEND_HASH_APPLY_KEEP;
+}
+/* }}} */
+
+/* if the original value is 0 (disabled), then allow setting/unsetting at will
+ otherwise, only allow 1 (enabled), and error on disabling */
+ZEND_INI_MH(phar_ini_modify_handler) /* {{{ */
+{
+ zend_bool old, ini;
+
+ if (entry->name_length == 14) {
+ old = PHAR_G(readonly_orig);
+ } else {
+ old = PHAR_G(require_hash_orig);
+ }
+
+ if (new_value_length == 2 && !strcasecmp("on", new_value)) {
+ ini = (zend_bool) 1;
+ }
+ else if (new_value_length == 3 && !strcasecmp("yes", new_value)) {
+ ini = (zend_bool) 1;
+ }
+ else if (new_value_length == 4 && !strcasecmp("true", new_value)) {
+ ini = (zend_bool) 1;
+ }
+ else {
+ ini = (zend_bool) atoi(new_value);
+ }
+
+ /* do not allow unsetting in runtime */
+ if (stage == ZEND_INI_STAGE_STARTUP) {
+ if (entry->name_length == 14) {
+ PHAR_G(readonly_orig) = ini;
+ } else {
+ PHAR_G(require_hash_orig) = ini;
+ }
+ } else if (old && !ini) {
+ return FAILURE;
+ }
+
+ if (entry->name_length == 14) {
+ PHAR_G(readonly) = ini;
+ if (PHAR_GLOBALS->request_init && PHAR_GLOBALS->phar_fname_map.arBuckets) {
+ zend_hash_apply_with_argument(&(PHAR_GLOBALS->phar_fname_map), phar_set_writeable_bit, (void *)&ini TSRMLS_CC);
+ }
+ } else {
+ PHAR_G(require_hash) = ini;
+ }
+ return SUCCESS;
+}
+/* }}}*/
+
+PHP_INI_BEGIN()
+ STD_PHP_INI_BOOLEAN( "phar.readonly", "1", PHP_INI_ALL, phar_ini_modify_handler, readonly, zend_phar_globals, phar_globals)
+ STD_PHP_INI_BOOLEAN( "phar.require_hash", "1", PHP_INI_ALL, phar_ini_modify_handler, require_hash, zend_phar_globals, phar_globals)
+PHP_INI_END()
+
+/**
+ * When all uses of a phar have been concluded, this frees the manifest
+ * and the phar slot
+ */
+static void phar_destroy_phar_data(phar_archive_data *phar TSRMLS_DC) /* {{{ */
+{
+ if (phar->alias && phar->alias != phar->fname) {
+ efree(phar->alias);
+ phar->alias = NULL;
+ }
+ if (phar->fname) {
+ efree(phar->fname);
+ phar->fname = NULL;
+ }
+ if (phar->signature) {
+ efree(phar->signature);
+ }
+ if (phar->manifest.arBuckets) {
+ zend_hash_destroy(&phar->manifest);
+ phar->manifest.arBuckets = NULL;
+ }
+ if (phar->mounted_dirs.arBuckets) {
+ zend_hash_destroy(&phar->mounted_dirs);
+ phar->mounted_dirs.arBuckets = NULL;
+ }
+ if (phar->metadata) {
+ zval_ptr_dtor(&phar->metadata);
+ phar->metadata = 0;
+ }
+ if (phar->fp) {
+ php_stream_close(phar->fp);
+ phar->fp = 0;
+ }
+ if (phar->ufp) {
+ php_stream_close(phar->ufp);
+ phar->fp = 0;
+ }
+ efree(phar);
+}
+/* }}}*/
+
+/**
+ * Delete refcount and destruct if needed. On destruct return 1 else 0.
+ */
+int phar_archive_delref(phar_archive_data *phar TSRMLS_DC) /* {{{ */
+{
+ if (--phar->refcount < 0) {
+ if (PHAR_GLOBALS->request_done
+ || zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), phar->fname, phar->fname_len) != SUCCESS) {
+ phar_destroy_phar_data(phar TSRMLS_CC);
+ }
+ return 1;
+ } else if (!phar->refcount) {
+ if (phar->fp && !(phar->flags & PHAR_FILE_COMPRESSION_MASK)) {
+ /* close open file handle - allows removal or rename of
+ the file on windows, which has greedy locking
+ only close if the archive was not already compressed. If it
+ was compressed, then the fp does not refer to the original file */
+ php_stream_close(phar->fp);
+ phar->fp = NULL;
+ }
+ if (!zend_hash_num_elements(&phar->manifest)) {
+ /* this is a new phar that has perhaps had an alias/metadata set, but has never
+ been flushed */
+ if (zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), phar->fname, phar->fname_len) != SUCCESS) {
+ phar_destroy_phar_data(phar TSRMLS_CC);
+ }
+ return 1;
+ }
+ }
+ return 0;
+}
+/* }}}*/
+
+/**
+ * Destroy phar's in shutdown, here we don't care about aliases
+ */
+static void destroy_phar_data_only(void *pDest) /* {{{ */
+{
+ phar_archive_data *phar_data = *(phar_archive_data **) pDest;
+ TSRMLS_FETCH();
+
+ if (EG(exception) || --phar_data->refcount < 0) {
+ phar_destroy_phar_data(phar_data TSRMLS_CC);
+ }
+}
+/* }}}*/
+
+/**
+ * Delete aliases to phar's that got kicked out of the global table
+ */
+static int phar_unalias_apply(void *pDest, void *argument TSRMLS_DC) /* {{{ */
+{
+ return *(void**)pDest == argument ? ZEND_HASH_APPLY_REMOVE : ZEND_HASH_APPLY_KEEP;
+}
+/* }}} */
+
+/**
+ * Delete aliases to phar's that got kicked out of the global table
+ */
+static int phar_tmpclose_apply(void *pDest TSRMLS_DC) /* {{{ */
+{
+ phar_entry_info *entry = (phar_entry_info *) pDest;
+
+ if (entry->fp_type != PHAR_TMP) {
+ return ZEND_HASH_APPLY_KEEP;
+ }
+ if (entry->fp && !entry->fp_refcount) {
+ php_stream_close(entry->fp);
+ entry->fp = NULL;
+ }
+ return ZEND_HASH_APPLY_KEEP;
+}
+/* }}} */
+
+/**
+ * Filename map destructor
+ */
+static void destroy_phar_data(void *pDest) /* {{{ */
+{
+ phar_archive_data *phar_data = *(phar_archive_data **) pDest;
+ TSRMLS_FETCH();
+
+ if (PHAR_GLOBALS->request_ends) {
+ /* first, iterate over the manifest and close all PHAR_TMP entry fp handles,
+ this prevents unnecessary unfreed stream resources */
+ zend_hash_apply(&(phar_data->manifest), phar_tmpclose_apply TSRMLS_CC);
+ destroy_phar_data_only(pDest);
+ return;
+ }
+ zend_hash_apply_with_argument(&(PHAR_GLOBALS->phar_alias_map), phar_unalias_apply, phar_data TSRMLS_CC);
+ if (--phar_data->refcount < 0) {
+ phar_destroy_phar_data(phar_data TSRMLS_CC);
+ }
+}
+/* }}}*/
+
+/**
+ * destructor for the manifest hash, frees each file's entry
+ */
+void destroy_phar_manifest_entry(void *pDest) /* {{{ */
+{
+ phar_entry_info *entry = (phar_entry_info *)pDest;
+ TSRMLS_FETCH();
+
+ if (entry->cfp) {
+ php_stream_close(entry->cfp);
+ entry->cfp = 0;
+ }
+ if (entry->fp) {
+ php_stream_close(entry->fp);
+ entry->fp = 0;
+ }
+ if (entry->metadata) {
+ zval_ptr_dtor(&entry->metadata);
+ entry->metadata = 0;
+ }
+ if (entry->metadata_str.c) {
+ smart_str_free(&entry->metadata_str);
+ entry->metadata_str.c = 0;
+ }
+ efree(entry->filename);
+ if (entry->link) {
+ efree(entry->link);
+ entry->link = 0;
+ }
+ if (entry->tmp) {
+ efree(entry->tmp);
+ entry->tmp = 0;
+ }
+}
+/* }}} */
+
+int phar_entry_delref(phar_entry_data *idata TSRMLS_DC) /* {{{ */
+{
+ int ret = 0;
+
+ if (idata->internal_file) {
+ if (--idata->internal_file->fp_refcount < 0) {
+ idata->internal_file->fp_refcount = 0;
+ }
+ if (idata->fp && idata->fp != idata->phar->fp && idata->fp != idata->phar->ufp && idata->fp != idata->internal_file->fp) {
+ php_stream_close(idata->fp);
+ }
+ }
+ phar_archive_delref(idata->phar TSRMLS_CC);
+ efree(idata);
+ return ret;
+}
+/* }}} */
+
+/**
+ * Removes an entry, either by actually removing it or by marking it.
+ */
+void phar_entry_remove(phar_entry_data *idata, char **error TSRMLS_DC) /* {{{ */
+{
+ phar_archive_data *phar;
+
+ phar = idata->phar;
+ if (idata->internal_file->fp_refcount < 2) {
+ if (idata->fp && idata->fp != idata->phar->fp && idata->fp != idata->phar->ufp && idata->fp != idata->internal_file->fp) {
+ php_stream_close(idata->fp);
+ }
+ zend_hash_del(&idata->phar->manifest, idata->internal_file->filename, idata->internal_file->filename_len);
+ idata->phar->refcount--;
+ efree(idata);
+ } else {
+ idata->internal_file->is_deleted = 1;
+ phar_entry_delref(idata TSRMLS_CC);
+ }
+ if (!phar->donotflush) {
+ phar_flush(phar, 0, 0, 0, error TSRMLS_CC);
+ }
+}
+/* }}} */
+
+#define MAPPHAR_ALLOC_FAIL(msg) \
+ if (fp) {\
+ php_stream_close(fp);\
+ }\
+ if (error) {\
+ spprintf(error, 0, msg, fname);\
+ }\
+ return FAILURE;
+
+#define MAPPHAR_FAIL(msg) \
+ efree(savebuf);\
+ if (mydata) {\
+ phar_destroy_phar_data(mydata TSRMLS_CC);\
+ }\
+ if (signature) {\
+ efree(signature);\
+ }\
+ MAPPHAR_ALLOC_FAIL(msg)
+
+#ifdef WORDS_BIGENDIAN
+# define PHAR_GET_32(buffer, var) \
+ var = ((((unsigned char*)(buffer))[3]) << 24) \
+ | ((((unsigned char*)(buffer))[2]) << 16) \
+ | ((((unsigned char*)(buffer))[1]) << 8) \
+ | (((unsigned char*)(buffer))[0]); \
+ (buffer) += 4
+# define PHAR_GET_16(buffer, var) \
+ var = ((((unsigned char*)(buffer))[1]) << 8) \
+ | (((unsigned char*)(buffer))[0]); \
+ (buffer) += 2
+# define PHAR_ZIP_32(buffer) ((((unsigned char*)(buffer))[3]) << 24) \
+ | ((((unsigned char*)(buffer))[2]) << 16) \
+ | ((((unsigned char*)(buffer))[1]) << 8) \
+ | (((unsigned char*)(buffer))[0])
+# define PHAR_ZIP_16(buffer) ((((unsigned char*)(buffer))[1]) << 8) \
+ | (((unsigned char*)(buffer))[0])
+#else
+# define PHAR_GET_32(buffer, var) \
+ var = *(php_uint32*)(buffer); \
+ buffer += 4
+# define PHAR_GET_16(buffer, var) \
+ var = *(php_uint16*)(buffer); \
+ buffer += 2
+# define PHAR_ZIP_32(buffer) buffer
+# define PHAR_ZIP_16(buffer) buffer
+#endif
+
+/**
+ * Open an already loaded phar
+ */
+int phar_open_loaded(char *fname, int fname_len, char *alias, int alias_len, int is_data, int options, phar_archive_data** pphar, char **error TSRMLS_DC) /* {{{ */
+{
+ phar_archive_data *phar;
+#ifdef PHP_WIN32
+ char *unixfname;
+#endif
+
+ if (error) {
+ *error = NULL;
+ }
+#ifdef PHP_WIN32
+ unixfname = estrndup(fname, fname_len);
+ phar_unixify_path_separators(unixfname, fname_len);
+ if (SUCCESS == phar_get_archive(&phar, unixfname, fname_len, alias, alias_len, error TSRMLS_CC)
+ && ((alias && fname_len == phar->fname_len
+ && !strncmp(unixfname, phar->fname, fname_len)) || !alias)
+ ) {
+ phar_entry_info *stub;
+ efree(unixfname);
+#else
+ if (SUCCESS == phar_get_archive(&phar, fname, fname_len, alias, alias_len, error TSRMLS_CC)
+ && ((alias && fname_len == phar->fname_len
+ && !strncmp(fname, phar->fname, fname_len)) || !alias)
+ ) {
+ phar_entry_info *stub;
+#endif
+ /* logic above is as follows:
+ If an explicit alias was requested, ensure the filename passed in
+ matches the phar's filename.
+ If no alias was passed in, then it can match either and be valid
+ */
+
+ if (!is_data) {
+ /* prevent any ".phar" without a stub getting through */
+ if (!phar->halt_offset && !phar->is_brandnew && (phar->is_tar || phar->is_zip)) {
+ if (PHAR_G(readonly) && FAILURE == zend_hash_find(&(phar->manifest), ".phar/stub.php", sizeof(".phar/stub.php")-1, (void **)&stub)) {
+ if (error) {
+ spprintf(error, 0, "'%s' is not a phar archive. Use PharData::__construct() for a standard zip or tar archive", fname);
+ }
+ return FAILURE;
+ }
+ }
+ }
+ phar->is_data = is_data && (phar->is_tar || phar->is_zip);
+ if (pphar) {
+ *pphar = phar;
+ }
+ return SUCCESS;
+ } else {
+#ifdef PHP_WIN32
+ efree(unixfname);
+#endif
+ if (pphar) {
+ *pphar = NULL;
+ }
+ if (phar && error && !(options & REPORT_ERRORS)) {
+ efree(error);
+ }
+ return FAILURE;
+ }
+}
+/* }}}*/
+
+/**
+ * Parse out metadata from the manifest for a single file
+ *
+ * Meta-data is in this format:
+ * [len32][data...]
+ *
+ * data is the serialized zval
+ */
+int phar_parse_metadata(char **buffer, zval **metadata, int zip_metadata_len TSRMLS_DC) /* {{{ */
+{
+ const unsigned char *p;
+ php_uint32 buf_len;
+ php_unserialize_data_t var_hash;
+
+ if (!zip_metadata_len) {
+ PHAR_GET_32(*buffer, buf_len);
+ } else {
+ buf_len = zip_metadata_len;
+ }
+
+ if (buf_len) {
+ ALLOC_INIT_ZVAL(*metadata);
+ p = (const unsigned char*) *buffer;
+ PHP_VAR_UNSERIALIZE_INIT(var_hash);
+ if (!php_var_unserialize(metadata, &p, p + buf_len, &var_hash TSRMLS_CC)) {
+ PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
+ zval_ptr_dtor(metadata);
+ *metadata = NULL;
+ return FAILURE;
+ }
+ PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
+ } else {
+ *metadata = NULL;
+ }
+ if (!zip_metadata_len) {
+ *buffer += buf_len;
+ }
+ return SUCCESS;
+}
+/* }}}*/
+
+static const char hexChars[] = "0123456789ABCDEF";
+
+static int phar_hex_str(const char *digest, size_t digest_len, char ** signature)
+{
+ int pos = -1;
+ size_t len;
+
+ *signature = (char*)safe_emalloc(digest_len, 2, 1);
+
+ for(len = 0; len < digest_len; ++len) {
+ (*signature)[++pos] = hexChars[((const unsigned char *)digest)[len] >> 4];
+ (*signature)[++pos] = hexChars[((const unsigned char *)digest)[len] & 0x0F];
+ }
+ (*signature)[++pos] = '\0';
+ return pos;
+}
+
+/**
+ * Does not check for a previously opened phar in the cache.
+ *
+ * Parse a new one and add it to the cache, returning either SUCCESS or
+ * FAILURE, and setting pphar to the pointer to the manifest entry
+ *
+ * This is used by phar_open_filename to process the manifest, but can be called
+ * directly.
+ */
+int phar_open_file(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) /* {{{ */
+{
+ char b32[4], *buffer, *endbuffer, *savebuf;
+ phar_archive_data *mydata = NULL;
+ phar_entry_info entry;
+ php_uint32 manifest_len, manifest_count, manifest_flags, manifest_index, tmp_len, sig_flags;
+ php_uint16 manifest_ver;
+ long offset;
+ int register_alias, sig_len, temp_alias = 0;
+ char *signature = NULL;
+
+ if (pphar) {
+ *pphar = NULL;
+ }
+ if (error) {
+ *error = NULL;
+ }
+
+ /* check for ?>\n and increment accordingly */
+ if (-1 == php_stream_seek(fp, halt_offset, SEEK_SET)) {
+ MAPPHAR_ALLOC_FAIL("cannot seek to __HALT_COMPILER(); location in phar \"%s\"")
+ }
+
+ buffer = b32;
+ if (3 != php_stream_read(fp, buffer, 3)) {
+ MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated manifest at stub end)")
+ }
+ if ((*buffer == ' ' || *buffer == '\n') && *(buffer + 1) == '?' && *(buffer + 2) == '>') {
+ int nextchar;
+ halt_offset += 3;
+ if (EOF == (nextchar = php_stream_getc(fp))) {
+ MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated manifest at stub end)")
+ }
+ if ((char) nextchar == '\r') {
+ /* if we have an \r we require an \n as well */
+ if (EOF == (nextchar = php_stream_getc(fp)) || (char)nextchar != '\n') {
+ MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated manifest at stub end)")
+ }
+ ++halt_offset;
+ }
+ if ((char) nextchar == '\n') {
+ ++halt_offset;
+ }
+ }
+ /* make sure we are at the right location to read the manifest */
+ if (-1 == php_stream_seek(fp, halt_offset, SEEK_SET)) {
+ MAPPHAR_ALLOC_FAIL("cannot seek to __HALT_COMPILER(); location in phar \"%s\"")
+ }
+
+ /* read in manifest */
+ buffer = b32;
+ if (4 != php_stream_read(fp, buffer, 4)) {
+ MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated manifest at manifest length)")
+ }
+ PHAR_GET_32(buffer, manifest_len);
+ if (manifest_len > 1048576 * 100) {
+ /* prevent serious memory issues by limiting manifest to at most 100 MB in length */
+ MAPPHAR_ALLOC_FAIL("manifest cannot be larger than 100 MB in phar \"%s\"")
+ }
+ buffer = (char *)emalloc(manifest_len);
+ savebuf = buffer;
+ endbuffer = buffer + manifest_len;
+ if (manifest_len < 10 || manifest_len != php_stream_read(fp, buffer, manifest_len)) {
+ MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest header)")
+ }
+
+ /* extract the number of entries */
+ PHAR_GET_32(buffer, manifest_count);
+ if (manifest_count == 0) {
+ MAPPHAR_FAIL("in phar \"%s\", manifest claims to have zero entries. Phars must have at least 1 entry");
+ }
+
+ /* extract API version, lowest nibble currently unused */
+ manifest_ver = (((unsigned char)buffer[0]) << 8)
+ + ((unsigned char)buffer[1]);
+ buffer += 2;
+ if ((manifest_ver & PHAR_API_VER_MASK) < PHAR_API_MIN_READ) {
+ efree(savebuf);
+ php_stream_close(fp);
+ if (error) {
+ 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);
+ }
+ return FAILURE;
+ }
+
+ PHAR_GET_32(buffer, manifest_flags);
+
+ manifest_flags &= ~PHAR_HDR_COMPRESSION_MASK;
+
+ manifest_flags &= ~PHAR_FILE_COMPRESSION_MASK;
+ /* remember whether this entire phar was compressed with gz/bzip2 */
+ manifest_flags |= compression;
+
+ /* The lowest nibble contains the phar wide flags. The compression flags can */
+ /* be ignored on reading because it is being generated anyways. */
+ if (manifest_flags & PHAR_HDR_SIGNATURE) {
+ unsigned char buf[1024];
+ int read_size, len;
+ char sig_buf[8], *sig_ptr = sig_buf;
+ off_t read_len;
+
+ if (-1 == php_stream_seek(fp, -8, SEEK_END)
+ || (read_len = php_stream_tell(fp)) < 20
+ || 8 != php_stream_read(fp, sig_buf, 8)
+ || memcmp(sig_buf+4, "GBMB", 4)) {
+ efree(savebuf);
+ php_stream_close(fp);
+ if (error) {
+ spprintf(error, 0, "phar \"%s\" has a broken signature", fname);
+ }
+ return FAILURE;
+ }
+ PHAR_GET_32(sig_ptr, sig_flags);
+ switch(sig_flags) {
+#if HAVE_HASH_EXT
+ case PHAR_SIG_SHA512: {
+ unsigned char digest[64], saved[64];
+ PHP_SHA512_CTX context;
+
+ php_stream_rewind(fp);
+ PHP_SHA512Init(&context);
+ read_len -= sizeof(digest);
+ if (read_len > sizeof(buf)) {
+ read_size = sizeof(buf);
+ } else {
+ read_size = (int)read_len;
+ }
+ while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
+ PHP_SHA512Update(&context, buf, len);
+ read_len -= (off_t)len;
+ if (read_len < read_size) {
+ read_size = (int)read_len;
+ }
+ }
+ PHP_SHA512Final(digest, &context);
+
+ if (read_len > 0
+ || php_stream_read(fp, (char*)saved, sizeof(saved)) != sizeof(saved)
+ || memcmp(digest, saved, sizeof(digest))) {
+ efree(savebuf);
+ php_stream_close(fp);
+ if (error) {
+ spprintf(error, 0, "phar \"%s\" has a broken signature", fname);
+ }
+ return FAILURE;
+ }
+
+ sig_len = phar_hex_str((const char*)digest, sizeof(digest), &signature);
+ break;
+ }
+ case PHAR_SIG_SHA256: {
+ unsigned char digest[32], saved[32];
+ PHP_SHA256_CTX context;
+
+ php_stream_rewind(fp);
+ PHP_SHA256Init(&context);
+ read_len -= sizeof(digest);
+ if (read_len > sizeof(buf)) {
+ read_size = sizeof(buf);
+ } else {
+ read_size = (int)read_len;
+ }
+ while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
+ PHP_SHA256Update(&context, buf, len);
+ read_len -= (off_t)len;
+ if (read_len < read_size) {
+ read_size = (int)read_len;
+ }
+ }
+ PHP_SHA256Final(digest, &context);
+
+ if (read_len > 0
+ || php_stream_read(fp, (char*)saved, sizeof(saved)) != sizeof(saved)
+ || memcmp(digest, saved, sizeof(digest))) {
+ efree(savebuf);
+ php_stream_close(fp);
+ if (error) {
+ spprintf(error, 0, "phar \"%s\" has a broken signature", fname);
+ }
+ return FAILURE;
+ }
+
+ sig_len = phar_hex_str((const char*)digest, sizeof(digest), &signature);
+ break;
+ }
+#else
+ case PHAR_SIG_SHA512:
+ case PHAR_SIG_SHA256:
+ efree(savebuf);
+ php_stream_close(fp);
+ if (error) {
+ spprintf(error, 0, "phar \"%s\" has a unsupported signature", fname);
+ }
+ return FAILURE;
+#endif
+ case PHAR_SIG_SHA1: {
+ unsigned char digest[20], saved[20];
+ PHP_SHA1_CTX context;
+
+ php_stream_rewind(fp);
+ PHP_SHA1Init(&context);
+ read_len -= sizeof(digest);
+ if (read_len > sizeof(buf)) {
+ read_size = sizeof(buf);
+ } else {
+ read_size = (int)read_len;
+ }
+ while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
+ PHP_SHA1Update(&context, buf, len);
+ read_len -= (off_t)len;
+ if (read_len < read_size) {
+ read_size = (int)read_len;
+ }
+ }
+ PHP_SHA1Final(digest, &context);
+
+ if (read_len > 0
+ || php_stream_read(fp, (char*)saved, sizeof(saved)) != sizeof(saved)
+ || memcmp(digest, saved, sizeof(digest))) {
+ efree(savebuf);
+ php_stream_close(fp);
+ if (error) {
+ spprintf(error, 0, "phar \"%s\" has a broken signature", fname);
+ }
+ return FAILURE;
+ }
+
+ sig_len = phar_hex_str((const char*)digest, sizeof(digest), &signature);
+ break;
+ }
+ case PHAR_SIG_MD5: {
+ unsigned char digest[16], saved[16];
+ PHP_MD5_CTX context;
+
+ php_stream_rewind(fp);
+ PHP_MD5Init(&context);
+ read_len -= sizeof(digest);
+ if (read_len > sizeof(buf)) {
+ read_size = sizeof(buf);
+ } else {
+ read_size = (int)read_len;
+ }
+ while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
+ PHP_MD5Update(&context, buf, len);
+ read_len -= (off_t)len;
+ if (read_len < read_size) {
+ read_size = (int)read_len;
+ }
+ }
+ PHP_MD5Final(digest, &context);
+
+ if (read_len > 0
+ || php_stream_read(fp, (char*)saved, sizeof(saved)) != sizeof(saved)
+ || memcmp(digest, saved, sizeof(digest))) {
+ efree(savebuf);
+ php_stream_close(fp);
+ if (error) {
+ spprintf(error, 0, "phar \"%s\" has a broken signature", fname);
+ }
+ return FAILURE;
+ }
+
+ sig_len = phar_hex_str((const char*)digest, sizeof(digest), &signature);
+ break;
+ }
+ default:
+ efree(savebuf);
+ php_stream_close(fp);
+ if (error) {
+ spprintf(error, 0, "phar \"%s\" has a broken or unsupported signature", fname);
+ }
+ return FAILURE;
+ }
+ } else if (PHAR_G(require_hash)) {
+ efree(savebuf);
+ php_stream_close(fp);
+ if (error) {
+ spprintf(error, 0, "phar \"%s\" does not have a signature", fname);
+ }
+ return FAILURE;
+ } else {
+ sig_flags = 0;
+ sig_len = 0;
+ }
+
+ /* extract alias */
+ PHAR_GET_32(buffer, tmp_len);
+ if (buffer + tmp_len > endbuffer) {
+ MAPPHAR_FAIL("internal corruption of phar \"%s\" (buffer overrun)");
+ }
+ if (manifest_len < 10 + tmp_len) {
+ MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest header)")
+ }
+ /* tmp_len = 0 says alias length is 0, which means the alias is not stored in the phar */
+ if (tmp_len) {
+ /* if the alias is stored we enforce it (implicit overrides explicit) */
+ if (alias && alias_len && (alias_len != (int)tmp_len || strncmp(alias, buffer, tmp_len)))
+ {
+ buffer[tmp_len] = '\0';
+ php_stream_close(fp);
+ if (signature) {
+ efree(signature);
+ }
+ if (error) {
+ spprintf(error, 0, "cannot load phar \"%s\" with implicit alias \"%s\" under different alias \"%s\"", fname, buffer, alias);
+ }
+ efree(savebuf);
+ return FAILURE;
+ }
+ alias_len = tmp_len;
+ alias = buffer;
+ buffer += tmp_len;
+ register_alias = 1;
+ } else if (!alias_len || !alias) {
+ /* if we neither have an explicit nor an implicit alias, we use the filename */
+ alias = NULL;
+ alias_len = 0;
+ register_alias = 0;
+ } else if (alias_len) {
+ register_alias = 1;
+ temp_alias = 1;
+ }
+
+ /* we have 5 32-bit items plus 1 byte at least */
+ if (manifest_count > ((manifest_len - 10 - tmp_len) / (5 * 4 + 1))) {
+ /* prevent serious memory issues */
+ MAPPHAR_FAIL("internal corruption of phar \"%s\" (too many manifest entries for size of manifest)")
+ }
+
+ mydata = ecalloc(sizeof(phar_archive_data), 1);
+
+ /* check whether we have meta data, zero check works regardless of byte order */
+ if (phar_parse_metadata(&buffer, &mydata->metadata, 0 TSRMLS_CC) == FAILURE) {
+ MAPPHAR_FAIL("unable to read phar metadata in .phar file \"%s\"");
+ }
+
+ /* set up our manifest */
+ zend_hash_init(&mydata->manifest, sizeof(phar_entry_info),
+ zend_get_hash_value, destroy_phar_manifest_entry, 0);
+ zend_hash_init(&mydata->mounted_dirs, sizeof(char *),
+ zend_get_hash_value, NULL, 0);
+ offset = halt_offset + manifest_len + 4;
+ memset(&entry, 0, sizeof(phar_entry_info));
+ entry.phar = mydata;
+ entry.fp_type = PHAR_FP;
+
+ for (manifest_index = 0; manifest_index < manifest_count; ++manifest_index) {
+ if (buffer + 4 > endbuffer) {
+ MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest entry)")
+ }
+ PHAR_GET_32(buffer, entry.filename_len);
+ if (entry.filename_len == 0) {
+ MAPPHAR_FAIL("zero-length filename encountered in phar \"%s\"");
+ }
+ if (buffer + entry.filename_len + 20 > endbuffer) {
+ MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest entry)");
+ }
+ if ((manifest_ver & PHAR_API_VER_MASK) >= PHAR_API_MIN_DIR && buffer[entry.filename_len - 1] == '/') {
+ entry.is_dir = 1;
+ } else {
+ entry.is_dir = 0;
+ }
+ entry.filename = estrndup(buffer, entry.filename_len);
+ buffer += entry.filename_len;
+ PHAR_GET_32(buffer, entry.uncompressed_filesize);
+ PHAR_GET_32(buffer, entry.timestamp);
+ if (offset == halt_offset + (int)manifest_len + 4) {
+ mydata->min_timestamp = entry.timestamp;
+ mydata->max_timestamp = entry.timestamp;
+ } else {
+ if (mydata->min_timestamp > entry.timestamp) {
+ mydata->min_timestamp = entry.timestamp;
+ } else if (mydata->max_timestamp < entry.timestamp) {
+ mydata->max_timestamp = entry.timestamp;
+ }
+ }
+ PHAR_GET_32(buffer, entry.compressed_filesize);
+ PHAR_GET_32(buffer, entry.crc32);
+ PHAR_GET_32(buffer, entry.flags);
+ if (entry.is_dir) {
+ entry.filename_len--;
+ entry.flags |= PHAR_ENT_PERM_DEF_DIR;
+ }
+ if (phar_parse_metadata(&buffer, &entry.metadata, 0 TSRMLS_CC) == FAILURE) {
+ efree(entry.filename);
+ MAPPHAR_FAIL("unable to read file metadata in .phar file \"%s\"");
+ }
+ entry.offset = entry.offset_abs = offset;
+ offset += entry.compressed_filesize;
+ switch (entry.flags & PHAR_ENT_COMPRESSION_MASK) {
+ case PHAR_ENT_COMPRESSED_GZ:
+ if (!phar_has_zlib) {
+ if (entry.metadata) {
+ zval_ptr_dtor(&entry.metadata);
+ }
+ efree(entry.filename);
+ MAPPHAR_FAIL("zlib extension is required for gz compressed .phar file \"%s\"");
+ }
+ break;
+ case PHAR_ENT_COMPRESSED_BZ2:
+ if (!phar_has_bz2) {
+ if (entry.metadata) {
+ zval_ptr_dtor(&entry.metadata);
+ }
+ efree(entry.filename);
+ MAPPHAR_FAIL("bz2 extension is required for bzip2 compressed .phar file \"%s\"");
+ }
+ break;
+ default:
+ if (entry.uncompressed_filesize != entry.compressed_filesize) {
+ if (entry.metadata) {
+ zval_ptr_dtor(&entry.metadata);
+ }
+ efree(entry.filename);
+ MAPPHAR_FAIL("internal corruption of phar \"%s\" (compressed and uncompressed size does not match for uncompressed entry)");
+ }
+ break;
+ }
+ manifest_flags |= (entry.flags & PHAR_ENT_COMPRESSION_MASK);
+ /* if signature matched, no need to check CRC32 for each file */
+ entry.is_crc_checked = (manifest_flags & PHAR_HDR_SIGNATURE ? 1 : 0);
+ zend_hash_add(&mydata->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL);
+ }
+
+ snprintf(mydata->version, sizeof(mydata->version), "%u.%u.%u", manifest_ver >> 12, (manifest_ver >> 8) & 0xF, (manifest_ver >> 4) & 0xF);
+ mydata->internal_file_start = halt_offset + manifest_len + 4;
+ mydata->halt_offset = halt_offset;
+ mydata->flags = manifest_flags;
+ mydata->fp = fp;
+ mydata->fname = estrndup(fname, fname_len);
+#ifdef PHP_WIN32
+ phar_unixify_path_separators(mydata->fname, fname_len);
+#endif
+ mydata->fname_len = fname_len;
+ endbuffer = strrchr(mydata->fname, '/');
+ if (endbuffer) {
+ mydata->ext = memchr(endbuffer, '.', (mydata->fname + fname_len) - endbuffer);
+ if (mydata->ext == endbuffer) {
+ mydata->ext = memchr(endbuffer + 1, '.', (mydata->fname + fname_len) - endbuffer - 1);
+ }
+ if (mydata->ext) {
+ mydata->ext_len = (mydata->fname + mydata->fname_len) - mydata->ext;
+ }
+ }
+ mydata->alias = alias ? estrndup(alias, alias_len) : estrndup(mydata->fname, fname_len);
+ mydata->alias_len = alias ? alias_len : fname_len;
+ mydata->sig_flags = sig_flags;
+ mydata->sig_len = sig_len;
+ mydata->signature = signature;
+ phar_request_initialize(TSRMLS_C);
+ if (register_alias) {
+ phar_archive_data **fd_ptr;
+
+ mydata->is_temporary_alias = temp_alias;
+ if (!phar_validate_alias(mydata->alias, mydata->alias_len)) {
+ signature = NULL;
+ fp = NULL;
+ MAPPHAR_FAIL("Cannot open archive \"%s\", invalid alias");
+ }
+ if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void **)&fd_ptr)) {
+ if (SUCCESS != phar_free_alias(*fd_ptr, alias, alias_len TSRMLS_CC)) {
+ signature = NULL;
+ fp = NULL;
+ MAPPHAR_FAIL("Cannot open archive \"%s\", alias is already in use by existing archive");
+ }
+ }
+ zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void*)&mydata, sizeof(phar_archive_data*), NULL);
+ } else {
+ mydata->is_temporary_alias = 1;
+ }
+ zend_hash_add(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len, (void*)&mydata, sizeof(phar_archive_data*), NULL);
+ efree(savebuf);
+
+ if (pphar) {
+ *pphar = mydata;
+ }
+
+ return SUCCESS;
+}
+/* }}} */
+
+/**
+ * Create or open a phar for writing
+ */
+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) /* {{{ */
+{
+ const char *ext_str, *z;
+ char *my_error;
+ int ext_len;
+ phar_archive_data **test, *unused = NULL;
+
+ test = &unused;
+ if (error) {
+ *error = NULL;
+ }
+
+ /* first try to open an existing file */
+ if (phar_detect_phar_fname_ext(fname, 1, &ext_str, &ext_len, !is_data, 0, 1 TSRMLS_CC) == SUCCESS) {
+ goto check_file;
+ }
+ /* next try to create a new file */
+ if (FAILURE == phar_detect_phar_fname_ext(fname, 1, &ext_str, &ext_len, !is_data, 1, 1 TSRMLS_CC)) {
+ if (error) {
+ spprintf(error, 0, "Cannot create phar '%s', file extension (or combination) not recognised", fname);
+ }
+ return FAILURE;
+ }
+
+check_file:
+ if (phar_open_loaded(fname, fname_len, alias, alias_len, is_data, options, test, &my_error TSRMLS_CC) == SUCCESS) {
+ if (pphar) {
+ *pphar = *test;
+ }
+ if ((*test)->is_data && !(*test)->is_tar && !(*test)->is_zip) {
+ if (error) {
+ spprintf(error, 0, "Cannot open '%s' as a PharData object. Use Phar::__construct() for executable archives", fname);
+ }
+ return FAILURE;
+ }
+ if (PHAR_G(readonly) && !(*test)->is_data && ((*test)->is_tar || (*test)->is_zip)) {
+ phar_entry_info *stub;
+ if (FAILURE == zend_hash_find(&((*test)->manifest), ".phar/stub.php", sizeof(".phar/stub.php")-1, (void **)&stub)) {
+ spprintf(error, 0, "'%s' is not a phar archive. Use PharData::__construct() for a standard zip or tar archive", fname);
+ return FAILURE;
+ }
+ }
+ if (!PHAR_G(readonly) || (*test)->is_data) {
+ (*test)->is_writeable = 1;
+ }
+ return SUCCESS;
+ } else if (my_error) {
+ if (error) {
+ *error = my_error;
+ } else {
+ efree(my_error);
+ }
+ return FAILURE;
+ }
+
+ if (ext_len > 3 && (z = memchr(ext_str, 'z', ext_len)) && ((ext_str + ext_len) - z >= 2) && !memcmp(z + 1, "ip", 2)) {
+ // assume zip-based phar
+ return phar_open_or_create_zip(fname, fname_len, alias, alias_len, is_data, options, pphar, error TSRMLS_CC);
+ }
+
+ if (ext_len > 3 && (z = memchr(ext_str, 't', ext_len)) && ((ext_str + ext_len) - z >= 2) && !memcmp(z + 1, "ar", 2)) {
+ // assume tar-based phar
+ return phar_open_or_create_tar(fname, fname_len, alias, alias_len, is_data, options, pphar, error TSRMLS_CC);
+ }
+
+ return phar_create_or_parse_filename(fname, fname_len, alias, alias_len, is_data, options, pphar, error TSRMLS_CC);
+
+}
+
+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) /* {{{ */
+{
+ phar_archive_data *mydata;
+ php_stream *fp;
+ char *actual = NULL, *p;
+
+ if (!pphar) {
+ pphar = &mydata;
+ }
+#if PHP_MAJOR_VERSION < 6
+ if (PG(safe_mode) && (!php_checkuid(fname, NULL, CHECKUID_ALLOW_ONLY_FILE))) {
+ return FAILURE;
+ }
+#endif
+
+ if (php_check_open_basedir(fname TSRMLS_CC)) {
+ return FAILURE;
+ }
+
+ /* first open readonly so it won't be created if not present */
+ fp = php_stream_open_wrapper(fname, "rb", IGNORE_URL|STREAM_MUST_SEEK|0, &actual);
+ if (actual) {
+ fname = actual;
+ fname_len = strlen(actual);
+ }
+
+ if (fp) {
+ if (phar_open_fp(fp, fname, fname_len, alias, alias_len, options, pphar, error TSRMLS_CC) == SUCCESS) {
+ if ((*pphar)->is_data || !PHAR_G(readonly)) {
+ (*pphar)->is_writeable = 1;
+ }
+ if (actual) {
+ efree(actual);
+ }
+ return SUCCESS;
+ } else {
+ /* file exists, but is either corrupt or not a phar archive */
+ if (actual) {
+ efree(actual);
+ }
+ return FAILURE;
+ }
+ }
+ if (actual) {
+ efree(actual);
+ }
+
+ if (PHAR_G(readonly) && !is_data) {
+ if (options & REPORT_ERRORS) {
+ if (error) {
+ spprintf(error, 0, "creating archive \"%s\" disabled by INI setting", fname);
+ }
+ }
+ return FAILURE;
+ }
+
+ /* set up our manifest */
+ mydata = ecalloc(sizeof(phar_archive_data), 1);
+
+ mydata->fname = expand_filepath(fname, NULL TSRMLS_CC);
+ fname_len = strlen(mydata->fname);
+#ifdef PHP_WIN32
+ phar_unixify_path_separators(mydata->fname, fname_len);
+#endif
+ p = strrchr(mydata->fname, '/');
+ if (p) {
+ mydata->ext = memchr(p, '.', (mydata->fname + fname_len) - p);
+ if (mydata->ext == p) {
+ mydata->ext = memchr(p + 1, '.', (mydata->fname + fname_len) - p - 1);
+ }
+ if (mydata->ext) {
+ mydata->ext_len = (mydata->fname + fname_len) - mydata->ext;
+ }
+ }
+
+ if (pphar) {
+ *pphar = mydata;
+ }
+ zend_hash_init(&mydata->manifest, sizeof(phar_entry_info),
+ zend_get_hash_value, destroy_phar_manifest_entry, 0);
+ zend_hash_init(&mydata->mounted_dirs, sizeof(char *),
+ zend_get_hash_value, NULL, 0);
+ mydata->fname_len = fname_len;
+ snprintf(mydata->version, sizeof(mydata->version), "%s", PHP_PHAR_API_VERSION);
+ mydata->is_temporary_alias = alias ? 0 : 1;
+ mydata->internal_file_start = -1;
+ mydata->fp = NULL;
+ mydata->is_writeable = 1;
+ mydata->is_brandnew = 1;
+ phar_request_initialize(TSRMLS_C);
+ zend_hash_add(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len, (void*)&mydata, sizeof(phar_archive_data*), NULL);
+ if (is_data) {
+ alias = NULL;
+ alias_len = 0;
+ } else {
+ phar_archive_data **fd_ptr;
+
+ if (alias && SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void **)&fd_ptr)) {
+ if (SUCCESS != phar_free_alias(*fd_ptr, alias, alias_len TSRMLS_CC)) {
+ if (error) {
+ spprintf(error, 4096, "phar error: phar \"%s\" cannot set alias \"%s\", already in use by another phar archive", mydata->fname, alias);
+ }
+ zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len);
+ if (pphar) {
+ *pphar = NULL;
+ }
+ return FAILURE;
+ }
+ }
+ mydata->alias = alias ? estrndup(alias, alias_len) : estrndup(mydata->fname, fname_len);
+ mydata->alias_len = alias ? alias_len : fname_len;
+ }
+ if (alias_len && alias) {
+ if (FAILURE == zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void*)&mydata, sizeof(phar_archive_data*), NULL)) {
+ if (options & REPORT_ERRORS) {
+ if (error) {
+ spprintf(error, 0, "archive \"%s\" cannot be associated with alias \"%s\", already in use", fname, alias);
+ }
+ }
+ zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len);
+ if (pphar) {
+ *pphar = NULL;
+ }
+ return FAILURE;
+ }
+ }
+ return SUCCESS;
+}
+/* }}}*/
+
+/**
+ * Return an already opened filename.
+ *
+ * Or scan a phar file for the required __HALT_COMPILER(); ?> token and verify
+ * that the manifest is proper, then pass it to phar_open_file(). SUCCESS
+ * or FAILURE is returned and pphar is set to a pointer to the phar's manifest
+ */
+int phar_open_filename(char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, char **error TSRMLS_DC) /* {{{ */
+{
+ php_stream *fp;
+ char *actual;
+ int ret, is_data = 0;
+
+ if (error) {
+ *error = NULL;
+ }
+
+ if (!strstr(fname, ".phar")) {
+ is_data = 1;
+ }
+
+ if (phar_open_loaded(fname, fname_len, alias, alias_len, is_data, options, pphar, error TSRMLS_CC) == SUCCESS) {
+ return SUCCESS;
+ } else if (error && *error) {
+ return FAILURE;
+ }
+
+#if PHP_MAJOR_VERSION < 6
+ if (PG(safe_mode) && (!php_checkuid(fname, NULL, CHECKUID_ALLOW_ONLY_FILE))) {
+ return FAILURE;
+ }
+#endif
+
+ if (php_check_open_basedir(fname TSRMLS_CC)) {
+ return FAILURE;
+ }
+
+ fp = php_stream_open_wrapper(fname, "rb", IGNORE_URL|STREAM_MUST_SEEK, &actual);
+ if (!fp) {
+ if (options & REPORT_ERRORS) {
+ if (error) {
+ spprintf(error, 0, "unable to open phar for reading \"%s\"", fname);
+ }
+ }
+ if (actual) {
+ efree(actual);
+ }
+ return FAILURE;
+ }
+
+ if (actual) {
+ fname = actual;
+ fname_len = strlen(actual);
+ }
+
+ ret = phar_open_fp(fp, fname, fname_len, alias, alias_len, options, pphar, error TSRMLS_CC);
+ if (actual) {
+ efree(actual);
+ }
+ return ret;
+}
+/* }}}*/
+
+static inline char *phar_strnstr(const char *buf, int buf_len, const char *search, int search_len)
+{
+ const char *c;
+ int so_far = 0;
+
+ /* this assumes buf_len > search_len */
+ c = buf - 1;
+ do {
+ if (!(c = memchr(c + 1, search[0], buf_len - search_len - so_far))) {
+ return (char *) NULL;
+ }
+ so_far = c - buf;
+ if (so_far >= (buf_len - search_len)) {
+ return (char *) NULL;
+ }
+ if (!memcmp(c, search, search_len)) {
+ return (char *) c;
+ }
+ } while (1);
+}
+
+/**
+ * Scan an open fp for the required __HALT_COMPILER(); ?> token and verify
+ * that the manifest is proper, then pass it to phar_open_file(). SUCCESS
+ * or FAILURE is returned and pphar is set to a pointer to the phar's manifest
+ */
+static int phar_open_fp(php_stream* fp, char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, char **error TSRMLS_DC) /* {{{ */
+{
+ const char token[] = "__HALT_COMPILER();";
+ const char zip_magic[] = "PK\x03\x04";
+ const char gz_magic[] = "\x1f\x8b\x08";
+ const char bz_magic[] = "BZh";
+ char *pos, buffer[1024 + sizeof(token)], test = '\0';
+ const long readsize = sizeof(buffer) - sizeof(token);
+ const long tokenlen = sizeof(token) - 1;
+ long halt_offset;
+ size_t got;
+ php_uint32 compression = PHAR_FILE_COMPRESSED_NONE;
+
+ if (error) {
+ *error = NULL;
+ }
+ if (-1 == php_stream_rewind(fp)) {
+ MAPPHAR_ALLOC_FAIL("cannot rewind phar \"%s\"")
+ }
+
+ buffer[sizeof(buffer)-1] = '\0';
+ memset(buffer, 32, sizeof(token));
+ halt_offset = 0;
+
+ /* Maybe it's better to compile the file instead of just searching, */
+ /* but we only want the offset. So we want a .re scanner to find it. */
+ while(!php_stream_eof(fp)) {
+ if ((got = php_stream_read(fp, buffer+tokenlen, readsize)) < (size_t) tokenlen) {
+ MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated entry)")
+ }
+ if (!test) {
+ test = '\1';
+ pos = buffer+tokenlen;
+ if (!memcmp(pos, gz_magic, 3)) {
+ char err = 0;
+ php_stream_filter *filter;
+ php_stream *temp;
+ /* to properly decompress, we have to tell zlib to look for a zlib or gzip header */
+ zval filterparams;
+
+ if (!phar_has_zlib) {
+ MAPPHAR_ALLOC_FAIL("unable to decompress gzipped phar archive \"%s\" to temporary file, enable zlib extension in php.ini")
+ }
+ array_init(&filterparams);
+
+/* this is defined in zlib's zconf.h */
+#ifndef MAX_WBITS
+#define MAX_WBITS 15
+#endif
+ add_assoc_long(&filterparams, "window", MAX_WBITS + 32);
+ /* entire file is gzip-compressed, uncompress to temporary file */
+ if (!(temp = php_stream_fopen_tmpfile())) {
+ MAPPHAR_ALLOC_FAIL("unable to create temporary file for decompression of gzipped phar archive \"%s\"")
+ }
+ php_stream_rewind(fp);
+ filter = php_stream_filter_create("zlib.inflate", &filterparams, php_stream_is_persistent(fp) TSRMLS_CC);
+ if (!filter) {
+ err = 1;
+ add_assoc_long(&filterparams, "window", MAX_WBITS);
+ filter = php_stream_filter_create("zlib.inflate", &filterparams, php_stream_is_persistent(fp) TSRMLS_CC);
+ zval_dtor(&filterparams);
+ if (!filter) {
+ php_stream_close(temp);
+ MAPPHAR_ALLOC_FAIL("unable to decompress gzipped phar archive \"%s\", ext/zlib is buggy in PHP versions older than 5.2.6")
+ }
+ } else {
+ zval_dtor(&filterparams);
+ }
+ php_stream_filter_append(&temp->writefilters, filter);
+ if (0 == php_stream_copy_to_stream(fp, temp, PHP_STREAM_COPY_ALL)) {
+ if (err) {
+ php_stream_close(temp);
+ MAPPHAR_ALLOC_FAIL("unable to decompress gzipped phar archive \"%s\", ext/zlib is buggy in PHP versions older than 5.2.6")
+ }
+ php_stream_close(temp);
+ MAPPHAR_ALLOC_FAIL("unable to decompress gzipped phar archive \"%s\" to temporary file")
+ }
+ php_stream_filter_flush(filter, 1);
+ php_stream_filter_remove(filter, 1 TSRMLS_CC);
+ php_stream_close(fp);
+ fp = temp;
+ php_stream_rewind(fp);
+ compression = PHAR_FILE_COMPRESSED_GZ;
+
+ /* now, start over */
+ test = '\0';
+ continue;
+ } else if (!memcmp(pos, bz_magic, 3)) {
+ php_stream_filter *filter;
+ php_stream *temp;
+
+ if (!phar_has_bz2) {
+ MAPPHAR_ALLOC_FAIL("unable to decompress bzipped phar archive \"%s\" to temporary file, enable bz2 extension in php.ini")
+ }
+ /* entire file is bzip-compressed, uncompress to temporary file */
+ if (!(temp = php_stream_fopen_tmpfile())) {
+ MAPPHAR_ALLOC_FAIL("unable to create temporary file for decompression of bzipped phar archive \"%s\"")
+ }
+ php_stream_rewind(fp);
+ filter = php_stream_filter_create("bzip2.decompress", NULL, php_stream_is_persistent(fp) TSRMLS_CC);
+ if (!filter) {
+ php_stream_close(temp);
+ MAPPHAR_ALLOC_FAIL("unable to decompress bzipped phar archive \"%s\", filter creation failed")
+ }
+ php_stream_filter_append(&temp->writefilters, filter);
+ if (0 == php_stream_copy_to_stream(fp, temp, PHP_STREAM_COPY_ALL)) {
+ php_stream_close(temp);
+ MAPPHAR_ALLOC_FAIL("unable to decompress bzipped phar archive \"%s\" to temporary file")
+ }
+ php_stream_filter_flush(filter, 1);
+ php_stream_filter_remove(filter, 1 TSRMLS_CC);
+ php_stream_close(fp);
+ fp = temp;
+ php_stream_rewind(fp);
+ compression = PHAR_FILE_COMPRESSED_BZ2;
+
+ /* now, start over */
+ test = '\0';
+ continue;
+ }
+ if (!memcmp(pos, zip_magic, 4)) {
+ php_stream_seek(fp, 0, SEEK_END);
+ return phar_open_zipfile(fp, fname, fname_len, alias, alias_len, pphar, error TSRMLS_CC);
+ }
+ if (got > 512) {
+ if (phar_is_tar(pos, fname)) {
+ php_stream_rewind(fp);
+ return phar_open_tarfile(fp, fname, fname_len, alias, alias_len, options, pphar, compression, error TSRMLS_CC);
+ }
+ }
+ }
+ if ((pos = phar_strnstr(buffer, 1024 + sizeof(token), token, sizeof(token)-1)) != NULL) {
+ halt_offset += (pos - buffer); /* no -tokenlen+tokenlen here */
+ return phar_open_file(fp, fname, fname_len, alias, alias_len, halt_offset, pphar, compression, error TSRMLS_CC);
+ }
+
+ halt_offset += got;
+ memmove(buffer, buffer + tokenlen, got + 1);
+ }
+
+ MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (__HALT_COMPILER(); not found)")
+}
+/* }}} */
+
+/*
+ * given the location of the file extension and the start of the file path,
+ * determine the end of the portion of the path (i.e. /path/to/file.ext/blah
+ * grabs "/path/to/file.ext" as does the straight /path/to/file.ext),
+ * stat it to determine if it exists.
+ * if so, check to see if it is a directory and fail if so
+ * if not, check to see if its dirname() exists (i.e. "/path/to") and is a directory
+ * succeed if we are creating the file, otherwise fail.
+ */
+static int phar_analyze_path(const char *fname, const char *ext, int ext_len, int for_create TSRMLS_DC)
+{
+ php_stream_statbuf ssb;
+ char *realpath, old, *a = (char *)(ext + ext_len);
+
+ old = *a;
+ *a = '\0';
+ if ((realpath = expand_filepath(fname, NULL TSRMLS_CC))) {
+#ifdef PHP_WIN32
+ phar_unixify_path_separators(realpath, strlen(realpath));
+#endif
+ if (zend_hash_exists(&(PHAR_GLOBALS->phar_fname_map), realpath, strlen(realpath))) {
+ *a = old;
+ efree(realpath);
+ return SUCCESS;
+ }
+ efree(realpath);
+ }
+ if (SUCCESS == php_stream_stat_path((char *) fname, &ssb)) {
+ *a = old;
+ if (ssb.sb.st_mode & S_IFDIR) {
+ return FAILURE;
+ }
+ if (for_create == 1) {
+ return FAILURE;
+ }
+ return SUCCESS;
+ } else {
+ char *slash;
+
+ if (!for_create) {
+ *a = old;
+ return FAILURE;
+ }
+ slash = (char *) strrchr(fname, '/');
+ *a = old;
+ if (slash) {
+ old = *slash;
+ *slash = '\0';
+ }
+ if (SUCCESS != php_stream_stat_path((char *) fname, &ssb)) {
+ if (slash) {
+ *slash = old;
+ } else {
+ if (!(realpath = expand_filepath(fname, NULL TSRMLS_CC))) {
+ return FAILURE;
+ }
+#ifdef PHP_WIN32
+ phar_unixify_path_separators(realpath, strlen(realpath));
+#endif
+ a = strstr(realpath, fname) + ((ext - fname) + ext_len);
+ *a = '\0';
+ slash = strrchr(realpath, '/');
+ if (slash) {
+ *slash = '\0';
+ } else {
+ efree(realpath);
+ return FAILURE;
+ }
+ if (SUCCESS != php_stream_stat_path(realpath, &ssb)) {
+ efree(realpath);
+ return FAILURE;
+ }
+ efree(realpath);
+ if (ssb.sb.st_mode & S_IFDIR) {
+ return SUCCESS;
+ }
+ }
+ return FAILURE;
+ }
+ if (slash) {
+ *slash = old;
+ }
+ if (ssb.sb.st_mode & S_IFDIR) {
+ return SUCCESS;
+ }
+ return FAILURE;
+ }
+}
+
+/* check for ".phar" in extension */
+static int phar_check_str(const char *fname, const char *ext_str, int ext_len, int executable, int for_create TSRMLS_DC)
+{
+ char test[51];
+ const char *pos;
+
+ if (ext_len >= 50) {
+ return FAILURE;
+ }
+ if (executable == 1) {
+ /* copy "." as well */
+ memcpy(test, ext_str - 1, ext_len + 1);
+ test[ext_len + 1] = '\0';
+ /* executable phars must contain ".phar" as a valid extension (phar://.pharmy/oops is invalid) */
+ /* (phar://hi/there/.phar/oops is also invalid) */
+ pos = strstr(test, ".phar");
+ if (pos && (*(pos - 1) != '/')
+ && (pos += 5) && (*pos == '\0' || *pos == '/' || *pos == '.')) {
+ return phar_analyze_path(fname, ext_str, ext_len, for_create TSRMLS_CC);
+ } else {
+ return FAILURE;
+ }
+ }
+ /* data phars need only contain a single non-"." to be valid */
+ if (!executable) {
+ pos = strstr(ext_str, ".phar");
+ if (!(pos && (*(pos - 1) != '/')
+ && (pos += 5) && (*pos == '\0' || *pos == '/' || *pos == '.')) && *(ext_str + 1) != '.' && *(ext_str + 1) != '/' && *(ext_str + 1) != '\0') {
+ return phar_analyze_path(fname, ext_str, ext_len, for_create TSRMLS_CC);
+ }
+ } else {
+ if (*(ext_str + 1) != '.' && *(ext_str + 1) != '/' && *(ext_str + 1) != '\0') {
+ return phar_analyze_path(fname, ext_str, ext_len, for_create TSRMLS_CC);
+ }
+ }
+ return FAILURE;
+}
+
+/*
+ * if executable is 1, only returns SUCCESS if the extension is one of the tar/zip .phar extensions
+ * if executable is 0, it returns SUCCESS only if the filename does *not* contain ".phar" anywhere, and treats
+ * the first extension as the filename extension
+ *
+ * if an extension is found, it sets ext_str to the location of the file extension in filename,
+ * and ext_len to the length of the extension.
+ * for urls like "phar://alias/oops" it instead sets ext_len to -1 and returns FAILURE, which tells
+ * the calling function to use "alias" as the phar alias
+ *
+ * the last parameter should be set to tell the thing to assume that filename is the full path, and only to check the
+ * extension rules, not to iterate.
+ */
+int phar_detect_phar_fname_ext(const char *filename, int check_length, const char **ext_str, int *ext_len, int executable, int for_create, int is_complete TSRMLS_DC) /* {{{ */
+{
+ const char *pos, *slash;
+ int filename_len = strlen(filename);
+
+ *ext_str = NULL;
+
+ if (!filename_len || filename_len == 1) {
+ return FAILURE;
+ }
+ phar_request_initialize(TSRMLS_C);
+ /* first check for alias in first segment */
+ pos = strchr(filename, '/');
+ if (pos && pos != filename) {
+ if (zend_hash_exists(&(PHAR_GLOBALS->phar_alias_map), (char *) filename, pos - filename)) {
+ *ext_str = pos;
+ *ext_len = -1;
+ return FAILURE;
+ }
+ }
+
+ if (zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map))) {
+ phar_archive_data **pphar;
+
+ if (is_complete) {
+ if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), (char *) filename, filename_len, (void **)&pphar)) {
+ *ext_str = filename + (filename_len - (*pphar)->ext_len);
+woohoo:
+ *ext_len = (*pphar)->ext_len;
+ if (executable == 2) {
+ return SUCCESS;
+ }
+ if (executable == 1 && !(*pphar)->is_data) {
+ return SUCCESS;
+ }
+ if (!executable && (*pphar)->is_data) {
+ return SUCCESS;
+ }
+ return FAILURE;
+ }
+ } else {
+ char *key;
+ uint keylen;
+ ulong unused;
+
+ zend_hash_internal_pointer_reset(&(PHAR_GLOBALS->phar_fname_map));
+ while (FAILURE != zend_hash_has_more_elements(&(PHAR_GLOBALS->phar_fname_map))) {
+ if (HASH_KEY_NON_EXISTANT == zend_hash_get_current_key_ex(&(PHAR_GLOBALS->phar_fname_map), &key, &keylen, &unused, 0, NULL)) {
+ break;
+ }
+
+ if (keylen > (uint) filename_len) {
+ zend_hash_move_forward(&(PHAR_GLOBALS->phar_fname_map));
+ continue;
+ }
+ if (!memcmp(filename, key, keylen) && (filename_len == keylen
+ || filename[keylen] == '/' || filename[keylen] == '\0')) {
+ if (FAILURE == zend_hash_get_current_data(&(PHAR_GLOBALS->phar_fname_map), (void **) &pphar)) {
+ break;
+ }
+ *ext_str = filename + (keylen - (*pphar)->ext_len);
+ goto woohoo;
+ }
+ zend_hash_move_forward(&(PHAR_GLOBALS->phar_fname_map));
+ }
+ }
+ }
+
+ pos = strchr(filename + 1, '.');
+next_extension:
+ if (!pos) {
+ return FAILURE;
+ }
+ while (pos != filename && (*(pos - 1) == '/' || *(pos - 1) == '\0')) {
+ pos = strchr(pos + 1, '.');
+ if (!pos) {
+ return FAILURE;
+ }
+ }
+
+ slash = strchr(pos, '/');
+ if (!slash) {
+ /* this is a url like "phar://blah.phar" with no directory */
+ *ext_str = pos;
+ *ext_len = strlen(pos);
+ /* file extension must contain "phar" */
+ switch (phar_check_str(filename, *ext_str, *ext_len, executable, for_create TSRMLS_CC)) {
+ case SUCCESS :
+ return SUCCESS;
+ case FAILURE :
+ /* we are at the end of the string, so we fail */
+ return FAILURE;
+ }
+ }
+ /* we've found an extension that ends at a directory separator */
+ *ext_str = pos;
+ *ext_len = slash - pos;
+ switch (phar_check_str(filename, *ext_str, *ext_len, executable, for_create TSRMLS_CC)) {
+ case SUCCESS :
+ return SUCCESS;
+ case FAILURE :
+ /* look for more extensions */
+ if (is_complete) {
+ return FAILURE;
+ }
+ pos = strchr(pos + 1, '.');
+ if (pos) {
+ *ext_str = NULL;
+ *ext_len = 0;
+ }
+ goto next_extension;
+ }
+ return FAILURE;
+}
+/* }}} */
+
+static int php_check_dots(const char *element, int n)
+{
+ for(n--; n >= 0; --n) {
+ if (element[n] != '.') {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+#define IS_DIRECTORY_UP(element, len) \
+ (len >= 2 && !php_check_dots(element, len))
+
+#define IS_DIRECTORY_CURRENT(element, len) \
+ (len == 1 && element[0] == '.')
+
+#define IS_BACKSLASH(c) ((c) == '/')
+
+#ifdef COMPILE_DL_PHAR
+/* stupid-ass non-extern declaration in tsrm_strtok.h breaks dumbass MS compiler */
+static inline int in_character_class(char ch, const char *delim)
+{
+ while (*delim) {
+ if (*delim == ch) {
+ return 1;
+ }
+ ++delim;
+ }
+ return 0;
+}
+
+char *tsrm_strtok_r(char *s, const char *delim, char **last)
+{
+ char *token;
+
+ if (s == NULL) {
+ s = *last;
+ }
+
+ while (*s && in_character_class(*s, delim)) {
+ ++s;
+ }
+ if (!*s) {
+ return NULL;
+ }
+
+ token = s;
+
+ while (*s && !in_character_class(*s, delim)) {
+ ++s;
+ }
+ if (!*s) {
+ *last = s;
+ } else {
+ *s = '\0';
+ *last = s + 1;
+ }
+ return token;
+}
+#endif
+
+/**
+ * Remove .. and . references within a phar filename
+ */
+char *phar_fix_filepath(char *path, int *new_len, int use_cwd TSRMLS_DC) /* {{{ */
+{
+ char *ptr, *free_path, *new_phar;
+ char *tok;
+ int ptr_length, new_phar_len = 1, path_length = *new_len;
+
+ if (PHAR_G(cwd_len) && use_cwd && path_length > 2 && path[0] == '.' && path[1] == '/') {
+ free_path = path;
+ new_phar_len = PHAR_G(cwd_len);
+ new_phar = estrndup(PHAR_G(cwd), new_phar_len);
+ } else {
+ free_path = path;
+ new_phar = estrndup("/\0", 2);
+ }
+ tok = NULL;
+ ptr = tsrm_strtok_r(path, "/", &tok);
+ while (ptr) {
+ ptr_length = strlen(ptr);
+
+ if (IS_DIRECTORY_UP(ptr, ptr_length)) {
+ char save;
+
+ save = '/';
+
+#define PREVIOUS new_phar[new_phar_len - 1]
+
+ while (new_phar_len > 1 &&
+ !IS_BACKSLASH(PREVIOUS)) {
+ save = PREVIOUS;
+ PREVIOUS = '\0';
+ new_phar_len--;
+ }
+
+ if (new_phar[0] != '/') {
+ new_phar[new_phar_len++] = save;
+ new_phar[new_phar_len] = '\0';
+ } else if (new_phar_len > 1) {
+ PREVIOUS = '\0';
+ new_phar_len--;
+ }
+ } else if (!IS_DIRECTORY_CURRENT(ptr, ptr_length)) {
+ if (new_phar_len > 1) {
+ new_phar = (char *) erealloc(new_phar, new_phar_len+ptr_length+1+1);
+ new_phar[new_phar_len++] = '/';
+ memcpy(&new_phar[new_phar_len], ptr, ptr_length+1);
+ } else {
+ new_phar = (char *) erealloc(new_phar, new_phar_len+ptr_length+1);
+ memcpy(&new_phar[new_phar_len], ptr, ptr_length+1);
+ }
+
+ new_phar_len += ptr_length;
+ }
+ ptr = tsrm_strtok_r(NULL, "/", &tok);
+ }
+
+ if (path[path_length-1] == '/' && new_phar_len > 1) {
+ new_phar = (char*)erealloc(new_phar, new_phar_len + 2);
+ new_phar[new_phar_len++] = '/';
+ new_phar[new_phar_len] = 0;
+ }
+
+ efree(free_path);
+
+ if (new_phar_len == 0) {
+ new_phar = (char *) erealloc(new_phar, new_phar_len+1+1);
+ new_phar[new_phar_len] = '/';
+ new_phar[++new_phar_len] = '\0';
+ }
+ *new_len = new_phar_len;
+ return new_phar;
+}
+/* }}} */
+
+/**
+ * Process a phar stream name, ensuring we can handle any of:
+ *
+ * - whatever.phar
+ * - whatever.phar.gz
+ * - whatever.phar.bz2
+ * - whatever.phar.php
+ *
+ * Optionally the name might start with 'phar://'
+ *
+ * This is used by phar_open_url()
+ */
+int phar_split_fname(char *filename, int filename_len, char **arch, int *arch_len, char **entry, int *entry_len, int executable, int for_create TSRMLS_DC) /* {{{ */
+{
+ const char *ext_str;
+#ifdef PHP_WIN32
+ char *save;
+#endif
+ int ext_len, free_filename = 0;
+
+ if (!strncasecmp(filename, "phar://", 7)) {
+ filename += 7;
+ filename_len -= 7;
+ }
+
+ ext_len = 0;
+#ifdef PHP_WIN32
+ free_filename = 1;
+ save = filename;
+ filename = estrndup(filename, filename_len);
+ phar_unixify_path_separators(filename, filename_len);
+#endif
+ if (phar_detect_phar_fname_ext(filename, 0, &ext_str, &ext_len, executable, for_create, 0 TSRMLS_CC) == FAILURE) {
+ if (ext_len != -1) {
+ if (!ext_str) {
+ /* no / detected, restore arch for error message */
+#ifdef PHP_WIN32
+ *arch = save;
+#else
+ *arch = filename;
+#endif
+ }
+ if (free_filename) {
+ efree(filename);
+ }
+ return FAILURE;
+ }
+ ext_len = 0;
+ /* no extension detected - instead we are dealing with an alias */
+ }
+
+ *arch_len = ext_str - filename + ext_len;
+ *arch = estrndup(filename, *arch_len);
+ if (ext_str[ext_len]) {
+ *entry_len = filename_len - *arch_len;
+ *entry = estrndup(ext_str+ext_len, *entry_len);
+#ifdef PHP_WIN32
+ phar_unixify_path_separators(*entry, *entry_len);
+#endif
+ *entry = phar_fix_filepath(*entry, entry_len, 0 TSRMLS_CC);
+ } else {
+ *entry_len = 1;
+ *entry = estrndup("/", 1);
+ }
+ if (free_filename) {
+ efree(filename);
+ }
+ return SUCCESS;
+}
+/* }}} */
+
+/**
+ * Invoked when a user calls Phar::mapPhar() from within an executing .phar
+ * to set up its manifest directly
+ */
+int phar_open_compiled_file(char *alias, int alias_len, char **error TSRMLS_DC) /* {{{ */
+{
+ char *fname;
+ long halt_offset;
+ zval *halt_constant;
+ php_stream *fp;
+ int fname_len;
+
+ if (error) {
+ *error = NULL;
+ }
+ fname = zend_get_executed_filename(TSRMLS_C);
+ fname_len = strlen(fname);
+
+ if (phar_open_loaded(fname, fname_len, alias, alias_len, 0, REPORT_ERRORS, NULL, 0 TSRMLS_CC) == SUCCESS) {
+ return SUCCESS;
+ }
+
+ if (!strcmp(fname, "[no active file]")) {
+ if (error) {
+ spprintf(error, 0, "cannot initialize a phar outside of PHP execution");
+ }
+ return FAILURE;
+ }
+
+ MAKE_STD_ZVAL(halt_constant);
+ if (0 == zend_get_constant("__COMPILER_HALT_OFFSET__", 24, halt_constant TSRMLS_CC)) {
+ FREE_ZVAL(halt_constant);
+ if (error) {
+ spprintf(error, 0, "__HALT_COMPILER(); must be declared in a phar");
+ }
+ return FAILURE;
+ }
+ halt_offset = Z_LVAL(*halt_constant);
+ FREE_ZVAL(halt_constant);
+
+ fp = php_stream_open_wrapper(fname, "rb", IGNORE_URL|STREAM_MUST_SEEK|REPORT_ERRORS, NULL);
+
+ if (!fp) {
+ if (error) {
+ spprintf(error, 0, "unable to open phar for reading \"%s\"", fname);
+ }
+ return FAILURE;
+ }
+
+ return phar_open_file(fp, fname, fname_len, alias, alias_len, halt_offset, NULL, PHAR_FILE_COMPRESSED_NONE, error TSRMLS_CC);
+}
+/* }}} */
+
+/**
+ * Validate the CRC32 of a file opened from within the phar
+ */
+int phar_postprocess_file(php_stream_wrapper *wrapper, int options, phar_entry_data *idata, php_uint32 crc32, char **error TSRMLS_DC) /* {{{ */
+{
+ php_uint32 crc = ~0;
+ int len = idata->internal_file->uncompressed_filesize;
+ php_stream *fp = idata->fp;
+ phar_entry_info *entry = idata->internal_file;
+
+ if (error) {
+ *error = NULL;
+ }
+ if (entry->is_zip) {
+ /* verify local file header */
+ phar_zip_file_header local;
+
+ if (SUCCESS != phar_open_archive_fp(idata->phar TSRMLS_CC)) {
+ 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);
+ return FAILURE;
+ }
+ php_stream_seek(idata->phar->fp, entry->header_offset, SEEK_SET);
+
+ if (sizeof(local) != php_stream_read(idata->phar->fp, (char *) &local, sizeof(local))) {
+
+ 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);
+ return FAILURE;
+ }
+ /* fix up for big-endian systems */
+ /* verify local header if not yet verified */
+ 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)) {
+ spprintf(error, 0, "phar error: internal corruption of zip-based phar \"%s\" (local head of file \"%s\" does not match central directory)", idata->phar->fname, entry->filename);
+ return FAILURE;
+ }
+ if (-1 == php_stream_seek(idata->phar->fp, PHAR_ZIP_16(local.filename_len) + PHAR_ZIP_16(local.extra_len), SEEK_CUR)) {
+ spprintf(error, 0, "phar error: internal corruption of zip-based phar \"%s\" (cannot seek to start of file data for file \"%s\")", idata->phar->fname, entry->filename);
+ return FAILURE;
+ }
+ }
+ php_stream_seek(fp, idata->zero, SEEK_SET);
+ while (len--) {
+ CRC32(crc, php_stream_getc(fp));
+ }
+ php_stream_seek(fp, idata->zero, SEEK_SET);
+ if (~crc == crc32) {
+ entry->is_crc_checked = 1;
+ return SUCCESS;
+ } else {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: internal corruption of phar \"%s\" (crc32 mismatch on file \"%s\")", idata->phar->fname, entry->filename);
+ return FAILURE;
+ }
+}
+/* }}} */
+
+static inline void phar_set_32(char *buffer, int var) /* {{{ */
+{
+#ifdef WORDS_BIGENDIAN
+ *((buffer) + 3) = (unsigned char) (((var) >> 24) & 0xFF);
+ *((buffer) + 2) = (unsigned char) (((var) >> 16) & 0xFF);
+ *((buffer) + 1) = (unsigned char) (((var) >> 8) & 0xFF);
+ *((buffer) + 0) = (unsigned char) ((var) & 0xFF);
+#else
+ *(php_uint32 *)(buffer) = (php_uint32)(var);
+#endif
+} /* }}} */
+
+static int phar_flush_clean_deleted_apply(void *data TSRMLS_DC) /* {{{ */
+{
+ phar_entry_info *entry = (phar_entry_info *)data;
+
+ if (entry->fp_refcount <= 0 && entry->is_deleted) {
+ return ZEND_HASH_APPLY_REMOVE;
+ } else {
+ return ZEND_HASH_APPLY_KEEP;
+ }
+}
+/* }}} */
+
+#include "stub.h"
+
+char *phar_create_default_stub(const char *index_php, const char *web_index, size_t *len, char **error TSRMLS_DC)
+{
+ char *stub = NULL;
+ int index_len, web_len;
+ size_t dummy;
+
+ if (!len) {
+ len = &dummy;
+ }
+
+ if (error) {
+ *error = NULL;
+ }
+
+ if (!index_php) {
+ index_php = "index.php";
+ }
+
+ if (!web_index) {
+ web_index = "index.php";
+ }
+
+ index_len = strlen(index_php);
+ web_len = strlen(web_index);
+
+ if (index_len > 400) {
+ /* ridiculous size not allowed for index.php startup filename */
+ if (error) {
+ spprintf(error, 0, "Illegal filename passed in for stub creation, was %d characters long, and only 400 or less is allowed", index_len);
+ return NULL;
+ }
+ }
+
+ if (web_len > 400) {
+ /* ridiculous size not allowed for index.php startup filename */
+ if (error) {
+ spprintf(error, 0, "Illegal web filename passed in for stub creation, was %d characters long, and only 400 or less is allowed", web_len);
+ return NULL;
+ }
+ }
+
+ phar_get_stub(index_php, web_index, len, &stub, index_len+1, web_len+1 TSRMLS_CC);
+ return stub;
+}
+
+/**
+ * Save phar contents to disk
+ *
+ * user_stub contains either a string, or a resource pointer, if len is a negative length.
+ * user_stub and len should be both 0 if the default or existing stub should be used
+ */
+int phar_flush(phar_archive_data *phar, char *user_stub, long len, int convert, char **error TSRMLS_DC) /* {{{ */
+{
+/* static const char newstub[] = "<?php __HALT_COMPILER(); ?>\r\n"; */
+ char *newstub;
+ phar_entry_info *entry, *newentry;
+ int halt_offset, restore_alias_len, global_flags = 0, closeoldfile;
+ char *pos, has_dirs = 0;
+ char manifest[18], entry_buffer[24];
+ off_t manifest_ftell;
+ long offset;
+ size_t wrote;
+ php_uint32 manifest_len, mytime, loc, new_manifest_count;
+ php_uint32 newcrc32;
+ php_stream *file, *oldfile, *newfile, *stubfile;
+ php_stream_filter *filter;
+ php_serialize_data_t metadata_hash;
+ smart_str main_metadata_str = {0};
+ int free_user_stub, free_fp = 1, free_ufp = 1;
+
+ if (error) {
+ *error = NULL;
+ }
+
+ if (PHAR_G(readonly) && !phar->is_data) {
+ return EOF;
+ }
+
+ if (!zend_hash_num_elements(&phar->manifest) && !user_stub) {
+ return EOF;
+ }
+
+ if (phar->is_zip) {
+ return phar_zip_flush(phar, user_stub, len, convert, error TSRMLS_CC);
+ }
+ if (phar->is_tar) {
+ return phar_tar_flush(phar, user_stub, len, convert, error TSRMLS_CC);
+ }
+
+ if (phar->fp && !phar->is_brandnew) {
+ oldfile = phar->fp;
+ closeoldfile = 0;
+ php_stream_rewind(oldfile);
+ } else {
+ oldfile = php_stream_open_wrapper(phar->fname, "rb", 0, NULL);
+ closeoldfile = oldfile != NULL;
+ }
+ newfile = php_stream_fopen_tmpfile();
+ if (!newfile) {
+ if (error) {
+ spprintf(error, 0, "unable to create temporary file");
+ }
+ if (closeoldfile) {
+ php_stream_close(oldfile);
+ }
+ return EOF;
+ }
+
+ if (user_stub) {
+ if (len < 0) {
+ /* resource passed in */
+ if (!(php_stream_from_zval_no_verify(stubfile, (zval **)user_stub))) {
+ if (closeoldfile) {
+ php_stream_close(oldfile);
+ }
+ php_stream_close(newfile);
+ if (error) {
+ spprintf(error, 0, "unable to access resource to copy stub to new phar \"%s\"", phar->fname);
+ }
+ return EOF;
+ }
+ if (len == -1) {
+ len = PHP_STREAM_COPY_ALL;
+ } else {
+ len = -len;
+ }
+ user_stub = 0;
+ if (!(len = php_stream_copy_to_mem(stubfile, &user_stub, len, 0)) || !user_stub) {
+ if (closeoldfile) {
+ php_stream_close(oldfile);
+ }
+ php_stream_close(newfile);
+ if (error) {
+ spprintf(error, 0, "unable to read resource to copy stub to new phar \"%s\"", phar->fname);
+ }
+ return EOF;
+ }
+ free_user_stub = 1;
+ } else {
+ free_user_stub = 0;
+ }
+ if ((pos = strstr(user_stub, "__HALT_COMPILER();")) == NULL)
+ {
+ if (closeoldfile) {
+ php_stream_close(oldfile);
+ }
+ php_stream_close(newfile);
+ if (error) {
+ spprintf(error, 0, "illegal stub for phar \"%s\"", phar->fname);
+ }
+ if (free_user_stub) {
+ efree(user_stub);
+ }
+ return EOF;
+ }
+ len = pos - user_stub + 18;
+ if ((size_t)len != php_stream_write(newfile, user_stub, len)
+ || 5 != php_stream_write(newfile, " ?>\r\n", 5)) {
+ if (closeoldfile) {
+ php_stream_close(oldfile);
+ }
+ php_stream_close(newfile);
+ if (error) {
+ spprintf(error, 0, "unable to create stub from string in new phar \"%s\"", phar->fname);
+ }
+ if (free_user_stub) {
+ efree(user_stub);
+ }
+ return EOF;
+ }
+ phar->halt_offset = len + 5;
+ if (free_user_stub) {
+ efree(user_stub);
+ }
+ } else {
+ size_t written;
+
+ if (!user_stub && phar->halt_offset && oldfile && !phar->is_brandnew) {
+ written = php_stream_copy_to_stream(oldfile, newfile, phar->halt_offset);
+ newstub = NULL;
+ } else {
+ /* this is either a brand new phar or a default stub overwrite */
+ newstub = phar_create_default_stub(NULL, NULL, &(phar->halt_offset), NULL TSRMLS_CC);
+ written = php_stream_write(newfile, newstub, phar->halt_offset);
+ }
+ if (phar->halt_offset != written) {
+ if (closeoldfile) {
+ php_stream_close(oldfile);
+ }
+ php_stream_close(newfile);
+ if (error) {
+ if (newstub) {
+ spprintf(error, 0, "unable to create stub in new phar \"%s\"", phar->fname);
+ } else {
+ spprintf(error, 0, "unable to copy stub of old phar to new phar \"%s\"", phar->fname);
+ }
+ }
+ if (newstub) {
+ efree(newstub);
+ }
+ return EOF;
+ }
+ if (newstub) {
+ efree(newstub);
+ }
+ }
+ manifest_ftell = php_stream_tell(newfile);
+ halt_offset = manifest_ftell;
+
+ /* Check whether we can get rid of some of the deleted entries which are
+ * unused. However some might still be in use so even after this clean-up
+ * we need to skip entries marked is_deleted. */
+ zend_hash_apply(&phar->manifest, phar_flush_clean_deleted_apply TSRMLS_CC);
+
+ /* compress as necessary, calculate crcs, serialize meta-data, manifest size, and file sizes */
+ main_metadata_str.c = 0;
+ if (phar->metadata) {
+ PHP_VAR_SERIALIZE_INIT(metadata_hash);
+ php_var_serialize(&main_metadata_str, &phar->metadata, &metadata_hash TSRMLS_CC);
+ PHP_VAR_SERIALIZE_DESTROY(metadata_hash);
+ } else {
+ main_metadata_str.len = 0;
+ }
+ new_manifest_count = 0;
+ offset = 0;
+ for (zend_hash_internal_pointer_reset(&phar->manifest);
+ zend_hash_has_more_elements(&phar->manifest) == SUCCESS;
+ zend_hash_move_forward(&phar->manifest)) {
+ if (zend_hash_get_current_data(&phar->manifest, (void **)&entry) == FAILURE) {
+ continue;
+ }
+ if (entry->cfp) {
+ /* did we forget to get rid of cfp last time? */
+ php_stream_close(entry->cfp);
+ entry->cfp = 0;
+ }
+ if (entry->is_deleted || entry->is_mounted) {
+ /* remove this from the new phar */
+ continue;
+ }
+ if (!entry->is_modified && entry->fp_refcount) {
+ /* open file pointers refer to this fp, do not free the stream */
+ switch (entry->fp_type) {
+ case PHAR_FP:
+ free_fp = 0;
+ break;
+ case PHAR_UFP:
+ free_ufp = 0;
+ default:
+ break;
+ }
+ }
+ /* after excluding deleted files, calculate manifest size in bytes and number of entries */
+ ++new_manifest_count;
+
+ if (entry->is_dir) {
+ /* we use this to calculate API version, 1.1.1 is used for phars with directories */
+ has_dirs = 1;
+ }
+ if (entry->metadata) {
+ if (entry->metadata_str.c) {
+ smart_str_free(&entry->metadata_str);
+ }
+ entry->metadata_str.c = 0;
+ entry->metadata_str.len = 0;
+ PHP_VAR_SERIALIZE_INIT(metadata_hash);
+ php_var_serialize(&entry->metadata_str, &entry->metadata, &metadata_hash TSRMLS_CC);
+ PHP_VAR_SERIALIZE_DESTROY(metadata_hash);
+ } else {
+ if (entry->metadata_str.c) {
+ smart_str_free(&entry->metadata_str);
+ }
+ entry->metadata_str.c = 0;
+ entry->metadata_str.len = 0;
+ }
+
+ /* 32 bits for filename length, length of filename, manifest + metadata, and add 1 for trailing / if a directory */
+ offset += 4 + entry->filename_len + sizeof(entry_buffer) + entry->metadata_str.len + (entry->is_dir ? 1 : 0);
+
+ /* compress and rehash as necessary */
+ if ((oldfile && !entry->is_modified) || entry->is_dir) {
+ if (entry->fp_type == PHAR_UFP) {
+ /* reset so we can copy the compressed data over */
+ entry->fp_type = PHAR_FP;
+ }
+ continue;
+ }
+ if (!phar_get_efp(entry, 0 TSRMLS_CC)) {
+ /* re-open internal file pointer just-in-time */
+ newentry = phar_open_jit(phar, entry, oldfile, error, 0 TSRMLS_CC);
+ if (!newentry) {
+ /* major problem re-opening, so we ignore this file and the error */
+ efree(*error);
+ *error = NULL;
+ continue;
+ }
+ entry = newentry;
+ }
+ file = phar_get_efp(entry, 0 TSRMLS_CC);
+ if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 1 TSRMLS_CC)) {
+ if (closeoldfile) {
+ php_stream_close(oldfile);
+ }
+ php_stream_close(newfile);
+ if (error) {
+ spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
+ }
+ return EOF;
+ }
+ newcrc32 = ~0;
+ mytime = entry->uncompressed_filesize;
+ for (loc = 0;loc < mytime; ++loc) {
+ CRC32(newcrc32, php_stream_getc(file));
+ }
+ entry->crc32 = ~newcrc32;
+ entry->is_crc_checked = 1;
+ if (!(entry->flags & PHAR_ENT_COMPRESSION_MASK)) {
+ /* not compressed */
+ entry->compressed_filesize = entry->uncompressed_filesize;
+ continue;
+ }
+ filter = php_stream_filter_create(phar_compress_filter(entry, 0), NULL, 0 TSRMLS_CC);
+ if (!filter) {
+ if (closeoldfile) {
+ php_stream_close(oldfile);
+ }
+ php_stream_close(newfile);
+ if (entry->flags & PHAR_ENT_COMPRESSED_GZ) {
+ if (error) {
+ spprintf(error, 0, "unable to gzip compress file \"%s\" to new phar \"%s\"", entry->filename, phar->fname);
+ }
+ } else {
+ if (error) {
+ spprintf(error, 0, "unable to bzip2 compress file \"%s\" to new phar \"%s\"", entry->filename, phar->fname);
+ }
+ }
+ return EOF;
+ }
+
+ /* create new file that holds the compressed version */
+ /* work around inability to specify freedom in write and strictness
+ in read count */
+ entry->cfp = php_stream_fopen_tmpfile();
+ if (!entry->cfp) {
+ if (error) {
+ spprintf(error, 0, "unable to create temporary file");
+ }
+ if (closeoldfile) {
+ php_stream_close(oldfile);
+ }
+ php_stream_close(newfile);
+ return EOF;
+ }
+ php_stream_flush(file);
+ if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC)) {
+ if (closeoldfile) {
+ php_stream_close(oldfile);
+ }
+ php_stream_close(newfile);
+ if (error) {
+ spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
+ }
+ return EOF;
+ }
+ php_stream_filter_append((&entry->cfp->writefilters), filter);
+ if (entry->uncompressed_filesize != php_stream_copy_to_stream(file, entry->cfp, entry->uncompressed_filesize)) {
+ if (closeoldfile) {
+ php_stream_close(oldfile);
+ }
+ php_stream_close(newfile);
+ if (error) {
+ spprintf(error, 0, "unable to copy compressed file contents of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
+ }
+ return EOF;
+ }
+ php_stream_filter_flush(filter, 1);
+ php_stream_flush(entry->cfp);
+ php_stream_filter_remove(filter, 1 TSRMLS_CC);
+ php_stream_seek(entry->cfp, 0, SEEK_END);
+ entry->compressed_filesize = (php_uint32) php_stream_tell(entry->cfp);
+ /* generate crc on compressed file */
+ php_stream_rewind(entry->cfp);
+ entry->old_flags = entry->flags;
+ entry->is_modified = 1;
+ global_flags |= (entry->flags & PHAR_ENT_COMPRESSION_MASK);
+ }
+ global_flags |= PHAR_HDR_SIGNATURE;
+
+ /* write out manifest pre-header */
+ /* 4: manifest length
+ * 4: manifest entry count
+ * 2: phar version
+ * 4: phar global flags
+ * 4: alias length
+ * ?: the alias itself
+ * 4: phar metadata length
+ * ?: phar metadata
+ */
+ restore_alias_len = phar->alias_len;
+ if (phar->is_temporary_alias) {
+ phar->alias_len = 0;
+ }
+
+ manifest_len = offset + phar->alias_len + sizeof(manifest) + main_metadata_str.len;
+ phar_set_32(manifest, manifest_len);
+ phar_set_32(manifest+4, new_manifest_count);
+ if (has_dirs) {
+ *(manifest + 8) = (unsigned char) (((PHAR_API_VERSION) >> 8) & 0xFF);
+ *(manifest + 9) = (unsigned char) (((PHAR_API_VERSION) & 0xF0));
+ } else {
+ *(manifest + 8) = (unsigned char) (((PHAR_API_VERSION_NODIR) >> 8) & 0xFF);
+ *(manifest + 9) = (unsigned char) (((PHAR_API_VERSION_NODIR) & 0xF0));
+ }
+ phar_set_32(manifest+10, global_flags);
+ phar_set_32(manifest+14, phar->alias_len);
+
+ /* write the manifest header */
+ if (sizeof(manifest) != php_stream_write(newfile, manifest, sizeof(manifest))
+ || (size_t)phar->alias_len != php_stream_write(newfile, phar->alias, phar->alias_len)) {
+ if (closeoldfile) {
+ php_stream_close(oldfile);
+ }
+ php_stream_close(newfile);
+ phar->alias_len = restore_alias_len;
+ if (error) {
+ spprintf(error, 0, "unable to write manifest header of new phar \"%s\"", phar->fname);
+ }
+ return EOF;
+ }
+
+ phar->alias_len = restore_alias_len;
+
+ phar_set_32(manifest, main_metadata_str.len);
+ if (4 != php_stream_write(newfile, manifest, 4) || (main_metadata_str.len
+ && main_metadata_str.len != php_stream_write(newfile, main_metadata_str.c, main_metadata_str.len))) {
+ smart_str_free(&main_metadata_str);
+ if (closeoldfile) {
+ php_stream_close(oldfile);
+ }
+ php_stream_close(newfile);
+ phar->alias_len = restore_alias_len;
+ if (error) {
+ spprintf(error, 0, "unable to write manifest meta-data of new phar \"%s\"", phar->fname);
+ }
+ return EOF;
+ }
+ smart_str_free(&main_metadata_str);
+
+ /* re-calculate the manifest location to simplify later code */
+ manifest_ftell = php_stream_tell(newfile);
+
+ /* now write the manifest */
+ for (zend_hash_internal_pointer_reset(&phar->manifest);
+ zend_hash_has_more_elements(&phar->manifest) == SUCCESS;
+ zend_hash_move_forward(&phar->manifest)) {
+ if (zend_hash_get_current_data(&phar->manifest, (void **)&entry) == FAILURE) {
+ continue;
+ }
+ if (entry->is_deleted || entry->is_mounted) {
+ /* remove this from the new phar if deleted, ignore if mounted */
+ continue;
+ }
+ if (entry->is_dir) {
+ /* add 1 for trailing slash */
+ phar_set_32(entry_buffer, entry->filename_len + 1);
+ } else {
+ phar_set_32(entry_buffer, entry->filename_len);
+ }
+ if (4 != php_stream_write(newfile, entry_buffer, 4)
+ || entry->filename_len != php_stream_write(newfile, entry->filename, entry->filename_len)
+ || (entry->is_dir && 1 != php_stream_write(newfile, "/", 1))) {
+ if (closeoldfile) {
+ php_stream_close(oldfile);
+ }
+ php_stream_close(newfile);
+ if (error) {
+ if (entry->is_dir) {
+ spprintf(error, 0, "unable to write filename of directory \"%s\" to manifest of new phar \"%s\"", entry->filename, phar->fname);
+ } else {
+ spprintf(error, 0, "unable to write filename of file \"%s\" to manifest of new phar \"%s\"", entry->filename, phar->fname);
+ }
+ }
+ return EOF;
+ }
+ /* set the manifest meta-data:
+ 4: uncompressed filesize
+ 4: creation timestamp
+ 4: compressed filesize
+ 4: crc32
+ 4: flags
+ 4: metadata-len
+ +: metadata
+ */
+ mytime = time(NULL);
+ phar_set_32(entry_buffer, entry->uncompressed_filesize);
+ phar_set_32(entry_buffer+4, mytime);
+ phar_set_32(entry_buffer+8, entry->compressed_filesize);
+ phar_set_32(entry_buffer+12, entry->crc32);
+ phar_set_32(entry_buffer+16, entry->flags);
+ phar_set_32(entry_buffer+20, entry->metadata_str.len);
+ if (sizeof(entry_buffer) != php_stream_write(newfile, entry_buffer, sizeof(entry_buffer))
+ || entry->metadata_str.len != php_stream_write(newfile, entry->metadata_str.c, entry->metadata_str.len)) {
+ if (closeoldfile) {
+ php_stream_close(oldfile);
+ }
+ php_stream_close(newfile);
+ if (error) {
+ spprintf(error, 0, "unable to write temporary manifest of file \"%s\" to manifest of new phar \"%s\"", entry->filename, phar->fname);
+ }
+ return EOF;
+ }
+ }
+
+ /* now copy the actual file data to the new phar */
+ offset = php_stream_tell(newfile);
+ for (zend_hash_internal_pointer_reset(&phar->manifest);
+ zend_hash_has_more_elements(&phar->manifest) == SUCCESS;
+ zend_hash_move_forward(&phar->manifest)) {
+ if (zend_hash_get_current_data(&phar->manifest, (void **)&entry) == FAILURE) {
+ continue;
+ }
+ if (entry->is_deleted || entry->is_dir || entry->is_mounted) {
+ continue;
+ }
+ if (entry->cfp) {
+ file = entry->cfp;
+ php_stream_rewind(file);
+ } else {
+ file = phar_get_efp(entry, 0 TSRMLS_CC);
+ if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC)) {
+ if (closeoldfile) {
+ php_stream_close(oldfile);
+ }
+ php_stream_close(newfile);
+ if (error) {
+ spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
+ }
+ return EOF;
+ }
+ }
+ if (!file) {
+ if (closeoldfile) {
+ php_stream_close(oldfile);
+ }
+ php_stream_close(newfile);
+ if (error) {
+ spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
+ }
+ return EOF;
+ }
+ /* this will have changed for all files that have either
+ changed compression or been modified */
+ entry->offset = entry->offset_abs = offset;
+ offset += entry->compressed_filesize;
+ wrote = php_stream_copy_to_stream(file, newfile, entry->compressed_filesize);
+ if (entry->compressed_filesize != wrote) {
+ if (closeoldfile) {
+ php_stream_close(oldfile);
+ }
+ php_stream_close(newfile);
+ if (error) {
+ spprintf(error, 0, "unable to write contents of file \"%s\" to new phar \"%s\"", entry->filename, phar->fname);
+ }
+ return EOF;
+ }
+ entry->is_modified = 0;
+ if (entry->cfp) {
+ php_stream_close(entry->cfp);
+ entry->cfp = NULL;
+ }
+ if (entry->fp_type == PHAR_MOD) {
+ /* this fp is in use by a phar_entry_data returned by phar_get_entry_data, it will be closed
+ when the phar_entry_data is phar_entry_delref'ed */
+ if (entry->fp_refcount == 0 && entry->fp != phar->fp && entry->fp != phar->ufp) {
+ php_stream_close(entry->fp);
+ }
+ entry->fp = NULL;
+ entry->fp_type = PHAR_FP;
+ } else if (entry->fp_type == PHAR_UFP) {
+ entry->fp_type = PHAR_FP;
+ }
+ }
+
+ /* append signature */
+ if (global_flags & PHAR_HDR_SIGNATURE) {
+ unsigned char buf[1024];
+ int sig_flags = 0, sig_len;
+ char sig_buf[4];
+
+ php_stream_rewind(newfile);
+
+ if (phar->signature) {
+ efree(phar->signature);
+ }
+
+ switch(phar->sig_flags) {
+#if HAVE_HASH_EXT
+ case PHAR_SIG_SHA512: {
+ unsigned char digest[64];
+ PHP_SHA512_CTX context;
+
+ PHP_SHA512Init(&context);
+ while ((sig_len = php_stream_read(newfile, (char*)buf, sizeof(buf))) > 0) {
+ PHP_SHA512Update(&context, buf, sig_len);
+ }
+ PHP_SHA512Final(digest, &context);
+ php_stream_write(newfile, (char *) digest, sizeof(digest));
+ sig_flags |= PHAR_SIG_SHA512;
+ phar->sig_len = phar_hex_str((const char*)digest, sizeof(digest), &phar->signature);
+ break;
+ }
+ case PHAR_SIG_SHA256: {
+ unsigned char digest[32];
+ PHP_SHA256_CTX context;
+
+ PHP_SHA256Init(&context);
+ while ((sig_len = php_stream_read(newfile, (char*)buf, sizeof(buf))) > 0) {
+ PHP_SHA256Update(&context, buf, sig_len);
+ }
+ PHP_SHA256Final(digest, &context);
+ php_stream_write(newfile, (char *) digest, sizeof(digest));
+ sig_flags |= PHAR_SIG_SHA256;
+ phar->sig_len = phar_hex_str((const char*)digest, sizeof(digest), &phar->signature);
+ break;
+ }
+#else
+ case PHAR_SIG_SHA512:
+ case PHAR_SIG_SHA256:
+ if (closeoldfile) {
+ php_stream_close(oldfile);
+ }
+ php_stream_close(newfile);
+ if (error) {
+ spprintf(error, 0, "unable to write contents of file \"%s\" to new phar \"%s\" with requested hash type", entry->filename, phar->fname);
+ }
+ return EOF;
+#endif
+ case PHAR_SIG_PGP:
+ /* TODO: currently fall back to sha1,later do both */
+ default:
+ case PHAR_SIG_SHA1: {
+ unsigned char digest[20];
+ PHP_SHA1_CTX context;
+
+ PHP_SHA1Init(&context);
+ while ((sig_len = php_stream_read(newfile, (char*)buf, sizeof(buf))) > 0) {
+ PHP_SHA1Update(&context, buf, sig_len);
+ }
+ PHP_SHA1Final(digest, &context);
+ php_stream_write(newfile, (char *) digest, sizeof(digest));
+ sig_flags |= PHAR_SIG_SHA1;
+ phar->sig_len = phar_hex_str((const char*)digest, sizeof(digest), &phar->signature);
+ break;
+ }
+ case PHAR_SIG_MD5: {
+ unsigned char digest[16];
+ PHP_MD5_CTX context;
+
+ PHP_MD5Init(&context);
+ while ((sig_len = php_stream_read(newfile, (char*)buf, sizeof(buf))) > 0) {
+ PHP_MD5Update(&context, buf, sig_len);
+ }
+ PHP_MD5Final(digest, &context);
+ php_stream_write(newfile, (char *) digest, sizeof(digest));
+ sig_flags |= PHAR_SIG_MD5;
+ phar->sig_len = phar_hex_str((const char*)digest, sizeof(digest), &phar->signature);
+ break;
+ }
+ }
+ phar_set_32(sig_buf, sig_flags);
+ php_stream_write(newfile, sig_buf, 4);
+ php_stream_write(newfile, "GBMB", 4);
+ phar->sig_flags = sig_flags;
+ }
+
+ /* finally, close the temp file, rename the original phar,
+ move the temp to the old phar, unlink the old phar, and reload it into memory
+ */
+ if (phar->fp && free_fp) {
+ php_stream_close(phar->fp);
+ }
+ if (phar->ufp) {
+ if (free_ufp) {
+ php_stream_close(phar->ufp);
+ }
+ phar->ufp = NULL;
+ }
+ if (closeoldfile) {
+ php_stream_close(oldfile);
+ }
+
+ phar->internal_file_start = halt_offset + manifest_len + 4;
+ phar->halt_offset = halt_offset;
+ phar->is_brandnew = 0;
+
+ php_stream_rewind(newfile);
+
+ if (phar->donotflush) {
+ /* deferred flush */
+ phar->fp = newfile;
+ } else {
+ phar->fp = php_stream_open_wrapper(phar->fname, "w+b", IGNORE_URL|STREAM_MUST_SEEK|REPORT_ERRORS, NULL);
+ if (!phar->fp) {
+ phar->fp = newfile;
+ if (error) {
+ spprintf(error, 4096, "unable to open new phar \"%s\" for writing", phar->fname);
+ }
+ return EOF;
+ }
+ if (phar->flags & PHAR_FILE_COMPRESSED_GZ) {
+ php_stream_filter *filter;
+ /* to properly compress, we have to tell zlib to add a zlib header */
+ zval filterparams;
+
+ array_init(&filterparams);
+ add_assoc_long(&filterparams, "window", MAX_WBITS+16);
+ filter = php_stream_filter_create("zlib.deflate", &filterparams, php_stream_is_persistent(phar->fp) TSRMLS_CC);
+ zval_dtor(&filterparams);
+ if (!filter) {
+ if (error) {
+ 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);
+ }
+ return EOF;
+ }
+ php_stream_filter_append(&phar->fp->writefilters, filter);
+ php_stream_copy_to_stream(newfile, phar->fp, PHP_STREAM_COPY_ALL);
+ php_stream_filter_flush(filter, 1);
+ php_stream_filter_remove(filter, 1 TSRMLS_CC);
+ php_stream_close(phar->fp);
+ /* use the temp stream as our base */
+ phar->fp = newfile;
+ } else if (phar->flags & PHAR_FILE_COMPRESSED_BZ2) {
+ php_stream_filter *filter;
+
+ filter = php_stream_filter_create("bzip2.compress", NULL, php_stream_is_persistent(phar->fp) TSRMLS_CC);
+ php_stream_filter_append(&phar->fp->writefilters, filter);
+ php_stream_copy_to_stream(newfile, phar->fp, PHP_STREAM_COPY_ALL);
+ php_stream_filter_flush(filter, 1);
+ php_stream_filter_remove(filter, 1 TSRMLS_CC);
+ php_stream_close(phar->fp);
+ /* use the temp stream as our base */
+ phar->fp = newfile;
+ } else {
+ php_stream_copy_to_stream(newfile, phar->fp, PHP_STREAM_COPY_ALL);
+ /* we could also reopen the file in "rb" mode but there is no need for that */
+ php_stream_close(newfile);
+ }
+ }
+
+ if (-1 == php_stream_seek(phar->fp, phar->halt_offset, SEEK_SET)) {
+ if (error) {
+ spprintf(error, 0, "unable to seek to __HALT_COMPILER(); in new phar \"%s\"", phar->fname);
+ }
+ return EOF;
+ }
+
+ return EOF;
+}
+/* }}} */
+
+#ifdef COMPILE_DL_PHAR
+ZEND_GET_MODULE(phar)
+#endif
+
+/* {{{ phar_functions[]
+ *
+ * Every user visible function must have an entry in phar_functions[].
+ */
+function_entry phar_functions[] = {
+ {NULL, NULL, NULL} /* Must be the last line in phar_functions[] */
+};
+/* }}}*/
+
+/* {{{ php_phar_init_globals
+ */
+static void php_phar_init_globals_module(zend_phar_globals *phar_globals)
+{
+ memset(phar_globals, 0, sizeof(zend_phar_globals));
+ phar_globals->readonly = 1;
+}
+/* }}} */
+
+#if PHP_VERSION_ID >= 50300
+static size_t phar_zend_stream_reader(void *handle, char *buf, size_t len TSRMLS_DC) /* {{{ */
+{
+ return php_stream_read(((phar_archive_data*)handle)->fp, buf, len);
+}
+/* }}} */
+
+static size_t phar_zend_stream_fsizer(void *handle TSRMLS_DC) /* {{{ */
+{
+ return ((phar_archive_data*)handle)->halt_offset + 32;
+} /* }}} */
+
+#else /* PHP_VERSION_ID */
+
+static long stream_fteller_for_zend(void *handle TSRMLS_DC) /* {{{ */
+{
+ return (long)php_stream_tell((php_stream*)handle);
+}
+/* }}} */
+#endif
+
+zend_op_array *(*phar_orig_compile_file)(zend_file_handle *file_handle, int type TSRMLS_DC);
+#if PHP_VERSION_ID >= 50300
+#define phar_orig_zend_open zend_stream_open_function
+char *phar_resolve_path(const char *filename, int filename_len TSRMLS_DC)
+{
+ return phar_find_in_include_path((char *) filename, filename_len, NULL TSRMLS_CC);
+}
+#else
+int (*phar_orig_zend_open)(const char *filename, zend_file_handle *handle TSRMLS_DC);
+#endif
+
+static zend_op_array *phar_compile_file(zend_file_handle *file_handle, int type TSRMLS_DC) /* {{{ */
+{
+ zend_op_array *res;
+ char *name = NULL;
+ int failed;
+ phar_archive_data *phar;
+
+ if (strstr(file_handle->filename, ".phar") && !strstr(file_handle->filename, "://")) {
+ if (SUCCESS == phar_open_filename(file_handle->filename, strlen(file_handle->filename), NULL, 0, 0, &phar, NULL TSRMLS_CC)) {
+ if (phar->is_zip || phar->is_tar) {
+ zend_file_handle f = *file_handle;
+
+ /* zip or tar-based phar */
+ spprintf(&name, 4096, "phar://%s/%s", file_handle->filename, ".phar/stub.php");
+ if (SUCCESS == phar_orig_zend_open((const char *)name, file_handle TSRMLS_CC)) {
+ efree(name);
+ name = NULL;
+ file_handle->filename = f.filename;
+ if (file_handle->opened_path) {
+ efree(file_handle->opened_path);
+ }
+ file_handle->opened_path = f.opened_path;
+ file_handle->free_filename = f.free_filename;
+ } else {
+ *file_handle = f;
+ }
+ } else if (phar->flags & PHAR_FILE_COMPRESSION_MASK) {
+ /* compressed phar */
+#if PHP_VERSION_ID >= 50300 && PHP_VERSION_ID < 60000
+ file_handle->type = ZEND_HANDLE_STREAM;
+ file_handle->free_filename = 0;
+ file_handle->handle.stream.handle = phar;
+ file_handle->handle.stream.reader = phar_zend_stream_reader;
+ file_handle->handle.stream.closer = NULL;
+ file_handle->handle.stream.fsizer = phar_zend_stream_fsizer;
+ file_handle->handle.stream.isatty = 0;
+ php_stream_rewind(phar->fp);
+ memset(&file_handle->handle.stream.mmap, 0, sizeof(file_handle->handle.stream.mmap));
+#else /* PHP_VERSION_ID */
+ file_handle->type = ZEND_HANDLE_STREAM;
+ file_handle->free_filename = 0;
+ file_handle->handle.stream.handle = phar->fp;
+ file_handle->handle.stream.reader = (zend_stream_reader_t)_php_stream_read;
+ file_handle->handle.stream.closer = NULL; /* don't close - let phar handle this one */
+ file_handle->handle.stream.fteller = stream_fteller_for_zend;
+ file_handle->handle.stream.interactive = 0;
+ php_stream_rewind(phar->fp);
+#endif
+ }
+ }
+ }
+ zend_try {
+ failed = 0;
+ res = phar_orig_compile_file(file_handle, type TSRMLS_CC);
+ } zend_catch {
+ failed = 1;
+ } zend_end_try();
+ if (name) {
+ efree(name);
+ }
+ if (failed) {
+ zend_bailout();
+ }
+ return res;
+}
+/* }}} */
+
+#if PHP_VERSION_ID < 50300
+int phar_zend_open(const char *filename, zend_file_handle *handle TSRMLS_DC) /* {{{ */
+{
+ char *arch, *entry;
+ int arch_len, entry_len;
+
+ /* this code is obsoleted in php 5.3 */
+ entry = (char *) filename;
+ if (!IS_ABSOLUTE_PATH(entry, strlen(entry)) && !strstr(entry, "://")) {
+ phar_archive_data **pphar = NULL;
+ char *fname;
+ int fname_len;
+
+ fname = zend_get_executed_filename(TSRMLS_C);
+ fname_len = strlen(fname);
+ if (fname_len > 7 && !strncasecmp(fname, "phar://", 7)) {
+ if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 1, 0 TSRMLS_CC)) {
+ zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar);
+ efree(arch);
+ efree(entry);
+ }
+ }
+ /* retrieving an include within the current directory, so use this if possible */
+ if (!(entry = phar_find_in_include_path((char *) filename, strlen(filename), NULL TSRMLS_CC))) {
+ /* this file is not in the phar, use the original path */
+ goto skip_phar;
+ }
+ if (SUCCESS == phar_orig_zend_open(entry, handle TSRMLS_CC)) {
+ if (!handle->opened_path) {
+ handle->opened_path = entry;
+ }
+ if (entry != filename) {
+ handle->free_filename = 1;
+ }
+ return SUCCESS;
+ }
+ if (entry != filename) {
+ efree(entry);
+ }
+ return FAILURE;
+ }
+skip_phar:
+ return phar_orig_zend_open(filename, handle TSRMLS_CC);
+}
+/* }}} */
+#endif
+typedef zend_op_array* (zend_compile_t)(zend_file_handle*, int TSRMLS_DC);
+typedef zend_compile_t* (compile_hook)(zend_compile_t *ptr);
+
+PHP_MINIT_FUNCTION(phar) /* {{{ */
+{
+ ZEND_INIT_MODULE_GLOBALS(phar, php_phar_init_globals_module, NULL);
+ REGISTER_INI_ENTRIES();
+
+ phar_has_bz2 = zend_hash_exists(&module_registry, "bz2", sizeof("bz2"));
+ phar_has_zlib = zend_hash_exists(&module_registry, "zlib", sizeof("zlib"));
+ phar_orig_compile_file = zend_compile_file;
+ zend_compile_file = phar_compile_file;
+
+#if PHP_VERSION_ID >= 50300
+ phar_save_resolve_path = zend_resolve_path;
+ zend_resolve_path = phar_resolve_path;
+#else
+ phar_orig_zend_open = zend_stream_open_function;
+ zend_stream_open_function = phar_zend_open;
+#endif
+
+ phar_object_init(TSRMLS_C);
+
+ return php_register_url_stream_wrapper("phar", &php_stream_phar_wrapper TSRMLS_CC);
+}
+/* }}} */
+
+PHP_MSHUTDOWN_FUNCTION(phar) /* {{{ */
+{
+ return php_unregister_url_stream_wrapper("phar" TSRMLS_CC);
+ if (zend_compile_file == phar_compile_file) {
+ zend_compile_file = phar_orig_compile_file;
+ }
+
+#if PHP_VERSION_ID < 50300
+ if (zend_stream_open_function == phar_zend_open) {
+ zend_stream_open_function = phar_orig_zend_open;
+ }
+#endif
+}
+/* }}} */
+
+void phar_request_initialize(TSRMLS_D) /* {{{ */
+{
+ if (!PHAR_GLOBALS->request_init)
+ {
+ PHAR_GLOBALS->request_init = 1;
+ PHAR_GLOBALS->request_ends = 0;
+ PHAR_GLOBALS->request_done = 0;
+ zend_hash_init(&(PHAR_GLOBALS->phar_fname_map), sizeof(phar_archive_data*), zend_get_hash_value, destroy_phar_data, 0);
+ zend_hash_init(&(PHAR_GLOBALS->phar_alias_map), sizeof(phar_archive_data*), zend_get_hash_value, NULL, 0);
+ zend_hash_init(&(PHAR_GLOBALS->phar_SERVER_mung_list), sizeof(const char *), zend_get_hash_value, NULL, 0);
+ PHAR_G(cwd) = NULL;
+ PHAR_G(cwd_len) = 0;
+ PHAR_G(cwd_init) = 0;
+ phar_intercept_functions(TSRMLS_C);
+ }
+}
+/* }}} */
+
+PHP_RSHUTDOWN_FUNCTION(phar) /* {{{ */
+{
+ PHAR_GLOBALS->request_ends = 1;
+ if (PHAR_GLOBALS->request_init)
+ {
+ phar_release_functions(TSRMLS_C);
+ zend_hash_destroy(&(PHAR_GLOBALS->phar_alias_map));
+ PHAR_GLOBALS->phar_alias_map.arBuckets = NULL;
+ zend_hash_destroy(&(PHAR_GLOBALS->phar_fname_map));
+ PHAR_GLOBALS->phar_fname_map.arBuckets = NULL;
+ zend_hash_destroy(&(PHAR_GLOBALS->phar_SERVER_mung_list));
+ PHAR_GLOBALS->phar_SERVER_mung_list.arBuckets = NULL;
+ PHAR_GLOBALS->request_init = 0;
+ if (PHAR_G(cwd)) {
+ efree(PHAR_G(cwd));
+ }
+ PHAR_G(cwd) = NULL;
+ PHAR_G(cwd_len) = 0;
+ PHAR_G(cwd_init) = 0;
+ }
+ PHAR_GLOBALS->request_done = 1;
+ return SUCCESS;
+}
+/* }}} */
+
+PHP_MINFO_FUNCTION(phar) /* {{{ */
+{
+ php_info_print_table_start();
+ php_info_print_table_header(2, "Phar: PHP Archive support", "enabled");
+ php_info_print_table_row(2, "Phar EXT version", PHP_PHAR_VERSION);
+ php_info_print_table_row(2, "Phar API version", PHP_PHAR_API_VERSION);
+ php_info_print_table_row(2, "CVS revision", "$Revision$");
+ php_info_print_table_row(2, "Phar-based phar archives", "enabled");
+ php_info_print_table_row(2, "Tar-based phar archives", "enabled");
+ php_info_print_table_row(2, "ZIP-based phar archives", "enabled");
+ if (phar_has_zlib) {
+ php_info_print_table_row(2, "gzip compression", "enabled");
+ } else {
+ php_info_print_table_row(2, "gzip compression", "disabled (install ext/zlib)");
+ }
+ if (phar_has_bz2) {
+ php_info_print_table_row(2, "bzip2 compression", "enabled");
+ } else {
+ php_info_print_table_row(2, "bzip2 compression", "disabled (install pecl/bz2)");
+ }
+ php_info_print_table_end();
+
+ php_info_print_box_start(0);
+ PUTS("Phar based on pear/PHP_Archive, original concept by Davey Shafik.");
+ PUTS(!sapi_module.phpinfo_as_text?"<br />":"\n");
+ PUTS("Phar fully realized by Gregory Beaver and Marcus Boerger.");
+ PUTS(!sapi_module.phpinfo_as_text?"<br />":"\n");
+ PUTS("Portions of tar implementation Copyright (c) 2003-2007 Tim Kientzle.");
+ php_info_print_box_end();
+
+ DISPLAY_INI_ENTRIES();
+}
+/* }}} */
+
+/* {{{ phar_module_entry
+ */
+static zend_module_dep phar_deps[] = {
+ ZEND_MOD_OPTIONAL("apc")
+ ZEND_MOD_OPTIONAL("zlib")
+ ZEND_MOD_OPTIONAL("bz2")
+#if HAVE_SPL
+ ZEND_MOD_REQUIRED("spl")
+#endif
+ {NULL, NULL, NULL}
+};
+
+zend_module_entry phar_module_entry = {
+ STANDARD_MODULE_HEADER_EX, NULL,
+ phar_deps,
+ "Phar",
+ phar_functions,
+ PHP_MINIT(phar),
+ PHP_MSHUTDOWN(phar),
+ NULL,
+ PHP_RSHUTDOWN(phar),
+ PHP_MINFO(phar),
+ PHP_PHAR_VERSION,
+ STANDARD_MODULE_PROPERTIES
+};
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
diff --git a/ext/phar/phar.phar b/ext/phar/phar.phar
new file mode 100755
index 0000000000..f26ce2b756
--- /dev/null
+++ b/ext/phar/phar.phar
@@ -0,0 +1,1229 @@
+#!/usr/bin/php
+<?php if (!class_exists('PHP_Archive')) {
+?><?php
+/**
+ * PHP_Archive Class (implements .phar)
+ *
+ * @package PHP_Archive
+ * @category PHP
+ */
+/**
+ * PHP_Archive Class (implements .phar)
+ *
+ * PHAR files a singular archive from which an entire application can run.
+ * To use it, simply package it using {@see PHP_Archive_Creator} and use phar://
+ * URIs to your includes. i.e. require_once 'phar://config.php' will include config.php
+ * from the root of the PHAR file.
+ *
+ * Gz code borrowed from the excellent File_Archive package by Vincent Lascaux.
+ *
+ * @copyright Copyright David Shafik and Synaptic Media 2004. All rights reserved.
+ * @author Davey Shafik <davey@synapticmedia.net>
+ * @author Greg Beaver <cellog@php.net>
+ * @link http://www.synapticmedia.net Synaptic Media
+ * @version $Id: Archive.php,v 1.52 2007/09/01 20:28:14 cellog Exp $
+ * @package PHP_Archive
+ * @category PHP
+ */
+
+class PHP_Archive
+{
+ const GZ = 0x00001000;
+ const BZ2 = 0x00002000;
+ const SIG = 0x00010000;
+ const SHA1 = 0x0002;
+ const MD5 = 0x0001;
+ /**
+ * Whether this archive is compressed with zlib
+ *
+ * @var bool
+ */
+ private $_compressed;
+ /**
+ * @var string Real path to the .phar archive
+ */
+ private $_archiveName = null;
+ /**
+ * Current file name in the phar
+ * @var string
+ */
+ protected $currentFilename = null;
+ /**
+ * Length of current file in the phar
+ * @var string
+ */
+ protected $internalFileLength = null;
+ /**
+ * Current file statistics (size, creation date, etc.)
+ * @var string
+ */
+ protected $currentStat = null;
+ /**
+ * @var resource|null Pointer to open .phar
+ */
+ protected $fp = null;
+ /**
+ * @var int Current Position of the pointer
+ */
+ protected $position = 0;
+
+ /**
+ * Map actual realpath of phars to meta-data about the phar
+ *
+ * Data is indexed by the alias that is used by internal files. In other
+ * words, if a file is included via:
+ * <code>
+ * require_once 'phar://PEAR.phar/PEAR/Installer.php';
+ * </code>
+ * then the alias is "PEAR.phar"
+ *
+ * Information stored is a boolean indicating whether this .phar is compressed
+ * with zlib, another for bzip2, phar-specific meta-data, and
+ * the precise offset of internal files
+ * within the .phar, used with the {@link $_manifest} to load actual file contents
+ * @var array
+ */
+ private static $_pharMapping = array();
+ /**
+ * Map real file paths to alias used
+ *
+ * @var array
+ */
+ private static $_pharFiles = array();
+ /**
+ * File listing for the .phar
+ *
+ * The manifest is indexed per phar.
+ *
+ * Files within the .phar are indexed by their relative path within the
+ * .phar. Each file has this information in its internal array
+ *
+ * - 0 = uncompressed file size
+ * - 1 = timestamp of when file was added to phar
+ * - 2 = offset of file within phar relative to internal file's start
+ * - 3 = compressed file size (actual size in the phar)
+ * @var array
+ */
+ private static $_manifest = array();
+ /**
+ * Absolute offset of internal files within the .phar, indexed by absolute
+ * path to the .phar
+ *
+ * @var array
+ */
+ private static $_fileStart = array();
+ /**
+ * file name of the phar
+ *
+ * @var string
+ */
+ private $_basename;
+
+
+ /**
+ * Default MIME types used for the web front controller
+ *
+ * @var array
+ */
+ public static $defaultmimes = array(
+ 'aif' => 'audio/x-aiff',
+ 'aiff' => 'audio/x-aiff',
+ 'arc' => 'application/octet-stream',
+ 'arj' => 'application/octet-stream',
+ 'art' => 'image/x-jg',
+ 'asf' => 'video/x-ms-asf',
+ 'asx' => 'video/x-ms-asf',
+ 'avi' => 'video/avi',
+ 'bin' => 'application/octet-stream',
+ 'bm' => 'image/bmp',
+ 'bmp' => 'image/bmp',
+ 'bz2' => 'application/x-bzip2',
+ 'css' => 'text/css',
+ 'doc' => 'application/msword',
+ 'dot' => 'application/msword',
+ 'dv' => 'video/x-dv',
+ 'dvi' => 'application/x-dvi',
+ 'eps' => 'application/postscript',
+ 'exe' => 'application/octet-stream',
+ 'gif' => 'image/gif',
+ 'gz' => 'application/x-gzip',
+ 'gzip' => 'application/x-gzip',
+ 'htm' => 'text/html',
+ 'html' => 'text/html',
+ 'ico' => 'image/x-icon',
+ 'jpe' => 'image/jpeg',
+ 'jpg' => 'image/jpeg',
+ 'jpeg' => 'image/jpeg',
+ 'js' => 'application/x-javascript',
+ 'log' => 'text/plain',
+ 'mid' => 'audio/x-midi',
+ 'mov' => 'video/quicktime',
+ 'mp2' => 'audio/mpeg',
+ 'mp3' => 'audio/mpeg3',
+ 'mpg' => 'audio/mpeg',
+ 'pdf' => 'aplication/pdf',
+ 'png' => 'image/png',
+ 'rtf' => 'application/rtf',
+ 'tif' => 'image/tiff',
+ 'tiff' => 'image/tiff',
+ 'txt' => 'text/plain',
+ 'xml' => 'text/xml',
+ );
+
+ public static $defaultphp = array(
+ 'php' => true
+ );
+
+ public static $defaultphps = array(
+ 'phps' => true
+ );
+
+ public static $deny = array('/.+\.inc$/');
+
+ public static function viewSource($archive, $file)
+ {
+ // security, idea borrowed from PHK
+ if (!file_exists($archive . '.introspect')) {
+ header("HTTP/1.0 404 Not Found");
+ return false;
+ }
+ if (self::_fileExists($archive, $_GET['viewsource'])) {
+ $source = highlight_file('phar://@ALIAS@/' .
+ $_GET['viewsource'], true);
+ header('Content-Type: text/html');
+ header('Content-Length: ' . strlen($source));
+ echo '<html><head><title>Source of ',
+ htmlspecialchars($_GET['viewsource']), '</title></head>';
+ echo '<body><h1>Source of ',
+ htmlspecialchars($_GET['viewsource']), '</h1>';
+ if (isset($_GET['introspect'])) {
+ echo '<a href="', htmlspecialchars($_SERVER['PHP_SELF']),
+ '?introspect=', urlencode(htmlspecialchars($_GET['introspect'])),
+ '">Return to ', htmlspecialchars($_GET['introspect']), '</a><br />';
+ }
+ echo $source;
+ return false;
+ } else {
+ header("HTTP/1.0 404 Not Found");
+ return false;
+ }
+
+ }
+
+ public static function introspect($archive, $dir)
+ {
+ // security, idea borrowed from PHK
+ if (!file_exists($archive . '.introspect')) {
+ header("HTTP/1.0 404 Not Found");
+ return false;
+ }
+ if (!$dir) {
+ $dir = '/';
+ }
+ $dir = self::processFile($dir);
+ if ($dir[0] != '/') {
+ $dir = '/' . $dir;
+ }
+ try {
+ $self = htmlspecialchars($_SERVER['PHP_SELF']);
+ $iterate = new DirectoryIterator('phar://@ALIAS@' . $dir);
+ echo '<html><head><title>Introspect ', htmlspecialchars($dir),
+ '</title></head><body><h1>Introspect ', htmlspecialchars($dir),
+ '</h1><ul>';
+ if ($dir != '/') {
+ echo '<li><a href="', $self, '?introspect=',
+ htmlspecialchars(dirname($dir)), '">..</a></li>';
+ }
+ foreach ($iterate as $entry) {
+ if ($entry->isDot()) continue;
+ $name = self::processFile($entry->getPathname());
+ $name = str_replace('phar://@ALIAS@/', '', $name);
+ if ($entry->isDir()) {
+ echo '<li><a href="', $self, '?introspect=',
+ urlencode(htmlspecialchars($name)),
+ '">',
+ htmlspecialchars($entry->getFilename()), '/</a> [directory]</li>';
+ } else {
+ echo '<li><a href="', $self, '?introspect=',
+ urlencode(htmlspecialchars($dir)), '&viewsource=',
+ urlencode(htmlspecialchars($name)),
+ '">',
+ htmlspecialchars($entry->getFilename()), '</a></li>';
+ }
+ }
+ return false;
+ } catch (Exception $e) {
+ echo '<html><head><title>Directory not found: ',
+ htmlspecialchars($dir), '</title></head>',
+ '<body><h1>Directory not found: ', htmlspecialchars($dir), '</h1>',
+ '<p>Try <a href="', htmlspecialchars($_SERVER['PHP_SELF']), '?introspect=/">',
+ 'This link</a></p></body></html>';
+ return false;
+ }
+ }
+
+ public static function webFrontController($initfile)
+ {
+ if (isset($_SERVER) && isset($_SERVER['REQUEST_URI'])) {
+ $uri = parse_url($_SERVER['REQUEST_URI']);
+ $archive = realpath($_SERVER['SCRIPT_FILENAME']);
+ $subpath = str_replace('/' . basename($archive), '', $uri['path']);
+ if (!$subpath || $subpath == '/') {
+ if (isset($_GET['viewsource'])) {
+ return self::viewSource($archive, $_GET['viewsource']);
+ }
+ if (isset($_GET['introspect'])) {
+ return self::introspect($archive, $_GET['introspect']);
+ }
+ $subpath = '/' . $initfile;
+ }
+ if (!self::_fileExists($archive, substr($subpath, 1))) {
+ header("HTTP/1.0 404 Not Found");
+ return false;
+ }
+ foreach (self::$deny as $pattern) {
+ if (preg_match($pattern, $subpath)) {
+ header("HTTP/1.0 404 Not Found");
+ return false;
+ }
+ }
+ $inf = pathinfo(basename($subpath));
+ if (!isset($inf['extension'])) {
+ header('Content-Type: text/plain');
+ header('Content-Length: ' .
+ self::_filesize($archive, substr($subpath, 1)));
+ readfile('phar://@ALIAS@' . $subpath);
+ return false;
+ }
+ if (isset(self::$defaultphp[$inf['extension']])) {
+ include 'phar://@ALIAS@' . $subpath;
+ return false;
+ }
+ if (isset(self::$defaultmimes[$inf['extension']])) {
+ header('Content-Type: ' . self::$defaultmimes[$inf['extension']]);
+ header('Content-Length: ' .
+ self::_filesize($archive, substr($subpath, 1)));
+ readfile('phar://@ALIAS@' . $subpath);
+ return false;
+ }
+ if (isset(self::$defaultphps[$inf['extension']])) {
+ header('Content-Type: text/html');
+ $c = highlight_file('phar://@ALIAS@' . $subpath, true);
+ header('Content-Length: ' . strlen($c));
+ echo $c;
+ return false;
+ }
+ header('Content-Type: text/plain');
+ header('Content-Length: ' .
+ self::_filesize($archive, substr($subpath, 1)));
+ readfile('phar://@ALIAS@' . $subpath);
+ }
+ }
+
+ /**
+ * Detect end of stub
+ *
+ * @param string $buffer stub past '__HALT_'.'COMPILER();'
+ * @return end of stub, prior to length of manifest.
+ */
+ private static final function _endOfStubLength($buffer)
+ {
+ $pos = 0;
+ if (!strlen($buffer)) {
+ return $pos;
+ }
+ if (($buffer[0] == ' ' || $buffer[0] == "\n") && @substr($buffer, 1, 2) == '?>')
+ {
+ $pos += 3;
+ if ($buffer[$pos] == "\r" && $buffer[$pos+1] == "\n") {
+ $pos += 2;
+ }
+ else if ($buffer[$pos] == "\n") {
+ $pos += 1;
+ }
+ }
+ return $pos;
+ }
+
+ /**
+ * Allows loading an external Phar archive without include()ing it
+ *
+ * @param string $file phar package to load
+ * @param string $alias alias to use
+ * @throws Exception
+ */
+ public static final function loadPhar($file, $alias = NULL)
+ {
+ $file = realpath($file);
+ if ($file) {
+ $fp = fopen($file, 'rb');
+ $buffer = '';
+ while (!feof($fp)) {
+ $buffer .= fread($fp, 8192);
+ // don't break phars
+ if ($pos = strpos($buffer, '__HALT_COMPI' . 'LER();')) {
+ $buffer .= fread($fp, 5);
+ fclose($fp);
+ $pos += 18;
+ $pos += self::_endOfStubLength(substr($buffer, $pos));
+ return self::_mapPhar($file, $pos, $alias);
+ }
+ }
+ fclose($fp);
+ }
+ }
+
+ /**
+ * Map a full real file path to an alias used to refer to the .phar
+ *
+ * This function can only be called from the initialization of the .phar itself.
+ * Any attempt to call from outside the .phar or to re-alias the .phar will fail
+ * as a security measure.
+ * @param string $alias
+ * @param int $dataoffset the value of __COMPILER_HALT_OFFSET__
+ */
+ public static final function mapPhar($alias = NULL, $dataoffset = NULL)
+ {
+ try {
+ $trace = debug_backtrace();
+ $file = $trace[0]['file'];
+ // this ensures that this is safe
+ if (!in_array($file, get_included_files())) {
+ die('SECURITY ERROR: PHP_Archive::mapPhar can only be called from within ' .
+ 'the phar that initiates it');
+ }
+ $file = realpath($file);
+ if (!isset($dataoffset)) {
+ $dataoffset = constant('__COMPILER_HALT_OFFSET'.'__');
+ $fp = fopen($file, 'rb');
+ fseek($fp, $dataoffset, SEEK_SET);
+ $dataoffset = $dataoffset + self::_endOfStubLength(fread($fp, 5));
+ fclose($fp);
+ }
+
+ self::_mapPhar($file, $dataoffset);
+ } catch (Exception $e) {
+ die($e->getMessage());
+ }
+ }
+
+ /**
+ * Sub-function, allows recovery from errors
+ *
+ * @param unknown_type $file
+ * @param unknown_type $dataoffset
+ */
+ private static function _mapPhar($file, $dataoffset, $alias = NULL)
+ {
+ $file = realpath($file);
+ if (isset(self::$_manifest[$file])) {
+ return;
+ }
+ if (!is_array(self::$_pharMapping)) {
+ self::$_pharMapping = array();
+ }
+ $fp = fopen($file, 'rb');
+ // seek to __HALT_COMPILER_OFFSET__
+ fseek($fp, $dataoffset);
+ $manifest_length = unpack('Vlen', fread($fp, 4));
+ $manifest = '';
+ $last = '1';
+ while (strlen($last) && strlen($manifest) < $manifest_length['len']) {
+ $read = 8192;
+ if ($manifest_length['len'] - strlen($manifest) < 8192) {
+ $read = $manifest_length['len'] - strlen($manifest);
+ }
+ $last = fread($fp, $read);
+ $manifest .= $last;
+ }
+ if (strlen($manifest) < $manifest_length['len']) {
+ throw new Exception('ERROR: manifest length read was "' .
+ strlen($manifest) .'" should be "' .
+ $manifest_length['len'] . '"');
+ }
+ $info = self::_unserializeManifest($manifest);
+ if ($info['alias']) {
+ $alias = $info['alias'];
+ $explicit = true;
+ } else {
+ if (!isset($alias)) {
+ $alias = $file;
+ }
+ $explicit = false;
+ }
+ self::$_manifest[$file] = $info['manifest'];
+ $compressed = $info['compressed'];
+ self::$_fileStart[$file] = ftell($fp);
+ fclose($fp);
+ if ($compressed & 0x00001000) {
+ if (!function_exists('gzinflate')) {
+ throw new Exception('Error: zlib extension is not enabled - gzinflate() function needed' .
+ ' for compressed .phars');
+ }
+ }
+ if ($compressed & 0x00002000) {
+ if (!function_exists('bzdecompress')) {
+ throw new Exception('Error: bzip2 extension is not enabled - bzdecompress() function needed' .
+ ' for compressed .phars');
+ }
+ }
+ if (isset(self::$_pharMapping[$alias])) {
+ throw new Exception('ERROR: PHP_Archive::mapPhar has already been called for alias "' .
+ $alias . '" cannot re-alias to "' . $file . '"');
+ }
+ self::$_pharMapping[$alias] = array($file, $compressed, $dataoffset, $explicit,
+ $info['metadata']);
+ self::$_pharFiles[$file] = $alias;
+ }
+
+ /**
+ * extract the manifest into an internal array
+ *
+ * @param string $manifest
+ * @return false|array
+ */
+ private static function _unserializeManifest($manifest)
+ {
+ // retrieve the number of files in the manifest
+ $info = unpack('V', substr($manifest, 0, 4));
+ $apiver = substr($manifest, 4, 2);
+ $apiver = bin2hex($apiver);
+ $apiver_dots = hexdec($apiver[0]) . '.' . hexdec($apiver[1]) . '.' . hexdec($apiver[2]);
+ $majorcompat = hexdec($apiver[0]);
+ $calcapi = explode('.', self::APIVersion());
+ if ($calcapi[0] != $majorcompat) {
+ throw new Exception('Phar is incompatible API version ' . $apiver_dots . ', but ' .
+ 'PHP_Archive is API version '.self::APIVersion());
+ }
+ if ($calcapi[0] === '0') {
+ if (self::APIVersion() != $apiver_dots) {
+ throw new Exception('Phar is API version ' . $apiver_dots .
+ ', but PHP_Archive is API version '.self::APIVersion(), E_USER_ERROR);
+ }
+ }
+ $flags = unpack('V', substr($manifest, 6, 4));
+ $ret = array('compressed' => $flags & 0x00003000);
+ // signature is not verified by default in PHP_Archive, phar is better
+ $ret['hassignature'] = $flags & 0x00010000;
+ $aliaslen = unpack('V', substr($manifest, 10, 4));
+ if ($aliaslen) {
+ $ret['alias'] = substr($manifest, 14, $aliaslen[1]);
+ } else {
+ $ret['alias'] = false;
+ }
+ $manifest = substr($manifest, 14 + $aliaslen[1]);
+ $metadatalen = unpack('V', substr($manifest, 0, 4));
+ if ($metadatalen[1]) {
+ $ret['metadata'] = unserialize(substr($manifest, 4, $metadatalen[1]));
+ $manifest = substr($manifest, 4 + $metadatalen[1]);
+ } else {
+ $ret['metadata'] = null;
+ $manifest = substr($manifest, 4);
+ }
+ $offset = 0;
+ $start = 0;
+ for ($i = 0; $i < $info[1]; $i++) {
+ // length of the file name
+ $len = unpack('V', substr($manifest, $start, 4));
+ $start += 4;
+ // file name
+ $savepath = substr($manifest, $start, $len[1]);
+ $start += $len[1];
+ // retrieve manifest data:
+ // 0 = uncompressed file size
+ // 1 = timestamp of when file was added to phar
+ // 2 = compressed filesize
+ // 3 = crc32
+ // 4 = flags
+ // 5 = metadata length
+ $ret['manifest'][$savepath] = array_values(unpack('Va/Vb/Vc/Vd/Ve/Vf', substr($manifest, $start, 24)));
+ $ret['manifest'][$savepath][3] = sprintf('%u', $ret['manifest'][$savepath][3]
+ & 0xffffffff);
+ if ($ret['manifest'][$savepath][5]) {
+ $ret['manifest'][$savepath][6] = unserialize(substr($manifest, $start + 24,
+ $ret['manifest'][$savepath][5]));
+ } else {
+ $ret['manifest'][$savepath][6] = null;
+ }
+ $ret['manifest'][$savepath][7] = $offset;
+ $offset += $ret['manifest'][$savepath][2];
+ $start += 24 + $ret['manifest'][$savepath][5];
+ }
+ return $ret;
+ }
+
+ /**
+ * @param string
+ */
+ private static function processFile($path)
+ {
+ if ($path == '.') {
+ return '';
+ }
+ $std = str_replace("\\", "/", $path);
+ while ($std != ($std = ereg_replace("[^\/:?]+/\.\./", "", $std))) ;
+ $std = str_replace("/./", "", $std);
+ if (strlen($std) > 1 && $std[0] == '/') {
+ $std = substr($std, 1);
+ }
+ if (strncmp($std, "./", 2) == 0) {
+ return substr($std, 2);
+ } else {
+ return $std;
+ }
+ }
+
+ /**
+ * Seek in the master archive to a matching file or directory
+ * @param string
+ */
+ protected function selectFile($path, $allowdirs = true)
+ {
+ $std = self::processFile($path);
+ if (isset(self::$_manifest[$this->_archiveName][$path])) {
+ $this->_setCurrentFile($path);
+ return true;
+ }
+ if (!$allowdirs) {
+ return 'Error: "' . $path . '" is not a file in phar "' . $this->_basename . '"';
+ }
+ foreach (self::$_manifest[$this->_archiveName] as $file => $info) {
+ if (empty($std) ||
+ //$std is a directory
+ strncmp($std.'/', $path, strlen($std)+1) == 0) {
+ $this->currentFilename = $this->internalFileLength = $this->currentStat = null;
+ return true;
+ }
+ }
+ return 'Error: "' . $path . '" not found in phar "' . $this->_basename . '"';
+ }
+
+ private function _setCurrentFile($path)
+ {
+ $this->currentStat = array(
+ 2 => 0100444, // file mode, readable by all, writeable by none
+ 4 => 0, // uid
+ 5 => 0, // gid
+ 7 => self::$_manifest[$this->_archiveName][$path][0], // size
+ 9 => self::$_manifest[$this->_archiveName][$path][1], // creation time
+ );
+ $this->currentFilename = $path;
+ $this->internalFileLength = self::$_manifest[$this->_archiveName][$path][2];
+ // seek to offset of file header within the .phar
+ if (is_resource(@$this->fp)) {
+ fseek($this->fp, self::$_fileStart[$this->_archiveName] + self::$_manifest[$this->_archiveName][$path][7]);
+ }
+ }
+
+ private static function _fileExists($archive, $path)
+ {
+ return isset(self::$_manifest[$archive]) &&
+ isset(self::$_manifest[$archive][$path]);
+ }
+
+ private static function _filesize($archive, $path)
+ {
+ return self::$_manifest[$archive][$path][0];
+ }
+
+ /**
+ * Seek to a file within the master archive, and extract its contents
+ * @param string
+ * @return array|string an array containing an error message string is returned
+ * upon error, otherwise the file contents are returned
+ */
+ public function extractFile($path)
+ {
+ $this->fp = @fopen($this->_archiveName, "rb");
+ if (!$this->fp) {
+ return array('Error: cannot open phar "' . $this->_archiveName . '"');
+ }
+ if (($e = $this->selectFile($path, false)) === true) {
+ $data = '';
+ $count = $this->internalFileLength;
+ while ($count) {
+ if ($count < 8192) {
+ $data .= @fread($this->fp, $count);
+ $count = 0;
+ } else {
+ $count -= 8192;
+ $data .= @fread($this->fp, 8192);
+ }
+ }
+ @fclose($this->fp);
+ if (self::$_manifest[$this->_archiveName][$path][4] & self::GZ) {
+ $data = gzinflate($data);
+ } elseif (self::$_manifest[$this->_archiveName][$path][4] & self::BZ2) {
+ $data = bzdecompress($data);
+ }
+ if (!isset(self::$_manifest[$this->_archiveName][$path]['ok'])) {
+ if (strlen($data) != $this->currentStat[7]) {
+ return array("Not valid internal .phar file (size error {$size} != " .
+ $this->currentStat[7] . ")");
+ }
+ if (self::$_manifest[$this->_archiveName][$path][3] != sprintf("%u", crc32($data) & 0xffffffff)) {
+ return array("Not valid internal .phar file (checksum error)");
+ }
+ self::$_manifest[$this->_archiveName][$path]['ok'] = true;
+ }
+ return $data;
+ } else {
+ @fclose($this->fp);
+ return array($e);
+ }
+ }
+
+ /**
+ * Parse urls like phar:///fullpath/to/my.phar/file.txt
+ *
+ * @param string $file
+ * @return false|array
+ */
+ static protected function parseUrl($file)
+ {
+ if (substr($file, 0, 7) != 'phar://') {
+ return false;
+ }
+ $file = substr($file, 7);
+
+ $ret = array('scheme' => 'phar');
+ $pos_p = strpos($file, '.phar.php');
+ $pos_z = strpos($file, '.phar.gz');
+ $pos_b = strpos($file, '.phar.bz2');
+ if ($pos_p) {
+ if ($pos_z) {
+ return false;
+ }
+ $ret['host'] = substr($file, 0, $pos_p + strlen('.phar.php'));
+ $ret['path'] = substr($file, strlen($ret['host']));
+ } elseif ($pos_z) {
+ $ret['host'] = substr($file, 0, $pos_z + strlen('.phar.gz'));
+ $ret['path'] = substr($file, strlen($ret['host']));
+ } elseif ($pos_b) {
+ $ret['host'] = substr($file, 0, $pos_z + strlen('.phar.bz2'));
+ $ret['path'] = substr($file, strlen($ret['host']));
+ } elseif (($pos_p = strpos($file, ".phar")) !== false) {
+ $ret['host'] = substr($file, 0, $pos_p + strlen('.phar'));
+ $ret['path'] = substr($file, strlen($ret['host']));
+ } else {
+ return false;
+ }
+ if (!$ret['path']) {
+ $ret['path'] = '/';
+ }
+ return $ret;
+ }
+
+ /**
+ * Locate the .phar archive in the include_path and detect the file to open within
+ * the archive.
+ *
+ * Possible parameters are phar://pharname.phar/filename_within_phar.ext
+ * @param string a file within the archive
+ * @return string the filename within the .phar to retrieve
+ */
+ public function initializeStream($file)
+ {
+ $file = self::processFile($file);
+ $info = @parse_url($file);
+ if (!$info) {
+ $info = self::parseUrl($file);
+ }
+ if (!$info) {
+ return false;
+ }
+ if (!isset($info['host'])) {
+ // malformed internal file
+ return false;
+ }
+ if (!isset(self::$_pharFiles[$info['host']]) &&
+ !isset(self::$_pharMapping[$info['host']])) {
+ try {
+ self::loadPhar($info['host']);
+ // use alias from here out
+ $info['host'] = self::$_pharFiles[$info['host']];
+ } catch (Exception $e) {
+ return false;
+ }
+ }
+ if (!isset($info['path'])) {
+ return false;
+ } elseif (strlen($info['path']) > 1) {
+ $info['path'] = substr($info['path'], 1);
+ }
+ if (isset(self::$_pharMapping[$info['host']])) {
+ $this->_basename = $info['host'];
+ $this->_archiveName = self::$_pharMapping[$info['host']][0];
+ $this->_compressed = self::$_pharMapping[$info['host']][1];
+ } elseif (isset(self::$_pharFiles[$info['host']])) {
+ $this->_archiveName = $info['host'];
+ $this->_basename = self::$_pharFiles[$info['host']];
+ $this->_compressed = self::$_pharMapping[$this->_basename][1];
+ }
+ $file = $info['path'];
+ return $file;
+ }
+
+ /**
+ * Open the requested file - PHP streams API
+ *
+ * @param string $file String provided by the Stream wrapper
+ * @access private
+ */
+ public function stream_open($file)
+ {
+ return $this->_streamOpen($file);
+ }
+
+ /**
+ * @param string filename to opne, or directory name
+ * @param bool if true, a directory will be matched, otherwise only files
+ * will be matched
+ * @uses trigger_error()
+ * @return bool success of opening
+ * @access private
+ */
+ private function _streamOpen($file, $searchForDir = false)
+ {
+ $path = $this->initializeStream($file);
+ if (!$path) {
+ trigger_error('Error: Unknown phar in "' . $file . '"', E_USER_ERROR);
+ }
+ if (is_array($this->file = $this->extractFile($path))) {
+ trigger_error($this->file[0], E_USER_ERROR);
+ return false;
+ }
+ if ($path != $this->currentFilename) {
+ if (!$searchForDir) {
+ trigger_error("Cannot open '$file', is a directory", E_USER_ERROR);
+ return false;
+ } else {
+ $this->file = '';
+ return true;
+ }
+ }
+
+ if (!is_null($this->file) && $this->file !== false) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Read the data - PHP streams API
+ *
+ * @param int
+ * @access private
+ */
+ public function stream_read($count)
+ {
+ $ret = substr($this->file, $this->position, $count);
+ $this->position += strlen($ret);
+ return $ret;
+ }
+
+ /**
+ * Whether we've hit the end of the file - PHP streams API
+ * @access private
+ */
+ function stream_eof()
+ {
+ return $this->position >= $this->currentStat[7];
+ }
+
+ /**
+ * For seeking the stream - PHP streams API
+ * @param int
+ * @param SEEK_SET|SEEK_CUR|SEEK_END
+ * @access private
+ */
+ public function stream_seek($pos, $whence)
+ {
+ switch ($whence) {
+ case SEEK_SET:
+ if ($pos < 0) {
+ return false;
+ }
+ $this->position = $pos;
+ break;
+ case SEEK_CUR:
+ if ($pos + $this->currentStat[7] < 0) {
+ return false;
+ }
+ $this->position += $pos;
+ break;
+ case SEEK_END:
+ if ($pos + $this->currentStat[7] < 0) {
+ return false;
+ }
+ $this->position = $pos + $this->currentStat[7];
+ break;
+ default:
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * The current position in the stream - PHP streams API
+ * @access private
+ */
+ public function stream_tell()
+ {
+ return $this->position;
+ }
+
+ /**
+ * The result of an fstat call, returns mod time from creation, and file size -
+ * PHP streams API
+ * @uses _stream_stat()
+ * @access private
+ */
+ public function stream_stat()
+ {
+ return $this->_stream_stat();
+ }
+
+ /**
+ * Retrieve statistics on a file or directory within the .phar
+ * @param string file/directory to stat
+ * @access private
+ */
+ public function _stream_stat($file = null)
+ {
+ $std = $file ? self::processFile($file) : $this->currentFilename;
+ if ($file) {
+ if (isset(self::$_manifest[$this->_archiveName][$file])) {
+ $this->_setCurrentFile($file);
+ $isdir = false;
+ } else {
+ do {
+ $isdir = false;
+ if ($file == '/') {
+ break;
+ }
+ foreach (self::$_manifest[$this->_archiveName] as $path => $info) {
+ if (strpos($path, $file) === 0) {
+ if (strlen($path) > strlen($file) &&
+ $path[strlen($file)] == '/') {
+ break 2;
+ }
+ }
+ }
+ // no files exist and no directories match this string
+ return false;
+ } while (false);
+ $isdir = true;
+ }
+ } else {
+ $isdir = false; // open streams must be files
+ }
+ $mode = $isdir ? 0040444 : 0100444;
+ // 040000 = dir, 010000 = file
+ // everything is readable, nothing is writeable
+ return array(
+ 0, 0, $mode, 0, 0, 0, 0, 0, 0, 0, 0, 0, // non-associative indices
+ 'dev' => 0, 'ino' => 0,
+ 'mode' => $mode,
+ 'nlink' => 0, 'uid' => 0, 'gid' => 0, 'rdev' => 0, 'blksize' => 0, 'blocks' => 0,
+ 'size' => $this->currentStat[7],
+ 'atime' => $this->currentStat[9],
+ 'mtime' => $this->currentStat[9],
+ 'ctime' => $this->currentStat[9],
+ );
+ }
+
+ /**
+ * Stat a closed file or directory - PHP streams API
+ * @param string
+ * @param int
+ * @access private
+ */
+ public function url_stat($url, $flags)
+ {
+ $path = $this->initializeStream($url);
+ return $this->_stream_stat($path);
+ }
+
+ /**
+ * Open a directory in the .phar for reading - PHP streams API
+ * @param string directory name
+ * @access private
+ */
+ public function dir_opendir($path)
+ {
+ $info = @parse_url($path);
+ if (!$info) {
+ $info = self::parseUrl($path);
+ if (!$info) {
+ trigger_error('Error: "' . $path . '" is a file, and cannot be opened with opendir',
+ E_USER_ERROR);
+ return false;
+ }
+ }
+ $path = !empty($info['path']) ?
+ $info['host'] . $info['path'] : $info['host'] . '/';
+ $path = $this->initializeStream('phar://' . $path);
+ if (isset(self::$_manifest[$this->_archiveName][$path])) {
+ trigger_error('Error: "' . $path . '" is a file, and cannot be opened with opendir',
+ E_USER_ERROR);
+ return false;
+ }
+ if ($path == false) {
+ trigger_error('Error: Unknown phar in "' . $file . '"', E_USER_ERROR);
+ return false;
+ }
+ $this->fp = @fopen($this->_archiveName, "rb");
+ if (!$this->fp) {
+ trigger_error('Error: cannot open phar "' . $this->_archiveName . '"');
+ return false;
+ }
+ $this->_dirFiles = array();
+ foreach (self::$_manifest[$this->_archiveName] as $file => $info) {
+ if ($path == '/') {
+ if (strpos($file, '/')) {
+ $a = explode('/', $file);
+ $this->_dirFiles[array_shift($a)] = true;
+ } else {
+ $this->_dirFiles[$file] = true;
+ }
+ } elseif (strpos($file, $path) === 0) {
+ $fname = substr($file, strlen($path) + 1);
+ if (strpos($fname, '/')) {
+ // this is a directory
+ $a = explode('/', $fname);
+ $this->_dirFiles[array_shift($a)] = true;
+ } elseif ($file[strlen($path)] == '/') {
+ // this is a file
+ $this->_dirFiles[$fname] = true;
+ }
+ }
+ }
+ @fclose($this->fp);
+ if (!count($this->_dirFiles)) {
+ return false;
+ }
+ @uksort($this->_dirFiles, 'strnatcmp');
+ return true;
+ }
+
+ /**
+ * Read the next directory entry - PHP streams API
+ * @access private
+ */
+ public function dir_readdir()
+ {
+ $ret = key($this->_dirFiles);
+ @next($this->_dirFiles);
+ if (!$ret) {
+ return false;
+ }
+ return $ret;
+ }
+
+ /**
+ * Close a directory handle opened with opendir() - PHP streams API
+ * @access private
+ */
+ public function dir_closedir()
+ {
+ $this->_dirFiles = array();
+ return true;
+ }
+
+ /**
+ * Rewind to the first directory entry - PHP streams API
+ * @access private
+ */
+ public function dir_rewinddir()
+ {
+ @reset($this->_dirFiles);
+ return true;
+ }
+
+ /**
+ * API version of this class
+ * @return string
+ */
+ public static final function APIVersion()
+ {
+ return '1.0.0';
+ }
+
+ /**
+ * Retrieve Phar-specific metadata for a Phar archive
+ *
+ * @param string $phar full path to Phar archive, or alias
+ * @return null|mixed The value that was serialized for the Phar
+ * archive's metadata
+ * @throws Exception
+ */
+ public static function getPharMetadata($phar)
+ {
+ if (isset(self::$_pharFiles[$phar])) {
+ $phar = self::$_pharFiles[$phar];
+ }
+ if (!isset(self::$_pharMapping[$phar])) {
+ throw new Exception('Unknown Phar archive: "' . $phar . '"');
+ }
+ return self::$_pharMapping[$phar][4];
+ }
+
+ /**
+ * Retrieve File-specific metadata for a Phar archive file
+ *
+ * @param string $phar full path to Phar archive, or alias
+ * @param string $file relative path to file within Phar archive
+ * @return null|mixed The value that was serialized for the Phar
+ * archive's metadata
+ * @throws Exception
+ */
+ public static function getFileMetadata($phar, $file)
+ {
+ if (!isset(self::$_pharFiles[$phar])) {
+ if (!isset(self::$_pharMapping[$phar])) {
+ throw new Exception('Unknown Phar archive: "' . $phar . '"');
+ }
+ $phar = self::$_pharMapping[$phar][0];
+ }
+ if (!isset(self::$_manifest[$phar])) {
+ throw new Exception('Unknown Phar: "' . $phar . '"');
+ }
+ $file = self::processFile($file);
+ if (!isset(self::$_manifest[$phar][$file])) {
+ throw new Exception('Unknown file "' . $file . '" within Phar "'. $phar . '"');
+ }
+ return self::$_manifest[$phar][$file][6];
+ }
+
+ /**
+ * @return list of supported signature algorithmns.
+ */
+ public static function getsupportedsignatures()
+ {
+ $ret = array('MD5', 'SHA-1');
+ if (extension_loaded('hash')) {
+ $ret[] = 'SHA-256';
+ $ret[] = 'SHA-512';
+ }
+ return $ret;
+ }
+}
+?><?php
+}
+if (!in_array('phar', stream_get_wrappers())) {
+ stream_wrapper_register('phar', 'PHP_Archive');
+}
+if (!class_exists('Phar',0)) {
+ include 'phar://'.__FILE__.'/phar.inc';
+}
+?><?php
+
+/** @file phar.php
+ * @ingroup Phar
+ * @brief class CLICommand
+ * @author Marcus Boerger
+ * @date 2007 - 2007
+ *
+ * Phar Command
+ */
+
+if (!extension_loaded('phar'))
+{
+ if (!class_exists('PHP_Archive', 0))
+ {
+ echo "Neither Extension Phar nor class PHP_Archive are available.\n";
+ exit(1);
+ }
+ if (!in_array('phar', stream_get_wrappers()))
+ {
+ stream_wrapper_register('phar', 'PHP_Archive');
+ }
+ if (!class_exists('Phar',0)) {
+ require 'phar://'.__FILE__.'/phar.inc';
+ }
+}
+
+foreach(array("SPL", "Reflection") as $ext)
+{
+ if (!extension_loaded($ext))
+ {
+ echo "$argv[0] requires PHP extension $ext.\n";
+ exit(1);
+ }
+}
+
+function command_include($file)
+{
+ $file = 'phar://' . __FILE__ . '/' . $file;
+ if (file_exists($file)) {
+ include($file);
+ }
+}
+
+function command_autoload($classname)
+{
+ command_include(strtolower($classname) . '.inc');
+}
+
+Phar::mapPhar();
+
+spl_autoload_register('command_autoload');
+
+new PharCommand($argc, $argv);
+
+__HALT_COMPILER(); ?>
+N
+
+$m¤ŸA ©¥Ä Eê–¤íÀõïÌ>È]î’”{Æ
+¼‚#"ø'¯ÉåHc_b;e,cþà—¬²õ6¾£é˜„;~%ÃGäxy±z";š¾¤'B“œ"‘Ó8Ïiákò,¹¨ËÙjµôX™z«Q'ýßÒ¯ivŸVLx’ðlõä=ƒ—‰¡B'5è´¦žÈÝ lvHPÛÍI².sÊÖèG¾p-2&ÝhoL¬1 ›5ží=8»° §¹z¿Ã(ãŸÁÖ×›¬êÞp·Æ+P#™Ï‰7ñ\ 
+Î@BÓz×÷\’ï¾#†ºPË5ÝÒ•! @V&nZ‘ .ÙbÞ.šþ2üê½Ôl,1~‘"#‡€{ZP^† Y¤ùütœ×5_N/´Äo( á.H¼ªDú R§šë(‰D êàÁ¹òDúXsžG]WÊ^OªQ©LiìÙ
+³íTß-£ÁW“‰Åüfk®sÏq”ô~ÖŠýO3
+øñˆt-iå¾eÞË‚8Ñý9ÿXÂL¹¯‘m›/¥üîÕMa¹Ò¢ÆÙYKÐpcºˆMZ»ƒ™Æ Q<(c¼Œ LæŒ/Q.ît?#A.ÃçbBµù±¸¹/ª [¤2GZçO¥wn”÷Z[œA¥¦éœÊaµ¸1AöY:zþ1WKnF#¢Û¸Õ¦6Ëh¥ÂŸÈò¢üëN-)I¼9–Õa]~¦|…„>ÜçÛf±Xœ‘ÿéó?ÿõñ# E˜Nl\F ÀéC\@u»¡XdŒH»ÐŠ ïk¨ñ…;ýz¿I´¢vDê²Êço‡:õéY¼ÕMG™†…ð÷+`+®3Z”,=Æj6®q]¡ŒmöÄj_*éWˆôò³ÃfPÔ*o‚¯¹_·K¼éá=?0ÅUc’—·¹¥ÙÀ“‡ ž¦ôž|¤QB9½·ˆÓ¯°ëÀ 6òl ’zƒQE(6Y
+‘bL.@¦„×—ŠNÏ ®h#*N>Œ,°–¨u¿
+­ÉÆ09Sâ"º³YK6¢­HÅ,™ròðæ­=ü‚ø[v*Ò[3zH8j°iŒµøX¬¶Ðä) 4½ r¡iŸs1²…n\áQ !XrŠ«$݈¸8
+C_þÇ—»65Ð,QˆìüZEŒ @­×× ×WçBñ2óŸØŸªÚCõ¦Üu›'Ob­:ôê0k'Ø “x _ÑôBq¼{xá?fQwd×Zÿe
+ØИÂ`ØÈÚ ëÛ,KTä#üÿ•~kaÅGàè{i@´I4sz¹?9•cçâÖ$N'Ù—yAn) R˜è–²icìpbɤH*‘Ž’ˆî‡^µ5+»Î
+ ^ç°Ðiœ®e…Á¡ùç5
+¨ÎH–RœZxÐË¿³8õ˜?´
+ûÍ
+ͱECbJ_›Œæ\ii¯¢£Åx?‹¹dÆ
+ëÓ!ù €~N£ÌoT‹fñ²é#¨çªG[ï×LÛá§á.#š.øD«.Ì#ÅküÙ ê´Ðï"8ŸûbæTSí>m©¡*j*Lu*ð ({ÔÒ­à?^–4Ù>R3aæJbî<É-Ž‚×N|!“Ó |m]lD|Ÿ>\úÃd&"ýç -5ƒ¨UiPøÁÄÌȹ„¿ïáﯽT®$•äò¿%%?&üÔ¯r,°€Ø ~ ÉÁgèíøè€cðwô€ˆà gH]ß zЊßáœAð>c›{@÷‹å,òùÁrzìy÷ÁƒÿÃßÈ„}1ºáKççd§ñ¾Ü8@[é¯8QÙÞ]âVk`1ÑDÝ
+xƒ<e•K\ÄA+fhnåûuF÷Aœnð6Ï€×–œ‘1ÁÿSv3A5NëÝD“/©—[‡{¥ZW ;Úá¨_Ïh&î]Ø’‹F¨R6ò#W–ÞÁ@–øT#Ù˜(GÆä ÎaÔU|©1ÂÙ“5û)V§&ÇnÜø§eã¨}"fŠnœòFfÀgu„ ºpQ¾)tÓé´(öR»ö0¢ÒX 8apl·nÏÀ¾Seíeù¡.'¥°ÙZ©È„è°L²ò¢6yÛª²
+ fej¯ôê<Á[à »•­&Bî€Ù¡àȧÖΖY'„±>+ݪæÕ£m i¤+—‘®„‘§ÃR‚ò•i­+Ћ‹Ûí—h`pqxËå,uð—Éð1ÉŸrx<æDGj„ƒò]qϸr{†­2W[¢ŸGTUWì8:¨Hʽš|¸«¾–¸þ’»( |™†LÒúõ€aRJƒV7)£×²’4V]IZN#<ôm21_xAúÍóKù»;1A…ŠMuñ
+yZVMjzm ‘ªJnÛhà÷•gÍ߶)L6-0êCÏ€7w†<4–3C
+¾D CέMXqDtñ¼Æ{@&hí¾ßaš Á]'Ámý£Ó¼Ñm·æe7ö®*Õç9ÎÚ³BªŠ:ê¨Á9vê ÕªŽ!-ШOf¦£?€ ?.Nþ
+•f`J-$Üe(V¸Ã¢ô:ï÷/àÔ”K”`8t+T„'D$0ŸÌ!`Ï‚ˆ­{M„Cî
+$ë.åF–íìõî]R»uR'Í{Iš§×·u²^J‚$ž)RKR‰Ýnþ÷›|
+ô31Ÿ¬+ŸÍÖÙ¤J ×Ha".D‘#èa“å*åKžU1‚é¢ø^”ÐŒŽˆ¬½èùû\$¹«õ8M&o cr1çÕÅÙëÔ¬åù`'=²¸˜_$Ùl—š Øø4Z+«â¢à+WƒˆEÐ<=d÷Ùøïßá¿ÿÚ}D>)”>}úÔ»?‰fÈø÷5{’&쯘zÄô“ïWq/äD€þNSXÁ,Ôèhôö#O?ð@#9s¦×sÆçÀ˜œ‰¹s‰G²í>ýë›—¤jú`[ÒÊÏ8øÔAèùÍ 42ó _ºd&¦…käÑRýªþ%Q¬g•'YÉb2%‚Zþü«¤‰ûq‘Løèú †d(닼äÙ(ÔG©®WœèO@àCV®ø$™áDQ‚$Ì‹K–gî
+®³Ë,ÿ˜Y‹$Ñ@à:¬GvlG·eG0“"¾ègøÅ;:ö=¡§
+˜qH:“0áõn‹ÍzMM«ªm&‡YìLhUéwiåaL³çE¿å º ÊK¾Ôô˜(å(‚^Ь”õ“h9ýFÀ|ùÃ7Ñ0*ñ¡ø~öãÉaÔÎ~I¿ù|ί¶š.A86W(ïa¾Na‰ø•–#ÔûI¶ZW´neÇj]~­ŸdSûz\NŠ„,£-ƶâšöÃD® ׃VDÑLQÆ×Ë1˜t6@n9Ÿ¢7R®ÇJŒI@rrSVb¯AR‚*uLdùeˆò£H¿„ìçbq&î#H‡Ô_ƒ’ ø ¿_ ö•vé¥U¿ ¤y ›¬­æ @³ù„6Q¸"¯|}q"]±I"ÚÀ{.À›(«=â|³;!ëoý9_³ ¸O°sá
+&/ƒ0ðx²±P©;é%¿¦ Àd6oà³Æ‡‚sAçVùõí€úì:k_ð¿­ÔÓÔt•Q„²Ëî±Ø îtT;eOÇÔíhõD¢×Ãþýï5(wš0版Ó}ÔÚè<R°‰êz$»×§;ÍO2fDÀ6‹²N³iù xVnœíL³ð1ÓÏHÛ/°‘Á؃Šzq°Cä¡Å`¿ñI(hm”M…Êñ5à4¹d2@"¾ ˆøè-ÅALø:r¶L®0’Žë‡+†>IU&z×`?³ùPZ­€Øà:ÃóÀ%3³5ų XÕÀê3è<Ðsª…«4¼Ù~¾§<¨~» XU~Ùlá1Þ‹Á]°‹BSîúŸ¨x'06ÁµxðóiB«/¢(C)!÷ÜU´ŒM 7ÌOxù§Ã· gÍÁ@£
+W/ârÛ¬7,áTÐäЪú î*PâäWØ ¡lí¶°%"µûéå òio\I=?×Ëz#‘F“ñCðv¿€‡å˜e&…h–duœ˜1_µä2‰Uï‰ÅÏ°%΋¥,hábÕ¿}ž›™>%<‰³eÞ[ÊšX5Ðr¢9=S5¢ýF’ UO›(`Ò³‘"œCâ¦U2‚xã§ëµ0–„üœÅc‘ñÀåkᘑÍç‚¡­¯ŠáÕ`†P° ìÓ« áïÞ*§uCØR¥œpÁ55Ðyø°
+ߺHÛe8Zí¥ÉeCìž,8ìI*ÃÇCÿGñVŽA±7I½¤’)lðsf´Q°h£ #‰î8§WÕÇo1–y¬ýa©n#ª–’NB\ìÛ£f{¤[zf.4ª†¼o‚nS(AŠ$bÍTVÛ¨9
+Éí[3õ¶§°ÞHúêmÂ'$E#`œ¦Ä…Ey;•î²ÖüÄ[mâN¸^—MâæãÿÁH(xâXUKŽƨ7Þ¬H¯l¬à$6
+Á&$ßý¬
+å×Ð(”uj×'§”˜BÐSÐ4ß pAi„Ý€hé>"û%êBú¯9õê\t C–€‚öïÒ€qµ²e|=æòŒpC«ä.Æ,Í<Ép=n×y’Õ'íôö–al$y"ØÙâ½ïSû=²Æ&è*Y.{GG£#0Ayv&Ò½¶’V7wßÅØmÞ»þ rW¸8B;‰a)b>½Ö¾Y _Le„¶­ä\¨ØhÃÝ°êzàëØøÅ +ÜÒîb²œb9æÅJÅH éx^3[Õ1Ô
+âfvžžcŽÍ
+ͪ‘¸ÛŸ&E9òu›³Iõ´T¸¨L7%”U°òõ)LƉXâvÕŽ°_å@¶·2<‰»îá¡:´)¿ œûø…V!®C¨°%±rÉ(¹£r=–ñ*É"ĵ²«(ܬ¢²JB]Õ…®Q<ž<G`U^áÞ^Æ."Ÿ²©•ˆr)¾ŠWÊ㟮Z±ûS#J
+«V”fžV:oƒ­‡ÎSÊë‘ôï'x º`ÇÌS)E]²3bÏgl/A¶NDµqÍO¯^üÙè@qNYÚ1‡È|eVX(*D©Žµú
+A‹>YÆYj€ÀÝ`¯~zkt2ëú‹o…ú§­ì’ç’W(íä~¸|}Æ뺋 ÝR~¬±ðŽ(ÕÞÁß1)H1{Û–™]ª¿øb÷28Œ
+½¬CÞ;û¬‹q»dÔYX~”Ùxìk¬vÓnãY2ó ±ð5¦Š]OãÄטSx§ÞÆBg5¯|IWz —¾ÆIöA í4¾ò7ÆÝc²Ñ¶nL<-u,_QžŒXà]·)<éøx=›q Y•žbfzlßÆÊ«ëÍ”[ þºômÄäšÛ(c,Гz
+‚cITâu-»Û1BÎ+š>꣱õÒÞ$¸Šëš¬3ѼãõÎs½êçdå‰
+‹Z>ÛפVsENc}§@»¥s¬LØÂT|½¡â›,û±«~¢8Dõß(·ê@óÑôìðTjnÞiê_ÛQ$QÛ‚r²àÆu.>´•9ø¦@ˆ‡×YZe"¤â%}ÔµGi<áƒhã?ø?ñÜ`VªXˆ‘÷öØ1;@C
+…¹ÊÊáÓ/±³ }+Û oýHßKÊH À\à
+ºzïWÕõUý¾³Þšë ÊË©.¨kgf‰d+.ÀûÊž+Z’ÓfEAèÚ²¸ÓÕ®Nm|—†‘¢˜zT{Ð’^“píCmº·¯álÙS5e´§xY.Ê^Ä~Éœ•(k6|
+̇ç pC»ªQŸòÞZbcÿÇ<Ò8»fóÌ ¯VÏHˆîU±æ®úKÓ Ø€¸V¹bRLÅ€þ….ÞÈ®‘í*^Ãz+WJ±ŽZ]I²ªQ°‚íŒþãå‡x·Õ+p¦á L™0t¹œÊ´-*°º&­k[[&^×\¥u£î«¶)7ê«ž&º°j]¤QGœ¨-ÇÒ5ã7ëÌ;YÌõ˜¡Ì¦vï“áñN:Ö. CQÕfãmÁµzkÞ+HTìå‹RïQI`mÝ˺nÀf‚¨Äâ`Ü!_ì­j/2bf(‰Cm$qYûw³Q”D¼G54Ú-Id™´DvÓêD f’±Ÿß¼`¢· d->£ˆv‘
+rN ¥wÑè]´kÖ1oWºÜ¦ ƒj7ÀøÈ^Ka—)ªxˆGÞŽGd±¿ Õ4H'öL*¹é_åÖ$_g•xŒ‘òÃÎóÏ?e)ìÜñRf@WfV1Mó|:òœƒÖåÉ9Á?çÎÅ!¾ ˜jbÐBô)`c|éH¥kcŒØS9—™„ó̼à
+;©+ ¢îv•ÄG»ÍU$Q4= òêqÊ3—®ÂÆVáG£Ù’BÂî®Q DÁ„Q 9¢+ò µÑÜÐ?r‡r…ó´Öq3å[«ñF¶[+qž÷˜r‹iÔÌÙP)å-©ûBÇCT×)_ÁÒë&äõ¼X&Ž/ÅO1Þ*“Nyèƈ:êx0£Ÿu®À8ëjä9!aî­É<F~2ŽFÚ÷®µ8q W·R‰Ï”\™ÎÔÏ­Â,Q—U  ƒÐLYŠE¨6¢3°#êÐrÖ MªXS‚iÞŧªž>I…‰³îøgë@톃úL§L^¤ªÒoSßMæ7ëËòÓÕ $Z+eHr/D“ï'ù
+$×Pôú¯l4Ñ´l·Õ§±ëùåNn›/9åH0Wö _éJ¨Ð¸>>çœ÷mq‚›W§tû·§{Iä,Ì̽rtsÇÖO Êùo«¼÷úþ!p8©‹ñº¿§jjyµ²|WûR„nµFMoõÔuVoâƵ0 ÝH¯çilVÁ’ˆ×öT´)’<o}BÕ—mîvØ´ÐõŸÝ>ŠÊ:Z-¹'È,•Ï×ÅÈͤYý°­bí&²ë©Sƒ-2&rªL*«‹\1l‘YÏÆuÆ©0¯·c•Rh{Šõò&vVŠ–»Ôm¶¥º=YÎ;oÒé–1ß$Âçu'O“Ô»%ì·Ä¿ÿ? ûyè‹qÓý¬¥pZÍ‘/µ‘56±¢ÒCWÙ¨–þb›nõçeSU~àè´‰Oû©º>šr“ä¥*ïés¾ G¢Óh+jRûžh-éÿÌ5øNå?¶î>ŒL-ö§[)²1/
+ªÝ›éÊ“q¸}eD~Ìúª &^€€Á‘Ú”õ(§ 3OÞÙSBýó敠ܲÜP­¨çäÒÄ é¼²õP_í¯Kì2Š¡É ë"°vfk”u¯Â œ{QÕD¤¿I?]•-µ>M$®[=Üß'âEÛ«{[Æhh¼¡f;—Œ—lœÝíE9sø&å6:v¦Ë3ûèùŽpõ9V·ÞêìT+”¶3@7Y{­ æ͵Æ++¥C£«e:ôSìó¯ M⪹žújÞ¢¯žué«Â‚}j?…ÚÛUY-$Ìøœ%’
+ÊÂ_ÑÒ&f¤‰þ‰4˜‡¤nü¬¦(3É^“OðzN§’ùRÝke’Q/…Š”ª®4W)Öúb3}ˆ«àŽöÎL؇9›úM·¤ð&‚s‰ÍÐHj•¾…žQNYÛ
+aúù‰ÙμÈÕh§ËÕ=è€V:iIW÷×Djà &RØãÉ©úD!½µVìõ„c¡n ¤Ê6ªdÒMÔ“bîÕ¯LšÉæ‰Ý­[tѧ©>žðÛÜõa.ÿŒÄêF’œïçˆÍ}Ó½F¬8¼
+hãŠýö+79UÜyGc=ÍMOÜÊüƒÇnB‚0°>TžJØb¢?kµÆ§7e¿ÃÖ=/㼑כÌ ¥Ëú¼ö LK©úö­Êw±kÝœ×Ðí7Înå•vD—Qž©†!Crb—Š=¼Ð–é7-È·a@º&O¾cˆÈz4Oùû¯
+E=t8&惬^KoO ¯1vU2¡´x­±¼]÷r¤–·ÚÆ"ACÓÈ0œÿ^Ý•pNaã3–·ã¢T«·Ö3­õ‹<D.CŒ©ÑºSº#pO®…V6È—š"ÕéÀµ¼IJ «^"ªgDø€›€PJh³Y
+$˜ë{†%+ˆ_¡ÇሠYí‚ø‹…¥é"¨øþ/²Hé5+bqòGQäPL³zî#VZEwÈV°º”زðu«ê.9kªk~ùò6öcbÝû}$D `éMtúKÉX~
+ˆoÕßÀi„(%èÜÑ|­¦ÍÙêlêðõ£¦†ï}!C?§ÖåÇI±!Ý<nKÒ<å7Bú|ÕlsŸzêá7sI gÐ%‘uý›{%!7+J/ŠR×ö‡ì¼ 2þÞ¨Ž¨B—>‹—2‡©ŽxÙÜk–XŽžÁÇïˬnÇPû™â 3² ’)T‰ÿ<èÒ⦞†º…>«¡îe¨hJ‡cP»Aö5èi}ÄùW0ȽôÿÆVÿz*`š”iÚ‚¡F7` ï«|*î¤ :06]ÐÈ@yC¦Ý?©ô ßøI"±ìc³ã[g'h™3˜Å¹ì;PHo#2/Ì x5pÃö\ÐÎ,ÿ‰»üÿŒ + ¾ñBßØ/A{Þк/lŸä¹j³Ñ»+yÈP+mFÆn­Ó £õs<_×Ia¿WyY&ò’XeL6Ie(aûî%®Sáô¼ó¥‡M³n’µÿ.¼ªMÃ~+v½‹
+~º#?|w|ç’AOƒ@…Ï쯘£6±T/4ÖÚ‹š4ö˜) °qYÈì.jˆÿÝjj iË…ÌûÞ¼}K¸Ÿ×E­T<™(˜Àc¦ A] OµMzEÛœ«PÃZÄ^ز¦ ƒÎíE ¾¨`…œOqN;”¢'çf6»…«þ%z‡ºmXVe‰6•9Vq mÛþËúôdSž×o N
+ÝÐ_מ÷Ön:Öv^]Ö†J²½®ì©Ú ±\Og}·ã¥öá^) ²ÛЋ'F_±jU”›tÇBN~£s‹>0]\ªHXÄ$“… £;}«CÿÂhtçx™>´M¤A£Ós"¤:Ë-Æ2ÞékL¶ò9ÆôݲÐ&•¸3ï9°ÓVäQ~&ò}o|ØŽ!7@ç?_9X-˪á~L†W^¡„d*ÿt
diff --git a/ext/phar/phar/clicommand.inc b/ext/phar/phar/clicommand.inc
new file mode 100755
index 0000000000..067456d691
--- /dev/null
+++ b/ext/phar/phar/clicommand.inc
@@ -0,0 +1,377 @@
+<?php
+
+/** @file clicommand.inc
+ * @ingroup Phar
+ * @brief class CLICommand
+ * @author Marcus Boerger
+ * @date 2007 - 2007
+ *
+ * Phar Command
+ */
+
+/** @ingroup Phar
+ * @brief Abstract base console command implementation
+ * @author Marcus Boerger
+ * @version 1.0
+ */
+abstract class CLICommand
+{
+ protected $argc;
+ protected $argv;
+ protected $cmds = array();
+ protected $args = array();
+ protected $typs = array();
+
+ function __construct($argc, array $argv)
+ {
+ $this->argc = $argc;
+ $this->argv = $argv;
+ $this->cmds = self::getCommands($this);
+ $this->typs = self::getArgTyps($this);
+
+ if ($argc < 2) {
+ self::error("No command given, check ${argv[0]} help\n");
+ } elseif (!isset($this->cmds[$argv[1]]['run'])) {
+ self::error("Unknown command '${argv[1]}', check ${argv[0]} help\n");
+ } else {
+ $command = $argv[1];
+ }
+
+ if (isset($this->cmds[$command]['arg'])) {
+ $this->args = call_user_func(array($this, $this->cmds[$command]['arg']));
+ $i = 1;
+ $missing = false;
+ while (++$i < $argc) {
+ if ($argv[$i][0] == '-') {
+ if (strlen($argv[$i]) == 2 && isset($this->args[$argv[$i][1]])) {
+ $arg = $argv[$i][1];
+ if (++$i >= $argc) {
+ self::error("Missing argument to parameter '$arg' of command '$command', check ${argv[0]} help\n");
+ } else {
+ $this->args[$arg]['val'] = $this->checkArgTyp($arg, $i, $argc, $argv);
+ }
+ } else {
+ self::error("Unknown parameter '${argv[$i]}' to command $command, check ${argv[0]} help\n");
+ }
+ } else {
+ break;
+ }
+ }
+ if (isset($this->args[''])) {
+ if ($i >= $argc) {
+ if (isset($this->args['']['require']) && $this->args['']['require']) {
+ self::error("Missing default trailing arguments to command $command, check ${argv[0]} help\n");
+ }
+ } else {
+ $this->args['']['val'] = array();
+ while($i < $argc) {
+ $this->args['']['val'][] = $argv[$i++];
+ }
+ }
+ } else if ($i < $argc) {
+ self::error("Unexpected default arguments to command $command, check ${argv[0]} help\n");
+ }
+
+ foreach($this->args as $arg => $inf) {
+ if (strlen($arg) && !isset($inf['val']) && isset($inf['required']) && $inf['required']) {
+ $missing .= "Missing parameter '-$arg' to command $command, check ${argv[0]} help\n";
+ }
+ }
+ if (strlen($missing))
+ {
+ self::error($missing);
+ }
+ }
+
+ call_user_func(array($this, $this->cmds[$command]['run']), $this->args);
+ }
+
+ static function notice ($msg)
+ {
+ fprintf(STDERR, $msg);
+ }
+
+ static function error ($msg, $exit_code = 1)
+ {
+ self::notice($msg);
+ exit($exit_code);
+ }
+
+ function checkArgTyp($arg, $i, $argc, $argv)
+ {
+ $typ = $this->args[$arg]['typ'];
+
+ if (isset($this->typs[$typ]['typ'])) {
+ return call_user_func(array($this, $this->typs[$typ]['typ']), $argv[$i], $this->args[$arg], $arg);
+ } else {
+ return $argv[$i];
+ }
+ }
+
+ static function getSubFuncs(CLICommand $cmdclass, $prefix, array $subs)
+ {
+ $a = array();
+ $r = new ReflectionClass($cmdclass);
+ $l = strlen($prefix);
+
+ foreach($r->getMethods() as $m)
+ {
+ if (substr($m->name, 0, $l) == $prefix)
+ {
+ foreach($subs as $sub)
+ {
+ $what = substr($m->name, $l+strlen($sub)+1);
+ $func = $prefix . $sub . '_' . $what;
+ $what = str_replace('_', '-', $what);
+ if ($r->hasMethod($func))
+ {
+ if (!isset($a[$what]))
+ {
+ $a[$what] = array();
+ }
+ $a[$what][$sub] = /*$m->class . '::' .*/ $func;
+ }
+ }
+ }
+ }
+ return $a;
+ }
+
+ static function getCommands(CLICommand $cmdclass)
+ {
+ return self::getSubFuncs($cmdclass, 'cli_cmd_', array('arg','inf','run'));
+ }
+
+ static function getArgTyps(CLICommand $cmdclass)
+ {
+ return self::getSubFuncs($cmdclass, 'cli_arg_', array('typ'));
+ }
+
+ static function cli_arg_typ_bool($arg, $cfg, $key)
+ {
+ return (bool)$arg;
+ }
+
+
+ static function cli_arg_typ_int($arg, $cfg, $key)
+ {
+ if ((int)$arg != $arg) {
+ self::error("Argument to -$key must be an integer.\n");
+ }
+
+ return (int)$arg;
+ }
+
+ static function cli_arg_typ_regex($arg, $cfg, $key)
+ {
+ if (strlen($arg))
+ {
+ if (strlen($arg) > 1 && $arg[0] == $arg[strlen($arg)-1] && strpos('/,', $arg) !== false)
+ {
+ return $arg;
+ }
+ else
+ {
+ return '/' . $arg . '/';
+ }
+ }
+ else
+ {
+ return NULL;
+ }
+ }
+
+ static function cli_arg_typ_select($arg, $cfg, $key)
+ {
+ if (!in_array($arg, array_keys($cfg['select']))) {
+ self::error("Parameter value '$arg' not one of '" . join("', '", array_keys($cfg['select'])) . "'.\n");
+ }
+ return $arg;
+ }
+
+ static function cli_arg_typ_dir($arg, $cfg, $key)
+ {
+ $f = realpath($arg);
+
+ if ($f===false || !file_exists($f) || !is_dir($f)) {
+ self::error("Requested path '$arg' does not exist.\n");
+ }
+ return $f;
+ }
+
+ static function cli_arg_typ_file($arg)
+ {
+ $f = new SplFileInfo($arg);
+ $f = $f->getRealPath();
+ if ($f===false || !file_exists($f))
+ {
+ echo "Requested file '$arg' does not exist.\n";
+ exit(1);
+ }
+ return $f;
+ }
+
+ static function cli_arg_typ_filenew($arg, $cfg, $key)
+ {
+ $d = dirname($arg);
+ $f = realpath($d);
+
+ if ($f === false) {
+ self::error("Path for file '$arg' does not exist.\n");
+ }
+ return $f . '/' . basename($arg);
+ }
+
+ static function cli_arg_typ_filecont($arg, $cfg, $key)
+ {
+ return file_get_contents(self::cli_arg_typ_file($arg, $cfg, $key));
+ }
+
+ function cli_get_SP2($l1, $arg_inf)
+ {
+ return str_repeat(' ', $l1 + 2 + 4 + 8);
+ }
+
+ function cli_get_SP3($l1, $l2, $arg_inf)
+ {
+ return str_repeat(' ', $l1 + 2 + 4 + 8 + 2 + $l2 + 2);
+ }
+
+ static function cli_cmd_inf_help()
+ {
+ return "This help or help for a selected command.";
+ }
+
+ private function cli_wordwrap($what, $l, $sp)
+ {
+ $p = max(79 - $l, 40); // minimum length for paragraph
+ $b = substr($what, 0, $l); // strip out initial $l
+ $r = substr($what, $l); // remainder
+ $r = str_replace("\n", "\n".$sp, $r); // in remainder replace \n's
+ return $b . wordwrap($r, $p, "\n".$sp);
+ }
+
+ private function cli_help_get_args($func, $l, $sp, $required)
+ {
+ $inf = "";
+ foreach(call_user_func($func, $l, $sp) as $arg => $conf)
+ {
+ if ((isset($conf['required']) && $conf['required']) != $required)
+ {
+ continue;
+ }
+ if (strlen($arg))
+ {
+ $arg = "-$arg ";
+ }
+ else
+ {
+ $arg = "... ";
+ }
+ $sp2 = $this->cli_get_SP2($l, $inf);
+ $l2 = strlen($sp2);
+ $inf .= $this->cli_wordwrap($sp . $arg . $conf['inf'], $l2, $sp2) . "\n";
+ if (isset($conf['select']) && count($conf['select']))
+ {
+ $ls = 0;
+ foreach($conf['select'] as $opt => $what)
+ {
+ $ls = max($ls, strlen($opt));
+ }
+ $sp3 = $this->cli_get_SP3($l, $ls, $inf);
+ $l3 = strlen($sp3);
+ foreach($conf['select'] as $opt => $what)
+ {
+ $inf .= $this->cli_wordwrap($sp2 . " " . sprintf("%-${ls}s ", $opt) . $what, $l3, $sp3) . "\n";
+ }
+ }
+ }
+ if (strlen($inf))
+ {
+ if ($required)
+ {
+ return $sp . "Required arguments:\n\n" . $inf;
+ }
+ else
+ {
+ return $sp . "Optional arguments:\n\n". $inf;
+ }
+ }
+ }
+
+ function cli_cmd_arg_help()
+ {
+ return array('' => array('typ'=>'any','val'=>NULL,'inf'=>'Optional command to retrieve help for.'));
+ }
+
+ function cli_cmd_run_help()
+ {
+ $argv = $this->argv;
+ $which = $this->args['']['val'];
+ if (isset($which))
+ {
+ if (count($which) != 1) {
+ self::error("More than one command given.\n");
+ }
+
+ $which = $which[0];
+ if (!array_key_exists($which, $this->cmds)) {
+ self::error("Unknown command, cannot retrieve help.\n");
+ }
+
+ $l = strlen($which);
+ $cmds = array($which => $this->cmds[$which]);
+ } else {
+ echo "\n$argv[0] <command> [options]\n\n";
+ $l = 0;
+ ksort($this->cmds);
+ foreach($this->cmds as $name => $funcs) {
+ $l = max($l, strlen($name));
+ }
+ $inf = "Commands:";
+ $lst = "";
+ $ind = strlen($inf) + 1;
+ foreach($this->cmds as $name => $funcs)
+ {
+ $lst .= ' ' . $name;
+ }
+ echo $this->cli_wordwrap($inf.$lst, $ind, str_repeat(' ', $ind)) . "\n\n";
+ $cmds = $this->cmds;
+ }
+ $sp = str_repeat(' ', $l + 2);
+ foreach($cmds as $name => $funcs)
+ {
+ $inf = $name . substr($sp, strlen($name));
+ if (isset($funcs['inf']))
+ {
+ $inf .= $this->cli_wordwrap(call_user_func(array($this, $funcs['inf'])), $l, $sp) . "\n";
+ if (isset($funcs['arg']))
+ {
+ $inf .= "\n";
+ $inf .= $this->cli_help_get_args(array($this, $funcs['arg']), $l, $sp, true);
+ $inf .= "\n";
+ $inf .= $this->cli_help_get_args(array($this, $funcs['arg']), $l, $sp, false);
+ }
+ }
+ echo "$inf\n\n";
+ }
+ exit(0);
+ }
+
+ static function cli_cmd_inf_help_list()
+ {
+ return "Lists available commands.";
+ }
+
+ function cli_cmd_run_help_list()
+ {
+ ksort($this->cmds);
+ $lst = '';
+ foreach($this->cmds as $name => $funcs) {
+ $lst .= $name . ' ';
+ }
+ echo substr($lst, 0, -1) . "\n";
+ }
+}
+
+?>
diff --git a/ext/phar/phar/phar.php b/ext/phar/phar/phar.php
new file mode 100755
index 0000000000..68a437b206
--- /dev/null
+++ b/ext/phar/phar/phar.php
@@ -0,0 +1,57 @@
+#!/usr/local/bin/php
+<?php
+
+/** @file phar.php
+ * @ingroup Phar
+ * @brief class CLICommand
+ * @author Marcus Boerger
+ * @date 2007 - 2007
+ *
+ * Phar Command
+ */
+
+if (!extension_loaded('phar'))
+{
+ if (!class_exists('PHP_Archive', 0))
+ {
+ echo "Neither Extension Phar nor class PHP_Archive are available.\n";
+ exit(1);
+ }
+ if (!in_array('phar', stream_get_wrappers()))
+ {
+ stream_wrapper_register('phar', 'PHP_Archive');
+ }
+ if (!class_exists('Phar',0)) {
+ require 'phar://'.__FILE__.'/phar.inc';
+ }
+}
+
+foreach(array("SPL", "Reflection") as $ext)
+{
+ if (!extension_loaded($ext))
+ {
+ echo "$argv[0] requires PHP extension $ext.\n";
+ exit(1);
+ }
+}
+
+function command_include($file)
+{
+ $file = 'phar://' . __FILE__ . '/' . $file;
+ if (file_exists($file)) {
+ include($file);
+ }
+}
+
+function command_autoload($classname)
+{
+ command_include(strtolower($classname) . '.inc');
+}
+
+Phar::mapPhar();
+
+spl_autoload_register('command_autoload');
+
+new PharCommand($argc, $argv);
+
+__HALT_COMPILER(); ?> \ No newline at end of file
diff --git a/ext/phar/phar/pharcommand.inc b/ext/phar/phar/pharcommand.inc
new file mode 100755
index 0000000000..e95f138d86
--- /dev/null
+++ b/ext/phar/phar/pharcommand.inc
@@ -0,0 +1,1442 @@
+<?php
+
+/**
+ * @file pharcommand.inc
+ * @ingroup Phar
+ * @brief class CLICommand
+ * @author Marcus Boerger
+ * @date 2007 - 2007
+ *
+ * Phar Command
+ */
+// {{{ class PharCommand extends CLICommand
+/**
+ * PharCommand class
+ *
+ * This class handles the handling of the phar
+ * commands. It will be used from command line/console
+ * in order to retrieve and execute phar functions.
+ *
+ * @ingroup Phar
+ * @brief Phar console command implementation
+ * @author Marcus Boerger
+ * @version 1.0
+ */
+class PharCommand extends CLICommand
+{
+ // {{{ public function cli_get_SP2
+ public function cli_get_SP2($l1, $arg_inf)
+ {
+ return str_repeat(' ', $l1 + 2 + 4 + 9);
+ }
+ // }}}
+ // {{{ public function cli_get_SP3
+ /**
+ * Cli Get SP3
+ *
+ * @param string $l1 Eleven
+ * @param string $l2 Twelve
+ * @param string $arg_inf
+ * @return string The repeated string.
+ */
+ function cli_get_SP3($l1, $l2, $arg_inf)
+ {
+ return str_repeat(' ', $l1 + 2 + 4 + 9 + 2 + $l2 + 2);
+ }
+ // }}}
+ // {{{ static function phar_args
+ /**
+ * Phar arguments
+ *
+ * This function contains all the phar commands
+ *
+ * @param string $which Which argument is chosen.
+ * @param string $phartype The type of phar, specific file to work on
+ * @return unknown
+ */
+ static function phar_args($which, $phartype)
+ {
+ $phar_args = array(
+ 'a' => array(
+ 'typ' => 'alias',
+ 'val' => NULL,
+ 'inf' => '<alias> Provide an alias name for the phar file.'
+ ),
+ 'b' => array(
+ 'typ' => 'any',
+ 'val' => NULL,
+ 'inf' => '<bang> Hash-bang line to start the archive (e.g. #!/usr/bin/php). The hash '
+ .' mark itself \'#!\' and the newline character are optional.'
+ ),
+ 'c' => array(
+ 'typ' => 'compalg',
+ 'val' => NULL,
+ 'inf' => '<algo> Compression algorithm.',
+ 'select' => array(
+ '0' => 'No compression',
+ 'none' => 'No compression',
+ 'auto' => 'Automatically select compression algorithm'
+ )
+ ),
+ 'e' => array(
+ 'typ' => 'entry',
+ 'val' => NULL,
+ 'inf' => '<entry> Name of entry to work on (must include PHAR internal directory name if any).'
+ ),
+ 'f' => array(
+ 'typ' => $phartype,
+ 'val' => NULL,
+ 'inf' => '<file> Specifies the phar file to work on.'
+ ),
+ 'h' => array(
+ 'typ' => 'select',
+ 'val' => NULL,
+ 'inf' => '<method> Selects the hash algorithmn.',
+ 'select' => array('md5' => 'MD5','sha1' => 'SHA1')
+ ),
+ 'i' => array(
+ 'typ' => 'regex',
+ 'val' => NULL,
+ 'inf' => '<regex> Specifies a regular expression for input files.'
+ ),
+ 'k' => array(
+ 'typ' => 'any',
+ 'val' => NULL,
+ 'inf' => '<index> Subscription index to work on.',
+ ),
+ 'l' => array(
+ 'typ' => 'int',
+ 'val' => 0,
+ 'inf' => '<level> Number of preceeding subdirectories to strip from file entries',
+ ),
+ 'm' => array(
+ 'typ' => 'any',
+ 'val' => NULL,
+ 'inf' => '<meta> Meta data to store with entry (serialized php data).'
+ ),
+ 'p' => array(
+ 'typ' => 'loader',
+ 'val' => NULL,
+ 'inf' => '<loader> Location of PHP_Archive class file (pear list-files PHP_Archive).'
+ .'You can use \'0\' or \'1\' to locate it automatically using the mentioned '
+ .'pear command. When using \'0\' the command does not error out when the '
+ .'class file cannot be located. This switch also adds some code around the '
+ .'stub so that class PHP_Archive gets registered as phar:// stream wrapper '
+ .'if necessary. And finally this switch will add the file phar.inc from '
+ .'this package and load it to ensure class Phar is present.'
+ ,
+ ),
+ 's' => array(
+ 'typ' => 'file',
+ 'val' => NULL,
+ 'inf' => '<stub> Select the stub file.'
+ ),
+ 'x' => array(
+ 'typ' => 'regex',
+ 'val' => NULL,
+ 'inf' => '<regex> Regular expression for input files to exclude.'
+ ),
+
+ );
+
+ if (extension_loaded('zlib')) {
+ $phar_args['c']['select']['gz'] = 'GZip compression';
+ $phar_args['c']['select']['gzip'] = 'GZip compression';
+ }
+
+ if (extension_loaded('bz2')) {
+ $phar_args['c']['select']['bz2'] = 'BZip2 compression';
+ $phar_args['c']['select']['bzip2'] = 'BZip2 compression';
+ }
+
+ $hash_avail = Phar::getSupportedSignatures();
+ if (in_array('SHA-256', $hash_avail)) {
+ $phar_args['h']['select']['sha256'] = 'SHA256';
+ }
+
+ if (in_array('SHA-512', Phar::getSupportedSignatures())) {
+ $phar_args['h']['select']['sha512'] = 'SHA512';
+ }
+
+ $args = array();
+
+ foreach($phar_args as $lkey => $cfg) {
+ $ukey = strtoupper($lkey);
+ $required = strpos($which, $ukey) !== false;
+ $optional = strpos($which, $lkey) !== false;
+
+ if ($required || $optional) {
+ $args[$lkey] = $cfg;
+ $args[$lkey]['required'] = $required;
+ }
+ }
+ return $args;
+ }
+ // }}}
+ // {{{ static function strEndsWith
+ /**
+ * String Ends With
+ *
+ * Wether a string end with another needle.
+ *
+ * @param string $haystack The haystack
+ * @param string $needle The needle.
+ * @return mixed false if doesn't end with anything, the string
+ * substr'ed if the string ends with the needle.
+ */
+ static function strEndsWith($haystack, $needle)
+ {
+ return substr($haystack, -strlen($needle)) == $needle;
+ }
+ // }}}
+ // {{{ static function cli_arg_typ_loader
+ /**
+ * Argument type loader
+ *
+ * @param string $arg Either 'auto', 'optional' or an filename that
+ * contains class PHP_Archive
+ * @param string $cfg Configuration to pass to a new file
+ * @param string $key The key
+ * @return string $arg The argument.
+ */
+ static function cli_arg_typ_loader($arg, $cfg, $key)
+ {
+ if (($arg == '0' || $arg == '1') && !file_exists($arg)) {
+ $found = NULL;
+ foreach(split("\n", `pear list-files PHP_Archive`) as $ent) {
+ $matches = NULL;
+ if (preg_match(",^php[ \t]+([^ \t].*pear[\\\\/]PHP[\\\\/]Archive.php)$,", $ent, $matches)) {
+ $found = $matches[1];
+ break;
+ }
+ }
+ if (!isset($found)) {
+ $msg = "Pear package PHP_Archive or Archive.php class file not found.\n";
+ if ($arg == '0') {
+ self::notice($msg);
+ } else {
+ self::error($msg);
+ }
+ }
+ $arg = $found;
+ }
+ return self::cli_arg_typ_file($arg);
+ }
+ // }}}
+ // {{{ static function cli_arg_typ_pharnew
+ /**
+ * Argument type new phar
+ *
+ * @param string $arg The new phar component.
+ * @param string $cfg Configuration to pass to a new file
+ * @param string $key The key
+ * @return string $arg The new argument file.
+ */
+ static function cli_arg_typ_pharnew($arg, $cfg, $key)
+ {
+ $arg = self::cli_arg_typ_filenew($arg, $cfg, $key);
+ if (!Phar::isValidPharFilename($arg)) {
+ self::error("Phar files must have file extension '.phar', '.phar.php', '.phar.bz2' or '.phar.gz'.\n");
+ }
+ return $arg;
+ }
+ // }}}
+ // {{{ static function cli_arg_typ_pharfile
+ /**
+ * Argument type existing Phar file
+ *
+ * Return filenam eof an existing Phar.
+ *
+ * @param string $arg The file in the phar to open.
+ * @param string $cfg The configuration information
+ * @param string $key The key information.
+ * @return string $pharfile The name of the loaded Phar file.
+ * @note The Phar will be loaded
+ */
+ static function cli_arg_typ_pharfile($arg, $cfg, $key)
+ {
+ try {
+ $pharfile = self::cli_arg_typ_file($arg, $cfg, $key);
+
+ if (!Phar::loadPhar($pharfile)) {
+ self::error("Unable to open phar '$arg'\n");
+ }
+
+ return $pharfile;
+ } catch(Exception $e) {
+ self::error("Exception while opening phar '$arg':\n" . $e->getMessage() . "\n");
+ }
+ }
+ // }}}
+ // {{{ static function cli_arg_typ_pharurl
+ /**
+ * Argument type Phar url-like
+ *
+ * Check the argument as cli_arg_Typ_phar and return its name prefixed
+ * with phar://
+ *
+ * Ex:
+ * <code>
+ * $arg = 'pharchive.phar/file.php';
+ * cli_arg_typ_pharurl($arg)
+ * </code>
+ *
+ * @param string $arg The url-like phar archive to retrieve.
+ * @return string The phar file-archive.
+ */
+ static function cli_arg_typ_pharurl($arg, $cfg, $key)
+ {
+ return 'phar://' . self::cli_arg_typ_pharfile($arg, $cfg, $key);
+ }
+ // }}}
+ // {{{ static function cli_arg_typ_phar
+ /**
+ * Cli argument type phar
+ *
+ * @param string $arg The phar archive to use.
+ * @return object new Phar of the passed argument.
+ */
+ static function cli_arg_typ_phar($arg, $cfg, $key)
+ {
+ try {
+ return new Phar(self::cli_arg_typ_pharfile($arg, $cfg, $key));
+ } catch(Exception $e) {
+ self::error("Exception while opening phar '$argv':\n" . $e->getMessage() . "\n");
+ }
+ }
+ // }}}
+ // {{{ static function cli_arg_typ_entry
+ /**
+ * Argument type Entry name
+ *
+ * @param string $arg The argument (the entry)
+ * @return string $arg The entry itself.
+ */
+ static function cli_arg_typ_entry($arg, $cfg, $key)
+ {
+ // no further check atm, maybe check for no '/' at beginning
+ return $arg;
+ }
+ // }}}
+ // {{{ static function cli_arg_typ_compalg
+ /**
+ * Argument type compression algorithm
+ *
+ * @param string $arg The phar selection
+ * @param string $cfg The config option.
+ * @param string $key The key information.
+ * @return string $arg The selected algorithm
+ */
+ static function cli_arg_typ_compalg($arg, $cfg, $key)
+ {
+ $arg = self::cli_arg_typ_select($arg, $cfg, $key);
+
+ switch($arg) {
+ case 'auto':
+ if (extension_loaded('zlib')) {
+ $arg = 'gz';
+ } elseif (extension_loaded('bz2')) {
+ $arg = 'bz2';
+ } else {
+ $arg = '0';
+ }
+ break;
+ }
+ return $arg;
+ }
+ // }}}
+ // {{{ static function cli_cmd_inf_pack
+ /**
+ * Information pack
+ *
+ * @return string A description about packing files into a Phar archive.
+ */
+ static function cli_cmd_inf_pack()
+ {
+ return "Pack files into a PHAR archive.\n" .
+ "When using -s <stub>, then the stub file is being " .
+ "excluded from the list of input files/dirs." .
+ "To create an archive that contains PEAR class PHP_Archiave " .
+ "then point -p argument to PHP/Archive.php.\n";
+ }
+ // }}}
+ // {{{ static function cli_cmd_arg_pack
+ /**
+ * Pack a new phar infos
+ *
+ * @return array $args The arguments for a new Phar archive.
+ */
+ static function cli_cmd_arg_pack()
+ {
+ $args = self::phar_args('abcFhilpsx', 'pharnew');
+
+ $args[''] = array(
+ 'typ' => 'any',
+ 'val' => NULL,
+ 'required' => 1,
+ 'inf' => ' Any number of input files and directories. If -i is in use then ONLY files and matching thegiven regular expression are being packed. If -x is given then files matching that regular expression are NOT being packed.',
+
+ );
+
+ return $args;
+ }
+ // }}}
+ // {{{ function phar_set_stub_begin
+ /**
+ * Set the stub
+ */
+ public function phar_set_stub_begin(Phar $phar, $stub, $loader = NULL, $hashbang = NULL)
+ {
+ if (isset($stub)) {
+ $c = file_get_contents($stub);
+
+ if (substr($c, 0, 2) == '#!') {
+ if (strpos($c, "\n") !== false) {
+ if (!isset($hashbang)) {
+ $hashbang = substr($c, 0, strpos($c, "\n") + 1);
+ }
+ $c = substr($c, strpos($c, "\n") + 1);
+ } else {
+ if (!isset($hashbang)) {
+ $hashbang = $c;
+ }
+ $c = NULL;
+ }
+ }
+
+ if (isset($hashbang)) {
+ if (substr($hashbang, 0, 2) != '#!') {
+ $hashbang = '#!' . $hashbang;
+ }
+ if (substr($hashbang, -1) != "\n") {
+ $hashbang .= "\n";
+ }
+ } else {
+ $hashbang = "";
+ }
+
+ if (isset($loader)) {
+ $s = "<?php if (!class_exists('PHP_Archive')) {\n?>";
+ $s .= file_get_contents($loader);
+ $s .= "<?php\n";
+ $s .= "}\n";
+ $s .= "if (!in_array('phar', stream_get_wrappers())) {\n";
+ $s .= "\tstream_wrapper_register('phar', 'PHP_Archive');\n";
+ $s .= "}\n";
+ $s .= "if (!class_exists('Phar',0)) {\n";
+ $s .= "\tinclude 'phar://'.__FILE__.'/phar.inc';\n";
+ $s .= "}\n";
+ $s .= '?>';
+ $s .= $c;
+
+ $phar->setStub($hashbang . $s);
+ } else {
+ $phar->setStub($hashbang . $c);
+ }
+ return new SplFileInfo($stub);
+ }
+ return NULL;
+ }
+ // }}}
+ // {{{ function phar_set_stub_end
+ /**
+ * Set stub end
+ */
+ public function phar_set_stub_end(Phar $phar, $stub, $loader = NULL)
+ {
+ if (isset($stub) && isset($loader)) {
+ if (substr(__FILE__, -15) == 'pharcommand.inc') {
+ self::phar_add_file($phar, 0, 'phar.inc', 'phar://'.__FILE__.'/phar.inc', NULL);
+ } else {
+ self::phar_add_file($phar, 0, 'phar.inc', dirname(__FILE__).'/phar/phar.inc', NULL);
+ }
+ }
+ }
+ // }}}
+ // {{{ function cli_cmd_run_pack
+ /**
+ * Pack a new Phar
+ *
+ * This function will try to pack a new Phar archive.
+ *
+ * @see Exit to make sure that we are done.
+ */
+ public function cli_cmd_run_pack()
+ {
+ if (ini_get('phar.readonly')) {
+ self::error("Creating phar files is disabled by ini setting 'phar.readonly'.\n");
+ }
+
+ if (!Phar::canWrite()) {
+ self::error("Creating phar files is disabled, Phar::canWrite() returned false.\n");
+ }
+
+ $alias = $this->args['a']['val'];
+ $hashbang = $this->args['b']['val'];
+ $archive = $this->args['f']['val'];
+ $hash = $this->args['h']['val'];
+ $regex = $this->args['i']['val'];
+ $level = $this->args['l']['val'];
+ $loader = $this->args['p']['val'];
+ $stub = $this->args['s']['val'];
+ $invregex = $this->args['x']['val'];
+ $input = $this->args['']['val'];
+
+ $phar = new Phar($archive, 0, $alias);
+
+ $phar->startBuffering();
+
+ $stub = $this->phar_set_stub_begin($phar, $stub, $loader, $hashbang);
+
+ if (!is_array($input)) {
+ $this->phar_add($phar, $level, $input, $regex, $invregex, $stub, NULL, isset($loader));
+ } else {
+ foreach($input as $i) {
+ $this->phar_add($phar, $level, $i, $regex, $invregex, $stub, NULL, isset($loader));
+ }
+ }
+
+ $this->phar_set_stub_end($phar, $stub, $loader);
+
+ switch($this->args['c']['val']) {
+ case 'gz':
+ case 'gzip':
+ $phar->compressAllFilesGZ();
+ break;
+ case 'bz2':
+ case 'bzip2':
+ $phar->compressAllFilesBZIP2();
+ break;
+ default:
+ $phar->uncompressAllFiles();
+ break;
+ }
+
+ if ($hash) {
+ $phar->setSignatureAlgorithm($hash);
+ }
+
+ $phar->stopBuffering();
+ exit(0);
+ }
+ // }}}
+ // {{{ static function phar_add
+ /**
+ * Add files to a phar archive.
+ *
+ * This function will take a directory and iterate through
+ * it and get the files to insert into the Phar archive.
+ *
+ * @param Phar $phar The phar object.
+ * @param string $input The input directory
+ * @param string $regex The regex use in RegexIterator.
+ * @param string $invregex The InvertedRegexIterator expression.
+ * @param SplFileInfo $stub Stub file object
+ * @param mixed $compress Compression algorithm or NULL
+ * @param boolean $noloader Whether to prevent adding the loader
+ */
+ static function phar_add(Phar $phar, $level, $input, $regex, $invregex, SplFileInfo $stub = NULL, $compress = NULL, $noloader = false)
+ {
+ if ($input && is_file($input) && !is_dir($input)) {
+ return self::phar_add_file($phar, $level, $input, $input, $compress);
+ }
+ $dir = new RecursiveDirectoryIterator($input);
+ $dir = new RecursiveIteratorIterator($dir);
+
+ if (isset($regex)) {
+ $dir = new RegexIterator($dir, $regex);
+ }
+
+ if (isset($invregex)) {
+ $dir = new InvertedRegexIterator($dir, $invregex);
+ }
+
+ try {
+ foreach($dir as $file) {
+ if (empty($stub) || $file->getRealPath() != $stub->getRealPath()) {
+ self::phar_add_file($phar, $level, $dir->getSubPathName(), $file, $compress, $noloader);
+ }
+ }
+ } catch(Excpetion $e) {
+ self::error("Unable to complete operation on file '$file'\n" . $e->getMessage() . "\n");
+ }
+ }
+ // }}}
+ // {{{ static function phar_add_file
+ /**
+ * Add a phar file
+ *
+ * This function adds a file to a phar archive.
+ *
+ * @param Phar $phar The phar object
+ * @param string $level The level of the file.
+ * @param string $entry The entry point
+ * @param string $file The file to add to the archive
+ * @param string $compress The compression scheme for the file.
+ * @param boolean $noloader Whether to prevent adding the loader
+ */
+ static function phar_add_file(Phar $phar, $level, $entry, $file, $compress, $noloader = false)
+ {
+ $entry = str_replace('//', '/', $entry);
+ while($level-- > 0 && ($p = strpos($entry, '/')) !== false) {
+ $entry = substr($entry, $p+1);
+ }
+
+ if ($noloader && $entry == 'phar.inc') {
+ return;
+ }
+
+ echo "$entry\n";
+
+ $phar[$entry] = file_get_contents($file);
+ switch($compress) {
+ case 'gz':
+ case 'gzip':
+ $phar[$entry]->setCompressedGZ();
+ break;
+ case 'bz2':
+ case 'bzip2':
+ $phar[$entry]->setCompressedBZIP2();
+ break;
+ default:
+ break;
+ }
+ }
+ // }}}
+ // {{{ public function phar_dir_echo
+ /**
+ * Echo directory
+ *
+ * @param string $pn
+ * @param unknown_type $f
+ */
+ public function phar_dir_echo($pn, $f)
+ {
+ echo "$f\n";
+ }
+ // }}}
+ // {{{ public function phar_dir_operation
+ /**
+ * Directory operations
+ *
+ * Phar directory operations.
+ *
+ * @param RecursiveIteratorIterator $dir The recursiveIteratorIterator object.
+ * @param string $func Function to call on the iterations
+ * @param array $args Function arguments.
+ */
+ public function phar_dir_operation(RecursiveIteratorIterator $dir, $func, array $args = array())
+ {
+ $regex = $this->args['i']['val'];
+ $invregex= $this->args['x']['val'];
+
+ if (isset($regex)) {
+ $dir = new RegexIterator($dir, $regex);
+ }
+
+ if (isset($invregex)) {
+ $dir = new InvertedRegexIterator($dir, $invregex);
+ }
+
+ $any = false;
+ foreach($dir as $pn => $f) {
+ $any = true;
+ call_user_func($func, $pn, $f, $args);
+ }
+ return $any;
+ }
+ // {{{ static function cli_cmd_inf_list
+ /**
+ * Cli Command Info List
+ *
+ * @return string What inf does
+ */
+ static function cli_cmd_inf_list()
+ {
+ return "List contents of a PHAR archive.";
+ }
+ // }}}
+ // {{{ static function cli_cmd_arg_list
+ /**
+ * Cli Command Argument List
+ *
+ * @return arguments list
+ */
+ static function cli_cmd_arg_list()
+ {
+ return self::phar_args('Fix', 'pharurl');
+ }
+ // }}}
+ // {{{ public function cli_cmd_run_list
+ /**
+ * Cli Command Run List
+ *
+ * @see $this->phar_dir_operation
+ */
+ public function cli_cmd_run_list()
+ {
+ $this->phar_dir_operation(
+ new DirectoryTreeIterator(
+ $this->args['f']['val']),
+ array($this, 'phar_dir_echo')
+ );
+ }
+ // }}}
+ // {{{ static function cli_command_inf_tree
+ /**
+ * Cli Command Inf Tree
+ *
+ * @return string The description of a directory tree for a Phar archive.
+ */
+ static function cli_cmd_inf_tree()
+ {
+ return "Get a directory tree for a PHAR archive.";
+ }
+ // }}}
+ // {{{ static function cli_cmd_arg_tree
+ /**
+ * Cli Command Argument Tree
+ *
+ * @return string Arguments in URL format.
+ */
+ static function cli_cmd_arg_tree()
+ {
+ return self::phar_args('Fix', 'pharurl');
+ }
+ // }}}
+ // {{{ public function cli_cmd_run_tree
+ /**
+ * Cli Command Run Tree
+ *
+ * Set the phar_dir_operation with a directorygraphiterator.
+ *
+ * @see DirectoryGraphIterator
+ * @see $this->phar_dir_operation
+ *
+ */
+ public function cli_cmd_run_tree()
+ {
+ $a = $this->phar_dir_operation(
+ new DirectoryGraphIterator(
+ $this->args['f']['val']),
+ array($this, 'phar_dir_echo')
+ );
+ if (!$a) {
+ echo "|-<root directory>\n";
+ }
+ }
+ // }}}
+ // {{{ cli_cmd_inf_extract
+ /**
+ * Cli Command Inf Extract
+ *
+ * @return string The description of the command extra to a directory.
+ */
+ static function cli_cmd_inf_extract()
+ {
+ return "Extract a PHAR package to a directory.";
+ }
+ // }}}
+ // {{{ static function cli_cmd_arg_extract
+ /**
+ * Cli Command Arguments Extract
+ *
+ * The arguments for the extract function.
+ *
+ * @return array The arguments for the extraction.
+ */
+ static function cli_cmd_arg_extract()
+ {
+ $args = self::phar_args('Fix', 'phar');
+
+ $args[''] = array(
+ 'type' => 'dir',
+ 'val' => '.',
+ 'inf' => ' Directory to extract to (defaults to \'.\').',
+ );
+
+ return $args;
+ }
+ // }}}
+ // {{{ public function cli_cmd_run_extract
+ /**
+ * Run Extract
+ *
+ * Run the extraction of a phar Archive.
+ *
+ * @see $this->phar_dir_operation
+ */
+ public function cli_cmd_run_extract()
+ {
+ $dir = $this->args['']['val'];
+
+ if (is_array($dir)) {
+ if (count($dir) != 1) {
+ self::error("Only one target directory allowed.\n");
+ } else {
+ $dir = $dir[0];
+ }
+ }
+
+ $phar = $this->args['f']['val'];
+ $base = $phar->getPathname();
+ $bend = strpos($base, '.phar');
+ $bend = strpos($base, '/', $bend);
+ $base = substr($base, 0, $bend + 1);
+ $blen = strlen($base);
+
+ $this->phar_dir_operation(
+ new RecursiveIteratorIterator($phar),
+ array($this, 'phar_dir_extract'),
+ array($blen, $dir)
+ );
+ }
+ // }}}
+ // {{{ public function phar_dir_extract
+ /**
+ * Extract to a directory
+ *
+ * This function will extract the content of a Phar
+ * to a directory and create new files and directories
+ * depending on the permissions on that folder.
+ *
+ * @param string $pn
+ * @param string $f The file name
+ * @param array $args The directory and Blen informations
+ */
+ public function phar_dir_extract($pn, $f, $args)
+ {
+ $blen = $args[0];
+ $dir = $args[1];
+ $sub = substr($pn, $blen);
+ $target = $dir . '/' . $sub;
+
+ if (!file_exists(dirname($target))) {
+ if (!is_writable(dirname($target))) {
+ self::error("Operation could not be completed\n");
+ }
+
+ mkdir(dirname($target));
+ }
+
+ echo "$sub";
+
+ if (!@copy($f, $target)) {
+ echo " ...error\n";
+ } else {
+ echo " ...ok\n";
+ }
+ }
+ // }}}
+ // {{{ static function cli_cmd_inf_delete
+ /**
+ * Delete an entry from a phar information.
+ *
+ * @return string The information
+ */
+ static function cli_cmd_inf_delete()
+ {
+ return 'Delete entry from a PHAR archive';
+ }
+ // }}}
+ // {{{ static function cli_cmd_arg_delete
+ /**
+ * The cli command argument for deleting.
+ *
+ * @return array informations about the arguments to use.
+ */
+ static function cli_cmd_arg_delete()
+ {
+ return self::phar_args('FE', 'phar');
+ }
+ // }}}
+ // {{{ public function cli_cmd_run_delete
+ /**
+ * Deleting execution
+ *
+ * Execute the deleting of the file from the phar archive.
+ */
+ public function cli_cmd_run_delete()
+ {
+ $phar = $this->args['f']['val'];
+ $entry = $this->args['e']['val'];
+
+ $phar->startBuffering();
+ unset($phar[$entry]);
+ $phar->stopBuffering();
+ }
+ // }}}
+ // {{{ static function cli_cmd_inf_add
+ /**
+ * Client comment add file information
+ *
+ * @return string The description of the feature
+ */
+ static function cli_cmd_inf_add()
+ {
+ return "Add entries to a PHAR package.";
+ }
+ // }}}
+ // {{{ static function cli_cmd_arg_add
+ /**
+ * Add a file arguments
+ */
+ static function cli_cmd_arg_add()
+ {
+ $args = self::phar_args('acFilx', 'phar');
+ $args[''] = array(
+ 'type' => 'any',
+ 'val' => NULL,
+ 'required' => 1,
+ 'inf' => ' Any number of input files and directories. If -i is in use then ONLY files and matching thegiven regular expression are being packed. If -x is given then files matching that regular expression are NOT being packed.',
+ );
+ return $args;
+ }
+ // }}}
+ // {{{ public functio cli_cmd_run_add
+ /**
+ * Add a file
+ *
+ * Run the action of adding a file to
+ * a phar archive.
+ */
+ public function cli_cmd_run_add()
+ {
+ $compress= $this->args['c']['val'];
+ $phar = $this->args['f']['val'];
+ $regex = $this->args['i']['val'];
+ $level = $this->args['l']['val'];
+ $invregex= $this->args['x']['val'];
+ $input = $this->args['']['val'];
+
+ $phar->startBuffering();
+
+ if (!is_array($input)) {
+ $this->phar_add($phar, $level, $input, $regex, $invregex, NULL, $compress);
+ } else {
+ foreach($input as $i) {
+ $this->phar_add($phar, $level, $i, $regex, $invregex, NULL, $compress);
+ }
+ }
+ $phar->stopBuffering();
+ exit(0);
+ }
+ // }}}
+ // {{{ public function cli_cmd_inf_stub_set
+ /**
+ * Set the stup of a phar file.
+ *
+ * @return string The stub set description.
+ */
+ public function cli_cmd_inf_stub_set()
+ {
+ return "Set the stub of a PHAR file. " .
+ "If no input file is specified as stub then stdin is being used.";
+ }
+ // }}}
+ // {{{ public function cli_cmd_arg_stub_set
+ /**
+ * Set the argument stub
+ *
+ * @return string arguments for a stub
+ */
+ public function cli_cmd_arg_stub_set()
+ {
+ $args = self::phar_args('bFps', 'phar');
+ $args['s']['val'] = 'php://stdin';
+ return $args;
+ }
+ // }}}
+ // {{{ public function cli_cmd_run_stub_set
+ /**
+ * Cli Command run stub set
+ *
+ * @see $phar->setStub()
+ */
+ public function cli_cmd_run_stub_set()
+ {
+ $hashbang = $this->args['b']['val'];
+ $phar = $this->args['f']['val'];
+ $stub = $this->args['s']['val'];
+ $loader = $this->args['p']['val'];
+
+ $this->phar_set_stub_begin($phar, $stub, $loader, $hashbang);
+ $this->phar_set_stub_end($phar, $stub, $loader);
+ }
+ // }}}
+ // {{{ public function cli_cmd_inf_stub_get
+ /**
+ * Get the command stub infos.
+ *
+ * @return string a description of the stub of a Phar file.
+ */
+ public function cli_cmd_inf_stub_get()
+ {
+ return "Get the stub of a PHAR file. " .
+ "If no output file is specified as stub then stdout is being used.";
+ }
+ // }}}
+ // {{{ public function cli_cmd_arg_stub_get
+ /**
+ * Get the argument stub
+ *
+ * @return array $args The arguments passed to the stub.
+ */
+ public function cli_cmd_arg_stub_get()
+ {
+ $args = self::phar_args('Fs', 'phar');
+ $args['s']['val'] = 'php://stdin';
+ return $args;
+ }
+ // }}}
+ // {{{ public function cli_cmd_run_stub_get
+ /**
+ * Cli Command Run Stub
+ *
+ * Get arguments and store them into a stub.
+ *
+ * @param arguments $args
+ * @see $this->args
+ */
+ public function cli_cmd_run_stub_get($args)
+ {
+ $phar = $this->args['f']['val'];
+ $stub = $this->args['s']['val'];
+
+ file_put_contents($stub, $phar->getStub());
+ }
+ // }}}
+ // {{{ public function cli_cmd_inf_compress
+ /**
+ * Cli Command Inf Compress
+ *
+ * Cli Command compress informations
+ *
+ * @return string A description of the command.
+ */
+ public function cli_cmd_inf_compress()
+ {
+ return "Compress or uncompress all files or a selected entry.";
+ }
+ // }}}
+ // {{{ public function cli_cmd_arg_cmpress
+ /**
+ * Cli Command Arg Compress
+ *
+ * @return array The arguments for compress
+ */
+ public function cli_cmd_arg_compress()
+ {
+ return self::phar_args('FCe', 'phar');
+ }
+ // }}}
+ // {{{ public function cli_cmd_run_compress
+ /**
+ * Cli Command Run Compress
+ *
+ * @see $this->args
+ */
+ public function cli_cmd_run_compress()
+ {
+ $phar = $this->args['f']['val'];
+ $entry = $this->args['e']['val'];
+
+ switch($this->args['c']['val']) {
+ case 'gz':
+ case 'gzip':
+ if (isset($entry)) {
+ $phar[$entry]->setCompressedGZ();
+ } else {
+ $phar->compressAllFilesGZ();
+ }
+ break;
+ case 'bz2':
+ case 'bzip2':
+ if (isset($entry)) {
+ $phar[$entry]->setCompressedBZIP2();
+ } else {
+ $phar->compressAllFilesBZIP2();
+ }
+ break;
+ default:
+ if (isset($entry)) {
+ $phar[$entry]->setUncompressed();
+ } else {
+ $phar->uncompressAllFiles();
+ }
+ break;
+ }
+ }
+ // }}}
+ // {{{ public function cli_cmd_inf_sign
+ /**
+ * Cli Command Info Signature
+ *
+ * @return string A description of the signature arguments.
+ */
+ public function cli_cmd_inf_sign()
+ {
+ return "Set signature hash algorithm.";
+ }
+ // }}}
+ // {{{ public function cli_cmd_arg_sign
+ /**
+ * Cli Command Argument Sign
+ *
+ * @return array Arguments for Signature
+ */
+ public function cli_cmd_arg_sign()
+ {
+ return self::phar_args('FH', 'phar');
+ }
+ // }}}
+ // {{{ public function cli_cmd_run_sign
+ /**
+ * Cli Command Run Signature
+ *
+ * @see $phar->setSignaturealgorithm
+ */
+ public function cli_cmd_run_sign()
+ {
+ $phar = $this->args['f']['val'];
+ $hash = $this->args['h']['val'];
+
+ $phar->setSignatureAlgorithm($hash);
+ }
+ // }}}
+ // {{{ public function cli_cmd_inf_meta_set
+ /**
+ * Cli Command Inf Meta Set
+ *
+ * @return string A description
+ */
+ public function cli_cmd_inf_meta_set()
+ {
+ return "Set meta data of a PHAR entry or a PHAR package using serialized input. " .
+ "If no input file is specified for meta data then stdin is being used." .
+ "You can also specify a particular index using -k. In that case the metadata is " .
+ "expected to be an array and the value of the given index is being set. If " .
+ "the metadata is not present or empty a new array will be created. If the " .
+ "metadata is present and a flat value then the return value is 1. Also using -k " .
+ "the input is been taken directly rather then being serialized.";
+ }
+ // }}}
+ // {{{ public function cli_cmd_arg_meta_set
+ /**
+ * Cli Command Argument Meta Set
+ *
+ * @return array The arguments for meta set
+ */
+ public function cli_cmd_arg_meta_set()
+ {
+ return self::phar_args('FekM', 'phar');
+ }
+ // }}}
+ // {{{ public function cli_cmd_run_met_set
+ /**
+ * Cli Command Run Metaset
+ *
+ * @see $phar->startBuffering
+ * @see $phar->setMetadata
+ * @see $phar->stopBuffering
+ */
+ public function cli_cmd_run_meta_set()
+ {
+ $phar = $this->args['f']['val'];
+ $entry = $this->args['e']['val'];
+ $index = $this->args['k']['val'];
+ $meta = $this->args['m']['val'];
+
+ $phar->startBuffering();
+
+ if (isset($index)) {
+ if (isset($entry)) {
+ if ($phar[$entry]->hasMetadata()) {
+ $old = $phar[$entry]->getMetadata();
+ } else {
+ $old = array();
+ }
+ } else {
+ if ($phar->hasMetadata()) {
+ $old = $phar->getMetadata();
+ } else {
+ $old = array();
+ }
+ }
+
+ if (!is_array($old)) {
+ self::error('Metadata is a flat value while an index operation was issued.');
+ }
+
+ $old[$index] = $meta;
+ $meta = $old;
+ } else {
+ $meta = unserialize($meta);
+ }
+
+ if (isset($entry)) {
+ $phar[$entry]->setMetadata($meta);
+ } else {
+ $phar->setMetadata($meta);
+ }
+ $phar->stopBuffering();
+ }
+ // }}}
+ // {{{ public function cli_cmd_inf_met_get
+ /**
+ * Cli Command Inf Metaget
+ *
+ * @return string A description of the metaget arguments
+ */
+ public function cli_cmd_inf_meta_get()
+ {
+ return "Get meta information of a PHAR entry or a PHAR package in serialized from. " .
+ "If no output file is specified for meta data then stdout is being used.\n" .
+ "You can also specify a particular index using -k. In that case the metadata is " .
+ "expected to be an array and the value of the given index is returned using echo " .
+ "rather than using serialize. If that index does not exist or no meta data is " .
+ "present then the return value is 1.";
+ }
+ // }}}
+ // {{{ public function cli_cmd_arg_meta_get
+ /**
+ * Cli Command arg metaget
+ *
+ * @return array The arguments for meta get.
+ */
+ public function cli_cmd_arg_meta_get()
+ {
+ return self::phar_args('Fek', 'phar');
+ }
+ // }}}
+ // {{{ public function cli_cmd_run_meta_get
+ /**
+ * Cli Command Run Metaget
+ *
+ * @see $this->args
+ * @see $phar[$x]->hasMetadata()
+ * @see $phar->getMetadata()
+ */
+ public function cli_cmd_run_meta_get()
+ {
+ $phar = $this->args['f']['val'];
+ $entry = $this->args['e']['val'];
+ $index = $this->args['k']['val'];
+
+ if (isset($entry)) {
+ if (!$phar[$entry]->hasMetadata()) {
+ echo "No Metadata\n";
+ exit(1);
+ }
+ echo serialize($phar[$entry]->getMetadata());
+ } else {
+ if (!$phar->hasMetadata()) {
+ echo "No Metadata\n";
+ exit(1);
+ }
+ $meta = $phar->getMetadata();
+ }
+
+ if (isset($index)) {
+ if (isset($index)) {
+ if (isset($meta[$index])) {
+ echo $meta[$index];
+ exit(0);
+ } else {
+ echo "No Metadata\n";
+ exit(1);
+ }
+ } else {
+ echo serialize($meta);
+ }
+ }
+ }
+ // }}}
+ // {{{ public function cli_cmd_inf_meta_del
+ /**
+ * Cli Command Inf Metadel
+ *
+ * @return string A description of the metadel function
+ */
+ public function cli_cmd_inf_meta_del()
+ {
+ return "Delete meta information of a PHAR entry or a PHAR package.\n" .
+ "If -k is given then the metadata is expected to be an array " .
+ "and the given index is being deleted.\n" .
+ "If something was deleted the return value is 0 otherwise it is 1.";
+ }
+ // }}}
+ // {{{ public function cli_cmd_arg_meta_del
+ /**
+ * CliC ommand Arg Metadelete
+ *
+ * @return array The arguments for metadel
+ */
+ public function cli_cmd_arg_meta_del()
+ {
+ return self::phar_args('Fek', 'phar');
+ }
+ // }}}
+ // {{{ public function cli_cmd_run_meta_del
+ /**
+ * Cli Command Run MetaDel
+ *
+ * @see $phar[$x]->delMetadata()
+ * @see $phar->delMetadata()
+ */
+ public function cli_cmd_run_meta_del()
+ {
+ $phar = $this->args['f']['val'];
+ $entry = $this->args['e']['val'];
+ $index = $this->args['k']['val'];
+
+ if (isset($entry)) {
+ if (isset($index)) {
+ if (!$phar[$entry]->hasMetadata()) {
+ exit(1);
+ }
+ $meta = $phar[$entry]->getMetadata();
+
+ // @todo add error message here.
+ if (!is_array($meta)) {
+ exit(1);
+ }
+
+ unset($meta[$index]);
+ $phar[$entry]->setMetadata($meta);
+ } else {
+ exit($phar[$entry]->delMetadata() ? 0 : 1);
+ }
+ } else {
+ if (isset($index)) {
+ if (!$phar->hasMetadata()) {
+ exit(1);
+ }
+
+ $meta = $phar->getMetadata();
+
+ // @todo Add error message
+ if (!is_array($meta)) {
+ exit(1);
+ }
+
+ unset($meta[$index]);
+ $phar->setMetadata($meta);
+ } else {
+ exit($phar->delMetadata() ? 0 : 1);
+ }
+ }
+ }
+ // }}}
+ // {{{ public function cli_cmd_inf_info
+ /**
+ * CLi Command Inf Info
+ *
+ * @return string A description about the info commands.
+ */
+ public function cli_cmd_inf_info()
+ {
+ return "Get information about a PHAR package.\n" .
+ "By using -k it is possible to return a single value.";
+ }
+ // }}}
+ // {{{ public function cli_cmd_arg_info
+ /**
+ * Cli Command Arg Infos
+ *
+ * @return array The arguments for info command.
+ */
+ public function cli_cmd_arg_info()
+ {
+ return self::phar_args('Fk', 'phar');
+ }
+ // }}}
+ // {{{ public function cli_cmd_run_info
+ /**
+ * Cli Command Run Info
+ *
+ * @param args $args
+ */
+ public function cli_cmd_run_info()
+ {
+ $phar = $this->args['f']['val'];
+ $index = $this->args['k']['val'];
+
+ $hash = $phar->getSignature();
+ $infos = array();
+
+ if ($phar->getAlias()) {
+ $infos['Alias'] = $phar->getAlias();
+ }
+
+ if (!$hash) {
+ $infos['Hash-type'] = 'NONE';
+ } else {
+ $infos['Hash-type'] = $hash['hash_type'];
+ $infos['Hash'] = $hash['hash'];
+ }
+
+ $csize = 0;
+ $usize = 0;
+ $count = 0;
+ $ccount = 0;
+ $ucount = 0;
+ $mcount = 0;
+ $compalg = array('GZ'=>0, 'BZ2'=>0);
+
+ foreach(new RecursiveIteratorIterator($phar) as $ent) {
+ $count++;
+ if ($ent->isCompressed()) {
+ $ccount++;
+ $csize += $ent->getCompressedSize();
+ if ($ent->isCompressedGZ()) {
+ $compalg['GZ']++;
+ } elseif ($ent->isCompressedBZIP2()) {
+ $compalg['BZ2']++;
+ }
+ } else {
+ $ucount++;
+ $csize += $ent->getSize();
+ }
+
+ $usize += $ent->getSize();
+
+ if ($ent->hasMetadata()) {
+ $mcount++;
+ }
+ }
+
+ $infos['Entries'] = $count;
+ $infos['Uncompressed-files'] = $ucount;
+ $infos['Compressed-files'] = $ccount;
+ $infos['Compressed-gz'] = $compalg['GZ'];
+ $infos['Compressed-bz2'] = $compalg['BZ2'];
+ $infos['Uncompressed-size'] = $usize;
+ $infos['Compressed-size'] = $csize;
+ $infos['Compression-ratio'] = sprintf('%.3g%%', $usize ? ($csize * 100) / $usize : 100);
+ $infos['Metadata-global'] = $phar->hasMetadata() * 1;
+ $infos['Metadata-files'] = $mcount;
+ $infos['Stub-size'] = strlen($phar->getStub());
+
+ if (isset($index)) {
+ if (!isset($infos[$index])) {
+ self::error("Requested value does not exist.\n");
+ }
+
+ echo $infos[$index];
+ exit(0);
+ }
+
+ $l = 0;
+ foreach($infos as $which => $val) {
+ $l = max(strlen($which), $l);
+ }
+
+ foreach($infos as $which => $val) {
+ echo $which . ':' . str_repeat(' ', $l + 1 - strlen($which)) . $val . "\n";
+ }
+ }
+ // }}}
+}
+// }}}
+?>
diff --git a/ext/phar/phar_internal.h b/ext/phar/phar_internal.h
new file mode 100755
index 0000000000..1aa5425125
--- /dev/null
+++ b/ext/phar/phar_internal.h
@@ -0,0 +1,470 @@
+/*
+ +----------------------------------------------------------------------+
+ | phar php single-file executable PHP extension |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 2006-2007 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt. |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gregory Beaver <cellog@php.net> |
+ | Marcus Boerger <helly@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <time.h>
+#include "php.h"
+#include "tar.h"
+#include "php_ini.h"
+#include "zend_constants.h"
+#include "zend_execute.h"
+#include "zend_exceptions.h"
+#include "zend_hash.h"
+#include "zend_interfaces.h"
+#include "zend_operators.h"
+#include "zend_qsort.h"
+#include "zend_vm.h"
+#include "main/php_streams.h"
+#include "main/streams/php_stream_plain_wrapper.h"
+#include "main/SAPI.h"
+#include "main/php_main.h"
+#include "main/php_open_temporary_file.h"
+#include "ext/standard/info.h"
+#include "ext/standard/basic_functions.h"
+#include "ext/standard/file.h"
+#include "ext/standard/php_string.h"
+#include "ext/standard/url.h"
+#include "ext/standard/crc32.h"
+#include "ext/standard/md5.h"
+#include "ext/standard/sha1.h"
+#include "ext/standard/php_var.h"
+#include "ext/standard/php_smart_str.h"
+#include "ext/standard/php_versioning.h"
+#ifndef PHP_WIN32
+#include "TSRM/tsrm_strtok_r.h"
+#endif
+#include "TSRM/tsrm_virtual_cwd.h"
+#if HAVE_SPL
+#include "ext/spl/spl_array.h"
+#include "ext/spl/spl_directory.h"
+#include "ext/spl/spl_engine.h"
+#include "ext/spl/spl_exceptions.h"
+#include "ext/spl/spl_iterators.h"
+#endif
+#include "php_phar.h"
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#if HAVE_HASH_EXT
+#include "ext/hash/php_hash.h"
+#include "ext/hash/php_hash_sha.h"
+#endif
+
+#ifndef E_RECOVERABLE_ERROR
+#define E_RECOVERABLE_ERROR E_ERROR
+#endif
+
+/* PHP_ because this is public information via MINFO */
+#define PHP_PHAR_API_VERSION "1.1.1"
+/* x.y.z maps to 0xyz0 */
+#define PHAR_API_VERSION 0x1110
+/* if we bump PHAR_API_VERSION, change this from 0x1100 to PHAR_API_VERSION */
+#define PHAR_API_VERSION_NODIR 0x1100
+#define PHAR_API_MIN_DIR 0x1110
+#define PHAR_API_MIN_READ 0x1000
+#define PHAR_API_MAJORVERSION 0x1000
+#define PHAR_API_MAJORVER_MASK 0xF000
+#define PHAR_API_VER_MASK 0xFFF0
+
+#define PHAR_HDR_COMPRESSION_MASK 0x0000F000
+#define PHAR_HDR_COMPRESSED_NONE 0x00000000
+#define PHAR_HDR_COMPRESSED_GZ 0x00001000
+#define PHAR_HDR_COMPRESSED_BZ2 0x00002000
+#define PHAR_HDR_SIGNATURE 0x00010000
+
+/* flags for defining that the entire file should be compressed */
+#define PHAR_FILE_COMPRESSION_MASK 0x00F00000
+#define PHAR_FILE_COMPRESSED_NONE 0x00000000
+#define PHAR_FILE_COMPRESSED_GZ 0x00100000
+#define PHAR_FILE_COMPRESSED_BZ2 0x00200000
+
+#define PHAR_SIG_MD5 0x0001
+#define PHAR_SIG_SHA1 0x0002
+#define PHAR_SIG_SHA256 0x0003
+#define PHAR_SIG_SHA512 0x0004
+#define PHAR_SIG_PGP 0x0010
+
+/* flags byte for each file adheres to these bitmasks.
+ All unused values are reserved */
+#define PHAR_ENT_COMPRESSION_MASK 0x0000F000
+#define PHAR_ENT_COMPRESSED_NONE 0x00000000
+#define PHAR_ENT_COMPRESSED_GZ 0x00001000
+#define PHAR_ENT_COMPRESSED_BZ2 0x00002000
+
+#define PHAR_ENT_PERM_MASK 0x000001FF
+#define PHAR_ENT_PERM_MASK_USR 0x000001C0
+#define PHAR_ENT_PERM_SHIFT_USR 6
+#define PHAR_ENT_PERM_MASK_GRP 0x00000038
+#define PHAR_ENT_PERM_SHIFT_GRP 3
+#define PHAR_ENT_PERM_MASK_OTH 0x00000007
+#define PHAR_ENT_PERM_DEF_FILE 0x000001B6
+#define PHAR_ENT_PERM_DEF_DIR 0x000001FF
+
+#define PHAR_FORMAT_SAME 0
+#define PHAR_FORMAT_PHAR 1
+#define PHAR_FORMAT_TAR 2
+#define PHAR_FORMAT_ZIP 3
+
+#define TAR_FILE '0'
+#define TAR_LINK '1'
+#define TAR_SYMLINK '2'
+#define TAR_DIR '5'
+#define TAR_NEW '8'
+
+ZEND_BEGIN_MODULE_GLOBALS(phar)
+ HashTable phar_fname_map;
+ HashTable phar_alias_map;
+ HashTable phar_SERVER_mung_list;
+ int readonly;
+ zend_bool readonly_orig;
+ zend_bool require_hash_orig;
+ int request_init;
+ int require_hash;
+ int request_done;
+ int request_ends;
+ void (*orig_fopen)(INTERNAL_FUNCTION_PARAMETERS);
+ void (*orig_file_get_contents)(INTERNAL_FUNCTION_PARAMETERS);
+ void (*orig_is_file)(INTERNAL_FUNCTION_PARAMETERS);
+ void (*orig_is_link)(INTERNAL_FUNCTION_PARAMETERS);
+ void (*orig_is_dir)(INTERNAL_FUNCTION_PARAMETERS);
+ void (*orig_opendir)(INTERNAL_FUNCTION_PARAMETERS);
+ void (*orig_file_exists)(INTERNAL_FUNCTION_PARAMETERS);
+ void (*orig_fileperms)(INTERNAL_FUNCTION_PARAMETERS);
+ void (*orig_fileinode)(INTERNAL_FUNCTION_PARAMETERS);
+ void (*orig_filesize)(INTERNAL_FUNCTION_PARAMETERS);
+ void (*orig_fileowner)(INTERNAL_FUNCTION_PARAMETERS);
+ void (*orig_filegroup)(INTERNAL_FUNCTION_PARAMETERS);
+ void (*orig_fileatime)(INTERNAL_FUNCTION_PARAMETERS);
+ void (*orig_filemtime)(INTERNAL_FUNCTION_PARAMETERS);
+ void (*orig_filectime)(INTERNAL_FUNCTION_PARAMETERS);
+ void (*orig_filetype)(INTERNAL_FUNCTION_PARAMETERS);
+ void (*orig_is_writable)(INTERNAL_FUNCTION_PARAMETERS);
+ void (*orig_is_readable)(INTERNAL_FUNCTION_PARAMETERS);
+ void (*orig_is_executable)(INTERNAL_FUNCTION_PARAMETERS);
+ void (*orig_lstat)(INTERNAL_FUNCTION_PARAMETERS);
+ void (*orig_readfile)(INTERNAL_FUNCTION_PARAMETERS);
+ void (*orig_stat)(INTERNAL_FUNCTION_PARAMETERS);
+ /* used for includes with . in them inside front controller */
+ char* cwd;
+ int cwd_len;
+ int cwd_init;
+ZEND_END_MODULE_GLOBALS(phar)
+
+ZEND_EXTERN_MODULE_GLOBALS(phar)
+
+#ifdef ZTS
+# include "TSRM.h"
+# define PHAR_G(v) TSRMG(phar_globals_id, zend_phar_globals *, v)
+# define PHAR_GLOBALS ((zend_phar_globals *) (*((void ***) tsrm_ls))[TSRM_UNSHUFFLE_RSRC_ID(phar_globals_id)])
+#else
+# define PHAR_G(v) (phar_globals.v)
+# define PHAR_GLOBALS (&phar_globals)
+#endif
+
+#ifndef php_uint16
+# if SIZEOF_SHORT == 2
+# define php_uint16 unsigned short
+# else
+# define php_uint16 uint16_t
+# endif
+#endif
+#include "pharzip.h"
+
+#if HAVE_SPL
+typedef union _phar_archive_object phar_archive_object;
+typedef union _phar_entry_object phar_entry_object;
+#endif
+
+/*
+ * used in phar_entry_info->fp_type to
+ */
+enum phar_fp_type {
+ /* regular file pointer phar_archive_data->fp */
+ PHAR_FP,
+ /* uncompressed file pointer phar_archive_data->uncompressed_fp */
+ PHAR_UFP,
+ /* modified file pointer phar_entry_info->fp */
+ PHAR_MOD,
+ /* temporary manifest entry (file outside of the phar mapped to a location inside the phar)
+ this entry stores the stream to open in link (normally used for tars, but we steal it here) */
+ PHAR_TMP
+};
+
+typedef struct _phar_archive_data phar_archive_data;
+/* entry for one file in a phar file */
+typedef struct _phar_entry_info {
+ /* first bytes are exactly as in file */
+ php_uint32 uncompressed_filesize;
+ php_uint32 timestamp;
+ php_uint32 compressed_filesize;
+ php_uint32 crc32;
+ php_uint32 flags;
+ /* remainder */
+ /* when changing compression, save old flags in case fp is NULL */
+ php_uint32 old_flags;
+ zval *metadata;
+ php_uint32 filename_len;
+ char *filename;
+ enum phar_fp_type fp_type;
+ /* offset within original phar file of the file contents */
+ long offset_abs;
+ /* offset within fp of the file contents */
+ long offset;
+ /* offset within original phar file of the file header (for zip-based/tar-based) */
+ long header_offset;
+ php_stream *fp;
+ php_stream *cfp;
+ int fp_refcount;
+ int is_crc_checked:1;
+ int is_modified:1;
+ int is_deleted:1;
+ int is_dir:1;
+ /* this flag is used for mounted entries (external files mapped to location
+ inside a phar */
+ int is_mounted:1;
+ char *tmp;
+ /* used when iterating */
+ int is_temp_dir:1;
+ phar_archive_data *phar;
+ smart_str metadata_str;
+ /* tar-based phar file stuff */
+ int is_tar:1;
+ char *link; /* symbolic link to another file */
+ char tar_type;
+ /* zip-based phar file stuff */
+ int is_zip:1;
+} phar_entry_info;
+
+/* information about a phar file (the archive itself) */
+struct _phar_archive_data {
+ char *fname;
+ int fname_len;
+ /* for phar_detect_fname_ext, this stores the location of the file extension within fname */
+ char *ext;
+ int ext_len;
+ char *alias;
+ int alias_len;
+ char version[12];
+ size_t internal_file_start;
+ size_t halt_offset;
+ HashTable manifest;
+ /* hash of mounted directory paths */
+ HashTable mounted_dirs;
+ php_uint32 flags;
+ php_uint32 min_timestamp;
+ php_uint32 max_timestamp;
+ php_stream *fp;
+ /* decompressed file contents are stored here */
+ php_stream *ufp;
+ int refcount;
+ php_uint32 sig_flags;
+ int sig_len;
+ char *signature;
+ zval *metadata;
+ /* if 1, then this alias was manually specified by the user and is not a permanent alias */
+ int is_temporary_alias:1;
+ int is_modified:1;
+ int is_writeable:1;
+ int is_brandnew:1;
+ /* defer phar creation */
+ int donotflush:1;
+ /* zip-based phar variables */
+ int is_zip:1;
+ /* tar-based phar variables */
+ int is_tar:1;
+ /* PharData variables */
+ int is_data:1;
+};
+
+#define PHAR_MIME_PHP '\0'
+#define PHAR_MIME_PHPS '\1'
+#define PHAR_MIME_OTHER '\2'
+
+typedef struct _phar_mime_type {
+ char *mime;
+ int len;
+ /* one of PHAR_MIME_* */
+ char type;
+} phar_mime_type;
+
+/* stream access data for one file entry in a phar file */
+typedef struct _phar_entry_data {
+ phar_archive_data *phar;
+ php_stream *fp;
+ /* stream position proxy, allows multiple open streams referring to the same fp */
+ off_t position;
+ /* for copies of the phar fp, defines where 0 is */
+ off_t zero;
+ int for_write:1;
+ int is_zip:1;
+ int is_tar:1;
+ phar_entry_info *internal_file;
+} phar_entry_data;
+
+#if HAVE_SPL
+/* archive php object */
+union _phar_archive_object {
+ zend_object std;
+ spl_filesystem_object spl;
+ struct {
+ zend_object std;
+ phar_archive_data *archive;
+ } arc;
+};
+#endif
+
+#if HAVE_SPL
+/* entry php object */
+union _phar_entry_object {
+ zend_object std;
+ spl_filesystem_object spl;
+ struct {
+ zend_object std;
+ phar_entry_info *entry;
+ } ent;
+};
+#endif
+
+#ifndef PHAR_MAIN
+extern int phar_has_bz2;
+extern int phar_has_zlib;
+# if PHP_VERSION_ID >= 50300
+extern char *(*phar_save_resolve_path)(const char *filename, int filename_len TSRMLS_DC);
+# endif
+#endif
+
+BEGIN_EXTERN_C()
+
+
+#ifdef PHP_WIN32
+char *tsrm_strtok_r(char *s, const char *delim, char **last);
+
+static inline void phar_unixify_path_separators(char *path, int path_len)
+{
+ char *s;
+
+ /* unixify win paths */
+ for (s = path; s - path < path_len; ++s) {
+ if (*s == '\\') {
+ *s = '/';
+ }
+ }
+}
+#endif
+/**
+ * validate an alias, returns 1 for success, 0 for failure
+ */
+static inline int phar_validate_alias(const char *alias, int alias_len) /* {{{ */
+{
+ return !(memchr(alias, '/', alias_len) || memchr(alias, '\\', alias_len) || memchr(alias, ':', alias_len) ||
+ memchr(alias, ';', alias_len));
+}
+/* }}} */
+
+
+void phar_request_initialize(TSRMLS_D);
+
+void phar_object_init(TSRMLS_D);
+
+int phar_open_entry_file(phar_archive_data *phar, phar_entry_info *entry, char **error TSRMLS_DC);
+int phar_open_filename(char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, char **error TSRMLS_DC);
+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);
+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);
+int phar_open_compiled_file(char *alias, int alias_len, char **error TSRMLS_DC);
+int phar_free_alias(phar_archive_data *phar, char *alias, int alias_len TSRMLS_DC);
+int phar_get_archive(phar_archive_data **archive, char *fname, int fname_len, char *alias, int alias_len, char **error TSRMLS_DC);
+int phar_open_loaded(char *fname, int fname_len, char *alias, int alias_len, int is_data, int options, phar_archive_data** pphar, char **error TSRMLS_DC);
+
+/* utility functions */
+char *phar_create_default_stub(const char *index_php, const char *web_index, size_t *len, char **error TSRMLS_DC);
+char *phar_decompress_filter(phar_entry_info * entry, int return_unknown);
+char *phar_compress_filter(phar_entry_info * entry, int return_unknown);
+
+int phar_mount_entry(phar_archive_data *phar, char *filename, int filename_len, char *path, int path_len TSRMLS_DC);
+char *phar_find_in_include_path(char *file, int file_len, phar_archive_data **pphar TSRMLS_DC);
+char *phar_fix_filepath(char *path, int *new_len, int use_cwd TSRMLS_DC);
+phar_entry_info * phar_open_jit(phar_archive_data *phar, phar_entry_info *entry, php_stream *fp,
+ char **error, int for_write TSRMLS_DC);
+int phar_parse_metadata(char **buffer, zval **metadata, int zip_metadata_len TSRMLS_DC);
+void destroy_phar_manifest_entry(void *pDest);
+int phar_seek_efp(phar_entry_info *entry, off_t offset, int whence, off_t position, int follow_links TSRMLS_DC);
+php_stream *phar_get_efp(phar_entry_info *entry, int follow_links TSRMLS_DC);
+int phar_copy_entry_fp(phar_entry_info *source, phar_entry_info *dest, char **error TSRMLS_DC);
+int phar_open_entry_fp(phar_entry_info *entry, char **error, int follow_links TSRMLS_DC);
+phar_entry_info *phar_get_link_source(phar_entry_info *entry TSRMLS_DC);
+int phar_create_writeable_entry(phar_archive_data *phar, phar_entry_info *entry, char **error TSRMLS_DC);
+int phar_separate_entry_fp(phar_entry_info *entry, char **error TSRMLS_DC);
+int phar_open_archive_fp(phar_archive_data *phar TSRMLS_DC);
+
+/* tar functions in tar.c */
+int phar_is_tar(char *buf, char *fname);
+int phar_open_tarfile(php_stream* fp, char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, php_uint32 compression, char **error TSRMLS_DC);
+int phar_open_or_create_tar(char *fname, int fname_len, char *alias, int alias_len, int is_data, int options, phar_archive_data** pphar, char **error TSRMLS_DC);
+int phar_tar_flush(phar_archive_data *phar, char *user_stub, long len, int defaultstub, char **error TSRMLS_DC);
+
+/* zip functions in zip.c */
+int phar_open_zipfile(php_stream *fp, char *fname, int fname_len, char *alias, int alias_len, phar_archive_data** pphar, char **error TSRMLS_DC);
+int phar_open_or_create_zip(char *fname, int fname_len, char *alias, int alias_len, int is_data, int options, phar_archive_data** pphar, char **error TSRMLS_DC);
+int phar_zip_flush(phar_archive_data *archive, char *user_stub, long len, int defaultstub, char **error TSRMLS_DC);
+
+#ifdef PHAR_MAIN
+static int phar_open_fp(php_stream* fp, char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, char **error TSRMLS_DC);
+extern php_stream_wrapper php_stream_phar_wrapper;
+#endif
+
+int phar_archive_delref(phar_archive_data *phar TSRMLS_DC);
+int phar_entry_delref(phar_entry_data *idata TSRMLS_DC);
+
+phar_entry_info *phar_get_entry_info(phar_archive_data *phar, char *path, int path_len, char **error TSRMLS_DC);
+phar_entry_info *phar_get_entry_info_dir(phar_archive_data *phar, char *path, int path_len, char dir, char **error TSRMLS_DC);
+phar_entry_data *phar_get_or_create_entry_data(char *fname, int fname_len, char *path, int path_len, char *mode, char allow_dir, char **error TSRMLS_DC);
+int phar_get_entry_data(phar_entry_data **ret, char *fname, int fname_len, char *path, int path_len, char *mode, char allow_dir, char **error TSRMLS_DC);
+int phar_flush(phar_archive_data *archive, char *user_stub, long len, int convert, char **error TSRMLS_DC);
+int phar_detect_phar_fname_ext(const char *filename, int check_length, const char **ext_str, int *ext_len, int executable, int for_create, int is_complete TSRMLS_DC);
+int phar_split_fname(char *filename, int filename_len, char **arch, int *arch_len, char **entry, int *entry_len, int executable, int for_create TSRMLS_DC);
+
+typedef enum {
+ pcr_use_query,
+ pcr_is_ok,
+ pcr_err_double_slash,
+ pcr_err_up_dir,
+ pcr_err_curr_dir,
+ pcr_err_back_slash,
+ pcr_err_star,
+ pcr_err_illegal_char,
+ pcr_err_empty_entry
+} phar_path_check_result;
+
+phar_path_check_result phar_path_check(char **p, int *len, const char **error);
+
+END_EXTERN_C()
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c
new file mode 100755
index 0000000000..98b602adbc
--- /dev/null
+++ b/ext/phar/phar_object.c
@@ -0,0 +1,4650 @@
+/*
+ +----------------------------------------------------------------------+
+ | phar php single-file executable PHP extension |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 2005-2007 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt. |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gregory Beaver <cellog@php.net> |
+ | Marcus Boerger <helly@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#include "phar_internal.h"
+#include "func_interceptors.h"
+
+static zend_class_entry *phar_ce_archive;
+static zend_class_entry *phar_ce_data;
+static zend_class_entry *phar_ce_PharException;
+
+#if HAVE_SPL
+static zend_class_entry *phar_ce_entry;
+#endif
+
+static int phar_file_type(HashTable *mimes, char *file, char **mime_type TSRMLS_DC) /* {{{ */
+{
+ char *ext;
+ phar_mime_type *mime;
+ ext = strrchr(file, '.');
+ if (!ext) {
+ *mime_type = "text/plain";
+ /* no file extension = assume text/plain */
+ return PHAR_MIME_OTHER;
+ }
+ ++ext;
+ if (SUCCESS != zend_hash_find(mimes, ext, strlen(ext), (void **) &mime)) {
+ *mime_type = "application/octet-stream";
+ return PHAR_MIME_OTHER;
+ }
+ *mime_type = mime->mime;
+ return mime->type;
+}
+/* }}} */
+
+static void phar_mung_server_vars(char *fname, char *entry, int entry_len, char *basename, int basename_len, char *request_uri, int request_uri_len TSRMLS_DC) /* {{{ */
+{
+ zval **_SERVER, **stuff;
+ char *path_info;
+
+ /* "tweak" $_SERVER variables requested in earlier call to Phar::mungServer() */
+ if (SUCCESS != zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void **) &_SERVER)) {
+ return;
+ }
+
+ /* PATH_INFO and PATH_TRANSLATED should always be munged */
+ if (SUCCESS == zend_hash_find(Z_ARRVAL_PP(_SERVER), "PATH_INFO", sizeof("PATH_INFO"), (void **) &stuff)) {
+ int code;
+ zval *temp;
+ char newname[] = "PHAR_PATH_INFO";
+
+ path_info = Z_STRVAL_PP(stuff);
+ code = Z_STRLEN_PP(stuff);
+ if (Z_STRLEN_PP(stuff) > entry_len && !memcmp(Z_STRVAL_PP(stuff), entry, entry_len)) {
+ ZVAL_STRINGL(*stuff, Z_STRVAL_PP(stuff) + entry_len, request_uri_len, 1);
+
+ MAKE_STD_ZVAL(temp);
+ ZVAL_STRINGL(temp, path_info, code, 0);
+ zend_hash_update(Z_ARRVAL_PP(_SERVER), newname, sizeof(newname), (void *) &temp, sizeof(zval **), NULL);
+ }
+ }
+ if (SUCCESS == zend_hash_find(Z_ARRVAL_PP(_SERVER), "PATH_TRANSLATED", sizeof("PATH_TRANSLATED"), (void **) &stuff)) {
+ int code;
+ zval *temp;
+ char newname[] = "PHAR_PATH_TRANSLATED";
+
+ path_info = Z_STRVAL_PP(stuff);
+ code = Z_STRLEN_PP(stuff);
+ Z_STRLEN_PP(stuff) = spprintf(&(Z_STRVAL_PP(stuff)), 4096, "phar://%s%s", fname, entry);
+
+ MAKE_STD_ZVAL(temp);
+ ZVAL_STRINGL(temp, path_info, code, 0);
+ zend_hash_update(Z_ARRVAL_PP(_SERVER), newname, sizeof(newname), (void *) &temp, sizeof(zval **), NULL);
+ }
+ if (!PHAR_GLOBALS->phar_SERVER_mung_list.arBuckets || !zend_hash_num_elements(&(PHAR_GLOBALS->phar_SERVER_mung_list))) {
+ return;
+ }
+ if (zend_hash_exists(&(PHAR_GLOBALS->phar_SERVER_mung_list), "REQUEST_URI", sizeof("REQUEST_URI")-1)) {
+ if (SUCCESS == zend_hash_find(Z_ARRVAL_PP(_SERVER), "REQUEST_URI", sizeof("REQUEST_URI"), (void **) &stuff)) {
+ int code;
+ zval *temp;
+ char newname[] = "PHAR_REQUEST_URI";
+
+ path_info = Z_STRVAL_PP(stuff);
+ code = Z_STRLEN_PP(stuff);
+ if (Z_STRLEN_PP(stuff) > basename_len && !memcmp(Z_STRVAL_PP(stuff), basename, basename_len)) {
+ ZVAL_STRINGL(*stuff, Z_STRVAL_PP(stuff) + basename_len, Z_STRLEN_PP(stuff) - basename_len, 1);
+
+ MAKE_STD_ZVAL(temp);
+ ZVAL_STRINGL(temp, path_info, code, 0);
+ zend_hash_update(Z_ARRVAL_PP(_SERVER), newname, sizeof(newname), (void *) &temp, sizeof(zval **), NULL);
+ }
+ }
+ }
+ if (zend_hash_exists(&(PHAR_GLOBALS->phar_SERVER_mung_list), "PHP_SELF", sizeof("PHP_SELF")-1)) {
+ if (SUCCESS == zend_hash_find(Z_ARRVAL_PP(_SERVER), "PHP_SELF", sizeof("PHP_SELF"), (void **) &stuff)) {
+ int code;
+ zval *temp;
+ char newname[] = "PHAR_PHP_SELF";
+
+ path_info = Z_STRVAL_PP(stuff);
+ code = Z_STRLEN_PP(stuff);
+ if (Z_STRLEN_PP(stuff) > basename_len && !memcmp(Z_STRVAL_PP(stuff), basename, basename_len)) {
+ ZVAL_STRINGL(*stuff, Z_STRVAL_PP(stuff) + basename_len, Z_STRLEN_PP(stuff) - basename_len, 1);
+
+ MAKE_STD_ZVAL(temp);
+ ZVAL_STRINGL(temp, path_info, code, 0);
+ zend_hash_update(Z_ARRVAL_PP(_SERVER), newname, sizeof(newname), (void *) &temp, sizeof(zval **), NULL);
+ }
+ }
+ }
+
+ if (zend_hash_exists(&(PHAR_GLOBALS->phar_SERVER_mung_list), "SCRIPT_NAME", sizeof("SCRIPT_NAME")-1)) {
+ if (SUCCESS == zend_hash_find(Z_ARRVAL_PP(_SERVER), "SCRIPT_NAME", sizeof("SCRIPT_NAME"), (void **) &stuff)) {
+ int code;
+ zval *temp;
+ char newname[] = "PHAR_SCRIPT_NAME";
+
+ path_info = Z_STRVAL_PP(stuff);
+ code = Z_STRLEN_PP(stuff);
+ ZVAL_STRINGL(*stuff, entry, entry_len, 1);
+
+ MAKE_STD_ZVAL(temp);
+ ZVAL_STRINGL(temp, path_info, code, 0);
+ zend_hash_update(Z_ARRVAL_PP(_SERVER), newname, sizeof(newname), (void *) &temp, sizeof(zval **), NULL);
+ }
+ }
+
+ if (zend_hash_exists(&(PHAR_GLOBALS->phar_SERVER_mung_list), "SCRIPT_FILENAME", sizeof("SCRIPT_FILENAME")-1)) {
+ if (SUCCESS == zend_hash_find(Z_ARRVAL_PP(_SERVER), "SCRIPT_FILENAME", sizeof("SCRIPT_FILENAME"), (void **) &stuff)) {
+ int code;
+ zval *temp;
+ char newname[] = "PHAR_SCRIPT_FILENAME";
+
+ path_info = Z_STRVAL_PP(stuff);
+ code = Z_STRLEN_PP(stuff);
+ Z_STRLEN_PP(stuff) = spprintf(&(Z_STRVAL_PP(stuff)), 4096, "phar://%s%s", fname, entry);
+
+ MAKE_STD_ZVAL(temp);
+ ZVAL_STRINGL(temp, path_info, code, 0);
+ zend_hash_update(Z_ARRVAL_PP(_SERVER), newname, sizeof(newname), (void *) &temp, sizeof(zval **), NULL);
+ }
+ }
+}
+/* }}} */
+
+static int phar_file_action(phar_entry_data *phar, char *mime_type, int code, char *entry, int entry_len, char *arch, int arch_len, char *basename, int basename_len, char *ru, int ru_len TSRMLS_DC) /* {{{ */
+{
+ char *name = NULL, buf[8192], *cwd;
+ zend_syntax_highlighter_ini syntax_highlighter_ini;
+ sapi_header_line ctr = {0};
+ size_t got;
+ int dummy = 1, name_len, ret;
+ zend_file_handle file_handle;
+ zend_op_array *new_op_array;
+ zval *result = NULL;
+
+ switch (code) {
+ case PHAR_MIME_PHPS:
+ efree(basename);
+ /* highlight source */
+ if (entry[0] == '/') {
+ name_len = spprintf(&name, 4096, "phar://%s%s", arch, entry);
+ } else {
+ name_len = spprintf(&name, 4096, "phar://%s/%s", arch, entry);
+ }
+ php_get_highlight_struct(&syntax_highlighter_ini);
+
+ highlight_file(name, &syntax_highlighter_ini TSRMLS_CC);
+
+ phar_entry_delref(phar TSRMLS_CC);
+ efree(name);
+#ifdef PHP_WIN32
+ efree(arch);
+#endif
+ zend_bailout();
+ case PHAR_MIME_OTHER:
+ /* send headers, output file contents */
+ efree(basename);
+ ctr.line_len = spprintf(&(ctr.line), 0, "Content-type: %s", mime_type);
+ sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
+ efree(ctr.line);
+ ctr.line_len = spprintf(&(ctr.line), 0, "Content-length: %d", phar->internal_file->uncompressed_filesize);
+ sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
+ efree(ctr.line);
+ if (FAILURE == sapi_send_headers(TSRMLS_C)) {
+ phar_entry_delref(phar TSRMLS_CC);
+ zend_bailout();
+ }
+
+ /* prepare to output */
+ if (!phar_get_efp(phar->internal_file, 1 TSRMLS_CC)) {
+ char *error;
+ if (!phar_open_jit(phar->phar, phar->internal_file, phar->phar->fp, &error, 0 TSRMLS_CC)) {
+ if (error) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
+ efree(error);
+ }
+ return -1;
+ }
+ phar->fp = phar_get_efp(phar->internal_file, 1 TSRMLS_CC);
+ phar->zero = phar->internal_file->offset;
+ }
+ phar_seek_efp(phar->internal_file, 0, SEEK_SET, 0, 1 TSRMLS_CC);
+ do {
+ got = php_stream_read(phar->fp, buf, MIN(8192, phar->internal_file->uncompressed_filesize - phar->position));
+ PHPWRITE(buf, got);
+ phar->position = php_stream_tell(phar->fp) - phar->zero;
+ if (phar->position == (off_t) phar->internal_file->uncompressed_filesize) {
+ break;
+ }
+ } while (1);
+
+ phar_entry_delref(phar TSRMLS_CC);
+ zend_bailout();
+ case PHAR_MIME_PHP:
+ if (basename) {
+ phar_mung_server_vars(arch, entry, entry_len, basename, basename_len, ru, ru_len TSRMLS_CC);
+ efree(basename);
+ }
+ phar_entry_delref(phar TSRMLS_CC);
+ if (entry[0] == '/') {
+ name_len = spprintf(&name, 4096, "phar://%s%s", arch, entry);
+ } else {
+ name_len = spprintf(&name, 4096, "phar://%s/%s", arch, entry);
+ }
+
+ ret = php_stream_open_for_zend_ex(name, &file_handle, ENFORCE_SAFE_MODE|USE_PATH|STREAM_OPEN_FOR_INCLUDE TSRMLS_CC);
+
+ if (ret != SUCCESS) {
+ efree(name);
+ return -1;
+ }
+ PHAR_G(cwd) = NULL;
+ PHAR_G(cwd_len) = 0;
+ if (zend_hash_add(&EG(included_files), file_handle.opened_path, strlen(file_handle.opened_path)+1, (void *)&dummy, sizeof(int), NULL)==SUCCESS) {
+ if ((cwd = strrchr(entry, '/'))) {
+ PHAR_G(cwd_init) = 1;
+ if (entry == cwd) {
+ /* root directory */
+ PHAR_G(cwd_len) = 0;
+ PHAR_G(cwd) = NULL;
+ } else if (entry[0] == '/') {
+ PHAR_G(cwd_len) = cwd - (entry + 1);
+ PHAR_G(cwd) = estrndup(entry + 1, PHAR_G(cwd_len));
+ } else {
+ PHAR_G(cwd_len) = cwd - entry;
+ PHAR_G(cwd) = estrndup(entry, PHAR_G(cwd_len));
+ }
+ }
+ new_op_array = zend_compile_file(&file_handle, ZEND_REQUIRE TSRMLS_CC);
+ zend_destroy_file_handle(&file_handle TSRMLS_CC);
+ } else {
+ new_op_array = NULL;
+#if PHP_VERSION_ID >= 50300
+ zend_file_handle_dtor(&file_handle TSRMLS_CC);
+#else
+ zend_file_handle_dtor(&file_handle);
+#endif
+ }
+#ifdef PHP_WIN32
+ efree(arch);
+#endif
+ if (new_op_array) {
+ EG(return_value_ptr_ptr) = &result;
+ EG(active_op_array) = new_op_array;
+
+ zend_try {
+ zend_execute(new_op_array TSRMLS_CC);
+ } zend_catch {
+ } zend_end_try();
+ destroy_op_array(new_op_array TSRMLS_CC);
+ efree(new_op_array);
+ if (PHAR_G(cwd)) {
+ efree(PHAR_G(cwd));
+ PHAR_G(cwd) = NULL;
+ PHAR_G(cwd_len) = 0;
+ }
+ PHAR_G(cwd_init) = 0;
+ efree(name);
+ if (EG(return_value_ptr_ptr) && *EG(return_value_ptr_ptr)) {
+ zval_ptr_dtor(EG(return_value_ptr_ptr));
+ }
+ zend_bailout();
+ }
+ return PHAR_MIME_PHP;
+ }
+ return -1;
+}
+/* }}} */
+
+static void phar_do_403(char *entry, int entry_len TSRMLS_DC) /* {{{ */
+{
+ sapi_header_line ctr = {0};
+
+ ctr.response_code = 403;
+ ctr.line_len = sizeof("HTTP/1.0 403 Access Denied");
+ ctr.line = "HTTP/1.0 403 Access Denied";
+ sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
+ sapi_send_headers(TSRMLS_C);
+ PHPWRITE("<html>\n <head>\n <title>Access Denied</title>\n </head>\n <body>\n <h1>403 - File ", sizeof("<html>\n <head>\n <title>Access Denied</title>\n </head>\n <body>\n <h1>403 - File ") - 1);
+ PHPWRITE(entry, entry_len);
+ PHPWRITE(" Access Denied</h1>\n </body>\n</html>", sizeof(" Access Denied</h1>\n </body>\n</html>") - 1);
+}
+/* }}} */
+
+static void phar_do_404(char *fname, int fname_len, char *f404, int f404_len, char *entry, int entry_len TSRMLS_DC) /* {{{ */
+{
+ int hi;
+ phar_entry_data *phar;
+ char *error;
+ if (f404_len) {
+ if (FAILURE == phar_get_entry_data(&phar, fname, fname_len, f404, f404_len, "r", 0, &error TSRMLS_CC)) {
+ if (error) {
+ efree(error);
+ }
+ goto nofile;
+ }
+ hi = phar_file_action(phar, "text/html", PHAR_MIME_PHP, f404, f404_len, fname, fname_len, NULL, 0, NULL, 0 TSRMLS_CC);
+ } else {
+ sapi_header_line ctr = {0};
+nofile:
+ ctr.response_code = 404;
+ ctr.line_len = sizeof("HTTP/1.0 404 Not Found")+1;
+ ctr.line = "HTTP/1.0 404 Not Found";
+ sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
+ sapi_send_headers(TSRMLS_C);
+ PHPWRITE("<html>\n <head>\n <title>File Not Found</title>\n </head>\n <body>\n <h1>404 - File ", sizeof("<html>\n <head>\n <title>File Not Found</title>\n </head>\n <body>\n <h1>404 - File ") - 1);
+ PHPWRITE(entry, entry_len);
+ PHPWRITE(" Not Found</h1>\n </body>\n</html>", sizeof(" Not Found</h1>\n </body>\n</html>") - 1);
+ }
+}
+/* }}} */
+
+/* post-process REQUEST_URI and retrieve the actual request URI. This is for
+ cases like http://localhost/blah.phar/path/to/file.php/extra/stuff
+ which calls "blah.phar" file "path/to/file.php" with PATH_INFO "/extra/stuff" */
+static void phar_postprocess_ru_web(char *fname, int fname_len, char **entry, int *entry_len, char **ru, int *ru_len TSRMLS_DC) /* {{{ */
+{
+ char *e = *entry + 1, *u = NULL, *u1 = NULL, *saveu = NULL;
+ int e_len = *entry_len - 1, u_len = 0;
+ phar_archive_data **pphar;
+
+ /* we already know we can retrieve the phar if we reach here */
+ zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len, (void **) &pphar);
+
+ do {
+ if (zend_hash_exists(&((*pphar)->manifest), e, e_len)) {
+ if (u) {
+ u[0] = '/';
+ *ru = estrndup(u, u_len+1);
+ ++u_len;
+ u[0] = '\0';
+ } else {
+ *ru = NULL;
+ }
+ *ru_len = u_len;
+ *entry_len = e_len + 1;
+ return;
+ }
+ if (u) {
+ u1 = strrchr(e, '/');
+ u[0] = '/';
+ saveu = u;
+ e_len += u_len + 1;
+ u = u1;
+ if (!u) {
+ return;
+ }
+ } else {
+ u = strrchr(e, '/');
+ if (!u) {
+ if (saveu) {
+ saveu[0] = '/';
+ }
+ return;
+ }
+ }
+ u[0] = '\0';
+ u_len = strlen(u + 1);
+ e_len -= u_len + 1;
+ if (e_len < 0) {
+ if (saveu) {
+ saveu[0] = '/';
+ }
+ return;
+ }
+ } while (1);
+}
+/* }}} */
+
+/* {{{ proto void Phar::running([bool retphar = true])
+ * return the name of the currently running phar archive. If the optional parameter
+ * is set to true, return the phar:// URL to the currently running phar
+ */
+PHP_METHOD(Phar, running)
+{
+ char *fname, *arch, *entry;
+ int fname_len, arch_len, entry_len;
+ zend_bool retphar = 1;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &retphar) == FAILURE) {
+ return;
+ }
+
+ fname = zend_get_executed_filename(TSRMLS_C);
+ fname_len = strlen(fname);
+
+ if (fname_len > 7 && !memcmp(fname, "phar://", 7) && SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
+ efree(entry);
+ if (retphar) {
+ RETVAL_STRINGL(fname, arch_len + 7, 1);
+ efree(arch);
+ return;
+ } else {
+ RETURN_STRINGL(arch, arch_len, 0);
+ }
+ }
+ RETURN_STRINGL("", 0, 1);
+}
+/* }}} */
+
+/* {{{ proto void Phar::mount(string pharpath, string externalfile)
+ * mount an external file or path to a location within the phar. This maps
+ * an external file or directory to a location within the phar archive, allowing
+ * reference to an external location as if it were within the phar archive. This
+ * is useful for writable temp files like databases
+ */
+PHP_METHOD(Phar, mount)
+{
+ char *fname, *arch, *entry, *path, *actual;
+ int fname_len, arch_len, entry_len, path_len, actual_len;
+ phar_archive_data **pphar;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &path, &path_len, &actual, &actual_len) == FAILURE) {
+ return;
+ }
+
+ fname = zend_get_executed_filename(TSRMLS_C);
+ fname_len = strlen(fname);
+
+ if (fname_len > 7 && !memcmp(fname, "phar://", 7) && SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
+ efree(entry);
+ entry = NULL;
+ if (path_len > 7 && !memcmp(path, "phar://", 7)) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Can only mount internal paths within a phar archive, use a relative path instead of \"%s\"", path);
+ efree(arch);
+ return;
+ }
+carry_on2:
+ if (SUCCESS != zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **)&pphar)) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "%s is not a phar archive, cannot mount", arch);
+ efree(arch);
+ return;
+ }
+carry_on:
+ if (SUCCESS != phar_mount_entry(*pphar, actual, actual_len, path, path_len TSRMLS_CC)) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Mounting of %s to %s within phar %s failed", path, actual, arch);
+ if (path && path == entry) {
+ efree(entry);
+ }
+ efree(arch);
+ return;
+ }
+ if (path && path == entry) {
+ efree(entry);
+ }
+ efree(arch);
+ return;
+ } else if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len, (void **)&pphar)) {
+ goto carry_on;
+ } else if (SUCCESS == phar_split_fname(path, path_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
+ path = entry;
+ path_len = entry_len;
+ goto carry_on2;
+ }
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Mounting of %s to %s failed", path, actual);
+}
+/* }}} */
+
+/* {{{ proto void Phar::webPhar([string alias, [string index, [string f404, [array mimetypes, [callback rewrites]]]]])
+ * mapPhar for web-based phars. Reads the currently executed file (a phar)
+ * and registers its manifest. When executed in the CLI or CGI command-line sapi,
+ * this works exactly like mapPhar(). When executed by a web-based sapi, this
+ * reads $_SERVER['REQUEST_URI'] (the actual original value) and parses out the
+ * intended internal file.
+ */
+PHP_METHOD(Phar, webPhar)
+{
+ HashTable mimetypes;
+ phar_mime_type mime;
+ zval *mimeoverride = NULL, *rewrite = NULL;
+ char *alias = NULL, *error, *index_php = NULL, *f404 = NULL, *ru = NULL;
+ int alias_len = 0, ret, f404_len = 0, free_pathinfo = 0, ru_len = 0;
+ char *fname, *basename, *path_info, *mime_type, *entry, *pt;
+ int fname_len, entry_len, code, index_php_len = 0, not_cgi;
+ phar_entry_data *phar;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!s!saz", &alias, &alias_len, &index_php, &index_php_len, &f404, &f404_len, &mimeoverride, &rewrite) == FAILURE) {
+ return;
+ }
+
+ phar_request_initialize(TSRMLS_C);
+ fname = zend_get_executed_filename(TSRMLS_C);
+ fname_len = strlen(fname);
+ if (phar_open_compiled_file(alias, alias_len, &error TSRMLS_CC) != SUCCESS) {
+ if (error) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
+ efree(error);
+ }
+ return;
+ }
+
+ /* retrieve requested file within phar */
+ if (!(SG(request_info).request_method && SG(request_info).request_uri && (!strcmp(SG(request_info).request_method, "GET") || !strcmp(SG(request_info).request_method, "POST")))) {
+ return;
+ }
+#ifdef PHP_WIN32
+ fname = estrndup(fname, fname_len);
+ phar_unixify_path_separators(fname, fname_len);
+#endif
+ basename = strrchr(fname, '/');
+ if (!basename) {
+ basename = fname;
+ } else {
+ ++basename;
+ }
+
+ if ((strlen(sapi_module.name) == sizeof("cgi-fcgi")-1 && !strncmp(sapi_module.name, "cgi-fcgi", sizeof("cgi-fcgi")-1))
+ || (strlen(sapi_module.name) == sizeof("cgi")-1 && !strncmp(sapi_module.name, "cgi", sizeof("cgi")-1))) {
+ char *testit;
+
+ testit = sapi_getenv("SCRIPT_NAME", sizeof("SCRIPT_NAME")-1 TSRMLS_CC);
+ if (!(pt = strstr(testit, basename))) {
+ return;
+ }
+ path_info = sapi_getenv("PATH_INFO", sizeof("PATH_INFO")-1 TSRMLS_CC);
+ if (path_info) {
+ entry = estrdup(path_info);
+ entry_len = strlen(entry);
+ spprintf(&path_info, 0, "%s%s", testit, path_info);
+ free_pathinfo = 1;
+ } else {
+ path_info = testit;
+ entry = estrndup("", 0);
+ entry_len = 0;
+ }
+ pt = estrndup(testit, (pt - testit) + (fname_len - (basename - fname)));
+ not_cgi = 0;
+ } else {
+ path_info = SG(request_info).request_uri;
+
+ if (!(pt = strstr(path_info, basename))) {
+ /* this can happen with rewrite rules - and we have no idea what to do then, so return */
+ return;
+ }
+ entry_len = strlen(path_info);
+
+ entry_len -= (pt - path_info) + (fname_len - (basename - fname));
+ entry = estrndup(pt + (fname_len - (basename - fname)), entry_len);
+
+ pt = estrndup(path_info, (pt - path_info) + (fname_len - (basename - fname)));
+ not_cgi = 1;
+ }
+
+ if (rewrite) {
+ zend_fcall_info fci;
+ zend_fcall_info_cache fcc;
+ zval *params, *retval_ptr, **zp[1];
+
+ MAKE_STD_ZVAL(params);
+ ZVAL_STRINGL(params, entry, entry_len, 1);
+ zp[0] = &params;
+
+#if PHP_VERSION_ID < 50300
+ if (FAILURE == zend_fcall_info_init(rewrite, &fci, &fcc TSRMLS_CC)) {
+#else
+ if (FAILURE == zend_fcall_info_init(rewrite, 0, &fci, &fcc, NULL, NULL TSRMLS_CC)) {
+#endif
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar error: invalid rewrite callback");
+ if (free_pathinfo) {
+ efree(path_info);
+ }
+ return;
+ }
+
+ fci.param_count = 1;
+ fci.params = zp;
+#if PHP_VERSION_ID < 50300
+ ++(params->refcount);
+#else
+ Z_ADDREF_P(params);
+#endif
+ fci.retval_ptr_ptr = &retval_ptr;
+
+ if (FAILURE == zend_call_function(&fci, &fcc TSRMLS_CC)) {
+ if (!EG(exception)) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar error: failed to call rewrite callback");
+ }
+ if (free_pathinfo) {
+ efree(path_info);
+ }
+ return;
+ }
+ if (!fci.retval_ptr_ptr || !retval_ptr) {
+ if (free_pathinfo) {
+ efree(path_info);
+ }
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar error: rewrite callback must return a string or false");
+ return;
+ }
+ switch (Z_TYPE_P(retval_ptr)) {
+ case IS_STRING :
+ efree(entry);
+ if (fci.retval_ptr_ptr != &retval_ptr) {
+ entry = estrndup(Z_STRVAL_PP(fci.retval_ptr_ptr), Z_STRLEN_PP(fci.retval_ptr_ptr));
+ entry_len = Z_STRLEN_PP(fci.retval_ptr_ptr);
+ } else {
+ entry = Z_STRVAL_P(retval_ptr);
+ entry_len = Z_STRLEN_P(retval_ptr);
+ }
+ break;
+ case IS_BOOL :
+ phar_do_403(entry, entry_len TSRMLS_CC);
+ if (free_pathinfo) {
+ efree(path_info);
+ }
+ zend_bailout();
+ return;
+ default:
+ efree(retval_ptr);
+ if (free_pathinfo) {
+ efree(path_info);
+ }
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar error: rewrite callback must return a string or false");
+ return;
+ }
+ }
+
+ if (entry_len) {
+ phar_postprocess_ru_web(fname, fname_len, &entry, &entry_len, &ru, &ru_len TSRMLS_CC);
+ }
+ if (!entry_len || (entry_len == 1 && entry[0] == '/')) {
+ efree(entry);
+ /* direct request */
+ if (index_php_len) {
+ entry = index_php;
+ entry_len = index_php_len;
+ if (entry[0] != '/') {
+ spprintf(&entry, 0, "/%s", index_php);
+ ++entry_len;
+ }
+ } else {
+ /* assume "index.php" is starting point */
+ entry = estrndup("/index.php", sizeof("/index.php"));
+ entry_len = sizeof("/index.php")-1;
+ }
+ if (FAILURE == phar_get_entry_data(&phar, fname, fname_len, entry, entry_len, "r", 0, NULL TSRMLS_CC)) {
+ phar_do_404(fname, fname_len, f404, f404_len, entry, entry_len TSRMLS_CC);
+ if (free_pathinfo) {
+ efree(path_info);
+ }
+ zend_bailout();
+ } else {
+ char *tmp, sa;
+ sapi_header_line ctr = {0};
+ ctr.response_code = 301;
+ ctr.line_len = sizeof("HTTP/1.1 301 Moved Permanently")+1;
+ ctr.line = "HTTP/1.1 301 Moved Permanently";
+ sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
+
+ if (not_cgi) {
+ tmp = strstr(path_info, basename) + fname_len;
+ sa = *tmp;
+ *tmp = '\0';
+ }
+ ctr.response_code = 0;
+ if (path_info[strlen(path_info)-1] == '/') {
+ ctr.line_len = spprintf(&(ctr.line), 4096, "Location: %s%s", path_info, entry + 1);
+ } else {
+ ctr.line_len = spprintf(&(ctr.line), 4096, "Location: %s%s", path_info, entry);
+ }
+ if (not_cgi) {
+ *tmp = sa;
+ }
+ if (free_pathinfo) {
+ efree(path_info);
+ }
+ sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
+ sapi_send_headers(TSRMLS_C);
+ phar_entry_delref(phar TSRMLS_CC);
+ efree(ctr.line);
+ zend_bailout();
+ }
+ }
+
+ if (FAILURE == phar_get_entry_data(&phar, fname, fname_len, entry, entry_len, "r", 0, &error TSRMLS_CC)) {
+ phar_do_404(fname, fname_len, f404, f404_len, entry, entry_len TSRMLS_CC);
+#ifdef PHP_WIN32
+ efree(fname);
+#endif
+ zend_bailout();
+ }
+
+ /* set up mime types */
+ zend_hash_init(&mimetypes, sizeof(phar_mime_type *), zend_get_hash_value, NULL, 0);
+#define PHAR_SET_MIME(mimetype, ret, fileext) \
+ mime.mime = mimetype; \
+ mime.len = sizeof((mimetype))+1; \
+ mime.type = ret; \
+ zend_hash_add(&mimetypes, fileext, sizeof(fileext)-1, (void *)&mime, sizeof(phar_mime_type), NULL); \
+
+ PHAR_SET_MIME("text/html", PHAR_MIME_PHPS, "phps")
+ PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "c")
+ PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "cc")
+ PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "cpp")
+ PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "c++")
+ PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "dtd")
+ PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "h")
+ PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "log")
+ PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "rng")
+ PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "txt")
+ PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "xsd")
+ PHAR_SET_MIME("", PHAR_MIME_PHP, "php")
+ PHAR_SET_MIME("", PHAR_MIME_PHP, "inc")
+ PHAR_SET_MIME("video/avi", PHAR_MIME_OTHER, "avi")
+ PHAR_SET_MIME("image/bmp", PHAR_MIME_OTHER, "bmp")
+ PHAR_SET_MIME("text/css", PHAR_MIME_OTHER, "css")
+ PHAR_SET_MIME("image/gif", PHAR_MIME_OTHER, "gif")
+ PHAR_SET_MIME("text/html", PHAR_MIME_OTHER, "htm")
+ PHAR_SET_MIME("text/html", PHAR_MIME_OTHER, "html")
+ PHAR_SET_MIME("text/html", PHAR_MIME_OTHER, "htmls")
+ PHAR_SET_MIME("image/x-ico", PHAR_MIME_OTHER, "ico")
+ PHAR_SET_MIME("image/jpeg", PHAR_MIME_OTHER, "jpe")
+ PHAR_SET_MIME("image/jpeg", PHAR_MIME_OTHER, "jpg")
+ PHAR_SET_MIME("image/jpeg", PHAR_MIME_OTHER, "jpeg")
+ PHAR_SET_MIME("application/x-javascript", PHAR_MIME_OTHER, "js")
+ PHAR_SET_MIME("audio/midi", PHAR_MIME_OTHER, "midi")
+ PHAR_SET_MIME("audio/midi", PHAR_MIME_OTHER, "mid")
+ PHAR_SET_MIME("audio/mod", PHAR_MIME_OTHER, "mod")
+ PHAR_SET_MIME("movie/quicktime", PHAR_MIME_OTHER, "mov")
+ PHAR_SET_MIME("audio/mp3", PHAR_MIME_OTHER, "mp3")
+ PHAR_SET_MIME("video/mpeg", PHAR_MIME_OTHER, "mpg")
+ PHAR_SET_MIME("video/mpeg", PHAR_MIME_OTHER, "mpeg")
+ PHAR_SET_MIME("application/pdf", PHAR_MIME_OTHER, "pdf")
+ PHAR_SET_MIME("image/png", PHAR_MIME_OTHER, "png")
+ PHAR_SET_MIME("application/shockwave-flash", PHAR_MIME_OTHER, "swf")
+ PHAR_SET_MIME("image/tiff", PHAR_MIME_OTHER, "tif")
+ PHAR_SET_MIME("image/tiff", PHAR_MIME_OTHER, "tiff")
+ PHAR_SET_MIME("audio/wav", PHAR_MIME_OTHER, "wav")
+ PHAR_SET_MIME("image/xbm", PHAR_MIME_OTHER, "xbm")
+ PHAR_SET_MIME("text/xml", PHAR_MIME_OTHER, "xml")
+
+ /* set up user overrides */
+#define PHAR_SET_USER_MIME(ret) \
+ if (Z_TYPE_PP(val) == IS_LONG) { \
+ mime.mime = ""; \
+ mime.len = 0; \
+ } else { \
+ mime.mime = Z_STRVAL_PP(val); \
+ mime.len = Z_STRLEN_PP(val); \
+ } \
+ mime.type = ret; \
+ zend_hash_update(&mimetypes, key, keylen-1, (void *)&mime, sizeof(phar_mime_type), NULL);
+
+ if (mimeoverride) {
+ if (!zend_hash_num_elements(Z_ARRVAL_P(mimeoverride))) {
+ goto no_mimes;
+ }
+ for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(mimeoverride)); SUCCESS == zend_hash_has_more_elements(Z_ARRVAL_P(mimeoverride)); zend_hash_move_forward(Z_ARRVAL_P(mimeoverride))) {
+ zval **val;
+ char *key;
+ uint keylen;
+ ulong intkey;
+ if (HASH_KEY_IS_LONG == zend_hash_get_current_key_ex(Z_ARRVAL_P(mimeoverride), &key, &keylen, &intkey, 0, NULL)) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Key of MIME type overrides array must be a file extension, was \"%d\"", intkey);
+ phar_entry_delref(phar TSRMLS_CC);
+#ifdef PHP_WIN32
+ efree(fname);
+#endif
+ RETURN_FALSE;
+ }
+ if (FAILURE == zend_hash_get_current_data(Z_ARRVAL_P(mimeoverride), (void **) &val)) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Failed to retrieve Mime type for extension \"%s\"", key);
+ phar_entry_delref(phar TSRMLS_CC);
+#ifdef PHP_WIN32
+ efree(fname);
+#endif
+ RETURN_FALSE;
+ }
+ switch (Z_TYPE_PP(val)) {
+ case IS_LONG :
+ if (Z_LVAL_PP(val) == PHAR_MIME_PHP || Z_LVAL_PP(val) == PHAR_MIME_PHPS) {
+ PHAR_SET_USER_MIME((char) Z_LVAL_PP(val))
+ } else {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Unknown mime type specifier used, only Phar::PHP, Phar::PHPS and a mime type string are allowed");
+ phar_entry_delref(phar TSRMLS_CC);
+#ifdef PHP_WIN32
+ efree(fname);
+#endif
+ RETURN_FALSE;
+ }
+ break;
+ case IS_STRING :
+ PHAR_SET_USER_MIME(PHAR_MIME_OTHER)
+ break;
+ default :
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Unknown mime type specifier used (not a string or int), only Phar::PHP, Phar::PHPS and a mime type string are allowed");
+ phar_entry_delref(phar TSRMLS_CC);
+#ifdef PHP_WIN32
+ efree(fname);
+#endif
+ RETURN_FALSE;
+ }
+ }
+ }
+
+no_mimes:
+ code = phar_file_type(&mimetypes, entry, &mime_type TSRMLS_CC);
+ zend_hash_destroy(&mimetypes);
+ ret = phar_file_action(phar, mime_type, code, entry, entry_len, fname, fname_len, pt, strlen(pt), ru, ru_len TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ proto void Phar::mungServer(array munglist)
+ * Defines a list of up to 4 $_SERVER variables that should be modified for execution
+ * to mask the presence of the phar archive. This should be used in conjunction with
+ * Phar::webPhar(), and has no effect otherwise
+ * SCRIPT_NAME, PHP_SELF, REQUEST_URI and SCRIPT_FILENAME
+ */
+PHP_METHOD(Phar, mungServer)
+{
+ zval *mungvalues;
+ int php_self = 0, request_uri = 0, script_name = 0, script_filename = 0;
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &mungvalues) == FAILURE) {
+ return;
+ }
+
+ if (!zend_hash_num_elements(Z_ARRVAL_P(mungvalues))) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "No values passed to Phar::mungServer(), expecting an array of any of these strings: PHP_SELF, REQUEST_URI, SCRIPT_FILENAME, SCRIPT_NAME");
+ return;
+ }
+ if (zend_hash_num_elements(Z_ARRVAL_P(mungvalues)) > 4) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Too many values passed to Phar::mungServer(), expecting an array of any of these strings: PHP_SELF, REQUEST_URI, SCRIPT_FILENAME, SCRIPT_NAME");
+ return;
+ }
+
+ phar_request_initialize(TSRMLS_C);
+
+ for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(mungvalues)); SUCCESS == zend_hash_has_more_elements(Z_ARRVAL_P(mungvalues)); zend_hash_move_forward(Z_ARRVAL_P(mungvalues))) {
+ zval **data = NULL;
+
+ if (SUCCESS != zend_hash_get_current_data(Z_ARRVAL_P(mungvalues), (void **) &data)) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "unable to retrieve array value in Phar::mungServer()");
+ return;
+ }
+ if (Z_TYPE_PP(data) != IS_STRING) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Non-string value passed to Phar::mungServer(), expecting an array of any of these strings: PHP_SELF, REQUEST_URI, SCRIPT_FILENAME, SCRIPT_NAME");
+ return;
+ }
+ if (!php_self && Z_STRLEN_PP(data) == sizeof("PHP_SELF")-1 && !strncmp(Z_STRVAL_PP(data), "PHP_SELF", sizeof("PHP_SELF")-1)) {
+ if (SUCCESS != zend_hash_add_empty_element(&(PHAR_GLOBALS->phar_SERVER_mung_list), "PHP_SELF", sizeof("PHP_SELF")-1)) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Unable to add PHP_SELF to Phar::mungServer() list of values to mung");
+ return;
+ }
+ php_self = 1;
+ }
+ if (Z_STRLEN_PP(data) == sizeof("REQUEST_URI")-1) {
+ if (!request_uri && !strncmp(Z_STRVAL_PP(data), "REQUEST_URI", sizeof("REQUEST_URI")-1)) {
+ if (SUCCESS != zend_hash_add_empty_element(&(PHAR_GLOBALS->phar_SERVER_mung_list), "REQUEST_URI", sizeof("REQUEST_URI")-1)) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Unable to add REQUEST_URI to Phar::mungServer() list of values to mung");
+ return;
+ }
+ request_uri = 1;
+ }
+ if (!script_name && !strncmp(Z_STRVAL_PP(data), "SCRIPT_NAME", sizeof("SCRIPT_NAME")-1)) {
+ if (SUCCESS != zend_hash_add_empty_element(&(PHAR_GLOBALS->phar_SERVER_mung_list), "SCRIPT_NAME", sizeof("SCRIPT_NAME")-1)) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Unable to add SCRIPT_NAME to Phar::mungServer() list of values to mung");
+ return;
+ }
+ script_name = 1;
+ }
+ }
+ if (!script_filename && Z_STRLEN_PP(data) == sizeof("SCRIPT_FILENAME")-1 && !strncmp(Z_STRVAL_PP(data), "SCRIPT_FILENAME", sizeof("SCRIPT_FILENAME")-1)) {
+ if (SUCCESS != zend_hash_add_empty_element(&(PHAR_GLOBALS->phar_SERVER_mung_list), "SCRIPT_FILENAME", sizeof("SCRIPT_FILENAME")-1)) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Unable to add SCRIPT_FILENAME to Phar::mungServer() list of values to mung");
+ return;
+ }
+ script_filename = 1;
+ }
+ }
+}
+/* }}} */
+
+/* {{{ proto void Phar::interceptFileFuncs()
+ * instructs phar to intercept fopen, file_get_contents, opendir, and all of the stat-related functions
+ * and return stat on files within the phar for relative paths
+ *
+ * Once called, this cannot be reversed, and continue until the end of the request.
+ *
+ * This allows legacy scripts to be pharred unmodified
+ */
+PHP_METHOD(Phar, interceptFileFuncs)
+{
+ phar_intercept_functions(TSRMLS_C);
+}
+/* }}} */
+
+/* {{{ proto array Phar::createDefaultStub([string indexfile[, string webindexfile]])
+ * Return a stub that can be used to run a phar-based archive without the phar extension
+ * indexfile is the CLI startup filename, which defaults to "index.php", webindexfile
+ * is the web startup filename, and also defaults to "index.php"
+ */
+PHP_METHOD(Phar, createDefaultStub)
+{
+ char *index = NULL, *webindex = NULL, *stub, *error;
+ int index_len = 0, webindex_len = 0;
+ size_t stub_len;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ss", &index, &index_len, &webindex, &webindex_len) == FAILURE) {
+ return;
+ }
+
+ stub = phar_create_default_stub(index, webindex, &stub_len, &error TSRMLS_CC);
+
+ if (error) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
+ efree(error);
+ return;
+ }
+ RETURN_STRINGL(stub, stub_len, 0);
+}
+/* }}} */
+
+/* {{{ proto mixed Phar::mapPhar([string alias, [int dataoffset]])
+ * Reads the currently executed file (a phar) and registers its manifest */
+PHP_METHOD(Phar, mapPhar)
+{
+ char *alias = NULL, *error;
+ int alias_len = 0;
+ long dataoffset = 0;
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!l", &alias, &alias_len, &dataoffset) == FAILURE) {
+ return;
+ }
+
+ phar_request_initialize(TSRMLS_C);
+
+ RETVAL_BOOL(phar_open_compiled_file(alias, alias_len, &error TSRMLS_CC) == SUCCESS);
+ if (error) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
+ efree(error);
+ }
+} /* }}} */
+
+/* {{{ proto mixed Phar::loadPhar(string filename [, string alias])
+ * Loads any phar archive with an alias */
+PHP_METHOD(Phar, loadPhar)
+{
+ char *fname, *alias = NULL, *error;
+ int fname_len, alias_len = 0;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s!", &fname, &fname_len, &alias, &alias_len) == FAILURE) {
+ return;
+ }
+
+ phar_request_initialize(TSRMLS_C);
+
+ RETVAL_BOOL(phar_open_filename(fname, fname_len, alias, alias_len, REPORT_ERRORS, NULL, &error TSRMLS_CC) == SUCCESS);
+ if (error) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
+ efree(error);
+ }
+} /* }}} */
+
+/* {{{ proto string Phar::apiVersion()
+ * Returns the api version */
+PHP_METHOD(Phar, apiVersion)
+{
+ RETURN_STRINGL(PHP_PHAR_API_VERSION, sizeof(PHP_PHAR_API_VERSION)-1, 1);
+}
+/* }}}*/
+
+/* {{{ proto bool Phar::canCompress([int method])
+ * Returns whether phar extension supports compression using zlib/bzip2 */
+PHP_METHOD(Phar, canCompress)
+{
+ long method = 0;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &method) == FAILURE) {
+ return;
+ }
+
+ switch (method) {
+ case PHAR_ENT_COMPRESSED_GZ:
+ if (phar_has_zlib) {
+ RETURN_TRUE;
+ } else {
+ RETURN_FALSE;
+ }
+
+ case PHAR_ENT_COMPRESSED_BZ2:
+ if (phar_has_bz2) {
+ RETURN_TRUE;
+ } else {
+ RETURN_FALSE;
+ }
+
+ default:
+ if (phar_has_zlib || phar_has_bz2) {
+ RETURN_TRUE;
+ } else {
+ RETURN_FALSE;
+ }
+ }
+}
+/* }}} */
+
+/* {{{ proto bool Phar::canWrite()
+ * Returns whether phar extension supports writing and creating phars */
+PHP_METHOD(Phar, canWrite)
+{
+ RETURN_BOOL(!PHAR_G(readonly));
+}
+/* }}} */
+
+/* {{{ proto bool Phar::isValidPharFilename(string filename[, bool executable = true])
+ * Returns whether the given filename is a valid phar filename */
+PHP_METHOD(Phar, isValidPharFilename)
+{
+ char *fname;
+ const char *ext_str;
+ int fname_len, ext_len;
+ zend_bool executable = 1;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &fname, &fname_len, &executable) == FAILURE) {
+ return;
+ }
+
+ fname_len = executable;
+ RETVAL_BOOL(phar_detect_phar_fname_ext(fname, 1, &ext_str, &ext_len, fname_len, 2, 1 TSRMLS_CC) == SUCCESS);
+}
+/* }}} */
+
+#if HAVE_SPL
+/**
+ * from spl_directory
+ */
+static void phar_spl_foreign_dtor(spl_filesystem_object *object TSRMLS_DC) /* {{{ */
+{
+ phar_archive_delref((phar_archive_data *) object->oth TSRMLS_CC);
+ object->oth = NULL;
+}
+/* }}} */
+
+/**
+ * from spl_directory
+ */
+static void phar_spl_foreign_clone(spl_filesystem_object *src, spl_filesystem_object *dst TSRMLS_DC) /* {{{ */
+{
+ phar_archive_data *phar_data = (phar_archive_data *) dst->oth;
+
+ ++(phar_data->refcount);
+}
+/* }}} */
+
+static spl_other_handler phar_spl_foreign_handler = {
+ phar_spl_foreign_dtor,
+ phar_spl_foreign_clone
+};
+#endif /* HAVE_SPL */
+
+/* {{{ proto void Phar::__construct(string fname [, int flags [, string alias]])
+ * Construct a Phar archive object
+ * {{{ proto void PharData::__construct(string fname [, int flags [, string alias]])
+ * Construct a PharData archive object
+ */
+PHP_METHOD(Phar, __construct)
+{
+#if !HAVE_SPL
+ zend_throw_exception_ex(zend_exception_get_default(TSRMLS_C), 0 TSRMLS_CC, "Cannot instantiate Phar object without SPL extension");
+#else
+ char *fname, *alias = NULL, *error, *arch = NULL, *entry = NULL, *save_fname, *objname;
+ int fname_len, alias_len = 0, arch_len, entry_len, is_data;
+ long flags = 0;
+ phar_archive_object *phar_obj;
+ phar_archive_data *phar_data;
+ zval *zobj = getThis(), arg1, arg2;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ls!", &fname, &fname_len, &flags, &alias, &alias_len) == FAILURE) {
+ return;
+ }
+
+ phar_obj = (phar_archive_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (phar_obj->arc.archive) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Cannot call constructor twice");
+ return;
+ }
+
+#if PHP_VERSION_ID >= 60000
+ objname = phar_obj->std.ce->name.s;
+#else
+ objname = phar_obj->std.ce->name;
+#endif
+ if (!strncmp(objname, "PharData", 8)) {
+ is_data = 1;
+ } else {
+ is_data = 0;
+ }
+
+ if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, !is_data, 2 TSRMLS_CC)) {
+ /* use arch (the basename for the archive) for fname instead of fname */
+ /* this allows support for RecursiveDirectoryIterator of subdirectories */
+ save_fname = fname;
+#ifdef PHP_WIN32
+ phar_unixify_path_separators(arch, arch_len);
+#endif
+ fname = arch;
+ fname_len = arch_len;
+#ifdef PHP_WIN32
+ } else {
+ arch = estrndup(fname, fname_len);
+ arch_len = fname_len;
+ save_fname = fname;
+ fname = arch;
+ phar_unixify_path_separators(arch, arch_len);
+#endif
+ }
+
+ if (phar_open_or_create_filename(fname, fname_len, alias, alias_len, is_data, REPORT_ERRORS, &phar_data, &error TSRMLS_CC) == FAILURE) {
+
+ if (fname == arch) {
+ efree(arch);
+ fname = save_fname;
+ }
+ if (entry) {
+ efree(entry);
+ }
+ if (error) {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
+ "%s", error);
+ efree(error);
+ } else {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
+ "Phar creation or opening failed");
+ }
+ return;
+ }
+
+ if (fname == arch) {
+ efree(arch);
+ fname = save_fname;
+ }
+
+ is_data = phar_data->is_data;
+ ++(phar_data->refcount);
+ phar_obj->arc.archive = phar_data;
+ phar_obj->spl.oth_handler = &phar_spl_foreign_handler;
+
+ if (entry) {
+ fname_len = spprintf(&fname, 0, "phar://%s%s", phar_data->fname, entry);
+ efree(entry);
+ } else {
+ fname_len = spprintf(&fname, 0, "phar://%s", phar_data->fname);
+ }
+
+ INIT_PZVAL(&arg1);
+ ZVAL_STRINGL(&arg1, fname, fname_len, 0);
+
+ if (ZEND_NUM_ARGS() > 1) {
+ INIT_PZVAL(&arg2);
+ ZVAL_LONG(&arg2, flags);
+ zend_call_method_with_2_params(&zobj, Z_OBJCE_P(zobj),
+ &spl_ce_RecursiveDirectoryIterator->constructor, "__construct", NULL, &arg1, &arg2);
+ } else {
+ zend_call_method_with_1_params(&zobj, Z_OBJCE_P(zobj),
+ &spl_ce_RecursiveDirectoryIterator->constructor, "__construct", NULL, &arg1);
+ }
+
+ phar_obj->arc.archive->is_data = is_data;
+ phar_obj->spl.info_class = phar_ce_entry;
+
+ efree(fname);
+#endif /* HAVE_SPL */
+}
+/* }}} */
+
+/* {{{ proto array Phar::getSupportedSignatures()
+ * Return array of supported signature types
+ */
+PHP_METHOD(Phar, getSupportedSignatures)
+{
+ array_init(return_value);
+
+ add_next_index_stringl(return_value, "MD5", 3, 1);
+ add_next_index_stringl(return_value, "SHA-1", 5, 1);
+#if HAVE_HASH_EXT
+ add_next_index_stringl(return_value, "SHA-256", 7, 1);
+ add_next_index_stringl(return_value, "SHA-512", 7, 1);
+#endif
+}
+/* }}} */
+
+/* {{{ proto array Phar::getSupportedCompression()
+ * Return array of supported comparession algorithms
+ */
+PHP_METHOD(Phar, getSupportedCompression)
+{
+ array_init(return_value);
+
+ if (phar_has_zlib) {
+ add_next_index_stringl(return_value, "GZ", 2, 1);
+ }
+ if (phar_has_bz2) {
+ add_next_index_stringl(return_value, "BZIP2", 5, 1);
+ }
+}
+/* }}} */
+
+/* {{{ proto array Phar::unlinkArchive(string archive)
+ * Completely remove a phar archive from memory and disk
+ */
+PHP_METHOD(Phar, unlinkArchive)
+{
+ char *fname, *error, *zname, *arch, *entry;
+ int fname_len, zname_len, arch_len, entry_len;
+ phar_archive_data *phar;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &fname, &fname_len) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ if (!fname_len) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Unknown phar archive \"\"");
+ return;
+ }
+
+ if (FAILURE == phar_open_filename(fname, fname_len, NULL, 0, REPORT_ERRORS, &phar, &error TSRMLS_CC)) {
+ if (error) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Unknown phar archive \"%s\": %s", fname, error);
+ efree(error);
+ } else {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Unknown phar archive \"%s\"", fname);
+ }
+ return;
+ }
+
+ zname = zend_get_executed_filename(TSRMLS_C);
+ zname_len = strlen(zname);
+
+ if (zname_len > 7 && !memcmp(zname, "phar://", 7) && SUCCESS == phar_split_fname(zname, zname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
+ if (arch_len == fname_len && !memcmp(arch, fname, arch_len)) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar archive \"%s\" cannot be unlinked from within itself", fname);
+ efree(arch);
+ efree(entry);
+ return;
+ }
+ efree(arch);
+ efree(entry);
+ }
+
+ if (phar->refcount) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar archive \"%s\" has open file handles or objects. fclose() all file handles, and unset() all objects prior to calling unlinkArchive()", fname);
+ return;
+ }
+ fname = estrndup(phar->fname, phar->fname_len);
+ phar_archive_delref(phar TSRMLS_CC);
+ unlink(fname);
+ efree(fname);
+ RETURN_TRUE;
+}
+/* }}} */
+
+#if HAVE_SPL
+
+#define PHAR_ARCHIVE_OBJECT() \
+ phar_archive_object *phar_obj = (phar_archive_object*)zend_object_store_get_object(getThis() TSRMLS_CC); \
+ if (!phar_obj->arc.archive) { \
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, \
+ "Cannot call method on an uninitialized Phar object"); \
+ return; \
+ }
+
+static int phar_build(zend_object_iterator *iter, void *puser TSRMLS_DC) /* {{{ */
+{
+ zval **value;
+ zend_uchar key_type;
+ zend_bool is_splfileinfo = 0, close_fp = 1;
+ ulong int_key;
+ struct _t {
+ phar_archive_object *p;
+ zend_class_entry *c;
+ char *b;
+ uint l;
+ zval *ret;
+ } *p_obj = (struct _t*) puser;
+ uint str_key_len, base_len = p_obj->l, fname_len;
+ phar_entry_data *data;
+ php_stream *fp;
+ long contents_len;
+ char *fname, *error, *str_key, *base = p_obj->b, *opened, *save = NULL, *temp = NULL;
+ zend_class_entry *ce = p_obj->c;
+ phar_archive_object *phar_obj = p_obj->p;
+ char *str = "[stream]";
+
+ iter->funcs->get_current_data(iter, &value TSRMLS_CC);
+ if (EG(exception)) {
+ return ZEND_HASH_APPLY_STOP;
+ }
+ if (!value) {
+ /* failure in get_current_data */
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %s returned no value", ce->name);
+ return ZEND_HASH_APPLY_STOP;
+ }
+ switch (Z_TYPE_PP(value)) {
+ case IS_STRING :
+ break;
+ case IS_RESOURCE :
+ php_stream_from_zval_no_verify(fp, value);
+ if (!fp) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Iterator %s returned an invalid stream handle", ce->name);
+ return ZEND_HASH_APPLY_STOP;
+ }
+ if (iter->funcs->get_current_key) {
+ key_type = iter->funcs->get_current_key(iter, &str_key, &str_key_len, &int_key TSRMLS_CC);
+ if (EG(exception)) {
+ return ZEND_HASH_APPLY_STOP;
+ }
+ if (key_type == HASH_KEY_IS_LONG) {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %s returned an invalid key (must return a string)", ce->name);
+ return ZEND_HASH_APPLY_STOP;
+ }
+ save = str_key;
+ if (str_key[str_key_len - 1] == '\0') str_key_len--;
+ } else {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %s returned an invalid key (must return a string)", ce->name);
+ return ZEND_HASH_APPLY_STOP;
+ }
+ close_fp = 0;
+ opened = (char *) estrndup(str, sizeof("[stream]") + 1);
+ goto after_open_fp;
+ case IS_OBJECT :
+ if (instanceof_function(Z_OBJCE_PP(value), spl_ce_SplFileInfo TSRMLS_CC)) {
+ char *test = NULL;
+ zval dummy;
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(*value TSRMLS_CC);
+
+ if (!base_len) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Iterator %s returns an SplFileInfo object, so base directory must be specified", ce->name);
+ return ZEND_HASH_APPLY_STOP;
+ }
+ switch (intern->type) {
+ case SPL_FS_DIR:
+#if PHP_VERSION_ID >= 60000
+ test = spl_filesystem_object_get_path(intern, NULL, NULL TSRMLS_CC).s;
+#elif PHP_VERSION_ID >= 50300
+ test = spl_filesystem_object_get_path(intern, NULL TSRMLS_CC);
+#else
+ test = intern->path;
+#endif
+ fname_len = spprintf(&fname, 0, "%s%c%s", test, DEFAULT_SLASH, intern->u.dir.entry.d_name);
+ php_stat(fname, fname_len, FS_IS_DIR, &dummy TSRMLS_CC);
+ if (Z_BVAL(dummy)) {
+ /* ignore directories */
+ efree(fname);
+ return ZEND_HASH_APPLY_KEEP;
+ }
+ test = expand_filepath(fname, NULL TSRMLS_CC);
+ if (test) {
+ efree(fname);
+ fname = test;
+ fname_len = strlen(fname);
+ }
+ save = fname;
+ is_splfileinfo = 1;
+ goto phar_spl_fileinfo;
+ case SPL_FS_INFO:
+ case SPL_FS_FILE:
+ fname = expand_filepath(intern->file_name, NULL TSRMLS_CC);
+ fname_len = strlen(fname);
+ save = fname;
+ is_splfileinfo = 1;
+ goto phar_spl_fileinfo;
+ }
+ }
+ /* fall-through */
+ default :
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %s returned an invalid value (must return a string)", ce->name);
+ return ZEND_HASH_APPLY_STOP;
+ }
+
+ fname = Z_STRVAL_PP(value);
+ fname_len = Z_STRLEN_PP(value);
+
+phar_spl_fileinfo:
+ if (base_len) {
+ temp = expand_filepath(base, NULL TSRMLS_CC);
+ base = temp;
+ base_len = strlen(base);
+ if (strstr(fname, base)) {
+ str_key_len = fname_len - base_len;
+ if (str_key_len <= 0) {
+ if (save) {
+ efree(save);
+ efree(temp);
+ }
+ return ZEND_HASH_APPLY_KEEP;
+ }
+ str_key = fname + base_len;
+ if (*str_key == '/' || *str_key == '\\') {
+ str_key++;
+ str_key_len--;
+ }
+ } else {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %s returned a path \"%s\" that is not in the base directory \"%s\"", ce->name, fname, base);
+ if (save) {
+ efree(save);
+ efree(temp);
+ }
+ return ZEND_HASH_APPLY_STOP;
+ }
+ } else {
+ if (iter->funcs->get_current_key) {
+ key_type = iter->funcs->get_current_key(iter, &str_key, &str_key_len, &int_key TSRMLS_CC);
+ if (EG(exception)) {
+ return ZEND_HASH_APPLY_STOP;
+ }
+ if (key_type == HASH_KEY_IS_LONG) {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %s returned an invalid key (must return a string)", ce->name);
+ return ZEND_HASH_APPLY_STOP;
+ }
+ save = str_key;
+ if (str_key[str_key_len - 1] == '\0') str_key_len--;
+ } else {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %s returned an invalid key (must return a string)", ce->name);
+ return ZEND_HASH_APPLY_STOP;
+ }
+ }
+#if PHP_MAJOR_VERSION < 6
+ if (PG(safe_mode) && (!php_checkuid(fname, NULL, CHECKUID_ALLOW_ONLY_FILE))) {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %s returned a path \"%s\" that safe mode prevents opening", ce->name, fname);
+ if (save) {
+ efree(save);
+ }
+ if (temp) {
+ efree(temp);
+ }
+ return ZEND_HASH_APPLY_STOP;
+ }
+#endif
+
+ if (php_check_open_basedir(fname TSRMLS_CC)) {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %s returned a path \"%s\" that open_basedir prevents opening", ce->name, fname);
+ if (save) {
+ efree(save);
+ }
+ if (temp) {
+ efree(temp);
+ }
+ return ZEND_HASH_APPLY_STOP;
+ }
+
+ /* try to open source file, then create internal phar file and copy contents */
+ fp = php_stream_open_wrapper(fname, "rb", STREAM_MUST_SEEK|0, &opened);
+ if (!fp) {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %s returned a file that could not be opened \"%s\"", ce->name, fname);
+ if (save) {
+ efree(save);
+ }
+ if (temp) {
+ efree(temp);
+ }
+ return ZEND_HASH_APPLY_STOP;
+ }
+
+after_open_fp:
+ if (!(data = phar_get_or_create_entry_data(phar_obj->arc.archive->fname, phar_obj->arc.archive->fname_len, str_key, str_key_len, "w+b", 0, &error TSRMLS_CC))) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Entry %s cannot be created: %s", str_key, error);
+ efree(error);
+ if (save) {
+ efree(save);
+ }
+ if (temp) {
+ efree(temp);
+ }
+ if (close_fp) {
+ php_stream_close(fp);
+ }
+ return ZEND_HASH_APPLY_STOP;
+ } else {
+ if (error) {
+ efree(error);
+ }
+ contents_len = php_stream_copy_to_stream(fp, data->fp, PHP_STREAM_COPY_ALL);
+ }
+ if (close_fp) {
+ php_stream_close(fp);
+ }
+
+ add_assoc_string(p_obj->ret, str_key, opened, 0);
+
+ if (save) {
+ efree(save);
+ }
+ if (temp) {
+ efree(temp);
+ }
+
+ data->internal_file->compressed_filesize = data->internal_file->uncompressed_filesize = contents_len;
+ phar_entry_delref(data TSRMLS_CC);
+ return ZEND_HASH_APPLY_KEEP;
+}
+/* }}} */
+
+/* {{{ proto array Phar::buildFromDirectory(string base_dir[, string regex])
+ * Construct a phar archive from an existing directory, recursively.
+ * Optional second parameter is a regular expression for filtering directory contents.
+ *
+ * Return value is an array mapping phar index to actual files added.
+ */
+PHP_METHOD(Phar, buildFromDirectory)
+{
+ char *dir, *error, *regex = NULL;
+ int dir_len, regex_len = 0;
+ zend_bool apply_reg = 0;
+ zval arg, arg2, *iter, *iteriter, *regexiter = NULL;
+ struct {
+ phar_archive_object *p;
+ zend_class_entry *c;
+ char *b;
+ uint l;
+ zval *ret;
+ } pass;
+
+ PHAR_ARCHIVE_OBJECT();
+
+ if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
+ "Cannot write to archive - write operations restricted by INI setting");
+ return;
+ }
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &dir, &dir_len, &regex, &regex_len) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ MAKE_STD_ZVAL(iter);
+
+ if (SUCCESS != object_init_ex(iter, spl_ce_RecursiveDirectoryIterator)) {
+ zval_ptr_dtor(&iter);
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Unable to instantiate directory iterator for %s", phar_obj->arc.archive->fname);
+ RETURN_FALSE;
+ }
+
+ INIT_PZVAL(&arg);
+ ZVAL_STRINGL(&arg, dir, dir_len, 0);
+
+ zend_call_method_with_1_params(&iter, spl_ce_RecursiveDirectoryIterator,
+ &spl_ce_RecursiveDirectoryIterator->constructor, "__construct", NULL, &arg);
+
+ if (EG(exception)) {
+ zval_ptr_dtor(&iter);
+ RETURN_FALSE;
+ }
+
+ MAKE_STD_ZVAL(iteriter);
+
+ if (SUCCESS != object_init_ex(iteriter, spl_ce_RecursiveIteratorIterator)) {
+ zval_ptr_dtor(&iter);
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Unable to instantiate directory iterator for %s", phar_obj->arc.archive->fname);
+ RETURN_FALSE;
+ }
+
+ zend_call_method_with_1_params(&iteriter, spl_ce_RecursiveIteratorIterator,
+ &spl_ce_RecursiveIteratorIterator->constructor, "__construct", NULL, iter);
+
+ if (EG(exception)) {
+ zval_ptr_dtor(&iter);
+ zval_ptr_dtor(&iteriter);
+ RETURN_FALSE;
+ }
+
+ zval_ptr_dtor(&iter);
+
+ if (regex_len > 0) {
+ apply_reg = 1;
+ MAKE_STD_ZVAL(regexiter);
+
+ if (SUCCESS != object_init_ex(regexiter, spl_ce_RegexIterator)) {
+ zval_dtor(regexiter);
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Unable to instantiate regex iterator for %s", phar_obj->arc.archive->fname);
+ RETURN_FALSE;
+ }
+
+ INIT_PZVAL(&arg2);
+ ZVAL_STRINGL(&arg2, regex, regex_len, 0);
+
+ zend_call_method_with_2_params(&regexiter, spl_ce_RegexIterator,
+ &spl_ce_RegexIterator->constructor, "__construct", NULL, iteriter, &arg2);
+ }
+
+ array_init(return_value);
+
+ pass.c = apply_reg ? Z_OBJCE_P(regexiter) : Z_OBJCE_P(iteriter);
+ pass.p = phar_obj;
+ pass.b = dir;
+ pass.l = dir_len;
+ pass.ret = return_value;
+
+ if (SUCCESS == spl_iterator_apply((apply_reg ? regexiter : iteriter), (spl_iterator_apply_func_t) phar_build, (void *) &pass TSRMLS_CC)) {
+ zval_ptr_dtor(&iteriter);
+ if (apply_reg) {
+ zval_ptr_dtor(&regexiter);
+ }
+ phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC);
+ if (error) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
+ efree(error);
+ }
+ }
+}
+
+/* {{{ proto array Phar::buildFromIterator(Iterator iter[, string base_directory])
+ * Construct a phar archive from an iterator. The iterator must return a series of strings
+ * that are full paths to files that should be added to the phar. The iterator key should
+ * be the path that the file will have within the phar archive.
+ *
+ * If base directory is specified, then the key will be ignored, and instead the portion of
+ * the current value minus the base directory will be used
+ *
+ * Returned is an array mapping phar index to actual file added
+ */
+PHP_METHOD(Phar, buildFromIterator)
+{
+ zval *obj;
+ char *error;
+ uint base_len = 0;
+ char *base = NULL;
+ struct {
+ phar_archive_object *p;
+ zend_class_entry *c;
+ char *b;
+ uint l;
+ zval *ret;
+ } pass;
+ PHAR_ARCHIVE_OBJECT();
+
+ if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
+ "Cannot write out phar archive, phar is read-only");
+ return;
+ }
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|s", &obj, zend_ce_traversable, &base, &base_len) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ array_init(return_value);
+
+ pass.c = Z_OBJCE_P(obj);
+ pass.p = phar_obj;
+ pass.b = base;
+ pass.l = base_len;
+ pass.ret = return_value;
+
+ if (SUCCESS == spl_iterator_apply(obj, (spl_iterator_apply_func_t) phar_build, (void *) &pass TSRMLS_CC)) {
+ phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC);
+ if (error) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
+ efree(error);
+ }
+ }
+
+}
+/* }}} */
+
+/* {{{ proto int Phar::count()
+ * Returns the number of entries in the Phar archive
+ */
+PHP_METHOD(Phar, count)
+{
+ PHAR_ARCHIVE_OBJECT();
+
+ RETURN_LONG(zend_hash_num_elements(&phar_obj->arc.archive->manifest));
+}
+/* }}} */
+
+/* {{{ proto bool Phar::isFileFormat(int format)
+ * Returns true if the phar archive is based on the tar/zip/phar file format depending
+ * on whether Phar::TAR, Phar::ZIP or Phar::PHAR was passed in
+ */
+PHP_METHOD(Phar, isFileFormat)
+{
+ long type;
+ PHAR_ARCHIVE_OBJECT();
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &type) == FAILURE) {
+ RETURN_FALSE;
+ }
+ switch (type) {
+ case PHAR_FORMAT_TAR:
+ RETURN_BOOL(phar_obj->arc.archive->is_tar);
+ case PHAR_FORMAT_ZIP:
+ RETURN_BOOL(phar_obj->arc.archive->is_zip);
+ case PHAR_FORMAT_PHAR:
+ RETURN_BOOL(!phar_obj->arc.archive->is_tar && !phar_obj->arc.archive->is_zip);
+ default:
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Unknown file format specified");
+ }
+}
+/* }}} */
+
+static int phar_copy_file_contents(phar_entry_info *entry, php_stream *fp TSRMLS_DC) /* {{{ */
+{
+ char *error;
+ off_t offset;
+ phar_entry_info *link;
+
+ if (FAILURE == phar_open_entry_fp(entry, &error, 1 TSRMLS_CC)) {
+ if (error) {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
+ "Cannot convert phar archive \"%s\", unable to open entry \"%s\" contents: %s", entry->phar->fname, entry->filename, error);
+ efree(error);
+ } else {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
+ "Cannot convert phar archive \"%s\", unable to open entry \"%s\" contents", entry->phar->fname, entry->filename);
+ }
+ return FAILURE;
+ }
+ /* copy old contents in entirety */
+ phar_seek_efp(entry, 0, SEEK_SET, 0, 1 TSRMLS_CC);
+ offset = php_stream_tell(fp);
+ link = phar_get_link_source(entry TSRMLS_CC);
+ if (!link) {
+ link = entry;
+ }
+ if (link->uncompressed_filesize != php_stream_copy_to_stream(phar_get_efp(link, 0 TSRMLS_CC), fp, link->uncompressed_filesize)) {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
+ "Cannot convert phar archive \"%s\", unable to copy entry \"%s\" contents", entry->phar->fname, entry->filename);
+ return FAILURE;
+ }
+ if (entry->fp_type == PHAR_MOD) {
+ /* save for potential restore on error */
+ entry->cfp = entry->fp;
+ entry->fp = NULL;
+ }
+ /* set new location of file contents */
+ entry->fp_type = PHAR_FP;
+ entry->offset = offset;
+ return SUCCESS;
+}
+/* }}} */
+
+static zval *phar_rename_archive(phar_archive_data *phar, char *ext, zend_bool compress TSRMLS_DC)
+{
+ char *oldname = NULL, *oldpath = NULL;
+ char *basename = NULL, *basepath = NULL;
+ char *newname = NULL, *newpath = NULL;
+ zval *ret, arg1;
+ zend_class_entry *ce;
+ char *error;
+ const char *pcr_error;
+ int ext_len = ext ? strlen(ext) : 0;
+
+ if (!ext) {
+ if (phar->is_zip) {
+ if (phar->is_data) {
+ ext = "zip";
+ } else {
+ ext = "phar.zip";
+ }
+ } else if (phar->is_tar) {
+ switch (phar->flags) {
+ case PHAR_FILE_COMPRESSED_GZ:
+ if (phar->is_data) {
+ ext = "tar.gz";
+ } else {
+ ext = "phar.tar.gz";
+ }
+ break;
+ case PHAR_FILE_COMPRESSED_BZ2:
+ if (phar->is_data) {
+ ext = "tar.bz2";
+ } else {
+ ext = "phar.tar.bz2";
+ }
+ break;
+ default:
+ if (phar->is_data) {
+ ext = "tar";
+ } else {
+ ext = "phar.tar";
+ }
+ }
+ } else {
+ switch (phar->flags) {
+ case PHAR_FILE_COMPRESSED_GZ:
+ ext = "phar.gz";
+ break;
+ case PHAR_FILE_COMPRESSED_BZ2:
+ ext = "phar.bz2";
+ break;
+ default:
+ ext = "phar";
+ }
+ }
+ } else if (phar_path_check(&ext, &ext_len, &pcr_error) > pcr_is_ok) {
+ if (phar->is_data) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "data phar converted from \"%s\" has invalid extension %s", phar->fname, ext);
+ } else {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "phar converted from \"%s\" has invalid extension %s", phar->fname, ext);
+ }
+ return NULL;
+ }
+
+ if (ext[0] == '.') {
+ ++ext;
+ }
+
+ oldpath = estrndup(phar->fname, phar->fname_len);
+ oldname = strrchr(phar->fname, '/');
+ ++oldname;
+
+ basename = estrndup(oldname, strlen(oldname));
+ spprintf(&newname, 0, "%s.%s", strtok(basename, "."), ext);
+ efree(basename);
+
+ basepath = estrndup(oldpath, strlen(oldpath) - strlen(oldname));
+ phar->fname_len = spprintf(&newpath, 0, "%s%s", basepath, newname);
+ phar->fname = newpath;
+ efree(basepath);
+ efree(newname);
+
+ if (zend_hash_exists(&(PHAR_GLOBALS->phar_fname_map), newpath, phar->fname_len)) {
+ efree(oldpath);
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Unable to add newly converted phar \"%s\" to the list of phars, a phar with that name already exists", phar->fname);
+ return NULL;
+ }
+
+ if (!phar->is_data) {
+ if (SUCCESS != phar_detect_phar_fname_ext(newpath, phar->fname_len, (const char **) &(phar->ext), &(phar->ext_len), 1, 1, 1 TSRMLS_CC)) {
+ efree(oldpath);
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "phar \"%s\" has invalid extension %s", phar->fname, ext);
+ return NULL;
+ }
+ if (phar->alias) {
+ if (phar->is_temporary_alias) {
+ phar->alias = NULL;
+ phar->alias_len = 0;
+ } else {
+ phar->alias = estrndup(newpath, strlen(newpath));
+ phar->alias_len = strlen(newpath);
+ phar->is_temporary_alias = 1;
+ zend_hash_update(&(PHAR_GLOBALS->phar_alias_map), newpath, phar->fname_len, (void*)&phar, sizeof(phar_archive_data*), NULL);
+ }
+ }
+ } else {
+ if (SUCCESS != phar_detect_phar_fname_ext(newpath, phar->fname_len, (const char **) &(phar->ext), &(phar->ext_len), 0, 1, 1 TSRMLS_CC)) {
+ efree(oldpath);
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "data phar \"%s\" has invalid extension %s", phar->fname, ext);
+ return NULL;
+ }
+ phar->alias = NULL;
+ phar->alias_len = 0;
+ }
+
+ if (SUCCESS != zend_hash_add(&(PHAR_GLOBALS->phar_fname_map), newpath, phar->fname_len, (void*)&phar, sizeof(phar_archive_data*), NULL)) {
+ efree(oldpath);
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Unable to add newly converted phar \"%s\" to the list of phars", phar->fname);
+ return NULL;
+ }
+
+ phar_flush(phar, 0, 0, 1, &error TSRMLS_CC);
+ if (error) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, error);
+ efree(error);
+ efree(oldpath);
+ return NULL;
+ }
+
+ efree(oldpath);
+
+ if (phar->is_data) {
+ ce = phar_ce_data;
+ } else {
+ ce = phar_ce_archive;
+ }
+
+ MAKE_STD_ZVAL(ret);
+ if (SUCCESS != object_init_ex(ret, ce)) {
+ zval_dtor(ret);
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Unable to instantiate phar object when converting archive \"%s\"", phar->fname);
+ return NULL;
+ }
+ INIT_PZVAL(&arg1);
+ ZVAL_STRINGL(&arg1, phar->fname, phar->fname_len, 0);
+
+ zend_call_method_with_1_params(&ret, ce, &ce->constructor, "__construct", NULL, &arg1);
+
+ return ret;
+}
+
+static zval *phar_convert_to_other(phar_archive_data *source, int convert, char *ext, php_uint32 flags TSRMLS_DC) /* {{{ */
+{
+ phar_archive_data *phar;
+ phar_entry_info *entry, newentry;
+ zval *ret;
+
+ phar = (phar_archive_data *) ecalloc(1, sizeof(phar_archive_data));
+ /* set whole-archive compression and type from parameter */
+ phar->flags = flags;
+
+ phar->is_data = source->is_data;
+ switch (convert) {
+ case PHAR_FORMAT_TAR :
+ phar->is_tar = 1;
+ break;
+ case PHAR_FORMAT_ZIP :
+ phar->is_zip = 1;
+ break;
+ default :
+ phar->is_data = 0;
+ break;
+ }
+
+ zend_hash_init(&(phar->manifest), sizeof(phar_entry_info),
+ zend_get_hash_value, destroy_phar_manifest_entry, 0);
+
+ phar->fp = php_stream_fopen_tmpfile();
+ phar->fname = source->fname;
+ phar->fname_len = source->fname_len;
+ phar->is_temporary_alias = source->is_temporary_alias;
+ phar->alias = source->alias;
+ /* first copy each file's uncompressed contents to a temporary file and set per-file flags */
+ for (zend_hash_internal_pointer_reset(&source->manifest); SUCCESS == zend_hash_has_more_elements(&source->manifest); zend_hash_move_forward(&source->manifest)) {
+
+ if (FAILURE == zend_hash_get_current_data(&source->manifest, (void **) &entry)) {
+ zend_hash_destroy(&(phar->manifest));
+ php_stream_close(phar->fp);
+ efree(phar);
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
+ "Cannot convert phar archive \"%s\"", source->fname);
+ return NULL;
+ }
+ newentry = *entry;
+ if (newentry.link) {
+ newentry.link = estrdup(newentry.link);
+ goto no_copy;
+ }
+ if (newentry.tmp) {
+ newentry.tmp = estrdup(newentry.tmp);
+ goto no_copy;
+ }
+ if (FAILURE == phar_copy_file_contents(&newentry, phar->fp TSRMLS_CC)) {
+ zend_hash_destroy(&(phar->manifest));
+ php_stream_close(phar->fp);
+ efree(phar);
+ /* exception already thrown */
+ return NULL;
+ }
+no_copy:
+ newentry.filename = estrndup(newentry.filename, newentry.filename_len);
+ if (newentry.metadata) {
+ zval *t;
+
+ t = newentry.metadata;
+ ALLOC_ZVAL(newentry.metadata);
+ *newentry.metadata = *t;
+ zval_copy_ctor(newentry.metadata);
+#if PHP_VERSION_ID < 50300
+ newentry.metadata->refcount = 1;
+#else
+ Z_SET_REFCOUNT_P(newentry.metadata, 1);
+#endif
+
+ newentry.metadata_str.c = NULL;
+ newentry.metadata_str.len = 0;
+ }
+ newentry.is_zip = phar->is_zip;
+ newentry.is_tar = phar->is_tar;
+ if (newentry.is_tar) {
+ newentry.tar_type = (entry->is_dir ? TAR_DIR : TAR_FILE);
+ }
+ newentry.is_modified = 1;
+ newentry.phar = phar;
+ newentry.old_flags = newentry.flags & ~PHAR_ENT_COMPRESSION_MASK; /* remove compression from old_flags */
+ zend_hash_add(&(phar->manifest), newentry.filename, newentry.filename_len, (void*)&newentry, sizeof(phar_entry_info), NULL);
+ }
+
+ if ((ret = phar_rename_archive(phar, ext, 0 TSRMLS_CC))) {
+ return ret;
+ } else {
+ zend_hash_destroy(&(phar->manifest));
+ php_stream_close(phar->fp);
+ efree(phar->fname);
+ efree(phar);
+ return NULL;
+ }
+}
+/* }}} */
+
+/* {{{ proto object Phar::convertToExecutable([int format[, int compression [, string file_ext]]])
+ * Convert a phar.tar or phar.zip archive to the phar file format. The
+ * optional parameter allows the user to determine the new
+ * filename extension (default is phar).
+ */
+PHP_METHOD(Phar, convertToExecutable)
+{
+ char *ext = NULL;
+ int is_data, ext_len = 0;
+ php_uint32 flags;
+ zval *ret;
+ /* a number that is not 0, 1 or 2 (Which is also Greg's birthday, so there) */
+ long format = 9021976, method = 9021976;
+ PHAR_ARCHIVE_OBJECT();
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lls", &format, &method, &ext, &ext_len) == FAILURE) {
+ return;
+ }
+
+ if (PHAR_G(readonly)) {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
+ "Cannot write out executable phar archive, phar is read-only");
+ return;
+ }
+
+ switch (format) {
+ case 9021976:
+ case PHAR_FORMAT_SAME: /* null is converted to 0 */
+ /* by default, use the existing format */
+ if (phar_obj->arc.archive->is_tar) {
+ format = PHAR_FORMAT_TAR;
+ } else if (phar_obj->arc.archive->is_zip) {
+ format = PHAR_FORMAT_ZIP;
+ } else {
+ format = PHAR_FORMAT_PHAR;
+ }
+ break;
+ case PHAR_FORMAT_PHAR:
+ case PHAR_FORMAT_TAR:
+ case PHAR_FORMAT_ZIP:
+ break;
+ default:
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
+ "Unknown file format specified, please pass one of Phar::PHAR, Phar::TAR or Phar::ZIP");
+ return;
+ }
+
+ switch (method) {
+ case 9021976:
+ flags = phar_obj->arc.archive->flags & PHAR_FILE_COMPRESSION_MASK;
+ break;
+ case 0:
+ flags = PHAR_FILE_COMPRESSED_NONE;
+ break;
+ case PHAR_ENT_COMPRESSED_GZ:
+ if (format == PHAR_FORMAT_ZIP) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
+ "Cannot compress entire archive with gzip, zip archives do not support whole-archive compression");
+ return;
+ }
+ if (!phar_has_zlib) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
+ "Cannot compress entire archive with gzip, enable ext/zlib in php.ini");
+ return;
+ }
+ flags = PHAR_FILE_COMPRESSED_GZ;
+ break;
+
+ case PHAR_ENT_COMPRESSED_BZ2:
+ if (format == PHAR_FORMAT_ZIP) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
+ "Cannot compress entire archive with bz2, zip archives do not support whole-archive compression");
+ return;
+ }
+ if (!phar_has_bz2) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
+ "Cannot compress entire archive with bz2, enable ext/bz2 in php.ini");
+ return;
+ }
+ flags = PHAR_FILE_COMPRESSED_BZ2;
+ break;
+ default:
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
+ "Unknown compression specified, please pass one of Phar::GZ or Phar::BZ2");
+ return;
+ }
+
+ is_data = phar_obj->arc.archive->is_data;
+ phar_obj->arc.archive->is_data = 0;
+ ret = phar_convert_to_other(phar_obj->arc.archive, format, ext, flags TSRMLS_CC);
+ phar_obj->arc.archive->is_data = is_data;
+ if (ret) {
+ RETURN_ZVAL(ret, 1, 1);
+ } else {
+ RETURN_NULL();
+ }
+}
+/* }}} */
+
+/* {{{ proto object Phar::convertToData([int format[, int compression [, string file_ext]]])
+ * Convert an archive to a non-executable .tar or .zip.
+ * The optional parameter allows the user to determine the new
+ * filename extension (default is .zip or .tar).
+ */
+PHP_METHOD(Phar, convertToData)
+{
+ char *ext = NULL;
+ int is_data, ext_len = 0;
+ php_uint32 flags;
+ zval *ret;
+ /* a number that is not 0, 1 or 2 (Which is also Greg's birthday so there) */
+ long format = 9021976, method = 9021976;
+ PHAR_ARCHIVE_OBJECT();
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lls", &format, &method, &ext, &ext_len) == FAILURE) {
+ return;
+ }
+
+ switch (format) {
+ case 9021976:
+ case PHAR_FORMAT_SAME: /* null is converted to 0 */
+ /* by default, use the existing format */
+ if (phar_obj->arc.archive->is_tar) {
+ format = PHAR_FORMAT_TAR;
+ } else if (phar_obj->arc.archive->is_zip) {
+ format = PHAR_FORMAT_ZIP;
+ } else {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
+ "Cannot write out data phar archive, use Phar::TAR or Phar::ZIP");
+ return;
+ }
+ break;
+ case PHAR_FORMAT_PHAR:
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
+ "Cannot write out data phar archive, use Phar::TAR or Phar::ZIP");
+ return;
+ case PHAR_FORMAT_TAR:
+ case PHAR_FORMAT_ZIP:
+ break;
+ default:
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
+ "Unknown file format specified, please pass one of Phar::TAR or Phar::ZIP");
+ return;
+ }
+
+ switch (method) {
+ case 9021976:
+ flags = phar_obj->arc.archive->flags & PHAR_FILE_COMPRESSION_MASK;
+ break;
+ case 0:
+ flags = PHAR_FILE_COMPRESSED_NONE;
+ break;
+ case PHAR_ENT_COMPRESSED_GZ:
+ if (format == PHAR_FORMAT_ZIP) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
+ "Cannot compress entire archive with gzip, zip archives do not support whole-archive compression");
+ return;
+ }
+ if (!phar_has_zlib) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
+ "Cannot compress entire archive with gzip, enable ext/zlib in php.ini");
+ return;
+ }
+ flags = PHAR_FILE_COMPRESSED_GZ;
+ break;
+
+ case PHAR_ENT_COMPRESSED_BZ2:
+ if (format == PHAR_FORMAT_ZIP) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
+ "Cannot compress entire archive with bz2, zip archives do not support whole-archive compression");
+ return;
+ }
+ if (!phar_has_bz2) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
+ "Cannot compress entire archive with bz2, enable ext/bz2 in php.ini");
+ return;
+ }
+ flags = PHAR_FILE_COMPRESSED_BZ2;
+ break;
+ default:
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
+ "Unknown compression specified, please pass one of Phar::GZ or Phar::BZ2");
+ return;
+ }
+
+ is_data = phar_obj->arc.archive->is_data;
+ phar_obj->arc.archive->is_data = 1;
+ ret = phar_convert_to_other(phar_obj->arc.archive, format, ext, flags TSRMLS_CC);
+ phar_obj->arc.archive->is_data = is_data;
+ if (ret) {
+ RETURN_ZVAL(ret, 1, 1);
+ } else {
+ RETURN_NULL();
+ }
+}
+/* }}} */
+
+/* {{{ proto int|false Phar::isCompressed()
+ * Returns Phar::GZ or PHAR::BZ2 if the entire archive is compressed
+ * (.tar.gz/tar.bz2 and so on), or FALSE otherwise.
+ */
+PHP_METHOD(Phar, isCompressed)
+{
+ PHAR_ARCHIVE_OBJECT();
+
+ if (phar_obj->arc.archive->flags & PHAR_FILE_COMPRESSED_GZ) {
+ RETURN_LONG(PHAR_ENT_COMPRESSED_GZ);
+ }
+ if (phar_obj->arc.archive->flags & PHAR_FILE_COMPRESSED_BZ2) {
+ RETURN_LONG(PHAR_ENT_COMPRESSED_BZ2);
+ }
+ RETURN_FALSE;
+}
+/* }}} */
+
+/* {{{ proto bool Phar::isWritable()
+ * Returns true if phar.readonly=0 or phar is a PharData AND the actual file is writable.
+ */
+PHP_METHOD(Phar, isWritable)
+{
+ php_stream_statbuf ssb;
+ PHAR_ARCHIVE_OBJECT();
+
+ if (!phar_obj->arc.archive->is_writeable) {
+ RETURN_FALSE;
+ }
+ if (SUCCESS != php_stream_stat_path(phar_obj->arc.archive->fname, &ssb)) {
+ if (phar_obj->arc.archive->is_brandnew) {
+ /* assume it works if the file doesn't exist yet */
+ RETURN_TRUE;
+ }
+ RETURN_FALSE;
+ }
+ RETURN_BOOL((ssb.sb.st_mode & (S_IWOTH | S_IWGRP | S_IWUSR)) != 0);
+}
+/* }}} */
+
+/* {{{ proto bool Phar::delete(string entry)
+ * Deletes a named file within the archive.
+ */
+PHP_METHOD(Phar, delete)
+{
+ char *fname;
+ int fname_len;
+ char *error;
+ phar_entry_info *entry;
+ PHAR_ARCHIVE_OBJECT();
+
+ if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
+ "Cannot write out phar archive, phar is read-only");
+ return;
+ }
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &fname, &fname_len) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ if (zend_hash_exists(&phar_obj->arc.archive->manifest, fname, (uint) fname_len)) {
+ if (SUCCESS == zend_hash_find(&phar_obj->arc.archive->manifest, fname, (uint) fname_len, (void**)&entry)) {
+ if (entry->is_deleted) {
+ /* entry is deleted, but has not been flushed to disk yet */
+ RETURN_TRUE;
+ } else {
+ entry->is_deleted = 1;
+ entry->is_modified = 1;
+ phar_obj->arc.archive->is_modified = 1;
+ }
+ }
+ } else {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Entry %s does not exist and cannot be deleted", fname);
+ RETURN_FALSE;
+ }
+
+ phar_flush(phar_obj->arc.archive, NULL, 0, 0, &error TSRMLS_CC);
+ if (error) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
+ efree(error);
+ }
+
+ RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto int Phar::getAlias()
+ * Returns the alias for the Phar or NULL.
+ */
+PHP_METHOD(Phar, getAlias)
+{
+ PHAR_ARCHIVE_OBJECT();
+
+ if (phar_obj->arc.archive->alias && phar_obj->arc.archive->alias != phar_obj->arc.archive->fname) {
+ RETURN_STRINGL(phar_obj->arc.archive->alias, phar_obj->arc.archive->alias_len, 1);
+ }
+}
+/* }}} */
+
+/* {{{ proto int Phar::getPath()
+ * Returns the real path to the phar archive on disk
+ */
+PHP_METHOD(Phar, getPath)
+{
+ PHAR_ARCHIVE_OBJECT();
+
+ RETURN_STRINGL(phar_obj->arc.archive->fname, phar_obj->arc.archive->fname_len, 1);
+}
+/* }}} */
+
+/* {{{ proto bool Phar::setAlias(string alias)
+ * Sets the alias for a Phar archive. The default value is the full path
+ * to the archive.
+ */
+PHP_METHOD(Phar, setAlias)
+{
+ char *alias, *error, *oldalias;
+ phar_archive_data **fd_ptr;
+ int alias_len, oldalias_len, old_temp, readd = 0;
+ PHAR_ARCHIVE_OBJECT();
+
+ if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
+ "Cannot write out phar archive, phar is read-only");
+ RETURN_FALSE;
+ }
+
+ if (phar_obj->arc.archive->is_data) {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
+ "A Phar alias cannot be set in a plain %s archive", phar_obj->arc.archive->is_tar ? "tar" : "zip");
+ RETURN_FALSE;
+ }
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &alias, &alias_len) == SUCCESS) {
+ if (alias_len == phar_obj->arc.archive->alias_len && memcmp(phar_obj->arc.archive->alias, alias, alias_len) == 0) {
+ RETURN_TRUE;
+ }
+ if (alias_len && SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void**)&fd_ptr)) {
+ spprintf(&error, 0, "alias \"%s\" is already used for archive \"%s\" and cannot be used for other archives", alias, (*fd_ptr)->fname);
+ if (SUCCESS == phar_free_alias(*fd_ptr, alias, alias_len TSRMLS_CC)) {
+ efree(error);
+ goto valid_alias;
+ }
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
+ efree(error);
+ RETURN_FALSE;
+ }
+ if (!phar_validate_alias(alias, alias_len)) {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
+ "Invalid alias \"%s\" specified for phar \"%s\"", alias, phar_obj->arc.archive->fname);
+ RETURN_FALSE;
+ }
+valid_alias:
+ if (phar_obj->arc.archive->alias_len && SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), phar_obj->arc.archive->alias, phar_obj->arc.archive->alias_len, (void**)&fd_ptr)) {
+ zend_hash_del(&(PHAR_GLOBALS->phar_alias_map), phar_obj->arc.archive->alias, phar_obj->arc.archive->alias_len);
+ readd = 1;
+ }
+
+ oldalias = phar_obj->arc.archive->alias;
+ oldalias_len = phar_obj->arc.archive->alias_len;
+ old_temp = phar_obj->arc.archive->is_temporary_alias;
+ if (alias_len) {
+ phar_obj->arc.archive->alias = estrndup(alias, alias_len);
+ } else {
+ phar_obj->arc.archive->alias = NULL;
+ }
+ phar_obj->arc.archive->alias_len = alias_len;
+ phar_obj->arc.archive->is_temporary_alias = 0;
+
+ phar_flush(phar_obj->arc.archive, NULL, 0, 0, &error TSRMLS_CC);
+ if (error) {
+ phar_obj->arc.archive->alias = oldalias;
+ phar_obj->arc.archive->alias_len = oldalias_len;
+ phar_obj->arc.archive->is_temporary_alias = old_temp;
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
+ if (readd) {
+ zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), oldalias, oldalias_len, (void*)&(phar_obj->arc.archive), sizeof(phar_archive_data*), NULL);
+ }
+ efree(error);
+ RETURN_FALSE;
+ }
+ zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void*)&(phar_obj->arc.archive), sizeof(phar_archive_data*), NULL);
+ if (oldalias) {
+ efree(oldalias);
+ }
+ RETURN_TRUE;
+ }
+
+ RETURN_FALSE;
+}
+/* }}} */
+
+/* {{{ proto string Phar::getVersion()
+ * Return version info of Phar archive
+ */
+PHP_METHOD(Phar, getVersion)
+{
+ PHAR_ARCHIVE_OBJECT();
+
+ RETURN_STRING(phar_obj->arc.archive->version, 1);
+}
+/* }}} */
+
+/* {{{ proto void Phar::startBuffering()
+ * Do not flush a writeable phar (save its contents) until explicitly requested
+ */
+PHP_METHOD(Phar, startBuffering)
+{
+ PHAR_ARCHIVE_OBJECT();
+
+ phar_obj->arc.archive->donotflush = 1;
+}
+/* }}} */
+
+/* {{{ proto bool Phar::isBuffering()
+ * Returns whether write operations are flushing to disk immediately.
+ */
+PHP_METHOD(Phar, isBuffering)
+{
+ PHAR_ARCHIVE_OBJECT();
+
+ RETURN_BOOL(!phar_obj->arc.archive->donotflush);
+}
+/* }}} */
+
+/* {{{ proto bool Phar::stopBuffering()
+ * Saves the contents of a modified archive to disk.
+ */
+PHP_METHOD(Phar, stopBuffering)
+{
+ char *error;
+ PHAR_ARCHIVE_OBJECT();
+
+ if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
+ "Cannot write out phar archive, phar is read-only");
+ return;
+ }
+
+ phar_obj->arc.archive->donotflush = 0;
+
+ phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC);
+ if (error) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
+ efree(error);
+ }
+}
+/* }}} */
+
+/* {{{ proto bool Phar::setStub(string|stream stub [, int len])
+ * Change the stub in a phar, phar.tar or phar.zip archive to something other
+ * than the default. The stub *must* end with a call to __HALT_COMPILER().
+ */
+PHP_METHOD(Phar, setStub)
+{
+ zval *zstub;
+ char *stub, *error;
+ int stub_len;
+ long len = -1;
+ php_stream *stream;
+ PHAR_ARCHIVE_OBJECT();
+
+ if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
+ "Cannot change stub, phar is read-only");
+ return;
+ }
+
+ if (phar_obj->arc.archive->is_data) {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
+ "A Phar stub cannot be set in a plain %s archive", phar_obj->arc.archive->is_tar ? "tar" : "zip");
+ return;
+ }
+
+ if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &zstub, &len) == SUCCESS) {
+ if ((php_stream_from_zval_no_verify(stream, &zstub)) != NULL) {
+ if (len > 0) {
+ len = -len;
+ } else {
+ len = -1;
+ }
+ phar_flush(phar_obj->arc.archive, (char *) &zstub, len, 0, &error TSRMLS_CC);
+ if (error) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
+ efree(error);
+ }
+ RETURN_TRUE;
+ } else {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
+ "Cannot change stub, unable to read from input stream");
+ }
+ } else if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &stub, &stub_len) == SUCCESS) {
+ phar_flush(phar_obj->arc.archive, stub, stub_len, 0, &error TSRMLS_CC);
+ if (error) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
+ efree(error);
+ }
+ RETURN_TRUE;
+ }
+
+ RETURN_FALSE;
+}
+/* }}} */
+
+/* {{{ proto bool Phar::setDefaultStub([string index[, string webindex]])
+ * In a pure phar archive, sets a stub that can be used to run the archive
+ * regardless of whether the phar extension is available. The first parameter
+ * is the CLI startup filename, which defaults to "index.php". The second
+ * parameter is the web startup filename and also defaults to "index.php"
+ * (falling back to CLI behaviour).
+ * Both parameters are optional.
+ * In a phar.zip or phar.tar archive, the default stub is used only to
+ * identify the archive to the extension as a Phar object. This allows the
+ * extension to treat phar.zip and phar.tar types as honorary phars. Since
+ * files cannot be loaded via this kind of stub, no parameters are accepted
+ * when the Phar object is zip- or tar-based.
+ */
+ PHP_METHOD(Phar, setDefaultStub)
+{
+ char *index = NULL, *webindex = NULL, *error = NULL, *stub = NULL;
+ int index_len = 0, webindex_len = 0, created_stub = 0;
+ size_t stub_len = 0;
+ PHAR_ARCHIVE_OBJECT();
+
+ if (phar_obj->arc.archive->is_data) {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
+ "A Phar stub cannot be set in a plain %s archive", phar_obj->arc.archive->is_tar ? "tar" : "zip");
+ return;
+ }
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!s", &index, &index_len, &webindex, &webindex_len) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ if (ZEND_NUM_ARGS() > 0 && (phar_obj->arc.archive->is_tar || phar_obj->arc.archive->is_zip)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "method accepts no arguments for a tar- or zip-based phar stub, %d given", ZEND_NUM_ARGS());
+ RETURN_FALSE;
+ }
+
+ if (PHAR_G(readonly)) {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
+ "Cannot change stub: phar.readonly=1");
+ RETURN_FALSE;
+ }
+
+ if (!phar_obj->arc.archive->is_tar && !phar_obj->arc.archive->is_zip) {
+
+ stub = phar_create_default_stub(index, webindex, &stub_len, &error TSRMLS_CC);
+
+ if (error) {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, error);
+ efree(error);
+ if (stub) {
+ efree(stub);
+ }
+ RETURN_FALSE;
+ }
+ created_stub = 1;
+ }
+
+ phar_flush(phar_obj->arc.archive, stub, stub_len, 1, &error TSRMLS_CC);
+
+ if (created_stub) {
+ efree(stub);
+ }
+
+ if (error) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
+ efree(error);
+ RETURN_FALSE;
+ }
+
+ RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto array Phar::setSignatureAlgorithm(int sigtype)
+ * Sets the signature algorithm for a phar and applies it. The signature
+ * algorithm must be one of Phar::MD5, Phar::SHA1, Phar::SHA256,
+ * Phar::SHA512, or Phar::PGP (PGP is not yet supported and falls back to
+ * SHA-1). Note that zip- and tar- based phar archives cannot support
+ * signatures.
+ */
+PHP_METHOD(Phar, setSignatureAlgorithm)
+{
+ long algo;
+ char *error;
+ PHAR_ARCHIVE_OBJECT();
+
+ if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
+ "Cannot set signature algorithm, phar is read-only");
+ return;
+ }
+ if (phar_obj->arc.archive->is_tar) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
+ "Cannot set signature algorithm, not possible with tar-based phar archives");
+ return;
+ }
+ if (phar_obj->arc.archive->is_zip) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
+ "Cannot set signature algorithm, not possible with zip-based phar archives");
+ return;
+ }
+
+ if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "l", &algo) != SUCCESS) {
+ return;
+ }
+
+ switch (algo) {
+ case PHAR_SIG_SHA256 :
+ case PHAR_SIG_SHA512 :
+#if !HAVE_HASH_EXT
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
+ "SHA-256 and SHA-512 signatures are only supported if the hash extension is enabled");
+ return;
+#endif
+ case PHAR_SIG_MD5 :
+ case PHAR_SIG_SHA1 :
+ case PHAR_SIG_PGP :
+ phar_obj->arc.archive->sig_flags = algo;
+ phar_obj->arc.archive->is_modified = 1;
+
+ phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC);
+ if (error) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
+ efree(error);
+ }
+ break;
+ default :
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
+ "Unknown signature algorithm specified");
+ }
+}
+/* }}} */
+
+/* {{{ proto array|false Phar::getSignature()
+ * Returns a hash signature, or FALSE if the archive is unsigned.
+ */
+PHP_METHOD(Phar, getSignature)
+{
+ PHAR_ARCHIVE_OBJECT();
+
+ if (phar_obj->arc.archive->signature) {
+ array_init(return_value);
+ add_assoc_stringl(return_value, "hash", phar_obj->arc.archive->signature, phar_obj->arc.archive->sig_len, 1);
+ switch(phar_obj->arc.archive->sig_flags) {
+ case PHAR_SIG_MD5:
+ add_assoc_stringl(return_value, "hash_type", "MD5", 3, 1);
+ break;
+ case PHAR_SIG_SHA1:
+ add_assoc_stringl(return_value, "hash_type", "SHA-1", 5, 1);
+ break;
+ case PHAR_SIG_SHA256:
+ add_assoc_stringl(return_value, "hash_type", "SHA-256", 7, 1);
+ break;
+ case PHAR_SIG_SHA512:
+ add_assoc_stringl(return_value, "hash_type", "SHA-512", 7, 1);
+ break;
+ }
+ } else {
+ RETURN_FALSE;
+ }
+}
+/* }}} */
+
+/* {{{ proto bool Phar::getModified()
+ * Return whether phar was modified
+ */
+PHP_METHOD(Phar, getModified)
+{
+ PHAR_ARCHIVE_OBJECT();
+
+ RETURN_BOOL(phar_obj->arc.archive->is_modified);
+}
+/* }}} */
+
+static int phar_set_compression(void *pDest, void *argument TSRMLS_DC) /* {{{ */
+{
+ phar_entry_info *entry = (phar_entry_info *)pDest;
+ php_uint32 compress = *(php_uint32 *)argument;
+
+ if (entry->is_deleted) {
+ return ZEND_HASH_APPLY_KEEP;
+ }
+ entry->old_flags = entry->flags;
+ entry->flags &= ~PHAR_ENT_COMPRESSION_MASK;
+ entry->flags |= compress;
+ entry->is_modified = 1;
+ return ZEND_HASH_APPLY_KEEP;
+}
+/* }}} */
+
+static int phar_test_compression(void *pDest, void *argument TSRMLS_DC) /* {{{ */
+{
+ phar_entry_info *entry = (phar_entry_info *)pDest;
+
+ if (entry->is_deleted) {
+ return ZEND_HASH_APPLY_KEEP;
+ }
+ if (!phar_has_bz2) {
+ if (entry->flags & PHAR_ENT_COMPRESSED_BZ2) {
+ *(int *) argument = 0;
+ }
+ }
+ if (!phar_has_zlib) {
+ if (entry->flags & PHAR_ENT_COMPRESSED_GZ) {
+ *(int *) argument = 0;
+ }
+ }
+ return ZEND_HASH_APPLY_KEEP;
+}
+/* }}} */
+
+static void pharobj_set_compression(HashTable *manifest, php_uint32 compress TSRMLS_DC) /* {{{ */
+{
+ zend_hash_apply_with_argument(manifest, phar_set_compression, &compress TSRMLS_CC);
+}
+/* }}} */
+
+static int pharobj_cancompress(HashTable *manifest TSRMLS_DC) /* {{{ */
+{
+ int test;
+ test = 1;
+ zend_hash_apply_with_argument(manifest, phar_test_compression, &test TSRMLS_CC);
+ return test;
+}
+/* }}} */
+
+/* {{{ proto object Phar::compress(int method[, string extension])
+ * Compress a .tar, or .phar.tar with whole-file compression
+ * The parameter can be one of Phar::GZ or Phar::BZ2 to specify
+ * the kind of compression desired
+ */
+PHP_METHOD(Phar, compress)
+{
+ long method;
+ char *ext = NULL;
+ int ext_len = 0;
+ php_uint32 flags;
+ zval *ret;
+ PHAR_ARCHIVE_OBJECT();
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|s", &method, &ext, &ext_len) == FAILURE) {
+ return;
+ }
+
+ if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
+ "Cannot compress phar archive, phar is read-only");
+ return;
+ }
+
+ if (phar_obj->arc.archive->is_zip) {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
+ "Cannot compress zip-based archives with whole-archive compression");
+ return;
+ }
+
+ switch (method) {
+ case 0:
+ flags = PHAR_FILE_COMPRESSED_NONE;
+ break;
+ case PHAR_ENT_COMPRESSED_GZ:
+ if (!phar_has_zlib) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
+ "Cannot compress entire archive with gzip, enable ext/zlib in php.ini");
+ return;
+ }
+ flags = PHAR_FILE_COMPRESSED_GZ;
+ break;
+
+ case PHAR_ENT_COMPRESSED_BZ2:
+ if (!phar_has_bz2) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
+ "Cannot compress entire archive with bz2, enable ext/bz2 in php.ini");
+ return;
+ }
+ flags = PHAR_FILE_COMPRESSED_BZ2;
+ break;
+ default:
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
+ "Unknown compression specified, please pass one of Phar::GZ or Phar::BZ2");
+ return;
+ }
+
+ if (phar_obj->arc.archive->is_tar) {
+ ret = phar_convert_to_other(phar_obj->arc.archive, PHAR_FORMAT_TAR, ext, flags TSRMLS_CC);
+ } else {
+ ret = phar_convert_to_other(phar_obj->arc.archive, PHAR_FORMAT_PHAR, ext, flags TSRMLS_CC);
+ }
+ if (ret) {
+ RETURN_ZVAL(ret, 1, 1);
+ } else {
+ RETURN_NULL();
+ }
+}
+/* }}} */
+
+/* {{{ proto object Phar::decompress([string extension])
+ * Decompress a .tar, or .phar.tar with whole-file compression
+ */
+PHP_METHOD(Phar, decompress)
+{
+ char *ext = NULL;
+ int ext_len = 0;
+ zval *ret;
+ PHAR_ARCHIVE_OBJECT();
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &ext, &ext_len) == FAILURE) {
+ return;
+ }
+
+ if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
+ "Cannot decompress phar archive, phar is read-only");
+ return;
+ }
+
+ if (phar_obj->arc.archive->is_zip) {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
+ "Cannot decompress zip-based archives with whole-archive compression");
+ return;
+ }
+
+ if (phar_obj->arc.archive->is_tar) {
+ ret = phar_convert_to_other(phar_obj->arc.archive, PHAR_FORMAT_TAR, ext, PHAR_FILE_COMPRESSED_NONE TSRMLS_CC);
+ } else {
+ ret = phar_convert_to_other(phar_obj->arc.archive, PHAR_FORMAT_PHAR, ext, PHAR_FILE_COMPRESSED_NONE TSRMLS_CC);
+ }
+ if (ret) {
+ RETURN_ZVAL(ret, 1, 1);
+ } else {
+ RETURN_NULL();
+ }
+}
+/* }}} */
+
+/* {{{ proto object Phar::compressFiles(int method)
+ * Compress all files within a phar or zip archive using the specified compression
+ * The parameter can be one of Phar::GZ or Phar::BZ2 to specify
+ * the kind of compression desired
+ */
+PHP_METHOD(Phar, compressFiles)
+{
+ char *error;
+ php_uint32 flags;
+ long method;
+ PHAR_ARCHIVE_OBJECT();
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &method) == FAILURE) {
+ return;
+ }
+
+ if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
+ "Phar is readonly, cannot change compression");
+ return;
+ }
+
+ switch (method) {
+ case PHAR_ENT_COMPRESSED_GZ:
+ if (!phar_has_zlib) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
+ "Cannot compress files within archive with gzip, enable ext/zlib in php.ini");
+ return;
+ }
+ flags = PHAR_ENT_COMPRESSED_GZ;
+ break;
+
+ case PHAR_ENT_COMPRESSED_BZ2:
+ if (!phar_has_bz2) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
+ "Cannot compress files within archive with bz2, enable ext/bz2 in php.ini");
+ return;
+ }
+ flags = PHAR_ENT_COMPRESSED_BZ2;
+ break;
+ default:
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
+ "Unknown compression specified, please pass one of Phar::GZ or Phar::BZ2");
+ return;
+ }
+ if (phar_obj->arc.archive->is_tar) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
+ "Cannot compress with Gzip compression, tar archives cannot compress individual files, use compress() to compress the whole archive");
+ return;
+ }
+ if (!pharobj_cancompress(&phar_obj->arc.archive->manifest TSRMLS_CC)) {
+ if (flags == PHAR_FILE_COMPRESSED_GZ) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
+ "Cannot compress all files as Gzip, some are compressed as bzip2 and cannot be decompressed");
+ } else {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
+ "Cannot compress all files as Bzip2, some are compressed as gzip and cannot be decompressed");
+ }
+ return;
+ }
+ pharobj_set_compression(&phar_obj->arc.archive->manifest, flags TSRMLS_CC);
+
+ phar_obj->arc.archive->is_modified = 1;
+
+ phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC);
+ if (error) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, error);
+ efree(error);
+ }
+}
+/* }}} */
+
+/* {{{ proto bool Phar::decompressFiles()
+ * decompress every file
+ */
+PHP_METHOD(Phar, decompressFiles)
+{
+ char *error;
+ PHAR_ARCHIVE_OBJECT();
+
+ if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
+ "Phar is readonly, cannot change compression");
+ return;
+ }
+ if (!pharobj_cancompress(&phar_obj->arc.archive->manifest TSRMLS_CC)) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
+ "Cannot decompress all files, some are compressed as bzip2 or gzip and cannot be decompressed");
+ return;
+ }
+ if (phar_obj->arc.archive->is_tar) {
+ RETURN_TRUE;
+ } else {
+ pharobj_set_compression(&phar_obj->arc.archive->manifest, PHAR_ENT_COMPRESSED_NONE TSRMLS_CC);
+ }
+
+ phar_obj->arc.archive->is_modified = 1;
+
+ phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC);
+ if (error) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, error);
+ efree(error);
+ }
+ RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto bool Phar::copy(string oldfile, string newfile)
+ * copy a file internal to the phar archive to another new file within the phar
+ */
+PHP_METHOD(Phar, copy)
+{
+ char *oldfile, *newfile, *error;
+ const char *pcr_error;
+ int oldfile_len, newfile_len;
+ phar_entry_info *oldentry, newentry = {0}, *temp;
+ PHAR_ARCHIVE_OBJECT();
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &oldfile, &oldfile_len, &newfile, &newfile_len) == FAILURE) {
+ return;
+ }
+
+ if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
+ "Cannot copy \"%s\" to \"%s\", phar is read-only", oldfile, newfile);
+ RETURN_FALSE;
+ }
+
+ if (!zend_hash_exists(&phar_obj->arc.archive->manifest, oldfile, (uint) oldfile_len) || SUCCESS != zend_hash_find(&phar_obj->arc.archive->manifest, oldfile, (uint) oldfile_len, (void**)&oldentry) || oldentry->is_deleted) {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
+ "file \"%s\" cannot be copied to file \"%s\", file does not exist in %s", oldfile, newfile, phar_obj->arc.archive->fname);
+ RETURN_FALSE;
+ }
+
+ if (zend_hash_exists(&phar_obj->arc.archive->manifest, newfile, (uint) newfile_len)) {
+ if (SUCCESS == zend_hash_find(&phar_obj->arc.archive->manifest, newfile, (uint) newfile_len, (void**)&temp) || !temp->is_deleted) {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
+ "file \"%s\" cannot be copied to file \"%s\", file must not already exist in phar %s", oldfile, newfile, phar_obj->arc.archive->fname);
+ RETURN_FALSE;
+ }
+ }
+
+ if (phar_path_check(&newfile, &newfile_len, &pcr_error) > pcr_is_ok) {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
+ "file \"%s\" contains invalid characters %s, cannot be copied from \"%s\" in phar %s", newfile, pcr_error, oldfile, phar_obj->arc.archive->fname);
+ RETURN_FALSE;
+ }
+
+ memcpy((void *) &newentry, oldentry, sizeof(phar_entry_info));
+ if (newentry.metadata) {
+ zval *t;
+
+ t = newentry.metadata;
+ ALLOC_ZVAL(newentry.metadata);
+ *newentry.metadata = *t;
+ zval_copy_ctor(newentry.metadata);
+#if PHP_VERSION_ID < 50300
+ newentry.metadata->refcount = 1;
+#else
+ Z_SET_REFCOUNT_P(newentry.metadata, 1);
+#endif
+
+ newentry.metadata_str.c = NULL;
+ newentry.metadata_str.len = 0;
+ }
+ newentry.filename = estrndup(newfile, newfile_len);
+ newentry.filename_len = newfile_len;
+ newentry.fp_refcount = 0;
+
+ if (oldentry->fp_type != PHAR_FP) {
+ if (FAILURE == phar_copy_entry_fp(oldentry, &newentry, &error TSRMLS_CC)) {
+ efree(newentry.filename);
+ php_stream_close(newentry.fp);
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
+ efree(error);
+ return;
+ }
+ }
+
+ zend_hash_add(&oldentry->phar->manifest, newfile, newfile_len, (void*)&newentry, sizeof(phar_entry_info), NULL);
+ phar_obj->arc.archive->is_modified = 1;
+
+ phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC);
+ if (error) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
+ efree(error);
+ }
+
+ RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto int Phar::offsetExists(string entry)
+ * determines whether a file exists in the phar
+ */
+PHP_METHOD(Phar, offsetExists)
+{
+ char *fname;
+ int fname_len;
+ phar_entry_info *entry;
+ PHAR_ARCHIVE_OBJECT();
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &fname, &fname_len) == FAILURE) {
+ return;
+ }
+
+ if (zend_hash_exists(&phar_obj->arc.archive->manifest, fname, (uint) fname_len)) {
+ if (SUCCESS == zend_hash_find(&phar_obj->arc.archive->manifest, fname, (uint) fname_len, (void**)&entry)) {
+ if (entry->is_deleted) {
+ /* entry is deleted, but has not been flushed to disk yet */
+ RETURN_FALSE;
+ }
+ }
+ RETURN_TRUE;
+ } else {
+ RETURN_FALSE;
+ }
+}
+/* }}} */
+
+/* {{{ proto int Phar::offsetGet(string entry)
+ * get a PharFileInfo object for a specific file
+ */
+PHP_METHOD(Phar, offsetGet)
+{
+ char *fname, *error;
+ int fname_len;
+ zval *zfname;
+ phar_entry_info *entry;
+ PHAR_ARCHIVE_OBJECT();
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &fname, &fname_len) == FAILURE) {
+ return;
+ }
+
+ if (!(entry = phar_get_entry_info_dir(phar_obj->arc.archive, fname, fname_len, 1, &error TSRMLS_CC))) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Entry %s does not exist%s%s", fname, error?", ":"", error?error:"");
+ } else {
+ if (entry->is_temp_dir) {
+ efree(entry->filename);
+ efree(entry);
+ }
+ fname_len = spprintf(&fname, 0, "phar://%s/%s", phar_obj->arc.archive->fname, fname);
+ MAKE_STD_ZVAL(zfname);
+ ZVAL_STRINGL(zfname, fname, fname_len, 0);
+ spl_instantiate_arg_ex1(phar_obj->spl.info_class, &return_value, 0, zfname TSRMLS_CC);
+ zval_ptr_dtor(&zfname);
+ }
+
+}
+/* }}} */
+
+/* {{{ add a file within the phar archive from a string or resource
+ */
+static void phar_add_file(phar_archive_data *phar, char *filename, int filename_len, char *cont_str, int cont_len, zval *zresource TSRMLS_DC)
+{
+ char *error;
+ long contents_len;
+ phar_entry_data *data;
+ php_stream *contents_file;
+
+ if (!(data = phar_get_or_create_entry_data(phar->fname, phar->fname_len, filename, filename_len, "w+b", 0, &error TSRMLS_CC))) {
+ if (error) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Entry %s does not exist and cannot be created: %s", filename, error);
+ efree(error);
+ } else {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Entry %s does not exist and cannot be created", filename);
+ }
+ return;
+ } else {
+ if (error) {
+ efree(error);
+ }
+ if (!data->internal_file->is_dir) {
+ if (cont_str) {
+ contents_len = php_stream_write(data->fp, cont_str, cont_len);
+ if (contents_len != cont_len) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Entry %s could not be written to", filename);
+ return;
+ }
+ } else {
+ if (!(php_stream_from_zval_no_verify(contents_file, &zresource))) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Entry %s could not be written to", filename);
+ return;
+ }
+ contents_len = php_stream_copy_to_stream(contents_file, data->fp, PHP_STREAM_COPY_ALL);
+ }
+ data->internal_file->compressed_filesize = data->internal_file->uncompressed_filesize = contents_len;
+ }
+ phar_entry_delref(data TSRMLS_CC);
+ phar_flush(phar, 0, 0, 0, &error TSRMLS_CC);
+ if (error) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
+ efree(error);
+ }
+ }
+}
+/* }}} */
+
+/* {{{ create a directory within the phar archive
+ */
+static void phar_mkdir(phar_archive_data *phar, char *dirname, int dirname_len TSRMLS_DC)
+{
+ char *error;
+ phar_entry_data *data;
+
+ if (!(data = phar_get_or_create_entry_data(phar->fname, phar->fname_len, dirname, dirname_len, "w+b", 2, &error TSRMLS_CC))) {
+ if (error) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Directory %s does not exist and cannot be created: %s", dirname, error);
+ efree(error);
+ } else {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Directory %s does not exist and cannot be created", dirname);
+ }
+ return;
+ } else {
+ if (error) {
+ efree(error);
+ }
+ phar_entry_delref(data TSRMLS_CC);
+ phar_flush(phar, 0, 0, 0, &error TSRMLS_CC);
+ if (error) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
+ efree(error);
+ }
+ }
+}
+/* }}} */
+
+
+/* {{{ proto int Phar::offsetSet(string entry, string value)
+ * set the contents of an internal file to those of an external file
+ */
+PHP_METHOD(Phar, offsetSet)
+{
+ char *fname, *cont_str = NULL;
+ int fname_len, cont_len;
+ zval *zresource;
+ PHAR_ARCHIVE_OBJECT();
+
+ if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Write operations disabled by INI setting");
+ return;
+ }
+
+ if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "sr", &fname, &fname_len, &zresource) == FAILURE
+ && zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &fname, &fname_len, &cont_str, &cont_len) == FAILURE) {
+ return;
+ }
+
+ if ((phar_obj->arc.archive->is_tar || phar_obj->arc.archive->is_zip) && fname_len == sizeof(".phar/stub.php")-1 && !memcmp(fname, ".phar/stub.php", sizeof(".phar/stub.php")-1)) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Cannot set stub \".phar/stub.php\" directly in phar \"%s\", use setStub", phar_obj->arc.archive->fname);
+ return;
+ }
+
+ if ((phar_obj->arc.archive->is_tar || phar_obj->arc.archive->is_zip) && fname_len == sizeof(".phar/alias.txt")-1 && !memcmp(fname, ".phar/alias.txt", sizeof(".phar/alias.txt")-1)) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Cannot set alias \".phar/alias.txt\" directly in phar \"%s\", use setAlias", phar_obj->arc.archive->fname);
+ return;
+ }
+ phar_add_file(phar_obj->arc.archive, fname, fname_len, cont_str, cont_len, zresource TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ proto int Phar::offsetUnset(string entry)
+ * remove a file from a phar
+ */
+PHP_METHOD(Phar, offsetUnset)
+{
+ char *fname, *error;
+ int fname_len;
+ phar_entry_info *entry;
+ PHAR_ARCHIVE_OBJECT();
+
+ if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Write operations disabled by INI setting");
+ return;
+ }
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &fname, &fname_len) == FAILURE) {
+ return;
+ }
+
+ if (zend_hash_exists(&phar_obj->arc.archive->manifest, fname, (uint) fname_len)) {
+ if (SUCCESS == zend_hash_find(&phar_obj->arc.archive->manifest, fname, (uint) fname_len, (void**)&entry)) {
+ if (entry->is_deleted) {
+ /* entry is deleted, but has not been flushed to disk yet */
+ return;
+ }
+ entry->is_modified = 0;
+ entry->is_deleted = 1;
+ /* we need to "flush" the stream to save the newly deleted file on disk */
+ phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC);
+ if (error) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
+ efree(error);
+ }
+ RETURN_TRUE;
+ }
+ } else {
+ RETURN_FALSE;
+ }
+}
+/* }}} */
+
+/* {{{ proto string Phar::addEmptyDir(string dirname)
+ * Adds an empty directory to the phar archive
+ */
+PHP_METHOD(Phar, addEmptyDir)
+{
+ char *dirname;
+ int dirname_len;
+ PHAR_ARCHIVE_OBJECT();
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &dirname, &dirname_len) == FAILURE) {
+ return;
+ }
+
+ phar_mkdir(phar_obj->arc.archive, dirname, dirname_len TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ proto string Phar::addFile(string filename[, string localname])
+ * Adds a file to the archive using the filename, or the second parameter as the name within the archive
+ */
+PHP_METHOD(Phar, addFile)
+{
+ char *fname, *localname = NULL;
+ int fname_len, localname_len = 0;
+ php_stream *resource;
+ zval *zresource;
+ PHAR_ARCHIVE_OBJECT();
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &fname, &fname_len, &localname, &localname_len) == FAILURE) {
+ return;
+ }
+
+#if PHP_MAJOR_VERSION < 6
+ if (PG(safe_mode) && (!php_checkuid(fname, NULL, CHECKUID_ALLOW_ONLY_FILE))) {
+ zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "phar error: unable to open file \"%s\" to add to phar archive, safe_mode restrictions prevent this", fname);
+ return;
+ }
+#endif
+
+ if (!strstr(fname, "://") && php_check_open_basedir(fname TSRMLS_CC)) {
+ zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "phar error: unable to open file \"%s\" to add to phar archive, open_basedir restrictions prevent this", fname);
+ return;
+ }
+
+ if (!(resource = php_stream_open_wrapper(fname, "rb", 0, NULL))) {
+ zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "phar error: unable to open file \"%s\" to add to phar archive", fname);
+ return;
+ }
+ if (localname) {
+ fname = localname;
+ fname_len = localname_len;
+ }
+
+ MAKE_STD_ZVAL(zresource);
+ php_stream_to_zval(resource, zresource);
+ phar_add_file(phar_obj->arc.archive, fname, fname_len, NULL, 0, zresource TSRMLS_CC);
+ efree(zresource);
+ php_stream_close(resource);
+}
+/* }}} */
+
+/* {{{ proto string Phar::addFromString(string localname, string contents)
+ * Adds a file to the archive using its contents as a string
+ */
+PHP_METHOD(Phar, addFromString)
+{
+ char *localname, *cont_str;
+ int localname_len, cont_len;
+ PHAR_ARCHIVE_OBJECT();
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &localname, &localname_len, &cont_str, &cont_len) == FAILURE) {
+ return;
+ }
+
+ phar_add_file(phar_obj->arc.archive, localname, localname_len, cont_str, cont_len, NULL TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ proto string Phar::getStub()
+ * Returns the stub at the head of a phar archive as a string.
+ */
+PHP_METHOD(Phar, getStub)
+{
+ size_t len;
+ char *buf;
+ php_stream *fp;
+ php_stream_filter *filter = NULL;
+ phar_entry_info *stub;
+ PHAR_ARCHIVE_OBJECT();
+
+ if (phar_obj->arc.archive->is_tar || phar_obj->arc.archive->is_zip) {
+
+ if (SUCCESS == zend_hash_find(&(phar_obj->arc.archive->manifest), ".phar/stub.php", sizeof(".phar/stub.php")-1, (void **)&stub)) {
+ if (phar_obj->arc.archive->fp && !phar_obj->arc.archive->is_brandnew && !(stub->flags & PHAR_ENT_COMPRESSION_MASK)) {
+ fp = phar_obj->arc.archive->fp;
+ } else {
+ fp = php_stream_open_wrapper(phar_obj->arc.archive->fname, "rb", 0, NULL);
+ if (stub->flags & PHAR_ENT_COMPRESSION_MASK) {
+ char *filter_name;
+
+ if ((filter_name = phar_decompress_filter(stub, 0)) != NULL) {
+ filter = php_stream_filter_create(phar_decompress_filter(stub, 0), NULL, php_stream_is_persistent(fp) TSRMLS_CC);
+ } else {
+ filter = NULL;
+ }
+ if (!filter) {
+ zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "phar error: unable to read stub of phar \"%s\" (cannot create %s filter)", phar_obj->arc.archive->fname, phar_decompress_filter(stub, 1));
+ return;
+ }
+ php_stream_filter_append(&fp->readfilters, filter);
+ }
+ }
+
+ if (!fp) {
+ zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC,
+ "Unable to read stub");
+ return;
+ }
+
+ php_stream_seek(fp, stub->offset_abs, SEEK_SET);
+ len = stub->uncompressed_filesize;
+ goto carry_on;
+ } else {
+ RETURN_STRINGL("", 0, 1);
+ }
+ }
+ len = phar_obj->arc.archive->halt_offset;
+
+ if (phar_obj->arc.archive->fp && !phar_obj->arc.archive->is_brandnew) {
+ fp = phar_obj->arc.archive->fp;
+ } else {
+ fp = php_stream_open_wrapper(phar_obj->arc.archive->fname, "rb", 0, NULL);
+ }
+
+ if (!fp) {
+ zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC,
+ "Unable to read stub");
+ return;
+ }
+
+ php_stream_rewind(fp);
+carry_on:
+ buf = safe_emalloc(len, 1, 1);
+ if (len != php_stream_read(fp, buf, len)) {
+ if (fp != phar_obj->arc.archive->fp) {
+ php_stream_close(fp);
+ }
+ zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC,
+ "Unable to read stub");
+ efree(buf);
+ return;
+ }
+ if (filter) {
+ php_stream_filter_flush(filter, 1);
+ php_stream_filter_remove(filter, 1 TSRMLS_CC);
+ }
+ if (fp != phar_obj->arc.archive->fp) {
+ php_stream_close(fp);
+ }
+ buf[len] = '\0';
+
+ RETURN_STRINGL(buf, len, 0);
+}
+/* }}}*/
+
+/* {{{ proto int Phar::hasMetaData()
+ * Returns TRUE if the phar has global metadata, FALSE otherwise.
+ */
+PHP_METHOD(Phar, hasMetadata)
+{
+ PHAR_ARCHIVE_OBJECT();
+
+ RETURN_BOOL(phar_obj->arc.archive->metadata != NULL);
+}
+/* }}} */
+
+/* {{{ proto int Phar::getMetaData()
+ * Returns the global metadata of the phar
+ */
+PHP_METHOD(Phar, getMetadata)
+{
+ PHAR_ARCHIVE_OBJECT();
+
+ if (phar_obj->arc.archive->metadata) {
+ RETURN_ZVAL(phar_obj->arc.archive->metadata, 1, 0);
+ }
+}
+/* }}} */
+
+/* {{{ proto int Phar::setMetaData(mixed $metadata)
+ * Sets the global metadata of the phar
+ */
+PHP_METHOD(Phar, setMetadata)
+{
+ char *error;
+ zval *metadata;
+ PHAR_ARCHIVE_OBJECT();
+
+ if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Write operations disabled by INI setting");
+ return;
+ }
+ if (phar_obj->arc.archive->is_tar) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
+ "Cannot set metadata, not possible with tar-based phar archives");
+ return;
+ }
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &metadata) == FAILURE) {
+ return;
+ }
+
+ if (phar_obj->arc.archive->metadata) {
+ zval_ptr_dtor(&phar_obj->arc.archive->metadata);
+ phar_obj->arc.archive->metadata = NULL;
+ }
+
+ MAKE_STD_ZVAL(phar_obj->arc.archive->metadata);
+ ZVAL_ZVAL(phar_obj->arc.archive->metadata, metadata, 1, 0);
+
+ phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC);
+ if (error) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
+ efree(error);
+ }
+}
+/* }}} */
+
+/* {{{ proto int Phar::delMetadata()
+ * Deletes the global metadata of the phar
+ */
+PHP_METHOD(Phar, delMetadata)
+{
+ char *error;
+ PHAR_ARCHIVE_OBJECT();
+
+ if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Write operations disabled by INI setting");
+ return;
+ }
+ if (phar_obj->arc.archive->is_tar) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
+ "Cannot delete metadata, not possible with tar-based phar archives");
+ return;
+ }
+ if (phar_obj->arc.archive->metadata) {
+ zval_ptr_dtor(&phar_obj->arc.archive->metadata);
+ phar_obj->arc.archive->metadata = NULL;
+
+ phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC);
+ if (error) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
+ efree(error);
+ RETURN_FALSE;
+ } else {
+ RETURN_TRUE;
+ }
+ } else {
+ RETURN_TRUE;
+ }
+}
+/* }}} */
+#if (PHP_MAJOR_VERSION < 6)
+#define OPENBASEDIR_CHECKPATH(filename) \
+ (PG(safe_mode) && (!php_checkuid(filename, NULL, CHECKUID_CHECK_FILE_AND_DIR))) || php_check_open_basedir(filename TSRMLS_CC)
+#else
+#define OPENBASEDIR_CHECKPATH(filename) \
+ php_check_open_basedir(filename TSRMLS_CC)
+#endif
+
+static int phar_extract_file(zend_bool overwrite, phar_entry_info *entry, char *dest, int dest_len, char **error TSRMLS_DC)
+{
+ php_stream_statbuf ssb;
+ int len;
+ php_stream *fp;
+ char *fullpath, *slash;
+ mode_t mode;
+
+ if (entry->is_mounted) {
+ /* silently ignore mounted entries */
+ return SUCCESS;
+ }
+ len = spprintf(&fullpath, 0, "%s/%s", dest, entry->filename);
+ if (len >= MAXPATHLEN) {
+ char *tmp;
+ /* truncate for error message */
+ fullpath[50] = '\0';
+ if (entry->filename_len > 50) {
+ tmp = estrndup(entry->filename, 50);
+ spprintf(error, 4096, "Cannot extract \"%s...\" to \"%s...\", extracted filename is too long for filesystem", tmp, fullpath);
+ efree(tmp);
+ } else {
+ spprintf(error, 4096, "Cannot extract \"%s\" to \"%s...\", extracted filename is too long for filesystem", entry->filename, fullpath);
+ }
+ efree(fullpath);
+ return FAILURE;
+ }
+ if (!len) {
+ spprintf(error, 4096, "Cannot extract \"%s\", internal error", entry->filename);
+ efree(fullpath);
+ return FAILURE;
+ }
+
+ if (OPENBASEDIR_CHECKPATH(fullpath)) {
+ spprintf(error, 4096, "Cannot extract \"%s\" to \"%s\", openbasedir/safe mode restrictions in effect", entry->filename, fullpath);
+ efree(fullpath);
+ return FAILURE;
+ }
+
+ /* let see if the path already exists */
+ if (!overwrite && SUCCESS == php_stream_stat_path(fullpath, &ssb)) {
+ spprintf(error, 4096, "Cannot extract \"%s\" to \"%s\", path already exists", entry->filename, fullpath);
+ efree(fullpath);
+ return FAILURE;
+ }
+ /* perform dirname */
+ slash = strrchr(entry->filename, '/');
+ if (slash) {
+ fullpath[dest_len + (slash - entry->filename) + 1] = '\0';
+ } else {
+ fullpath[dest_len] = '\0';
+ }
+ if (FAILURE == php_stream_stat_path(fullpath, &ssb)) {
+ if (entry->is_dir) {
+ if (!php_stream_mkdir(fullpath, entry->flags & PHAR_ENT_PERM_MASK, PHP_STREAM_MKDIR_RECURSIVE, NULL)) {
+ spprintf(error, 4096, "Cannot extract \"%s\", could not create directory \"%s\"", entry->filename, fullpath);
+ efree(fullpath);
+ return FAILURE;
+ }
+ } else {
+ if (!php_stream_mkdir(fullpath, 0777, PHP_STREAM_MKDIR_RECURSIVE, NULL)) {
+ spprintf(error, 4096, "Cannot extract \"%s\", could not create directory \"%s\"", entry->filename, fullpath);
+ efree(fullpath);
+ return FAILURE;
+ }
+ }
+ }
+ if (slash) {
+ fullpath[dest_len + (slash - entry->filename) + 1] = '/';
+ } else {
+ fullpath[dest_len] = '/';
+ }
+
+ /* it is a standalone directory, job done */
+ if (entry->is_dir) {
+ efree(fullpath);
+ return SUCCESS;
+ }
+
+ fp = php_stream_open_wrapper(fullpath, "w+b", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL);
+
+ if (!fp) {
+ spprintf(error, 4096, "Cannot extract \"%s\", could not open for writing \"%s\"", entry->filename, fullpath);
+ efree(fullpath);
+ return FAILURE;
+ }
+
+ if (!phar_get_efp(entry, 0 TSRMLS_CC)) {
+ if (FAILURE == phar_open_entry_fp(entry, error, 1 TSRMLS_CC)) {
+ if (error) {
+ spprintf(error, 4096, "Cannot extract \"%s\" to \"%s\", unable to open internal file pointer: %s", entry->filename, fullpath, *error);
+ } else {
+ spprintf(error, 4096, "Cannot extract \"%s\" to \"%s\", unable to open internal file pointer", entry->filename, fullpath);
+ }
+ efree(fullpath);
+ php_stream_close(fp);
+ return FAILURE;
+ }
+ }
+
+ if (FAILURE == phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC)) {
+ spprintf(error, 4096, "Cannot extract \"%s\" to \"%s\", unable to seek internal file pointer", entry->filename, fullpath);
+ efree(fullpath);
+ php_stream_close(fp);
+ return FAILURE;
+ }
+
+ if (entry->uncompressed_filesize != php_stream_copy_to_stream(phar_get_efp(entry, 0 TSRMLS_CC), fp, entry->uncompressed_filesize)) {
+ spprintf(error, 4096, "Cannot extract \"%s\" to \"%s\", copying contents failed", entry->filename, fullpath);
+ efree(fullpath);
+ php_stream_close(fp);
+ return FAILURE;
+ }
+
+ php_stream_close(fp);
+ mode = (mode_t) entry->flags & PHAR_ENT_PERM_MASK;
+
+ if (FAILURE == VCWD_CHMOD(fullpath, mode)) {
+ spprintf(error, 4096, "Cannot extract \"%s\" to \"%s\", setting file permissions failed", entry->filename, fullpath);
+ efree(fullpath);
+ return FAILURE;
+ }
+
+ efree(fullpath);
+ return SUCCESS;
+}
+
+/* {{{ proto bool Phar::extractTo(string pathto[[, mixed files], bool overwrite])
+ * Extract one or more file from a phar archive, optionally overwriting existing files
+ */
+PHP_METHOD(Phar, extractTo)
+{
+ char *error = NULL;
+ php_stream_statbuf ssb;
+ phar_entry_info *entry;
+ char *pathto, *filename;
+ int pathto_len, filename_len;
+ int ret, i;
+ int nelems;
+ zval *zval_files = NULL;
+ zend_bool overwrite = 0;
+ PHAR_ARCHIVE_OBJECT();
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z!b", &pathto, &pathto_len, &zval_files, &overwrite) == FAILURE) {
+ return;
+ }
+
+ if (pathto_len < 1) {
+ zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC,
+ "Invalid argument, extraction path must be non-zero length");
+ return;
+ }
+ if (pathto_len >= MAXPATHLEN) {
+ char *tmp = estrndup(pathto, 50);
+ /* truncate for error message */
+ zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "Cannot extract to \"%s...\", destination directory is too long for filesystem", tmp);
+ efree(tmp);
+ return;
+ }
+
+ if (php_stream_stat_path(pathto, &ssb) < 0) {
+ ret = php_stream_mkdir(pathto, 0777, PHP_STREAM_MKDIR_RECURSIVE, NULL);
+ if (!ret) {
+ zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC,
+ "Unable to create path \"%s\" for extraction", pathto);
+ return;
+ }
+ } else if (!(ssb.sb.st_mode & S_IFDIR)) {
+ zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC,
+ "Unable to use path \"%s\" for extraction, it is a file, must be a directory", pathto);
+ return;
+ }
+
+ if (zval_files) {
+ switch (Z_TYPE_P(zval_files)) {
+ case IS_NULL:
+ goto all_files;
+ case IS_STRING:
+ filename = Z_STRVAL_P(zval_files);
+ filename_len = Z_STRLEN_P(zval_files);
+ break;
+ case IS_ARRAY:
+ nelems = zend_hash_num_elements(Z_ARRVAL_P(zval_files));
+ if (nelems == 0 ) {
+ RETURN_FALSE;
+ }
+ for (i = 0; i < nelems; i++) {
+ zval **zval_file;
+ if (zend_hash_index_find(Z_ARRVAL_P(zval_files), i, (void **) &zval_file) == SUCCESS) {
+ switch (Z_TYPE_PP(zval_file)) {
+ case IS_STRING:
+ break;
+ default:
+ zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC,
+ "Invalid argument, array of filenames to extract contains non-string value");
+ return;
+ }
+ if (FAILURE == zend_hash_find(&phar_obj->arc.archive->manifest, Z_STRVAL_PP(zval_file), Z_STRLEN_PP(zval_file), (void **)&entry)) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC,
+ "Phar Error: attempted to extract non-existent file \"%s\" from phar \"%s\"", Z_STRVAL_PP(zval_file), phar_obj->arc.archive->fname);
+ }
+ if (FAILURE == phar_extract_file(overwrite, entry, pathto, pathto_len, &error TSRMLS_CC)) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC,
+ "Extraction from phar \"%s\" failed: %s", phar_obj->arc.archive->fname, error);
+ efree(error);
+ return;
+ }
+ }
+ }
+ RETURN_TRUE;
+ default:
+ zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC,
+ "Invalid argument, expected a filename (string) or array of filenames");
+ return;
+ }
+ if (FAILURE == zend_hash_find(&phar_obj->arc.archive->manifest, filename, filename_len, (void **)&entry)) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC,
+ "Phar Error: attempted to extract non-existent file \"%s\" from phar \"%s\"", filename, phar_obj->arc.archive->fname);
+ return;
+ }
+ if (FAILURE == phar_extract_file(overwrite, entry, pathto, pathto_len, &error TSRMLS_CC)) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC,
+ "Extraction from phar \"%s\" failed: %s", phar_obj->arc.archive->fname, error);
+ efree(error);
+ return;
+ }
+ } else {
+ phar_archive_data *phar = phar_obj->arc.archive;
+
+all_files:
+ /* Extract all files */
+ if (!zend_hash_num_elements(&(phar->manifest))) {
+ RETURN_TRUE;
+ }
+
+ for (zend_hash_internal_pointer_reset(&phar->manifest);
+ zend_hash_has_more_elements(&phar->manifest) == SUCCESS;
+ zend_hash_move_forward(&phar->manifest)) {
+ phar_entry_info *entry;
+ if (zend_hash_get_current_data(&phar->manifest, (void **)&entry) == FAILURE) {
+ continue;
+ }
+ if (FAILURE == phar_extract_file(overwrite, entry, pathto, pathto_len, &error TSRMLS_CC)) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC,
+ "Extraction from phar \"%s\" failed: %s", phar->fname, error);
+ efree(error);
+ return;
+ }
+ }
+ }
+ RETURN_TRUE;
+}
+/* }}} */
+
+
+/* {{{ proto void PharFileInfo::__construct(string entry)
+ * Construct a Phar entry object
+ */
+PHP_METHOD(PharFileInfo, __construct)
+{
+ char *fname, *arch, *entry, *error;
+ int fname_len, arch_len, entry_len;
+ phar_entry_object *entry_obj;
+ phar_entry_info *entry_info;
+ phar_archive_data *phar_data;
+ zval *zobj = getThis(), arg1;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &fname, &fname_len) == FAILURE) {
+ return;
+ }
+
+ entry_obj = (phar_entry_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (entry_obj->ent.entry) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Cannot call constructor twice");
+ return;
+ }
+
+ if (fname_len < 7 || memcmp(fname, "phar://", 7) || phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC) == FAILURE) {
+ zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC,
+ "'%s' is not a valid phar archive URL (must have at least phar://filename.phar)", fname);
+ return;
+ }
+
+ if (phar_open_filename(arch, arch_len, NULL, 0, REPORT_ERRORS, &phar_data, &error TSRMLS_CC) == FAILURE) {
+ efree(arch);
+ efree(entry);
+ if (error) {
+ zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC,
+ "Cannot open phar file '%s': %s", fname, error);
+ efree(error);
+ } else {
+ zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC,
+ "Cannot open phar file '%s'", fname);
+ }
+ return;
+ }
+
+ if ((entry_info = phar_get_entry_info_dir(phar_data, entry, entry_len, 1, &error TSRMLS_CC)) == NULL) {
+ zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC,
+ "Cannot access phar file entry '%s' in archive '%s'%s%s", entry, arch, error?", ":"", error?error:"");
+ efree(arch);
+ efree(entry);
+ return;
+ }
+
+ efree(arch);
+ efree(entry);
+
+ entry_obj->ent.entry = entry_info;
+
+ INIT_PZVAL(&arg1);
+ ZVAL_STRINGL(&arg1, fname, fname_len, 0);
+
+ zend_call_method_with_1_params(&zobj, Z_OBJCE_P(zobj),
+ &spl_ce_SplFileInfo->constructor, "__construct", NULL, &arg1);
+}
+/* }}} */
+
+#define PHAR_ENTRY_OBJECT() \
+ phar_entry_object *entry_obj = (phar_entry_object*)zend_object_store_get_object(getThis() TSRMLS_CC); \
+ if (!entry_obj->ent.entry) { \
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, \
+ "Cannot call method on an uninitialized PharFileInfo object"); \
+ return; \
+ }
+
+/* {{{ proto void PharFileInfo::__destruct()
+ * clean up directory-based entry objects
+ */
+PHP_METHOD(PharFileInfo, __destruct)
+{
+ phar_entry_object *entry_obj = (phar_entry_object*)zend_object_store_get_object(getThis() TSRMLS_CC); \
+
+ if (entry_obj->ent.entry && entry_obj->ent.entry->is_temp_dir) {
+ if (entry_obj->ent.entry->filename) {
+ efree(entry_obj->ent.entry->filename);
+ entry_obj->ent.entry->filename = NULL;
+ }
+ efree(entry_obj->ent.entry);
+ entry_obj->ent.entry = NULL;
+ }
+}
+/* }}} */
+
+/* {{{ proto int PharFileInfo::getCompressedSize()
+ * Returns the compressed size
+ */
+PHP_METHOD(PharFileInfo, getCompressedSize)
+{
+ PHAR_ENTRY_OBJECT();
+
+ RETURN_LONG(entry_obj->ent.entry->compressed_filesize);
+}
+/* }}} */
+
+/* {{{ proto bool PharFileInfo::isCompressed([int compression_type])
+ * Returns whether the entry is compressed, and whether it is compressed with Phar::GZ or Phar::BZ2 if specified
+ */
+PHP_METHOD(PharFileInfo, isCompressed)
+{
+ /* a number that is not Phar::GZ or Phar::BZ2 */
+ long method = 9021976;
+ PHAR_ENTRY_OBJECT();
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &method) == FAILURE) {
+ return;
+ }
+
+ switch (method) {
+ case 9021976:
+ RETURN_BOOL(entry_obj->ent.entry->flags & PHAR_ENT_COMPRESSION_MASK);
+ case PHAR_ENT_COMPRESSED_GZ:
+ RETURN_BOOL(entry_obj->ent.entry->flags & PHAR_ENT_COMPRESSED_GZ);
+ case PHAR_ENT_COMPRESSED_BZ2:
+ RETURN_BOOL(entry_obj->ent.entry->flags & PHAR_ENT_COMPRESSED_BZ2);
+ default:
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, \
+ "Unknown compression type specified"); \
+ }
+}
+/* }}} */
+
+/* {{{ proto int PharFileInfo::getCRC32()
+ * Returns CRC32 code or throws an exception if not CRC checked
+ */
+PHP_METHOD(PharFileInfo, getCRC32)
+{
+ PHAR_ENTRY_OBJECT();
+
+ if (entry_obj->ent.entry->is_dir) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, \
+ "Phar entry is a directory, does not have a CRC"); \
+ return;
+ }
+ if (entry_obj->ent.entry->is_crc_checked) {
+ RETURN_LONG(entry_obj->ent.entry->crc32);
+ } else {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, \
+ "Phar entry was not CRC checked"); \
+ }
+}
+/* }}} */
+
+/* {{{ proto int PharFileInfo::isCRCChecked()
+ * Returns whether file entry is CRC checked
+ */
+PHP_METHOD(PharFileInfo, isCRCChecked)
+{
+ PHAR_ENTRY_OBJECT();
+
+ RETURN_BOOL(entry_obj->ent.entry->is_crc_checked);
+}
+/* }}} */
+
+/* {{{ proto int PharFileInfo::getPharFlags()
+ * Returns the Phar file entry flags
+ */
+PHP_METHOD(PharFileInfo, getPharFlags)
+{
+ PHAR_ENTRY_OBJECT();
+
+ RETURN_LONG(entry_obj->ent.entry->flags & ~(PHAR_ENT_PERM_MASK|PHAR_ENT_COMPRESSION_MASK));
+}
+/* }}} */
+
+/* {{{ proto int PharFileInfo::chmod()
+ * set the file permissions for the Phar. This only allows setting execution bit, read/write
+ */
+PHP_METHOD(PharFileInfo, chmod)
+{
+ char *error;
+ long perms;
+ PHAR_ENTRY_OBJECT();
+
+ if (entry_obj->ent.entry->is_temp_dir) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, \
+ "Phar entry \"%s\" is a temporary directory (not an actual entry in the archive), cannot chmod", entry_obj->ent.entry->filename); \
+ return;
+ }
+ if (PHAR_G(readonly) && !entry_obj->ent.entry->phar->is_data) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Cannot modify permissions for file \"%s\" in phar \"%s\", write operations are prohibited", entry_obj->ent.entry->filename, entry_obj->ent.entry->phar->fname);
+ return;
+ }
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &perms) == FAILURE) {
+ return;
+ }
+ /* clear permissions */
+ entry_obj->ent.entry->flags &= ~PHAR_ENT_PERM_MASK;
+ perms &= 0777;
+ entry_obj->ent.entry->flags |= perms;
+ entry_obj->ent.entry->old_flags = entry_obj->ent.entry->flags;
+ entry_obj->ent.entry->phar->is_modified = 1;
+ entry_obj->ent.entry->is_modified = 1;
+ /* hackish cache in php_stat needs to be cleared */
+ /* if this code fails to work, check main/streams/streams.c, _php_stream_stat_path */
+ if (BG(CurrentLStatFile)) {
+ efree(BG(CurrentLStatFile));
+ }
+ if (BG(CurrentStatFile)) {
+ efree(BG(CurrentStatFile));
+ }
+ BG(CurrentLStatFile) = NULL;
+ BG(CurrentStatFile) = NULL;
+
+ phar_flush(entry_obj->ent.entry->phar, 0, 0, 0, &error TSRMLS_CC);
+ if (error) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
+ efree(error);
+ }
+}
+/* }}} */
+
+/* {{{ proto int PharFileInfo::hasMetaData()
+ * Returns the metadata of the entry
+ */
+PHP_METHOD(PharFileInfo, hasMetadata)
+{
+ PHAR_ENTRY_OBJECT();
+
+ RETURN_BOOL(entry_obj->ent.entry->metadata != NULL);
+}
+/* }}} */
+
+/* {{{ proto int PharFileInfo::getMetaData()
+ * Returns the metadata of the entry
+ */
+PHP_METHOD(PharFileInfo, getMetadata)
+{
+ PHAR_ENTRY_OBJECT();
+
+ if (entry_obj->ent.entry->metadata) {
+ RETURN_ZVAL(entry_obj->ent.entry->metadata, 1, 0);
+ }
+}
+/* }}} */
+
+/* {{{ proto int PharFileInfo::setMetaData(mixed $metadata)
+ * Sets the metadata of the entry
+ */
+PHP_METHOD(PharFileInfo, setMetadata)
+{
+ char *error;
+ zval *metadata;
+ PHAR_ENTRY_OBJECT();
+
+ if (PHAR_G(readonly) && !entry_obj->ent.entry->phar->is_data) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Write operations disabled by phar.readonly INI setting");
+ return;
+ }
+ if (entry_obj->ent.entry->is_tar) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
+ "Cannot set metadata, not possible with tar-based phar archives");
+ return;
+ }
+ if (entry_obj->ent.entry->is_temp_dir) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, \
+ "Phar entry is a temporary directory (not an actual entry in the archive), cannot set metadata"); \
+ return;
+ }
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &metadata) == FAILURE) {
+ return;
+ }
+
+ if (entry_obj->ent.entry->metadata) {
+ zval_ptr_dtor(&entry_obj->ent.entry->metadata);
+ entry_obj->ent.entry->metadata = NULL;
+ }
+
+ MAKE_STD_ZVAL(entry_obj->ent.entry->metadata);
+ ZVAL_ZVAL(entry_obj->ent.entry->metadata, metadata, 1, 0);
+
+ phar_flush(entry_obj->ent.entry->phar, 0, 0, 0, &error TSRMLS_CC);
+ if (error) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
+ efree(error);
+ }
+}
+/* }}} */
+
+/* {{{ proto bool PharFileInfo::delMetaData()
+ * Deletes the metadata of the entry
+ */
+PHP_METHOD(PharFileInfo, delMetadata)
+{
+ char *error;
+ PHAR_ENTRY_OBJECT();
+
+ if (PHAR_G(readonly) && !entry_obj->ent.entry->phar->is_data) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Write operations disabled by phar.readonly INI setting");
+ return;
+ }
+ if (entry_obj->ent.entry->is_tar) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
+ "Cannot delete metadata, not possible with tar-based phar archives");
+ return;
+ }
+ if (entry_obj->ent.entry->is_temp_dir) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, \
+ "Phar entry is a temporary directory (not an actual entry in the archive), cannot delete metadata"); \
+ return;
+ }
+ if (entry_obj->ent.entry->metadata) {
+ zval_ptr_dtor(&entry_obj->ent.entry->metadata);
+ entry_obj->ent.entry->metadata = NULL;
+
+ phar_flush(entry_obj->ent.entry->phar, 0, 0, 0, &error TSRMLS_CC);
+ if (error) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
+ efree(error);
+ RETURN_FALSE;
+ } else {
+ RETURN_TRUE;
+ }
+ } else {
+ RETURN_TRUE;
+ }
+}
+/* }}} */
+
+/* {{{ proto string PharFileInfo::getContent()
+ * return the complete file contents of the entry (like file_get_contents)
+ */
+PHP_METHOD(PharFileInfo, getContent)
+{
+ char *error;
+ php_stream *fp;
+ phar_entry_info *link;
+ PHAR_ENTRY_OBJECT();
+
+ if (entry_obj->ent.entry->is_dir) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
+ "Phar error: Cannot retrieve contents, \"%s\" in phar \"%s\" is a directory", entry_obj->ent.entry->filename, entry_obj->ent.entry->phar->fname);
+ return;
+ }
+ link = phar_get_link_source(entry_obj->ent.entry TSRMLS_CC);
+ if (!link) {
+ link = entry_obj->ent.entry;
+ }
+ if (SUCCESS != phar_open_entry_fp(link, &error, 0 TSRMLS_CC)) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
+ "Phar error: Cannot retrieve contents, \"%s\" in phar \"%s\": %s", entry_obj->ent.entry->filename, entry_obj->ent.entry->phar->fname, error);
+ efree(error);
+ return;
+ }
+ if (!(fp = phar_get_efp(link, 0 TSRMLS_CC))) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
+ "Phar error: Cannot retrieve contents of \"%s\" in phar \"%s\"", entry_obj->ent.entry->filename, entry_obj->ent.entry->phar->fname);
+ return;
+ }
+ phar_seek_efp(link, 0, SEEK_SET, 0, 0 TSRMLS_CC);
+ Z_TYPE_P(return_value) = IS_STRING;
+ Z_STRLEN_P(return_value) = php_stream_copy_to_mem(fp, &(Z_STRVAL_P(return_value)), link->uncompressed_filesize, 0);
+ if (!Z_STRVAL_P(return_value)) {
+ Z_STRVAL_P(return_value) = estrndup("", 0);
+ }
+}
+/* }}} */
+
+/* {{{ proto int PharFileInfo::compress(int compression_type)
+ * Instructs the Phar class to compress the current file using zlib or bzip2 compression
+ */
+PHP_METHOD(PharFileInfo, compress)
+{
+ long method;
+ char *error;
+ PHAR_ENTRY_OBJECT();
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &method) == FAILURE) {
+ return;
+ }
+
+ if (entry_obj->ent.entry->is_tar) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
+ "Cannot compress with Gzip compression, not possible with tar-based phar archives");
+ return;
+ }
+ if (entry_obj->ent.entry->is_dir) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, \
+ "Phar entry is a directory, cannot set compression"); \
+ return;
+ }
+ if (PHAR_G(readonly) && !entry_obj->ent.entry->phar->is_data) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
+ "Phar is readonly, cannot change compression");
+ return;
+ }
+ if (entry_obj->ent.entry->is_deleted) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
+ "Cannot compress deleted file");
+ return;
+ }
+
+ switch (method) {
+ case PHAR_ENT_COMPRESSED_GZ:
+ if (entry_obj->ent.entry->flags & PHAR_ENT_COMPRESSED_GZ) {
+ RETURN_TRUE;
+ return;
+ }
+ if ((entry_obj->ent.entry->flags & PHAR_ENT_COMPRESSED_BZ2) != 0) {
+ if (!phar_has_bz2) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
+ "Cannot compress with gzip compression, file is already compressed with bzip2 compression and bz2 extension is not enabled, cannot decompress");
+ return;
+ }
+ /* decompress this file indirectly */
+ if (SUCCESS != phar_open_entry_fp(entry_obj->ent.entry, &error, 1 TSRMLS_CC)) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
+ "Phar error: Cannot decompress bzip2-compressed file \"%s\" in phar \"%s\" in order to compress with gzip: %s", entry_obj->ent.entry->filename, entry_obj->ent.entry->phar->fname, error);
+ efree(error);
+ return;
+ }
+ }
+ if (!phar_has_zlib) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
+ "Cannot compress with gzip compression, zlib extension is not enabled");
+ return;
+ }
+ entry_obj->ent.entry->old_flags = entry_obj->ent.entry->flags;
+ entry_obj->ent.entry->flags &= ~PHAR_ENT_COMPRESSION_MASK;
+ entry_obj->ent.entry->flags |= PHAR_ENT_COMPRESSED_GZ;
+ break;
+ case PHAR_ENT_COMPRESSED_BZ2:
+ if (entry_obj->ent.entry->flags & PHAR_ENT_COMPRESSED_BZ2) {
+ RETURN_TRUE;
+ return;
+ }
+ if ((entry_obj->ent.entry->flags & PHAR_ENT_COMPRESSED_GZ) != 0) {
+ if (!phar_has_zlib) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
+ "Cannot compress with bzip2 compression, file is already compressed with gzip compression and zlib extension is not enabled, cannot decompress");
+ return;
+ }
+ /* decompress this file indirectly */
+ if (SUCCESS != phar_open_entry_fp(entry_obj->ent.entry, &error, 1 TSRMLS_CC)) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
+ "Phar error: Cannot decompress gzip-compressed file \"%s\" in phar \"%s\" in order to compress with bzip2: %s", entry_obj->ent.entry->filename, entry_obj->ent.entry->phar->fname, error);
+ efree(error);
+ return;
+ }
+ }
+ if (!phar_has_bz2) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
+ "Cannot compress with bzip2 compression, bz2 extension is not enabled");
+ return;
+ }
+ entry_obj->ent.entry->old_flags = entry_obj->ent.entry->flags;
+ entry_obj->ent.entry->flags &= ~PHAR_ENT_COMPRESSION_MASK;
+ entry_obj->ent.entry->flags |= PHAR_ENT_COMPRESSED_BZ2;
+ break;
+ default:
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, \
+ "Unknown compression type specified"); \
+ }
+
+ entry_obj->ent.entry->phar->is_modified = 1;
+ entry_obj->ent.entry->is_modified = 1;
+
+ phar_flush(entry_obj->ent.entry->phar, 0, 0, 0, &error TSRMLS_CC);
+ if (error) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
+ efree(error);
+ }
+ RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto int PharFileInfo::decompress()
+ * Instructs the Phar class to decompress the current file
+ */
+PHP_METHOD(PharFileInfo, decompress)
+{
+ char *error;
+ PHAR_ENTRY_OBJECT();
+
+ if (entry_obj->ent.entry->is_dir) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, \
+ "Phar entry is a directory, cannot set compression"); \
+ return;
+ }
+ if ((entry_obj->ent.entry->flags & PHAR_ENT_COMPRESSION_MASK) == 0) {
+ RETURN_TRUE;
+ return;
+ }
+ if (PHAR_G(readonly) && !entry_obj->ent.entry->phar->is_data) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
+ "Phar is readonly, cannot decompress");
+ return;
+ }
+ if (entry_obj->ent.entry->is_deleted) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
+ "Cannot compress deleted file");
+ return;
+ }
+ if ((entry_obj->ent.entry->flags & PHAR_ENT_COMPRESSED_GZ) != 0 && !phar_has_zlib) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
+ "Cannot decompress Gzip-compressed file, zlib extension is not enabled");
+ return;
+ }
+ if ((entry_obj->ent.entry->flags & PHAR_ENT_COMPRESSED_BZ2) != 0 && !phar_has_bz2) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
+ "Cannot decompress Bzip2-compressed file, bz2 extension is not enabled");
+ return;
+ }
+ if (!entry_obj->ent.entry->fp) {
+ if (FAILURE == phar_open_archive_fp(entry_obj->ent.entry->phar TSRMLS_CC)) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Cannot decompress entry \"%s\", phar error: Cannot open phar archive \"%s\" for reading", entry_obj->ent.entry->filename, entry_obj->ent.entry->phar->fname);
+ return;
+ }
+ entry_obj->ent.entry->fp_type = PHAR_FP;
+ }
+ entry_obj->ent.entry->old_flags = entry_obj->ent.entry->flags;
+ entry_obj->ent.entry->flags &= ~PHAR_ENT_COMPRESSION_MASK;
+ entry_obj->ent.entry->phar->is_modified = 1;
+ entry_obj->ent.entry->is_modified = 1;
+
+ phar_flush(entry_obj->ent.entry->phar, 0, 0, 0, &error TSRMLS_CC);
+ if (error) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
+ efree(error);
+ }
+ RETURN_TRUE;
+}
+/* }}} */
+
+#endif /* HAVE_SPL */
+
+/* {{{ phar methods */
+
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_phar___construct, 0, 0, 1)
+ ZEND_ARG_INFO(0, filename)
+ ZEND_ARG_INFO(0, flags)
+ ZEND_ARG_INFO(0, alias)
+ZEND_END_ARG_INFO();
+
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_createDS, 0, 0, 0)
+ ZEND_ARG_INFO(0, index)
+ ZEND_ARG_INFO(0, webindex)
+ZEND_END_ARG_INFO();
+
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_loadPhar, 0, 0, 1)
+ ZEND_ARG_INFO(0, filename)
+ ZEND_ARG_INFO(0, alias)
+ZEND_END_ARG_INFO();
+
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_mapPhar, 0, 0, 0)
+ ZEND_ARG_INFO(0, alias)
+ ZEND_ARG_INFO(0, offset)
+ZEND_END_ARG_INFO();
+
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_mount, 0, 0, 2)
+ ZEND_ARG_INFO(0, inphar)
+ ZEND_ARG_INFO(0, externalfile)
+ZEND_END_ARG_INFO();
+
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_mungServer, 0, 0, 1)
+ ZEND_ARG_INFO(0, munglist)
+ZEND_END_ARG_INFO();
+
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_webPhar, 0, 0, 0)
+ ZEND_ARG_INFO(0, alias)
+ ZEND_ARG_INFO(0, index)
+ ZEND_ARG_INFO(0, f404)
+ ZEND_ARG_INFO(0, mimetypes)
+ ZEND_ARG_INFO(0, rewrites)
+ZEND_END_ARG_INFO();
+
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_running, 0, 0, 1)
+ ZEND_ARG_INFO(0, retphar)
+ZEND_END_ARG_INFO();
+
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_ua, 0, 0, 1)
+ ZEND_ARG_INFO(0, archive)
+ZEND_END_ARG_INFO();
+
+#if HAVE_SPL
+
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_build, 0, 0, 1)
+ ZEND_ARG_INFO(0, iterator)
+ ZEND_ARG_INFO(0, base_directory)
+ZEND_END_ARG_INFO();
+
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_conv, 0, 0, 0)
+ ZEND_ARG_INFO(0, format)
+ ZEND_ARG_INFO(0, compression_type)
+ ZEND_ARG_INFO(0, file_ext)
+ZEND_END_ARG_INFO();
+
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_comps, 0, 0, 1)
+ ZEND_ARG_INFO(0, compression_type)
+ ZEND_ARG_INFO(0, file_ext)
+ZEND_END_ARG_INFO();
+
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_decomp, 0, 0, 0)
+ ZEND_ARG_INFO(0, file_ext)
+ZEND_END_ARG_INFO();
+
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_comp, 0, 0, 1)
+ ZEND_ARG_INFO(0, compression_type)
+ZEND_END_ARG_INFO();
+
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_compo, 0, 0, 0)
+ ZEND_ARG_INFO(0, compression_type)
+ZEND_END_ARG_INFO();
+
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_copy, 0, 0, 2)
+ ZEND_ARG_INFO(0, newfile)
+ ZEND_ARG_INFO(0, oldfile)
+ZEND_END_ARG_INFO();
+
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_delete, 0, 0, 1)
+ ZEND_ARG_INFO(0, entry)
+ZEND_END_ARG_INFO();
+
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_fromdir, 0, 0, 1)
+ ZEND_ARG_INFO(0, base_dir)
+ ZEND_ARG_INFO(0, regex)
+ZEND_END_ARG_INFO();
+
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_offsetExists, 0, 0, 1)
+ ZEND_ARG_INFO(0, entry)
+ZEND_END_ARG_INFO();
+
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_offsetSet, 0, 0, 2)
+ ZEND_ARG_INFO(0, entry)
+ ZEND_ARG_INFO(0, value)
+ZEND_END_ARG_INFO();
+
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_setAlias, 0, 0, 1)
+ ZEND_ARG_INFO(0, alias)
+ZEND_END_ARG_INFO();
+
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_setMetadata, 0, 0, 1)
+ ZEND_ARG_INFO(0, metadata)
+ZEND_END_ARG_INFO();
+
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_setSigAlgo, 0, 0, 1)
+ ZEND_ARG_INFO(0, algorithm)
+ZEND_END_ARG_INFO();
+
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_setStub, 0, 0, 1)
+ ZEND_ARG_INFO(0, newstub)
+ ZEND_ARG_INFO(0, maxlen)
+ZEND_END_ARG_INFO();
+
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_emptydir, 0, 0, 0)
+ ZEND_ARG_INFO(0, dirname)
+ZEND_END_ARG_INFO();
+
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_extract, 0, 0, 1)
+ ZEND_ARG_INFO(0, pathto)
+ ZEND_ARG_INFO(0, files)
+ ZEND_ARG_INFO(0, overwrite)
+ZEND_END_ARG_INFO();
+
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_addfile, 0, 0, 1)
+ ZEND_ARG_INFO(0, filename)
+ ZEND_ARG_INFO(0, localname)
+ZEND_END_ARG_INFO();
+
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_fromstring, 0, 0, 1)
+ ZEND_ARG_INFO(0, localname)
+ ZEND_ARG_INFO(0, contents)
+ZEND_END_ARG_INFO();
+
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_isff, 0, 0, 1)
+ ZEND_ARG_INFO(0, fileformat)
+ZEND_END_ARG_INFO();
+
+#endif /* HAVE_SPL */
+
+zend_function_entry php_archive_methods[] = {
+#if !HAVE_SPL
+ PHP_ME(Phar, __construct, arginfo_phar___construct, ZEND_ACC_PRIVATE)
+#else
+ PHP_ME(Phar, __construct, arginfo_phar___construct, ZEND_ACC_PUBLIC)
+ PHP_ME(Phar, addEmptyDir, arginfo_phar_emptydir, ZEND_ACC_PUBLIC)
+ PHP_ME(Phar, addFile, arginfo_phar_addfile, ZEND_ACC_PUBLIC)
+ PHP_ME(Phar, addFromString, arginfo_phar_fromstring, ZEND_ACC_PUBLIC)
+ PHP_ME(Phar, buildFromDirectory, arginfo_phar_fromdir, ZEND_ACC_PUBLIC)
+ PHP_ME(Phar, buildFromIterator, arginfo_phar_build, ZEND_ACC_PUBLIC)
+ PHP_ME(Phar, compressFiles, arginfo_phar_comp, ZEND_ACC_PUBLIC)
+ PHP_ME(Phar, decompressFiles, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(Phar, compress, arginfo_phar_comps, ZEND_ACC_PUBLIC)
+ PHP_ME(Phar, decompress, arginfo_phar_decomp, ZEND_ACC_PUBLIC)
+ PHP_ME(Phar, convertToExecutable, arginfo_phar_conv, ZEND_ACC_PUBLIC)
+ PHP_ME(Phar, convertToData, arginfo_phar_conv, ZEND_ACC_PUBLIC)
+ PHP_ME(Phar, copy, arginfo_phar_copy, ZEND_ACC_PUBLIC)
+ PHP_ME(Phar, count, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(Phar, delete, arginfo_phar_delete, ZEND_ACC_PUBLIC)
+ PHP_ME(Phar, delMetadata, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(Phar, extractTo, arginfo_phar_extract, ZEND_ACC_PUBLIC)
+ PHP_ME(Phar, getAlias, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(Phar, getPath, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(Phar, getMetadata, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(Phar, getModified, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(Phar, getSignature, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(Phar, getStub, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(Phar, getVersion, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(Phar, hasMetadata, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(Phar, isBuffering, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(Phar, isCompressed, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(Phar, isFileFormat, arginfo_phar_isff, ZEND_ACC_PUBLIC)
+ PHP_ME(Phar, isWritable, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(Phar, offsetExists, arginfo_phar_offsetExists, ZEND_ACC_PUBLIC)
+ PHP_ME(Phar, offsetGet, arginfo_phar_offsetExists, ZEND_ACC_PUBLIC)
+ PHP_ME(Phar, offsetSet, arginfo_phar_offsetSet, ZEND_ACC_PUBLIC)
+ PHP_ME(Phar, offsetUnset, arginfo_phar_offsetExists, ZEND_ACC_PUBLIC)
+ PHP_ME(Phar, setAlias, arginfo_phar_setAlias, ZEND_ACC_PUBLIC)
+ PHP_ME(Phar, setDefaultStub, arginfo_phar_createDS, ZEND_ACC_PUBLIC)
+ PHP_ME(Phar, setMetadata, arginfo_phar_setMetadata, ZEND_ACC_PUBLIC)
+ PHP_ME(Phar, setSignatureAlgorithm, arginfo_phar_setSigAlgo, ZEND_ACC_PUBLIC)
+ PHP_ME(Phar, setStub, arginfo_phar_setStub, ZEND_ACC_PUBLIC)
+ PHP_ME(Phar, startBuffering, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(Phar, stopBuffering, NULL, ZEND_ACC_PUBLIC)
+#endif
+ /* static member functions */
+ PHP_ME(Phar, apiVersion, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
+ PHP_ME(Phar, canCompress, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
+ PHP_ME(Phar, canWrite, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
+ PHP_ME(Phar, createDefaultStub, arginfo_phar_createDS, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
+ PHP_ME(Phar, getSupportedCompression,NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
+ PHP_ME(Phar, getSupportedSignatures,NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
+ PHP_ME(Phar, interceptFileFuncs, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
+ PHP_ME(Phar, isValidPharFilename, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
+ PHP_ME(Phar, loadPhar, arginfo_phar_loadPhar, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
+ PHP_ME(Phar, mapPhar, arginfo_phar_mapPhar, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
+ PHP_ME(Phar, running, arginfo_phar_running, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
+ PHP_ME(Phar, mount, arginfo_phar_mount, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
+ PHP_ME(Phar, mungServer, arginfo_phar_mungServer, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
+ PHP_ME(Phar, unlinkArchive, arginfo_phar_ua, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
+ PHP_ME(Phar, webPhar, arginfo_phar_webPhar, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
+ {NULL, NULL, NULL}
+};
+
+#if HAVE_SPL
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_entry___construct, 0, 0, 1)
+ ZEND_ARG_INFO(0, filename)
+ZEND_END_ARG_INFO();
+
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_entry_chmod, 0, 0, 1)
+ ZEND_ARG_INFO(0, perms)
+ZEND_END_ARG_INFO();
+
+zend_function_entry php_entry_methods[] = {
+ PHP_ME(PharFileInfo, __construct, arginfo_entry___construct, ZEND_ACC_PUBLIC)
+ PHP_ME(PharFileInfo, __destruct, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(PharFileInfo, chmod, arginfo_entry_chmod, ZEND_ACC_PUBLIC)
+ PHP_ME(PharFileInfo, compress, arginfo_phar_comp, ZEND_ACC_PUBLIC)
+ PHP_ME(PharFileInfo, decompress, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(PharFileInfo, delMetadata, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(PharFileInfo, getCompressedSize, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(PharFileInfo, getCRC32, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(PharFileInfo, getContent, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(PharFileInfo, getMetadata, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(PharFileInfo, getPharFlags, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(PharFileInfo, hasMetadata, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(PharFileInfo, isCompressed, arginfo_phar_compo, ZEND_ACC_PUBLIC)
+ PHP_ME(PharFileInfo, isCRCChecked, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(PharFileInfo, setMetadata, arginfo_phar_setMetadata, ZEND_ACC_PUBLIC)
+ {NULL, NULL, NULL}
+};
+#endif /* HAVE_SPL */
+
+zend_function_entry phar_exception_methods[] = {
+ {NULL, NULL, NULL}
+};
+/* }}} */
+
+#define REGISTER_PHAR_CLASS_CONST_LONG(class_name, const_name, value) \
+ zend_declare_class_constant_long(class_name, const_name, sizeof(const_name)-1, (long)value TSRMLS_CC);
+
+#if PHP_VERSION_ID < 50200
+# define phar_exception_get_default() zend_exception_get_default()
+#else
+# define phar_exception_get_default() zend_exception_get_default(TSRMLS_C)
+#endif
+
+void phar_object_init(TSRMLS_D) /* {{{ */
+{
+ zend_class_entry ce;
+
+ INIT_CLASS_ENTRY(ce, "PharException", phar_exception_methods);
+ phar_ce_PharException = zend_register_internal_class_ex(&ce, phar_exception_get_default(), NULL TSRMLS_CC);
+
+#if HAVE_SPL
+ INIT_CLASS_ENTRY(ce, "Phar", php_archive_methods);
+ phar_ce_archive = zend_register_internal_class_ex(&ce, spl_ce_RecursiveDirectoryIterator, NULL TSRMLS_CC);
+
+ zend_class_implements(phar_ce_archive TSRMLS_CC, 2, spl_ce_Countable, zend_ce_arrayaccess);
+
+ INIT_CLASS_ENTRY(ce, "PharData", php_archive_methods);
+ phar_ce_data = zend_register_internal_class_ex(&ce, spl_ce_RecursiveDirectoryIterator, NULL TSRMLS_CC);
+
+ zend_class_implements(phar_ce_data TSRMLS_CC, 2, spl_ce_Countable, zend_ce_arrayaccess);
+
+ INIT_CLASS_ENTRY(ce, "PharFileInfo", php_entry_methods);
+ phar_ce_entry = zend_register_internal_class_ex(&ce, spl_ce_SplFileInfo, NULL TSRMLS_CC);
+#else
+ INIT_CLASS_ENTRY(ce, "Phar", php_archive_methods);
+ phar_ce_archive = zend_register_internal_class(&ce TSRMLS_CC);
+ phar_ce_archive->ce_flags |= ZEND_ACC_FINAL_CLASS;
+
+ INIT_CLASS_ENTRY(ce, "PharData", php_archive_methods);
+ phar_ce_data = zend_register_internal_class(&ce TSRMLS_CC);
+ phar_ce_data->ce_flags |= ZEND_ACC_FINAL_CLASS;
+#endif
+
+ REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "BZ2", PHAR_ENT_COMPRESSED_BZ2)
+ REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "GZ", PHAR_ENT_COMPRESSED_GZ)
+ REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "NONE", PHAR_ENT_COMPRESSED_NONE)
+ REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "PHAR", PHAR_FORMAT_PHAR)
+ REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "TAR", PHAR_FORMAT_TAR)
+ REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "ZIP", PHAR_FORMAT_ZIP)
+ REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "COMPRESSED", PHAR_ENT_COMPRESSION_MASK)
+ REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "PHP", PHAR_MIME_PHP)
+ REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "PHPS", PHAR_MIME_PHPS)
+ REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "MD5", PHAR_SIG_MD5)
+ REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "PGP", PHAR_SIG_PGP)
+ REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "SHA1", PHAR_SIG_SHA1)
+ REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "SHA256", PHAR_SIG_SHA256)
+ REGISTER_PHAR_CLASS_CONST_LONG(phar_ce_archive, "SHA512", PHAR_SIG_SHA512)
+}
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
diff --git a/ext/phar/phar_path_check.c b/ext/phar/phar_path_check.c
new file mode 100755
index 0000000000..c1a273281b
--- /dev/null
+++ b/ext/phar/phar_path_check.c
@@ -0,0 +1,187 @@
+/* Generated by re2c 0.12.3 on Tue Jan 8 18:41:21 2008 */
+#line 1 "ext/phar/phar_path_check.re"
+/*
+ +----------------------------------------------------------------------+
+ | phar php single-file executable PHP extension |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 2007 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt. |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Marcus Boerger <helly@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#include "phar_internal.h"
+
+phar_path_check_result phar_path_check(char **s, int *len, const char **error)
+{
+ const unsigned char *p = (const unsigned char*)*s;
+ const unsigned char *m;
+
+ if (*len == 1 && *p == '.') {
+ *error = "current directory reference";
+ return pcr_err_curr_dir;
+ } else if (*len == 2 && p[0] == '.' && p[1] == '.') {
+ *error = "upper directory reference";
+ return pcr_err_up_dir;
+ }
+
+#define YYCTYPE unsigned char
+#define YYCURSOR p
+#define YYLIMIT p+*len
+#define YYMARKER m
+#define YYFILL(n)
+
+loop:
+{
+
+#line 48 "ext/phar/phar_path_check.c"
+ {
+ YYCTYPE yych;
+
+ if((YYLIMIT - YYCURSOR) < 4) YYFILL(4);
+ yych = *YYCURSOR;
+ if(yych <= '.') {
+ if(yych <= 0x0A) {
+ if(yych <= 0x00) goto yy13;
+ if(yych <= 0x09) goto yy10;
+ goto yy12;
+ } else {
+ if(yych <= 0x19) goto yy10;
+ if(yych == '*') goto yy6;
+ goto yy15;
+ }
+ } else {
+ if(yych <= '?') {
+ if(yych <= '/') goto yy2;
+ if(yych <= '>') goto yy15;
+ goto yy8;
+ } else {
+ if(yych == '\\') goto yy4;
+ if(yych <= 0x7F) goto yy15;
+ goto yy10;
+ }
+ }
+yy2:
+ yych = *(YYMARKER = ++YYCURSOR);
+ if(yych <= '-') goto yy3;
+ if(yych <= '.') goto yy16;
+ if(yych <= '/') goto yy18;
+yy3:
+#line 93 "ext/phar/phar_path_check.re"
+ {
+ goto loop;
+ }
+#line 85 "ext/phar/phar_path_check.c"
+yy4:
+ ++YYCURSOR;
+#line 60 "ext/phar/phar_path_check.re"
+ {
+ *error = "back-slash";
+ return pcr_err_back_slash;
+ }
+#line 93 "ext/phar/phar_path_check.c"
+yy6:
+ ++YYCURSOR;
+#line 64 "ext/phar/phar_path_check.re"
+ {
+ *error = "star";
+ return pcr_err_star;
+ }
+#line 101 "ext/phar/phar_path_check.c"
+yy8:
+ ++YYCURSOR;
+#line 68 "ext/phar/phar_path_check.re"
+ {
+ if (**s == '/') {
+ (*s)++;
+ }
+ *len = (p - (const unsigned char*)*s) -1;
+ *error = NULL;
+ return pcr_use_query;
+ }
+#line 113 "ext/phar/phar_path_check.c"
+yy10:
+ ++YYCURSOR;
+yy11:
+#line 76 "ext/phar/phar_path_check.re"
+ {
+ *error ="illegal character";
+ return pcr_err_illegal_char;
+ }
+#line 122 "ext/phar/phar_path_check.c"
+yy12:
+ yych = *++YYCURSOR;
+ goto yy11;
+yy13:
+ ++YYCURSOR;
+#line 80 "ext/phar/phar_path_check.re"
+ {
+ if (**s == '/') {
+ (*s)++;
+ (*len)--;
+ }
+ if ((p - (const unsigned char*)*s) - 1 != *len)
+ {
+ *error ="illegal character";
+ return pcr_err_illegal_char;
+ }
+ *error = NULL;
+ return pcr_is_ok;
+ }
+#line 142 "ext/phar/phar_path_check.c"
+yy15:
+ yych = *++YYCURSOR;
+ goto yy3;
+yy16:
+ yych = *++YYCURSOR;
+ if(yych <= 0x00) goto yy21;
+ if(yych <= '-') goto yy17;
+ if(yych <= '.') goto yy20;
+ if(yych <= '/') goto yy21;
+yy17:
+ YYCURSOR = YYMARKER;
+ goto yy3;
+yy18:
+ ++YYCURSOR;
+#line 48 "ext/phar/phar_path_check.re"
+ {
+ *error = "double slash";
+ return pcr_err_double_slash;
+ }
+#line 162 "ext/phar/phar_path_check.c"
+yy20:
+ yych = *++YYCURSOR;
+ if(yych <= 0x00) goto yy23;
+ if(yych == '/') goto yy23;
+ goto yy17;
+yy21:
+ ++YYCURSOR;
+#line 56 "ext/phar/phar_path_check.re"
+ {
+ *error = "current directory reference";
+ return pcr_err_curr_dir;
+ }
+#line 175 "ext/phar/phar_path_check.c"
+yy23:
+ ++YYCURSOR;
+#line 52 "ext/phar/phar_path_check.re"
+ {
+ *error = "upper directory reference";
+ return pcr_err_up_dir;
+ }
+#line 183 "ext/phar/phar_path_check.c"
+ }
+}
+#line 96 "ext/phar/phar_path_check.re"
+
+}
diff --git a/ext/phar/phar_path_check.re b/ext/phar/phar_path_check.re
new file mode 100755
index 0000000000..97a6b5d565
--- /dev/null
+++ b/ext/phar/phar_path_check.re
@@ -0,0 +1,97 @@
+/*
+ +----------------------------------------------------------------------+
+ | phar php single-file executable PHP extension |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 2007 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt. |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Marcus Boerger <helly@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#include "phar_internal.h"
+
+phar_path_check_result phar_path_check(char **s, int *len, const char **error)
+{
+ const unsigned char *p = (const unsigned char*)*s;
+ const unsigned char *m;
+
+ if (*len == 1 && *p == '.') {
+ *error = "current directory reference";
+ return pcr_err_curr_dir;
+ } else if (*len == 2 && p[0] == '.' && p[1] == '.') {
+ *error = "upper directory reference";
+ return pcr_err_up_dir;
+ }
+
+#define YYCTYPE unsigned char
+#define YYCURSOR p
+#define YYLIMIT p+*len
+#define YYMARKER m
+#define YYFILL(n)
+
+loop:
+/*!re2c
+END = "\x00";
+ILL = [\x01-\x19\x80-\xFF];
+EOS = "/" | END;
+ANY = .;
+"//" {
+ *error = "double slash";
+ return pcr_err_double_slash;
+ }
+"/.." EOS {
+ *error = "upper directory reference";
+ return pcr_err_up_dir;
+ }
+"/." EOS {
+ *error = "current directory reference";
+ return pcr_err_curr_dir;
+ }
+"\\" {
+ *error = "back-slash";
+ return pcr_err_back_slash;
+ }
+"*" {
+ *error = "star";
+ return pcr_err_star;
+ }
+"?" {
+ if (**s == '/') {
+ (*s)++;
+ }
+ *len = (p - (const unsigned char*)*s) -1;
+ *error = NULL;
+ return pcr_use_query;
+ }
+ILL {
+ *error ="illegal character";
+ return pcr_err_illegal_char;
+ }
+END {
+ if (**s == '/') {
+ (*s)++;
+ (*len)--;
+ }
+ if ((p - (const unsigned char*)*s) - 1 != *len)
+ {
+ *error ="illegal character";
+ return pcr_err_illegal_char;
+ }
+ *error = NULL;
+ return pcr_is_ok;
+ }
+ANY {
+ goto loop;
+ }
+*/
+}
diff --git a/ext/phar/pharzip.h b/ext/phar/pharzip.h
new file mode 100644
index 0000000000..e74b5ba47f
--- /dev/null
+++ b/ext/phar/pharzip.h
@@ -0,0 +1,247 @@
+/*
+ +----------------------------------------------------------------------+
+ | phar php single-file executable PHP extension |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 2006-2008 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt. |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gregory Beaver <cellog@php.net> |
+ | Marcus Boerger <helly@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifdef PHP_WIN32
+#pragma pack(1)
+# define PHAR_ZIP_PACK
+#else
+# define PHAR_ZIP_PACK __attribute__((__packed__))
+#endif
+typedef struct _phar_zip_file_header {
+ char signature[4]; /* local file header signature 4 bytes (0x04034b50) */
+ char zipversion[2]; /* version needed to extract 2 bytes */
+ php_uint16 flags; /* general purpose bit flag 2 bytes */
+ php_uint16 compressed; /* compression method 2 bytes */
+ php_uint16 timestamp; /* last mod file time 2 bytes */
+ php_uint16 datestamp; /* last mod file date 2 bytes */
+ php_uint32 crc32; /* crc-32 4 bytes */
+ php_uint32 compsize; /* compressed size 4 bytes */
+ php_uint32 uncompsize; /* uncompressed size 4 bytes */
+ php_uint16 filename_len; /* file name length 2 bytes */
+ php_uint16 extra_len; /* extra field length 2 bytes */
+/* file name (variable size) */
+/* extra field (variable size) */
+} PHAR_ZIP_PACK phar_zip_file_header;
+
+typedef struct _phar_zip_file_datadesc {
+ php_uint32 crc32; /* crc-32 4 bytes */
+ php_uint32 compsize; /* compressed size 4 bytes */
+ php_uint32 uncompsize; /* uncompressed size 4 bytes */
+} PHAR_ZIP_PACK phar_zip_data_desc;
+
+typedef struct _phar_zip_file_datadesc_zip64 {
+ php_uint32 crc32; /* crc-32 4 bytes */
+ php_uint32 compsize; /* compressed size 8 bytes */
+ php_uint32 compsize2;
+ php_uint32 uncompsize; /* uncompressed size 8 bytes */
+ php_uint32 uncompsize2;
+} PHAR_ZIP_PACK phar_zip_data_desc_zip64;
+
+typedef struct _phar_zip_archive_extra_data_record {
+ char signature[4]; /* archive extra data signature 4 bytes (0x08064b50) */
+ php_uint32 len; /* extra field length 4 bytes */
+/* extra field data (variable size) */
+} PHAR_ZIP_PACK phar_zip_archive_extra_data_record;
+
+/* madeby/extractneeded value if bzip2 compression is used */
+#define PHAR_ZIP_BZIP2 "46"
+/* madeby/extractneeded value for other cases */
+#define PHAR_ZIP_NORM "20"
+
+#define PHAR_ZIP_FLAG_ENCRYPTED 0x0001
+/* data descriptor present for this file */
+#define PHAR_ZIP_FLAG_DATADESC 0x0008
+#define PHAR_ZIP_FLAG_UTF8 0x0400
+
+/*
+0 - The file is stored (no compression)
+1 - The file is Shrunk
+2 - The file is Reduced with compression factor 1
+3 - The file is Reduced with compression factor 2
+4 - The file is Reduced with compression factor 3
+5 - The file is Reduced with compression factor 4
+6 - The file is Imploded
+7 - Reserved for Tokenizing compression algorithm
+8 - The file is Deflated
+9 - Enhanced Deflating using Deflate64(tm)
+10 - PKWARE Data Compression Library Imploding (old IBM TERSE)
+11 - Reserved by PKWARE
+12 - File is compressed using BZIP2 algorithm
+13 - Reserved by PKWARE
+14 - LZMA (EFS)
+15 - Reserved by PKWARE
+16 - Reserved by PKWARE
+17 - Reserved by PKWARE
+18 - File is compressed using IBM TERSE (new)
+19 - IBM LZ77 z Architecture (PFS)
+97 - WavPack compressed data
+98 - PPMd version I, Rev 1
+*/
+#define PHAR_ZIP_COMP_NONE 0
+#define PHAR_ZIP_COMP_DEFLATE 8
+#define PHAR_ZIP_COMP_BZIP2 12
+
+/*
+ -ASi Unix Extra Field:
+ ====================
+
+ The following is the layout of the ASi extra block for Unix. The
+ local-header and central-header versions are identical.
+ (Last Revision 19960916)
+
+ Value Size Description
+ ----- ---- -----------
+ (Unix3) 0x756e Short tag for this extra block type ("nu")
+ TSize Short total data size for this block
+ CRC Long CRC-32 of the remaining data
+ Mode Short file permissions
+ SizDev Long symlink'd size OR major/minor dev num
+ UID Short user ID
+ GID Short group ID
+ (var.) variable symbolic link filename
+
+ Mode is the standard Unix st_mode field from struct stat, containing
+ user/group/other permissions, setuid/setgid and symlink info, etc.
+
+ If Mode indicates that this file is a symbolic link, SizDev is the
+ size of the file to which the link points. Otherwise, if the file
+ is a device, SizDev contains the standard Unix st_rdev field from
+ struct stat (includes the major and minor numbers of the device).
+ SizDev is undefined in other cases.
+
+ If Mode indicates that the file is a symbolic link, the final field
+ will be the name of the file to which the link points. The file-
+ name length can be inferred from TSize.
+
+ [Note that TSize may incorrectly refer to the data size not counting
+ the CRC; i.e., it may be four bytes too small.]
+*/
+
+typedef struct _phar_zip_extra_field_header {
+ char tag[2];
+ php_uint16 size;
+} PHAR_ZIP_PACK phar_zip_extra_field_header;
+
+typedef struct _phar_zip_unix3 {
+ char tag[2]; /* 0x756e Short tag for this extra block type ("nu") */
+ php_uint16 size; /* TSize Short total data size for this block */
+ php_uint32 crc32; /* CRC Long CRC-32 of the remaining data */
+ php_uint16 perms; /* Mode Short file permissions */
+ php_uint32 symlinksize; /* SizDev Long symlink'd size OR major/minor dev num */
+ php_uint16 uid; /* UID Short user ID */
+ php_uint16 gid; /* GID Short group ID */
+/* (var.) variable symbolic link filename */
+} PHAR_ZIP_PACK phar_zip_unix3;
+
+typedef struct _phar_zip_central_dir_file {
+ char signature[4]; /* central file header signature 4 bytes (0x02014b50) */
+ char madeby[2]; /* version made by 2 bytes */
+ char zipversion[2]; /* version needed to extract 2 bytes */
+ php_uint16 flags; /* general purpose bit flag 2 bytes */
+ php_uint16 compressed; /* compression method 2 bytes */
+ php_uint16 timestamp; /* last mod file time 2 bytes */
+ php_uint16 datestamp; /* last mod file date 2 bytes */
+ php_uint32 crc32; /* crc-32 4 bytes */
+ php_uint32 compsize; /* compressed size 4 bytes */
+ php_uint32 uncompsize; /* uncompressed size 4 bytes */
+ php_uint16 filename_len; /* file name length 2 bytes */
+ php_uint16 extra_len; /* extra field length 2 bytes */
+ php_uint16 comment_len; /* file comment length 2 bytes */
+ php_uint16 disknumber; /* disk number start 2 bytes */
+ php_uint16 internal_atts; /* internal file attributes 2 bytes */
+ php_uint32 external_atts; /* external file attributes 4 bytes */
+ php_uint32 offset; /* relative offset of local header 4 bytes */
+
+/* file name (variable size) */
+/* extra field (variable size) */
+/* file comment (variable size) */
+} PHAR_ZIP_PACK phar_zip_central_dir_file;
+
+typedef struct _phar_zip_dir_signature {
+ char signature[4]; /* header signature 4 bytes (0x05054b50) */
+ php_uint16 size; /* size of data 2 bytes */
+} PHAR_ZIP_PACK phar_zip_dir_signature;
+
+typedef struct _phar_zip64_dir_end {
+ char signature[4]; /* zip64 end of central dir
+ signature 4 bytes (0x06064b50) */
+ php_uint32 size1; /* size of zip64 end of central
+ directory record 8 bytes */
+ php_uint32 size2;
+ char madeby[2]; /* version made by 2 bytes */
+ php_uint16 extractneeded; /* version needed to extract 2 bytes */
+ php_uint32 disknum; /* number of this disk 4 bytes */
+ php_uint32 cdir_num; /* number of the disk with the
+ start of the central directory 4 bytes */
+ php_uint32 entries1; /* total number of entries in the
+ central directory on this disk 8 bytes */
+ php_uint32 entries2;
+ php_uint32 entriestotal1; /* total number of entries in the
+ central directory 8 bytes */
+ php_uint32 entriestotal2;
+ php_uint32 cdirsize1; /* size of the central directory 8 bytes */
+ php_uint32 cdirsize2;
+ php_uint32 offset1; /* offset of start of central
+ directory with respect to
+ the starting disk number 8 bytes */
+ php_uint32 offset2;
+/* zip64 extensible data sector (variable size) */
+} PHAR_ZIP_PACK phar_zip64_dir_end;
+
+typedef struct _phar_zip64_dir_locator {
+ char signature[4]; /* zip64 end of central dir locator
+ signature 4 bytes (0x07064b50) */
+ php_uint32 disknum; /* number of the disk with the
+ start of the zip64 end of
+ central directory 4 bytes */
+ php_uint32 diroffset1; /* relative offset of the zip64
+ end of central directory record 8 bytes */
+ php_uint32 diroffset2;
+ php_uint32 totaldisks; /* total number of disks 4 bytes */
+} PHAR_ZIP_PACK phar_zip64_dir_locator;
+
+typedef struct _phar_zip_dir_end {
+ char signature[4]; /* end of central dir signature 4 bytes (0x06054b50) */
+ php_uint16 disknumber; /* number of this disk 2 bytes */
+ php_uint16 centraldisk; /* number of the disk with the
+ start of the central directory 2 bytes */
+ php_uint16 counthere; /* total number of entries in the
+ central directory on this disk 2 bytes */
+ php_uint16 count; /* total number of entries in
+ the central directory 2 bytes */
+ php_uint32 cdir_size; /* size of the central directory 4 bytes */
+ php_uint32 cdir_offset; /* offset of start of central
+ directory with respect to
+ the starting disk number 4 bytes */
+ php_uint16 comment_len; /* .ZIP file comment length 2 bytes */
+/* .ZIP file comment (variable size) */
+} PHAR_ZIP_PACK phar_zip_dir_end;
+#ifdef PHP_WIN32
+#pragma pack()
+#endif
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
diff --git a/ext/phar/php_phar.h b/ext/phar/php_phar.h
new file mode 100644
index 0000000000..89023972f6
--- /dev/null
+++ b/ext/phar/php_phar.h
@@ -0,0 +1,47 @@
+/*
+ +----------------------------------------------------------------------+
+ | phar php single-file executable PHP extension |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 2005 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt. |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gregory Beaver <cellog@php.net> |
+ | Marcus Boerger <helly@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifndef PHP_PHAR_H
+#define PHP_PHAR_H
+
+#define PHP_PHAR_VERSION "2.0.0b2-dev"
+
+#include "ext/standard/basic_functions.h"
+extern zend_module_entry phar_module_entry;
+#define phpext_phar_ptr &phar_module_entry
+
+#ifdef PHP_WIN32
+#define PHP_PHAR_API __declspec(dllexport)
+#else
+#define PHP_PHAR_API
+#endif
+
+#endif /* PHP_PHAR_H */
+
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
diff --git a/ext/phar/shortarc.php b/ext/phar/shortarc.php
new file mode 100644
index 0000000000..fa52636646
--- /dev/null
+++ b/ext/phar/shortarc.php
@@ -0,0 +1,295 @@
+<?php
+
+$web = '000';
+
+if (in_array('phar', stream_get_wrappers()) && class_exists('Phar', 0)) {
+ Phar::interceptFileFuncs();
+ set_include_path('phar://' . __FILE__ . PATH_SEPARATOR . get_include_path());
+ Phar::webPhar(null, $web);
+ include 'phar://' . __FILE__ . '/' . Extract_Phar::START;
+ return;
+}
+
+if (@(isset($_SERVER['REQUEST_URI']) && isset($_SERVER['REQUEST_METHOD']) && ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'POST'))) {
+ Extract_Phar::go(true);
+ $mimes = array(
+ 'phps' => 2,
+ 'c' => 'text/plain',
+ 'cc' => 'text/plain',
+ 'cpp' => 'text/plain',
+ 'c++' => 'text/plain',
+ 'dtd' => 'text/plain',
+ 'h' => 'text/plain',
+ 'log' => 'text/plain',
+ 'rng' => 'text/plain',
+ 'txt' => 'text/plain',
+ 'xsd' => 'text/plain',
+ 'php' => 1,
+ 'inc' => 1,
+ 'avi' => 'video/avi',
+ 'bmp' => 'image/bmp',
+ 'css' => 'text/css',
+ 'gif' => 'image/gif',
+ 'htm' => 'text/html',
+ 'html' => 'text/html',
+ 'htmls' => 'text/html',
+ 'ico' => 'image/x-ico',
+ 'jpe' => 'image/jpeg',
+ 'jpg' => 'image/jpeg',
+ 'jpeg' => 'image/jpeg',
+ 'js' => 'application/x-javascript',
+ 'midi' => 'audio/midi',
+ 'mid' => 'audio/midi',
+ 'mod' => 'audio/mod',
+ 'mov' => 'movie/quicktime',
+ 'mp3' => 'audio/mp3',
+ 'mpg' => 'video/mpeg',
+ 'mpeg' => 'video/mpeg',
+ 'pdf' => 'application/pdf',
+ 'png' => 'image/png',
+ 'swf' => 'application/shockwave-flash',
+ 'tif' => 'image/tiff',
+ 'tiff' => 'image/tiff',
+ 'wav' => 'audio/wav',
+ 'xbm' => 'image/xbm',
+ 'xml' => 'text/xml',
+ );
+
+ header("Cache-Control: no-cache, must-revalidate");
+ header("Pragma: no-cache");
+
+ $basename = basename(__FILE__);
+ if (!strpos($_SERVER['REQUEST_URI'], $basename)) {
+ chdir(Extract_Phar::$temp);
+ include $web;
+ return;
+ }
+ $pt = substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], $basename) + strlen($basename));
+ if (!$pt || $pt == '/') {
+ $pt = $web;
+ header('HTTP/1.1 301 Moved Permanently');
+ header('Location: ' . $_SERVER['REQUEST_URI'] . '/' . $pt);
+ exit;
+ }
+ $a = realpath(Extract_Phar::$temp . DIRECTORY_SEPARATOR . $pt);
+ if (!$a || strlen(dirname($a)) < strlen(Extract_Phar::$temp)) {
+ header('HTTP/1.0 404 Not Found');
+ echo "<html>\n <head>\n <title>File Not Found<title>\n </head>\n <body>\n <h1>404 - File ", $pt, " Not Found</h1>\n </body>\n</html>";
+ exit;
+ }
+ $b = pathinfo($a);
+ if (!isset($b['extension'])) {
+ header('Content-Type: text/plain');
+ header('Content-Length: ' . filesize($a));
+ readfile($a);
+ exit;
+ }
+ if (isset($mimes[$b['extension']])) {
+ if ($mimes[$b['extension']] === 1) {
+ include $a;
+ exit;
+ }
+ if ($mimes[$b['extension']] === 2) {
+ highlight_file($a);
+ exit;
+ }
+ header('Content-Type: ' .$mimes[$b['extension']]);
+ header('Content-Length: ' . filesize($a));
+ readfile($a);
+ exit;
+ }
+}
+
+class Extract_Phar
+{
+ static $temp;
+ static $origdir;
+ const GZ = 0x1000;
+ const BZ2 = 0x2000;
+ const MASK = 0x3000;
+ const START = 'index.php';
+ const LEN = XXXX;
+
+ static function go($return = false)
+ {
+ $fp = fopen(__FILE__, 'rb');
+ fseek($fp, self::LEN);
+ $L = unpack('V', $a = fread($fp, 4));
+ $m = '';
+
+ do {
+ $read = 8192;
+ if ($L[1] - strlen($m) < 8192) {
+ $read = $L[1] - strlen($m);
+ }
+ $last = fread($fp, $read);
+ $m .= $last;
+ } while (strlen($last) && strlen($m) < $L[1]);
+
+ if (strlen($m) < $L[1]) {
+ die('ERROR: manifest length read was "' .
+ strlen($m) .'" should be "' .
+ $L[1] . '"');
+ }
+
+ $info = self::_unpack($m);
+ $f = $info['c'];
+
+ if ($f & self::GZ) {
+ if (!function_exists('gzinflate')) {
+ die('Error: zlib extension is not enabled -' .
+ ' gzinflate() function needed for zlib-compressed .phars');
+ }
+ }
+
+ if ($f & self::BZ2) {
+ if (!function_exists('bzdecompress')) {
+ die('Error: bzip2 extension is not enabled -' .
+ ' bzdecompress() function needed for bz2-compressed .phars');
+ }
+ }
+
+ $temp = self::tmpdir();
+
+ if (!$temp || !is_writable($temp)) {
+ $sessionpath = session_save_path();
+ if (strpos ($sessionpath, ";") !== false)
+ $sessionpath = substr ($sessionpath, strpos ($sessionpath, ";")+1);
+ if (!file_exists($sessionpath) || !is_dir($sessionpath)) {
+ die('Could not locate temporary directory to extract phar');
+ }
+ $temp = $sessionpath;
+ }
+
+ $temp .= '/pharextract/'.basename(__FILE__, '.phar');
+ self::$temp = $temp;
+ self::$origdir = getcwd();
+ @mkdir($temp, 0777, true);
+ $temp = realpath($temp);
+
+ if (!file_exists($temp . DIRECTORY_SEPARATOR . md5_file(__FILE__))) {
+ self::_removeTmpFiles($temp, getcwd());
+ @mkdir($temp, 0777, true);
+ @file_put_contents($temp . '/' . md5_file(__FILE__), '');
+
+ foreach ($info['m'] as $path => $file) {
+ $a = !file_exists(dirname($temp . '/' . $path));
+ @mkdir(dirname($temp . '/' . $path), 0777, true);
+ clearstatcache();
+
+ if ($path[strlen($path) - 1] == '/') {
+ @mkdir($temp . '/' . $path, 0777);
+ } else {
+ file_put_contents($temp . '/' . $path, self::extractFile($path, $file, $fp));
+ @chmod($temp . '/' . $path, 0666);
+ }
+ }
+ }
+
+ chdir($temp);
+
+ if (!$return) {
+ include self::START;
+ }
+ }
+
+ static function tmpdir()
+ {
+ if (strpos(PHP_OS, 'WIN') !== false) {
+ if ($var = getenv('TMP') ? getenv('TMP') : getenv('TEMP')) {
+ return $var;
+ }
+ if (is_dir('/temp') || mkdir('/temp')) {
+ return realpath('/temp');
+ }
+ return false;
+ }
+ if ($var = getenv('TMPDIR')) {
+ return $var;
+ }
+ return realpath('/tmp');
+ }
+
+ static function _unpack($m)
+ {
+ $info = unpack('V', substr($m, 0, 4));
+ // skip API version, phar flags, alias, metadata
+ $l = unpack('V', substr($m, 10, 4));
+ $m = substr($m, 14 + $l[1]);
+ $s = unpack('V', substr($m, 0, 4));
+ $o = 0;
+ $start = 4 + $s[1];
+ $ret['c'] = 0;
+
+ for ($i = 0; $i < $info[1]; $i++) {
+ // length of the file name
+ $len = unpack('V', substr($m, $start, 4));
+ $start += 4;
+ // file name
+ $savepath = substr($m, $start, $len[1]);
+ $start += $len[1];
+ // retrieve manifest data:
+ // 0 = size, 1 = timestamp, 2 = compressed size, 3 = crc32, 4 = flags
+ // 5 = metadata length
+ $ret['m'][$savepath] = array_values(unpack('Va/Vb/Vc/Vd/Ve/Vf', substr($m, $start, 24)));
+ $ret['m'][$savepath][3] = sprintf('%u', $ret['m'][$savepath][3]
+ & 0xffffffff);
+ $ret['m'][$savepath][7] = $o;
+ $o += $ret['m'][$savepath][2];
+ $start += 24 + $ret['m'][$savepath][5];
+ $ret['c'] |= $ret['m'][$savepath][4] & self::MASK;
+ }
+ return $ret;
+ }
+
+ static function extractFile($path, $entry, $fp)
+ {
+ $data = '';
+ $c = $entry[2];
+
+ while ($c) {
+ if ($c < 8192) {
+ $data .= @fread($fp, $c);
+ $c = 0;
+ } else {
+ $c -= 8192;
+ $data .= @fread($fp, 8192);
+ }
+ }
+
+ if ($entry[4] & self::GZ) {
+ $data = gzinflate($data);
+ } elseif ($entry[4] & self::BZ2) {
+ $data = bzdecompress($data);
+ }
+
+ if (strlen($data) != $entry[0]) {
+ die("Invalid internal .phar file (size error " . strlen($data) . " != " .
+ $stat[7] . ")");
+ }
+
+ if ($entry[3] != sprintf("%u", crc32($data) & 0xffffffff)) {
+ die("Invalid internal .phar file (checksum error)");
+ }
+
+ return $data;
+ }
+
+ static function _removeTmpFiles($temp, $origdir)
+ {
+ chdir($temp);
+
+ foreach (glob('*') as $f) {
+ if (file_exists($f)) {
+ is_dir($f) ? @rmdir($f) : @unlink($f);
+ if (file_exists($f) && is_dir($f)) {
+ self::_removeTmpFiles($f, getcwd());
+ }
+ }
+ }
+
+ @rmdir($temp);
+ clearstatcache();
+ chdir($origdir);
+ }
+}
diff --git a/ext/phar/stream.c b/ext/phar/stream.c
new file mode 100644
index 0000000000..3d9f14e4d4
--- /dev/null
+++ b/ext/phar/stream.c
@@ -0,0 +1,845 @@
+/*
+ +----------------------------------------------------------------------+
+ | phar:// stream wrapper support |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 2005-2008 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt. |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gregory Beaver <cellog@php.net> |
+ | Marcus Boerger <helly@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#define PHAR_STREAM 1
+#include "phar_internal.h"
+#include "stream.h"
+#include "dirstream.h"
+
+php_stream_ops phar_ops = {
+ phar_stream_write, /* write */
+ phar_stream_read, /* read */
+ phar_stream_close, /* close */
+ phar_stream_flush, /* flush */
+ "phar stream",
+ phar_stream_seek, /* seek */
+ NULL, /* cast */
+ phar_stream_stat, /* stat */
+ NULL, /* set option */
+};
+
+php_stream_wrapper_ops phar_stream_wops = {
+ phar_wrapper_open_url,
+ NULL, /* phar_wrapper_close */
+ NULL, /* phar_wrapper_stat, */
+ phar_wrapper_stat, /* stat_url */
+ phar_wrapper_open_dir, /* opendir */
+ "phar",
+ phar_wrapper_unlink, /* unlink */
+ phar_wrapper_rename, /* rename */
+ phar_wrapper_mkdir, /* create directory */
+ phar_wrapper_rmdir, /* remove directory */
+};
+
+php_stream_wrapper php_stream_phar_wrapper = {
+ &phar_stream_wops,
+ NULL,
+ 0 /* is_url */
+};
+
+/**
+ * Open a phar file for streams API
+ */
+php_url* phar_open_url(php_stream_wrapper *wrapper, char *filename, char *mode, int options TSRMLS_DC) /* {{{ */
+{
+ php_url *resource;
+ char *arch = NULL, *entry = NULL, *error;
+ int arch_len, entry_len;
+
+ if (strlen(filename) < 7 || strncasecmp(filename, "phar://", 7)) {
+ return NULL;
+ }
+ if (mode[0] == 'a') {
+ if (!(options & PHP_STREAM_URL_STAT_QUIET)) {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: open mode append not supported");
+ }
+ return NULL;
+ }
+ if (phar_split_fname(filename, strlen(filename), &arch, &arch_len, &entry, &entry_len, 2, (mode[0] == 'w' ? 2 : 0) TSRMLS_CC) == FAILURE) {
+ if (!(options & PHP_STREAM_URL_STAT_QUIET)) {
+ if (arch && !entry) {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: no directory in \"%s\", must have at least phar://%s/ for root directory (always use full path to a new phar)", filename, arch);
+ arch = NULL;
+ } else {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: invalid url or non-existent phar \"%s\"", filename);
+ }
+ }
+ return NULL;
+ }
+ resource = ecalloc(1, sizeof(php_url));
+ resource->scheme = estrndup("phar", 4);
+ resource->host = arch;
+
+ resource->path = entry;
+#if MBO_0
+ if (resource) {
+ fprintf(stderr, "Alias: %s\n", alias);
+ fprintf(stderr, "Scheme: %s\n", resource->scheme);
+/* fprintf(stderr, "User: %s\n", resource->user);*/
+/* fprintf(stderr, "Pass: %s\n", resource->pass ? "***" : NULL);*/
+ fprintf(stderr, "Host: %s\n", resource->host);
+/* fprintf(stderr, "Port: %d\n", resource->port);*/
+ fprintf(stderr, "Path: %s\n", resource->path);
+/* fprintf(stderr, "Query: %s\n", resource->query);*/
+/* fprintf(stderr, "Fragment: %s\n", resource->fragment);*/
+ }
+#endif
+ if (mode[0] == 'w' || (mode[0] == 'r' && mode[1] == '+')) {
+ phar_archive_data **pphar = NULL;
+
+ if (PHAR_GLOBALS->request_init && PHAR_GLOBALS->phar_fname_map.arBuckets && FAILURE == zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **)&pphar)) {
+ pphar = NULL;
+ }
+ if (PHAR_G(readonly) && (!pphar || !(*pphar)->is_data)) {
+ if (!(options & PHP_STREAM_URL_STAT_QUIET)) {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: write operations disabled by INI setting");
+ }
+ php_url_free(resource);
+ return NULL;
+ }
+ if (phar_open_or_create_filename(resource->host, arch_len, NULL, 0, 0, options, NULL, &error TSRMLS_CC) == FAILURE)
+ {
+ if (error) {
+ if (!(options & PHP_STREAM_URL_STAT_QUIET)) {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, error);
+ }
+ efree(error);
+ }
+ php_url_free(resource);
+ return NULL;
+ }
+ } else {
+ if (phar_open_filename(resource->host, arch_len, NULL, 0, options, NULL, &error TSRMLS_CC) == FAILURE)
+ {
+ if (error) {
+ if (!(options & PHP_STREAM_URL_STAT_QUIET)) {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, error);
+ }
+ efree(error);
+ }
+ php_url_free(resource);
+ return NULL;
+ }
+ }
+ return resource;
+}
+/* }}} */
+
+/**
+ * used for fopen('phar://...') and company
+ */
+static php_stream * phar_wrapper_open_url(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC) /* {{{ */
+{
+ phar_entry_data *idata;
+ char *internal_file;
+ char *error;
+ HashTable *pharcontext;
+ php_url *resource = NULL;
+ php_stream *fpf;
+ zval **pzoption, *metadata;
+ uint host_len;
+
+ if ((resource = phar_open_url(wrapper, path, mode, options TSRMLS_CC)) == NULL) {
+ return NULL;
+ }
+
+ /* we must have at the very least phar://alias.phar/internalfile.php */
+ if (!resource->scheme || !resource->host || !resource->path) {
+ php_url_free(resource);
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: invalid url \"%s\"", path);
+ return NULL;
+ }
+
+ if (strcasecmp("phar", resource->scheme)) {
+ php_url_free(resource);
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: not a phar stream url \"%s\"", path);
+ return NULL;
+ }
+
+ host_len = strlen(resource->host);
+ phar_request_initialize(TSRMLS_C);
+
+ /* strip leading "/" */
+ internal_file = estrdup(resource->path + 1);
+ if (mode[0] == 'w' || (mode[0] == 'r' && mode[1] == '+')) {
+ if (NULL == (idata = phar_get_or_create_entry_data(resource->host, host_len, internal_file, strlen(internal_file), mode, 0, &error TSRMLS_CC))) {
+ if (error) {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, error);
+ efree(error);
+ } else {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: file \"%s\" could not be created in phar \"%s\"", internal_file, resource->host);
+ }
+ efree(internal_file);
+ php_url_free(resource);
+ return NULL;
+ }
+ if (error) {
+ efree(error);
+ }
+ fpf = php_stream_alloc(&phar_ops, idata, NULL, mode);
+ php_url_free(resource);
+ efree(internal_file);
+ if (context && context->options && zend_hash_find(HASH_OF(context->options), "phar", sizeof("phar"), (void**)&pzoption) == SUCCESS) {
+ pharcontext = HASH_OF(*pzoption);
+ if (idata->internal_file->uncompressed_filesize == 0
+ && idata->internal_file->compressed_filesize == 0
+ && zend_hash_find(pharcontext, "compress", sizeof("compress"), (void**)&pzoption) == SUCCESS
+ && Z_TYPE_PP(pzoption) == IS_LONG
+ && (Z_LVAL_PP(pzoption) & ~PHAR_ENT_COMPRESSION_MASK) == 0
+ ) {
+ idata->internal_file->flags &= ~PHAR_ENT_COMPRESSION_MASK;
+ idata->internal_file->flags |= Z_LVAL_PP(pzoption);
+ }
+ if (zend_hash_find(pharcontext, "metadata", sizeof("metadata"), (void**)&pzoption) == SUCCESS) {
+ if (idata->internal_file->metadata) {
+ zval_ptr_dtor(&idata->internal_file->metadata);
+ idata->internal_file->metadata = NULL;
+ }
+
+ MAKE_STD_ZVAL(idata->internal_file->metadata);
+ metadata = *pzoption;
+ ZVAL_ZVAL(idata->internal_file->metadata, metadata, 1, 0);
+ idata->phar->is_modified = 1;
+ }
+ }
+ if (opened_path) {
+ spprintf(opened_path, MAXPATHLEN, "phar://%s/%s", idata->phar->fname, idata->internal_file->filename);
+ }
+ return fpf;
+ } else {
+ if ((FAILURE == phar_get_entry_data(&idata, resource->host, host_len, internal_file, strlen(internal_file), "r", 0, &error TSRMLS_CC)) || !idata) {
+ if (error) {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, error);
+ efree(error);
+ } else {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: \"%s\" is not a file in phar \"%s\"", internal_file, resource->host);
+ }
+ efree(internal_file);
+ php_url_free(resource);
+ return NULL;
+ }
+ }
+ php_url_free(resource);
+
+#if MBO_0
+ fprintf(stderr, "Pharname: %s\n", idata->phar->filename);
+ fprintf(stderr, "Filename: %s\n", internal_file);
+ fprintf(stderr, "Entry: %s\n", idata->internal_file->filename);
+ fprintf(stderr, "Size: %u\n", idata->internal_file->uncompressed_filesize);
+ fprintf(stderr, "Compressed: %u\n", idata->internal_file->flags);
+ fprintf(stderr, "Offset: %u\n", idata->internal_file->offset_within_phar);
+ fprintf(stderr, "Cached: %s\n", idata->internal_file->filedata ? "yes" : "no");
+#endif
+
+ /* check length, crc32 */
+ if (!idata->internal_file->is_crc_checked && phar_postprocess_file(wrapper, options, idata, idata->internal_file->crc32, &error TSRMLS_CC) != SUCCESS) {
+ /* already issued the error */
+ phar_entry_delref(idata TSRMLS_CC);
+ efree(internal_file);
+ return NULL;
+ }
+
+ if (!PHAR_G(cwd_init) && options & STREAM_OPEN_FOR_INCLUDE) {
+ char *entry = idata->internal_file->filename, *cwd;
+
+ PHAR_G(cwd_init) = 1;
+ if ((idata->phar->is_tar || idata->phar->is_zip) && idata->internal_file->filename_len == sizeof(".phar/stub.php")-1 && !strncmp(idata->internal_file->filename, ".phar/stub.php", sizeof(".phar/stub.php")-1)) {
+ /* we're executing the stub, which doesn't count as a file */
+ PHAR_G(cwd_init) = 0;
+ } else if ((cwd = strrchr(entry, '/'))) {
+ PHAR_G(cwd_len) = cwd - entry;
+ PHAR_G(cwd) = estrndup(entry, PHAR_G(cwd_len));
+ } else {
+ /* root directory */
+ PHAR_G(cwd_len) = 0;
+ PHAR_G(cwd) = NULL;
+ }
+ }
+ fpf = php_stream_alloc(&phar_ops, idata, NULL, mode);
+ if (opened_path) {
+ spprintf(opened_path, MAXPATHLEN, "phar://%s/%s", idata->phar->fname, idata->internal_file->filename);
+ }
+ efree(internal_file);
+ return fpf;
+}
+/* }}} */
+
+/**
+ * Used for fclose($fp) where $fp is a phar archive
+ */
+static int phar_stream_close(php_stream *stream, int close_handle TSRMLS_DC) /* {{{ */
+{
+ phar_entry_delref((phar_entry_data *)stream->abstract TSRMLS_CC);
+
+ return 0;
+}
+/* }}} */
+
+/**
+ * used for fread($fp) and company on a fopen()ed phar file handle
+ */
+static size_t phar_stream_read(php_stream *stream, char *buf, size_t count TSRMLS_DC) /* {{{ */
+{
+ phar_entry_data *data = (phar_entry_data *)stream->abstract;
+ size_t got;
+
+ if (data->internal_file->is_deleted) {
+ stream->eof = 1;
+ return 0;
+ }
+
+ /* use our proxy position */
+ php_stream_seek(data->fp, data->position + data->zero, SEEK_SET);
+
+ got = php_stream_read(data->fp, buf, MIN(count, data->internal_file->uncompressed_filesize - data->position));
+ data->position = php_stream_tell(data->fp) - data->zero;
+ stream->eof = (data->position == (off_t) data->internal_file->uncompressed_filesize);
+
+
+ return got;
+}
+/* }}} */
+
+/**
+ * Used for fseek($fp) on a phar file handle
+ */
+static int phar_stream_seek(php_stream *stream, off_t offset, int whence, off_t *newoffset TSRMLS_DC) /* {{{ */
+{
+ phar_entry_data *data = (phar_entry_data *)stream->abstract;
+
+ int res;
+ off_t temp;
+ switch (whence) {
+ case SEEK_END :
+ temp = data->zero + data->internal_file->uncompressed_filesize + offset;
+ break;
+ case SEEK_CUR :
+ temp = data->zero + data->position + offset;
+ break;
+ case SEEK_SET :
+ temp = data->zero + offset;
+ break;
+ }
+ if (temp > data->zero + (off_t) data->internal_file->uncompressed_filesize) {
+ *newoffset = -1;
+ return -1;
+ }
+ if (temp < data->zero) {
+ *newoffset = -1;
+ return -1;
+ }
+ res = php_stream_seek(data->fp, temp, SEEK_SET);
+ *newoffset = php_stream_tell(data->fp) - data->zero;
+ data->position = *newoffset;
+ return res;
+}
+/* }}} */
+
+/**
+ * Used for writing to a phar file
+ */
+static size_t phar_stream_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC) /* {{{ */
+{
+ phar_entry_data *data = (phar_entry_data *) stream->abstract;
+
+ php_stream_seek(data->fp, data->position, SEEK_SET);
+ if (count != php_stream_write(data->fp, buf, count)) {
+ php_stream_wrapper_log_error(stream->wrapper, stream->flags TSRMLS_CC, "phar error: Could not write %d characters to \"%s\" in phar \"%s\"", (int) count, data->internal_file->filename, data->phar->fname);
+ return -1;
+ }
+ data->position = php_stream_tell(data->fp);
+ if (data->position > (off_t)data->internal_file->uncompressed_filesize) {
+ data->internal_file->uncompressed_filesize = data->position;
+ }
+ data->internal_file->compressed_filesize = data->internal_file->uncompressed_filesize;
+ data->internal_file->old_flags = data->internal_file->flags;
+ data->internal_file->is_modified = 1;
+ return count;
+}
+/* }}} */
+
+/**
+ * Used to save work done on a writeable phar
+ */
+static int phar_stream_flush(php_stream *stream TSRMLS_DC) /* {{{ */
+{
+ char *error;
+ int ret;
+ if (stream->mode[0] == 'w' || (stream->mode[0] == 'r' && stream->mode[1] == '+')) {
+ ret = phar_flush(((phar_entry_data *)stream->abstract)->phar, 0, 0, 0, &error TSRMLS_CC);
+ if (error) {
+ php_stream_wrapper_log_error(stream->wrapper, REPORT_ERRORS TSRMLS_CC, error);
+ efree(error);
+ }
+ return ret;
+ } else {
+ return EOF;
+ }
+}
+/* }}} */
+
+ /* {{{ phar_dostat */
+/**
+ * stat an opened phar file handle stream, used by phar_stat()
+ */
+void phar_dostat(phar_archive_data *phar, phar_entry_info *data, php_stream_statbuf *ssb,
+ zend_bool is_temp_dir, char *alias, int alias_len TSRMLS_DC)
+{
+ char *tmp;
+ int tmp_len;
+ memset(ssb, 0, sizeof(php_stream_statbuf));
+
+ if (!is_temp_dir && !data->is_dir) {
+ ssb->sb.st_size = data->uncompressed_filesize;
+ ssb->sb.st_mode = data->flags & PHAR_ENT_PERM_MASK;
+ ssb->sb.st_mode |= S_IFREG; /* regular file */
+ /* timestamp is just the timestamp when this was added to the phar */
+#ifdef NETWARE
+ ssb->sb.st_mtime.tv_sec = data->timestamp;
+ ssb->sb.st_atime.tv_sec = data->timestamp;
+ ssb->sb.st_ctime.tv_sec = data->timestamp;
+#else
+ ssb->sb.st_mtime = data->timestamp;
+ ssb->sb.st_atime = data->timestamp;
+ ssb->sb.st_ctime = data->timestamp;
+#endif
+ } else if (!is_temp_dir && data->is_dir) {
+ ssb->sb.st_size = 0;
+ ssb->sb.st_mode = data->flags & PHAR_ENT_PERM_MASK;
+ ssb->sb.st_mode |= S_IFDIR; /* regular directory */
+ /* timestamp is just the timestamp when this was added to the phar */
+#ifdef NETWARE
+ ssb->sb.st_mtime.tv_sec = data->timestamp;
+ ssb->sb.st_atime.tv_sec = data->timestamp;
+ ssb->sb.st_ctime.tv_sec = data->timestamp;
+#else
+ ssb->sb.st_mtime = data->timestamp;
+ ssb->sb.st_atime = data->timestamp;
+ ssb->sb.st_ctime = data->timestamp;
+#endif
+ } else {
+ ssb->sb.st_size = 0;
+ ssb->sb.st_mode = 0777;
+ ssb->sb.st_mode |= S_IFDIR; /* regular directory */
+#ifdef NETWARE
+ ssb->sb.st_mtime.tv_sec = phar->max_timestamp;
+ ssb->sb.st_atime.tv_sec = phar->max_timestamp;
+ ssb->sb.st_ctime.tv_sec = phar->max_timestamp;
+#else
+ ssb->sb.st_mtime = phar->max_timestamp;
+ ssb->sb.st_atime = phar->max_timestamp;
+ ssb->sb.st_ctime = phar->max_timestamp;
+#endif
+ }
+ if (!phar->is_writeable) {
+ ssb->sb.st_mode = (ssb->sb.st_mode & 0555) | (ssb->sb.st_mode & ~0777);
+ }
+
+ ssb->sb.st_nlink = 1;
+ ssb->sb.st_rdev = -1;
+ if (data) {
+ tmp_len = data->filename_len + alias_len;
+ } else {
+ tmp_len = alias_len + 1;
+ }
+ tmp = (char *) emalloc(tmp_len);
+ memcpy(tmp, alias, alias_len);
+ if (data) {
+ memcpy(tmp + alias_len, data->filename, data->filename_len);
+ } else {
+ *(tmp+alias_len) = '/';
+ }
+ /* this is only for APC, so use /dev/null device - no chance of conflict there! */
+ ssb->sb.st_dev = 0xc;
+ /* generate unique inode number for alias/filename, so no phars will conflict */
+ ssb->sb.st_ino = (unsigned short)zend_get_hash_value(tmp, tmp_len);
+ efree(tmp);
+#ifndef PHP_WIN32
+ ssb->sb.st_blksize = -1;
+ ssb->sb.st_blocks = -1;
+#endif
+}
+/* }}}*/
+
+/**
+ * Stat an opened phar file handle
+ */
+static int phar_stream_stat(php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC) /* {{{ */
+{
+ phar_entry_data *data = (phar_entry_data *)stream->abstract;
+
+ /* If ssb is NULL then someone is misbehaving */
+ if (!ssb) {
+ return -1;
+ }
+
+ phar_dostat(data->phar, data->internal_file, ssb, 0, data->phar->alias, data->phar->alias_len TSRMLS_CC);
+ return 0;
+}
+/* }}} */
+
+/**
+ * Stream wrapper stat implementation of stat()
+ */
+static int phar_wrapper_stat(php_stream_wrapper *wrapper, char *url, int flags,
+ php_stream_statbuf *ssb, php_stream_context *context TSRMLS_DC) /* {{{ */
+{
+ php_url *resource = NULL;
+ char *internal_file, *key, *error;
+ uint keylen;
+ ulong unused;
+ phar_archive_data *phar;
+ phar_entry_info *entry;
+ uint host_len;
+ int internal_file_len;
+
+ if ((resource = phar_open_url(wrapper, url, "r", flags|PHP_STREAM_URL_STAT_QUIET TSRMLS_CC)) == NULL) {
+ return FAILURE;
+ }
+
+ /* we must have at the very least phar://alias.phar/internalfile.php */
+ if (!resource->scheme || !resource->host || !resource->path) {
+ php_url_free(resource);
+ return FAILURE;
+ }
+
+ if (strcasecmp("phar", resource->scheme)) {
+ php_url_free(resource);
+ return FAILURE;
+ }
+
+ host_len = strlen(resource->host);
+ phar_request_initialize(TSRMLS_C);
+
+ internal_file = resource->path + 1; /* strip leading "/" */
+ /* find the phar in our trusty global hash indexed by alias (host of phar://blah.phar/file.whatever) */
+ if (FAILURE == phar_get_archive(&phar, resource->host, strlen(resource->host), NULL, 0, &error TSRMLS_CC)) {
+ php_url_free(resource);
+ if (error) {
+ efree(error);
+ }
+ return FAILURE;
+ }
+ if (error) {
+ efree(error);
+ }
+ if (*internal_file == '\0') {
+ /* root directory requested */
+ phar_dostat(phar, NULL, ssb, 1, phar->alias, phar->alias_len TSRMLS_CC);
+ php_url_free(resource);
+ return SUCCESS;
+ }
+ if (!phar->manifest.arBuckets) {
+ php_url_free(resource);
+ return FAILURE;
+ }
+ internal_file_len = strlen(internal_file);
+ /* search through the manifest of files, and if we have an exact match, it's a file */
+ if (SUCCESS == zend_hash_find(&phar->manifest, internal_file, internal_file_len, (void**)&entry)) {
+ phar_dostat(phar, entry, ssb, 0, phar->alias, phar->alias_len TSRMLS_CC);
+ php_url_free(resource);
+ return SUCCESS;
+ } else {
+ /* search for directory (partial match of a file) */
+ zend_hash_internal_pointer_reset(&phar->manifest);
+ while (FAILURE != zend_hash_has_more_elements(&phar->manifest)) {
+ if (HASH_KEY_NON_EXISTANT !=
+ zend_hash_get_current_key_ex(
+ &phar->manifest, &key, &keylen, &unused, 0, NULL)) {
+ if (keylen >= (uint)internal_file_len && 0 == memcmp(internal_file, key, internal_file_len)) {
+ /* directory found, all dirs have the same stat */
+ if (key[internal_file_len] == '/') {
+ phar_dostat(phar, NULL, ssb, 1, phar->alias, phar->alias_len TSRMLS_CC);
+ php_url_free(resource);
+ return SUCCESS;
+ }
+ }
+ }
+ if (SUCCESS != zend_hash_move_forward(&phar->manifest)) {
+ break;
+ }
+ }
+ /* check for mounted directories */
+ if (phar->mounted_dirs.arBuckets && zend_hash_num_elements(&phar->mounted_dirs)) {
+ char *key;
+ ulong unused;
+ uint keylen;
+
+ zend_hash_internal_pointer_reset(&phar->mounted_dirs);
+ while (FAILURE != zend_hash_has_more_elements(&phar->mounted_dirs)) {
+ if (HASH_KEY_NON_EXISTANT == zend_hash_get_current_key_ex(&phar->mounted_dirs, &key, &keylen, &unused, 0, NULL)) {
+ break;
+ }
+ if ((int)keylen >= internal_file_len || strncmp(key, internal_file, keylen)) {
+ continue;
+ } else {
+ char *test;
+ int test_len;
+ phar_entry_info *entry;
+ php_stream_statbuf ssbi;
+
+ if (SUCCESS != zend_hash_find(&phar->manifest, key, keylen, (void **) &entry)) {
+ goto free_resource;
+ }
+ if (!entry->tmp || !entry->is_mounted) {
+ goto free_resource;
+ }
+ test_len = spprintf(&test, MAXPATHLEN, "%s%s", entry->tmp, internal_file + keylen);
+ if (SUCCESS != php_stream_stat_path(test, &ssbi)) {
+ efree(test);
+ continue;
+ }
+ /* mount the file/directory just in time */
+ if (SUCCESS != phar_mount_entry(phar, test, test_len, internal_file, internal_file_len TSRMLS_CC)) {
+ efree(test);
+ goto free_resource;
+ }
+ efree(test);
+ if (SUCCESS != zend_hash_find(&phar->manifest, internal_file, internal_file_len, (void**)&entry)) {
+ goto free_resource;
+ }
+ phar_dostat(phar, entry, ssb, 0, phar->alias, phar->alias_len TSRMLS_CC);
+ php_url_free(resource);
+ return SUCCESS;
+ }
+ }
+ }
+ }
+
+free_resource:
+ php_url_free(resource);
+ return FAILURE;
+}
+/* }}} */
+
+/**
+ * Unlink a file within a phar archive
+ */
+static int phar_wrapper_unlink(php_stream_wrapper *wrapper, char *url, int options, php_stream_context *context TSRMLS_DC) /* {{{ */
+{
+ php_url *resource;
+ char *internal_file, *error;
+ phar_entry_data *idata;
+ phar_archive_data **pphar;
+ uint host_len;
+
+ if ((resource = phar_open_url(wrapper, url, "rb", options TSRMLS_CC)) == NULL) {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: unlink failed");
+ return 0;
+ }
+
+ /* we must have at the very least phar://alias.phar/internalfile.php */
+ if (!resource->scheme || !resource->host || !resource->path) {
+ php_url_free(resource);
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: invalid url \"%s\"", url);
+ return 0;
+ }
+
+ if (strcasecmp("phar", resource->scheme)) {
+ php_url_free(resource);
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: not a phar stream url \"%s\"", url);
+ return 0;
+ }
+
+ host_len = strlen(resource->host);
+ phar_request_initialize(TSRMLS_C);
+
+ if (FAILURE == zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), resource->host, strlen(resource->host), (void **) &pphar)) {
+ pphar = NULL;
+ }
+ if (PHAR_G(readonly) && (!pphar || !(*pphar)->is_data)) {
+ php_url_free(resource);
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: write operations disabled by INI setting");
+ return 0;
+ }
+
+ /* need to copy to strip leading "/", will get touched again */
+ internal_file = estrdup(resource->path + 1);
+ if (FAILURE == phar_get_entry_data(&idata, resource->host, strlen(resource->host), internal_file, strlen(internal_file), "r", 0, &error TSRMLS_CC)) {
+ /* constraints of fp refcount were not met */
+ if (error) {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "unlink of \"%s\" failed: %s", url, error);
+ efree(error);
+ } else {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "unlink of \"%s\" failed, file does not exist", url);
+ }
+ efree(internal_file);
+ php_url_free(resource);
+ return 0;
+ }
+ if (error) {
+ efree(error);
+ }
+ if (idata->internal_file->fp_refcount > 1) {
+ /* more than just our fp resource is open for this file */
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: \"%s\" in phar \"%s\", has open file pointers, cannot unlink", internal_file, resource->host);
+ efree(internal_file);
+ php_url_free(resource);
+ phar_entry_delref(idata TSRMLS_CC);
+ return 0;
+ }
+ php_url_free(resource);
+ efree(internal_file);
+ phar_entry_remove(idata, &error TSRMLS_CC);
+ if (error) {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, error);
+ efree(error);
+ }
+ return 1;
+}
+/* }}} */
+
+static int phar_wrapper_rename(php_stream_wrapper *wrapper, char *url_from, char *url_to, int options, php_stream_context *context TSRMLS_DC) /* {{{ */
+{
+ php_url *resource_from, *resource_to;
+ char *error;
+ phar_archive_data *phar, *pfrom, *pto;
+ phar_entry_info *entry;
+ uint host_len;
+
+ error = NULL;
+
+ if ((resource_from = phar_open_url(wrapper, url_from, "wb", options|PHP_STREAM_URL_STAT_QUIET TSRMLS_CC)) == NULL) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": invalid or non-writable url \"%s\"", url_from, url_to, url_from);
+ return 0;
+ }
+ if (SUCCESS != phar_get_archive(&pfrom, resource_from->host, strlen(resource_from->host), NULL, 0, &error TSRMLS_CC)) {
+ pfrom = NULL;
+ if (error) {
+ efree(error);
+ }
+ }
+ if (PHAR_G(readonly) && (!pfrom || !pfrom->is_data)) {
+ php_url_free(resource_from);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: write operations disabled by phar.readonly INI setting");
+ return 0;
+ }
+
+ if ((resource_to = phar_open_url(wrapper, url_to, "wb", options|PHP_STREAM_URL_STAT_QUIET TSRMLS_CC)) == NULL) {
+ php_url_free(resource_from);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": invalid or non-writable url \"%s\"", url_from, url_to, url_to);
+ return 0;
+ }
+ if (SUCCESS != phar_get_archive(&pto, resource_to->host, strlen(resource_to->host), NULL, 0, &error TSRMLS_CC)) {
+ if (error) {
+ efree(error);
+ }
+ pto = NULL;
+ }
+ if (PHAR_G(readonly) && (!pto || !pto->is_data)) {
+ php_url_free(resource_from);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: write operations disabled by phar.readonly INI setting");
+ return 0;
+ }
+
+ if (strcmp(resource_from->host, resource_to->host)) {
+ php_url_free(resource_from);
+ php_url_free(resource_to);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\", not within the same phar archive", url_from, url_to);
+ return 0;
+ }
+
+ /* we must have at the very least phar://alias.phar/internalfile.php */
+ if (!resource_from->scheme || !resource_from->host || !resource_from->path) {
+ php_url_free(resource_from);
+ php_url_free(resource_to);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": invalid url \"%s\"", url_from, url_to, url_from);
+ return 0;
+ }
+
+ if (!resource_to->scheme || !resource_to->host || !resource_to->path) {
+ php_url_free(resource_from);
+ php_url_free(resource_to);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": invalid url \"%s\"", url_from, url_to, url_to);
+ return 0;
+ }
+
+ if (strcasecmp("phar", resource_from->scheme)) {
+ php_url_free(resource_from);
+ php_url_free(resource_to);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": not a phar stream url \"%s\"", url_from, url_to, url_from);
+ return 0;
+ }
+
+ if (strcasecmp("phar", resource_to->scheme)) {
+ php_url_free(resource_from);
+ php_url_free(resource_to);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": not a phar stream url \"%s\"", url_from, url_to, url_to);
+ return 0;
+ }
+
+ host_len = strlen(resource_from->host);
+ phar_request_initialize(TSRMLS_C);
+
+ if (SUCCESS != phar_get_archive(&phar, resource_from->host, strlen(resource_from->host), NULL, 0, &error TSRMLS_CC)) {
+ php_url_free(resource_from);
+ php_url_free(resource_to);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": %s", url_from, url_to, error);
+ efree(error);
+ return 0;
+ }
+
+ if (SUCCESS == zend_hash_find(&(phar->manifest), resource_from->path+1, strlen(resource_from->path)-1, (void **)&entry)) {
+ phar_entry_info new, *source;
+
+ /* perform rename magic */
+ if (entry->is_deleted) {
+ php_url_free(resource_from);
+ php_url_free(resource_to);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\" from extracted phar archive, source has been deleted", url_from, url_to);
+ return 0;
+ }
+ /* transfer all data over to the new entry */
+ memcpy((void *) &new, (void *) entry, sizeof(phar_entry_info));
+ /* mark the old one for deletion */
+ entry->is_deleted = 1;
+ entry->fp = NULL;
+ entry->metadata = 0;
+ entry->link = entry->tmp = NULL;
+ source = entry;
+
+ /* add to the manifest, and then store the pointer to the new guy in entry */
+ zend_hash_add(&(phar->manifest), resource_to->path+1, strlen(resource_to->path)-1, (void **)&new, sizeof(phar_entry_info), (void **) &entry);
+
+ entry->filename = estrdup(resource_to->path+1);
+ if (FAILURE == phar_copy_entry_fp(source, entry, &error TSRMLS_CC)) {
+ php_url_free(resource_from);
+ php_url_free(resource_to);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": %s", url_from, url_to, error);
+ efree(error);
+ zend_hash_del(&(phar->manifest), entry->filename, strlen(entry->filename));
+ return 0;
+ }
+ entry->is_modified = 1;
+ entry->filename_len = strlen(entry->filename);
+ phar_flush(phar, 0, 0, 0, &error TSRMLS_CC);
+ if (error) {
+ php_url_free(resource_from);
+ php_url_free(resource_to);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": %s", url_from, url_to, error);
+ efree(error);
+ zend_hash_del(&(phar->manifest), entry->filename, strlen(entry->filename));
+ return 0;
+ }
+ }
+ php_url_free(resource_from);
+ php_url_free(resource_to);
+ return 1;
+}
+/* }}} */
diff --git a/ext/phar/stream.h b/ext/phar/stream.h
new file mode 100644
index 0000000000..f273acb0aa
--- /dev/null
+++ b/ext/phar/stream.h
@@ -0,0 +1,49 @@
+/*
+ +----------------------------------------------------------------------+
+ | phar php single-file executable PHP extension |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 2006-2007 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt. |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gregory Beaver <cellog@php.net> |
+ | Marcus Boerger <helly@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+BEGIN_EXTERN_C()
+int phar_postprocess_file(php_stream_wrapper *wrapper, int options, phar_entry_data *idata, php_uint32 crc32, char **error TSRMLS_DC);
+
+php_url* phar_open_url(php_stream_wrapper *wrapper, char *filename, char *mode, int options TSRMLS_DC);
+void phar_entry_remove(phar_entry_data *idata, char **error TSRMLS_DC);
+
+static php_stream* phar_wrapper_open_url(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC);
+static int phar_wrapper_rename(php_stream_wrapper *wrapper, char *url_from, char *url_to, int options, php_stream_context *context TSRMLS_DC);
+static int phar_wrapper_unlink(php_stream_wrapper *wrapper, char *url, int options, php_stream_context *context TSRMLS_DC);
+static int phar_wrapper_stat(php_stream_wrapper *wrapper, char *url, int flags, php_stream_statbuf *ssb, php_stream_context *context TSRMLS_DC);
+
+/* file/stream handlers */
+static size_t phar_stream_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC);
+static size_t phar_stream_read( php_stream *stream, char *buf, size_t count TSRMLS_DC);
+static int phar_stream_close(php_stream *stream, int close_handle TSRMLS_DC);
+static int phar_stream_flush(php_stream *stream TSRMLS_DC);
+static int phar_stream_seek( php_stream *stream, off_t offset, int whence, off_t *newoffset TSRMLS_DC);
+static int phar_stream_stat( php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC);
+END_EXTERN_C()
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
diff --git a/ext/phar/stub.h b/ext/phar/stub.h
new file mode 100644
index 0000000000..f5858e2f07
--- /dev/null
+++ b/ext/phar/stub.h
@@ -0,0 +1,33 @@
+/*
+ +----------------------------------------------------------------------+
+ | phar php single-file executable PHP extension generated stub |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 2005-2008 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt. |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gregory Beaver <cellog@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+static inline void phar_get_stub(const char *index_php, const char *web, size_t *len, char **stub, const int name_len, const int web_len TSRMLS_DC)
+{
+ static const char newstub0[] = "<?php\n\n$web = '";
+ static const char newstub1_0[] = "';\n\nif (in_array('phar', stream_get_wrappers()) && class_exists('Phar', 0)) {\nPhar::interceptFileFuncs();\nset_include_path('phar://' . __FILE__ . PATH_SEPARATOR . get_include_path());\nPhar::webPhar(null, $web);\ninclude 'phar://' . __FILE__ . '/' . Extract_Phar::START;\nreturn;\n}\n\nif (@(isset($_SERVER['REQUEST_URI']) && isset($_SERVER['REQUEST_METHOD']) && ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'POST'))) {\nExtract_Phar::go(true);\n$mimes = array(\n'phps' => 2,\n'c' => 'text/plain',\n'cc' => 'text/plain',\n'cpp' => 'text/plain',\n'c++' => 'text/plain',\n'dtd' => 'text/plain',\n'h' => 'text/plain',\n'log' => 'text/plain',\n'rng' => 'text/plain',\n'txt' => 'text/plain',\n'xsd' => 'text/plain',\n'php' => 1,\n'inc' => 1,\n'avi' => 'video/avi',\n'bmp' => 'image/bmp',\n'css' => 'text/css',\n'gif' => 'image/gif',\n'htm' => 'text/html',\n'html' => 'text/html',\n'htmls' => 'text/html',\n'ico' => 'image/x-ico',\n'jpe' => 'image/jpeg',\n'jpg' => 'image/jpeg',\n'jpeg' => 'image/jpeg',\n'js' => 'application/x-javascript',\n'midi' => 'audio/midi',\n'mid' => 'audio/midi',\n'mod' => 'audio/mod',\n'mov' => 'movie/quicktime',\n'mp3' => 'audio/mp3',\n'mpg' => 'video/mpeg',\n'mpeg' => 'video/mpeg',\n'pdf' => 'application/pdf',\n'png' => 'image/png',\n'swf' => 'application/shockwave-flash',\n'tif' => 'image/tiff',\n'tiff' => 'image/tiff',\n'wav' => 'audio/wav',\n'xbm' => 'image/xbm',\n'xml' => 'text/xml',\n);\n\nheader(\"Cache-Control: no-cache, must-revalidate\");\nheader(\"Pragma: no-cache\");\n\n$basename = basename(__FILE__);\nif (!strpos($_SERVER['REQUEST_URI'], $basename)) {\nchdir(Extract_Phar::$temp);\ninclude $web;\nreturn;\n}\n$pt = substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], $basename) + strlen($basename));\nif (!$pt || $pt == '/') {\n$pt = $web;\nheader('HTTP/1.1 301 Moved Permanently');\nheader('Location: ' . $_SERVER['REQUEST_URI'] . '/' . $pt);\nexit;\n}\n$a = realpath(Extract_Phar::$temp . DIRECTORY_SEPARATOR . $pt);\nif (!$a || strlen(dirname($a)) < strlen(";
+ static const char newstub1_1[] = "Extract_Phar::$temp)) {\nheader('HTTP/1.0 404 Not Found');\necho \"<html>\\n <head>\\n <title>File Not Found<title>\\n </head>\\n <body>\\n <h1>404 - File \", $pt, \" Not Found</h1>\\n </body>\\n</html>\";\nexit;\n}\n$b = pathinfo($a);\nif (!isset($b['extension'])) {\nheader('Content-Type: text/plain');\nheader('Content-Length: ' . filesize($a));\nreadfile($a);\nexit;\n}\nif (isset($mimes[$b['extension']])) {\nif ($mimes[$b['extension']] === 1) {\ninclude $a;\nexit;\n}\nif ($mimes[$b['extension']] === 2) {\nhighlight_file($a);\nexit;\n}\nheader('Content-Type: ' .$mimes[$b['extension']]);\nheader('Content-Length: ' . filesize($a));\nreadfile($a);\nexit;\n}\n}\n\nclass Extract_Phar\n{\nstatic $temp;\nstatic $origdir;\nconst GZ = 0x1000;\nconst BZ2 = 0x2000;\nconst MASK = 0x3000;\nconst START = '";
+ static const char newstub2[] = "';\nconst LEN = ";
+ static const char newstub3_0[] = ";\n\nstatic function go($return = false)\n{\n$fp = fopen(__FILE__, 'rb');\nfseek($fp, self::LEN);\n$L = unpack('V', $a = fread($fp, 4));\n$m = '';\n\ndo {\n$read = 8192;\nif ($L[1] - strlen($m) < 8192) {\n$read = $L[1] - strlen($m);\n}\n$last = fread($fp, $read);\n$m .= $last;\n} while (strlen($last) && strlen($m) < $L[1]);\n\nif (strlen($m) < $L[1]) {\ndie('ERROR: manifest length read was \"' .\nstrlen($m) .'\" should be \"' .\n$L[1] . '\"');\n}\n\n$info = self::_unpack($m);\n$f = $info['c'];\n\nif ($f & self::GZ) {\nif (!function_exists('gzinflate')) {\ndie('Error: zlib extension is not enabled -' .\n' gzinflate() function needed for zlib-compressed .phars');\n}\n}\n\nif ($f & self::BZ2) {\nif (!function_exists('bzdecompress')) {\ndie('Error: bzip2 extension is not enabled -' .\n' bzdecompress() function needed for bz2-compressed .phars');\n}\n}\n\n$temp = self::tmpdir();\n\nif (!$temp || !is_writable($temp)) {\n$sessionpath = session_save_path();\nif (strpos ($sessionpath, \";\") !== false)\n$sessionpath = substr ($sessionpath, strpos ($sessionpath, \";\")+1);\nif (!file_exists($sessionpath) || !is_dir($sessionpath)) {\ndie('Could not locate temporary directory to extract phar');\n}\n$temp = $sessionpath;\n}\n\n$temp .= '/pharextract/'.basename(__FILE__, '.phar');\nself::$temp = $temp;\nself::$origdir = getcwd();\n@mkdir($temp, 0777, true);\n$temp = realpath($temp);\n\nif (!file_exists($temp . DIRECTORY_SEPARATOR . md5_file(__FILE__))) {\nself::_removeTmpFiles($temp, getcwd());\n@mkdir($temp, 0777, true);\n@file_put_contents($temp . '/' . md5_file(__FILE__), '');\n\nforeach ($info['m'] as $path => $file) {\n$a = !file_exists(dirname($temp . '/' . $path));\n@mkdir(dirname($temp . '/' . $path), 0777, true);\nclearstatcache();\n\nif ($path[strlen($path) - 1] == '/') {\n@mkdir($temp . '/' . $path, 0777);\n} else {\nfile_put_contents($temp . '/' . $path, self::extractFile($path, $file, $fp));\n@chmod($temp . '/' . $path, 0666);\n}\n}\n}\n\nchdir($temp);\n\nif (!$return) {\ninclude self::START;\n}\n}\n\nstatic fun";
+ static const char newstub3_1[] = "ction tmpdir()\n{\nif (strpos(PHP_OS, 'WIN') !== false) {\nif ($var = getenv('TMP') ? getenv('TMP') : getenv('TEMP')) {\nreturn $var;\n}\nif (is_dir('/temp') || mkdir('/temp')) {\nreturn realpath('/temp');\n}\nreturn false;\n}\nif ($var = getenv('TMPDIR')) {\nreturn $var;\n}\nreturn realpath('/tmp');\n}\n\nstatic function _unpack($m)\n{\n$info = unpack('V', substr($m, 0, 4));\n $l = unpack('V', substr($m, 10, 4));\n$m = substr($m, 14 + $l[1]);\n$s = unpack('V', substr($m, 0, 4));\n$o = 0;\n$start = 4 + $s[1];\n$ret['c'] = 0;\n\nfor ($i = 0; $i < $info[1]; $i++) {\n $len = unpack('V', substr($m, $start, 4));\n$start += 4;\n $savepath = substr($m, $start, $len[1]);\n$start += $len[1];\n $ret['m'][$savepath] = array_values(unpack('Va/Vb/Vc/Vd/Ve/Vf', substr($m, $start, 24)));\n$ret['m'][$savepath][3] = sprintf('%u', $ret['m'][$savepath][3]\n& 0xffffffff);\n$ret['m'][$savepath][7] = $o;\n$o += $ret['m'][$savepath][2];\n$start += 24 + $ret['m'][$savepath][5];\n$ret['c'] |= $ret['m'][$savepath][4] & self::MASK;\n}\nreturn $ret;\n}\n\nstatic function extractFile($path, $entry, $fp)\n{\n$data = '';\n$c = $entry[2];\n\nwhile ($c) {\nif ($c < 8192) {\n$data .= @fread($fp, $c);\n$c = 0;\n} else {\n$c -= 8192;\n$data .= @fread($fp, 8192);\n}\n}\n\nif ($entry[4] & self::GZ) {\n$data = gzinflate($data);\n} elseif ($entry[4] & self::BZ2) {\n$data = bzdecompress($data);\n}\n\nif (strlen($data) != $entry[0]) {\ndie(\"Invalid internal .phar file (size error \" . strlen($data) . \" != \" .\n$stat[7] . \")\");\n}\n\nif ($entry[3] != sprintf(\"%u\", crc32($data) & 0xffffffff)) {\ndie(\"Invalid internal .phar file (checksum error)\");\n}\n\nreturn $data;\n}\n\nstatic function _removeTmpFiles($temp, $origdir)\n{\nchdir($temp);\n\nforeach (glob('*') as $f) {\nif (file_exists($f)) {\nis_dir($f) ? @rmdir($f) : @unlink($f);\nif (file_exists($f) && is_dir($f)) {\nself::_removeTmpFiles($f, getcwd());\n}\n}\n}\n\n@rmdir($temp);\nclearstatcache();\nchdir($origdir);\n}\n}\n\nExtract_Phar::go();\n__HALT_COMPILER(); ?>";
+
+ static const int newstub_len = 6633;
+
+ *len = spprintf(stub, name_len + web_len + newstub_len, "%s%s%s%s%s%s%d%s%s", newstub0, web, newstub1_0, newstub1_1, index_php, newstub2, name_len + web_len + newstub_len, newstub3_0, newstub3_1);
+}
diff --git a/ext/phar/tar.c b/ext/phar/tar.c
new file mode 100644
index 0000000000..ac19ef3f68
--- /dev/null
+++ b/ext/phar/tar.c
@@ -0,0 +1,831 @@
+/*
+ +----------------------------------------------------------------------+
+ | TAR archive support for Phar |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 2005-2008 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt. |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Dmitry Stogov <dmitry@zend.com> |
+ | Gregory Beaver <cellog@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#include "phar_internal.h"
+
+static php_uint32 phar_tar_number(char *buf, int len) /* {{{ */
+{
+ php_uint32 num = 0;
+ int i = 0;
+
+ while (i < len && buf[i] == ' ') {
+ ++i;
+ }
+ while (i < len &&
+ buf[i] >= '0' &&
+ buf[i] <= '7') {
+ num = num * 8 + (buf[i] - '0');
+ ++i;
+ }
+ return num;
+}
+/* }}} */
+
+/* adapted from format_octal() in libarchive
+ *
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+static int phar_tar_octal(char *buf, php_uint32 val, int len) /* {{{ */
+{
+ char *p = buf;
+ int s = len;
+
+ p += len; /* Start at the end and work backwards. */
+ while (s-- > 0) {
+ *--p = (char)('0' + (val & 7));
+ val >>= 3;
+ }
+
+ if (val == 0)
+ return SUCCESS;
+
+ /* If it overflowed, fill field with max value. */
+ while (len-- > 0)
+ *p++ = '7';
+
+ return FAILURE;
+}
+/* }}} */
+
+static php_uint32 phar_tar_checksum(char *buf, int len) /* {{{ */
+{
+ php_uint32 sum = 0;
+ char *end = buf + len;
+
+ while (buf != end) {
+ sum += (unsigned char)*buf;
+ ++buf;
+ }
+ return sum;
+}
+/* }}} */
+
+int phar_is_tar(char *buf, char *fname)
+{
+ tar_header *header = (tar_header *) buf;
+ php_uint32 checksum = phar_tar_number(header->checksum, sizeof(header->checksum));
+ php_uint32 ret;
+ char save[sizeof(header->checksum)];
+
+ /* assume that the first filename in a tar won't begin with <?php */
+ if (!strncmp(buf, "<?php", sizeof("<?php")-1)) {
+ return 0;
+ }
+
+ memcpy(save, header->checksum, sizeof(header->checksum));
+ memset(header->checksum, ' ', sizeof(header->checksum));
+ ret = (checksum == phar_tar_checksum(buf, 512));
+ memcpy(header->checksum, save, sizeof(header->checksum));
+ if (!ret && strstr(fname, ".tar")) {
+ /* probably a corrupted tar - so we will pretend it is one */
+ return 1;
+ }
+ return ret;
+}
+
+int phar_open_or_create_tar(char *fname, int fname_len, char *alias, int alias_len, int is_data, int options, phar_archive_data** pphar, char **error TSRMLS_DC) /* {{{ */
+{
+ phar_archive_data *phar;
+ int ret = phar_create_or_parse_filename(fname, fname_len, alias, alias_len, is_data, options, &phar, error TSRMLS_CC);
+
+ if (FAILURE == ret) {
+ return FAILURE;
+ }
+
+ if (pphar) {
+ *pphar = phar;
+ }
+
+ phar->is_data = is_data;
+
+ if (phar->is_tar) {
+ return ret;
+ }
+
+ if (phar->is_brandnew) {
+ phar->is_tar = 1;
+ phar->internal_file_start = 0;
+ return SUCCESS;
+ }
+
+ /* we've reached here - the phar exists and is a regular phar */
+ if (error) {
+ spprintf(error, 4096, "phar tar error: \"%s\" already exists as a regular phar and must be deleted from disk prior to creating as a tar-based phar", fname);
+ }
+ return FAILURE;
+}
+
+int phar_open_tarfile(php_stream* fp, char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, php_uint32 compression, char **error TSRMLS_DC) /* {{{ */
+{
+ char buf[512], *actual_alias = NULL, *p;
+ phar_entry_info entry = {0};
+ size_t pos = 0, read, totalsize;
+ tar_header *hdr;
+ php_uint32 sum1, sum2, size, old;
+ phar_archive_data *myphar, **actual;
+
+ if (error) {
+ *error = NULL;
+ }
+
+ php_stream_seek(fp, 0, SEEK_END);
+ totalsize = php_stream_tell(fp);
+ php_stream_seek(fp, 0, SEEK_SET);
+ read = php_stream_read(fp, buf, sizeof(buf));
+ if (read != sizeof(buf)) {
+ if (error) {
+ spprintf(error, 4096, "phar error: \"%s\" is not a tar file or is truncated", fname);
+ }
+ php_stream_close(fp);
+ return FAILURE;
+ }
+ hdr = (tar_header*)buf;
+ old = (memcmp(hdr->magic, "ustar", sizeof("ustar")-1) != 0);
+
+ myphar = (phar_archive_data *) ecalloc(1, sizeof(phar_archive_data));
+ zend_hash_init(&myphar->manifest, sizeof(phar_entry_info),
+ zend_get_hash_value, destroy_phar_manifest_entry, 0);
+ zend_hash_init(&myphar->mounted_dirs, sizeof(char *),
+ zend_get_hash_value, NULL, 0);
+ myphar->is_tar = 1;
+ /* remember whether this entire phar was compressed with gz/bzip2 */
+ myphar->flags = compression;
+
+ entry.is_tar = 1;
+ entry.is_crc_checked = 1;
+ entry.phar = myphar;
+ do {
+ pos += sizeof(buf);
+ hdr = (tar_header*) buf;
+ sum1 = phar_tar_number(hdr->checksum, sizeof(hdr->checksum));
+ if (sum1 == 0 && phar_tar_checksum(buf, sizeof(buf)) == 0) {
+ break;
+ }
+ memset(hdr->checksum, ' ', sizeof(hdr->checksum));
+ sum2 = phar_tar_checksum(buf, old?sizeof(old_tar_header):sizeof(tar_header));
+
+ size = entry.uncompressed_filesize = entry.compressed_filesize =
+ phar_tar_number(hdr->size, sizeof(hdr->size));
+
+ if (!old && hdr->prefix[0] != 0) {
+ char name[256];
+
+ strcpy(name, hdr->prefix);
+ /* remove potential buffer overflow */
+ if (hdr->name[99]) {
+ strncat(name, hdr->name, 100);
+ } else {
+ strcat(name, hdr->name);
+ }
+ entry.filename_len = strlen(hdr->prefix) + 100;
+ if (name[entry.filename_len - 1] == '/') {
+ /* some tar programs store directories with trailing slash */
+ entry.filename_len--;
+ }
+ entry.filename = estrndup(name, entry.filename_len);
+ } else {
+ entry.filename = estrdup(hdr->name);
+ entry.filename_len = strlen(entry.filename);
+ if (entry.filename[entry.filename_len - 1] == '/') {
+ /* some tar programs store directories with trailing slash */
+ entry.filename[entry.filename_len - 1] = '\0';
+ entry.filename_len--;
+ }
+ }
+ if (sum1 != sum2) {
+ if (error) {
+ spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file (checksum mismatch of file \"%s\")", fname, entry.filename);
+ }
+ efree(entry.filename);
+ php_stream_close(fp);
+ zend_hash_destroy(&myphar->manifest);
+ myphar->manifest.arBuckets = 0;
+ zend_hash_destroy(&myphar->mounted_dirs);
+ myphar->mounted_dirs.arBuckets = 0;
+ efree(myphar);
+ return FAILURE;
+ }
+
+ entry.tar_type = ((old & (hdr->typeflag == 0))?'0':hdr->typeflag);
+ entry.offset = entry.offset_abs = pos; /* header_offset unused in tar */
+ entry.fp_type = PHAR_FP;
+ entry.flags = phar_tar_number(hdr->mode, sizeof(hdr->mode)) & PHAR_ENT_PERM_MASK;
+ entry.timestamp = phar_tar_number(hdr->mtime, sizeof(hdr->mtime));
+
+#ifndef S_ISDIR
+#define S_ISDIR(mode) (((mode)&S_IFMT) == S_IFDIR)
+#endif
+ if (old && entry.tar_type == TAR_FILE && S_ISDIR(entry.flags)) {
+ entry.tar_type = TAR_DIR;
+ }
+ if (entry.tar_type == TAR_DIR) {
+ entry.is_dir = 1;
+ } else {
+ entry.is_dir = 0;
+ }
+
+ entry.link = NULL;
+ if (entry.tar_type == TAR_LINK) {
+ if (!zend_hash_exists(&myphar->manifest, hdr->linkname, strlen(hdr->linkname))) {
+ if (error) {
+ spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file - hard link to non-existent file \"%s\"", fname, hdr->linkname);
+ }
+ efree(entry.filename);
+ php_stream_close(fp);
+ zend_hash_destroy(&myphar->manifest);
+ myphar->manifest.arBuckets = 0;
+ zend_hash_destroy(&myphar->mounted_dirs);
+ myphar->mounted_dirs.arBuckets = 0;
+ efree(myphar);
+ return FAILURE;
+ }
+ entry.link = estrdup(hdr->linkname);
+ } else if (entry.tar_type == TAR_SYMLINK) {
+ entry.link = estrdup(hdr->linkname);
+ }
+ zend_hash_add(&myphar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL);
+ if (!actual_alias && entry.filename_len == sizeof(".phar/alias.txt")-1 && !strncmp(entry.filename, ".phar/alias.txt", sizeof(".phar/alias.txt")-1)) {
+ size_t read;
+ /* found explicit alias */
+ if (size > 511) {
+ if (error) {
+ spprintf(error, 4096, "phar error: tar-based phar \"%s\" has alias that is larger than 511 bytes, cannot process", fname);
+ }
+ php_stream_close(fp);
+ zend_hash_destroy(&myphar->manifest);
+ myphar->manifest.arBuckets = 0;
+ zend_hash_destroy(&myphar->mounted_dirs);
+ myphar->mounted_dirs.arBuckets = 0;
+ efree(myphar);
+ return FAILURE;
+ }
+ read = php_stream_read(fp, buf, size);
+ if (read == size) {
+ buf[size] = '\0';
+ if (!phar_validate_alias(buf, size)) {
+ if (size > 50) {
+ buf[50] = '.';
+ buf[51] = '.';
+ buf[52] = '.';
+ buf[53] = '\0';
+ }
+ if (error) {
+ spprintf(error, 4096, "phar error: invalid alias \"%s\" in tar-based phar \"%s\"", buf, fname);
+ }
+ php_stream_close(fp);
+ zend_hash_destroy(&myphar->manifest);
+ myphar->manifest.arBuckets = 0;
+ zend_hash_destroy(&myphar->mounted_dirs);
+ myphar->mounted_dirs.arBuckets = 0;
+ efree(myphar);
+ return FAILURE;
+ }
+ actual_alias = estrndup(buf, size);
+ myphar->alias = actual_alias;
+ myphar->alias_len = size;
+ php_stream_seek(fp, pos, SEEK_SET);
+ } else {
+ if (error) {
+ spprintf(error, 4096, "phar error: Unable to read alias from tar-based phar \"%s\"", fname);
+ }
+ php_stream_close(fp);
+ zend_hash_destroy(&myphar->manifest);
+ myphar->manifest.arBuckets = 0;
+ zend_hash_destroy(&myphar->mounted_dirs);
+ myphar->mounted_dirs.arBuckets = 0;
+ efree(myphar);
+ return FAILURE;
+ }
+ }
+ size = (size+511)&~511;
+ pos += size;
+ if (((hdr->typeflag == 0) || (hdr->typeflag == TAR_FILE)) && size > 0) {
+ /* this is not good enough - seek succeeds even on truncated tars */
+ php_stream_seek(fp, size, SEEK_CUR);
+ if ((uint)php_stream_tell(fp) > totalsize) {
+ if (error) {
+ spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file (truncated)", fname);
+ }
+ php_stream_close(fp);
+ zend_hash_destroy(&myphar->manifest);
+ myphar->manifest.arBuckets = 0;
+ zend_hash_destroy(&myphar->mounted_dirs);
+ myphar->mounted_dirs.arBuckets = 0;
+ efree(myphar);
+ return FAILURE;
+ }
+ }
+ read = php_stream_read(fp, buf, sizeof(buf));
+ if (read != sizeof(buf)) {
+ if (error) {
+ spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file (truncated)", fname);
+ }
+ php_stream_close(fp);
+ zend_hash_destroy(&myphar->manifest);
+ myphar->manifest.arBuckets = 0;
+ zend_hash_destroy(&myphar->mounted_dirs);
+ myphar->mounted_dirs.arBuckets = 0;
+ efree(myphar);
+ return FAILURE;
+ }
+ } while (read != 0);
+ myphar->fname = estrndup(fname, fname_len);
+#ifdef PHP_WIN32
+ phar_unixify_path_separators(myphar->fname, fname_len);
+#endif
+ myphar->fname_len = fname_len;
+ p = strrchr(myphar->fname, '/');
+ if (p) {
+ myphar->ext = memchr(p, '.', (myphar->fname + fname_len) - p);
+ if (myphar->ext == p) {
+ myphar->ext = memchr(p + 1, '.', (myphar->fname + fname_len) - p - 1);
+ }
+ if (myphar->ext) {
+ myphar->ext_len = (myphar->fname + fname_len) - myphar->ext;
+ }
+ }
+ myphar->fp = fp;
+ phar_request_initialize(TSRMLS_C);
+ if (SUCCESS != zend_hash_add(&(PHAR_GLOBALS->phar_fname_map), myphar->fname, fname_len, (void*)&myphar, sizeof(phar_archive_data*), (void **)&actual)) {
+ if (error) {
+ spprintf(error, 4096, "phar error: Unable to add tar-based phar \"%s\" to phar registry", fname);
+ }
+ php_stream_close(fp);
+ zend_hash_destroy(&myphar->manifest);
+ myphar->manifest.arBuckets = 0;
+ zend_hash_destroy(&myphar->mounted_dirs);
+ myphar->mounted_dirs.arBuckets = 0;
+ efree(myphar);
+ return FAILURE;
+ }
+ myphar = *actual;
+ if (actual_alias) {
+ phar_archive_data **fd_ptr;
+
+ myphar->is_temporary_alias = 0;
+ if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), actual_alias, myphar->alias_len, (void **)&fd_ptr)) {
+ if (SUCCESS != phar_free_alias(*fd_ptr, actual_alias, myphar->alias_len TSRMLS_CC)) {
+ if (error) {
+ spprintf(error, 4096, "phar error: Unable to add tar-based phar \"%s\", alias is already in use", fname);
+ }
+ zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), myphar->fname, fname_len);
+ return FAILURE;
+ }
+ }
+ zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), actual_alias, myphar->alias_len, (void*)&myphar, sizeof(phar_archive_data*), NULL);
+ } else {
+ phar_archive_data **fd_ptr;
+
+ if (alias_len) {
+ if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void **)&fd_ptr)) {
+ if (SUCCESS != phar_free_alias(*fd_ptr, alias, alias_len TSRMLS_CC)) {
+ if (error) {
+ spprintf(error, 4096, "phar error: Unable to add tar-based phar \"%s\", alias is already in use", fname);
+ }
+ zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), myphar->fname, fname_len);
+ return FAILURE;
+ }
+ }
+ zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), actual_alias, myphar->alias_len, (void*)&myphar, sizeof(phar_archive_data*), NULL);
+ myphar->alias = estrndup(alias, alias_len);
+ myphar->alias_len = alias_len;
+ } else {
+ myphar->alias = estrndup(myphar->fname, fname_len);
+ myphar->alias_len = fname_len;
+ }
+ myphar->is_temporary_alias = 1;
+ }
+ if (pphar) {
+ *pphar = myphar;
+ }
+ return SUCCESS;
+}
+/* }}} */
+
+struct _phar_pass_tar_info {
+ php_stream *old;
+ php_stream *new;
+ int free_fp;
+ int free_ufp;
+ char **error;
+};
+
+int phar_tar_writeheaders(void *pDest, void *argument TSRMLS_DC)
+{
+ tar_header header;
+ size_t pos;
+ phar_entry_info *entry = (phar_entry_info *) pDest;
+ struct _phar_pass_tar_info *fp = (struct _phar_pass_tar_info *)argument;
+ char padding[512];
+
+ if (entry->is_mounted) {
+ return ZEND_HASH_APPLY_KEEP;
+ }
+ if (entry->is_deleted) {
+ if (entry->fp_refcount <= 0) {
+ return ZEND_HASH_APPLY_REMOVE;
+ } else {
+ /* we can't delete this in-memory until it is closed */
+ return ZEND_HASH_APPLY_KEEP;
+ }
+ }
+
+ memset((char *) &header, 0, sizeof(header));
+ if (entry->filename_len > 100) {
+ if (entry->filename_len > 255) {
+ if (fp->error) {
+ spprintf(fp->error, 4096, "tar-based phar \"%s\" cannot be created, filename \"%s\" is too long for tar file format", entry->phar->fname, entry->filename);
+ }
+ return ZEND_HASH_APPLY_STOP;
+ }
+ memcpy(header.prefix, entry->filename+100, entry->filename_len - 100);
+ memcpy(header.name, entry->filename, 100);
+ } else {
+ memcpy(header.name, entry->filename, entry->filename_len);
+ }
+ phar_tar_octal(header.mode, entry->flags & PHAR_ENT_PERM_MASK, sizeof(header.mode)-1);
+ if (FAILURE == phar_tar_octal(header.size, entry->uncompressed_filesize, sizeof(header.size)-1)) {
+ if (fp->error) {
+ spprintf(fp->error, 4096, "tar-based phar \"%s\" cannot be created, filename \"%s\" is too large for tar file format", entry->phar->fname, entry->filename);
+ }
+ return ZEND_HASH_APPLY_STOP;
+ }
+ if (FAILURE == phar_tar_octal(header.mtime, entry->timestamp, sizeof(header.mtime)-1)) {
+ if (fp->error) {
+ spprintf(fp->error, 4096, "tar-based phar \"%s\" cannot be created, file modification time of file \"%s\" is too large for tar file format", entry->phar->fname, entry->filename);
+ }
+ return ZEND_HASH_APPLY_STOP;
+ }
+ /* calc checksum */
+ header.typeflag = entry->tar_type;
+ if (entry->link) {
+ strncpy(header.linkname, entry->link, strlen(entry->link));
+ }
+ strncpy(header.magic, "ustar", sizeof("ustar")-1);
+ strncpy(header.version, "00", sizeof("00")-1);
+ strncpy(header.checksum, " ", sizeof(" ")-1);
+ entry->crc32 = phar_tar_checksum((char *)&header, sizeof(header));
+ if (FAILURE == phar_tar_octal(header.checksum, entry->crc32, sizeof(header.checksum)-1)) {
+ if (fp->error) {
+ spprintf(fp->error, 4096, "tar-based phar \"%s\" cannot be created, checksum of file \"%s\" is too large for tar file format", entry->phar->fname, entry->filename);
+ }
+ return ZEND_HASH_APPLY_STOP;
+ }
+
+ /* write header */
+ entry->header_offset = php_stream_tell(fp->new);
+ if (sizeof(header) != php_stream_write(fp->new, (char *) &header, sizeof(header))) {
+ if (fp->error) {
+ spprintf(fp->error, 4096, "tar-based phar \"%s\" cannot be created, header for file \"%s\" could not be written", entry->phar->fname, entry->filename);
+ }
+ return ZEND_HASH_APPLY_STOP;
+ }
+ pos = php_stream_tell(fp->new); /* save start of file within tar */
+
+ /* write contents */
+ if (entry->uncompressed_filesize) {
+ if (FAILURE == phar_open_entry_fp(entry, fp->error, 0 TSRMLS_CC)) {
+ return ZEND_HASH_APPLY_STOP;
+ }
+ if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC)) {
+ if (fp->error) {
+ spprintf(fp->error, 4096, "tar-based phar \"%s\" cannot be created, contents of file \"%s\" could not be written, seek failed", entry->phar->fname, entry->filename);
+ }
+ return ZEND_HASH_APPLY_STOP;
+ }
+ if (entry->uncompressed_filesize != php_stream_copy_to_stream(phar_get_efp(entry, 0 TSRMLS_CC), fp->new, entry->uncompressed_filesize)) {
+ if (fp->error) {
+ spprintf(fp->error, 4096, "tar-based phar \"%s\" cannot be created, contents of file \"%s\" could not be written", entry->phar->fname, entry->filename);
+ }
+ return ZEND_HASH_APPLY_STOP;
+ }
+
+ memset(padding, 0, 512);
+ php_stream_write(fp->new, padding, ((entry->uncompressed_filesize +511)&~511) - entry->uncompressed_filesize);
+ }
+ if (!entry->is_modified && entry->fp_refcount) {
+ /* open file pointers refer to this fp, do not free the stream */
+ switch (entry->fp_type) {
+ case PHAR_FP:
+ fp->free_fp = 0;
+ break;
+ case PHAR_UFP:
+ fp->free_ufp = 0;
+ default:
+ break;
+ }
+ }
+
+ entry->is_modified = 0;
+ if (entry->fp_type == PHAR_MOD && entry->fp != entry->phar->fp && entry->fp != entry->phar->ufp) {
+ if (!entry->fp_refcount) {
+ php_stream_close(entry->fp);
+ }
+ entry->fp = NULL;
+ }
+ entry->fp_type = PHAR_FP;
+
+ /* note new location within tar */
+ entry->offset = entry->offset_abs = pos;
+ return ZEND_HASH_APPLY_KEEP;
+}
+
+int phar_tar_flush(phar_archive_data *phar, char *user_stub, long len, int defaultstub, char **error TSRMLS_DC) /* {{{ */
+{
+ phar_entry_info entry = {0};
+ static const char newstub[] = "<?php // tar-based phar archive stub file\n__HALT_COMPILER();";
+ php_stream *oldfile, *newfile, *stubfile;
+ int closeoldfile, free_user_stub;
+ struct _phar_pass_tar_info pass;
+ char *buf;
+
+ entry.flags = PHAR_ENT_PERM_DEF_FILE;
+ entry.timestamp = time(NULL);
+ entry.is_modified = 1;
+ entry.is_crc_checked = 1;
+ entry.is_tar = 1;
+ entry.tar_type = '0';
+ entry.phar = phar;
+ entry.fp_type = PHAR_MOD;
+
+ if (phar->is_data) {
+ goto nostub;
+ }
+
+ /* set alias */
+ if (!phar->is_temporary_alias && phar->alias_len) {
+ entry.filename = estrndup(".phar/alias.txt", sizeof(".phar/alias.txt")-1);
+ entry.filename_len = sizeof(".phar/alias.txt")-1;
+ entry.fp = php_stream_fopen_tmpfile();
+ entry.crc32 = phar_tar_checksum(phar->alias, phar->alias_len);
+ if (phar->alias_len != (int)php_stream_write(entry.fp, phar->alias, phar->alias_len)) {
+ if (error) {
+ spprintf(error, 0, "unable to set alias in tar-based phar \"%s\"", phar->fname);
+ }
+ return EOF;
+ }
+ entry.uncompressed_filesize = phar->alias_len;
+ if (SUCCESS != zend_hash_update(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL)) {
+ if (error) {
+ spprintf(error, 0, "unable to set alias in tar-based phar \"%s\"", phar->fname);
+ }
+ return EOF;
+ }
+ } else {
+ zend_hash_del(&phar->manifest, ".phar/alias.txt", sizeof(".phar/alias.txt")-1);
+ }
+
+ /* set stub */
+ if (user_stub && !defaultstub) {
+ char *pos;
+ if (len < 0) {
+ /* resource passed in */
+ if (!(php_stream_from_zval_no_verify(stubfile, (zval **)user_stub))) {
+ if (error) {
+ spprintf(error, 0, "unable to access resource to copy stub to new tar-based phar \"%s\"", phar->fname);
+ }
+ return EOF;
+ }
+ if (len == -1) {
+ len = PHP_STREAM_COPY_ALL;
+ } else {
+ len = -len;
+ }
+ user_stub = 0;
+ if (!(len = php_stream_copy_to_mem(stubfile, &user_stub, len, 0)) || !user_stub) {
+ if (error) {
+ spprintf(error, 0, "unable to read resource to copy stub to new tar-based phar \"%s\"", phar->fname);
+ }
+ return EOF;
+ }
+ free_user_stub = 1;
+ } else {
+ free_user_stub = 0;
+ }
+ if ((pos = strstr(user_stub, "__HALT_COMPILER();")) == NULL)
+ {
+ if (error) {
+ spprintf(error, 0, "illegal stub for tar-based phar \"%s\"", phar->fname);
+ }
+ if (free_user_stub) {
+ efree(user_stub);
+ }
+ return EOF;
+ }
+ len = pos - user_stub + 18;
+ entry.fp = php_stream_fopen_tmpfile();
+ entry.uncompressed_filesize = len + 5;
+
+ if ((size_t)len != php_stream_write(entry.fp, user_stub, len)
+ || 5 != php_stream_write(entry.fp, " ?>\r\n", 5)) {
+ if (error) {
+ spprintf(error, 0, "unable to create stub from string in new tar-based phar \"%s\"", phar->fname);
+ }
+ if (free_user_stub) {
+ efree(user_stub);
+ }
+ php_stream_close(entry.fp);
+ return EOF;
+ }
+ entry.filename = estrndup(".phar/stub.php", sizeof(".phar/stub.php")-1);
+ entry.filename_len = sizeof(".phar/stub.php")-1;
+ zend_hash_update(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL);
+ if (free_user_stub) {
+ efree(user_stub);
+ }
+ } else {
+ /* Either this is a brand new phar (add the stub), or the default stub is required (overwrite the stub) */
+ entry.fp = php_stream_fopen_tmpfile();
+
+ if (sizeof(newstub)-1 != php_stream_write(entry.fp, newstub, sizeof(newstub)-1)) {
+ php_stream_close(entry.fp);
+ if (error) {
+ spprintf(error, 0, "unable to %s stub in%star-based phar \"%s\", failed", user_stub ? "overwrite" : "create", user_stub ? " " : " new ", phar->fname);
+ }
+ return EOF;
+ }
+
+ entry.uncompressed_filesize = entry.compressed_filesize = sizeof(newstub) - 1;
+ entry.filename = estrndup(".phar/stub.php", sizeof(".phar/stub.php")-1);
+ entry.filename_len = sizeof(".phar/stub.php")-1;
+
+ if (!defaultstub) {
+ if (!zend_hash_exists(&phar->manifest, ".phar/stub.php", sizeof(".phar/stub.php")-1)) {
+ if (SUCCESS != zend_hash_add(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL)) {
+ php_stream_close(entry.fp);
+ efree(entry.filename);
+ if (error) {
+ spprintf(error, 0, "unable to create stub in tar-based phar \"%s\"", phar->fname);
+ }
+ return EOF;
+ }
+ } else {
+ php_stream_close(entry.fp);
+ efree(entry.filename);
+ }
+ } else {
+ if (SUCCESS != zend_hash_update(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL)) {
+ php_stream_close(entry.fp);
+ efree(entry.filename);
+ if (error) {
+ spprintf(error, 0, "unable to overwrite stub in tar-based phar \"%s\"", phar->fname);
+ }
+ return EOF;
+ }
+ }
+ }
+
+nostub:
+
+ if (phar->fp && !phar->is_brandnew) {
+ oldfile = phar->fp;
+ closeoldfile = 0;
+ php_stream_rewind(oldfile);
+ } else {
+ oldfile = php_stream_open_wrapper(phar->fname, "rb", 0, NULL);
+ closeoldfile = oldfile != NULL;
+ }
+ newfile = php_stream_fopen_tmpfile();
+ if (!newfile) {
+ if (error) {
+ spprintf(error, 0, "unable to create temporary file");
+ }
+ if (closeoldfile) {
+ php_stream_close(oldfile);
+ }
+ return EOF;
+ }
+
+ pass.old = oldfile;
+ pass.new = newfile;
+ pass.error = error;
+ pass.free_fp = 1;
+ pass.free_ufp = 1;
+
+ zend_hash_apply_with_argument(&phar->manifest, (apply_func_arg_t) phar_tar_writeheaders, (void *) &pass TSRMLS_CC);
+
+ /* add final zero blocks */
+ buf = (char *) ecalloc(1024, 1);
+ php_stream_write(newfile, buf, 1024);
+ efree(buf);
+
+ if (closeoldfile) {
+ php_stream_close(oldfile);
+ }
+ /* on error in the hash iterator above, error is set */
+ if (error && *error) {
+ php_stream_close(newfile);
+ return EOF;
+ }
+ if (phar->fp && pass.free_fp) {
+ php_stream_close(phar->fp);
+ }
+ if (phar->ufp) {
+ if (pass.free_ufp) {
+ php_stream_close(phar->ufp);
+ }
+ phar->ufp = NULL;
+ }
+
+ phar->is_brandnew = 0;
+
+ php_stream_rewind(newfile);
+
+ if (phar->donotflush) {
+ /* deferred flush */
+ phar->fp = newfile;
+ } else {
+ phar->fp = php_stream_open_wrapper(phar->fname, "w+b", IGNORE_URL|STREAM_MUST_SEEK|REPORT_ERRORS, NULL);
+ if (!phar->fp) {
+ phar->fp = newfile;
+ if (error) {
+ spprintf(error, 0, "unable to open new phar \"%s\" for writing", phar->fname);
+ }
+ return EOF;
+ }
+ if (phar->flags & PHAR_FILE_COMPRESSED_GZ) {
+ php_stream_filter *filter;
+ /* to properly compress, we have to tell zlib to add a zlib header */
+ zval filterparams;
+
+ array_init(&filterparams);
+/* this is defined in zlib's zconf.h */
+#ifndef MAX_WBITS
+#define MAX_WBITS 15
+#endif
+ add_assoc_long(&filterparams, "window", MAX_WBITS + 16);
+ filter = php_stream_filter_create("zlib.deflate", &filterparams, php_stream_is_persistent(phar->fp) TSRMLS_CC);
+ zval_dtor(&filterparams);
+ if (!filter) {
+ /* copy contents uncompressed rather than lose them */
+ php_stream_copy_to_stream(newfile, phar->fp, PHP_STREAM_COPY_ALL);
+ php_stream_close(newfile);
+ if (error) {
+ 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);
+ }
+ return EOF;
+ }
+ php_stream_filter_append(&phar->fp->writefilters, filter);
+ php_stream_copy_to_stream(newfile, phar->fp, PHP_STREAM_COPY_ALL);
+ php_stream_filter_flush(filter, 1);
+ php_stream_filter_remove(filter, 1 TSRMLS_CC);
+ php_stream_close(phar->fp);
+ /* use the temp stream as our base */
+ phar->fp = newfile;
+ } else if (phar->flags & PHAR_FILE_COMPRESSED_BZ2) {
+ php_stream_filter *filter;
+
+ filter = php_stream_filter_create("bzip2.compress", NULL, php_stream_is_persistent(phar->fp) TSRMLS_CC);
+ php_stream_filter_append(&phar->fp->writefilters, filter);
+ php_stream_copy_to_stream(newfile, phar->fp, PHP_STREAM_COPY_ALL);
+ php_stream_filter_flush(filter, 1);
+ php_stream_filter_remove(filter, 1 TSRMLS_CC);
+ php_stream_close(phar->fp);
+ /* use the temp stream as our base */
+ phar->fp = newfile;
+ } else {
+ php_stream_copy_to_stream(newfile, phar->fp, PHP_STREAM_COPY_ALL);
+ /* we could also reopen the file in "rb" mode but there is no need for that */
+ php_stream_close(newfile);
+ }
+ }
+ return EOF;
+}
+/* }}} */
diff --git a/ext/phar/tar.h b/ext/phar/tar.h
new file mode 100644
index 0000000000..6dc1fd3127
--- /dev/null
+++ b/ext/phar/tar.h
@@ -0,0 +1,90 @@
+#ifndef __PHAR_TAR_H
+#define __PHAR_TAR_H
+/*
+ +----------------------------------------------------------------------+
+ | TAR archive support for Phar |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 2005-2008 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt. |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Dmitry Stogov <dmitry@zend.com> |
+ | Gregory Beaver <cellog@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#ifdef PHP_WIN32
+#pragma pack(1)
+# define PHAR_TAR_PACK
+#else
+# define PHAR_TAR_PACK __attribute__((__packed__))
+#endif
+/**
+ * the format of the header block for a file, in the older UNIX-compatible
+ * TAR format
+ */
+typedef struct _old_tar_header { /* {{{ */
+ char name[100]; /* name of file;
+ directory is indicated by a trailing slash (/) */
+ char mode[8]; /* file mode */
+ char uid[8]; /* owner user ID */
+ char gid[8]; /* owner group ID */
+ char size[12]; /* length of file in bytes */
+ char mtime[12]; /* modify time of file */
+ char checksum[8]; /* checksum for header */
+ char link; /* indicator for links;
+ 1 for a linked file,
+ 2 for a symbolic link,
+ 0 otherwise */
+ char linkname[100]; /* name of linked file */
+} PHAR_TAR_PACK old_tar_header;
+/* }}} */
+
+/**
+ * the new USTAR header format.
+ * Note that tar can determine that the USTAR format is being used by the
+ * presence of the null-terminated string "ustar" in the magic field.
+ */
+typedef struct _tar_header { /* {{{ */
+ char name[100]; /* name of file */
+ char mode[8]; /* file mode */
+ char uid[8]; /* owner user ID */
+ char gid[8]; /* owner group ID */
+ char size[12]; /* length of file in bytes */
+ char mtime[12]; /* modify time of file */
+ char checksum[8]; /* checksum for header */
+ char typeflag; /* type of file
+ 0 Regular file
+ 1 Link to another file already archived
+ 2 Symbolic link
+ 3 Character special device
+ 4 Block special device
+ 5 Directory
+ 6 FIFO special file
+ 7 Reserved */
+ char linkname[100]; /* name of linked file */
+ char magic[6]; /* USTAR indicator */
+ char version[2]; /* USTAR version */
+ char uname[32]; /* owner user name */
+ char gname[32]; /* owner group name */
+ char devmajor[8]; /* device major number */
+ char devminor[8]; /* device minor number */
+ char prefix[155]; /* prefix for file name;
+ the value of the prefix field, if non-null,
+ is prefixed to the name field to allow names
+ longer then 100 characters */
+ char padding[12]; /* unused zeroed bytes */
+} PHAR_TAR_PACK tar_header;
+/* }}} */
+
+#ifdef PHP_WIN32
+#pragma pack()
+#endif
+
+#endif /* __PHAR_TAR_H */
diff --git a/ext/phar/tests/001.phpt b/ext/phar/tests/001.phpt
new file mode 100644
index 0000000000..1205e4e1aa
--- /dev/null
+++ b/ext/phar/tests/001.phpt
@@ -0,0 +1,12 @@
+--TEST--
+Phar::apiVersion
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--FILE--
+<?php
+var_dump(Phar::apiVersion());
+?>
+===DONE===
+--EXPECT--
+string(5) "1.1.1"
+===DONE===
diff --git a/ext/phar/tests/002.phpt b/ext/phar/tests/002.phpt
new file mode 100644
index 0000000000..a7cf0cb2d2
--- /dev/null
+++ b/ext/phar/tests/002.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Phar::mapPhar truncated manifest/improper params
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--FILE--
+<?php
+try {
+Phar::mapPhar(5, 'hio', 'hi');
+
+Phar::mapPhar();
+} catch (Exception $e) {
+ echo $e->getMessage();
+}
+__HALT_COMPILER(); ?>
+--EXPECTF--
+Warning: Phar::mapPhar() expects at most 2 parameters, 3 given in %s002.php on line %d
+internal corruption of phar "%s002.php" (truncated manifest at manifest length) \ No newline at end of file
diff --git a/ext/phar/tests/003.phpt b/ext/phar/tests/003.phpt
new file mode 100644
index 0000000000..fcc95a8481
--- /dev/null
+++ b/ext/phar/tests/003.phpt
@@ -0,0 +1,13 @@
+--TEST--
+Phar::canCompress
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--FILE--
+<?php
+/* check this works and actually returns the boolean value */
+var_dump(Phar::canCompress() == (
+ extension_loaded("zlib") || extension_loaded("bz2")
+ ));
+?>
+--EXPECT--
+bool(true)
diff --git a/ext/phar/tests/003a.phpt b/ext/phar/tests/003a.phpt
new file mode 100755
index 0000000000..37e31072d4
--- /dev/null
+++ b/ext/phar/tests/003a.phpt
@@ -0,0 +1,14 @@
+--TEST--
+Phar::canCompress, specific
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--FILE--
+<?php
+var_dump(Phar::canCompress(Phar::GZ) == extension_loaded("zlib"));
+var_dump(Phar::canCompress(Phar::BZ2) == extension_loaded("bz2"));
+?>
+===DONE===
+--EXPECT--
+bool(true)
+bool(true)
+===DONE===
diff --git a/ext/phar/tests/004.phpt b/ext/phar/tests/004.phpt
new file mode 100644
index 0000000000..963a9b45a0
--- /dev/null
+++ b/ext/phar/tests/004.phpt
@@ -0,0 +1,14 @@
+--TEST--
+Phar::mapPhar no __HALT_COMPILER();
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip");?>
+--FILE--
+<?php
+try {
+Phar::mapPhar('hio');
+} catch (Exception $e) {
+echo $e->getMessage();
+}
+?>
+--EXPECTF--
+__HALT_COMPILER(); must be declared in a phar
diff --git a/ext/phar/tests/005.phpt b/ext/phar/tests/005.phpt
new file mode 100644
index 0000000000..a6e3449016
--- /dev/null
+++ b/ext/phar/tests/005.phpt
@@ -0,0 +1,14 @@
+--TEST--
+Phar::mapPhar truncated manifest (none)
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip");?>
+--FILE--
+<?php
+try {
+Phar::mapPhar('hio');
+} catch (Exception $e) {
+echo $e->getMessage();
+}
+__HALT_COMPILER(); ?>()
+--EXPECTF--
+internal corruption of phar "%s" (truncated manifest at manifest length)
diff --git a/ext/phar/tests/006.phpt b/ext/phar/tests/006.phpt
new file mode 100644
index 0000000000..b2e8b29ef9
--- /dev/null
+++ b/ext/phar/tests/006.phpt
@@ -0,0 +1,14 @@
+--TEST--
+Phar::mapPhar truncated manifest (manifest length truncated)
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip");?>
+--FILE--
+<?php
+try {
+Phar::mapPhar('hio');
+} catch (Exception $e) {
+echo $e->getMessage();
+}
+__HALT_COMPILER(); ?>
+--EXPECTF--
+internal corruption of phar "%s" (truncated manifest at manifest length)
diff --git a/ext/phar/tests/007.phpt b/ext/phar/tests/007.phpt
new file mode 100644
index 0000000000..a13c2a452a
--- /dev/null
+++ b/ext/phar/tests/007.phpt
@@ -0,0 +1,14 @@
+--TEST--
+Phar::mapPhar manifest too big
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip");?>
+--FILE--
+<?php
+try {
+Phar::mapPhar('hio');
+} catch (Exception $e) {
+echo $e->getMessage();
+}
+__HALT_COMPILER(); ?>~~~~
+--EXPECTF--
+manifest cannot be larger than 100 MB in phar "%s"
diff --git a/ext/phar/tests/008.phpt b/ext/phar/tests/008.phpt
new file mode 100644
index 0000000000..664ffea5cb
--- /dev/null
+++ b/ext/phar/tests/008.phpt
@@ -0,0 +1,21 @@
+--TEST--
+Phar::mapPhar truncated manifest (not enough for manifest length)
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip");?>
+--FILE--
+<?php
+$file = "<?php
+Phar::mapPhar('hio');
+__HALT_COMPILER(); ?>";
+$file .= pack('V', 500) . 'notenough';
+file_put_contents(dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php', $file);
+try {
+include dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+} catch (Exception $e) {
+echo $e->getMessage();
+}
+?>
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECTF--
+internal corruption of phar "%s" (truncated manifest header)
diff --git a/ext/phar/tests/009.phpt b/ext/phar/tests/009.phpt
new file mode 100644
index 0000000000..c80445d61b
--- /dev/null
+++ b/ext/phar/tests/009.phpt
@@ -0,0 +1,23 @@
+--TEST--
+Phar::mapPhar too many manifest entries
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip");?>
+--INI--
+phar.require_hash=0
+--FILE--
+<?php
+$file = "<?php
+Phar::mapPhar('hio');
+__HALT_COMPILER(); ?>";
+$file .= pack('VVnVVV', 500, 500, 0x1000, 0x00000000, 0, 0) . str_repeat('A', 500);
+file_put_contents(dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php', $file);
+try {
+include dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+} catch (Exception $e) {
+echo $e->getMessage();
+}
+?>
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECTF--
+internal corruption of phar "%s009.phar.php" (too many manifest entries for size of manifest)
diff --git a/ext/phar/tests/010.phpt b/ext/phar/tests/010.phpt
new file mode 100644
index 0000000000..3dce5f8f4c
--- /dev/null
+++ b/ext/phar/tests/010.phpt
@@ -0,0 +1,29 @@
+--TEST--
+Phar::mapPhar buffer overrun
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip");?>
+--INI--
+phar.require_hash=0
+--FILE--
+<?php
+$file = "<?php
+Phar::mapPhar('hio');
+__HALT_COMPILER(); ?>";
+
+// this fails because the manifest length does not include the other 10 byte manifest data
+
+$manifest = pack('V', 1) . 'a' . pack('VVVVVV', 0, time(), 0, crc32(''), 0x00000000, 0);
+$file .= pack('VVnVV', strlen($manifest), 1, 0x1000, 0x00000000, 3) . 'hio' . pack('V', 0) . $manifest;
+
+file_put_contents(dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php', $file);
+try {
+include dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+echo file_get_contents('phar://hio/a');
+} catch (Exception $e) {
+echo $e->getMessage();
+}
+?>
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECTF--
+internal corruption of phar "%s" (too many manifest entries for size of manifest)
diff --git a/ext/phar/tests/011.phpt b/ext/phar/tests/011.phpt
new file mode 100644
index 0000000000..4a1f0dd42c
--- /dev/null
+++ b/ext/phar/tests/011.phpt
@@ -0,0 +1,30 @@
+--TEST--
+Phar::mapPhar filesize too small in manifest
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip");?>
+--INI--
+phar.require_hash=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = "<?php
+Phar::mapPhar('hio');
+__HALT_COMPILER(); ?>";
+
+// compressed file length does not match incompressed lentgh for an uncompressed file
+
+$files = array();
+$files['a'] = array('cont'=>'a','ulen'=>1,'clen'=>2);;
+include 'files/phar_test.inc';
+try {
+include $fname;
+echo file_get_contents('phar://hio/a');
+} catch (Exception $e) {
+echo $e->getMessage();
+}
+?>
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECTF--
+internal corruption of phar "%s" (compressed and uncompressed size does not match for uncompressed entry)
diff --git a/ext/phar/tests/012.phpt b/ext/phar/tests/012.phpt
new file mode 100644
index 0000000000..3246eff468
--- /dev/null
+++ b/ext/phar/tests/012.phpt
@@ -0,0 +1,28 @@
+--TEST--
+Phar::mapPhar valid file
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip");?>
+--INI--
+phar.require_hash=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = "<?php
+Phar::mapPhar('hio');
+__HALT_COMPILER(); ?>";
+
+$files = array();
+$files['a'] = 'a';
+
+include 'files/phar_test.inc';
+include $fname;
+
+echo file_get_contents('phar://hio/a');
+
+?>
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECT--
+a
diff --git a/ext/phar/tests/013.phpt b/ext/phar/tests/013.phpt
new file mode 100644
index 0000000000..ae3ae72936
--- /dev/null
+++ b/ext/phar/tests/013.phpt
@@ -0,0 +1,23 @@
+--TEST--
+Phar::mapPhar filesize mismatch
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip");?>
+--INI--
+phar.require_hash=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = "<?php __HALT_COMPILER(); ?>";
+// filesize should be 1, and is 2
+
+$files = array();
+$files['a'] = array('cont'=>'a', 'ulen'=>2, 'clen'=>2);
+include 'files/phar_test.inc';
+
+echo file_get_contents($pname.'/a');
+?>
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECTF--
+Warning: file_get_contents(phar://%s/a): failed to open stream: phar error: internal corruption of phar "%s" (%s file "a") in %s on line %d
diff --git a/ext/phar/tests/014.phpt b/ext/phar/tests/014.phpt
new file mode 100644
index 0000000000..d08e6550b6
--- /dev/null
+++ b/ext/phar/tests/014.phpt
@@ -0,0 +1,23 @@
+--TEST--
+Phar::mapPhar filesize mismatch
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip");?>
+--INI--
+phar.require_hash=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = "<?php __HALT_COMPILER(); ?>";
+// wrong crc32
+
+$files = array();
+$files['a'] = array('cont'=>'a', 'crc32'=>crc32('aX'));
+include 'files/phar_test.inc';
+
+echo file_get_contents($pname.'/a');
+?>
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECTF--
+Warning: file_get_contents(phar://%s/a): failed to open stream: phar error: internal corruption of phar "%s" (crc32 mismatch on file "a") in %s on line %d
diff --git a/ext/phar/tests/015.phpt b/ext/phar/tests/015.phpt
new file mode 100644
index 0000000000..b93b77e9fb
--- /dev/null
+++ b/ext/phar/tests/015.phpt
@@ -0,0 +1,23 @@
+--TEST--
+Phar::mapPhar valid file (gzipped)
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("zlib")) die("skip zlib not present"); ?>
+--INI--
+phar.require_hash=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = "<?php __HALT_COMPILER(); ?>";
+
+$files = array();
+$files['a'] = array('cont'=>'a','comp'=>chr(75) . chr(4) . chr(0) /* 'a' gzdeflated */, 'flags'=>0x00001000);
+include 'files/phar_test.inc';
+
+echo file_get_contents($pname .'/a');
+?>
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECT--
+a
diff --git a/ext/phar/tests/015b.phpt b/ext/phar/tests/015b.phpt
new file mode 100755
index 0000000000..08ead2d9c0
--- /dev/null
+++ b/ext/phar/tests/015b.phpt
@@ -0,0 +1,23 @@
+--TEST--
+Phar::mapPhar valid file (bzip2)
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip");?>
+<?php if (!extension_loaded("bz2")) die("skip bz2 not present"); ?>
+--INI--
+phar.require_hash=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = "<?php __HALT_COMPILER(); ?>";
+
+$files = array();
+$files['a'] = array('cont'=>'Hello World', 'comp'=>pack('H*', '425a6834314159265359065c89da0000009780400000400080060490002000310c082031a916c41d41e2ee48a70a1200cb913b40'),'flags'=>0x00002000);
+include 'files/phar_test.inc';
+
+var_dump(file_get_contents($pname . '/a'));
+?>
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECT--
+string(11) "Hello World"
diff --git a/ext/phar/tests/016.phpt b/ext/phar/tests/016.phpt
new file mode 100644
index 0000000000..302d06d3cb
--- /dev/null
+++ b/ext/phar/tests/016.phpt
@@ -0,0 +1,39 @@
+--TEST--
+Phar::mapPhar invalid file (gzipped file length is too short)
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip");?>
+<?php if (!extension_loaded("zlib")) die("skip zlib not present"); ?>
+--INI--
+phar.require_hash=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = "<?php __HALT_COMPILER(); ?>";
+// file length is too short
+
+$files = array();
+// "hi" gzdeflated
+$files['a'] = array('cont'=>'a','comp'=> pack('H*', 'cbc80400'),'flags'=>0x00001000, 'ulen' => 1, 'clen' => 4);
+$files['b'] = $files['a'];
+$files['c'] = array('cont'=>'*');
+$files['d'] = $files['a'];
+include 'files/phar_test.inc';
+
+var_dump(file_get_contents($pname . '/a'));
+var_dump(file_get_contents($pname . '/b'));
+var_dump(file_get_contents($pname . '/c'));
+var_dump(file_get_contents($pname . '/d'));
+?>
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECTF--
+Warning: file_get_contents(phar://%s/a): failed to open stream: phar error: internal corruption of phar "%s" (actual filesize mismatch on file "a") in %s on line %d
+bool(false)
+
+Warning: file_get_contents(phar://%s/b): failed to open stream: phar error: internal corruption of phar "%s" (actual filesize mismatch on file "b") in %s on line %d
+bool(false)
+string(1) "*"
+
+Warning: file_get_contents(phar://%s/d): failed to open stream: phar error: internal corruption of phar "%s" (actual filesize mismatch on file "d") in %s on line %d
+bool(false)
diff --git a/ext/phar/tests/016b.phpt b/ext/phar/tests/016b.phpt
new file mode 100755
index 0000000000..8fe66826d6
--- /dev/null
+++ b/ext/phar/tests/016b.phpt
@@ -0,0 +1,24 @@
+--TEST--
+Phar::mapPhar invalid file (gzipped file length is too short)
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip");?>
+<?php if (!extension_loaded("zlib")) die("skip zlib not present"); ?>
+--INI--
+phar.require_hash=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = "<?php __HALT_COMPILER(); ?>";
+// file length is too short
+
+$files = array();
+$files['a'] = array('cont'=>'a','flags'=>0x00001000, 'clen' => 1);
+include 'files/phar_test.inc';
+
+echo file_get_contents($pname . '/a');
+?>
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECTF--
+Warning: file_get_contents(phar://%s/a): failed to open stream: phar error: internal corruption of phar "%s" (actual filesize mismatch on file "a") in %s on line %d
diff --git a/ext/phar/tests/017.phpt b/ext/phar/tests/017.phpt
new file mode 100644
index 0000000000..ec012eaa11
--- /dev/null
+++ b/ext/phar/tests/017.phpt
@@ -0,0 +1,26 @@
+--TEST--
+Phar: opendir test - no dir specified at all
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = "<?php
+Phar::mapPhar('hio');
+__HALT_COMPILER(); ?>";
+
+$files = array();
+$files['a'] = 'abc';
+include 'files/phar_test.inc';
+
+include $fname;
+$dir = opendir('phar://hio');
+?>
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECTF--
+Warning: opendir(phar://hio): failed to open dir: phar error: no directory in "phar://hio", must have at least phar://hio/ for root directory (always use full path to a new phar)
+phar url "phar://hio" is unknown in %s017.php on line %d \ No newline at end of file
diff --git a/ext/phar/tests/018.phpt b/ext/phar/tests/018.phpt
new file mode 100644
index 0000000000..97cd323779
--- /dev/null
+++ b/ext/phar/tests/018.phpt
@@ -0,0 +1,33 @@
+--TEST--
+Phar: opendir test, root directory
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = "<?php
+Phar::mapPhar('hio');
+__HALT_COMPILER(); ?>";
+
+$files = array();
+$files['a'] = 'a';
+$files['b/a'] = 'b';
+include 'files/phar_test.inc';
+
+include $fname;
+$dir = opendir('phar://hio/');
+while (false !== ($a = readdir($dir))) {
+ var_dump($a);
+ var_dump(is_dir('phar://hio/' . $a));
+}
+?>
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECT--
+string(1) "a"
+bool(false)
+string(1) "b"
+bool(true) \ No newline at end of file
diff --git a/ext/phar/tests/019.phpt b/ext/phar/tests/019.phpt
new file mode 100644
index 0000000000..3d00b5f8e9
--- /dev/null
+++ b/ext/phar/tests/019.phpt
@@ -0,0 +1,34 @@
+--TEST--
+Phar: opendir test, subdirectory
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = "<?php
+Phar::mapPhar('hio');
+__HALT_COMPILER(); ?>";
+
+$files = array();
+$files['a'] = 'a';
+$files['b/a'] = 'b';
+$files['b/c/d'] = 'c';
+$files['bad/c'] = 'd';
+include 'files/phar_test.inc';
+include $fname;
+$dir = opendir('phar://hio/b');
+while (false !== ($a = readdir($dir))) {
+ var_dump($a);
+ var_dump(is_dir('phar://hio/b/' . $a));
+}
+?>
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECT--
+string(1) "a"
+bool(false)
+string(1) "c"
+bool(true) \ No newline at end of file
diff --git a/ext/phar/tests/019b.phpt b/ext/phar/tests/019b.phpt
new file mode 100755
index 0000000000..574919b793
--- /dev/null
+++ b/ext/phar/tests/019b.phpt
@@ -0,0 +1,65 @@
+--TEST--
+Phar: opendir test, recurse into
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = "<?php
+Phar::mapPhar('hio');
+__HALT_COMPILER(); ?>";
+
+$files = array();
+$files['a'] = 'a';
+$files['b/a'] = 'b';
+$files['b/c/d'] = 'c';
+$files['bad/c'] = 'd';
+include 'files/phar_test.inc';
+include $fname;
+
+function dump($phar, $base)
+{
+ var_dump($phar . $base);
+ $dir = opendir($phar . $base);
+ if ($base == '/')
+ {
+ $base = '';
+ }
+ while (false !== ($entry = readdir($dir))) {
+ $entry = $base . '/' . $entry;
+ var_dump($entry);
+ var_dump(is_dir($phar . $entry));
+ if (is_dir($phar . $entry))
+ {
+ dump($phar, $entry);
+ }
+ }
+}
+
+dump('phar://hio', '/');
+
+?>
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECT--
+string(11) "phar://hio/"
+string(2) "/a"
+bool(false)
+string(2) "/b"
+bool(true)
+string(12) "phar://hio/b"
+string(4) "/b/a"
+bool(false)
+string(4) "/b/c"
+bool(true)
+string(14) "phar://hio/b/c"
+string(6) "/b/c/d"
+bool(false)
+string(4) "/bad"
+bool(true)
+string(14) "phar://hio/bad"
+string(6) "/bad/c"
+bool(false)
diff --git a/ext/phar/tests/019c.phpt b/ext/phar/tests/019c.phpt
new file mode 100755
index 0000000000..242b666871
--- /dev/null
+++ b/ext/phar/tests/019c.phpt
@@ -0,0 +1,73 @@
+--TEST--
+Phar: opendir test, recurse into
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = "<?php
+Phar::mapPhar('hio');
+__HALT_COMPILER(); ?>";
+
+$files = array();
+$files['a'] = 'a';
+$files['b/a'] = 'b';
+$files['b/c/d'] = 'c';
+$files['bad/c'] = 'd';
+include 'files/phar_test.inc';
+include $fname;
+
+function dump($phar, $base)
+{
+ var_dump($phar . $base);
+ $dir = opendir($phar . $base);
+ if ($base == '/')
+ {
+ $base = '';
+ }
+ while (false !== ($entry = readdir($dir))) {
+ $entry = $base . '/' . $entry;
+ var_dump($entry);
+ var_dump(is_dir($phar . $entry));
+ if (is_dir($phar . $entry))
+ {
+ dump($phar, $entry);
+ }
+ else
+ {
+ var_dump(file_get_contents($phar . $entry));
+ }
+ }
+}
+
+dump('phar://hio', '/');
+
+?>
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECT--
+string(11) "phar://hio/"
+string(2) "/a"
+bool(false)
+string(1) "a"
+string(2) "/b"
+bool(true)
+string(12) "phar://hio/b"
+string(4) "/b/a"
+bool(false)
+string(1) "b"
+string(4) "/b/c"
+bool(true)
+string(14) "phar://hio/b/c"
+string(6) "/b/c/d"
+bool(false)
+string(1) "c"
+string(4) "/bad"
+bool(true)
+string(14) "phar://hio/bad"
+string(6) "/bad/c"
+bool(false)
+string(1) "d"
diff --git a/ext/phar/tests/020.phpt b/ext/phar/tests/020.phpt
new file mode 100644
index 0000000000..b06cdbf731
--- /dev/null
+++ b/ext/phar/tests/020.phpt
@@ -0,0 +1,136 @@
+--TEST--
+Phar: url stat
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = "<?php
+Phar::mapPhar('hio');
+__HALT_COMPILER(); ?>";
+
+$pfile = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$files = array();
+$files['a'] = 'a';
+$files['b/a'] = 'b';
+$files['b/c/d'] = 'c';
+$files['bad/c'] = 'd';
+include 'files/phar_test.inc';
+include $fname;
+
+var_dump(stat('phar://hio/a'), stat('phar://hio/b'));
+?>
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECTF--
+array(26) {
+ [0]=>
+ int(12)
+ [1]=>
+ int(%d)
+ [2]=>
+ int(33060)
+ [3]=>
+ int(1)
+ [4]=>
+ int(0)
+ [5]=>
+ int(0)
+ [6]=>
+ int(-1)
+ [7]=>
+ int(1)
+ [8]=>
+ int(%d)
+ [9]=>
+ int(%d)
+ [10]=>
+ int(%d)
+ [11]=>
+ int(-1)
+ [12]=>
+ int(-1)
+ ["dev"]=>
+ int(12)
+ ["ino"]=>
+ int(%d)
+ ["mode"]=>
+ int(33060)
+ ["nlink"]=>
+ int(1)
+ ["uid"]=>
+ int(0)
+ ["gid"]=>
+ int(0)
+ ["rdev"]=>
+ int(-1)
+ ["size"]=>
+ int(1)
+ ["atime"]=>
+ int(%d)
+ ["mtime"]=>
+ int(%d)
+ ["ctime"]=>
+ int(%d)
+ ["blksize"]=>
+ int(-1)
+ ["blocks"]=>
+ int(-1)
+}
+array(26) {
+ [0]=>
+ int(12)
+ [1]=>
+ int(%d)
+ [2]=>
+ int(16749)
+ [3]=>
+ int(1)
+ [4]=>
+ int(0)
+ [5]=>
+ int(0)
+ [6]=>
+ int(-1)
+ [7]=>
+ int(0)
+ [8]=>
+ int(%d)
+ [9]=>
+ int(%d)
+ [10]=>
+ int(%d)
+ [11]=>
+ int(-1)
+ [12]=>
+ int(-1)
+ ["dev"]=>
+ int(12)
+ ["ino"]=>
+ int(%d)
+ ["mode"]=>
+ int(16749)
+ ["nlink"]=>
+ int(1)
+ ["uid"]=>
+ int(0)
+ ["gid"]=>
+ int(0)
+ ["rdev"]=>
+ int(-1)
+ ["size"]=>
+ int(0)
+ ["atime"]=>
+ int(%d)
+ ["mtime"]=>
+ int(%d)
+ ["ctime"]=>
+ int(%d)
+ ["blksize"]=>
+ int(-1)
+ ["blocks"]=>
+ int(-1)
+} \ No newline at end of file
diff --git a/ext/phar/tests/021.phpt b/ext/phar/tests/021.phpt
new file mode 100644
index 0000000000..9c9cd97568
--- /dev/null
+++ b/ext/phar/tests/021.phpt
@@ -0,0 +1,85 @@
+--TEST--
+Phar: stream stat
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = "<?php
+Phar::mapPhar('hio');
+__HALT_COMPILER(); ?>";
+
+$files = array();
+$files['a'] = 'a';
+$files['b/a'] = 'b';
+$files['b/c/d'] = 'c';
+$files['bad/c'] = 'd';
+
+include 'files/phar_test.inc';
+
+include $fname;
+
+$fp = fopen('phar://hio/a', 'r');
+var_dump(fstat($fp));
+fclose($fp);
+?>
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECTF--
+array(26) {
+ [0]=>
+ int(12)
+ [1]=>
+ int(%d)
+ [2]=>
+ int(33060)
+ [3]=>
+ int(1)
+ [4]=>
+ int(0)
+ [5]=>
+ int(0)
+ [6]=>
+ int(-1)
+ [7]=>
+ int(1)
+ [8]=>
+ int(%d)
+ [9]=>
+ int(%d)
+ [10]=>
+ int(%d)
+ [11]=>
+ int(-1)
+ [12]=>
+ int(-1)
+ ["dev"]=>
+ int(12)
+ ["ino"]=>
+ int(%d)
+ ["mode"]=>
+ int(33060)
+ ["nlink"]=>
+ int(1)
+ ["uid"]=>
+ int(0)
+ ["gid"]=>
+ int(0)
+ ["rdev"]=>
+ int(-1)
+ ["size"]=>
+ int(1)
+ ["atime"]=>
+ int(%d)
+ ["mtime"]=>
+ int(%d)
+ ["ctime"]=>
+ int(%d)
+ ["blksize"]=>
+ int(-1)
+ ["blocks"]=>
+ int(-1)
+} \ No newline at end of file
diff --git a/ext/phar/tests/022.phpt b/ext/phar/tests/022.phpt
new file mode 100644
index 0000000000..20c24a0214
--- /dev/null
+++ b/ext/phar/tests/022.phpt
@@ -0,0 +1,110 @@
+--TEST--
+Phar: stream stat
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = "<?php
+Phar::mapPhar('hio');
+__HALT_COMPILER(); ?>";
+
+$files = array();
+$files['a'] = 'abcdefg';
+
+include 'files/phar_test.inc';
+
+include $fname;
+
+$fp = fopen('phar://hio/a', 'r');
+var_dump(ftell($fp));
+echo 'fseek($fp, 1)';var_dump(fseek($fp, 1));
+var_dump(ftell($fp));
+echo 'fseek($fp, 1, SEEK_CUR)';var_dump(fseek($fp, 1, SEEK_CUR));
+var_dump(ftell($fp));
+echo 'fseek($fp, -1, SEEK_CUR)';var_dump(fseek($fp, -1, SEEK_CUR));
+var_dump(ftell($fp));
+echo 'fseek($fp, -1, SEEK_END)';var_dump(fseek($fp, -1, SEEK_END));
+var_dump(ftell($fp));
+echo 'fseek($fp, -8, SEEK_END)';var_dump(fseek($fp, -8, SEEK_END));
+var_dump(ftell($fp));
+echo 'fseek($fp, -7, SEEK_END)';var_dump(fseek($fp, -7, SEEK_END));
+var_dump(ftell($fp));
+echo 'fseek($fp, 0, SEEK_END)';var_dump(fseek($fp, 0, SEEK_END));
+var_dump(ftell($fp));
+echo 'fseek($fp, 1, SEEK_END)';var_dump(fseek($fp, 1, SEEK_END));
+var_dump(ftell($fp));
+echo 'fseek($fp, -8, SEEK_END)';var_dump(fseek($fp, -8, SEEK_END));
+var_dump(ftell($fp));
+echo 'fseek($fp, 6)';var_dump(fseek($fp, 6));
+var_dump(ftell($fp));
+echo 'fseek($fp, 8)';var_dump(fseek($fp, 8));
+var_dump(ftell($fp));
+echo 'fseek($fp, -1)';var_dump(fseek($fp, -1));
+var_dump(ftell($fp));
+echo "next\n";
+fseek($fp, 4);
+var_dump(ftell($fp));
+echo 'fseek($fp, -5, SEEK_CUR)';var_dump(fseek($fp, -5, SEEK_CUR));
+var_dump(ftell($fp));
+fseek($fp, 4);
+var_dump(ftell($fp));
+echo 'fseek($fp, 5, SEEK_CUR)';var_dump(fseek($fp, 5, SEEK_CUR));
+var_dump(ftell($fp));
+fseek($fp, 4);
+var_dump(ftell($fp));
+echo 'fseek($fp, -4, SEEK_CUR)';var_dump(fseek($fp, -4, SEEK_CUR));
+var_dump(ftell($fp));
+fseek($fp, 4);
+var_dump(ftell($fp));
+echo 'fseek($fp, 3, SEEK_CUR)';var_dump(fseek($fp, 3, SEEK_CUR));
+var_dump(ftell($fp));
+fclose($fp);
+?>
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php');
+exit(0);
+ ?>
+--EXPECT--
+int(0)
+fseek($fp, 1)int(0)
+int(1)
+fseek($fp, 1, SEEK_CUR)int(0)
+int(2)
+fseek($fp, -1, SEEK_CUR)int(0)
+int(1)
+fseek($fp, -1, SEEK_END)int(0)
+int(6)
+fseek($fp, -8, SEEK_END)int(-1)
+bool(false)
+fseek($fp, -7, SEEK_END)int(0)
+int(0)
+fseek($fp, 0, SEEK_END)int(0)
+int(7)
+fseek($fp, 1, SEEK_END)int(-1)
+bool(false)
+fseek($fp, -8, SEEK_END)int(-1)
+bool(false)
+fseek($fp, 6)int(0)
+int(6)
+fseek($fp, 8)int(-1)
+bool(false)
+fseek($fp, -1)int(-1)
+bool(false)
+next
+int(4)
+fseek($fp, -5, SEEK_CUR)int(-1)
+bool(false)
+int(4)
+fseek($fp, 5, SEEK_CUR)int(-1)
+bool(false)
+int(4)
+fseek($fp, -4, SEEK_CUR)int(0)
+int(0)
+int(4)
+fseek($fp, 3, SEEK_CUR)int(0)
+int(7)
diff --git a/ext/phar/tests/023.phpt b/ext/phar/tests/023.phpt
new file mode 100755
index 0000000000..808f91deae
--- /dev/null
+++ b/ext/phar/tests/023.phpt
@@ -0,0 +1,32 @@
+--TEST--
+Phar: phar:// file_get_contents
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = "<?php __HALT_COMPILER(); ?>";
+
+$files = array();
+$files['a.php'] = '<?php echo "This is a\n"; ?>';
+$files['b.php'] = '<?php echo "This is b\n"; ?>';
+$files['b/c.php'] = '<?php echo "This is b/c\n"; ?>';
+
+include 'files/phar_test.inc';
+
+var_dump(file_get_contents($pname . '/a.php'));
+var_dump(file_get_contents($pname . '/b.php'));
+var_dump(file_get_contents($pname . '/b/c.php'));
+
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECT--
+string(28) "<?php echo "This is a\n"; ?>"
+string(28) "<?php echo "This is b\n"; ?>"
+string(30) "<?php echo "This is b/c\n"; ?>"
+===DONE===
diff --git a/ext/phar/tests/024.phpt b/ext/phar/tests/024.phpt
new file mode 100755
index 0000000000..ad30d2644d
--- /dev/null
+++ b/ext/phar/tests/024.phpt
@@ -0,0 +1,32 @@
+--TEST--
+Phar: phar:// include
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = "<?php __HALT_COMPILER(); ?>";
+
+$files = array();
+$files['a.php'] = '<?php echo "This is a\n"; ?>';
+$files['b.php'] = '<?php echo "This is b\n"; ?>';
+$files['b/c.php'] = '<?php echo "This is b/c\n"; ?>';
+
+include 'files/phar_test.inc';
+
+include $pname . '/a.php';
+include $pname . '/b.php';
+include $pname . '/b/c.php';
+
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECT--
+This is a
+This is b
+This is b/c
+===DONE===
diff --git a/ext/phar/tests/025.phpt b/ext/phar/tests/025.phpt
new file mode 100755
index 0000000000..bbb5bc4e83
--- /dev/null
+++ b/ext/phar/tests/025.phpt
@@ -0,0 +1,32 @@
+--TEST--
+Phar: phar:// include (repeated names)
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = "<?php __HALT_COMPILER(); ?>";
+
+$files = array();
+$files['a'] = '<?php echo "This is a\n"; ?>';
+$files['b'] = '<?php echo "This is b\n"; ?>';
+$files['b/b'] = '<?php echo "This is b/b\n"; ?>';
+
+include 'files/phar_test.inc';
+
+include $pname . '/a';
+include $pname . '/b';
+include $pname . '/b/b';
+
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECT--
+This is a
+This is b
+This is b/b
+===DONE===
diff --git a/ext/phar/tests/026.phpt b/ext/phar/tests/026.phpt
new file mode 100755
index 0000000000..696fbcf415
--- /dev/null
+++ b/ext/phar/tests/026.phpt
@@ -0,0 +1,34 @@
+--TEST--
+Phar: phar:// require from within
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = "<?php __HALT_COMPILER(); ?>";
+
+$files = array();
+$files['a.php'] = '<?php echo "This is a\n"; require \''.$pname.'/b.php\'; ?>';
+$files['b.php'] = '<?php echo "This is b\n"; require \''.$pname.'/b/c.php\'; ?>';
+$files['b/c.php'] = '<?php echo "This is b/c\n"; require \''.$pname.'/b/d.php\'; ?>';
+$files['b/d.php'] = '<?php echo "This is b/d\n"; require \''.$pname.'/e.php\'; ?>';
+$files['e.php'] = '<?php echo "This is e\n"; ?>';
+
+include 'files/phar_test.inc';
+
+require $pname . '/a.php';
+
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECT--
+This is a
+This is b
+This is b/c
+This is b/d
+This is e
+===DONE===
diff --git a/ext/phar/tests/027.phpt b/ext/phar/tests/027.phpt
new file mode 100755
index 0000000000..679fefc2cd
--- /dev/null
+++ b/ext/phar/tests/027.phpt
@@ -0,0 +1,94 @@
+--TEST--
+Phar: phar:// opendir
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = "<?php __HALT_COMPILER(); ?>";
+
+$files = array();
+$files['a.php'] = '<?php echo "This is a\n"; require \''.$pname.'/b.php\'; ?>';
+$files['b.php'] = '<?php echo "This is b\n"; require \''.$pname.'/b/c.php\'; ?>';
+$files['b/c.php'] = '<?php echo "This is b/c\n"; require \''.$pname.'/b/d.php\'; ?>';
+$files['b/d.php'] = '<?php echo "This is b/d\n"; require \''.$pname.'/e.php\'; ?>';
+$files['e.php'] = '<?php echo "This is e\n"; ?>';
+
+include 'files/phar_test.inc';
+
+function dump($phar, $base)
+{
+ var_dump(str_replace(dirname(__FILE__), '*', $phar) . $base);
+ $dir = opendir($phar . $base);
+ if ($base == '/')
+ {
+ $base = '';
+ }
+ while (false !== ($entry = readdir($dir))) {
+ $entry = $base . '/' . $entry;
+ var_dump($entry);
+ var_dump(is_dir($phar . $entry));
+ if (is_dir($phar . $entry))
+ {
+ dump($phar, $entry);
+ }
+ }
+}
+
+dump($pname, '/');
+
+$a = opendir($pname);
+// this may stop working in future versions, but is here for code coverage purposes
+echo "fseek on dir handle\n";
+var_dump(fseek($a, 0, SEEK_END), ftell($a));
+var_dump(fseek($a, -1), ftell($a));
+var_dump(fseek($a, 1), ftell($a));
+echo "fwrite on dir handle\n";
+var_dump(fwrite($a, 'hi'));
+var_dump(fstat($a));
+closedir($a);
+echo "opendir edge cases\n";
+var_dump(opendir("phar://"));
+var_dump(opendir("phar://foo.phar/hi"));
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECTF--
+string(%d) "phar://*/027.phar.php/"
+string(6) "/a.php"
+bool(false)
+string(2) "/b"
+bool(true)
+string(%d) "phar://*/027.phar.php/b"
+string(8) "/b/c.php"
+bool(false)
+string(8) "/b/d.php"
+bool(false)
+string(6) "/b.php"
+bool(false)
+string(6) "/e.php"
+bool(false)
+fseek on dir handle
+int(0)
+int(4)
+int(-1)
+int(4)
+int(0)
+int(1)
+fwrite on dir handle
+int(0)
+bool(false)
+opendir edge cases
+
+Warning: opendir(phar://): failed to open dir: phar error: no directory in "phar://", must have at least phar:/// for root directory (always use full path to a new phar)
+phar url "phar://" is unknown in %s027.php on line %d
+bool(false)
+
+Warning: opendir(phar://foo.phar/hi): failed to open dir: phar error: invalid url or non-existent phar "phar://foo.phar/hi"
+phar url "phar://foo.phar/hi" is unknown in %s027.php on line %d
+bool(false)
+===DONE===
diff --git a/ext/phar/tests/028.phpt b/ext/phar/tests/028.phpt
new file mode 100755
index 0000000000..087f822777
--- /dev/null
+++ b/ext/phar/tests/028.phpt
@@ -0,0 +1,47 @@
+--TEST--
+Phar::loadPhar
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://hio';
+$file = '<?php include "' . $pname . '/a.php"; __HALT_COMPILER(); ?>';
+$alias = '';
+
+$files = array();
+$files['a.php'] = '<?php echo "This is a\n"; include "'.$pname.'/b.php"; ?>';
+$files['b.php'] = '<?php echo "This is b\n"; include "'.$pname.'/b/c.php"; ?>';
+$files['b/c.php'] = '<?php echo "This is b/c\n"; include "'.$pname.'/b/d.php"; ?>';
+$files['b/d.php'] = '<?php echo "This is b/d\n"; include "'.$pname.'/e.php"; ?>';
+$files['e.php'] = '<?php echo "This is e\n"; ?>';
+
+include 'files/phar_test.inc';
+
+Phar::loadPhar($fname, 'hio');
+
+include $fname;
+
+echo "======\n";
+
+include $pname . '/a.php';
+
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECTF--
+This is a
+This is b
+This is b/c
+This is b/d
+This is e
+======
+This is a
+This is b
+This is b/c
+This is b/d
+This is e
+===DONE===
diff --git a/ext/phar/tests/029.phpt b/ext/phar/tests/029.phpt
new file mode 100755
index 0000000000..41fcec03e7
--- /dev/null
+++ b/ext/phar/tests/029.phpt
@@ -0,0 +1,50 @@
+--TEST--
+Phar::loadPhar overloading alias names
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+--FILE--
+<?php
+$fname1 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.1.phar.php';
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.2.phar.php';
+$fname = $fname1;
+$alias = '';
+$pname = 'phar://hio';
+$file = '<?php include "' . $pname . '/a.php"; __HALT_COMPILER(); ?>';
+
+$files = array();
+$files['a.php'] = '<?php echo "This is a\n"; include "'.$pname.'/b.php"; ?>';
+$files['b.php'] = '<?php echo "This is b\n"; include "'.$pname.'/b/c.php"; ?>';
+$files['b/c.php'] = '<?php echo "This is b/c\n"; include "'.$pname.'/b/d.php"; ?>';
+$files['b/d.php'] = '<?php echo "This is b/d\n"; include "'.$pname.'/e.php"; ?>';
+$files['e.php'] = '<?php echo "This is e\n"; ?>';
+
+include 'files/phar_test.inc';
+
+copy($fname1, $fname2);
+
+var_dump(Phar::loadPhar($fname1, 'hio'));
+var_dump(Phar::loadPhar($fname1, 'copy'));
+$a = new Phar($fname1);
+try
+{
+ var_dump(Phar::loadPhar($fname2, 'copy'));
+}
+catch (Exception $e)
+{
+ echo $e->getMessage() . "\n";
+}
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.1.phar.php');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.2.phar.php');
+?>
+--EXPECTF--
+bool(true)
+bool(true)
+alias "copy" is already used for archive "%s029.1.phar.php" cannot be overloaded with "%s029.2.phar.php"
+===DONE===
diff --git a/ext/phar/tests/030.phpt b/ext/phar/tests/030.phpt
new file mode 100755
index 0000000000..afaeb1a802
--- /dev/null
+++ b/ext/phar/tests/030.phpt
@@ -0,0 +1,38 @@
+--TEST--
+Phar::loadPhar ignoring alias
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = '<?php include "' . $pname . '/a.php"; __HALT_COMPILER(); ?>';
+
+$files = array();
+$files['a.php'] = '<?php echo "This is a\n"; include \''.$pname.'/b.php\'; ?>';
+$files['b.php'] = '<?php echo "This is b\n"; include \''.$pname.'/b/c.php\'; ?>';
+$files['b/c.php'] = '<?php echo "This is b/c\n"; include \''.$pname.'/b/d.php\'; ?>';
+$files['b/d.php'] = '<?php echo "This is b/d\n"; include \''.$pname.'/e.php\'; ?>';
+$files['e.php'] = '<?php echo "This is e\n"; ?>';
+
+include 'files/phar_test.inc';
+
+Phar::loadPhar($fname);
+
+require $pname . '/a.php';
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php');
+?>
+--EXPECTF--
+This is a
+This is b
+This is b/c
+This is b/d
+This is e
+===DONE===
diff --git a/ext/phar/tests/031.phpt b/ext/phar/tests/031.phpt
new file mode 100755
index 0000000000..4d5988621d
--- /dev/null
+++ b/ext/phar/tests/031.phpt
@@ -0,0 +1,31 @@
+--TEST--
+Phar: include and parser error
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+--FILE--
+<?php
+
+$pharconfig = 3;
+
+require_once 'files/phar_oo_test.inc';
+
+Phar::loadPhar($fname);
+
+$pname = 'phar://' . $fname . '/a.php';
+
+var_dump(file_get_contents($pname));
+require $pname;
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/files/phar_oo_test.phar.php');
+__halt_compiler();
+?>
+--EXPECTF--
+string(25) "<?php echo new new class;"
+
+Parse error: %s in phar://%sphar_oo_test.phar.php/a.php on line %d
diff --git a/ext/phar/tests/032.phpt b/ext/phar/tests/032.phpt
new file mode 100755
index 0000000000..faf3dcbf58
--- /dev/null
+++ b/ext/phar/tests/032.phpt
@@ -0,0 +1,29 @@
+--TEST--
+Phar: require hash
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=1
+--FILE--
+<?php
+
+$pharconfig = 0;
+
+require_once 'files/phar_oo_test.inc';
+
+try {
+Phar::loadPhar($fname);
+} catch (Exception $e) {
+echo $e->getMessage();
+}
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/files/phar_oo_test.phar.php');
+__halt_compiler();
+?>
+--EXPECTF--
+
+phar "%sphar_oo_test.phar.php" does not have a signature===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/033.phpt b/ext/phar/tests/033.phpt
new file mode 100644
index 0000000000..d53c7f52fa
--- /dev/null
+++ b/ext/phar/tests/033.phpt
@@ -0,0 +1,47 @@
+--TEST--
+Phar::chmod
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.1.phar.php';
+$pname = 'phar://hio';
+$file = '<?php include "' . $pname . '/a.php"; __HALT_COMPILER(); ?>';
+
+$files = array();
+$files['a.php'] = '<?php echo "This is a\n"; include "'.$pname.'/b.php"; ?>';
+$files['dir/'] = '';
+$hasdir = 1;
+include 'files/phar_test.inc';
+$a = new Phar($fname);
+var_dump($a['a.php']->isExecutable());
+$a['a.php']->chmod(0777);
+var_dump($a['a.php']->isExecutable());
+$a['a.php']->chmod(0666);
+var_dump($a['a.php']->isExecutable());
+echo "test dir\n";
+var_dump($a['dir']->isDir());
+var_dump($a['dir']->isReadable());
+$a['dir']->chmod(000);
+var_dump($a['dir']->isReadable());
+$a['dir']->chmod(0666);
+var_dump($a['dir']->isReadable());
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.1.phar.php');
+?>
+--EXPECT--
+bool(false)
+bool(true)
+bool(false)
+test dir
+bool(true)
+bool(true)
+bool(false)
+bool(true)
+===DONE===
diff --git a/ext/phar/tests/033a.phpt b/ext/phar/tests/033a.phpt
new file mode 100644
index 0000000000..e8725bdda6
--- /dev/null
+++ b/ext/phar/tests/033a.phpt
@@ -0,0 +1,36 @@
+--TEST--
+Phar::chmod
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=1
+phar.require_hash=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.1.phar.php';
+$pname = 'phar://hio';
+$file = '<?php include "' . $pname . '/a.php"; __HALT_COMPILER(); ?>';
+
+$files = array();
+$files['a.php'] = '<?php echo "This is a\n"; include "'.$pname.'/b.php"; ?>';
+include 'files/phar_test.inc';
+try {
+ $a = new Phar($fname);
+ var_dump($a['a.php']->isExecutable());
+ $a['a.php']->chmod(0777);
+ var_dump($a['a.php']->isExecutable());
+ $a['a.php']->chmod(0666);
+ var_dump($a['a.php']->isExecutable());
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.1.phar.php');
+?>
+--EXPECTF--
+bool(false)
+Cannot modify permissions for file "a.php" in phar "%s033a.1.phar.php", write operations are prohibited
+===DONE===
diff --git a/ext/phar/tests/addfuncs.phpt b/ext/phar/tests/addfuncs.phpt
new file mode 100644
index 0000000000..d9a183fd68
--- /dev/null
+++ b/ext/phar/tests/addfuncs.phpt
@@ -0,0 +1,41 @@
+--TEST--
+Phar: addFile/addFromString
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$phar = new Phar($fname);
+$phar->addFromString('a', 'hi');
+echo file_get_contents($pname . '/a') . "\n";
+$phar->addFile($pname . '/a', 'b');
+echo file_get_contents($pname . '/b') . "\n";
+try {
+$phar->addFile($pname . '/a');
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+try {
+$phar->addFile($pname . '/a', 'a');
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+try {
+$phar->addFile(dirname(__FILE__) . '/does/not/exist');
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECTF--
+hi
+hi
+Entry phar://%saddfuncs.phar.php/a does not exist and cannot be created: phar error: invalid path "phar://%saddfuncs.phar.php/a" contains double slash
+Entry a does not exist and cannot be created: phar error: file "a" in phar "%saddfuncs.phar.php" cannot be opened for writing, readable file pointers are open
+phar error: unable to open file "%s/does/not/exist" to add to phar archive
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/alias_acrobatics.phpt b/ext/phar/tests/alias_acrobatics.phpt
new file mode 100644
index 0000000000..1bb20a4b3a
--- /dev/null
+++ b/ext/phar/tests/alias_acrobatics.phpt
@@ -0,0 +1,46 @@
+--TEST--
+Phar: alias edge cases
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar';
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.2.phar';
+
+$p = new Phar($fname);
+
+$p->setAlias('foo');
+$p['unused'] = 'hi';
+try {
+$a = new Phar($fname2, 0, 'foo');
+} catch (Exception $e) {
+echo $e->getMessage(),"\n";
+}
+copy($fname, $fname2);
+echo "2\n";
+try {
+$a = new Phar($fname2);
+} catch (Exception $e) {
+echo $e->getMessage(),"\n";
+}
+try {
+$b = new Phar($fname, 0, 'another');
+} catch (Exception $e) {
+echo $e->getMessage(),"\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.2.phar');
+?>
+--EXPECTF--
+alias "foo" is already used for archive "%salias_acrobatics.phar" cannot be overloaded with "%salias_acrobatics.2.phar"
+2
+Cannot open archive "%salias_acrobatics.2.phar", alias is already in use by existing archive
+alias "another" is already used for archive "%salias_acrobatics.phar" cannot be overloaded with "%salias_acrobatics.phar"
+===DONE===
diff --git a/ext/phar/tests/badparameters.phpt b/ext/phar/tests/badparameters.phpt
new file mode 100644
index 0000000000..a6ce37b3f9
--- /dev/null
+++ b/ext/phar/tests/badparameters.phpt
@@ -0,0 +1,210 @@
+--TEST--
+Phar: bad parameters to various methods
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+ini_set('phar.readonly', 1);
+Phar::mungServer('hi');
+Phar::createDefaultStub(array());
+Phar::loadPhar(array());
+Phar::canCompress('hi');
+$a = new Phar(array());
+$a = new Phar(dirname(__FILE__) . '/files/frontcontroller10.phar');
+$a->convertToExecutable(array());
+$a->convertToData(array());
+$b = new PharData(dirname(__FILE__) . '/whatever.tar');
+$c = new PharData(dirname(__FILE__) . '/whatever.zip');
+$b->delete(array());
+try {
+$a->delete('oops');
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+try {
+$b->delete('oops');
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+echo $a->getPath() . "\n";
+try {
+$a->setAlias('oops');
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+try {
+$b->setAlias('oops');
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+ini_set('phar.readonly', 0);
+$a->setAlias(array());
+ini_set('phar.readonly', 1);
+try {
+$b->stopBuffering();
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+try {
+$a->setStub('oops');
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+try {
+$b->setStub('oops');
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+ini_set('phar.readonly', 0);
+$a->setStub(array());
+ini_set('phar.readonly', 1);
+try {
+$b->setDefaultStub('oops');
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+$a->setDefaultStub(array());
+try {
+$a->setDefaultStub('oops');
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+try {
+$a->setSignatureAlgorithm(Phar::MD5);
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+try {
+$b->setSignatureAlgorithm(Phar::MD5);
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+try {
+$c->setSignatureAlgorithm(Phar::MD5);
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+$a->compress(array());
+try {
+$a->compress(1);
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+$a->compressFiles(array());
+try {
+$a->decompressFiles();
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+$a->copy(array());
+try {
+$a->copy('a', 'b');
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+$a->offsetExists(array());
+$a->offsetGet(array());
+ini_set('phar.readonly', 0);
+$a->offsetSet(array());
+ini_set('phar.readonly', 1);
+$b->offsetUnset(array());
+try {
+$a->offsetUnset('a');
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+$a->addEmptyDir(array());
+$a->addFile(array());
+$a->addFromString(array());
+try {
+$a->setMetadata('a');
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+try {
+$b->setMetadata('a');
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+ini_set('phar.readonly', 0);
+$a->setMetadata(1,2);
+ini_set('phar.readonly', 1);
+try {
+$a->delMetadata();
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+try {
+$b->delMetadata();
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--EXPECTF--
+Warning: Phar::mungServer() expects parameter 1 to be array, string given in %sbadparameters.php on line %d
+
+Warning: Phar::createDefaultStub() expects parameter 1 to be string, array given in %sbadparameters.php on line %d
+
+Warning: Phar::loadPhar() expects parameter 1 to be string, array given in %sbadparameters.php on line %d
+
+Warning: Phar::canCompress() expects parameter 1 to be long, string given in %sbadparameters.php on line %d
+
+Warning: Phar::__construct() expects parameter 1 to be string, array given in %sbadparameters.php on line %d
+
+Warning: Phar::convertToExecutable() expects parameter 1 to be long, array given in %sbadparameters.php on line %d
+
+Warning: Phar::convertToData() expects parameter 1 to be long, array given in %sbadparameters.php on line %d
+
+Warning: PharData::delete() expects parameter 1 to be string, array given in %sbadparameters.php on line %d
+Cannot write out phar archive, phar is read-only
+Entry oops does not exist and cannot be deleted
+%sfiles/frontcontroller10.phar
+Cannot write out phar archive, phar is read-only
+A Phar alias cannot be set in a plain tar archive
+
+Warning: Phar::setAlias() expects parameter 1 to be string, array given in %sbadparameters.php on line %d
+Cannot change stub, phar is read-only
+A Phar stub cannot be set in a plain tar archive
+
+Warning: Phar::setStub() expects parameter 1 to be string, array given in %sbadparameters.php on line %d
+A Phar stub cannot be set in a plain tar archive
+
+Warning: Phar::setDefaultStub() expects parameter 1 to be string, array given in %sbadparameters.php on line %d
+Cannot change stub: phar.readonly=1
+Cannot set signature algorithm, phar is read-only
+Cannot set signature algorithm, not possible with tar-based phar archives
+Cannot set signature algorithm, not possible with zip-based phar archives
+
+Warning: Phar::compress() expects parameter 1 to be long, array given in %sbadparameters.php on line %d
+Cannot compress phar archive, phar is read-only
+
+Warning: Phar::compressFiles() expects parameter 1 to be long, array given in %sbadparameters.php on line %d
+Phar is readonly, cannot change compression
+
+Warning: Phar::copy() expects exactly 2 parameters, 1 given in %sbadparameters.php on line %d
+Cannot copy "a" to "b", phar is read-only
+
+Warning: Phar::offsetExists() expects parameter 1 to be string, array given in %sbadparameters.php on line %d
+
+Warning: Phar::offsetGet() expects parameter 1 to be string, array given in %sbadparameters.php on line %d
+
+Warning: Phar::offsetSet() expects exactly 2 parameters, 1 given in %sbadparameters.php on line %d
+
+Warning: PharData::offsetUnset() expects parameter 1 to be string, array given in %sbadparameters.php on line %d
+Write operations disabled by INI setting
+
+Warning: Phar::addEmptyDir() expects parameter 1 to be string, array given in %sbadparameters.php on line %d
+
+Warning: Phar::addFile() expects parameter 1 to be string, array given in %sbadparameters.php on line %d
+
+Warning: Phar::addFromString() expects exactly 2 parameters, 1 given in %sbadparameters.php on line %d
+Write operations disabled by INI setting
+Cannot set metadata, not possible with tar-based phar archives
+
+Warning: Phar::setMetadata() expects exactly 1 parameter, 2 given in %sbadparameters.php on line %d
+Write operations disabled by INI setting
+Cannot delete metadata, not possible with tar-based phar archives
+===DONE===
diff --git a/ext/phar/tests/bug13727.phpt b/ext/phar/tests/bug13727.phpt
new file mode 100644
index 0000000000..cc7fc19a6c
--- /dev/null
+++ b/ext/phar/tests/bug13727.phpt
@@ -0,0 +1,4135 @@
+--TEST--
+Phar: SLOW TEST bug #13727: "Number of files in the Phar" limited to 2042
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$dirName = dirname(__FILE__);
+$pname = 'phar://' . $fname;
+$pArchive="DataArchive.phar";
+$p = new Phar($fname, 0, $pArchive);
+for ($i = 0; $i < 4*1024; $i++){
+ echo("$i\n");
+ if (!is_dir($fileDir="$dirName/test_data"))
+ mkdir($fileDir, 0777, true);
+ file_put_contents("$fileDir/$i", "");
+ $p->addFile("$fileDir/$i", "$dirName");
+}
+echo("\n Written Files($i)\n");
+?>
+===DONE===
+--CLEAN--
+<?php
+$dirName = dirname(__FILE__);
+$fileDir="$dirName/test_data";
+for ($i = 0; $i < 4*1024; $i++){
+ unlink("$fileDir/$i");
+}
+rmdir($fileDir);
+unlink($dirName . '/' . basename(__FILE__, '.clean.php') . '.phar.php');
+__HALT_COMPILER();
+?>
+--EXPECT--
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+792
+793
+794
+795
+796
+797
+798
+799
+800
+801
+802
+803
+804
+805
+806
+807
+808
+809
+810
+811
+812
+813
+814
+815
+816
+817
+818
+819
+820
+821
+822
+823
+824
+825
+826
+827
+828
+829
+830
+831
+832
+833
+834
+835
+836
+837
+838
+839
+840
+841
+842
+843
+844
+845
+846
+847
+848
+849
+850
+851
+852
+853
+854
+855
+856
+857
+858
+859
+860
+861
+862
+863
+864
+865
+866
+867
+868
+869
+870
+871
+872
+873
+874
+875
+876
+877
+878
+879
+880
+881
+882
+883
+884
+885
+886
+887
+888
+889
+890
+891
+892
+893
+894
+895
+896
+897
+898
+899
+900
+901
+902
+903
+904
+905
+906
+907
+908
+909
+910
+911
+912
+913
+914
+915
+916
+917
+918
+919
+920
+921
+922
+923
+924
+925
+926
+927
+928
+929
+930
+931
+932
+933
+934
+935
+936
+937
+938
+939
+940
+941
+942
+943
+944
+945
+946
+947
+948
+949
+950
+951
+952
+953
+954
+955
+956
+957
+958
+959
+960
+961
+962
+963
+964
+965
+966
+967
+968
+969
+970
+971
+972
+973
+974
+975
+976
+977
+978
+979
+980
+981
+982
+983
+984
+985
+986
+987
+988
+989
+990
+991
+992
+993
+994
+995
+996
+997
+998
+999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
+1055
+1056
+1057
+1058
+1059
+1060
+1061
+1062
+1063
+1064
+1065
+1066
+1067
+1068
+1069
+1070
+1071
+1072
+1073
+1074
+1075
+1076
+1077
+1078
+1079
+1080
+1081
+1082
+1083
+1084
+1085
+1086
+1087
+1088
+1089
+1090
+1091
+1092
+1093
+1094
+1095
+1096
+1097
+1098
+1099
+1100
+1101
+1102
+1103
+1104
+1105
+1106
+1107
+1108
+1109
+1110
+1111
+1112
+1113
+1114
+1115
+1116
+1117
+1118
+1119
+1120
+1121
+1122
+1123
+1124
+1125
+1126
+1127
+1128
+1129
+1130
+1131
+1132
+1133
+1134
+1135
+1136
+1137
+1138
+1139
+1140
+1141
+1142
+1143
+1144
+1145
+1146
+1147
+1148
+1149
+1150
+1151
+1152
+1153
+1154
+1155
+1156
+1157
+1158
+1159
+1160
+1161
+1162
+1163
+1164
+1165
+1166
+1167
+1168
+1169
+1170
+1171
+1172
+1173
+1174
+1175
+1176
+1177
+1178
+1179
+1180
+1181
+1182
+1183
+1184
+1185
+1186
+1187
+1188
+1189
+1190
+1191
+1192
+1193
+1194
+1195
+1196
+1197
+1198
+1199
+1200
+1201
+1202
+1203
+1204
+1205
+1206
+1207
+1208
+1209
+1210
+1211
+1212
+1213
+1214
+1215
+1216
+1217
+1218
+1219
+1220
+1221
+1222
+1223
+1224
+1225
+1226
+1227
+1228
+1229
+1230
+1231
+1232
+1233
+1234
+1235
+1236
+1237
+1238
+1239
+1240
+1241
+1242
+1243
+1244
+1245
+1246
+1247
+1248
+1249
+1250
+1251
+1252
+1253
+1254
+1255
+1256
+1257
+1258
+1259
+1260
+1261
+1262
+1263
+1264
+1265
+1266
+1267
+1268
+1269
+1270
+1271
+1272
+1273
+1274
+1275
+1276
+1277
+1278
+1279
+1280
+1281
+1282
+1283
+1284
+1285
+1286
+1287
+1288
+1289
+1290
+1291
+1292
+1293
+1294
+1295
+1296
+1297
+1298
+1299
+1300
+1301
+1302
+1303
+1304
+1305
+1306
+1307
+1308
+1309
+1310
+1311
+1312
+1313
+1314
+1315
+1316
+1317
+1318
+1319
+1320
+1321
+1322
+1323
+1324
+1325
+1326
+1327
+1328
+1329
+1330
+1331
+1332
+1333
+1334
+1335
+1336
+1337
+1338
+1339
+1340
+1341
+1342
+1343
+1344
+1345
+1346
+1347
+1348
+1349
+1350
+1351
+1352
+1353
+1354
+1355
+1356
+1357
+1358
+1359
+1360
+1361
+1362
+1363
+1364
+1365
+1366
+1367
+1368
+1369
+1370
+1371
+1372
+1373
+1374
+1375
+1376
+1377
+1378
+1379
+1380
+1381
+1382
+1383
+1384
+1385
+1386
+1387
+1388
+1389
+1390
+1391
+1392
+1393
+1394
+1395
+1396
+1397
+1398
+1399
+1400
+1401
+1402
+1403
+1404
+1405
+1406
+1407
+1408
+1409
+1410
+1411
+1412
+1413
+1414
+1415
+1416
+1417
+1418
+1419
+1420
+1421
+1422
+1423
+1424
+1425
+1426
+1427
+1428
+1429
+1430
+1431
+1432
+1433
+1434
+1435
+1436
+1437
+1438
+1439
+1440
+1441
+1442
+1443
+1444
+1445
+1446
+1447
+1448
+1449
+1450
+1451
+1452
+1453
+1454
+1455
+1456
+1457
+1458
+1459
+1460
+1461
+1462
+1463
+1464
+1465
+1466
+1467
+1468
+1469
+1470
+1471
+1472
+1473
+1474
+1475
+1476
+1477
+1478
+1479
+1480
+1481
+1482
+1483
+1484
+1485
+1486
+1487
+1488
+1489
+1490
+1491
+1492
+1493
+1494
+1495
+1496
+1497
+1498
+1499
+1500
+1501
+1502
+1503
+1504
+1505
+1506
+1507
+1508
+1509
+1510
+1511
+1512
+1513
+1514
+1515
+1516
+1517
+1518
+1519
+1520
+1521
+1522
+1523
+1524
+1525
+1526
+1527
+1528
+1529
+1530
+1531
+1532
+1533
+1534
+1535
+1536
+1537
+1538
+1539
+1540
+1541
+1542
+1543
+1544
+1545
+1546
+1547
+1548
+1549
+1550
+1551
+1552
+1553
+1554
+1555
+1556
+1557
+1558
+1559
+1560
+1561
+1562
+1563
+1564
+1565
+1566
+1567
+1568
+1569
+1570
+1571
+1572
+1573
+1574
+1575
+1576
+1577
+1578
+1579
+1580
+1581
+1582
+1583
+1584
+1585
+1586
+1587
+1588
+1589
+1590
+1591
+1592
+1593
+1594
+1595
+1596
+1597
+1598
+1599
+1600
+1601
+1602
+1603
+1604
+1605
+1606
+1607
+1608
+1609
+1610
+1611
+1612
+1613
+1614
+1615
+1616
+1617
+1618
+1619
+1620
+1621
+1622
+1623
+1624
+1625
+1626
+1627
+1628
+1629
+1630
+1631
+1632
+1633
+1634
+1635
+1636
+1637
+1638
+1639
+1640
+1641
+1642
+1643
+1644
+1645
+1646
+1647
+1648
+1649
+1650
+1651
+1652
+1653
+1654
+1655
+1656
+1657
+1658
+1659
+1660
+1661
+1662
+1663
+1664
+1665
+1666
+1667
+1668
+1669
+1670
+1671
+1672
+1673
+1674
+1675
+1676
+1677
+1678
+1679
+1680
+1681
+1682
+1683
+1684
+1685
+1686
+1687
+1688
+1689
+1690
+1691
+1692
+1693
+1694
+1695
+1696
+1697
+1698
+1699
+1700
+1701
+1702
+1703
+1704
+1705
+1706
+1707
+1708
+1709
+1710
+1711
+1712
+1713
+1714
+1715
+1716
+1717
+1718
+1719
+1720
+1721
+1722
+1723
+1724
+1725
+1726
+1727
+1728
+1729
+1730
+1731
+1732
+1733
+1734
+1735
+1736
+1737
+1738
+1739
+1740
+1741
+1742
+1743
+1744
+1745
+1746
+1747
+1748
+1749
+1750
+1751
+1752
+1753
+1754
+1755
+1756
+1757
+1758
+1759
+1760
+1761
+1762
+1763
+1764
+1765
+1766
+1767
+1768
+1769
+1770
+1771
+1772
+1773
+1774
+1775
+1776
+1777
+1778
+1779
+1780
+1781
+1782
+1783
+1784
+1785
+1786
+1787
+1788
+1789
+1790
+1791
+1792
+1793
+1794
+1795
+1796
+1797
+1798
+1799
+1800
+1801
+1802
+1803
+1804
+1805
+1806
+1807
+1808
+1809
+1810
+1811
+1812
+1813
+1814
+1815
+1816
+1817
+1818
+1819
+1820
+1821
+1822
+1823
+1824
+1825
+1826
+1827
+1828
+1829
+1830
+1831
+1832
+1833
+1834
+1835
+1836
+1837
+1838
+1839
+1840
+1841
+1842
+1843
+1844
+1845
+1846
+1847
+1848
+1849
+1850
+1851
+1852
+1853
+1854
+1855
+1856
+1857
+1858
+1859
+1860
+1861
+1862
+1863
+1864
+1865
+1866
+1867
+1868
+1869
+1870
+1871
+1872
+1873
+1874
+1875
+1876
+1877
+1878
+1879
+1880
+1881
+1882
+1883
+1884
+1885
+1886
+1887
+1888
+1889
+1890
+1891
+1892
+1893
+1894
+1895
+1896
+1897
+1898
+1899
+1900
+1901
+1902
+1903
+1904
+1905
+1906
+1907
+1908
+1909
+1910
+1911
+1912
+1913
+1914
+1915
+1916
+1917
+1918
+1919
+1920
+1921
+1922
+1923
+1924
+1925
+1926
+1927
+1928
+1929
+1930
+1931
+1932
+1933
+1934
+1935
+1936
+1937
+1938
+1939
+1940
+1941
+1942
+1943
+1944
+1945
+1946
+1947
+1948
+1949
+1950
+1951
+1952
+1953
+1954
+1955
+1956
+1957
+1958
+1959
+1960
+1961
+1962
+1963
+1964
+1965
+1966
+1967
+1968
+1969
+1970
+1971
+1972
+1973
+1974
+1975
+1976
+1977
+1978
+1979
+1980
+1981
+1982
+1983
+1984
+1985
+1986
+1987
+1988
+1989
+1990
+1991
+1992
+1993
+1994
+1995
+1996
+1997
+1998
+1999
+2000
+2001
+2002
+2003
+2004
+2005
+2006
+2007
+2008
+2009
+2010
+2011
+2012
+2013
+2014
+2015
+2016
+2017
+2018
+2019
+2020
+2021
+2022
+2023
+2024
+2025
+2026
+2027
+2028
+2029
+2030
+2031
+2032
+2033
+2034
+2035
+2036
+2037
+2038
+2039
+2040
+2041
+2042
+2043
+2044
+2045
+2046
+2047
+2048
+2049
+2050
+2051
+2052
+2053
+2054
+2055
+2056
+2057
+2058
+2059
+2060
+2061
+2062
+2063
+2064
+2065
+2066
+2067
+2068
+2069
+2070
+2071
+2072
+2073
+2074
+2075
+2076
+2077
+2078
+2079
+2080
+2081
+2082
+2083
+2084
+2085
+2086
+2087
+2088
+2089
+2090
+2091
+2092
+2093
+2094
+2095
+2096
+2097
+2098
+2099
+2100
+2101
+2102
+2103
+2104
+2105
+2106
+2107
+2108
+2109
+2110
+2111
+2112
+2113
+2114
+2115
+2116
+2117
+2118
+2119
+2120
+2121
+2122
+2123
+2124
+2125
+2126
+2127
+2128
+2129
+2130
+2131
+2132
+2133
+2134
+2135
+2136
+2137
+2138
+2139
+2140
+2141
+2142
+2143
+2144
+2145
+2146
+2147
+2148
+2149
+2150
+2151
+2152
+2153
+2154
+2155
+2156
+2157
+2158
+2159
+2160
+2161
+2162
+2163
+2164
+2165
+2166
+2167
+2168
+2169
+2170
+2171
+2172
+2173
+2174
+2175
+2176
+2177
+2178
+2179
+2180
+2181
+2182
+2183
+2184
+2185
+2186
+2187
+2188
+2189
+2190
+2191
+2192
+2193
+2194
+2195
+2196
+2197
+2198
+2199
+2200
+2201
+2202
+2203
+2204
+2205
+2206
+2207
+2208
+2209
+2210
+2211
+2212
+2213
+2214
+2215
+2216
+2217
+2218
+2219
+2220
+2221
+2222
+2223
+2224
+2225
+2226
+2227
+2228
+2229
+2230
+2231
+2232
+2233
+2234
+2235
+2236
+2237
+2238
+2239
+2240
+2241
+2242
+2243
+2244
+2245
+2246
+2247
+2248
+2249
+2250
+2251
+2252
+2253
+2254
+2255
+2256
+2257
+2258
+2259
+2260
+2261
+2262
+2263
+2264
+2265
+2266
+2267
+2268
+2269
+2270
+2271
+2272
+2273
+2274
+2275
+2276
+2277
+2278
+2279
+2280
+2281
+2282
+2283
+2284
+2285
+2286
+2287
+2288
+2289
+2290
+2291
+2292
+2293
+2294
+2295
+2296
+2297
+2298
+2299
+2300
+2301
+2302
+2303
+2304
+2305
+2306
+2307
+2308
+2309
+2310
+2311
+2312
+2313
+2314
+2315
+2316
+2317
+2318
+2319
+2320
+2321
+2322
+2323
+2324
+2325
+2326
+2327
+2328
+2329
+2330
+2331
+2332
+2333
+2334
+2335
+2336
+2337
+2338
+2339
+2340
+2341
+2342
+2343
+2344
+2345
+2346
+2347
+2348
+2349
+2350
+2351
+2352
+2353
+2354
+2355
+2356
+2357
+2358
+2359
+2360
+2361
+2362
+2363
+2364
+2365
+2366
+2367
+2368
+2369
+2370
+2371
+2372
+2373
+2374
+2375
+2376
+2377
+2378
+2379
+2380
+2381
+2382
+2383
+2384
+2385
+2386
+2387
+2388
+2389
+2390
+2391
+2392
+2393
+2394
+2395
+2396
+2397
+2398
+2399
+2400
+2401
+2402
+2403
+2404
+2405
+2406
+2407
+2408
+2409
+2410
+2411
+2412
+2413
+2414
+2415
+2416
+2417
+2418
+2419
+2420
+2421
+2422
+2423
+2424
+2425
+2426
+2427
+2428
+2429
+2430
+2431
+2432
+2433
+2434
+2435
+2436
+2437
+2438
+2439
+2440
+2441
+2442
+2443
+2444
+2445
+2446
+2447
+2448
+2449
+2450
+2451
+2452
+2453
+2454
+2455
+2456
+2457
+2458
+2459
+2460
+2461
+2462
+2463
+2464
+2465
+2466
+2467
+2468
+2469
+2470
+2471
+2472
+2473
+2474
+2475
+2476
+2477
+2478
+2479
+2480
+2481
+2482
+2483
+2484
+2485
+2486
+2487
+2488
+2489
+2490
+2491
+2492
+2493
+2494
+2495
+2496
+2497
+2498
+2499
+2500
+2501
+2502
+2503
+2504
+2505
+2506
+2507
+2508
+2509
+2510
+2511
+2512
+2513
+2514
+2515
+2516
+2517
+2518
+2519
+2520
+2521
+2522
+2523
+2524
+2525
+2526
+2527
+2528
+2529
+2530
+2531
+2532
+2533
+2534
+2535
+2536
+2537
+2538
+2539
+2540
+2541
+2542
+2543
+2544
+2545
+2546
+2547
+2548
+2549
+2550
+2551
+2552
+2553
+2554
+2555
+2556
+2557
+2558
+2559
+2560
+2561
+2562
+2563
+2564
+2565
+2566
+2567
+2568
+2569
+2570
+2571
+2572
+2573
+2574
+2575
+2576
+2577
+2578
+2579
+2580
+2581
+2582
+2583
+2584
+2585
+2586
+2587
+2588
+2589
+2590
+2591
+2592
+2593
+2594
+2595
+2596
+2597
+2598
+2599
+2600
+2601
+2602
+2603
+2604
+2605
+2606
+2607
+2608
+2609
+2610
+2611
+2612
+2613
+2614
+2615
+2616
+2617
+2618
+2619
+2620
+2621
+2622
+2623
+2624
+2625
+2626
+2627
+2628
+2629
+2630
+2631
+2632
+2633
+2634
+2635
+2636
+2637
+2638
+2639
+2640
+2641
+2642
+2643
+2644
+2645
+2646
+2647
+2648
+2649
+2650
+2651
+2652
+2653
+2654
+2655
+2656
+2657
+2658
+2659
+2660
+2661
+2662
+2663
+2664
+2665
+2666
+2667
+2668
+2669
+2670
+2671
+2672
+2673
+2674
+2675
+2676
+2677
+2678
+2679
+2680
+2681
+2682
+2683
+2684
+2685
+2686
+2687
+2688
+2689
+2690
+2691
+2692
+2693
+2694
+2695
+2696
+2697
+2698
+2699
+2700
+2701
+2702
+2703
+2704
+2705
+2706
+2707
+2708
+2709
+2710
+2711
+2712
+2713
+2714
+2715
+2716
+2717
+2718
+2719
+2720
+2721
+2722
+2723
+2724
+2725
+2726
+2727
+2728
+2729
+2730
+2731
+2732
+2733
+2734
+2735
+2736
+2737
+2738
+2739
+2740
+2741
+2742
+2743
+2744
+2745
+2746
+2747
+2748
+2749
+2750
+2751
+2752
+2753
+2754
+2755
+2756
+2757
+2758
+2759
+2760
+2761
+2762
+2763
+2764
+2765
+2766
+2767
+2768
+2769
+2770
+2771
+2772
+2773
+2774
+2775
+2776
+2777
+2778
+2779
+2780
+2781
+2782
+2783
+2784
+2785
+2786
+2787
+2788
+2789
+2790
+2791
+2792
+2793
+2794
+2795
+2796
+2797
+2798
+2799
+2800
+2801
+2802
+2803
+2804
+2805
+2806
+2807
+2808
+2809
+2810
+2811
+2812
+2813
+2814
+2815
+2816
+2817
+2818
+2819
+2820
+2821
+2822
+2823
+2824
+2825
+2826
+2827
+2828
+2829
+2830
+2831
+2832
+2833
+2834
+2835
+2836
+2837
+2838
+2839
+2840
+2841
+2842
+2843
+2844
+2845
+2846
+2847
+2848
+2849
+2850
+2851
+2852
+2853
+2854
+2855
+2856
+2857
+2858
+2859
+2860
+2861
+2862
+2863
+2864
+2865
+2866
+2867
+2868
+2869
+2870
+2871
+2872
+2873
+2874
+2875
+2876
+2877
+2878
+2879
+2880
+2881
+2882
+2883
+2884
+2885
+2886
+2887
+2888
+2889
+2890
+2891
+2892
+2893
+2894
+2895
+2896
+2897
+2898
+2899
+2900
+2901
+2902
+2903
+2904
+2905
+2906
+2907
+2908
+2909
+2910
+2911
+2912
+2913
+2914
+2915
+2916
+2917
+2918
+2919
+2920
+2921
+2922
+2923
+2924
+2925
+2926
+2927
+2928
+2929
+2930
+2931
+2932
+2933
+2934
+2935
+2936
+2937
+2938
+2939
+2940
+2941
+2942
+2943
+2944
+2945
+2946
+2947
+2948
+2949
+2950
+2951
+2952
+2953
+2954
+2955
+2956
+2957
+2958
+2959
+2960
+2961
+2962
+2963
+2964
+2965
+2966
+2967
+2968
+2969
+2970
+2971
+2972
+2973
+2974
+2975
+2976
+2977
+2978
+2979
+2980
+2981
+2982
+2983
+2984
+2985
+2986
+2987
+2988
+2989
+2990
+2991
+2992
+2993
+2994
+2995
+2996
+2997
+2998
+2999
+3000
+3001
+3002
+3003
+3004
+3005
+3006
+3007
+3008
+3009
+3010
+3011
+3012
+3013
+3014
+3015
+3016
+3017
+3018
+3019
+3020
+3021
+3022
+3023
+3024
+3025
+3026
+3027
+3028
+3029
+3030
+3031
+3032
+3033
+3034
+3035
+3036
+3037
+3038
+3039
+3040
+3041
+3042
+3043
+3044
+3045
+3046
+3047
+3048
+3049
+3050
+3051
+3052
+3053
+3054
+3055
+3056
+3057
+3058
+3059
+3060
+3061
+3062
+3063
+3064
+3065
+3066
+3067
+3068
+3069
+3070
+3071
+3072
+3073
+3074
+3075
+3076
+3077
+3078
+3079
+3080
+3081
+3082
+3083
+3084
+3085
+3086
+3087
+3088
+3089
+3090
+3091
+3092
+3093
+3094
+3095
+3096
+3097
+3098
+3099
+3100
+3101
+3102
+3103
+3104
+3105
+3106
+3107
+3108
+3109
+3110
+3111
+3112
+3113
+3114
+3115
+3116
+3117
+3118
+3119
+3120
+3121
+3122
+3123
+3124
+3125
+3126
+3127
+3128
+3129
+3130
+3131
+3132
+3133
+3134
+3135
+3136
+3137
+3138
+3139
+3140
+3141
+3142
+3143
+3144
+3145
+3146
+3147
+3148
+3149
+3150
+3151
+3152
+3153
+3154
+3155
+3156
+3157
+3158
+3159
+3160
+3161
+3162
+3163
+3164
+3165
+3166
+3167
+3168
+3169
+3170
+3171
+3172
+3173
+3174
+3175
+3176
+3177
+3178
+3179
+3180
+3181
+3182
+3183
+3184
+3185
+3186
+3187
+3188
+3189
+3190
+3191
+3192
+3193
+3194
+3195
+3196
+3197
+3198
+3199
+3200
+3201
+3202
+3203
+3204
+3205
+3206
+3207
+3208
+3209
+3210
+3211
+3212
+3213
+3214
+3215
+3216
+3217
+3218
+3219
+3220
+3221
+3222
+3223
+3224
+3225
+3226
+3227
+3228
+3229
+3230
+3231
+3232
+3233
+3234
+3235
+3236
+3237
+3238
+3239
+3240
+3241
+3242
+3243
+3244
+3245
+3246
+3247
+3248
+3249
+3250
+3251
+3252
+3253
+3254
+3255
+3256
+3257
+3258
+3259
+3260
+3261
+3262
+3263
+3264
+3265
+3266
+3267
+3268
+3269
+3270
+3271
+3272
+3273
+3274
+3275
+3276
+3277
+3278
+3279
+3280
+3281
+3282
+3283
+3284
+3285
+3286
+3287
+3288
+3289
+3290
+3291
+3292
+3293
+3294
+3295
+3296
+3297
+3298
+3299
+3300
+3301
+3302
+3303
+3304
+3305
+3306
+3307
+3308
+3309
+3310
+3311
+3312
+3313
+3314
+3315
+3316
+3317
+3318
+3319
+3320
+3321
+3322
+3323
+3324
+3325
+3326
+3327
+3328
+3329
+3330
+3331
+3332
+3333
+3334
+3335
+3336
+3337
+3338
+3339
+3340
+3341
+3342
+3343
+3344
+3345
+3346
+3347
+3348
+3349
+3350
+3351
+3352
+3353
+3354
+3355
+3356
+3357
+3358
+3359
+3360
+3361
+3362
+3363
+3364
+3365
+3366
+3367
+3368
+3369
+3370
+3371
+3372
+3373
+3374
+3375
+3376
+3377
+3378
+3379
+3380
+3381
+3382
+3383
+3384
+3385
+3386
+3387
+3388
+3389
+3390
+3391
+3392
+3393
+3394
+3395
+3396
+3397
+3398
+3399
+3400
+3401
+3402
+3403
+3404
+3405
+3406
+3407
+3408
+3409
+3410
+3411
+3412
+3413
+3414
+3415
+3416
+3417
+3418
+3419
+3420
+3421
+3422
+3423
+3424
+3425
+3426
+3427
+3428
+3429
+3430
+3431
+3432
+3433
+3434
+3435
+3436
+3437
+3438
+3439
+3440
+3441
+3442
+3443
+3444
+3445
+3446
+3447
+3448
+3449
+3450
+3451
+3452
+3453
+3454
+3455
+3456
+3457
+3458
+3459
+3460
+3461
+3462
+3463
+3464
+3465
+3466
+3467
+3468
+3469
+3470
+3471
+3472
+3473
+3474
+3475
+3476
+3477
+3478
+3479
+3480
+3481
+3482
+3483
+3484
+3485
+3486
+3487
+3488
+3489
+3490
+3491
+3492
+3493
+3494
+3495
+3496
+3497
+3498
+3499
+3500
+3501
+3502
+3503
+3504
+3505
+3506
+3507
+3508
+3509
+3510
+3511
+3512
+3513
+3514
+3515
+3516
+3517
+3518
+3519
+3520
+3521
+3522
+3523
+3524
+3525
+3526
+3527
+3528
+3529
+3530
+3531
+3532
+3533
+3534
+3535
+3536
+3537
+3538
+3539
+3540
+3541
+3542
+3543
+3544
+3545
+3546
+3547
+3548
+3549
+3550
+3551
+3552
+3553
+3554
+3555
+3556
+3557
+3558
+3559
+3560
+3561
+3562
+3563
+3564
+3565
+3566
+3567
+3568
+3569
+3570
+3571
+3572
+3573
+3574
+3575
+3576
+3577
+3578
+3579
+3580
+3581
+3582
+3583
+3584
+3585
+3586
+3587
+3588
+3589
+3590
+3591
+3592
+3593
+3594
+3595
+3596
+3597
+3598
+3599
+3600
+3601
+3602
+3603
+3604
+3605
+3606
+3607
+3608
+3609
+3610
+3611
+3612
+3613
+3614
+3615
+3616
+3617
+3618
+3619
+3620
+3621
+3622
+3623
+3624
+3625
+3626
+3627
+3628
+3629
+3630
+3631
+3632
+3633
+3634
+3635
+3636
+3637
+3638
+3639
+3640
+3641
+3642
+3643
+3644
+3645
+3646
+3647
+3648
+3649
+3650
+3651
+3652
+3653
+3654
+3655
+3656
+3657
+3658
+3659
+3660
+3661
+3662
+3663
+3664
+3665
+3666
+3667
+3668
+3669
+3670
+3671
+3672
+3673
+3674
+3675
+3676
+3677
+3678
+3679
+3680
+3681
+3682
+3683
+3684
+3685
+3686
+3687
+3688
+3689
+3690
+3691
+3692
+3693
+3694
+3695
+3696
+3697
+3698
+3699
+3700
+3701
+3702
+3703
+3704
+3705
+3706
+3707
+3708
+3709
+3710
+3711
+3712
+3713
+3714
+3715
+3716
+3717
+3718
+3719
+3720
+3721
+3722
+3723
+3724
+3725
+3726
+3727
+3728
+3729
+3730
+3731
+3732
+3733
+3734
+3735
+3736
+3737
+3738
+3739
+3740
+3741
+3742
+3743
+3744
+3745
+3746
+3747
+3748
+3749
+3750
+3751
+3752
+3753
+3754
+3755
+3756
+3757
+3758
+3759
+3760
+3761
+3762
+3763
+3764
+3765
+3766
+3767
+3768
+3769
+3770
+3771
+3772
+3773
+3774
+3775
+3776
+3777
+3778
+3779
+3780
+3781
+3782
+3783
+3784
+3785
+3786
+3787
+3788
+3789
+3790
+3791
+3792
+3793
+3794
+3795
+3796
+3797
+3798
+3799
+3800
+3801
+3802
+3803
+3804
+3805
+3806
+3807
+3808
+3809
+3810
+3811
+3812
+3813
+3814
+3815
+3816
+3817
+3818
+3819
+3820
+3821
+3822
+3823
+3824
+3825
+3826
+3827
+3828
+3829
+3830
+3831
+3832
+3833
+3834
+3835
+3836
+3837
+3838
+3839
+3840
+3841
+3842
+3843
+3844
+3845
+3846
+3847
+3848
+3849
+3850
+3851
+3852
+3853
+3854
+3855
+3856
+3857
+3858
+3859
+3860
+3861
+3862
+3863
+3864
+3865
+3866
+3867
+3868
+3869
+3870
+3871
+3872
+3873
+3874
+3875
+3876
+3877
+3878
+3879
+3880
+3881
+3882
+3883
+3884
+3885
+3886
+3887
+3888
+3889
+3890
+3891
+3892
+3893
+3894
+3895
+3896
+3897
+3898
+3899
+3900
+3901
+3902
+3903
+3904
+3905
+3906
+3907
+3908
+3909
+3910
+3911
+3912
+3913
+3914
+3915
+3916
+3917
+3918
+3919
+3920
+3921
+3922
+3923
+3924
+3925
+3926
+3927
+3928
+3929
+3930
+3931
+3932
+3933
+3934
+3935
+3936
+3937
+3938
+3939
+3940
+3941
+3942
+3943
+3944
+3945
+3946
+3947
+3948
+3949
+3950
+3951
+3952
+3953
+3954
+3955
+3956
+3957
+3958
+3959
+3960
+3961
+3962
+3963
+3964
+3965
+3966
+3967
+3968
+3969
+3970
+3971
+3972
+3973
+3974
+3975
+3976
+3977
+3978
+3979
+3980
+3981
+3982
+3983
+3984
+3985
+3986
+3987
+3988
+3989
+3990
+3991
+3992
+3993
+3994
+3995
+3996
+3997
+3998
+3999
+4000
+4001
+4002
+4003
+4004
+4005
+4006
+4007
+4008
+4009
+4010
+4011
+4012
+4013
+4014
+4015
+4016
+4017
+4018
+4019
+4020
+4021
+4022
+4023
+4024
+4025
+4026
+4027
+4028
+4029
+4030
+4031
+4032
+4033
+4034
+4035
+4036
+4037
+4038
+4039
+4040
+4041
+4042
+4043
+4044
+4045
+4046
+4047
+4048
+4049
+4050
+4051
+4052
+4053
+4054
+4055
+4056
+4057
+4058
+4059
+4060
+4061
+4062
+4063
+4064
+4065
+4066
+4067
+4068
+4069
+4070
+4071
+4072
+4073
+4074
+4075
+4076
+4077
+4078
+4079
+4080
+4081
+4082
+4083
+4084
+4085
+4086
+4087
+4088
+4089
+4090
+4091
+4092
+4093
+4094
+4095
+
+ Written Files(4096)
+===DONE===
diff --git a/ext/phar/tests/bug13786.phpt b/ext/phar/tests/bug13786.phpt
new file mode 100644
index 0000000000..572d1eb9aa
--- /dev/null
+++ b/ext/phar/tests/bug13786.phpt
@@ -0,0 +1,32 @@
+--TEST--
+Phar: bug #13786: "PHP crashes on phar recreate after unlink"
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+
+try {
+for ($i = 0; $i < 2; $i++) {
+ $fname = "DataArchive.phar";
+ $path = dirname(__FILE__) . DIRECTORY_SEPARATOR . $fname;
+ $phar = new Phar($path);
+ $phar->addFromString($i, "file $i in $fname");
+ var_dump(file_get_contents($phar[$i]));
+ unset($phar);
+ unlink($path);
+}
+
+echo("\nWritten files: $i\n");
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+
+?>
+===DONE===
+--EXPECTF--
+string(26) "file 0 in DataArchive.phar"
+unable to seek to start of file "0" while creating new phar "%sDataArchive.phar"
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/create_new_and_modify.phpt b/ext/phar/tests/create_new_and_modify.phpt
new file mode 100755
index 0000000000..66587de023
--- /dev/null
+++ b/ext/phar/tests/create_new_and_modify.phpt
@@ -0,0 +1,48 @@
+--TEST--
+Phar: create and modify phar
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=1
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+
+@unlink($fname);
+
+file_put_contents($pname . '/a.php', "brand new!\n");
+
+$phar = new Phar($fname);
+$sig1 = $phar->getSignature();
+
+include $pname . '/a.php';
+
+file_put_contents($pname .'/a.php', "modified!\n");
+file_put_contents($pname .'/b.php', "another!\n");
+
+$phar = new Phar($fname);
+$sig2 = $phar->getSignature();
+
+var_dump($sig1['hash']);
+var_dump($sig2['hash']);
+var_dump($sig1['hash'] != $sig2['hash']);
+
+include $pname . '/a.php';
+include $pname . '/b.php';
+
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECTF--
+brand new!
+string(40) "%s"
+string(40) "%s"
+bool(true)
+modified!
+another!
+===DONE===
diff --git a/ext/phar/tests/create_new_phar.phpt b/ext/phar/tests/create_new_phar.phpt
new file mode 100644
index 0000000000..ec57c27217
--- /dev/null
+++ b/ext/phar/tests/create_new_phar.phpt
@@ -0,0 +1,21 @@
+--TEST--
+Phar: create a completely new phar
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=1
+--FILE--
+<?php
+
+file_put_contents('phar://' . dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php/a.php',
+ 'brand new!');
+include 'phar://' . dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php/a.php';
+?>
+
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECT--
+brand new!
+===DONE===
diff --git a/ext/phar/tests/create_new_phar_b.phpt b/ext/phar/tests/create_new_phar_b.phpt
new file mode 100755
index 0000000000..8f1298245c
--- /dev/null
+++ b/ext/phar/tests/create_new_phar_b.phpt
@@ -0,0 +1,27 @@
+--TEST--
+Phar: create a completely new phar
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=1
+phar.require_hash=1
+--FILE--
+<?php
+
+file_put_contents('phar://' . dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php/a.php',
+ 'brand new!');
+include 'phar://' . dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php/a.php';
+?>
+
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECTF--
+
+Warning: file_put_contents(phar://%screate_new_phar_b.phar.php/a.php): failed to open stream: phar error: write operations disabled by INI setting in %screate_new_phar_b.php on line %d
+
+Warning: include(phar://%screate_new_phar_b.phar.php/a.php): failed to open stream: %s in %screate_new_phar_b.php on line %d
+
+Warning: include(): Failed opening 'phar://%screate_new_phar_b.phar.php/a.php' for inclusion (include_path='%s') in %screate_new_phar_b.php on line %d
+
+===DONE===
diff --git a/ext/phar/tests/create_new_phar_c.phpt b/ext/phar/tests/create_new_phar_c.phpt
new file mode 100755
index 0000000000..6beaa2eb61
--- /dev/null
+++ b/ext/phar/tests/create_new_phar_c.phpt
@@ -0,0 +1,29 @@
+--TEST--
+Phar: create a completely new phar
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=1
+--FILE--
+<?php
+
+file_put_contents('phar://' . dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php/a.php',
+ 'brand new!');
+
+$phar = new Phar(dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php');
+
+var_dump($phar->getSignature());
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECTF--
+array(2) {
+ ["hash"]=>
+ string(40) "%s"
+ ["hash_type"]=>
+ string(5) "SHA-1"
+}
+===DONE===
diff --git a/ext/phar/tests/create_path_error.phpt b/ext/phar/tests/create_path_error.phpt
new file mode 100755
index 0000000000..d3fc035860
--- /dev/null
+++ b/ext/phar/tests/create_path_error.phpt
@@ -0,0 +1,62 @@
+--TEST--
+Phar: create with illegal path
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=1
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+
+@unlink($fname);
+
+file_put_contents($pname . '/a.php?', "query");
+file_put_contents($pname . '/b.php?bla', "query");
+
+var_dump(file_get_contents($pname . '/a.php'));
+var_dump(file_get_contents($pname . '/b.php'));
+
+function error_handler($errno, $errmsg)
+{
+ echo "Error: $errmsg\n";
+}
+
+set_error_handler('error_handler');
+
+$checks = array('/', '.', '../', 'a/..', 'a/', 'b//a.php');
+foreach($checks as $check)
+{
+ file_put_contents($pname . '/' . $check, "error");
+}
+
+$phar = new Phar($fname);
+$checks = array("a\0");
+foreach($checks as $check)
+{
+ try
+ {
+ $phar[$check] = 'error';
+ }
+ catch(Exception $e)
+ {
+ echo 'Exception: ' . $e->getMessage() . "\n";
+ }
+}
+
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECTF--
+string(5) "query"
+string(5) "query"
+Error: file_put_contents(phar://%s//): failed to open stream: phar error: file "" in phar "%s" cannot be empty
+Error: file_put_contents(phar://%s/.): failed to open stream: phar error: file "" in phar "%s" cannot be empty
+Error: file_put_contents(phar://%s/../): failed to open stream: phar error: file "" in phar "%s" cannot be empty
+Error: file_put_contents(phar://%s/a/..): failed to open stream: phar error: file "" in phar "%s" cannot be empty
+Exception: Entry a does not exist and cannot be created: phar error: invalid path "a" contains illegal character
+===DONE===
diff --git a/ext/phar/tests/delete.phpt b/ext/phar/tests/delete.phpt
new file mode 100644
index 0000000000..1d98509064
--- /dev/null
+++ b/ext/phar/tests/delete.phpt
@@ -0,0 +1,31 @@
+--TEST--
+Phar: delete test
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = "<?php
+Phar::mapPhar('hio');
+__HALT_COMPILER(); ?>";
+
+$files = array();
+$files['a'] = 'a';
+include 'files/phar_test.inc';
+include $fname;
+$phar = new Phar($fname);
+
+echo file_get_contents($pname . '/a') . "\n";
+$phar->delete('a');
+echo file_get_contents($pname . '/a') . "\n";
+?>
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECTF--
+a
+
+Warning: file_get_contents(phar://%sdelete.phar.php/a): failed to open stream: phar error: "a" is not a file in phar "%sdelete.phar.php" in %sdelete.php on line 16 \ No newline at end of file
diff --git a/ext/phar/tests/delete_in_phar.phpt b/ext/phar/tests/delete_in_phar.phpt
new file mode 100644
index 0000000000..4842d27913
--- /dev/null
+++ b/ext/phar/tests/delete_in_phar.phpt
@@ -0,0 +1,48 @@
+--TEST--
+Phar: delete a file within a .phar
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = "<?php __HALT_COMPILER(); ?>";
+
+$files = array();
+$files['a.php'] = '<?php echo "This is a\n"; ?>';
+$files['b.php'] = '<?php echo "This is b\n"; ?>';
+$files['b/c.php'] = '<?php echo "This is b/c\n"; ?>';
+include 'files/phar_test.inc';
+
+include $pname . '/a.php';
+include $pname . '/b.php';
+include $pname . '/b/c.php';
+unlink($pname . '/b/c.php');
+?>
+===AFTER===
+<?php
+include $pname . '/a.php';
+include $pname . '/b.php';
+include $pname . '/b/c.php';
+?>
+
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECTF--
+This is a
+This is b
+This is b/c
+===AFTER===
+This is a
+This is b
+
+Warning: include(%sdelete_in_phar.phar.php/b/c.php): failed to open stream: phar error: "b/c.php" is not a file in phar "%sdelete_in_phar.phar.php" in %sdelete_in_phar.php on line %d
+
+Warning: include(): Failed opening 'phar://%sdelete_in_phar.phar.php/b/c.php' for inclusion (include_path='%s') in %sdelete_in_phar.php on line %d
+
+===DONE===
+ \ No newline at end of file
diff --git a/ext/phar/tests/delete_in_phar_b.phpt b/ext/phar/tests/delete_in_phar_b.phpt
new file mode 100755
index 0000000000..d26f51cbf1
--- /dev/null
+++ b/ext/phar/tests/delete_in_phar_b.phpt
@@ -0,0 +1,46 @@
+--TEST--
+Phar: delete a file within a .phar
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=1
+phar.require_hash=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = "<?php __HALT_COMPILER(); ?>";
+
+$files = array();
+$files['a.php'] = '<?php echo "This is a\n"; ?>';
+$files['b.php'] = '<?php echo "This is b\n"; ?>';
+$files['b/c.php'] = '<?php echo "This is b/c\n"; ?>';
+include 'files/phar_test.inc';
+
+include $pname . '/a.php';
+include $pname . '/b.php';
+include $pname . '/b/c.php';
+unlink($pname . '/b/c.php');
+?>
+===AFTER===
+<?php
+include $pname . '/a.php';
+include $pname . '/b.php';
+include $pname . '/b/c.php';
+?>
+
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECTF--
+This is a
+This is b
+This is b/c
+
+Warning: unlink(): phar error: write operations disabled by INI setting in %sdelete_in_phar_b.php on line %d
+===AFTER===
+This is a
+This is b
+This is b/c
+
+===DONE===
diff --git a/ext/phar/tests/delete_in_phar_confirm.phpt b/ext/phar/tests/delete_in_phar_confirm.phpt
new file mode 100644
index 0000000000..13a8d0db29
--- /dev/null
+++ b/ext/phar/tests/delete_in_phar_confirm.phpt
@@ -0,0 +1,51 @@
+--TEST--
+Phar: delete a file within a .phar (confirm disk file is changed)
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = "<?php __HALT_COMPILER(); ?>";
+
+$files = array();
+$files['a.php'] = '<?php echo "This is a\n"; ?>';
+$files['b.php'] = '<?php echo "This is b\n"; ?>';
+$files['b/c.php'] = '<?php echo "This is b/c\n"; ?>';
+include 'files/phar_test.inc';
+
+include $pname . '/a.php';
+include $pname . '/b.php';
+include $pname . '/b/c.php';
+$md5 = md5_file($fname);
+unlink($pname . '/b/c.php');
+clearstatcache();
+$md52 = md5_file($fname);
+if ($md5 == $md52) echo 'file was not modified';
+?>
+===AFTER===
+<?php
+include 'phar://' . dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php/a.php';
+include 'phar://' . dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php/b.php';
+include 'phar://' . dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php/b/c.php';
+?>
+
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECTF--
+This is a
+This is b
+This is b/c
+===AFTER===
+This is a
+This is b
+
+Warning: include(%sdelete_in_phar_confirm.phar.php/b/c.php): failed to open stream: phar error: "b/c.php" is not a file in phar "%sdelete_in_phar_confirm.phar.php" in %sdelete_in_phar_confirm.php on line %d
+
+Warning: include(): Failed opening 'phar://%sdelete_in_phar_confirm.phar.php/b/c.php' for inclusion (include_path='%s') in %sdelete_in_phar_confirm.php on line %d
+
+===DONE===
diff --git a/ext/phar/tests/dir.phpt b/ext/phar/tests/dir.phpt
new file mode 100644
index 0000000000..a8f9d3f889
--- /dev/null
+++ b/ext/phar/tests/dir.phpt
@@ -0,0 +1,92 @@
+--TEST--
+Phar: mkdir/rmdir test
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.1.phar.php';
+$pname2 = 'phar://' . $fname2;
+$fname3 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.2.phar.php';
+$pname3 = 'phar://' . $fname3;
+$phar = new Phar($fname);
+var_dump($phar->isFileFormat(Phar::PHAR));
+
+$phar->addEmptyDir('test');
+var_dump($phar['test']->isDir());
+var_dump($phar['test/']->isDir());
+copy($fname, $fname2);
+mkdir($pname . '/another/dir/');
+var_dump($phar['another/dir']->isDir());
+rmdir($pname . '/another/dir/');
+copy($fname, $fname3);
+clearstatcache();
+var_dump(file_exists($pname . '/another/dir/'));
+var_dump(file_exists($pname2 . '/test/'));
+var_dump(file_exists($pname3 . '/another/dir/'));
+ini_set('phar.readonly', 1);
+mkdir($pname . '/fails');
+ini_set('phar.readonly', 0);
+// create new phar by mkdir
+mkdir('phar://' . dirname(__FILE__) . '/ok.phar/fails');
+mkdir('phar://' . dirname(__FILE__) . '/ok.phar/fails');
+file_put_contents('phar://' . dirname(__FILE__) . '/ok.phar/sub/directory.txt', 'hi');
+mkdir('phar://' . dirname(__FILE__) . '/ok.phar/sub');
+mkdir('phar://' . dirname(__FILE__) . '/ok.phar/sub/directory.txt');
+file_put_contents(dirname(__FILE__) . '/oops.phar', '<?php this should screw em up __HALT_COMPILER();');
+mkdir('phar://' . dirname(__FILE__) . '/oops.phar/fails');
+
+mkdir('phar://');
+rmdir('phar://');
+rmdir('phar://' . dirname(__FILE__) . '/unknown.phar/hi');
+ini_set('phar.readonly', 1);
+rmdir($pname . '/another/dir');
+ini_set('phar.readonly', 0);
+rmdir($pname);
+rmdir($pname . '/');
+mkdir($pname . '/');
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+<?php unlink(dirname(__FILE__) . '/ok.phar'); ?>
+<?php unlink(dirname(__FILE__) . '/oops.phar'); ?>
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.1.phar.php'); ?>
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.2.phar.php'); ?>
+--EXPECTF--
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(false)
+bool(true)
+bool(false)
+
+Warning: mkdir(): phar error: cannot create directory "phar://%sdir.phar.php/fails", write operations disabled in %sdir.php on line %d
+
+Warning: mkdir(): phar error: cannot create directory "fails" in phar "%sok.phar", directory already exists in %sdir.php on line %d
+
+Warning: mkdir(): phar error: cannot create directory "sub" in phar "%sok.phar", directory already exists in %sdir.php on line %d
+
+Warning: mkdir(): phar error: cannot create directory "sub/directory.txt" in phar "%sok.phar", phar error: path "sub/directory.txt" exists and is a not a directory in %sdir.php on line %d
+
+Warning: mkdir(): internal corruption of phar "%soops.phar" (truncated manifest at stub end) in %sdir.php on line %d
+
+Warning: mkdir(): phar error: cannot create directory "phar://", no phar archive specified in %sdir.php on line %d
+
+Warning: rmdir(): phar error: cannot remove directory "phar://", no phar archive specified, or phar archive does not exist in %sdir.php on line %d
+
+Warning: rmdir(): phar error: cannot remove directory "hi" in phar "%sunknown.phar", directory does not exist in %sdir.php on line %d
+
+Warning: rmdir(): phar error: cannot rmdir directory "phar://%sdir.phar.php/another/dir", write operations disabled in %sdir.php on line %d
+
+Warning: rmdir(): phar error: cannot remove directory "" in phar "%sdir.phar.php", directory does not exist in %sdir.php on line %d
+
+Warning: rmdir(): phar error: cannot remove directory "" in phar "%sdir.phar.php", directory does not exist in %sdir.php on line %d
+
+Warning: mkdir(): phar error: cannot create directory "" in phar "%sdir.phar.php", phar error: invalid path "" must not be empty in %sdir.php on line %d
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/fgc_edgecases.phpt b/ext/phar/tests/fgc_edgecases.phpt
new file mode 100644
index 0000000000..e899604e95
--- /dev/null
+++ b/ext/phar/tests/fgc_edgecases.phpt
@@ -0,0 +1,95 @@
+--TEST--
+Phar: test edge cases of file_get_contents() function interception
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip");?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+Phar::interceptFileFuncs();
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+
+file_get_contents(array());
+chdir(dirname(__FILE__));
+file_put_contents($fname, "blah\n");
+file_put_contents("foob", "test\n");
+echo file_get_contents($fname);
+unlink($fname);
+mkdir($pname . '/oops');
+file_put_contents($pname . '/foo/hi', '<?php
+echo file_get_contents("foo/" . basename(__FILE__));
+$context = stream_context_create();
+file_get_contents("./hi", 0, $context, 0, -1);
+echo file_get_contents("foob");
+set_include_path("' . addslashes(dirname(__FILE__)) . '");
+echo file_get_contents("foob", true);
+echo file_get_contents("./hi", 0, $context);
+echo file_get_contents("../oops");
+echo file_get_contents("./hi", 0, $context, 50000);
+ini_set("magic_quotes_runtime", 1);
+echo file_get_contents("./hi");
+echo file_get_contents("./hi", 0, $context, 0, 0);
+?>
+');
+include $pname . '/foo/hi';
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+<?php rmdir(dirname(__FILE__) . '/poo'); ?>
+<?php unlink(dirname(__FILE__) . '/foob'); ?>
+--EXPECTF--
+Warning: file_get_contents() expects parameter 1 to be string, array given in %sfgc_edgecases.php on line %d
+blah
+<?php
+echo file_get_contents("foo/" . basename(__FILE__));
+$context = stream_context_create();
+file_get_contents("./hi", 0, $context, 0, -1);
+echo file_get_contents("foob");
+set_include_path("%stests");
+echo file_get_contents("foob", true);
+echo file_get_contents("./hi", 0, $context);
+echo file_get_contents("../oops");
+echo file_get_contents("./hi", 0, $context, 50000);
+ini_set("magic_quotes_runtime", 1);
+echo file_get_contents("./hi");
+echo file_get_contents("./hi", 0, $context, 0, 0);
+?>
+
+Warning: file_get_contents(): length must be greater than or equal to zero in phar://%sfgc_edgecases.phar.php/foo/hi on line %d
+test
+test
+<?php
+echo file_get_contents("foo/" . basename(__FILE__));
+$context = stream_context_create();
+file_get_contents("./hi", 0, $context, 0, -1);
+echo file_get_contents("foob");
+set_include_path("%stests");
+echo file_get_contents("foob", true);
+echo file_get_contents("./hi", 0, $context);
+echo file_get_contents("../oops");
+echo file_get_contents("./hi", 0, $context, 50000);
+ini_set("magic_quotes_runtime", 1);
+echo file_get_contents("./hi");
+echo file_get_contents("./hi", 0, $context, 0, 0);
+?>
+
+Warning: file_get_contents(phar://%sfgc_edgecases.phar.php/oops): failed to open stream: phar error: path "oops" is a directory in phar://%sfgc_edgecases.phar.php/foo/hi on line %d
+
+Warning: file_get_contents(): Failed to seek to position 50000 in the stream in phar://%sfgc_edgecases.phar.php/foo/hi on line %d
+<?php
+echo file_get_contents(\"foo/\" . basename(__FILE__));
+$context = stream_context_create();
+file_get_contents(\"./hi\", 0, $context, 0, -1);
+echo file_get_contents(\"foob\");
+set_include_path(\"%stests\");
+echo file_get_contents(\"foob\", true);
+echo file_get_contents(\"./hi\", 0, $context);
+echo file_get_contents(\"../oops\");
+echo file_get_contents(\"./hi\", 0, $context, 50000);
+ini_set(\"magic_quotes_runtime\", 1);
+echo file_get_contents(\"./hi\");
+echo file_get_contents(\"./hi\", 0, $context, 0, 0);
+?>
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/file_get_contents.phpt b/ext/phar/tests/file_get_contents.phpt
new file mode 100644
index 0000000000..fcc9d64655
--- /dev/null
+++ b/ext/phar/tests/file_get_contents.phpt
@@ -0,0 +1,30 @@
+--TEST--
+Phar: test file_get_contents() interception
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip");?>
+--INI--
+phar.require_hash=1
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$a = new Phar($fname);
+$a['index.php'] = '<?php
+echo file_get_contents("dir/file1.txt");
+echo file_get_contents("file1.txt", true);
+?>';
+$a['dir/file1.txt'] = 'hi';
+$a['dir/file2.txt'] = 'hi2';
+$a['dir/file3.txt'] = 'hi3';
+$a->setStub('<?php
+Phar::interceptFileFuncs();
+set_include_path("phar://" . __FILE__ . "/dir" . PATH_SEPARATOR . "phar://" . __FILE__);
+include "index.php";
+__HALT_COMPILER();');
+include $fname;
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECT--
+hihi===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/files/extracted.inc b/ext/phar/tests/files/extracted.inc
new file mode 100644
index 0000000000..a6e52246a3
--- /dev/null
+++ b/ext/phar/tests/files/extracted.inc
@@ -0,0 +1 @@
+<?php var_dump(__FILE__); ?>
diff --git a/ext/phar/tests/files/frontcontroller.phar b/ext/phar/tests/files/frontcontroller.phar
new file mode 100644
index 0000000000..626bf48acf
--- /dev/null
+++ b/ext/phar/tests/files/frontcontroller.phar
Binary files differ
diff --git a/ext/phar/tests/files/frontcontroller.phar.inc b/ext/phar/tests/files/frontcontroller.phar.inc
new file mode 100644
index 0000000000..80d42e886b
--- /dev/null
+++ b/ext/phar/tests/files/frontcontroller.phar.inc
@@ -0,0 +1,13 @@
+<?php
+@unlink(dirname(__FILE__) . '/frontcontroller.phar');
+$a = new Phar(dirname(__FILE__) . '/frontcontroller.phar');
+$a['a.php'] = 'hio';
+$a['a.jpg'] = 'hio';
+$a['a.phps'] = '<?php function hio(){}';
+$a['index.php'] = 'here is my index';
+$a->setStub('<?php
+Phar::webPhar();
+echo "oops did not run\n";
+var_dump($_ENV, $_SERVER);
+__HALT_COMPILER();');
+?>
diff --git a/ext/phar/tests/files/frontcontroller10.phar b/ext/phar/tests/files/frontcontroller10.phar
new file mode 100644
index 0000000000..078ce75b2c
--- /dev/null
+++ b/ext/phar/tests/files/frontcontroller10.phar
Binary files differ
diff --git a/ext/phar/tests/files/frontcontroller10.phar.inc b/ext/phar/tests/files/frontcontroller10.phar.inc
new file mode 100644
index 0000000000..4c139db58b
--- /dev/null
+++ b/ext/phar/tests/files/frontcontroller10.phar.inc
@@ -0,0 +1,20 @@
+<?php
+@unlink(dirname(__FILE__) . '/frontcontroller10.phar');
+$a = new Phar(dirname(__FILE__) . '/frontcontroller10.phar');
+$a['index.php'] = '<?php
+var_dump($_SERVER["PHP_SELF"]);
+var_dump($_SERVER["SCRIPT_NAME"]);
+var_dump($_SERVER["SCRIPT_FILENAME"]);
+var_dump($_SERVER["REQUEST_URI"]);
+var_dump($_SERVER["PHAR_PHP_SELF"]);
+var_dump($_SERVER["PHAR_SCRIPT_NAME"]);
+var_dump($_SERVER["PHAR_SCRIPT_FILENAME"]);
+var_dump($_SERVER["PHAR_REQUEST_URI"]);
+';
+$a->setStub('<?php
+Phar::mungServer(array("PHP_SELF", "SCRIPT_NAME", "SCRIPT_FILENAME", "REQUEST_URI", "OOPSIE"));
+Phar::webPhar();
+echo "oops did not run\n";
+var_dump($_ENV, $_SERVER);
+__HALT_COMPILER();');
+?>
diff --git a/ext/phar/tests/files/frontcontroller11.phar b/ext/phar/tests/files/frontcontroller11.phar
new file mode 100644
index 0000000000..61ea843222
--- /dev/null
+++ b/ext/phar/tests/files/frontcontroller11.phar
Binary files differ
diff --git a/ext/phar/tests/files/frontcontroller11.phar.inc b/ext/phar/tests/files/frontcontroller11.phar.inc
new file mode 100644
index 0000000000..086350800b
--- /dev/null
+++ b/ext/phar/tests/files/frontcontroller11.phar.inc
@@ -0,0 +1,20 @@
+<?php
+@unlink(dirname(__FILE__) . '/frontcontroller11.phar');
+$a = new Phar(dirname(__FILE__) . '/frontcontroller11.phar');
+$a['index.php'] = '<?php
+var_dump($_SERVER["PHP_SELF"]);
+var_dump($_SERVER["SCRIPT_NAME"]);
+var_dump($_SERVER["SCRIPT_FILENAME"]);
+var_dump($_SERVER["REQUEST_URI"]);
+var_dump($_SERVER["PHAR_PHP_SELF"]);
+var_dump($_SERVER["PHAR_SCRIPT_NAME"]);
+var_dump($_SERVER["PHAR_SCRIPT_FILENAME"]);
+var_dump($_SERVER["PHAR_REQUEST_URI"]);
+';
+$a->setStub('<?php
+Phar::mungServer(array(array(), "SCRIPT_NAME", "SCRIPT_FILENAME", "REQUEST_URI"));
+Phar::webPhar();
+echo "oops did not run\n";
+var_dump($_ENV, $_SERVER);
+__HALT_COMPILER();');
+?>
diff --git a/ext/phar/tests/files/frontcontroller12.phar b/ext/phar/tests/files/frontcontroller12.phar
new file mode 100644
index 0000000000..9e45587610
--- /dev/null
+++ b/ext/phar/tests/files/frontcontroller12.phar
Binary files differ
diff --git a/ext/phar/tests/files/frontcontroller12.phar.inc b/ext/phar/tests/files/frontcontroller12.phar.inc
new file mode 100644
index 0000000000..ba17df37e1
--- /dev/null
+++ b/ext/phar/tests/files/frontcontroller12.phar.inc
@@ -0,0 +1,20 @@
+<?php
+@unlink(dirname(__FILE__) . '/frontcontroller12.phar');
+$a = new Phar(dirname(__FILE__) . '/frontcontroller12.phar');
+$a['index.php'] = '<?php
+var_dump($_SERVER["PHP_SELF"]);
+var_dump($_SERVER["SCRIPT_NAME"]);
+var_dump($_SERVER["SCRIPT_FILENAME"]);
+var_dump($_SERVER["REQUEST_URI"]);
+var_dump($_SERVER["PHAR_PHP_SELF"]);
+var_dump($_SERVER["PHAR_SCRIPT_NAME"]);
+var_dump($_SERVER["PHAR_SCRIPT_FILENAME"]);
+var_dump($_SERVER["PHAR_REQUEST_URI"]);
+';
+$a->setStub('<?php
+Phar::mungServer(array("PHP_SELF", "SCRIPT_NAME", "SCRIPT_FILENAME", "REQUEST_URI"));
+Phar::webPhar();
+echo "oops did not run\n";
+var_dump($_ENV, $_SERVER);
+__HALT_COMPILER();');
+?>
diff --git a/ext/phar/tests/files/frontcontroller13.phar b/ext/phar/tests/files/frontcontroller13.phar
new file mode 100644
index 0000000000..750ff27a8e
--- /dev/null
+++ b/ext/phar/tests/files/frontcontroller13.phar
Binary files differ
diff --git a/ext/phar/tests/files/frontcontroller13.phar.inc b/ext/phar/tests/files/frontcontroller13.phar.inc
new file mode 100644
index 0000000000..0bfef46853
--- /dev/null
+++ b/ext/phar/tests/files/frontcontroller13.phar.inc
@@ -0,0 +1,14 @@
+<?php
+@unlink(dirname(__FILE__) . '/frontcontroller13.phar');
+$a = new Phar(dirname(__FILE__) . '/frontcontroller13.phar');
+$a['index.php'] = '<?php
+var_dump("test");
+include "oof/test.php";';
+$a['oof/test.php'] = '<?php
+var_dump("oof/test.php");
+include "./hi.php";';
+$a['oof/hi.php'] = '<?php
+var_dump("hi");';
+$a->setStub('<?php
+Phar::webPhar();
+__HALT_COMPILER();'); \ No newline at end of file
diff --git a/ext/phar/tests/files/frontcontroller14.phar b/ext/phar/tests/files/frontcontroller14.phar
new file mode 100644
index 0000000000..78a42a999f
--- /dev/null
+++ b/ext/phar/tests/files/frontcontroller14.phar
Binary files differ
diff --git a/ext/phar/tests/files/frontcontroller14.phar.inc b/ext/phar/tests/files/frontcontroller14.phar.inc
new file mode 100644
index 0000000000..d0ebd9a45a
--- /dev/null
+++ b/ext/phar/tests/files/frontcontroller14.phar.inc
@@ -0,0 +1,19 @@
+<?php
+@unlink(dirname(__FILE__) . '/frontcontroller14.phar');
+$a = new Phar(dirname(__FILE__) . '/frontcontroller14.phar');
+$a['html/index.php'] = '<?php
+var_dump($_SERVER["PATH_INFO"]);
+var_dump($_SERVER["PATH_TRANSLATED"]);
+';
+$a->setStub('<?php
+function s($a)
+{
+ return "/html/index.php";
+}
+Phar::interceptFileFuncs();
+Phar::mungServer(array("PHP_SELF", "REQUEST_URI"));
+Phar::webPhar("whatever", "/html/index.php", null, array(), "s");
+echo "oops did not run\n";
+var_dump($_ENV, $_SERVER);
+__HALT_COMPILER();');
+?>
diff --git a/ext/phar/tests/files/frontcontroller16.phar b/ext/phar/tests/files/frontcontroller16.phar
new file mode 100644
index 0000000000..cce5db5bb5
--- /dev/null
+++ b/ext/phar/tests/files/frontcontroller16.phar
Binary files differ
diff --git a/ext/phar/tests/files/frontcontroller16.phar.inc b/ext/phar/tests/files/frontcontroller16.phar.inc
new file mode 100644
index 0000000000..3c9986da00
--- /dev/null
+++ b/ext/phar/tests/files/frontcontroller16.phar.inc
@@ -0,0 +1,16 @@
+<?php
+@unlink(dirname(__FILE__) . '/frontcontroller16.phar');
+$a = new Phar(dirname(__FILE__) . '/frontcontroller16.phar');
+$a['index.php'] = '<?php
+echo "hi";
+';
+$a->setStub('<?php
+try {
+Phar::webPhar("test.phar", "/index.php", null, array(), array("fail", "here"));
+} catch (Exception $e) {
+die($e->getMessage() . "\n");
+}
+echo "oops did not run\n";
+var_dump($_ENV, $_SERVER);
+__HALT_COMPILER();');
+?>
diff --git a/ext/phar/tests/files/frontcontroller17.phar b/ext/phar/tests/files/frontcontroller17.phar
new file mode 100644
index 0000000000..b83d41fd5b
--- /dev/null
+++ b/ext/phar/tests/files/frontcontroller17.phar
Binary files differ
diff --git a/ext/phar/tests/files/frontcontroller17.phar.inc b/ext/phar/tests/files/frontcontroller17.phar.inc
new file mode 100644
index 0000000000..85b8729f31
--- /dev/null
+++ b/ext/phar/tests/files/frontcontroller17.phar.inc
@@ -0,0 +1,16 @@
+<?php
+@unlink(dirname(__FILE__) . '/frontcontroller17.phar');
+$a = new Phar(dirname(__FILE__) . '/frontcontroller17.phar');
+$a['index.php'] = '<?php
+echo "hi";
+';
+$a->setStub('<?php
+try {
+Phar::webPhar("test.phar", "/index.php", null, array(), "sort");
+} catch (Exception $e) {
+die($e->getMessage() . "\n");
+}
+echo "oops did not run\n";
+var_dump($_ENV, $_SERVER);
+__HALT_COMPILER();');
+?>
diff --git a/ext/phar/tests/files/frontcontroller18.phar b/ext/phar/tests/files/frontcontroller18.phar
new file mode 100644
index 0000000000..c447f397ac
--- /dev/null
+++ b/ext/phar/tests/files/frontcontroller18.phar
Binary files differ
diff --git a/ext/phar/tests/files/frontcontroller18.phar.inc b/ext/phar/tests/files/frontcontroller18.phar.inc
new file mode 100644
index 0000000000..847a713ba3
--- /dev/null
+++ b/ext/phar/tests/files/frontcontroller18.phar.inc
@@ -0,0 +1,19 @@
+<?php
+@unlink(dirname(__FILE__) . '/frontcontroller18.phar');
+$a = new Phar(dirname(__FILE__) . '/frontcontroller18.phar');
+$a['index.php'] = '<?php
+echo "hi";
+';
+$a->setStub('<?php
+function s($a)
+{
+}
+try {
+Phar::webPhar("test.phar", "/index.php", null, array(), "s");
+} catch (Exception $e) {
+die($e->getMessage() . "\n");
+}
+echo "oops did not run\n";
+var_dump($_ENV, $_SERVER);
+__HALT_COMPILER();');
+?>
diff --git a/ext/phar/tests/files/frontcontroller19.phar b/ext/phar/tests/files/frontcontroller19.phar
new file mode 100644
index 0000000000..bdf8ee13c2
--- /dev/null
+++ b/ext/phar/tests/files/frontcontroller19.phar
Binary files differ
diff --git a/ext/phar/tests/files/frontcontroller19.phar.inc b/ext/phar/tests/files/frontcontroller19.phar.inc
new file mode 100644
index 0000000000..ba84ac410a
--- /dev/null
+++ b/ext/phar/tests/files/frontcontroller19.phar.inc
@@ -0,0 +1,25 @@
+<?php
+@unlink(dirname(__FILE__) . '/frontcontroller19.phar');
+$a = new Phar(dirname(__FILE__) . '/frontcontroller19.phar');
+$a['start/index.php'] = '<?php
+echo "start/index.php\n";
+include "./another.php";
+';
+$a['start/another.php'] = '<?php
+echo "start/another.php\n";
+include "../another.php";
+?>';
+$a['another.php'] = '<?php
+echo "another.php\n";
+?>';
+$a->setStub('<?php
+set_include_path("phar://" . __FILE__);
+try {
+Phar::webPhar("test.phar", "/start/index.php");
+} catch (Exception $e) {
+die($e->getMessage() . "\n");
+}
+echo "oops did not run\n";
+var_dump($_ENV, $_SERVER);
+__HALT_COMPILER();');
+?>
diff --git a/ext/phar/tests/files/frontcontroller2.phar b/ext/phar/tests/files/frontcontroller2.phar
new file mode 100644
index 0000000000..0dd0e7f695
--- /dev/null
+++ b/ext/phar/tests/files/frontcontroller2.phar
Binary files differ
diff --git a/ext/phar/tests/files/frontcontroller2.phar.inc b/ext/phar/tests/files/frontcontroller2.phar.inc
new file mode 100644
index 0000000000..653c79691d
--- /dev/null
+++ b/ext/phar/tests/files/frontcontroller2.phar.inc
@@ -0,0 +1,12 @@
+<?php
+@unlink(dirname(__FILE__) . '/frontcontroller2.phar');
+$a = new Phar(dirname(__FILE__) . '/frontcontroller2.phar');
+$a['a.php'] = 'hio';
+$a['a.jpg'] = 'hio';
+$a['a.phps'] = '<?php function hio(){}';
+$a->setStub('<?php
+Phar::webPhar("whatever", "a.php");
+echo "oops did not run\n";
+var_dump($_ENV, $_SERVER);
+__HALT_COMPILER();');
+?>
diff --git a/ext/phar/tests/files/frontcontroller3.phar b/ext/phar/tests/files/frontcontroller3.phar
new file mode 100644
index 0000000000..afcf03af35
--- /dev/null
+++ b/ext/phar/tests/files/frontcontroller3.phar
Binary files differ
diff --git a/ext/phar/tests/files/frontcontroller3.phar.inc b/ext/phar/tests/files/frontcontroller3.phar.inc
new file mode 100644
index 0000000000..2759d9ee45
--- /dev/null
+++ b/ext/phar/tests/files/frontcontroller3.phar.inc
@@ -0,0 +1,18 @@
+<?php
+@unlink(dirname(__FILE__) . '/frontcontroller3.phar');
+$a = new Phar(dirname(__FILE__) . '/frontcontroller3.phar');
+$a['a.php'] = 'hio';
+$a['a.jpg'] = 'hio';
+$a['a.phps'] = '<?php function hio(){}';
+$a->setStub('<?php
+function s($a)
+{
+ static $b = array("/hi" => "a.phps");
+ if (isset($b[$a])) return $b[$a];
+ return $a;
+}
+Phar::webPhar("whatever", "/index.php", null, array(), "s");
+echo "oops did not run\n";
+var_dump($_ENV, $_SERVER);
+__HALT_COMPILER();');
+?>
diff --git a/ext/phar/tests/files/frontcontroller4.phar b/ext/phar/tests/files/frontcontroller4.phar
new file mode 100644
index 0000000000..4c9a92a197
--- /dev/null
+++ b/ext/phar/tests/files/frontcontroller4.phar
Binary files differ
diff --git a/ext/phar/tests/files/frontcontroller4.phar.inc b/ext/phar/tests/files/frontcontroller4.phar.inc
new file mode 100644
index 0000000000..5c6a43f954
--- /dev/null
+++ b/ext/phar/tests/files/frontcontroller4.phar.inc
@@ -0,0 +1,18 @@
+<?php
+@unlink(dirname(__FILE__) . '/frontcontroller4.phar');
+$a = new Phar(dirname(__FILE__) . '/frontcontroller4.phar');
+$a['a.php'] = 'hio';
+$a['a.jpg'] = 'hio';
+$a['a.phps'] = '<?php function hio(){}';
+$a->setStub('<?php
+function s($a)
+{
+ static $b = array("/hi" => false);
+ if (isset($b[$a])) return $b[$a];
+ return $a;
+}
+Phar::webPhar("whatever", "index.php", null, array(), "s");
+echo "oops did not run\n";
+var_dump($_ENV, $_SERVER);
+__HALT_COMPILER();');
+?>
diff --git a/ext/phar/tests/files/frontcontroller5.phar b/ext/phar/tests/files/frontcontroller5.phar
new file mode 100644
index 0000000000..f206b5996d
--- /dev/null
+++ b/ext/phar/tests/files/frontcontroller5.phar
Binary files differ
diff --git a/ext/phar/tests/files/frontcontroller5.phar.inc b/ext/phar/tests/files/frontcontroller5.phar.inc
new file mode 100644
index 0000000000..d2d810c367
--- /dev/null
+++ b/ext/phar/tests/files/frontcontroller5.phar.inc
@@ -0,0 +1,12 @@
+<?php
+@unlink(dirname(__FILE__) . '/frontcontroller5.phar');
+$a = new Phar(dirname(__FILE__) . '/frontcontroller5.phar');
+$a['a.php'] = 'hio';
+$a['a.jpg'] = 'hio';
+$a['a.phps'] = '<?php function hio(){}';
+$a->setStub('<?php
+Phar::webPhar("whatever", "index.php", null, array(0 => "oops"));
+echo "oops did not run\n";
+var_dump($_ENV, $_SERVER);
+__HALT_COMPILER();');
+?>
diff --git a/ext/phar/tests/files/frontcontroller6.phar b/ext/phar/tests/files/frontcontroller6.phar
new file mode 100644
index 0000000000..e3b6bb86a1
--- /dev/null
+++ b/ext/phar/tests/files/frontcontroller6.phar
Binary files differ
diff --git a/ext/phar/tests/files/frontcontroller6.phar.inc b/ext/phar/tests/files/frontcontroller6.phar.inc
new file mode 100644
index 0000000000..5c900eb603
--- /dev/null
+++ b/ext/phar/tests/files/frontcontroller6.phar.inc
@@ -0,0 +1,12 @@
+<?php
+@unlink(dirname(__FILE__) . '/frontcontroller6.phar');
+$a = new Phar(dirname(__FILE__) . '/frontcontroller6.phar');
+$a['a.php'] = 'hio';
+$a['a.jpg'] = 'hio';
+$a['a.phps'] = '<?php function hio(){}';
+$a->setStub('<?php
+Phar::webPhar("whatever", "index.php", null, array("blah" => 100));
+echo "oops did not run\n";
+var_dump($_ENV, $_SERVER);
+__HALT_COMPILER();');
+?>
diff --git a/ext/phar/tests/files/frontcontroller7.phar b/ext/phar/tests/files/frontcontroller7.phar
new file mode 100644
index 0000000000..79672809b4
--- /dev/null
+++ b/ext/phar/tests/files/frontcontroller7.phar
Binary files differ
diff --git a/ext/phar/tests/files/frontcontroller7.phar.inc b/ext/phar/tests/files/frontcontroller7.phar.inc
new file mode 100644
index 0000000000..684970263e
--- /dev/null
+++ b/ext/phar/tests/files/frontcontroller7.phar.inc
@@ -0,0 +1,12 @@
+<?php
+@unlink(dirname(__FILE__) . '/frontcontroller7.phar');
+$a = new Phar(dirname(__FILE__) . '/frontcontroller7.phar');
+$a['a.php'] = 'hio';
+$a['a.jpg'] = 'hio';
+$a['a.phps'] = '<?php function hio(){}';
+$a->setStub('<?php
+Phar::webPhar("whatever", "index.php", null, array("blah" => null));
+echo "oops did not run\n";
+var_dump($_ENV, $_SERVER);
+__HALT_COMPILER();');
+?>
diff --git a/ext/phar/tests/files/frontcontroller8.phar b/ext/phar/tests/files/frontcontroller8.phar
new file mode 100644
index 0000000000..ec05ceafb0
--- /dev/null
+++ b/ext/phar/tests/files/frontcontroller8.phar
Binary files differ
diff --git a/ext/phar/tests/files/frontcontroller8.phar.inc b/ext/phar/tests/files/frontcontroller8.phar.inc
new file mode 100644
index 0000000000..1dfb654a03
--- /dev/null
+++ b/ext/phar/tests/files/frontcontroller8.phar.inc
@@ -0,0 +1,19 @@
+<?php
+@unlink(dirname(__FILE__) . '/frontcontroller8.phar');
+$a = new Phar(dirname(__FILE__) . '/frontcontroller8.phar');
+$a['a.phps'] = 'hio1';
+$a['a1.phps'] = '<?php var_dump($_SERVER["REQUEST_URI"], $_SERVER["PATH_INFO"]);';
+$a['a.jpg'] = 'hio2';
+$a['a.php'] = '<?php function hio(){}';
+$a['fronk.gronk'] = 'hio3';
+$a['404.php'] = 'My 404 is rawesome';
+$a['noext'] = 'hi';
+$a['unknown.ext'] = '<?php var_dump("hi");';
+$a['bigfile.txt'] = str_repeat('a', 8193);
+$a['fatalerror.phps'] = '<?php oopsie_daisy();';
+$a->setStub('<?php
+Phar::webPhar("whatever", "index.php", "404.php", array("jpg" => "foo/bar", "phps" => Phar::PHP, "php" => Phar::PHPS));
+echo "oops did not run\n";
+var_dump($_ENV, $_SERVER);
+__HALT_COMPILER();');
+?>
diff --git a/ext/phar/tests/files/frontcontroller9.phar b/ext/phar/tests/files/frontcontroller9.phar
new file mode 100644
index 0000000000..39ca28c96c
--- /dev/null
+++ b/ext/phar/tests/files/frontcontroller9.phar
Binary files differ
diff --git a/ext/phar/tests/files/frontcontroller9.phar.inc b/ext/phar/tests/files/frontcontroller9.phar.inc
new file mode 100644
index 0000000000..00861f6420
--- /dev/null
+++ b/ext/phar/tests/files/frontcontroller9.phar.inc
@@ -0,0 +1,14 @@
+<?php
+@unlink(dirname(__FILE__) . '/frontcontroller9.phar');
+$a = new Phar(dirname(__FILE__) . '/frontcontroller9.phar');
+$a['a.phps'] = 'hio1';
+$a['a.jpg'] = 'hio2';
+$a['a.php'] = '<?php function hio(){}';
+$a['fronk.gronk'] = 'hio3';
+$a->setStub('<?php
+Phar::mungServer(array());
+Phar::webPhar("whatever", "index.php", null, array("jpg" => "foo/bar", "phps" => Phar::PHP, "php" => Phar::PHPS));
+echo "oops did not run\n";
+var_dump($_ENV, $_SERVER);
+__HALT_COMPILER();');
+?>
diff --git a/ext/phar/tests/files/md5.phar b/ext/phar/tests/files/md5.phar
new file mode 100644
index 0000000000..8ca2f84dac
--- /dev/null
+++ b/ext/phar/tests/files/md5.phar
Binary files differ
diff --git a/ext/phar/tests/files/nophar.phar b/ext/phar/tests/files/nophar.phar
new file mode 100644
index 0000000000..f1c5252018
--- /dev/null
+++ b/ext/phar/tests/files/nophar.phar
Binary files differ
diff --git a/ext/phar/tests/files/nophar.phar.inc b/ext/phar/tests/files/nophar.phar.inc
new file mode 100644
index 0000000000..36d5628762
--- /dev/null
+++ b/ext/phar/tests/files/nophar.phar.inc
@@ -0,0 +1,10 @@
+<?php
+$fname = dirname(__FILE__) . '/nophar.phar';
+@unlink($fname);
+$p = new Phar($fname);
+$p['index.php'] = '<?php include "b/c.php";' . "\n";
+$p['web.php'] = '<?php echo "web\n";';
+$p['b/c.php'] = '<?php echo "in b\n";$a = fopen("index.php", "r", true);echo stream_get_contents($a);fclose($a);include dirname(__FILE__) . "/../d";';
+$p['d'] = "in d\n";
+$p->setStub($p->createDefaultStub('index.php', 'web.php'));
+?> \ No newline at end of file
diff --git a/ext/phar/tests/files/phar_oo_test.inc b/ext/phar/tests/files/phar_oo_test.inc
new file mode 100644
index 0000000000..9863e8da93
--- /dev/null
+++ b/ext/phar/tests/files/phar_oo_test.inc
@@ -0,0 +1,49 @@
+<?php
+
+ini_set('date.timezone', 'GMT');
+
+$fname = dirname(__FILE__) . '/phar_oo_test.phar.php';
+$pname = 'phar://' . $fname;
+$file = '<?php include "' . $pname . '/a.php"; __HALT_COMPILER(); ?>';
+
+$files = array();
+
+if (!isset($pharconfig)) $pharconfig = 0;
+
+switch($pharconfig)
+{
+ default:
+ case 0:
+ $files['a.php'] = '<?php echo "This is a.php\n"; ?>';
+ $files['b.php'] = '<?php echo "This is b.php\n"; ?>';
+ $files['b/c.php'] = '<?php echo "This is b/c.php\n"; ?>';
+ $files['b/d.php'] = '<?php echo "This is b/d.php\n"; ?>';
+ $files['e.php'] = '<?php echo "This is e.php\n"; ?>';
+ break;
+ case 1:
+ $files['a.csv'] =<<<EOF
+1,2,3
+2,a,b
+3,"c","'e'"
+EOF;
+ break;
+ case 2:
+ $files['a.csv'] =<<<EOF
+1,2,3
+2,a,b
+3,"c","'e'"
+4
+5,5
+
+7,777
+EOF;
+ break;
+ case 3:
+ $files['a.php'] = '<?php echo new new class;';
+ break;
+}
+
+$ftime = mktime(12, 0, 0, 3, 1, 2006);
+include 'phar_test.inc';
+
+?> \ No newline at end of file
diff --git a/ext/phar/tests/files/phar_test.inc b/ext/phar/tests/files/phar_test.inc
new file mode 100644
index 0000000000..a5e9d3fdc8
--- /dev/null
+++ b/ext/phar/tests/files/phar_test.inc
@@ -0,0 +1,76 @@
+<?php
+
+if (function_exists('date_default_timezone_set')) {
+ date_default_timezone_set('UTC');
+}
+
+$manifest = '';
+$glags = 0;
+
+foreach($files as $name => $cont)
+{
+ global $gflags, $files;
+
+ $comp = NULL;
+ $crc32= NULL;
+ $clen = NULL;
+ $ulen = NULL;
+ $time = isset($ftime) ? $ftime : @mktime(12, 0, 0, 3, 1, 2006);
+ $flags= 0;
+ $perm = 0x000001B6;
+ $meta = NULL;
+
+ // overwrite if array
+ if (is_array($cont))
+ {
+ foreach(array('comp','crc32','clen','ulen','time','flags','perm','meta','cont') as $what)
+ {
+ if (isset($cont[$what]))
+ {
+ $$what = $cont[$what];
+ }
+ }
+ }
+
+ // create if not yet done
+ if (empty($comp)) $comp = $cont;
+ if (empty($ulen)) $ulen = strlen($cont);
+ if (empty($clen)) $clen = strlen($comp);
+ if (empty($crc32))$crc32= crc32($cont);
+ if (isset($meta)) $meta = serialize($meta);
+
+ // write manifest entry
+ $manifest .= pack('V', strlen($name)) . $name;
+ $manifest .= pack('VVVVVV', $ulen, $time, $clen, $crc32, $flags|$perm, strlen($meta)) . $meta;
+
+ // globals
+ $gflags |= $flags;
+ $files[$name] = $comp;
+}
+
+if (!isset($alias)) $alias = 'hio';
+
+if (isset($pmeta)) $pmeta = serialize($pmeta); else $pmeta = '';
+$manifest = pack('VnVV', count($files), isset($hasdir) ? 0x1110 : 0x1000, $gflags, strlen($alias)) . $alias . pack('V', strlen($pmeta)) . $pmeta . $manifest;
+$file .= pack('V', strlen($manifest)) . $manifest;
+
+foreach($files as $cont)
+{
+ $file .= $cont;
+}
+
+file_put_contents($fname, $file);
+
+if (@$gzip) {
+ $fp = gzopen($fname, 'w');
+ fwrite($fp, $file);
+ fclose($fp);
+}
+
+if (@$bz2) {
+ $fp = bzopen($fname, 'w');
+ fwrite($fp, $file);
+ fclose($fp);
+}
+
+?> \ No newline at end of file
diff --git a/ext/phar/tests/files/sha1.phar b/ext/phar/tests/files/sha1.phar
new file mode 100644
index 0000000000..c7e9e7e6a2
--- /dev/null
+++ b/ext/phar/tests/files/sha1.phar
Binary files differ
diff --git a/ext/phar/tests/files/sha256.phar b/ext/phar/tests/files/sha256.phar
new file mode 100644
index 0000000000..81459eef0f
--- /dev/null
+++ b/ext/phar/tests/files/sha256.phar
Binary files differ
diff --git a/ext/phar/tests/files/sha512.phar b/ext/phar/tests/files/sha512.phar
new file mode 100644
index 0000000000..a7473819aa
--- /dev/null
+++ b/ext/phar/tests/files/sha512.phar
Binary files differ
diff --git a/ext/phar/tests/files/zfapp.tgz b/ext/phar/tests/files/zfapp.tgz
new file mode 100644
index 0000000000..fcaec86d65
--- /dev/null
+++ b/ext/phar/tests/files/zfapp.tgz
Binary files differ
diff --git a/ext/phar/tests/fopen.phpt b/ext/phar/tests/fopen.phpt
new file mode 100644
index 0000000000..5b694d6e2d
--- /dev/null
+++ b/ext/phar/tests/fopen.phpt
@@ -0,0 +1,43 @@
+--TEST--
+Phar: test fopen() interception
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip");?>
+<?php if (substr(phpversion(), 0, 3) == '5.2') die("skip PHP >= 5.3 required for this test");?>
+--INI--
+phar.require_hash=1
+phar.readonly=0
+--FILE--
+<?php
+Phar::interceptFileFuncs();
+$a = fopen(__FILE__, 'rb'); // this satisfies 1 line of code coverage
+fclose($a);
+$a = fopen(); // this satisfies another line of code coverage
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$a = new Phar($fname);
+$a['index.php'] = '<?php
+$a = fopen("dir/file1.txt", "r");
+echo fread($a, 2);
+fclose($a);
+$a = fopen("file1.txt", "r", true);
+echo fread($a, 2);
+fclose($a);
+$a = fopen("notfound.txt", "r", true);
+?>';
+$a['dir/file1.txt'] = 'hi';
+$a['dir/file2.txt'] = 'hi2';
+$a['dir/file3.txt'] = 'hi3';
+$a->setStub('<?php
+set_include_path("phar://" . __FILE__ . "/dir" . PATH_SEPARATOR . "phar://" . __FILE__);
+include "index.php";
+__HALT_COMPILER();');
+include $fname;
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECTF--
+Warning: fopen() expects at least 2 parameters, 0 given in %sfopen.php on line %d
+hihi
+Warning: fopen(notfound.txt): failed to open stream: No such file or directory in phar://%sfopen.phar.php/index.php on line %d
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/fopen5.2.phpt b/ext/phar/tests/fopen5.2.phpt
new file mode 100644
index 0000000000..aa064f1662
--- /dev/null
+++ b/ext/phar/tests/fopen5.2.phpt
@@ -0,0 +1,43 @@
+--TEST--
+Phar: test fopen() interception
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip");?>
+<?php if (substr(phpversion(), 0, 3) != '5.2') die("skip PHP 5.2 required for this test");?>
+--INI--
+phar.require_hash=1
+phar.readonly=0
+--FILE--
+<?php
+Phar::interceptFileFuncs();
+$a = fopen(__FILE__, 'rb'); // this satisfies 1 line of code coverage
+fclose($a);
+$a = fopen(); // this satisfies another line of code coverage
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$a = new Phar($fname);
+$a['index.php'] = '<?php
+$a = fopen("dir/file1.txt", "r");
+echo fread($a, 2);
+fclose($a);
+$a = fopen("file1.txt", "r", true);
+echo fread($a, 2);
+fclose($a);
+$a = fopen("notfound.txt", "r", true);
+?>';
+$a['dir/file1.txt'] = 'hi';
+$a['dir/file2.txt'] = 'hi2';
+$a['dir/file3.txt'] = 'hi3';
+$a->setStub('<?php
+set_include_path("phar://" . __FILE__ . "/dir" . PATH_SEPARATOR . "phar://" . __FILE__);
+include "index.php";
+__HALT_COMPILER();');
+include $fname;
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECTF--
+Warning: fopen() expects at least 2 parameters, 0 given in %sfopen5.2.php on line %d
+hihi
+Warning: fopen(phar://%sfopen5.2.phar.php/notfound.txt): failed to open stream: phar error: "notfound.txt" is not a file in phar "%sfopen5.2.phar.php" in phar://%sfopen5.2.phar.php/index.php on line %d
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/fopen_edgecases.phpt b/ext/phar/tests/fopen_edgecases.phpt
new file mode 100644
index 0000000000..4c28ff31a1
--- /dev/null
+++ b/ext/phar/tests/fopen_edgecases.phpt
@@ -0,0 +1,124 @@
+--TEST--
+Phar: fopen/stat/fseek/unlink/rename edge cases
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.2.phar.php';
+$fname3 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.3.phar.php';
+$pname = 'phar://' . $fname;
+$pname2 = 'phar://' . $fname2;
+$pname3 = 'phar://' . $fname3;
+
+// create in cwd
+chdir(dirname(__FILE__));
+file_put_contents('phar://fopen_edgetest.phar/hi', 'hi');
+// append
+$a = fopen($pname . '/b/c.php', 'a');
+// invalid pharname
+$a = fopen($pname . '.phar.gz', 'r');
+// test phar_open_url() with quiet stat for code coverage
+var_dump(file_exists($pname . '.phar.gz/hi'));
+// test open for write with new phar
+$a = fopen($pname . '/hi', 'w');
+fclose($a);
+// test open for write with corrupted phar
+file_put_contents($fname2, '<?php oh crap __HALT_COMPILER();');
+$a = fopen($pname2 . '/hi', 'w');
+$a = fopen('phar://', 'r');
+$a = fopen('phar://foo.phar', 'r');
+
+file_put_contents($pname . '/hi', 'hi');
+$a = fopen($pname . '/hi', 'r');
+var_dump(fseek($a, 1), ftell($a));
+var_dump(fseek($a, 1, SEEK_CUR), ftell($a));
+fclose($a);
+
+var_dump(stat('phar://'));
+var_dump(stat('phar://foo.phar'));
+var_dump(is_dir($pname));
+
+// this tests coverage of the case where the phar exists and has no files
+$phar = new Phar($fname3);
+var_dump(file_exists($pname3 . '/test'));
+
+unlink($pname2 . '/hi');
+unlink('phar://');
+unlink('phar://foo.phar');
+unlink($pname . '/oops');
+
+rename('phar://', 'phar://');
+rename($pname . '/hi', 'phar://');
+rename('phar://foo.phar/hi', 'phar://');
+rename($pname . '/hi', 'phar://foo.phar/hi');
+
+ini_set('phar.readonly', 1);
+rename($pname . '/hi', $pname . '/there');
+ini_set('phar.readonly', 0);
+Phar::unlinkArchive($fname);
+file_put_contents($pname . '/test.php', '<?php
+$a = fopen("./notfound.php", "r");
+?>');
+include $pname . '/test.php';
+?>
+
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.2.phar.php'); ?>
+<?php unlink(dirname(__FILE__) . '/fopen_edgetest.phar');
+--EXPECTF--
+Warning: fopen(phar://%sfopen_edgecases.phar.php/b/c.php): failed to open stream: phar error: open mode append not supported in %sfopen_edgecases.php on line %d
+
+Warning: fopen(phar://%sfopen_edgecases.phar.php.phar.gz): failed to open stream: phar error: invalid url or non-existent phar "phar://%sfopen_edgecases.phar.php.phar.gz" in %sfopen_edgecases.php on line %d
+bool(false)
+
+Warning: fopen(phar://%sfopen_edgecases.2.phar.php/hi): failed to open stream: internal corruption of phar "%sfopen_edgecases.2.phar.php" (truncated manifest at stub end) in %sfopen_edgecases.php on line %d
+
+Warning: fopen(phar://): failed to open stream: phar error: no directory in "phar://", must have at least phar:/// for root directory (always use full path to a new phar) in %sfopen_edgecases.php on line %d
+
+Warning: fopen(phar://foo.phar): failed to open stream: %s in %sfopen_edgecases.php on line %d
+int(0)
+int(1)
+int(0)
+int(2)
+
+Warning: stat(): stat failed for phar:// in %sfopen_edgecases.php on line %d
+bool(false)
+
+Warning: stat(): stat failed for phar://foo.phar in %sfopen_edgecases.php on line %d
+bool(false)
+bool(true)
+bool(false)
+
+Warning: unlink(): internal corruption of phar "%sfopen_edgecases.2.phar.php" (truncated manifest at stub end) in %sfopen_edgecases.php on line %d
+
+Warning: unlink(): phar error: unlink failed in %sfopen_edgecases.php on line %d
+
+Warning: unlink(): phar error: no directory in "phar://", must have at least phar:/// for root directory (always use full path to a new phar) in %sfopen_edgecases.php on line %d
+
+Warning: unlink(): phar error: unlink failed in %sfopen_edgecases.php on line %d
+
+Warning: unlink(): phar error: invalid url or non-existent phar "phar://foo.phar" in %sfopen_edgecases.php on line %d
+
+Warning: unlink(): phar error: unlink failed in %sfopen_edgecases.php on line %d
+
+Warning: unlink(): unlink of "phar://%sfopen_edgecases.phar.php/oops" failed, file does not exist in %sfopen_edgecases.php on line %d
+
+Warning: rename(): phar error: cannot rename "phar://" to "phar://": invalid or non-writable url "phar://" in %sfopen_edgecases.php on line %d
+
+Warning: rename(): phar error: cannot rename "phar://%sfopen_edgecases.phar.php/hi" to "phar://": invalid or non-writable url "phar://" in %sfopen_edgecases.php on line %d
+
+Warning: rename(): phar error: cannot rename "phar://foo.phar/hi" to "phar://": invalid or non-writable url "phar://" in %sfopen_edgecases.php on line %d
+
+Warning: rename(): phar error: cannot rename "phar://%sfopen_edgecases.phar.php/hi" to "phar://foo.phar/hi", not within the same phar archive in %sfopen_edgecases.php on line %d
+
+Warning: rename(): phar error: cannot rename "phar://%sfopen_edgecases.phar.php/hi" to "phar://%sfopen_edgecases.phar.php/there": invalid or non-writable url "phar://%sfopen_edgecases.phar.php/hi" in %sfopen_edgecases.php on line %d
+
+Warning: fopen(./notfound.php): failed to open stream: No such file or directory in phar://%sfopen_edgecases.phar.php/test.php on line %d
+
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/fopen_edgecases2.phpt b/ext/phar/tests/fopen_edgecases2.phpt
new file mode 100644
index 0000000000..3579a2c221
--- /dev/null
+++ b/ext/phar/tests/fopen_edgecases2.phpt
@@ -0,0 +1,43 @@
+--TEST--
+Phar: test edge cases of fopen() function interception #2
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip");?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+Phar::interceptFileFuncs();
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+
+fopen(array(), 'r');
+chdir(dirname(__FILE__));
+file_put_contents($fname, "blah\n");
+file_put_contents("foob", "test\n");
+$a = fopen($fname, 'rb');
+echo fread($a, 1000);
+fclose($a);
+unlink($fname);
+mkdir($pname . '/oops');
+file_put_contents($pname . '/foo/hi', '<?php
+$context = stream_context_create();
+$a = fopen("foob", "rb", false, $context);
+echo fread($a, 1000);
+fclose($a);
+fopen("../oops", "r");
+?>
+');
+include $pname . '/foo/hi';
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+<?php rmdir(dirname(__FILE__) . '/poo'); ?>
+<?php unlink(dirname(__FILE__) . '/foob'); ?>
+--EXPECTF--
+Warning: fopen() expects parameter 1 to be string, array given in %sfopen_edgecases2.php on line %d
+blah
+test
+
+Warning: fopen(phar://%sfopen_edgecases2.phar.php/oops): failed to open stream: phar error: path "oops" is a directory in phar://%sfopen_edgecases2.phar.php/foo/hi on line %d
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/frontcontroller1.phpt b/ext/phar/tests/frontcontroller1.phpt
new file mode 100644
index 0000000000..7093323617
--- /dev/null
+++ b/ext/phar/tests/frontcontroller1.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Phar front controller other
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller1.php
+REQUEST_URI=/frontcontroller1.php/a.jpg
+PATH_INFO=/a.jpg
+--FILE_EXTERNAL--
+files/frontcontroller.phar
+--EXPECTHEADERS--
+Content-type: image/jpeg
+Content-length: 3
+--EXPECT--
+hio
diff --git a/ext/phar/tests/frontcontroller10.phpt b/ext/phar/tests/frontcontroller10.phpt
new file mode 100644
index 0000000000..2dbf1cbed8
--- /dev/null
+++ b/ext/phar/tests/frontcontroller10.phpt
@@ -0,0 +1,22 @@
+--TEST--
+Phar front controller rewrite access denied
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller10.php
+REQUEST_URI=/frontcontroller10.php/hi
+PATH_INFO=/hi
+--FILE_EXTERNAL--
+files/frontcontroller4.phar
+--EXPECTHEADERS--
+Content-type: text/html
+Status: 403 Access Denied
+--EXPECT--
+<html>
+ <head>
+ <title>Access Denied</title>
+ </head>
+ <body>
+ <h1>403 - File /hi Access Denied</h1>
+ </body>
+</html>
diff --git a/ext/phar/tests/frontcontroller11.phpt b/ext/phar/tests/frontcontroller11.phpt
new file mode 100644
index 0000000000..3823fec191
--- /dev/null
+++ b/ext/phar/tests/frontcontroller11.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Phar front controller mime type extension is not a string
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller11.php
+REQUEST_URI=/frontcontroller11.php/a.php
+PATH_INFO=/a.php
+--FILE_EXTERNAL--
+files/frontcontroller5.phar
+--EXPECTHEADERS--
+Content-type: text/html
+--EXPECTF--
+Fatal error: Uncaught exception 'PharException' with message 'Key of MIME type overrides array must be a file extension, was "0"' in %sfrontcontroller11.php:2
+Stack trace:
+#0 %sfrontcontroller11.php(2): Phar::webPhar('whatever', 'index.php', '', Array)
+#1 {main}
+ thrown in %sfrontcontroller11.php on line 2 \ No newline at end of file
diff --git a/ext/phar/tests/frontcontroller12.phpt b/ext/phar/tests/frontcontroller12.phpt
new file mode 100644
index 0000000000..e07876a41b
--- /dev/null
+++ b/ext/phar/tests/frontcontroller12.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Phar front controller mime type unknown int
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller12.php
+REQUEST_URI=/frontcontroller12.php/a.php
+PATH_INFO=/a.php
+--FILE_EXTERNAL--
+files/frontcontroller6.phar
+--EXPECTHEADERS--
+Content-type: text/html
+--EXPECTF--
+Fatal error: Uncaught exception 'PharException' with message 'Unknown mime type specifier used, only Phar::PHP, Phar::PHPS and a mime type string are allowed' in %sfrontcontroller12.php:2
+Stack trace:
+#0 %sfrontcontroller12.php(2): Phar::webPhar('whatever', 'index.php', '', Array)
+#1 {main}
+ thrown in %sfrontcontroller12.php on line 2 \ No newline at end of file
diff --git a/ext/phar/tests/frontcontroller13.phpt b/ext/phar/tests/frontcontroller13.phpt
new file mode 100644
index 0000000000..74ed0e1b75
--- /dev/null
+++ b/ext/phar/tests/frontcontroller13.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Phar front controller mime type not string/int
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller13.php
+REQUEST_URI=/frontcontroller13.php/a.php
+PATH_INFO=/a.php
+--FILE_EXTERNAL--
+files/frontcontroller7.phar
+--EXPECTHEADERS--
+Content-type: text/html
+--EXPECTF--
+Fatal error: Uncaught exception 'PharException' with message 'Unknown mime type specifier used (not a string or int), only Phar::PHP, Phar::PHPS and a mime type string are allowed' in %sfrontcontroller13.php:2
+Stack trace:
+#0 %sfrontcontroller13.php(2): Phar::webPhar('whatever', 'index.php', '', Array)
+#1 {main}
+ thrown in %sfrontcontroller13.php on line 2 \ No newline at end of file
diff --git a/ext/phar/tests/frontcontroller14.phpt b/ext/phar/tests/frontcontroller14.phpt
new file mode 100644
index 0000000000..2bdb145c6e
--- /dev/null
+++ b/ext/phar/tests/frontcontroller14.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Phar front controller mime type override, other
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller14.php
+REQUEST_URI=/frontcontroller14.php/a.jpg
+PATH_INFO=/a.jpg
+--FILE_EXTERNAL--
+files/frontcontroller8.phar
+--EXPECTHEADERS--
+Content-type: foo/bar
+Content-length: 4
+--EXPECT--
+hio2
diff --git a/ext/phar/tests/frontcontroller15.phpt b/ext/phar/tests/frontcontroller15.phpt
new file mode 100644
index 0000000000..eb69ede8f5
--- /dev/null
+++ b/ext/phar/tests/frontcontroller15.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Phar front controller mime type override, Phar::PHPS
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller15.php
+REQUEST_URI=/frontcontroller15.php/a.php
+PATH_INFO=/a.php
+--FILE_EXTERNAL--
+files/frontcontroller8.phar
+--EXPECTHEADERS--
+Content-type: text/html
+--EXPECT--
+<code><span style="color: #000000">
+<span style="color: #0000BB">&lt;?php&nbsp;</span><span style="color: #007700">function&nbsp;</span><span style="color: #0000BB">hio</span><span style="color: #007700">(){}</span>
+</span>
+</code>
+
diff --git a/ext/phar/tests/frontcontroller16.phpt b/ext/phar/tests/frontcontroller16.phpt
new file mode 100644
index 0000000000..5c6a03e16a
--- /dev/null
+++ b/ext/phar/tests/frontcontroller16.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Phar front controller mime type override, Phar::PHP
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller16.php
+REQUEST_URI=/frontcontroller16.php/a.phps
+PATH_INFO=/a.phps
+--FILE_EXTERNAL--
+files/frontcontroller8.phar
+--EXPECTHEADERS--
+Content-type: text/html
+--EXPECT--
+hio1
+
diff --git a/ext/phar/tests/frontcontroller17.phpt b/ext/phar/tests/frontcontroller17.phpt
new file mode 100644
index 0000000000..233e2e2a49
--- /dev/null
+++ b/ext/phar/tests/frontcontroller17.phpt
@@ -0,0 +1,16 @@
+--TEST--
+Phar front controller mime type unknown
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller17.php
+REQUEST_URI=/frontcontroller17.php/fronk.gronk
+PATH_INFO=/fronk.gronk
+--FILE_EXTERNAL--
+files/frontcontroller8.phar
+--EXPECTHEADERS--
+Content-type: application/octet-stream
+Content-length: 4
+--EXPECT--
+hio3
+
diff --git a/ext/phar/tests/frontcontroller18.phpt b/ext/phar/tests/frontcontroller18.phpt
new file mode 100644
index 0000000000..19aea45563
--- /dev/null
+++ b/ext/phar/tests/frontcontroller18.phpt
@@ -0,0 +1,16 @@
+--TEST--
+Phar front controller $_SERVER munging failure
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller18.php
+REQUEST_URI=/frontcontroller18.php/fronk.gronk
+PATH_INFO=/fronk.gronk
+--FILE_EXTERNAL--
+files/frontcontroller9.phar
+--EXPECTF--
+Fatal error: Uncaught exception 'PharException' with message 'No values passed to Phar::mungServer(), expecting an array of any of these strings: PHP_SELF, REQUEST_URI, SCRIPT_FILENAME, SCRIPT_NAME' in %sfrontcontroller18.php:2
+Stack trace:
+#0 %sfrontcontroller18.php(2): Phar::mungServer(Array)
+#1 {main}
+ thrown in %sfrontcontroller18.php on line 2
diff --git a/ext/phar/tests/frontcontroller19.phpt b/ext/phar/tests/frontcontroller19.phpt
new file mode 100644
index 0000000000..9adafa2b30
--- /dev/null
+++ b/ext/phar/tests/frontcontroller19.phpt
@@ -0,0 +1,16 @@
+--TEST--
+Phar front controller $_SERVER munging failure 2
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller19.php
+REQUEST_URI=/frontcontroller19.php/
+PATH_INFO=/
+--FILE_EXTERNAL--
+files/frontcontroller10.phar
+--EXPECTF--
+Fatal error: Uncaught exception 'PharException' with message 'Too many values passed to Phar::mungServer(), expecting an array of any of these strings: PHP_SELF, REQUEST_URI, SCRIPT_FILENAME, SCRIPT_NAME' in %sfrontcontroller19.php:2
+Stack trace:
+#0 %sfrontcontroller19.php(2): Phar::mungServer(Array)
+#1 {main}
+ thrown in %sfrontcontroller19.php on line 2
diff --git a/ext/phar/tests/frontcontroller2.phpt b/ext/phar/tests/frontcontroller2.phpt
new file mode 100644
index 0000000000..4b1652c461
--- /dev/null
+++ b/ext/phar/tests/frontcontroller2.phpt
@@ -0,0 +1,14 @@
+--TEST--
+Phar front controller PHP test
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller2.php
+REQUEST_URI=/frontcontroller2.php/a.php
+PATH_INFO=/a.php
+--FILE_EXTERNAL--
+files/frontcontroller.phar
+--EXPECTHEADERS--
+Content-type: text/html
+--EXPECT--
+hio
diff --git a/ext/phar/tests/frontcontroller20.phpt b/ext/phar/tests/frontcontroller20.phpt
new file mode 100644
index 0000000000..45e2bfc25e
--- /dev/null
+++ b/ext/phar/tests/frontcontroller20.phpt
@@ -0,0 +1,16 @@
+--TEST--
+Phar front controller $_SERVER munging failure 3
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller20.php
+REQUEST_URI=/frontcontroller20.php/
+PATH_INFO=/
+--FILE_EXTERNAL--
+files/frontcontroller11.phar
+--EXPECTF--
+Fatal error: Uncaught exception 'PharException' with message 'Non-string value passed to Phar::mungServer(), expecting an array of any of these strings: PHP_SELF, REQUEST_URI, SCRIPT_FILENAME, SCRIPT_NAME' in %sfrontcontroller20.php:2
+Stack trace:
+#0 %sfrontcontroller20.php(2): Phar::mungServer(Array)
+#1 {main}
+ thrown in %sfrontcontroller20.php on line 2
diff --git a/ext/phar/tests/frontcontroller21.phpt b/ext/phar/tests/frontcontroller21.phpt
new file mode 100644
index 0000000000..70d3508496
--- /dev/null
+++ b/ext/phar/tests/frontcontroller21.phpt
@@ -0,0 +1,22 @@
+--TEST--
+Phar front controller $_SERVER munging success
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller21.php
+REQUEST_URI=/frontcontroller21.php/index.php?test=hi
+PATH_INFO=/index.php
+QUERY_STRING=test=hi
+--FILE_EXTERNAL--
+files/frontcontroller12.phar
+--EXPECTHEADERS--
+Content-type: text/html
+--EXPECTF--
+string(10) "/index.php"
+string(10) "/index.php"
+string(%d) "phar://%sfrontcontroller21.php/index.php"
+string(18) "/index.php?test=hi"
+string(32) "/frontcontroller21.php/index.php"
+string(22) "/frontcontroller21.php"
+string(%d) "%sfrontcontroller21.php"
+string(40) "/frontcontroller21.php/index.php?test=hi" \ No newline at end of file
diff --git a/ext/phar/tests/frontcontroller22.phpt b/ext/phar/tests/frontcontroller22.phpt
new file mode 100644
index 0000000000..9925ba16d3
--- /dev/null
+++ b/ext/phar/tests/frontcontroller22.phpt
@@ -0,0 +1,19 @@
+--TEST--
+Phar front controller include from cwd test 1
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller22.php
+REQUEST_URI=/frontcontroller22.php/index.php
+PATH_INFO=/index.php
+--FILE_EXTERNAL--
+files/frontcontroller13.phar
+--EXPECTHEADERS--
+Content-type: text/html
+--EXPECTF--
+string(4) "test"
+string(12) "oof/test.php"
+
+Warning: include(./hi.php): failed to open stream: No such file or directory in phar://%s/oof/test.php on line %d
+
+Warning: include(): Failed opening './hi.php' for inclusion (include_path='%s') in phar://%soof/test.php on line %d \ No newline at end of file
diff --git a/ext/phar/tests/frontcontroller23.phpt b/ext/phar/tests/frontcontroller23.phpt
new file mode 100644
index 0000000000..14f32dd6db
--- /dev/null
+++ b/ext/phar/tests/frontcontroller23.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Phar front controller with generic action router test
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller23.php
+REQUEST_URI=/frontcontroller23.php/hi/there
+PATH_INFO=/hi/there
+--FILE_EXTERNAL--
+files/frontcontroller14.phar
+--EXPECTHEADERS--
+Content-type: text/html
+--EXPECTF--
+string(9) "/hi/there"
+string(%d) "phar://%sfrontcontroller23.php/html/index.php" \ No newline at end of file
diff --git a/ext/phar/tests/frontcontroller24.phpt b/ext/phar/tests/frontcontroller24.phpt
new file mode 100644
index 0000000000..dca5a693cd
--- /dev/null
+++ b/ext/phar/tests/frontcontroller24.phpt
@@ -0,0 +1,14 @@
+--TEST--
+Phar front controller with custom 404 php script
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller24.php
+REQUEST_URI=/frontcontroller24.php/unknown/file
+PATH_INFO=/unknown/file
+--FILE_EXTERNAL--
+files/frontcontroller8.phar
+--EXPECTHEADERS--
+Content-type: text/html
+--EXPECTF--
+My 404 is rawesome \ No newline at end of file
diff --git a/ext/phar/tests/frontcontroller25.phpt b/ext/phar/tests/frontcontroller25.phpt
new file mode 100644
index 0000000000..4d0475b078
--- /dev/null
+++ b/ext/phar/tests/frontcontroller25.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Phar front controller with extra path_info
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller25.php
+REQUEST_URI=/frontcontroller25.php/a1.phps/extra/stuff
+PATH_INFO=/a1.phps/extra/stuff
+--FILE_EXTERNAL--
+files/frontcontroller8.phar
+--EXPECTHEADERS--
+Content-type: text/html
+--EXPECTF--
+string(42) "/frontcontroller25.php/a1.phps/extra/stuff"
+string(12) "/extra/stuff" \ No newline at end of file
diff --git a/ext/phar/tests/frontcontroller26.phpt b/ext/phar/tests/frontcontroller26.phpt
new file mode 100644
index 0000000000..a8097b0886
--- /dev/null
+++ b/ext/phar/tests/frontcontroller26.phpt
@@ -0,0 +1,14 @@
+--TEST--
+Phar front controller with unknown extension mime type
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller26.php
+REQUEST_URI=/frontcontroller26.php/unknown.ext
+PATH_INFO=/unknown.ext
+--FILE_EXTERNAL--
+files/frontcontroller8.phar
+--EXPECTHEADERS--
+Content-type: application/octet-stream
+--EXPECTF--
+<?php var_dump("hi"); \ No newline at end of file
diff --git a/ext/phar/tests/frontcontroller27.phpt b/ext/phar/tests/frontcontroller27.phpt
new file mode 100644
index 0000000000..78c9536410
--- /dev/null
+++ b/ext/phar/tests/frontcontroller27.phpt
@@ -0,0 +1,14 @@
+--TEST--
+Phar front controller with no extension
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller27.php
+REQUEST_URI=/frontcontroller27.php/noext
+PATH_INFO=/noext
+--FILE_EXTERNAL--
+files/frontcontroller8.phar
+--EXPECTHEADERS--
+Content-type: text/plain
+--EXPECTF--
+hi \ No newline at end of file
diff --git a/ext/phar/tests/frontcontroller28.phpt b/ext/phar/tests/frontcontroller28.phpt
new file mode 100644
index 0000000000..59311120b4
--- /dev/null
+++ b/ext/phar/tests/frontcontroller28.phpt
@@ -0,0 +1,14 @@
+--TEST--
+Phar front controller with huge file
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller28.php
+REQUEST_URI=/frontcontroller28.php/bigfile.txt
+PATH_INFO=/bigfile.txt
+--FILE_EXTERNAL--
+files/frontcontroller8.phar
+--EXPECTHEADERS--
+Content-type: text/plain
+--EXPECT--
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
diff --git a/ext/phar/tests/frontcontroller29.phpt b/ext/phar/tests/frontcontroller29.phpt
new file mode 100644
index 0000000000..64674b5a28
--- /dev/null
+++ b/ext/phar/tests/frontcontroller29.phpt
@@ -0,0 +1,14 @@
+--TEST--
+Phar front controller with fatal error in php file
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller29.php
+REQUEST_URI=/frontcontroller29.php/fatalerror.phps
+PATH_INFO=/fatalerror.phps
+--FILE_EXTERNAL--
+files/frontcontroller8.phar
+--EXPECTHEADERS--
+Content-type: text/html
+--EXPECTF--
+Fatal error: Call to undefined function oopsie_daisy() in phar://%sfatalerror.phps on line 1 \ No newline at end of file
diff --git a/ext/phar/tests/frontcontroller3.phpt b/ext/phar/tests/frontcontroller3.phpt
new file mode 100644
index 0000000000..1b8093542f
--- /dev/null
+++ b/ext/phar/tests/frontcontroller3.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Phar front controller phps
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller3.php
+REQUEST_URI=/frontcontroller3.php/a.phps
+PATH_INFO=/a.phps
+--FILE_EXTERNAL--
+files/frontcontroller.phar
+--EXPECTHEADERS--
+Content-type: text/html
+--EXPECT--
+<code><span style="color: #000000">
+<span style="color: #0000BB">&lt;?php&nbsp;</span><span style="color: #007700">function&nbsp;</span><span style="color: #0000BB">hio</span><span style="color: #007700">(){}</span>
+</span>
+</code>
diff --git a/ext/phar/tests/frontcontroller30.phpt b/ext/phar/tests/frontcontroller30.phpt
new file mode 100644
index 0000000000..de6960c244
--- /dev/null
+++ b/ext/phar/tests/frontcontroller30.phpt
@@ -0,0 +1,12 @@
+--TEST--
+Phar front controller with weird SCRIPT_NAME
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/huh?
+REQUEST_URI=/huh?
+--FILE_EXTERNAL--
+files/frontcontroller8.phar
+--EXPECTF--
+oops did not run
+%a \ No newline at end of file
diff --git a/ext/phar/tests/frontcontroller31.phpt b/ext/phar/tests/frontcontroller31.phpt
new file mode 100644
index 0000000000..6ec7ca1b6f
--- /dev/null
+++ b/ext/phar/tests/frontcontroller31.phpt
@@ -0,0 +1,13 @@
+--TEST--
+Phar front controller with invalid callback for rewrites
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller31.php
+REQUEST_URI=/frontcontroller31.php
+--EXPECTHEADERS--
+Content-type: text/html
+--FILE_EXTERNAL--
+files/frontcontroller16.phar
+--EXPECT--
+phar error: invalid rewrite callback \ No newline at end of file
diff --git a/ext/phar/tests/frontcontroller32.phpt b/ext/phar/tests/frontcontroller32.phpt
new file mode 100644
index 0000000000..da9a4ef256
--- /dev/null
+++ b/ext/phar/tests/frontcontroller32.phpt
@@ -0,0 +1,13 @@
+--TEST--
+Phar front controller with valid callback that is not good
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller32.php
+REQUEST_URI=/frontcontroller32.php
+--EXPECTHEADERS--
+Content-type: text/html
+--FILE_EXTERNAL--
+files/frontcontroller17.phar
+--EXPECTF--
+%ahar error: failed to call rewrite callback \ No newline at end of file
diff --git a/ext/phar/tests/frontcontroller33.phpt b/ext/phar/tests/frontcontroller33.phpt
new file mode 100644
index 0000000000..e1bc2a79fb
--- /dev/null
+++ b/ext/phar/tests/frontcontroller33.phpt
@@ -0,0 +1,13 @@
+--TEST--
+Phar front controller with valid callback that does not return any value
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller33.php
+REQUEST_URI=/frontcontroller33.php
+--EXPECTHEADERS--
+Content-type: text/html
+--FILE_EXTERNAL--
+files/frontcontroller18.phar
+--EXPECTF--
+phar error: rewrite callback must return a string or false \ No newline at end of file
diff --git a/ext/phar/tests/frontcontroller34.phpt b/ext/phar/tests/frontcontroller34.phpt
new file mode 100644
index 0000000000..636667032a
--- /dev/null
+++ b/ext/phar/tests/frontcontroller34.phpt
@@ -0,0 +1,16 @@
+--TEST--
+Phar front controller with cwd
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller34.php
+REQUEST_URI=/frontcontroller34.php/start/index.php
+PATH_INFO=/start/index.php
+--EXPECTHEADERS--
+Content-type: text/html
+--FILE_EXTERNAL--
+files/frontcontroller19.phar
+--EXPECT--
+start/index.php
+start/another.php
+another.php
diff --git a/ext/phar/tests/frontcontroller4.phpt b/ext/phar/tests/frontcontroller4.phpt
new file mode 100644
index 0000000000..f2482b9219
--- /dev/null
+++ b/ext/phar/tests/frontcontroller4.phpt
@@ -0,0 +1,13 @@
+--TEST--
+Phar front controller index.php relocate (no /)
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller4.php
+REQUEST_URI=/frontcontroller4.php
+--FILE_EXTERNAL--
+files/frontcontroller.phar
+--EXPECTHEADERS--
+Status: 301 Moved Permanently
+Location: /frontcontroller4.php/index.php
+--EXPECT--
diff --git a/ext/phar/tests/frontcontroller5.phpt b/ext/phar/tests/frontcontroller5.phpt
new file mode 100644
index 0000000000..1990a2b008
--- /dev/null
+++ b/ext/phar/tests/frontcontroller5.phpt
@@ -0,0 +1,14 @@
+--TEST--
+Phar front controller index.php relocate
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller5.php
+REQUEST_URI=/frontcontroller5.php/
+PATH_INFO=/
+--FILE_EXTERNAL--
+files/frontcontroller.phar
+--EXPECTHEADERS--
+Status: 301 Moved Permanently
+Location: /frontcontroller5.php/index.php
+--EXPECT--
diff --git a/ext/phar/tests/frontcontroller6.phpt b/ext/phar/tests/frontcontroller6.phpt
new file mode 100644
index 0000000000..1a2cc2cd23
--- /dev/null
+++ b/ext/phar/tests/frontcontroller6.phpt
@@ -0,0 +1,21 @@
+--TEST--
+Phar front controller 404
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller6.php
+REQUEST_URI=/frontcontroller6.php/notfound.php
+PATH_INFO=/notfound.php
+--FILE_EXTERNAL--
+files/frontcontroller.phar
+--EXPECTHEADERS--
+Status: 404 Not Found
+--EXPECT--
+<html>
+ <head>
+ <title>File Not Found</title>
+ </head>
+ <body>
+ <h1>404 - File /notfound.php Not Found</h1>
+ </body>
+</html> \ No newline at end of file
diff --git a/ext/phar/tests/frontcontroller7.phpt b/ext/phar/tests/frontcontroller7.phpt
new file mode 100644
index 0000000000..aff2087522
--- /dev/null
+++ b/ext/phar/tests/frontcontroller7.phpt
@@ -0,0 +1,14 @@
+--TEST--
+Phar front controller alternate index file
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller7.php
+REQUEST_URI=/frontcontroller7.php/
+PATH_INFO=/
+--FILE_EXTERNAL--
+files/frontcontroller2.phar
+--EXPECTHEADERS--
+Status: 301 Moved Permanently
+Location: /frontcontroller7.php/a.php
+--EXPECT--
diff --git a/ext/phar/tests/frontcontroller8.phpt b/ext/phar/tests/frontcontroller8.phpt
new file mode 100644
index 0000000000..36e3206d66
--- /dev/null
+++ b/ext/phar/tests/frontcontroller8.phpt
@@ -0,0 +1,21 @@
+--TEST--
+Phar front controller no index file 404
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller8.php
+REQUEST_URI=/frontcontroller8.php/
+PATH_INFO=/
+--FILE_EXTERNAL--
+files/frontcontroller3.phar
+--EXPECTHEADERS--
+Status: 404 Not Found
+--EXPECT--
+<html>
+ <head>
+ <title>File Not Found</title>
+ </head>
+ <body>
+ <h1>404 - File /index.php Not Found</h1>
+ </body>
+</html> \ No newline at end of file
diff --git a/ext/phar/tests/frontcontroller9.phpt b/ext/phar/tests/frontcontroller9.phpt
new file mode 100644
index 0000000000..b7af364853
--- /dev/null
+++ b/ext/phar/tests/frontcontroller9.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Phar front controller rewrite array
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller9.php
+REQUEST_URI=/frontcontroller9.php/hi
+PATH_INFO=/hi
+--FILE_EXTERNAL--
+files/frontcontroller3.phar
+--EXPECTHEADERS--
+Content-type: text/html
+--EXPECT--
+<code><span style="color: #000000">
+<span style="color: #0000BB">&lt;?php&nbsp;</span><span style="color: #007700">function&nbsp;</span><span style="color: #0000BB">hio</span><span style="color: #007700">(){}</span>
+</span>
+</code> \ No newline at end of file
diff --git a/ext/phar/tests/include_path.phpt b/ext/phar/tests/include_path.phpt
new file mode 100644
index 0000000000..5f9462c260
--- /dev/null
+++ b/ext/phar/tests/include_path.phpt
@@ -0,0 +1,34 @@
+--TEST--
+Phar: include_path with phar:// wrapper
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/tempmanifest1.phar.php';
+$a = new Phar($fname);
+$a['file1.php'] = 'file1.php
+';
+$a['test/file1.php'] = 'test/file1.php
+';
+unset($a);
+set_include_path('.' . PATH_SEPARATOR . 'phar://' . $fname);
+include 'file1.php';
+set_include_path('.' . PATH_SEPARATOR . 'phar://' . $fname . '/test');
+include 'file1.php';
+include 'file2.php';
+?>
+===DONE===
+--CLEAN--
+<?php
+@unlink(dirname(__FILE__) . '/tempmanifest1.phar.php');
+?>
+--EXPECTF--
+file1.php
+test/file1.php
+
+Warning: include(file2.php): failed to open stream: No such file or directory in %sinclude_path.php on line %d
+
+Warning: include(): Failed opening 'file2.php' for inclusion (include_path='%sphar://%stempmanifest1.phar.php/test') in %sinclude_path.php on line %d
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/ini_set.phpt b/ext/phar/tests/ini_set.phpt
new file mode 100644
index 0000000000..588cd4a74b
--- /dev/null
+++ b/ext/phar/tests/ini_set.phpt
@@ -0,0 +1,28 @@
+--TEST--
+Phar: test ini_set with readonly and require_hash enabled
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip");?>
+--INI--
+phar.require_hash=1
+phar.readonly=1
+--FILE--
+<?php
+var_dump(ini_set('phar.require_hash', 1));
+var_dump(ini_set('phar.readonly', 1));
+var_dump(ini_get('phar.require_hash'));
+var_dump(ini_get('phar.readonly'));
+var_dump(ini_set('phar.require_hash', 0));
+var_dump(ini_set('phar.readonly', 0));
+var_dump(ini_get('phar.require_hash'));
+var_dump(ini_get('phar.readonly'));
+__HALT_COMPILER();
+?>
+--EXPECT--
+string(1) "1"
+string(1) "1"
+string(1) "1"
+string(1) "1"
+string(1) "1"
+string(1) "1"
+string(1) "1"
+string(1) "1"
diff --git a/ext/phar/tests/ini_set_off.phpt b/ext/phar/tests/ini_set_off.phpt
new file mode 100644
index 0000000000..7da07c5d8d
--- /dev/null
+++ b/ext/phar/tests/ini_set_off.phpt
@@ -0,0 +1,85 @@
+--TEST--
+Phar: test ini_set with readonly and require_hash disabled
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip");?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+var_dump(ini_set('phar.require_hash', 1));
+var_dump(ini_set('phar.readonly', 1));
+var_dump(ini_get('phar.require_hash'));
+var_dump(ini_get('phar.readonly'));
+ini_set('phar.require_hash', 0);
+ini_set('phar.readonly', 0);
+var_dump(Phar::canWrite());
+?>
+yes
+<?php
+var_dump(ini_set('phar.require_hash', 'yes'));
+var_dump(ini_set('phar.readonly', 'yes'));
+var_dump(ini_get('phar.require_hash'));
+var_dump(ini_get('phar.readonly'));
+var_dump(Phar::canWrite());
+ini_set('phar.require_hash', 0);
+ini_set('phar.readonly', 0);
+?>
+on
+<?php
+var_dump(ini_set('phar.require_hash', 'on'));
+var_dump(ini_set('phar.readonly', 'on'));
+var_dump(ini_get('phar.require_hash'));
+var_dump(ini_get('phar.readonly'));
+var_dump(Phar::canWrite());
+ini_set('phar.require_hash', 0);
+ini_set('phar.readonly', 0);
+?>
+true
+<?php
+var_dump(ini_set('phar.require_hash', 'true'));
+var_dump(ini_set('phar.readonly', 'true'));
+var_dump(Phar::canWrite());
+var_dump(ini_get('phar.require_hash'));
+var_dump(ini_get('phar.readonly'));
+?>
+0
+<?php
+var_dump(ini_set('phar.require_hash', 0));
+var_dump(ini_set('phar.readonly', 0));
+var_dump(Phar::canWrite());
+var_dump(ini_get('phar.require_hash'));
+var_dump(ini_get('phar.readonly'));
+?>
+===DONE===
+--EXPECT--
+string(1) "0"
+string(1) "0"
+string(1) "1"
+string(1) "1"
+bool(true)
+yes
+string(1) "0"
+string(1) "0"
+string(3) "yes"
+string(3) "yes"
+bool(false)
+on
+string(1) "0"
+string(1) "0"
+string(2) "on"
+string(2) "on"
+bool(false)
+true
+string(1) "0"
+string(1) "0"
+bool(false)
+string(4) "true"
+string(4) "true"
+0
+string(4) "true"
+string(4) "true"
+bool(true)
+string(1) "0"
+string(1) "0"
+===DONE===
diff --git a/ext/phar/tests/invalid_alias.phpt b/ext/phar/tests/invalid_alias.phpt
new file mode 100644
index 0000000000..dc0c71ed11
--- /dev/null
+++ b/ext/phar/tests/invalid_alias.phpt
@@ -0,0 +1,45 @@
+--TEST--
+Phar: set alias with invalid alias containing / \ : or ;
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar';
+
+$p = new Phar($fname);
+try {
+ $p->setAlias('hi/');
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+try {
+ $p->setAlias('hi\\l');
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+
+try {
+ $p->setAlias('hil;');
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+
+try {
+ $p->setAlias(':hil');
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar');
+?>
+--EXPECTF--
+Invalid alias "hi/" specified for phar "%sinvalid_alias.phar"
+Invalid alias "hi\l" specified for phar "%sinvalid_alias.phar"
+Invalid alias "hil;" specified for phar "%sinvalid_alias.phar"
+Invalid alias ":hil" specified for phar "%sinvalid_alias.phar"
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/invalid_setstubalias.phpt b/ext/phar/tests/invalid_setstubalias.phpt
new file mode 100644
index 0000000000..04cb779ddb
--- /dev/null
+++ b/ext/phar/tests/invalid_setstubalias.phpt
@@ -0,0 +1,47 @@
+--TEST--
+Phar: invalid set alias or stub via array access
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar';
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.zip';
+
+$p = new Phar($fname);
+try {
+ $p['.phar/stub.php'] = 'hi';
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+try {
+ $p['.phar/alias.txt'] = 'hi';
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+$p = new Phar($fname2);
+try {
+ $p['.phar/stub.php'] = 'hi';
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+try {
+ $p['.phar/alias.txt'] = 'hi';
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.zip');
+?>
+--EXPECTF--
+Cannot set stub ".phar/stub.php" directly in phar "%sinvalid_setstubalias.phar.tar", use setStub
+Cannot set alias ".phar/alias.txt" directly in phar "%sinvalid_setstubalias.phar.tar", use setAlias
+Cannot set stub ".phar/stub.php" directly in phar "%sinvalid_setstubalias.phar.zip", use setStub
+Cannot set alias ".phar/alias.txt" directly in phar "%sinvalid_setstubalias.phar.zip", use setAlias
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/metadata_read.phpt b/ext/phar/tests/metadata_read.phpt
new file mode 100644
index 0000000000..c3d12d6fbd
--- /dev/null
+++ b/ext/phar/tests/metadata_read.phpt
@@ -0,0 +1,61 @@
+--TEST--
+Phar with meta-data (read)
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip");?>
+--INI--
+phar.require_hash=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = "<?php __HALT_COMPILER(); ?>";
+
+$files = array();
+$files['a'] = array('cont' => 'a');
+$files['b'] = array('cont' => 'b', 'meta' => 'hi there');
+$files['c'] = array('cont' => 'c', 'meta' => array('hi', 'there'));
+$files['d'] = array('cont' => 'd', 'meta' => array('hi'=>'there','foo'=>'bar'));
+include 'files/phar_test.inc';
+
+foreach($files as $name => $cont) {
+ var_dump(file_get_contents($pname.'/'.$name));
+}
+
+$phar = new Phar($fname);
+foreach($files as $name => $cont) {
+ var_dump($phar[$name]->getMetadata());
+}
+
+unset($phar);
+
+foreach($files as $name => $cont) {
+ var_dump(file_get_contents($pname.'/'.$name));
+}
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECT--
+string(1) "a"
+string(1) "b"
+string(1) "c"
+string(1) "d"
+NULL
+string(8) "hi there"
+array(2) {
+ [0]=>
+ string(2) "hi"
+ [1]=>
+ string(5) "there"
+}
+array(2) {
+ ["hi"]=>
+ string(5) "there"
+ ["foo"]=>
+ string(3) "bar"
+}
+string(1) "a"
+string(1) "b"
+string(1) "c"
+string(1) "d"
+===DONE===
diff --git a/ext/phar/tests/metadata_write.phpt b/ext/phar/tests/metadata_write.phpt
new file mode 100755
index 0000000000..4b9930b693
--- /dev/null
+++ b/ext/phar/tests/metadata_write.phpt
@@ -0,0 +1,62 @@
+--TEST--
+Phar with meta-data (write)
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip");?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = "<?php __HALT_COMPILER(); ?>";
+
+$files = array();
+$files['a'] = array('cont' => 'a');
+$files['b'] = array('cont' => 'b', 'meta' => 'hi there');
+$files['c'] = array('cont' => 'c', 'meta' => array('hi', 'there'));
+$files['d'] = array('cont' => 'd', 'meta' => array('hi'=>'there','foo'=>'bar'));
+include 'files/phar_test.inc';
+
+foreach($files as $name => $cont) {
+ var_dump(file_get_contents($pname.'/'.$name));
+}
+
+$phar = new Phar($fname);
+$phar['a']->setMetadata(42);
+$phar['b']->setMetadata(NULL);
+$phar['c']->setMetadata(array(25, 'foo'=>'bar'));
+$phar['d']->setMetadata(true);
+
+foreach($files as $name => $cont) {
+ var_dump($phar[$name]->getMetadata());
+}
+
+unset($phar);
+
+foreach($files as $name => $cont) {
+ var_dump(file_get_contents($pname.'/'.$name));
+}
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECT--
+string(1) "a"
+string(1) "b"
+string(1) "c"
+string(1) "d"
+int(42)
+NULL
+array(2) {
+ [0]=>
+ int(25)
+ ["foo"]=>
+ string(3) "bar"
+}
+bool(true)
+string(1) "a"
+string(1) "b"
+string(1) "c"
+string(1) "d"
+===DONE===
diff --git a/ext/phar/tests/metadata_write_commit.phpt b/ext/phar/tests/metadata_write_commit.phpt
new file mode 100755
index 0000000000..0d0a5e56ad
--- /dev/null
+++ b/ext/phar/tests/metadata_write_commit.phpt
@@ -0,0 +1,79 @@
+--TEST--
+Phar with meta-data (write)
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip");?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = "<?php __HALT_COMPILER(); ?>";
+
+$files = array();
+$files['a'] = array('cont' => 'a');
+$files['b'] = array('cont' => 'b', 'meta' => 'hi there');
+$files['c'] = array('cont' => 'c', 'meta' => array('hi', 'there'));
+$files['d'] = array('cont' => 'd', 'meta' => array('hi'=>'there','foo'=>'bar'));
+include 'files/phar_test.inc';
+
+foreach($files as $name => $cont) {
+ var_dump(file_get_contents($pname.'/'.$name));
+}
+
+$phar = new Phar($fname);
+$phar->startBuffering();
+$phar['a']->setMetadata(42);
+$phar['b']->setMetadata(NULL);
+$phar['c']->setMetadata(array(25, 'foo'=>'bar'));
+$phar['d']->setMetadata(true);
+
+foreach($files as $name => $cont) {
+ var_dump($phar[$name]->getMetadata());
+}
+$phar->stopBuffering();
+
+unset($phar);
+
+$phar = new Phar($fname);
+
+foreach($files as $name => $cont) {
+ var_dump(file_get_contents($pname.'/'.$name));
+}
+
+foreach($files as $name => $cont) {
+ var_dump($phar[$name]->getMetadata());
+}
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECT--
+string(1) "a"
+string(1) "b"
+string(1) "c"
+string(1) "d"
+int(42)
+NULL
+array(2) {
+ [0]=>
+ int(25)
+ ["foo"]=>
+ string(3) "bar"
+}
+bool(true)
+string(1) "a"
+string(1) "b"
+string(1) "c"
+string(1) "d"
+int(42)
+NULL
+array(2) {
+ [0]=>
+ int(25)
+ ["foo"]=>
+ string(3) "bar"
+}
+bool(true)
+===DONE===
diff --git a/ext/phar/tests/mkdir.phpt b/ext/phar/tests/mkdir.phpt
new file mode 100644
index 0000000000..af8bceb32c
--- /dev/null
+++ b/ext/phar/tests/mkdir.phpt
@@ -0,0 +1,41 @@
+--TEST--
+phar: mkdir/rmdir edge cases
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+Phar::interceptFileFuncs();
+mkdir('phar://');
+mkdir('phar://foo.phar');
+$a = new Phar($fname);
+$a['a'] = 'hi';
+mkdir($pname . '/a');
+rmdir('phar://');
+rmdir('phar://foo.phar');
+rmdir($pname . '/a');
+$a->addEmptyDir('bb');
+$a->addEmptyDir('bb');
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php');
+__HALT_COMPILER();
+?>
+--EXPECTF--
+Warning: mkdir(): phar error: cannot create directory "phar://", no phar archive specified in %smkdir.php on line %d
+
+Warning: mkdir(): phar error: cannot create directory "" in phar "foo.phar", phar error: invalid path "" must not be empty in %smkdir.php on line %d
+
+Warning: mkdir(): phar error: cannot create directory "a" in phar "%smkdir.phar.php", phar error: path "a" exists and is a not a directory in %smkdir.php on line %d
+
+Warning: rmdir(): phar error: cannot remove directory "phar://", no phar archive specified, or phar archive does not exist in %smkdir.php on line %d
+
+Warning: rmdir(): phar error: cannot remove directory "" in phar "foo.phar", directory does not exist in %smkdir.php on line %d
+
+Warning: rmdir(): phar error: cannot remove directory "a" in phar "%smkdir.phar.php", phar error: path "a" exists and is a not a directory in %smkdir.php on line %d
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/mounteddir.phpt b/ext/phar/tests/mounteddir.phpt
new file mode 100644
index 0000000000..c438eefb1d
--- /dev/null
+++ b/ext/phar/tests/mounteddir.phpt
@@ -0,0 +1,109 @@
+--TEST--
+Phar: mounted manifest directory test
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/tempmanifest1.phar.php';
+$pname = 'phar://' . $fname;
+
+$a = new Phar($fname);
+$a['index.php'] = '<?php
+Phar::mount("testit", dirname(Phar::running(0)) . "/testit");
+echo file_get_contents(Phar::running(1) . "/testit/extfile.php"), "\n";
+echo file_get_contents(Phar::running(1) . "/testit/directory"), "\n";
+echo file_get_contents(Phar::running(1) . "/testit/existing.txt"), "\n";
+include "testit/extfile.php";
+include "testit/extfile2.php";
+?>';
+$a['testit/existing.txt'] = 'oops';
+$a->setStub('<?php
+set_include_path("phar://" . __FILE__);
+include "index.php";
+__HALT_COMPILER();');
+unset($a);
+mkdir(dirname(__FILE__) . '/testit');
+mkdir(dirname(__FILE__) . '/testit/directory');
+file_put_contents(dirname(__FILE__) . '/testit/extfile.php', '<?php
+var_dump(__FILE__);
+?>');
+file_put_contents(dirname(__FILE__) . '/testit/extfile2.php', '<?php
+var_dump(__FILE__);
+?>');
+include dirname(__FILE__) . '/testit/extfile.php';
+include $fname;
+
+$a = opendir($pname . '/testit');
+$out = array();
+while (false !== ($b = readdir($a))) {
+ $out[] = $b;
+}
+sort($out);
+foreach ($out as $b) {
+ echo "$b\n";
+}
+$out = array();
+foreach (new Phar($pname . '/testit') as $b) {
+ $out[] = $b->getPathName();
+}
+sort($out);
+foreach ($out as $b) {
+ echo "$b\n";
+}
+try {
+Phar::mount($pname . '/testit', 'another\\..\\mistake');
+} catch (Exception $e) {
+echo $e->getMessage(), "\n";
+}
+try {
+Phar::mount($pname . '/notfound', dirname(__FILE__) . '/this/does/not/exist');
+} catch (Exception $e) {
+echo $e->getMessage(), "\n";
+}
+try {
+Phar::mount($pname . '/testit', dirname(__FILE__));
+} catch (Exception $e) {
+echo $e->getMessage(), "\n";
+}
+try {
+Phar::mount($pname . '/testit/extfile.php', dirname(__FILE__));
+} catch (Exception $e) {
+echo $e->getMessage(), "\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+@unlink(dirname(__FILE__) . '/tempmanifest1.phar.php');
+@unlink(dirname(__FILE__) . '/testit/extfile.php');
+@unlink(dirname(__FILE__) . '/testit/extfile2.php');
+@rmdir(dirname(__FILE__) . '/testit/directory');
+@rmdir(dirname(__FILE__) . '/testit');
+
+?>
+--EXPECTF--
+string(%d) "%sextfile.php"
+<?php
+var_dump(__FILE__);
+?>
+
+Warning: file_get_contents(phar://%stempmanifest1.phar.php/testit/directory): failed to open stream: phar error: path "testit/directory" is a directory in phar://%stempmanifest1.phar.php/index.php on line %d
+
+oops
+string(%d) "phar://%sextfile.php"
+string(%d) "phar://%sextfile2.php"
+.
+..
+directory
+extfile.php
+extfile2.php
+phar://%stempmanifest1.phar.php/testit%cdirectory
+phar://%stempmanifest1.phar.php/testit%cextfile.php
+phar://%stempmanifest1.phar.php/testit%cextfile2.php
+Mounting of /testit to another\..\mistake within phar %stempmanifest1.phar.php failed
+Mounting of /notfound to %stests/this/does/not/exist within phar %stempmanifest1.phar.php failed
+Mounting of /testit to %stests within phar %stests/tempmanifest1.phar.php failed
+Mounting of /testit/extfile.php to %stests within phar %stests/tempmanifest1.phar.php failed
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/nophar.phpt b/ext/phar/tests/nophar.phpt
new file mode 100644
index 0000000000..d97df8af2e
--- /dev/null
+++ b/ext/phar/tests/nophar.phpt
@@ -0,0 +1,14 @@
+--TEST--
+Phar: phar run without pecl/phar with default stub
+--SKIPIF--
+<?php if (extension_loaded("phar")) die("skip Phar extension must be disabled for this test"); ?>
+--FILE--
+<?php
+include dirname(__FILE__) . '/files/nophar.phar';
+?>
+===DONE===
+--EXPECT--
+in b
+<?php include "b/c.php";
+in d
+===DONE===
diff --git a/ext/phar/tests/nophar_web.phpt b/ext/phar/tests/nophar_web.phpt
new file mode 100644
index 0000000000..7ee67b4546
--- /dev/null
+++ b/ext/phar/tests/nophar_web.phpt
@@ -0,0 +1,11 @@
+--TEST--
+Phar: default web stub, no phar extension
+--SKIPIF--
+<?php if (extension_loaded("phar")) die("skip Phar extension must be disabled for this test"); ?>
+--ENV--
+SCRIPT_NAME=/nophar.phar
+REQUEST_URI=/nophar.phar
+--FILE_EXTERNAL--
+files/nophar.phar
+--EXPECT--
+web
diff --git a/ext/phar/tests/open_for_write_existing.phpt b/ext/phar/tests/open_for_write_existing.phpt
new file mode 100644
index 0000000000..2a3ec8b824
--- /dev/null
+++ b/ext/phar/tests/open_for_write_existing.phpt
@@ -0,0 +1,31 @@
+--TEST--
+Phar: fopen a .phar for writing (existing file)
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = "<?php __HALT_COMPILER(); ?>";
+
+$files = array();
+$files['a.php'] = '<?php echo "This is a\n"; ?>';
+$files['b.php'] = '<?php echo "This is b\n"; ?>';
+$files['b/c.php'] = '<?php echo "This is b/c\n"; ?>';
+include 'files/phar_test.inc';
+
+$fp = fopen($pname . '/b/c.php', 'wb');
+fwrite($fp, 'extra');
+fclose($fp);
+include $pname . '/b/c.php';
+?>
+
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECTF--
+extra
+===DONE===
diff --git a/ext/phar/tests/open_for_write_existing_b.phpt b/ext/phar/tests/open_for_write_existing_b.phpt
new file mode 100755
index 0000000000..6c3cd3e986
--- /dev/null
+++ b/ext/phar/tests/open_for_write_existing_b.phpt
@@ -0,0 +1,42 @@
+--TEST--
+Phar: fopen a .phar for writing (existing file)
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=1
+phar.require_hash=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = "<?php __HALT_COMPILER(); ?>";
+
+$files = array();
+$files['a.php'] = '<?php echo "This is a\n"; ?>';
+$files['b.php'] = '<?php echo "This is b\n"; ?>';
+$files['b/c.php'] = '<?php echo "This is b/c\n"; ?>';
+include 'files/phar_test.inc';
+
+function err_handler($errno, $errstr, $errfile, $errline) {
+ echo "Catchable fatal error: $errstr in $errfile on line $errline\n";
+}
+
+set_error_handler("err_handler", E_RECOVERABLE_ERROR);
+
+$fp = fopen($pname . '/b/c.php', 'wb');
+fwrite($fp, 'extra');
+fclose($fp);
+include $pname . '/b/c.php';
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECTF--
+
+Warning: fopen(phar://%sopen_for_write_existing_b.phar.php/b/c.php): failed to open stream: phar error: write operations disabled by INI setting in %sopen_for_write_existing_b.php on line %d
+
+Warning: fwrite(): supplied argument is not a valid stream resource in %spen_for_write_existing_b.php on line %d
+
+Warning: fclose(): supplied argument is not a valid stream resource in %spen_for_write_existing_b.php on line %d
+This is b/c
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/open_for_write_existing_c.phpt b/ext/phar/tests/open_for_write_existing_c.phpt
new file mode 100755
index 0000000000..9bbaaae92a
--- /dev/null
+++ b/ext/phar/tests/open_for_write_existing_c.phpt
@@ -0,0 +1,36 @@
+--TEST--
+Phar: fopen a .phar for writing (existing file)
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=1
+phar.require_hash=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = "<?php __HALT_COMPILER(); ?>";
+
+$files = array();
+$files['a.php'] = '<?php echo "This is a\n"; ?>';
+$files['b.php'] = '<?php echo "This is b\n"; ?>';
+$files['b/c.php'] = '<?php echo "This is b/c\n"; ?>';
+include 'files/phar_test.inc';
+
+$fp = fopen($pname . '/b/c.php', 'wb');
+fwrite($fp, 'extra');
+fclose($fp);
+include $pname . '/b/c.php';
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECTF--
+
+Warning: fopen(phar://%sopen_for_write_existing_c.phar.php/b/c.php): failed to open stream: phar error: write operations disabled by INI setting in %sopen_for_write_existing_c.php on line %d
+
+Warning: fwrite(): supplied argument is not a valid stream resource in %sopen_for_write_existing_c.php on line %d
+
+Warning: fclose(): supplied argument is not a valid stream resource in %sopen_for_write_existing_c.php on line %d
+This is b/c
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/open_for_write_newfile.phpt b/ext/phar/tests/open_for_write_newfile.phpt
new file mode 100644
index 0000000000..13114072da
--- /dev/null
+++ b/ext/phar/tests/open_for_write_newfile.phpt
@@ -0,0 +1,33 @@
+--TEST--
+Phar: fopen a .phar for writing (new file)
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = "<?php __HALT_COMPILER(); ?>";
+
+$files = array();
+$files['a.php'] = '<?php echo "This is a\n"; ?>';
+$files['b.php'] = '<?php echo "This is b\n"; ?>';
+$files['b/c.php'] = '<?php echo "This is b/c\n"; ?>';
+include 'files/phar_test.inc';
+
+$fp = fopen($pname . '/b/new.php', 'wb');
+fwrite($fp, 'extra');
+fclose($fp);
+include $pname . '/b/c.php';
+include $pname . '/b/new.php';
+?>
+
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECT--
+This is b/c
+extra
+===DONE===
diff --git a/ext/phar/tests/open_for_write_newfile_b.phpt b/ext/phar/tests/open_for_write_newfile_b.phpt
new file mode 100755
index 0000000000..1c136ff1d5
--- /dev/null
+++ b/ext/phar/tests/open_for_write_newfile_b.phpt
@@ -0,0 +1,49 @@
+--TEST--
+Phar: fopen a .phar for writing (new file)
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=1
+phar.require_hash=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = "<?php __HALT_COMPILER(); ?>";
+
+$files = array();
+$files['a.php'] = '<?php echo "This is a\n"; ?>';
+$files['b.php'] = '<?php echo "This is b\n"; ?>';
+$files['b/c.php'] = '<?php echo "This is b/c\n"; ?>';
+include 'files/phar_test.inc';
+
+function err_handler($errno, $errstr, $errfile, $errline) {
+ echo "Catchable fatal error: $errstr in $errfile on line $errline\n";
+}
+
+set_error_handler("err_handler", E_RECOVERABLE_ERROR);
+
+$fp = fopen($pname . '/b/new.php', 'wb');
+fwrite($fp, 'extra');
+fclose($fp);
+include $pname . '/b/c.php';
+include $pname . '/b/new.php';
+?>
+
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECTF--
+
+Warning: fopen(phar://%sopen_for_write_newfile_b.phar.php/b/new.php): failed to open stream: phar error: write operations disabled by INI setting in %sopen_for_write_newfile_b.php on line %d
+
+Warning: fwrite(): supplied argument is not a valid stream resource in %sopen_for_write_newfile_b.php on line %d
+
+Warning: fclose(): supplied argument is not a valid stream resource in %sopen_for_write_newfile_b.php on line 20
+This is b/c
+
+Warning: include(phar://%sopen_for_write_newfile_b.phar.php/b/new.php): failed to open stream: phar error: "b/new.php" is not a file in phar "%sopen_for_write_newfile_b.phar.php" in %sopen_for_write_newfile_b.php on line 22
+
+Warning: include(): Failed opening 'phar://%sopen_for_write_newfile_b.phar.php/b/new.php' for inclusion (include_path='%s') in %sopen_for_write_newfile_b.php on line %d
+
+===DONE===
diff --git a/ext/phar/tests/open_for_write_newfile_c.phpt b/ext/phar/tests/open_for_write_newfile_c.phpt
new file mode 100755
index 0000000000..59b4339eb9
--- /dev/null
+++ b/ext/phar/tests/open_for_write_newfile_c.phpt
@@ -0,0 +1,43 @@
+--TEST--
+Phar: fopen a .phar for writing (new file)
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=1
+phar.require_hash=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = "<?php __HALT_COMPILER(); ?>";
+
+$files = array();
+$files['a.php'] = '<?php echo "This is a\n"; ?>';
+$files['b.php'] = '<?php echo "This is b\n"; ?>';
+$files['b/c.php'] = '<?php echo "This is b/c\n"; ?>';
+include 'files/phar_test.inc';
+
+$fp = fopen($pname . '/b/new.php', 'wb');
+fwrite($fp, 'extra');
+fclose($fp);
+include $pname . '/b/c.php';
+include $pname . '/b/new.php';
+?>
+
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECTF--
+
+Warning: fopen(phar://%sopen_for_write_newfile_c.phar.php/b/new.php): failed to open stream: phar error: write operations disabled by INI setting in %sopen_for_write_newfile_c.php on line %d
+
+Warning: fwrite(): supplied argument is not a valid stream resource in %sopen_for_write_newfile_c.php on line %d
+
+Warning: fclose(): supplied argument is not a valid stream resource in %sopen_for_write_newfile_c.php on line %d
+This is b/c
+
+Warning: include(phar://%sopen_for_write_newfile_c.phar.php/b/new.php): failed to open stream: phar error: "b/new.php" is not a file in phar "%sopen_for_write_newfile_c.phar.php" in %sopen_for_write_newfile_c.php on line %d
+
+Warning: include(): Failed opening 'phar://%sopen_for_write_newfile_c.phar.php/b/new.php' for inclusion (include_path='%s') in %sopen_for_write_newfile_c.php on line %d
+
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/opendir.phpt b/ext/phar/tests/opendir.phpt
new file mode 100644
index 0000000000..46ab7c9682
--- /dev/null
+++ b/ext/phar/tests/opendir.phpt
@@ -0,0 +1,42 @@
+--TEST--
+Phar: test opendir() interception
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip");?>
+--INI--
+phar.require_hash=1
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$a = new Phar($fname);
+$a['index.php'] = '<?php
+$a = opendir("dir");
+while (false !== ($e = readdir($a))) {
+ echo $e;
+}
+?>';
+$a['dir/file1.txt'] = 'hi';
+$a['dir/file2.txt'] = 'hi2';
+$a['dir/file3.txt'] = 'hi3';
+$a->setStub('<?php
+Phar::interceptFileFuncs();
+set_include_path("phar://" . __FILE__);
+include "index.php";
+__HALT_COMPILER();');
+include $fname;
+echo "\n";
+opendir('phar://');
+opendir('phar://hi.phar');
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECTF--
+file1.txtfile2.txtfile3.txt
+
+Warning: opendir(phar://): failed to open dir: phar error: no directory in "phar://", must have at least phar:/// for root directory (always use full path to a new phar)
+phar url "phar://" is unknown in %sopendir.php on line %d
+
+Warning: opendir(phar://hi.phar): failed to open dir: phar error: invalid url or non-existent phar "phar://hi.phar"
+phar url "phar://hi.phar" is unknown in %sopendir.php on line %d
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/opendir_edgecases.phpt b/ext/phar/tests/opendir_edgecases.phpt
new file mode 100644
index 0000000000..d330d27ff3
--- /dev/null
+++ b/ext/phar/tests/opendir_edgecases.phpt
@@ -0,0 +1,46 @@
+--TEST--
+Phar: test edge cases of opendir() function interception
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip");?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+Phar::interceptFileFuncs();
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+opendir(array());
+mkdir(dirname(__FILE__) . '/poo');
+chdir(dirname(__FILE__));
+$a = opendir('poo');
+while (false !== ($b = readdir($a))) {
+echo "$b\n";
+}
+closedir($a);
+file_put_contents($pname . '/foo', '<?php
+$context = stream_context_create();
+$a = opendir(".", $context);
+$res = array();
+while (false !== ($b = readdir($a))) {
+$res[] = $b;
+}
+sort($res);
+foreach ($res as $b) {
+echo "$b\n";
+}
+opendir("oops");
+?>');
+include $pname . '/foo';
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+<?php rmdir(dirname(__FILE__) . '/poo');
+--EXPECTF--
+Warning: opendir() expects parameter 1 to be string, array given in %sopendir_edgecases.php on line %d
+.
+..
+foo
+
+Warning: opendir(phar://%sopendir_edgecases.phar.php/oops): failed to open dir: %s in phar://%sopendir_edgecases.phar.php/foo on line %d
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/phar_begin_setstub_commit.phpt b/ext/phar/tests/phar_begin_setstub_commit.phpt
new file mode 100755
index 0000000000..d36865ddc5
--- /dev/null
+++ b/ext/phar/tests/phar_begin_setstub_commit.phpt
@@ -0,0 +1,50 @@
+--TEST--
+Phar::startBuffering()/setStub()/stopBuffering()
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+$p = new Phar(dirname(__FILE__) . '/brandnewphar.phar', 0, 'brandnewphar.phar');
+//var_dump($p->getStub());
+var_dump($p->isBuffering());
+$p->startBuffering();
+var_dump($p->isBuffering());
+$p['a.php'] = '<?php var_dump("Hello");';
+$p->setStub('<?php var_dump("First"); Phar::mapPhar("brandnewphar.phar"); __HALT_COMPILER(); ?>');
+include 'phar://brandnewphar.phar/a.php';
+var_dump($p->getStub());
+$p['b.php'] = '<?php var_dump("World");';
+$p->setStub('<?php var_dump("Second"); Phar::mapPhar("brandnewphar.phar"); __HALT_COMPILER();');
+include 'phar://brandnewphar.phar/b.php';
+var_dump($p->getStub());
+$p->stopBuffering();
+echo "===COMMIT===\n";
+var_dump($p->isBuffering());
+include 'phar://brandnewphar.phar/a.php';
+include 'phar://brandnewphar.phar/b.php';
+var_dump($p->getStub());
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/brandnewphar.phar');
+?>
+--EXPECT--
+bool(true)
+bool(false)
+string(5) "Hello"
+string(84) "<?php var_dump("First"); Phar::mapPhar("brandnewphar.phar"); __HALT_COMPILER(); ?>
+"
+string(5) "World"
+string(85) "<?php var_dump("Second"); Phar::mapPhar("brandnewphar.phar"); __HALT_COMPILER(); ?>
+"
+===COMMIT===
+bool(true)
+string(5) "Hello"
+string(5) "World"
+string(85) "<?php var_dump("Second"); Phar::mapPhar("brandnewphar.phar"); __HALT_COMPILER(); ?>
+"
+===DONE===
diff --git a/ext/phar/tests/phar_buildfromdirectory1.phpt b/ext/phar/tests/phar_buildfromdirectory1.phpt
new file mode 100644
index 0000000000..505b15036f
--- /dev/null
+++ b/ext/phar/tests/phar_buildfromdirectory1.phpt
@@ -0,0 +1,28 @@
+--TEST--
+Phar::buildFromDirectory() - readonly
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+$phar = new Phar(dirname(__FILE__) . '/buildfromdirectory.phar');
+try {
+ ini_set('phar.readonly', 1);
+ $phar->buildFromDirectory(1);
+} catch (Exception $e) {
+ var_dump(get_class($e));
+ echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/buildfromdirectory.phar');
+__HALT_COMPILER();
+?>
+--EXPECT--
+string(24) "UnexpectedValueException"
+Cannot write to archive - write operations restricted by INI setting
+===DONE===
diff --git a/ext/phar/tests/phar_buildfromdirectory2.phpt b/ext/phar/tests/phar_buildfromdirectory2.phpt
new file mode 100644
index 0000000000..fcad4725a7
--- /dev/null
+++ b/ext/phar/tests/phar_buildfromdirectory2.phpt
@@ -0,0 +1,27 @@
+--TEST--
+Phar::buildFromDirectory() - non-directory passed as first parameter
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+try {
+ $phar = new Phar(dirname(__FILE__) . '/buildfromdirectory.phar');
+ $phar->buildFromDirectory(1);
+} catch (Exception $e) {
+ var_dump(get_class($e));
+ echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/buildfromdirectory.phar');
+__HALT_COMPILER();
+?>
+--EXPECT--
+string(24) "UnexpectedValueException"
+RecursiveDirectoryIterator::__construct(1): failed to open dir: No such file or directory
+===DONE===
diff --git a/ext/phar/tests/phar_buildfromdirectory3.phpt b/ext/phar/tests/phar_buildfromdirectory3.phpt
new file mode 100644
index 0000000000..435bbdfba6
--- /dev/null
+++ b/ext/phar/tests/phar_buildfromdirectory3.phpt
@@ -0,0 +1,27 @@
+--TEST--
+Phar::buildFromDirectory() - object passed as second parameter
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+
+try {
+ $phar = new Phar(dirname(__FILE__) . '/buildfromiterator.phar');
+ $phar->buildFromDirectory('files', new stdClass);
+} catch (Exception $e) {
+ var_dump(get_class($e));
+ echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/buildfromiterator.phar');
+__HALT_COMPILER();
+?>
+--EXPECTF--
+Warning: Phar::buildFromDirectory() expects parameter 2 to be string, object given in %sphar_buildfromdirectory3.php on line %d
+===DONE===
diff --git a/ext/phar/tests/phar_buildfromdirectory4.phpt b/ext/phar/tests/phar_buildfromdirectory4.phpt
new file mode 100644
index 0000000000..cf11d62af6
--- /dev/null
+++ b/ext/phar/tests/phar_buildfromdirectory4.phpt
@@ -0,0 +1,50 @@
+--TEST--
+Phar::buildFromDirectory(), directory exists
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+
+mkdir(dirname(__FILE__).'/testdir');
+foreach(range(1, 4) as $i) {
+ file_put_contents(dirname(__FILE__)."/testdir/file$i.txt", "some content for file $i");
+}
+
+try {
+ $phar = new Phar(dirname(__FILE__) . '/buildfromdirectory.phar');
+ $a = $phar->buildFromDirectory(dirname(__FILE__) . '/testdir');
+ asort($a);
+ var_dump($a);
+} catch (Exception $e) {
+ var_dump(get_class($e));
+ echo $e->getMessage() . "\n";
+}
+
+var_dump(file_exists(dirname(__FILE__) . '/buildfromdirectory.phar'));
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/buildfromdirectory.phar');
+foreach(range(1, 4) as $i) {
+ unlink(dirname(__FILE__) . "/testdir/file$i.txt");
+}
+rmdir(dirname(__FILE__) . '/testdir');
+?>
+--EXPECTF--
+array(4) {
+ ["file1.txt"]=>
+ string(%d) "%stestdir%cfile1.txt"
+ ["file2.txt"]=>
+ string(%d) "%stestdir%cfile2.txt"
+ ["file3.txt"]=>
+ string(%d) "%stestdir%cfile3.txt"
+ ["file4.txt"]=>
+ string(%d) "%stestdir%cfile4.txt"
+}
+bool(true)
+===DONE===
diff --git a/ext/phar/tests/phar_buildfromdirectory5.phpt b/ext/phar/tests/phar_buildfromdirectory5.phpt
new file mode 100644
index 0000000000..51e5cec691
--- /dev/null
+++ b/ext/phar/tests/phar_buildfromdirectory5.phpt
@@ -0,0 +1,50 @@
+--TEST--
+Phar::buildFromDirectory() with matching regex
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+
+mkdir(dirname(__FILE__).'/testdir');
+foreach(range(1, 4) as $i) {
+ file_put_contents(dirname(__FILE__)."/testdir/file$i.txt", "some content for file $i");
+}
+
+try {
+ $phar = new Phar(dirname(__FILE__) . '/buildfromdirectory.phar');
+ $a = $phar->buildFromDirectory(dirname(__FILE__) . '/testdir', '/\.txt/');
+ asort($a);
+ var_dump($a);
+} catch (Exception $e) {
+ var_dump(get_class($e));
+ echo $e->getMessage() . "\n";
+}
+
+var_dump(file_exists(dirname(__FILE__) . '/buildfromdirectory.phar'));
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/buildfromdirectory.phar');
+foreach(range(1, 4) as $i) {
+ unlink(dirname(__FILE__) . "/testdir/file$i.txt");
+}
+rmdir(dirname(__FILE__) . '/testdir');
+?>
+--EXPECTF--
+array(4) {
+ ["file1.txt"]=>
+ string(%d) "%stestdir%cfile1.txt"
+ ["file2.txt"]=>
+ string(%d) "%stestdir%cfile2.txt"
+ ["file3.txt"]=>
+ string(%d) "%stestdir%cfile3.txt"
+ ["file4.txt"]=>
+ string(%d) "%stestdir%cfile4.txt"
+}
+bool(true)
+===DONE===
diff --git a/ext/phar/tests/phar_buildfromdirectory6.phpt b/ext/phar/tests/phar_buildfromdirectory6.phpt
new file mode 100644
index 0000000000..2edd0962f1
--- /dev/null
+++ b/ext/phar/tests/phar_buildfromdirectory6.phpt
@@ -0,0 +1,40 @@
+--TEST--
+Phar::buildFromDirectory() with non-matching regex
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+
+mkdir(dirname(__FILE__).'/testdir', 0777);
+foreach(range(1, 4) as $i) {
+ file_put_contents(dirname(__FILE__)."/testdir/file$i.txt", "some content for file $i");
+}
+
+try {
+ $phar = new Phar(dirname(__FILE__) . '/buildfromdirectory.phar');
+ var_dump($phar->buildFromDirectory(dirname(__FILE__) . '/testdir', '/\.php/'));
+} catch (Exception $e) {
+ var_dump(get_class($e));
+ echo $e->getMessage() . "\n";
+}
+
+var_dump(file_exists(dirname(__FILE__) . '/buildfromdirectory.phar'));
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/buildfromdirectory.phar');
+foreach(range(1, 4) as $i) {
+ unlink(dirname(__FILE__) . "/testdir/file$i.txt");
+}
+rmdir(dirname(__FILE__) . '/testdir');
+?>
+--EXPECT--
+array(0) {
+}
+bool(false)
+===DONE===
diff --git a/ext/phar/tests/phar_buildfromiterator1.phpt b/ext/phar/tests/phar_buildfromiterator1.phpt
new file mode 100644
index 0000000000..f75823f94c
--- /dev/null
+++ b/ext/phar/tests/phar_buildfromiterator1.phpt
@@ -0,0 +1,28 @@
+--TEST--
+Phar::buildFromIterator() readonly
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+$phar = new Phar(dirname(__FILE__) . '/buildfromiterator.phar');
+try {
+ ini_set('phar.readonly', 1);
+ $phar->buildFromIterator(1);
+} catch (Exception $e) {
+ var_dump(get_class($e));
+ echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/buildfromiterator.phar');
+__HALT_COMPILER();
+?>
+--EXPECT--
+string(24) "UnexpectedValueException"
+Cannot write out phar archive, phar is read-only
+===DONE===
diff --git a/ext/phar/tests/phar_buildfromiterator10.phpt b/ext/phar/tests/phar_buildfromiterator10.phpt
new file mode 100644
index 0000000000..3f03245727
--- /dev/null
+++ b/ext/phar/tests/phar_buildfromiterator10.phpt
@@ -0,0 +1,98 @@
+--TEST--
+Phar::buildFromIterator() RegexIterator(RecursiveIteratorIterator), SplFileInfo as current
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+try {
+ chdir(dirname(__FILE__));
+ $phar = new Phar(dirname(__FILE__) . '/buildfromiterator.phar');
+ $dir = new RecursiveDirectoryIterator('.');
+ $iter = new RecursiveIteratorIterator($dir);
+ $a = $phar->buildFromIterator(new RegexIterator($iter, '/_\d{3}\.phpt$/'), dirname(__FILE__) . DIRECTORY_SEPARATOR);
+ asort($a);
+ var_dump($a);
+} catch (Exception $e) {
+ var_dump(get_class($e));
+ echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/buildfromiterator.phar');
+__HALT_COMPILER();
+?>
+--EXPECTF--
+array(33) {
+ ["phar_ctx_001.phpt"]=>
+ string(%d) "%sphar_ctx_001.phpt"
+ ["phar_get_supported_signatures_001.phpt"]=>
+ string(%d) "%sphar_get_supported_signatures_001.phpt"
+ ["phar_get_supported_signatures_002.phpt"]=>
+ string(%d) "%sphar_get_supported_signatures_002.phpt"
+ ["phar_oo_001.phpt"]=>
+ string(%d) "%sphar_oo_001.phpt"
+ ["phar_oo_002.phpt"]=>
+ string(%d) "%sphar_oo_002.phpt"
+ ["phar_oo_003.phpt"]=>
+ string(%d) "%sphar_oo_003.phpt"
+ ["phar_oo_004.phpt"]=>
+ string(%d) "%sphar_oo_004.phpt"
+ ["phar_oo_005.phpt"]=>
+ string(%d) "%sphar_oo_005.phpt"
+ ["phar_oo_006.phpt"]=>
+ string(%d) "%sphar_oo_006.phpt"
+ ["phar_oo_007.phpt"]=>
+ string(%d) "%sphar_oo_007.phpt"
+ ["phar_oo_008.phpt"]=>
+ string(%d) "%sphar_oo_008.phpt"
+ ["phar_oo_009.phpt"]=>
+ string(%d) "%sphar_oo_009.phpt"
+ ["phar_oo_010.phpt"]=>
+ string(%d) "%sphar_oo_010.phpt"
+ ["phar_oo_011.phpt"]=>
+ string(%d) "%sphar_oo_011.phpt"
+ ["phar_oo_012.phpt"]=>
+ string(%d) "%sphar_oo_012.phpt"
+ ["phar_oo_compressed_001.phpt"]=>
+ string(%d) "%sphar_oo_compressed_001.phpt"
+ ["phar_oo_compressed_002.phpt"]=>
+ string(%d) "%sphar_oo_compressed_002.phpt"
+ ["phpinfo_001.phpt"]=>
+ string(%d) "%sphpinfo_001.phpt"
+ ["phpinfo_002.phpt"]=>
+ string(%d) "%sphpinfo_002.phpt"
+ ["phpinfo_003.phpt"]=>
+ string(%d) "%sphpinfo_003.phpt"
+ ["phpinfo_004.phpt"]=>
+ string(%d) "%sphpinfo_004.phpt"
+ ["tar/tar_001.phpt"]=>
+ string(%d) "%star%ctar_001.phpt"
+ ["tar/tar_002.phpt"]=>
+ string(%d) "%star%ctar_002.phpt"
+ ["tar/tar_003.phpt"]=>
+ string(%d) "%star%ctar_003.phpt"
+ ["tar/tar_004.phpt"]=>
+ string(%d) "%star%ctar_004.phpt"
+ ["zip/corrupt_001.phpt"]=>
+ string(%d) "%szip%ccorrupt_001.phpt"
+ ["zip/corrupt_002.phpt"]=>
+ string(%d) "%szip%ccorrupt_002.phpt"
+ ["zip/corrupt_003.phpt"]=>
+ string(%d) "%szip%ccorrupt_003.phpt"
+ ["zip/corrupt_004.phpt"]=>
+ string(%d) "%szip%ccorrupt_004.phpt"
+ ["zip/corrupt_005.phpt"]=>
+ string(%d) "%szip%ccorrupt_005.phpt"
+ ["zip/corrupt_006.phpt"]=>
+ string(%d) "%szip%ccorrupt_006.phpt"
+ ["zip/corrupt_007.phpt"]=>
+ string(%d) "%szip%ccorrupt_007.phpt"
+ ["zip/corrupt_008.phpt"]=>
+ string(%d) "%szip%ccorrupt_008.phpt"
+}
+===DONE===
diff --git a/ext/phar/tests/phar_buildfromiterator2.phpt b/ext/phar/tests/phar_buildfromiterator2.phpt
new file mode 100644
index 0000000000..cdc2df1050
--- /dev/null
+++ b/ext/phar/tests/phar_buildfromiterator2.phpt
@@ -0,0 +1,26 @@
+--TEST--
+Phar::buildFromIterator() wrong object
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+try {
+ $phar = new Phar(dirname(__FILE__) . '/buildfromiterator.phar');
+ $phar->buildFromIterator(new stdClass);
+} catch (Exception $e) {
+ var_dump(get_class($e));
+ echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/buildfromiterator.phar');
+__HALT_COMPILER();
+?>
+--EXPECTF--
+Warning: Phar::buildFromIterator() expects parameter 1 to be Traversable, object given in %sphar_buildfromiterator2.php on line %d
+===DONE===
diff --git a/ext/phar/tests/phar_buildfromiterator3.phpt b/ext/phar/tests/phar_buildfromiterator3.phpt
new file mode 100644
index 0000000000..5fca706041
--- /dev/null
+++ b/ext/phar/tests/phar_buildfromiterator3.phpt
@@ -0,0 +1,54 @@
+--TEST--
+Phar::buildFromIterator() iterator, but object passed
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+class myIterator implements Iterator
+{
+ var $a;
+ function __construct(array $a)
+ {
+ $this->a = $a;
+ }
+ function next() {
+ echo "next\n";
+ return next($this->a);
+ }
+ function current() {
+ echo "current\n";
+ return current($this->a);
+ }
+ function key() {
+ echo "key\n";
+ return key($this->a);
+ }
+ function valid() {
+ echo "valid\n";
+ return current($this->a);
+ }
+ function rewind() {
+ echo "rewind\n";
+ return reset($this->a);
+ }
+}
+try {
+ $phar = new Phar(dirname(__FILE__) . '/buildfromiterator.phar');
+ $phar->buildFromIterator(new myIterator(array()), new stdClass);
+} catch (Exception $e) {
+ var_dump(get_class($e));
+ echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/buildfromiterator.phar');
+__HALT_COMPILER();
+?>
+--EXPECTF--
+Warning: Phar::buildFromIterator() expects parameter 2 to be string, object given in %sphar_buildfromiterator3.php on line %d
+===DONE===
diff --git a/ext/phar/tests/phar_buildfromiterator4.phpt b/ext/phar/tests/phar_buildfromiterator4.phpt
new file mode 100644
index 0000000000..3c20460d53
--- /dev/null
+++ b/ext/phar/tests/phar_buildfromiterator4.phpt
@@ -0,0 +1,64 @@
+--TEST--
+Phar::buildFromIterator() iterator, 1 file passed in
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+class myIterator implements Iterator
+{
+ var $a;
+ function __construct(array $a)
+ {
+ $this->a = $a;
+ }
+ function next() {
+ echo "next\n";
+ return next($this->a);
+ }
+ function current() {
+ echo "current\n";
+ return current($this->a);
+ }
+ function key() {
+ echo "key\n";
+ return key($this->a);
+ }
+ function valid() {
+ echo "valid\n";
+ return current($this->a);
+ }
+ function rewind() {
+ echo "rewind\n";
+ return reset($this->a);
+ }
+}
+try {
+ chdir(dirname(__FILE__));
+ $phar = new Phar(dirname(__FILE__) . '/buildfromiterator.phar');
+ var_dump($phar->buildFromIterator(new myIterator(array('a' => basename(__FILE__, 'php') . 'phpt'))));
+} catch (Exception $e) {
+ var_dump(get_class($e));
+ echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/buildfromiterator.phar');
+__HALT_COMPILER();
+?>
+--EXPECTF--
+rewind
+valid
+current
+key
+next
+valid
+array(1) {
+ ["a"]=>
+ string(%d) "%sphar_buildfromiterator4.phpt"
+}
+===DONE===
diff --git a/ext/phar/tests/phar_buildfromiterator5.phpt b/ext/phar/tests/phar_buildfromiterator5.phpt
new file mode 100644
index 0000000000..3bd2cec78c
--- /dev/null
+++ b/ext/phar/tests/phar_buildfromiterator5.phpt
@@ -0,0 +1,59 @@
+--TEST--
+Phar::buildFromIterator() iterator, iterator returns non-string
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+class myIterator implements Iterator
+{
+ var $a;
+ function __construct(array $a)
+ {
+ $this->a = $a;
+ }
+ function next() {
+ echo "next\n";
+ return next($this->a);
+ }
+ function current() {
+ echo "current\n";
+ return current($this->a);
+ }
+ function key() {
+ echo "key\n";
+ return key($this->a);
+ }
+ function valid() {
+ echo "valid\n";
+ return current($this->a);
+ }
+ function rewind() {
+ echo "rewind\n";
+ return reset($this->a);
+ }
+}
+try {
+ chdir(dirname(__FILE__));
+ $phar = new Phar(dirname(__FILE__) . '/buildfromiterator.phar');
+ var_dump($phar->buildFromIterator(new myIterator(array('a' => new stdClass))));
+} catch (Exception $e) {
+ var_dump(get_class($e));
+ echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/buildfromiterator.phar');
+__HALT_COMPILER();
+?>
+--EXPECTF--
+rewind
+valid
+current
+string(24) "UnexpectedValueException"
+Iterator myIterator returned an invalid value (must return a string)
+===DONE===
diff --git a/ext/phar/tests/phar_buildfromiterator6.phpt b/ext/phar/tests/phar_buildfromiterator6.phpt
new file mode 100644
index 0000000000..ae73bbd479
--- /dev/null
+++ b/ext/phar/tests/phar_buildfromiterator6.phpt
@@ -0,0 +1,60 @@
+--TEST--
+Phar::buildFromIterator() iterator, key is int
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+class myIterator implements Iterator
+{
+ var $a;
+ function __construct(array $a)
+ {
+ $this->a = $a;
+ }
+ function next() {
+ echo "next\n";
+ return next($this->a);
+ }
+ function current() {
+ echo "current\n";
+ return current($this->a);
+ }
+ function key() {
+ echo "key\n";
+ return key($this->a);
+ }
+ function valid() {
+ echo "valid\n";
+ return current($this->a);
+ }
+ function rewind() {
+ echo "rewind\n";
+ return reset($this->a);
+ }
+}
+try {
+ chdir(dirname(__FILE__));
+ $phar = new Phar(dirname(__FILE__) . '/buildfromiterator.phar');
+ var_dump($phar->buildFromIterator(new myIterator(array(basename(__FILE__, 'php') . 'phpt'))));
+} catch (Exception $e) {
+ var_dump(get_class($e));
+ echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/buildfromiterator.phar');
+__HALT_COMPILER();
+?>
+--EXPECTF--
+rewind
+valid
+current
+key
+string(24) "UnexpectedValueException"
+Iterator myIterator returned an invalid key (must return a string)
+===DONE===
diff --git a/ext/phar/tests/phar_buildfromiterator7.phpt b/ext/phar/tests/phar_buildfromiterator7.phpt
new file mode 100644
index 0000000000..38d2e1a5f2
--- /dev/null
+++ b/ext/phar/tests/phar_buildfromiterator7.phpt
@@ -0,0 +1,60 @@
+--TEST--
+Phar::buildFromIterator() iterator, file can't be opened
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+class myIterator implements Iterator
+{
+ var $a;
+ function __construct(array $a)
+ {
+ $this->a = $a;
+ }
+ function next() {
+ echo "next\n";
+ return next($this->a);
+ }
+ function current() {
+ echo "current\n";
+ return current($this->a);
+ }
+ function key() {
+ echo "key\n";
+ return key($this->a);
+ }
+ function valid() {
+ echo "valid\n";
+ return current($this->a);
+ }
+ function rewind() {
+ echo "rewind\n";
+ return reset($this->a);
+ }
+}
+try {
+ chdir(dirname(__FILE__));
+ $phar = new Phar(dirname(__FILE__) . '/buildfromiterator.phar');
+ var_dump($phar->buildFromIterator(new myIterator(array('a' => basename(__FILE__, 'php') . '/oopsie/there.phpt'))));
+} catch (Exception $e) {
+ var_dump(get_class($e));
+ echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/buildfromiterator.phar');
+__HALT_COMPILER();
+?>
+--EXPECT--
+rewind
+valid
+current
+key
+string(24) "UnexpectedValueException"
+Iterator myIterator returned a file that could not be opened "phar_buildfromiterator7./oopsie/there.phpt"
+===DONE===
diff --git a/ext/phar/tests/phar_buildfromiterator8.phpt b/ext/phar/tests/phar_buildfromiterator8.phpt
new file mode 100644
index 0000000000..d382b82ee0
--- /dev/null
+++ b/ext/phar/tests/phar_buildfromiterator8.phpt
@@ -0,0 +1,96 @@
+--TEST--
+Phar::buildFromIterator() RegexIterator(DirectoryIterator), SplFileInfo as current
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+try {
+ chdir(dirname(__FILE__));
+ $phar = new Phar(dirname(__FILE__) . '/buildfromiterator.phar');
+ $a = $phar->buildFromIterator(new RegexIterator(new DirectoryIterator('.'), '/^\d{0,3}\.phpt\\z|^\.\\z|^\.\.\\z/'), dirname(__FILE__) . DIRECTORY_SEPARATOR);
+ asort($a);
+ var_dump($a);
+} catch (Exception $e) {
+ var_dump(get_class($e));
+ echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/buildfromiterator.phar');
+__HALT_COMPILER();
+?>
+--EXPECTF--
+array(33) {
+ ["001.phpt"]=>
+ string(%d) "%s001.phpt"
+ ["002.phpt"]=>
+ string(%d) "%s002.phpt"
+ ["003.phpt"]=>
+ string(%d) "%s003.phpt"
+ ["004.phpt"]=>
+ string(%d) "%s004.phpt"
+ ["005.phpt"]=>
+ string(%d) "%s005.phpt"
+ ["006.phpt"]=>
+ string(%d) "%s006.phpt"
+ ["007.phpt"]=>
+ string(%d) "%s007.phpt"
+ ["008.phpt"]=>
+ string(%d) "%s008.phpt"
+ ["009.phpt"]=>
+ string(%d) "%s009.phpt"
+ ["010.phpt"]=>
+ string(%d) "%s010.phpt"
+ ["011.phpt"]=>
+ string(%d) "%s011.phpt"
+ ["012.phpt"]=>
+ string(%d) "%s012.phpt"
+ ["013.phpt"]=>
+ string(%d) "%s013.phpt"
+ ["014.phpt"]=>
+ string(%d) "%s014.phpt"
+ ["015.phpt"]=>
+ string(%d) "%s015.phpt"
+ ["016.phpt"]=>
+ string(%d) "%s016.phpt"
+ ["017.phpt"]=>
+ string(%d) "%s017.phpt"
+ ["018.phpt"]=>
+ string(%d) "%s018.phpt"
+ ["019.phpt"]=>
+ string(%d) "%s019.phpt"
+ ["020.phpt"]=>
+ string(%d) "%s020.phpt"
+ ["021.phpt"]=>
+ string(%d) "%s021.phpt"
+ ["022.phpt"]=>
+ string(%d) "%s022.phpt"
+ ["023.phpt"]=>
+ string(%d) "%s023.phpt"
+ ["024.phpt"]=>
+ string(%d) "%s024.phpt"
+ ["025.phpt"]=>
+ string(%d) "%s025.phpt"
+ ["026.phpt"]=>
+ string(%d) "%s026.phpt"
+ ["027.phpt"]=>
+ string(%d) "%s027.phpt"
+ ["028.phpt"]=>
+ string(%d) "%s028.phpt"
+ ["029.phpt"]=>
+ string(%d) "%s029.phpt"
+ ["030.phpt"]=>
+ string(%d) "%s030.phpt"
+ ["031.phpt"]=>
+ string(%d) "%s031.phpt"
+ ["032.phpt"]=>
+ string(%d) "%s032.phpt"
+ ["033.phpt"]=>
+ string(%d) "%s033.phpt"
+}
+===DONE===
diff --git a/ext/phar/tests/phar_buildfromiterator9.phpt b/ext/phar/tests/phar_buildfromiterator9.phpt
new file mode 100644
index 0000000000..0b56307545
--- /dev/null
+++ b/ext/phar/tests/phar_buildfromiterator9.phpt
@@ -0,0 +1,65 @@
+--TEST--
+Phar::buildFromIterator() iterator, 1 file resource passed in
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+class myIterator implements Iterator
+{
+ var $a;
+ function __construct(array $a)
+ {
+ $this->a = $a;
+ }
+ function next() {
+ echo "next\n";
+ return next($this->a);
+ }
+ function current() {
+ echo "current\n";
+ return current($this->a);
+ }
+ function key() {
+ echo "key\n";
+ return key($this->a);
+ }
+ function valid() {
+ echo "valid\n";
+ return current($this->a);
+ }
+ function rewind() {
+ echo "rewind\n";
+ return reset($this->a);
+ }
+}
+try {
+ chdir(dirname(__FILE__));
+ $phar = new Phar(dirname(__FILE__) . '/buildfromiterator.phar');
+ var_dump($phar->buildFromIterator(new myIterator(array('a' => $a = fopen(basename(__FILE__, 'php') . 'phpt', 'r')))));
+ fclose($a);
+} catch (Exception $e) {
+ var_dump(get_class($e));
+ echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/buildfromiterator.phar');
+__HALT_COMPILER();
+?>
+--EXPECTF--
+rewind
+valid
+current
+key
+next
+valid
+array(1) {
+ ["a"]=>
+ string(%d) "[stream]"
+}
+===DONE===
diff --git a/ext/phar/tests/phar_bz2.phpt b/ext/phar/tests/phar_bz2.phpt
new file mode 100644
index 0000000000..71b10f9092
--- /dev/null
+++ b/ext/phar/tests/phar_bz2.phpt
@@ -0,0 +1,63 @@
+--TEST--
+Phar: bzipped phar
+--SKIPIF--
+<?php if (!extension_loaded('phar')) die('skip'); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+<?php if (!extension_loaded("bz2")) die("skip bz2 not available"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/phar_bz2.phar';
+$pname = 'phar://' . $fname;
+$fname2 = dirname(__FILE__) . '/phar_bz2.2.phar';
+$pname2 = 'phar://' . $fname2;
+
+$file = '<?php
+Phar::mapPhar();
+var_dump("it worked");
+include "phar://" . __FILE__ . "/tar_004.php";
+__HALT_COMPILER();';
+
+$files = array();
+$files['tar_004.php'] = '<?php var_dump(__FILE__);';
+$files['internal/file/here'] = "hi there!\n";
+$files['internal/dir/'] = '';
+$files['dir/'] = '';
+$bz2 = true;
+
+include 'files/phar_test.inc';
+
+include $fname;
+
+$a = new Phar($fname);
+$a['test'] = 'hi';
+copy($fname, $fname2);
+$a->setAlias('another');
+$b = new Phar($fname2);
+var_dump($b->isFileFormat(Phar::PHAR));
+var_dump($b->isCompressed() == Phar::BZ2);
+// additional code coverage
+$b->isFileFormat(array());
+try {
+$b->isFileFormat(25);
+} catch (Exception $e) {
+echo $e->getMessage(),"\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+@unlink(dirname(__FILE__) . '/phar_bz2.phar');
+@unlink(dirname(__FILE__) . '/phar_bz2.2.phar');
+?>
+--EXPECTF--
+string(9) "it worked"
+string(%d) "phar://%sphar_bz2.phar/tar_004.php"
+bool(true)
+bool(true)
+
+Warning: Phar::isFileFormat() expects parameter 1 to be long, array given in %sphar_bz2.php on line %d
+Unknown file format specified
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/phar_commitwrite.phpt b/ext/phar/tests/phar_commitwrite.phpt
new file mode 100644
index 0000000000..63878355b0
--- /dev/null
+++ b/ext/phar/tests/phar_commitwrite.phpt
@@ -0,0 +1,42 @@
+--TEST--
+Phar::setStub()/stopBuffering()
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+$p = new Phar(dirname(__FILE__) . '/brandnewphar.phar', 0, 'brandnewphar.phar');
+$p['file1.txt'] = 'hi';
+$p->stopBuffering();
+var_dump(strlen($p->getStub()));
+$p->setStub("<?php
+function __autoload(\$class)
+{
+ include 'phar://' . str_replace('_', '/', \$class);
+}
+Phar::mapPhar('brandnewphar.phar');
+include 'phar://brandnewphar.phar/startup.php';
+__HALT_COMPILER();
+?>");
+var_dump($p->getStub());
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/brandnewphar.phar');
+__HALT_COMPILER();
+?>
+--EXPECT--
+int(6651)
+string(200) "<?php
+function __autoload($class)
+{
+ include 'phar://' . str_replace('_', '/', $class);
+}
+Phar::mapPhar('brandnewphar.phar');
+include 'phar://brandnewphar.phar/startup.php';
+__HALT_COMPILER(); ?>
+"
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/phar_convert_again.phpt b/ext/phar/tests/phar_convert_again.phpt
new file mode 100644
index 0000000000..4543a238d5
--- /dev/null
+++ b/ext/phar/tests/phar_convert_again.phpt
@@ -0,0 +1,218 @@
+--TEST--
+Phar::conversion to other formats
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("zlib")) die("skip no zlib"); ?>
+<?php if (!extension_loaded("bz2")) die("skip no bz2"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar';
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '2.tbz';
+$pname = 'phar://' . $fname;
+$stub = '<?php echo "first stub\n"; __HALT_COMPILER(); ?>';
+$file = $stub;
+
+$files = array();
+$files['a'] = 'a';
+$files['b'] = 'b';
+$files['c'] = 'c';
+
+include 'files/phar_test.inc';
+
+$phar = new Phar($fname);
+$zip = $phar->convertToData(Phar::ZIP);
+echo $zip->getPath() . "\n";
+$tgz = $phar->convertToData(Phar::TAR, Phar::GZ);
+echo $tgz->getPath() . "\n";
+$tbz = $phar->convertToData(Phar::TAR, Phar::BZ2);
+echo $tbz->getPath() . "\n";
+try {
+$phar = $tbz->convertToExecutable(Phar::PHAR, Phar::NONE);
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+copy($tbz->getPath(), $fname2);
+$tbz = new PharData($fname2);
+$phar = $tbz->convertToExecutable(Phar::PHAR, Phar::NONE);
+echo $phar->getPath() . "\n";
+$phar['a'] = 'hi';
+$phar['a']->setMetadata('hi');
+$zip = $phar->convertToExecutable(Phar::ZIP);
+echo $zip->getPath() . "\n";
+echo $zip['a']->getMetadata() . "\n";
+$data = $zip->convertToData();
+echo $data->getPath() . "\n";
+// extra code coverage
+try {
+$data->setStub('hi');
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+try {
+$data->setDefaultStub();
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+try {
+$data->setAlias('hi');
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+try {
+$data->setSignatureAlgorithm(Phar::MD5);
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+$tar = $phar->convertToExecutable(Phar::TAR);
+echo $tar->getPath() . "\n";
+$data = $tar->convertToData();
+echo $data->getPath() . "\n";
+$tgz = $tar->convertToExecutable(null, Phar::GZ);
+echo $tgz->getPath() . "\n";
+try {
+$tgz->convertToExecutable(25);
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+try {
+$tgz->convertToExecutable(Phar::ZIP, Phar::GZ);
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+try {
+$tgz->convertToExecutable(Phar::ZIP, Phar::BZ2);
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+try {
+$phar->convertToData();
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+try {
+$tgz->convertToData(Phar::PHAR);
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+try {
+$tgz->convertToData(25);
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+try {
+$tgz->convertToData(Phar::ZIP, Phar::GZ);
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+try {
+$tgz->convertToData(Phar::ZIP, Phar::BZ2);
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+try {
+$tgz->convertToExecutable(Phar::TAR, 25);
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+try {
+$tgz->convertToData(Phar::TAR, 25);
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+// extra code coverage
+try {
+$data->setStub('hi');
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+try {
+$data->setAlias('hi');
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+try {
+$data->setDefaultStub();
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+try {
+$data->setSignatureAlgorithm(Phar::MD5);
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+
+try {
+$tgz->convertToData(Phar::TAR, Phar::GZ, '.phar.tgz.oops');
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+
+try {
+$phar->convertToExecutable(Phar::TAR, Phar::GZ, '.tgz.oops');
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+
+try {
+$tgz->convertToData(Phar::TAR, Phar::GZ, '.phar/.tgz.oops');
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar.gz');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.zip');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.tar.gz');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.tar');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.tar.bz2');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '2.tbz');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '2.phar');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '2.phar.tar');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '2.tar');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '2.phar.zip');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '2.zip');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '2.phar.tar.gz');
+__HALT_COMPILER();
+?>
+--EXPECTF--
+%sphar_convert_again.zip
+%sphar_convert_again.tar.gz
+%sphar_convert_again.tar.bz2
+Unable to add newly converted phar "%sphar_convert_again.phar" to the list of phars, a phar with that name already exists
+%sphar_convert_again2.phar
+%sphar_convert_again2.phar.zip
+hi
+%sphar_convert_again2.zip
+A Phar stub cannot be set in a plain zip archive
+A Phar stub cannot be set in a plain zip archive
+A Phar alias cannot be set in a plain zip archive
+Cannot set signature algorithm, not possible with zip-based phar archives
+%sphar_convert_again2.phar.tar
+%sphar_convert_again2.tar
+%sphar_convert_again2.phar.tar.gz
+Unknown file format specified, please pass one of Phar::PHAR, Phar::TAR or Phar::ZIP
+Cannot compress entire archive with gzip, zip archives do not support whole-archive compression
+Cannot compress entire archive with bz2, zip archives do not support whole-archive compression
+Cannot write out data phar archive, use Phar::TAR or Phar::ZIP
+Cannot write out data phar archive, use Phar::TAR or Phar::ZIP
+Unknown file format specified, please pass one of Phar::TAR or Phar::ZIP
+Cannot compress entire archive with gzip, zip archives do not support whole-archive compression
+Cannot compress entire archive with bz2, zip archives do not support whole-archive compression
+Unknown compression specified, please pass one of Phar::GZ or Phar::BZ2
+Unknown compression specified, please pass one of Phar::GZ or Phar::BZ2
+A Phar stub cannot be set in a plain tar archive
+A Phar alias cannot be set in a plain tar archive
+A Phar stub cannot be set in a plain tar archive
+Cannot set signature algorithm, not possible with tar-based phar archives
+data phar "%sphar_convert_again2.phar.tgz.oops" has invalid extension phar.tgz.oops
+phar "%sphar_convert_again2.tgz.oops" has invalid extension tgz.oops
+data phar "%sphar_convert_again2.phar/.tgz.oops" has invalid extension phar/.tgz.oops
+===DONE===
diff --git a/ext/phar/tests/phar_convert_repeated.phpt b/ext/phar/tests/phar_convert_repeated.phpt
new file mode 100644
index 0000000000..b2ef195ea7
--- /dev/null
+++ b/ext/phar/tests/phar_convert_repeated.phpt
@@ -0,0 +1,149 @@
+--TEST--
+Phar::convertToZip|Tar|Phar() repeated (phar_based archives)
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar';
+$pname = 'phar://' . $fname;
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.zip';
+$fname3 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar';
+$stub = '<?php echo "first stub\n"; __HALT_COMPILER(); ?>';
+$file = $stub;
+
+$files = array();
+$files['a'] = 'a';
+$files['b'] = 'b';
+$files['c'] = 'c';
+
+include 'files/phar_test.inc';
+
+echo "=================== new Phar() =======================\n";
+$phar = new Phar($fname);
+var_dump($phar->isFileFormat(Phar::PHAR));
+var_dump($phar->isFileFormat(Phar::TAR));
+var_dump($phar->isFileFormat(Phar::ZIP));
+var_dump($phar->getStub());
+var_dump($phar->getAlias());
+
+echo "================= convertToTar() =====================\n";
+
+$phar = $phar->convertToExecutable(Phar::TAR);
+var_dump($phar->isFileFormat(Phar::PHAR));
+var_dump($phar->isFileFormat(Phar::TAR));
+var_dump($phar->isFileFormat(Phar::ZIP));
+var_dump($phar->getStub());
+var_dump($phar->getAlias());
+
+echo "================= convertToZip() =====================\n";
+
+$phar = $phar->convertToExecutable(Phar::ZIP);
+var_dump($phar->isFileFormat(Phar::PHAR));
+var_dump($phar->isFileFormat(Phar::TAR));
+var_dump($phar->isFileFormat(Phar::ZIP));
+var_dump($phar->getStub());
+var_dump($phar->getAlias());
+
+echo "================= convertToPhar() ====================\n";
+
+$phar = $phar->convertToExecutable(Phar::PHAR, Phar::NONE, '.2.phar');
+var_dump($phar->isFileFormat(Phar::PHAR));
+var_dump($phar->isFileFormat(Phar::TAR));
+var_dump($phar->isFileFormat(Phar::ZIP));
+var_dump(strlen($phar->getStub()));
+var_dump($phar->getAlias());
+
+echo "================= convertToZip() =====================\n";
+
+$phar = $phar->convertToExecutable(Phar::ZIP, Phar::NONE, '.2.phar.zip');
+var_dump($phar->isFileFormat(Phar::PHAR));
+var_dump($phar->isFileFormat(Phar::TAR));
+var_dump($phar->isFileFormat(Phar::ZIP));
+var_dump($phar->getStub());
+var_dump($phar->getAlias());
+
+echo "================= convertToTar() =====================\n";
+
+$phar = $phar->convertToExecutable(Phar::TAR, Phar::NONE, '2.phar.tar');
+var_dump($phar->isFileFormat(Phar::PHAR));
+var_dump($phar->isFileFormat(Phar::TAR));
+var_dump($phar->isFileFormat(Phar::ZIP));
+var_dump($phar->getStub());
+var_dump($phar->getAlias());
+
+echo "================= convertToZip() =====================\n";
+
+$phar = $phar->convertToExecutable(Phar::ZIP, Phar::NONE, '3.phar.zip');
+var_dump($phar->isFileFormat(Phar::PHAR));
+var_dump($phar->isFileFormat(Phar::TAR));
+var_dump($phar->isFileFormat(Phar::ZIP));
+var_dump($phar->getStub());
+var_dump($phar->getAlias());
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.zip');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.2.phar.zip');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.2.phar.tar');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.2.phar');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.3.phar.zip');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.3.phar.tar');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.3.phar');
+?>
+--EXPECTF--
+=================== new Phar() =======================
+bool(true)
+bool(false)
+bool(false)
+string(48) "<?php echo "first stub\n"; __HALT_COMPILER(); ?>"
+string(3) "hio"
+================= convertToTar() =====================
+bool(false)
+bool(true)
+bool(false)
+string(60) "<?php // tar-based phar archive stub file
+__HALT_COMPILER();"
+string(%d) "%sphar_convert_repeated.phar.tar"
+================= convertToZip() =====================
+bool(false)
+bool(false)
+bool(true)
+string(60) "<?php // zip-based phar archive stub file
+__HALT_COMPILER();"
+NULL
+================= convertToPhar() ====================
+bool(true)
+bool(false)
+bool(false)
+int(6651)
+NULL
+================= convertToZip() =====================
+bool(false)
+bool(false)
+bool(true)
+string(60) "<?php // zip-based phar archive stub file
+__HALT_COMPILER();"
+NULL
+================= convertToTar() =====================
+bool(false)
+bool(true)
+bool(false)
+string(60) "<?php // tar-based phar archive stub file
+__HALT_COMPILER();"
+NULL
+================= convertToZip() =====================
+bool(false)
+bool(false)
+bool(true)
+string(60) "<?php // zip-based phar archive stub file
+__HALT_COMPILER();"
+NULL
+===DONE===
diff --git a/ext/phar/tests/phar_convert_repeated_b.phpt b/ext/phar/tests/phar_convert_repeated_b.phpt
new file mode 100644
index 0000000000..3d958927bb
--- /dev/null
+++ b/ext/phar/tests/phar_convert_repeated_b.phpt
@@ -0,0 +1,117 @@
+--TEST--
+PharData::convertToZip|Tar|Phar() repeated (phardata_based archives)
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=1
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.zip';
+
+echo "=================== new PharData() ==================\n";
+$phar = new PharData($fname);
+$phar['a'] = 'a';
+$phar['b'] = 'b';
+$phar['c'] = 'c';
+
+var_dump($phar->isFileFormat(Phar::PHAR));
+var_dump($phar->isFileFormat(Phar::TAR));
+var_dump($phar->isFileFormat(Phar::ZIP));
+var_dump($phar->getStub());
+var_dump($phar->getAlias());
+
+echo "================= convertToTar() =====================\n";
+
+$phar = $phar->convertToData(Phar::TAR);
+var_dump($phar->isFileFormat(Phar::PHAR));
+var_dump($phar->isFileFormat(Phar::TAR));
+var_dump($phar->isFileFormat(Phar::ZIP));
+var_dump($phar->getStub());
+var_dump($phar->getAlias());
+
+echo "================= convertToZip() =====================\n";
+
+$phar = $phar->convertToData(Phar::ZIP, Phar::NONE, '.1.zip');
+var_dump($phar->isFileFormat(Phar::PHAR));
+var_dump($phar->isFileFormat(Phar::TAR));
+var_dump($phar->isFileFormat(Phar::ZIP));
+var_dump($phar->getStub());
+var_dump($phar->getAlias());
+
+echo "================= convertToPhar() ====================\n";
+
+try {
+ $phar = $phar->convertToExecutable(Phar::PHAR);
+ var_dump($phar->isFileFormat(Phar::PHAR));
+ var_dump($phar->isFileFormat(Phar::TAR));
+ var_dump($phar->isFileFormat(Phar::ZIP));
+ var_dump(strlen($phar->getStub()));
+ var_dump($phar->getAlias());
+} catch(Exception $e) {
+ echo $e->getMessage()."\n";
+}
+
+echo "================ convertToTar(GZ) ====================\n";
+
+$phar = $phar->convertToData(Phar::TAR, Phar::GZ, '.2.tar');
+var_dump($phar->isFileFormat(Phar::PHAR));
+var_dump($phar->isFileFormat(Phar::TAR));
+var_dump($phar->isFileFormat(Phar::ZIP));
+var_dump($phar->getStub());
+var_dump($phar->getAlias());
+
+echo "================= convertToPhar() ====================\n";
+
+try {
+ $phar = $phar->convertToExecutable(Phar::PHAR);
+ var_dump($phar->isFileFormat(Phar::PHAR));
+ var_dump($phar->isFileFormat(Phar::TAR));
+ var_dump($phar->isFileFormat(Phar::ZIP));
+ var_dump(strlen($phar->getStub()));
+ var_dump($phar->getAlias());
+} catch(Exception $e) {
+ echo $e->getMessage()."\n";
+}
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.gz');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.tar.gz');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.tar');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.2.tar');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.zip');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.1.zip');
+?>
+--EXPECT--
+=================== new PharData() ==================
+bool(false)
+bool(false)
+bool(true)
+string(0) ""
+NULL
+================= convertToTar() =====================
+bool(false)
+bool(true)
+bool(false)
+string(0) ""
+NULL
+================= convertToZip() =====================
+bool(false)
+bool(false)
+bool(true)
+string(0) ""
+NULL
+================= convertToPhar() ====================
+Cannot write out executable phar archive, phar is read-only
+================ convertToTar(GZ) ====================
+bool(false)
+bool(true)
+bool(false)
+string(0) ""
+NULL
+================= convertToPhar() ====================
+Cannot write out executable phar archive, phar is read-only
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/phar_convert_tar.phpt b/ext/phar/tests/phar_convert_tar.phpt
new file mode 100644
index 0000000000..d4031ec32f
--- /dev/null
+++ b/ext/phar/tests/phar_convert_tar.phpt
@@ -0,0 +1,57 @@
+--TEST--
+Phar::convertToTar()
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar';
+$pname = 'phar://' . $fname;
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar';
+$fname3 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.2.phar.tar';
+$stub = '<?php echo "first stub\n"; __HALT_COMPILER(); ?>';
+$file = $stub;
+
+$files = array();
+$files['a'] = 'a';
+$files['b'] = 'b';
+$files['c'] = 'c';
+
+include 'files/phar_test.inc';
+
+$phar = new Phar($fname);
+var_dump($phar->isFileFormat(Phar::TAR));
+var_dump($phar->getStub());
+
+$phar = $phar->convertToExecutable(Phar::TAR);
+var_dump($phar->isFileFormat(Phar::TAR));
+var_dump($phar->getStub());
+
+copy($fname2, $fname3);
+
+$phar = new Phar($fname3);
+var_dump($phar->isFileFormat(Phar::TAR));
+var_dump($phar->getStub());
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.2.phar.tar');
+__HALT_COMPILER();
+?>
+--EXPECT--
+bool(false)
+string(48) "<?php echo "first stub\n"; __HALT_COMPILER(); ?>"
+bool(true)
+string(60) "<?php // tar-based phar archive stub file
+__HALT_COMPILER();"
+bool(true)
+string(60) "<?php // tar-based phar archive stub file
+__HALT_COMPILER();"
+===DONE===
diff --git a/ext/phar/tests/phar_convert_tar2.phpt b/ext/phar/tests/phar_convert_tar2.phpt
new file mode 100644
index 0000000000..f0f0f69825
--- /dev/null
+++ b/ext/phar/tests/phar_convert_tar2.phpt
@@ -0,0 +1,64 @@
+--TEST--
+Phar::convertToTar() gzip compressed
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("zlib")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar.gz';
+$fname3 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.2.phar.tar';
+$stub = '<?php echo "first stub\n"; __HALT_COMPILER(); ?>';
+$file = $stub;
+
+$files = array();
+$files['a'] = 'a';
+$files['b'] = 'b';
+$files['c'] = 'c';
+
+include 'files/phar_test.inc';
+
+$phar = new Phar($fname);
+var_dump($phar->isFileFormat(Phar::TAR));
+var_dump($phar->isCompressed());
+var_dump($phar->getStub());
+
+$phar = $phar->convertToExecutable(Phar::TAR, Phar::GZ);
+var_dump($phar->isFileFormat(Phar::TAR));
+var_dump($phar->isCompressed());
+var_dump($phar->getStub());
+
+copy($fname2, $fname3);
+
+$phar = new Phar($fname3);
+var_dump($phar->isFileFormat(Phar::TAR));
+var_dump($phar->isCompressed() == Phar::GZ);
+var_dump($phar->getStub());
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar.gz');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.2.phar.tar');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php');
+?>
+--EXPECT--
+bool(false)
+bool(false)
+string(48) "<?php echo "first stub\n"; __HALT_COMPILER(); ?>"
+bool(true)
+int(4096)
+string(60) "<?php // tar-based phar archive stub file
+__HALT_COMPILER();"
+bool(true)
+bool(true)
+string(60) "<?php // tar-based phar archive stub file
+__HALT_COMPILER();"
+===DONE===
diff --git a/ext/phar/tests/phar_convert_tar3.phpt b/ext/phar/tests/phar_convert_tar3.phpt
new file mode 100644
index 0000000000..52fd0f555a
--- /dev/null
+++ b/ext/phar/tests/phar_convert_tar3.phpt
@@ -0,0 +1,65 @@
+--TEST--
+Phar::convertToTar() bz2 compressed
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("bz2")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar';
+$fname3 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.2.phar.tar';
+$stub = '<?php echo "first stub\n"; __HALT_COMPILER(); ?>';
+$file = $stub;
+
+$files = array();
+$files['a'] = 'a';
+$files['b'] = 'b';
+$files['c'] = 'c';
+
+include 'files/phar_test.inc';
+
+$phar = new Phar($fname);
+var_dump($phar->isFileFormat(Phar::TAR));
+var_dump($phar->isCompressed());
+var_dump($phar->getStub());
+
+$phar = $phar->convertToExecutable(Phar::TAR, Phar::BZ2);
+var_dump($phar->isFileFormat(Phar::TAR));
+var_dump($phar->isCompressed());
+var_dump($phar->getStub());
+
+copy($fname2 . '.bz2', $fname3);
+
+$phar = new Phar($fname3);
+var_dump($phar->isFileFormat(Phar::TAR));
+var_dump($phar->isCompressed() == Phar::BZ2);
+var_dump($phar->getStub());
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar.bz2');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.2.phar.tar');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php');
+__HALT_COMPILER();
+?>
+--EXPECT--
+bool(false)
+bool(false)
+string(48) "<?php echo "first stub\n"; __HALT_COMPILER(); ?>"
+bool(true)
+int(8192)
+string(60) "<?php // tar-based phar archive stub file
+__HALT_COMPILER();"
+bool(true)
+bool(true)
+string(60) "<?php // tar-based phar archive stub file
+__HALT_COMPILER();"
+===DONE===
diff --git a/ext/phar/tests/phar_convert_zip.phpt b/ext/phar/tests/phar_convert_zip.phpt
new file mode 100644
index 0000000000..734551ee9c
--- /dev/null
+++ b/ext/phar/tests/phar_convert_zip.phpt
@@ -0,0 +1,56 @@
+--TEST--
+Phar::convertToZip()
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar';
+$pname = 'phar://' . $fname;
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.zip';
+$fname3 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.2.phar.zip';
+$stub = '<?php echo "first stub\n"; __HALT_COMPILER(); ?>';
+$file = $stub;
+
+$files = array();
+$files['a'] = 'a';
+$files['b'] = 'b';
+$files['c'] = 'c';
+
+include 'files/phar_test.inc';
+
+$phar = new Phar($fname);
+var_dump($phar->isFileFormat(Phar::ZIP));
+var_dump($phar->getStub());
+
+$phar = $phar->convertToExecutable(Phar::ZIP);
+var_dump($phar->isFileFormat(Phar::ZIP));
+var_dump($phar->getStub());
+
+copy($fname2, $fname3);
+
+$phar = new Phar($fname3);
+var_dump($phar->isFileFormat(Phar::ZIP));
+var_dump($phar->getStub());
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.zip');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.2.phar.zip');
+__HALT_COMPILER();
+?>
+--EXPECT--
+bool(false)
+string(48) "<?php echo "first stub\n"; __HALT_COMPILER(); ?>"
+bool(true)
+string(60) "<?php // zip-based phar archive stub file
+__HALT_COMPILER();"
+bool(true)
+string(60) "<?php // zip-based phar archive stub file
+__HALT_COMPILER();"
+===DONE===
diff --git a/ext/phar/tests/phar_copy.phpt b/ext/phar/tests/phar_copy.phpt
new file mode 100644
index 0000000000..0a43947bd1
--- /dev/null
+++ b/ext/phar/tests/phar_copy.phpt
@@ -0,0 +1,72 @@
+--TEST--
+Phar: copy()
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+<?php if (!extension_loaded("zlib")) die("skip zlib not available"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=1
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '2.phar.php';
+
+$pname = 'phar://'.$fname;
+$iname = '/file.txt';
+$ename = '/error/..';
+
+$p = new Phar($fname);
+
+try
+{
+ $p['a'] = 'hi';
+ $p->startBuffering();
+ $p->copy('a', 'b');
+ echo file_get_contents($p['b']->getPathName());
+ $p['a']->compress(Phar::GZ);
+ $p['b']->setMetadata('a');
+ $p->copy('b', 'c');
+ $p->stopBuffering();
+ echo file_get_contents($p['c']->getPathName());
+ copy($fname, $fname2);
+ $p->copy('a', $ename);
+}
+catch(Exception $e)
+{
+ echo $e->getMessage() . "\n";
+}
+ini_set('phar.readonly',1);
+$p2 = new Phar($fname2);
+echo "\n";
+echo 'a: ' , file_get_contents($p2['a']->getPathName());
+echo 'b: ' ,file_get_contents($p2['b']->getPathName());
+echo 'c: ' ,file_get_contents($p2['c']->getPathName()), $p2['c']->getMetaData(), "\n";
+ini_set('phar.readonly', 0);
+try {
+$p2->copy('notexisting', 'another');
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+try {
+$p2->copy('a', 'b');
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+$p2['a']->compress(Phar::GZ);
+$p2->copy('a', 'd');
+echo $p2['d']->getContent() . "\n";
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '2.phar.php'); ?>
+--EXPECTF--
+hihifile "/error/.." contains invalid characters upper directory reference, cannot be copied from "a" in phar %s
+
+a: hib: hic: hia
+file "notexisting" cannot be copied to file "another", file does not exist in %sphar_copy2.phar.php
+file "a" cannot be copied to file "b", file must not already exist in phar %sphar_copy2.phar.php
+hi
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/phar_create_in_cwd.phpt b/ext/phar/tests/phar_create_in_cwd.phpt
new file mode 100644
index 0000000000..83de7bed28
--- /dev/null
+++ b/ext/phar/tests/phar_create_in_cwd.phpt
@@ -0,0 +1,45 @@
+--TEST--
+Phar: attempt to create a Phar with relative path
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+chdir(dirname(__FILE__));
+try {
+ $p = new Phar('brandnewphar.phar');
+ $p['file1.txt'] = 'hi';
+ var_dump(strlen($p->getStub()));
+ $p->setStub("<?php
+function __autoload(\$class)
+{
+ include 'phar://' . str_replace('_', '/', \$class);
+}
+Phar::mapPhar('brandnewphar.phar');
+include 'phar://brandnewphar.phar/startup.php';
+__HALT_COMPILER();
+?>");
+ var_dump($p->getStub());
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/brandnewphar.phar');
+?>
+--EXPECT--
+int(6651)
+string(200) "<?php
+function __autoload($class)
+{
+ include 'phar://' . str_replace('_', '/', $class);
+}
+Phar::mapPhar('brandnewphar.phar');
+include 'phar://brandnewphar.phar/startup.php';
+__HALT_COMPILER(); ?>
+"
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/phar_createdefaultstub.phpt b/ext/phar/tests/phar_createdefaultstub.phpt
new file mode 100644
index 0000000000..a8648dc311
--- /dev/null
+++ b/ext/phar/tests/phar_createdefaultstub.phpt
@@ -0,0 +1,929 @@
+--TEST--
+Phar: Phar::createDefaultStub() with and without arg
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--FILE--
+<?php
+try {
+var_dump(Phar::createDefaultStub());
+echo "============================================================================\n";
+echo "============================================================================\n";
+var_dump(Phar::createDefaultStub('my/custom/thingy.php'));
+echo "============================================================================\n";
+echo "============================================================================\n";
+var_dump(strlen(Phar::createDefaultStub(str_repeat('a', 400))));
+echo "============================================================================\n";
+echo "============================================================================\n";
+var_dump(Phar::createDefaultStub(str_repeat('a', 401)));
+} catch(Exception $e) {
+echo $e->getMessage() . "\n";
+}
+echo "============================================================================\n";
+echo "============================================================================\n";
+echo "============================================================================\n";
+echo "============================================================================\n";
+try {
+var_dump(Phar::createDefaultStub('my/custom/thingy.php', 'the/web.php'));
+echo "============================================================================\n";
+echo "============================================================================\n";
+var_dump(strlen(Phar::createDefaultStub('index.php', str_repeat('a', 400))));
+var_dump(Phar::createDefaultStub('hio', str_repeat('a', 401)));
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--EXPECT--
+string(6651) "<?php
+
+$web = 'index.php';
+
+if (in_array('phar', stream_get_wrappers()) && class_exists('Phar', 0)) {
+Phar::interceptFileFuncs();
+set_include_path('phar://' . __FILE__ . PATH_SEPARATOR . get_include_path());
+Phar::webPhar(null, $web);
+include 'phar://' . __FILE__ . '/' . Extract_Phar::START;
+return;
+}
+
+if (@(isset($_SERVER['REQUEST_URI']) && isset($_SERVER['REQUEST_METHOD']) && ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'POST'))) {
+Extract_Phar::go(true);
+$mimes = array(
+'phps' => 2,
+'c' => 'text/plain',
+'cc' => 'text/plain',
+'cpp' => 'text/plain',
+'c++' => 'text/plain',
+'dtd' => 'text/plain',
+'h' => 'text/plain',
+'log' => 'text/plain',
+'rng' => 'text/plain',
+'txt' => 'text/plain',
+'xsd' => 'text/plain',
+'php' => 1,
+'inc' => 1,
+'avi' => 'video/avi',
+'bmp' => 'image/bmp',
+'css' => 'text/css',
+'gif' => 'image/gif',
+'htm' => 'text/html',
+'html' => 'text/html',
+'htmls' => 'text/html',
+'ico' => 'image/x-ico',
+'jpe' => 'image/jpeg',
+'jpg' => 'image/jpeg',
+'jpeg' => 'image/jpeg',
+'js' => 'application/x-javascript',
+'midi' => 'audio/midi',
+'mid' => 'audio/midi',
+'mod' => 'audio/mod',
+'mov' => 'movie/quicktime',
+'mp3' => 'audio/mp3',
+'mpg' => 'video/mpeg',
+'mpeg' => 'video/mpeg',
+'pdf' => 'application/pdf',
+'png' => 'image/png',
+'swf' => 'application/shockwave-flash',
+'tif' => 'image/tiff',
+'tiff' => 'image/tiff',
+'wav' => 'audio/wav',
+'xbm' => 'image/xbm',
+'xml' => 'text/xml',
+);
+
+header("Cache-Control: no-cache, must-revalidate");
+header("Pragma: no-cache");
+
+$basename = basename(__FILE__);
+if (!strpos($_SERVER['REQUEST_URI'], $basename)) {
+chdir(Extract_Phar::$temp);
+include $web;
+return;
+}
+$pt = substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], $basename) + strlen($basename));
+if (!$pt || $pt == '/') {
+$pt = $web;
+header('HTTP/1.1 301 Moved Permanently');
+header('Location: ' . $_SERVER['REQUEST_URI'] . '/' . $pt);
+exit;
+}
+$a = realpath(Extract_Phar::$temp . DIRECTORY_SEPARATOR . $pt);
+if (!$a || strlen(dirname($a)) < strlen(Extract_Phar::$temp)) {
+header('HTTP/1.0 404 Not Found');
+echo "<html>\n <head>\n <title>File Not Found<title>\n </head>\n <body>\n <h1>404 - File ", $pt, " Not Found</h1>\n </body>\n</html>";
+exit;
+}
+$b = pathinfo($a);
+if (!isset($b['extension'])) {
+header('Content-Type: text/plain');
+header('Content-Length: ' . filesize($a));
+readfile($a);
+exit;
+}
+if (isset($mimes[$b['extension']])) {
+if ($mimes[$b['extension']] === 1) {
+include $a;
+exit;
+}
+if ($mimes[$b['extension']] === 2) {
+highlight_file($a);
+exit;
+}
+header('Content-Type: ' .$mimes[$b['extension']]);
+header('Content-Length: ' . filesize($a));
+readfile($a);
+exit;
+}
+}
+
+class Extract_Phar
+{
+static $temp;
+static $origdir;
+const GZ = 0x1000;
+const BZ2 = 0x2000;
+const MASK = 0x3000;
+const START = 'index.php';
+const LEN = 6653;
+
+static function go($return = false)
+{
+$fp = fopen(__FILE__, 'rb');
+fseek($fp, self::LEN);
+$L = unpack('V', $a = fread($fp, 4));
+$m = '';
+
+do {
+$read = 8192;
+if ($L[1] - strlen($m) < 8192) {
+$read = $L[1] - strlen($m);
+}
+$last = fread($fp, $read);
+$m .= $last;
+} while (strlen($last) && strlen($m) < $L[1]);
+
+if (strlen($m) < $L[1]) {
+die('ERROR: manifest length read was "' .
+strlen($m) .'" should be "' .
+$L[1] . '"');
+}
+
+$info = self::_unpack($m);
+$f = $info['c'];
+
+if ($f & self::GZ) {
+if (!function_exists('gzinflate')) {
+die('Error: zlib extension is not enabled -' .
+' gzinflate() function needed for zlib-compressed .phars');
+}
+}
+
+if ($f & self::BZ2) {
+if (!function_exists('bzdecompress')) {
+die('Error: bzip2 extension is not enabled -' .
+' bzdecompress() function needed for bz2-compressed .phars');
+}
+}
+
+$temp = self::tmpdir();
+
+if (!$temp || !is_writable($temp)) {
+$sessionpath = session_save_path();
+if (strpos ($sessionpath, ";") !== false)
+$sessionpath = substr ($sessionpath, strpos ($sessionpath, ";")+1);
+if (!file_exists($sessionpath) || !is_dir($sessionpath)) {
+die('Could not locate temporary directory to extract phar');
+}
+$temp = $sessionpath;
+}
+
+$temp .= '/pharextract/'.basename(__FILE__, '.phar');
+self::$temp = $temp;
+self::$origdir = getcwd();
+@mkdir($temp, 0777, true);
+$temp = realpath($temp);
+
+if (!file_exists($temp . DIRECTORY_SEPARATOR . md5_file(__FILE__))) {
+self::_removeTmpFiles($temp, getcwd());
+@mkdir($temp, 0777, true);
+@file_put_contents($temp . '/' . md5_file(__FILE__), '');
+
+foreach ($info['m'] as $path => $file) {
+$a = !file_exists(dirname($temp . '/' . $path));
+@mkdir(dirname($temp . '/' . $path), 0777, true);
+clearstatcache();
+
+if ($path[strlen($path) - 1] == '/') {
+@mkdir($temp . '/' . $path, 0777);
+} else {
+file_put_contents($temp . '/' . $path, self::extractFile($path, $file, $fp));
+@chmod($temp . '/' . $path, 0666);
+}
+}
+}
+
+chdir($temp);
+
+if (!$return) {
+include self::START;
+}
+}
+
+static function tmpdir()
+{
+if (strpos(PHP_OS, 'WIN') !== false) {
+if ($var = getenv('TMP') ? getenv('TMP') : getenv('TEMP')) {
+return $var;
+}
+if (is_dir('/temp') || mkdir('/temp')) {
+return realpath('/temp');
+}
+return false;
+}
+if ($var = getenv('TMPDIR')) {
+return $var;
+}
+return realpath('/tmp');
+}
+
+static function _unpack($m)
+{
+$info = unpack('V', substr($m, 0, 4));
+ $l = unpack('V', substr($m, 10, 4));
+$m = substr($m, 14 + $l[1]);
+$s = unpack('V', substr($m, 0, 4));
+$o = 0;
+$start = 4 + $s[1];
+$ret['c'] = 0;
+
+for ($i = 0; $i < $info[1]; $i++) {
+ $len = unpack('V', substr($m, $start, 4));
+$start += 4;
+ $savepath = substr($m, $start, $len[1]);
+$start += $len[1];
+ $ret['m'][$savepath] = array_values(unpack('Va/Vb/Vc/Vd/Ve/Vf', substr($m, $start, 24)));
+$ret['m'][$savepath][3] = sprintf('%u', $ret['m'][$savepath][3]
+& 0xffffffff);
+$ret['m'][$savepath][7] = $o;
+$o += $ret['m'][$savepath][2];
+$start += 24 + $ret['m'][$savepath][5];
+$ret['c'] |= $ret['m'][$savepath][4] & self::MASK;
+}
+return $ret;
+}
+
+static function extractFile($path, $entry, $fp)
+{
+$data = '';
+$c = $entry[2];
+
+while ($c) {
+if ($c < 8192) {
+$data .= @fread($fp, $c);
+$c = 0;
+} else {
+$c -= 8192;
+$data .= @fread($fp, 8192);
+}
+}
+
+if ($entry[4] & self::GZ) {
+$data = gzinflate($data);
+} elseif ($entry[4] & self::BZ2) {
+$data = bzdecompress($data);
+}
+
+if (strlen($data) != $entry[0]) {
+die("Invalid internal .phar file (size error " . strlen($data) . " != " .
+$stat[7] . ")");
+}
+
+if ($entry[3] != sprintf("%u", crc32($data) & 0xffffffff)) {
+die("Invalid internal .phar file (checksum error)");
+}
+
+return $data;
+}
+
+static function _removeTmpFiles($temp, $origdir)
+{
+chdir($temp);
+
+foreach (glob('*') as $f) {
+if (file_exists($f)) {
+is_dir($f) ? @rmdir($f) : @unlink($f);
+if (file_exists($f) && is_dir($f)) {
+self::_removeTmpFiles($f, getcwd());
+}
+}
+}
+
+@rmdir($temp);
+clearstatcache();
+chdir($origdir);
+}
+}
+
+Extract_Phar::go();
+__HALT_COMPILER(); ?>"
+============================================================================
+============================================================================
+string(6662) "<?php
+
+$web = 'index.php';
+
+if (in_array('phar', stream_get_wrappers()) && class_exists('Phar', 0)) {
+Phar::interceptFileFuncs();
+set_include_path('phar://' . __FILE__ . PATH_SEPARATOR . get_include_path());
+Phar::webPhar(null, $web);
+include 'phar://' . __FILE__ . '/' . Extract_Phar::START;
+return;
+}
+
+if (@(isset($_SERVER['REQUEST_URI']) && isset($_SERVER['REQUEST_METHOD']) && ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'POST'))) {
+Extract_Phar::go(true);
+$mimes = array(
+'phps' => 2,
+'c' => 'text/plain',
+'cc' => 'text/plain',
+'cpp' => 'text/plain',
+'c++' => 'text/plain',
+'dtd' => 'text/plain',
+'h' => 'text/plain',
+'log' => 'text/plain',
+'rng' => 'text/plain',
+'txt' => 'text/plain',
+'xsd' => 'text/plain',
+'php' => 1,
+'inc' => 1,
+'avi' => 'video/avi',
+'bmp' => 'image/bmp',
+'css' => 'text/css',
+'gif' => 'image/gif',
+'htm' => 'text/html',
+'html' => 'text/html',
+'htmls' => 'text/html',
+'ico' => 'image/x-ico',
+'jpe' => 'image/jpeg',
+'jpg' => 'image/jpeg',
+'jpeg' => 'image/jpeg',
+'js' => 'application/x-javascript',
+'midi' => 'audio/midi',
+'mid' => 'audio/midi',
+'mod' => 'audio/mod',
+'mov' => 'movie/quicktime',
+'mp3' => 'audio/mp3',
+'mpg' => 'video/mpeg',
+'mpeg' => 'video/mpeg',
+'pdf' => 'application/pdf',
+'png' => 'image/png',
+'swf' => 'application/shockwave-flash',
+'tif' => 'image/tiff',
+'tiff' => 'image/tiff',
+'wav' => 'audio/wav',
+'xbm' => 'image/xbm',
+'xml' => 'text/xml',
+);
+
+header("Cache-Control: no-cache, must-revalidate");
+header("Pragma: no-cache");
+
+$basename = basename(__FILE__);
+if (!strpos($_SERVER['REQUEST_URI'], $basename)) {
+chdir(Extract_Phar::$temp);
+include $web;
+return;
+}
+$pt = substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], $basename) + strlen($basename));
+if (!$pt || $pt == '/') {
+$pt = $web;
+header('HTTP/1.1 301 Moved Permanently');
+header('Location: ' . $_SERVER['REQUEST_URI'] . '/' . $pt);
+exit;
+}
+$a = realpath(Extract_Phar::$temp . DIRECTORY_SEPARATOR . $pt);
+if (!$a || strlen(dirname($a)) < strlen(Extract_Phar::$temp)) {
+header('HTTP/1.0 404 Not Found');
+echo "<html>\n <head>\n <title>File Not Found<title>\n </head>\n <body>\n <h1>404 - File ", $pt, " Not Found</h1>\n </body>\n</html>";
+exit;
+}
+$b = pathinfo($a);
+if (!isset($b['extension'])) {
+header('Content-Type: text/plain');
+header('Content-Length: ' . filesize($a));
+readfile($a);
+exit;
+}
+if (isset($mimes[$b['extension']])) {
+if ($mimes[$b['extension']] === 1) {
+include $a;
+exit;
+}
+if ($mimes[$b['extension']] === 2) {
+highlight_file($a);
+exit;
+}
+header('Content-Type: ' .$mimes[$b['extension']]);
+header('Content-Length: ' . filesize($a));
+readfile($a);
+exit;
+}
+}
+
+class Extract_Phar
+{
+static $temp;
+static $origdir;
+const GZ = 0x1000;
+const BZ2 = 0x2000;
+const MASK = 0x3000;
+const START = 'my/custom/thingy.php';
+const LEN = 6664;
+
+static function go($return = false)
+{
+$fp = fopen(__FILE__, 'rb');
+fseek($fp, self::LEN);
+$L = unpack('V', $a = fread($fp, 4));
+$m = '';
+
+do {
+$read = 8192;
+if ($L[1] - strlen($m) < 8192) {
+$read = $L[1] - strlen($m);
+}
+$last = fread($fp, $read);
+$m .= $last;
+} while (strlen($last) && strlen($m) < $L[1]);
+
+if (strlen($m) < $L[1]) {
+die('ERROR: manifest length read was "' .
+strlen($m) .'" should be "' .
+$L[1] . '"');
+}
+
+$info = self::_unpack($m);
+$f = $info['c'];
+
+if ($f & self::GZ) {
+if (!function_exists('gzinflate')) {
+die('Error: zlib extension is not enabled -' .
+' gzinflate() function needed for zlib-compressed .phars');
+}
+}
+
+if ($f & self::BZ2) {
+if (!function_exists('bzdecompress')) {
+die('Error: bzip2 extension is not enabled -' .
+' bzdecompress() function needed for bz2-compressed .phars');
+}
+}
+
+$temp = self::tmpdir();
+
+if (!$temp || !is_writable($temp)) {
+$sessionpath = session_save_path();
+if (strpos ($sessionpath, ";") !== false)
+$sessionpath = substr ($sessionpath, strpos ($sessionpath, ";")+1);
+if (!file_exists($sessionpath) || !is_dir($sessionpath)) {
+die('Could not locate temporary directory to extract phar');
+}
+$temp = $sessionpath;
+}
+
+$temp .= '/pharextract/'.basename(__FILE__, '.phar');
+self::$temp = $temp;
+self::$origdir = getcwd();
+@mkdir($temp, 0777, true);
+$temp = realpath($temp);
+
+if (!file_exists($temp . DIRECTORY_SEPARATOR . md5_file(__FILE__))) {
+self::_removeTmpFiles($temp, getcwd());
+@mkdir($temp, 0777, true);
+@file_put_contents($temp . '/' . md5_file(__FILE__), '');
+
+foreach ($info['m'] as $path => $file) {
+$a = !file_exists(dirname($temp . '/' . $path));
+@mkdir(dirname($temp . '/' . $path), 0777, true);
+clearstatcache();
+
+if ($path[strlen($path) - 1] == '/') {
+@mkdir($temp . '/' . $path, 0777);
+} else {
+file_put_contents($temp . '/' . $path, self::extractFile($path, $file, $fp));
+@chmod($temp . '/' . $path, 0666);
+}
+}
+}
+
+chdir($temp);
+
+if (!$return) {
+include self::START;
+}
+}
+
+static function tmpdir()
+{
+if (strpos(PHP_OS, 'WIN') !== false) {
+if ($var = getenv('TMP') ? getenv('TMP') : getenv('TEMP')) {
+return $var;
+}
+if (is_dir('/temp') || mkdir('/temp')) {
+return realpath('/temp');
+}
+return false;
+}
+if ($var = getenv('TMPDIR')) {
+return $var;
+}
+return realpath('/tmp');
+}
+
+static function _unpack($m)
+{
+$info = unpack('V', substr($m, 0, 4));
+ $l = unpack('V', substr($m, 10, 4));
+$m = substr($m, 14 + $l[1]);
+$s = unpack('V', substr($m, 0, 4));
+$o = 0;
+$start = 4 + $s[1];
+$ret['c'] = 0;
+
+for ($i = 0; $i < $info[1]; $i++) {
+ $len = unpack('V', substr($m, $start, 4));
+$start += 4;
+ $savepath = substr($m, $start, $len[1]);
+$start += $len[1];
+ $ret['m'][$savepath] = array_values(unpack('Va/Vb/Vc/Vd/Ve/Vf', substr($m, $start, 24)));
+$ret['m'][$savepath][3] = sprintf('%u', $ret['m'][$savepath][3]
+& 0xffffffff);
+$ret['m'][$savepath][7] = $o;
+$o += $ret['m'][$savepath][2];
+$start += 24 + $ret['m'][$savepath][5];
+$ret['c'] |= $ret['m'][$savepath][4] & self::MASK;
+}
+return $ret;
+}
+
+static function extractFile($path, $entry, $fp)
+{
+$data = '';
+$c = $entry[2];
+
+while ($c) {
+if ($c < 8192) {
+$data .= @fread($fp, $c);
+$c = 0;
+} else {
+$c -= 8192;
+$data .= @fread($fp, 8192);
+}
+}
+
+if ($entry[4] & self::GZ) {
+$data = gzinflate($data);
+} elseif ($entry[4] & self::BZ2) {
+$data = bzdecompress($data);
+}
+
+if (strlen($data) != $entry[0]) {
+die("Invalid internal .phar file (size error " . strlen($data) . " != " .
+$stat[7] . ")");
+}
+
+if ($entry[3] != sprintf("%u", crc32($data) & 0xffffffff)) {
+die("Invalid internal .phar file (checksum error)");
+}
+
+return $data;
+}
+
+static function _removeTmpFiles($temp, $origdir)
+{
+chdir($temp);
+
+foreach (glob('*') as $f) {
+if (file_exists($f)) {
+is_dir($f) ? @rmdir($f) : @unlink($f);
+if (file_exists($f) && is_dir($f)) {
+self::_removeTmpFiles($f, getcwd());
+}
+}
+}
+
+@rmdir($temp);
+clearstatcache();
+chdir($origdir);
+}
+}
+
+Extract_Phar::go();
+__HALT_COMPILER(); ?>"
+============================================================================
+============================================================================
+int(7042)
+============================================================================
+============================================================================
+Illegal filename passed in for stub creation, was 401 characters long, and only 400 or less is allowed
+============================================================================
+============================================================================
+============================================================================
+============================================================================
+string(6664) "<?php
+
+$web = 'the/web.php';
+
+if (in_array('phar', stream_get_wrappers()) && class_exists('Phar', 0)) {
+Phar::interceptFileFuncs();
+set_include_path('phar://' . __FILE__ . PATH_SEPARATOR . get_include_path());
+Phar::webPhar(null, $web);
+include 'phar://' . __FILE__ . '/' . Extract_Phar::START;
+return;
+}
+
+if (@(isset($_SERVER['REQUEST_URI']) && isset($_SERVER['REQUEST_METHOD']) && ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'POST'))) {
+Extract_Phar::go(true);
+$mimes = array(
+'phps' => 2,
+'c' => 'text/plain',
+'cc' => 'text/plain',
+'cpp' => 'text/plain',
+'c++' => 'text/plain',
+'dtd' => 'text/plain',
+'h' => 'text/plain',
+'log' => 'text/plain',
+'rng' => 'text/plain',
+'txt' => 'text/plain',
+'xsd' => 'text/plain',
+'php' => 1,
+'inc' => 1,
+'avi' => 'video/avi',
+'bmp' => 'image/bmp',
+'css' => 'text/css',
+'gif' => 'image/gif',
+'htm' => 'text/html',
+'html' => 'text/html',
+'htmls' => 'text/html',
+'ico' => 'image/x-ico',
+'jpe' => 'image/jpeg',
+'jpg' => 'image/jpeg',
+'jpeg' => 'image/jpeg',
+'js' => 'application/x-javascript',
+'midi' => 'audio/midi',
+'mid' => 'audio/midi',
+'mod' => 'audio/mod',
+'mov' => 'movie/quicktime',
+'mp3' => 'audio/mp3',
+'mpg' => 'video/mpeg',
+'mpeg' => 'video/mpeg',
+'pdf' => 'application/pdf',
+'png' => 'image/png',
+'swf' => 'application/shockwave-flash',
+'tif' => 'image/tiff',
+'tiff' => 'image/tiff',
+'wav' => 'audio/wav',
+'xbm' => 'image/xbm',
+'xml' => 'text/xml',
+);
+
+header("Cache-Control: no-cache, must-revalidate");
+header("Pragma: no-cache");
+
+$basename = basename(__FILE__);
+if (!strpos($_SERVER['REQUEST_URI'], $basename)) {
+chdir(Extract_Phar::$temp);
+include $web;
+return;
+}
+$pt = substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], $basename) + strlen($basename));
+if (!$pt || $pt == '/') {
+$pt = $web;
+header('HTTP/1.1 301 Moved Permanently');
+header('Location: ' . $_SERVER['REQUEST_URI'] . '/' . $pt);
+exit;
+}
+$a = realpath(Extract_Phar::$temp . DIRECTORY_SEPARATOR . $pt);
+if (!$a || strlen(dirname($a)) < strlen(Extract_Phar::$temp)) {
+header('HTTP/1.0 404 Not Found');
+echo "<html>\n <head>\n <title>File Not Found<title>\n </head>\n <body>\n <h1>404 - File ", $pt, " Not Found</h1>\n </body>\n</html>";
+exit;
+}
+$b = pathinfo($a);
+if (!isset($b['extension'])) {
+header('Content-Type: text/plain');
+header('Content-Length: ' . filesize($a));
+readfile($a);
+exit;
+}
+if (isset($mimes[$b['extension']])) {
+if ($mimes[$b['extension']] === 1) {
+include $a;
+exit;
+}
+if ($mimes[$b['extension']] === 2) {
+highlight_file($a);
+exit;
+}
+header('Content-Type: ' .$mimes[$b['extension']]);
+header('Content-Length: ' . filesize($a));
+readfile($a);
+exit;
+}
+}
+
+class Extract_Phar
+{
+static $temp;
+static $origdir;
+const GZ = 0x1000;
+const BZ2 = 0x2000;
+const MASK = 0x3000;
+const START = 'my/custom/thingy.php';
+const LEN = 6666;
+
+static function go($return = false)
+{
+$fp = fopen(__FILE__, 'rb');
+fseek($fp, self::LEN);
+$L = unpack('V', $a = fread($fp, 4));
+$m = '';
+
+do {
+$read = 8192;
+if ($L[1] - strlen($m) < 8192) {
+$read = $L[1] - strlen($m);
+}
+$last = fread($fp, $read);
+$m .= $last;
+} while (strlen($last) && strlen($m) < $L[1]);
+
+if (strlen($m) < $L[1]) {
+die('ERROR: manifest length read was "' .
+strlen($m) .'" should be "' .
+$L[1] . '"');
+}
+
+$info = self::_unpack($m);
+$f = $info['c'];
+
+if ($f & self::GZ) {
+if (!function_exists('gzinflate')) {
+die('Error: zlib extension is not enabled -' .
+' gzinflate() function needed for zlib-compressed .phars');
+}
+}
+
+if ($f & self::BZ2) {
+if (!function_exists('bzdecompress')) {
+die('Error: bzip2 extension is not enabled -' .
+' bzdecompress() function needed for bz2-compressed .phars');
+}
+}
+
+$temp = self::tmpdir();
+
+if (!$temp || !is_writable($temp)) {
+$sessionpath = session_save_path();
+if (strpos ($sessionpath, ";") !== false)
+$sessionpath = substr ($sessionpath, strpos ($sessionpath, ";")+1);
+if (!file_exists($sessionpath) || !is_dir($sessionpath)) {
+die('Could not locate temporary directory to extract phar');
+}
+$temp = $sessionpath;
+}
+
+$temp .= '/pharextract/'.basename(__FILE__, '.phar');
+self::$temp = $temp;
+self::$origdir = getcwd();
+@mkdir($temp, 0777, true);
+$temp = realpath($temp);
+
+if (!file_exists($temp . DIRECTORY_SEPARATOR . md5_file(__FILE__))) {
+self::_removeTmpFiles($temp, getcwd());
+@mkdir($temp, 0777, true);
+@file_put_contents($temp . '/' . md5_file(__FILE__), '');
+
+foreach ($info['m'] as $path => $file) {
+$a = !file_exists(dirname($temp . '/' . $path));
+@mkdir(dirname($temp . '/' . $path), 0777, true);
+clearstatcache();
+
+if ($path[strlen($path) - 1] == '/') {
+@mkdir($temp . '/' . $path, 0777);
+} else {
+file_put_contents($temp . '/' . $path, self::extractFile($path, $file, $fp));
+@chmod($temp . '/' . $path, 0666);
+}
+}
+}
+
+chdir($temp);
+
+if (!$return) {
+include self::START;
+}
+}
+
+static function tmpdir()
+{
+if (strpos(PHP_OS, 'WIN') !== false) {
+if ($var = getenv('TMP') ? getenv('TMP') : getenv('TEMP')) {
+return $var;
+}
+if (is_dir('/temp') || mkdir('/temp')) {
+return realpath('/temp');
+}
+return false;
+}
+if ($var = getenv('TMPDIR')) {
+return $var;
+}
+return realpath('/tmp');
+}
+
+static function _unpack($m)
+{
+$info = unpack('V', substr($m, 0, 4));
+ $l = unpack('V', substr($m, 10, 4));
+$m = substr($m, 14 + $l[1]);
+$s = unpack('V', substr($m, 0, 4));
+$o = 0;
+$start = 4 + $s[1];
+$ret['c'] = 0;
+
+for ($i = 0; $i < $info[1]; $i++) {
+ $len = unpack('V', substr($m, $start, 4));
+$start += 4;
+ $savepath = substr($m, $start, $len[1]);
+$start += $len[1];
+ $ret['m'][$savepath] = array_values(unpack('Va/Vb/Vc/Vd/Ve/Vf', substr($m, $start, 24)));
+$ret['m'][$savepath][3] = sprintf('%u', $ret['m'][$savepath][3]
+& 0xffffffff);
+$ret['m'][$savepath][7] = $o;
+$o += $ret['m'][$savepath][2];
+$start += 24 + $ret['m'][$savepath][5];
+$ret['c'] |= $ret['m'][$savepath][4] & self::MASK;
+}
+return $ret;
+}
+
+static function extractFile($path, $entry, $fp)
+{
+$data = '';
+$c = $entry[2];
+
+while ($c) {
+if ($c < 8192) {
+$data .= @fread($fp, $c);
+$c = 0;
+} else {
+$c -= 8192;
+$data .= @fread($fp, 8192);
+}
+}
+
+if ($entry[4] & self::GZ) {
+$data = gzinflate($data);
+} elseif ($entry[4] & self::BZ2) {
+$data = bzdecompress($data);
+}
+
+if (strlen($data) != $entry[0]) {
+die("Invalid internal .phar file (size error " . strlen($data) . " != " .
+$stat[7] . ")");
+}
+
+if ($entry[3] != sprintf("%u", crc32($data) & 0xffffffff)) {
+die("Invalid internal .phar file (checksum error)");
+}
+
+return $data;
+}
+
+static function _removeTmpFiles($temp, $origdir)
+{
+chdir($temp);
+
+foreach (glob('*') as $f) {
+if (file_exists($f)) {
+is_dir($f) ? @rmdir($f) : @unlink($f);
+if (file_exists($f) && is_dir($f)) {
+self::_removeTmpFiles($f, getcwd());
+}
+}
+}
+
+@rmdir($temp);
+clearstatcache();
+chdir($origdir);
+}
+}
+
+Extract_Phar::go();
+__HALT_COMPILER(); ?>"
+============================================================================
+============================================================================
+int(7042)
+Illegal web filename passed in for stub creation, was 401 characters long, and only 400 or less is allowed
+===DONE===
diff --git a/ext/phar/tests/phar_ctx_001.phpt b/ext/phar/tests/phar_ctx_001.phpt
new file mode 100644
index 0000000000..13b4d6a781
--- /dev/null
+++ b/ext/phar/tests/phar_ctx_001.phpt
@@ -0,0 +1,100 @@
+--TEST--
+Phar context
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("zlib")) die("skip zlib not present"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = '<?php __HALT_COMPILER(); ?>';
+
+$files = array();
+$files['a'] = 'a';
+$files['b'] = 'b';
+$files['c'] = 'c';
+
+include 'files/phar_test.inc';
+
+$phar = new Phar($fname);
+
+var_dump(file_get_contents($pname . '/a'));
+var_dump($phar['a']->isCompressed());
+var_dump(file_get_contents($pname . '/b'));
+var_dump($phar['b']->isCompressed());
+var_dump(file_get_contents($pname . '/c'));
+var_dump($phar['c']->isCompressed());
+
+$context = stream_context_create(array('phar'=> array('compress'=>Phar::GZ, 'metadata' => array(2, 'hi' => 3))));
+$context2 = stream_context_create(array('phar' => array('metadata' => array(4))));
+
+file_put_contents($pname . '/a', 'new a', 0); // no compression
+file_put_contents($pname . '/b', 'new b', 0, $context);
+file_put_contents($pname . '/d', 'new d', 0, $context2);
+
+$phar = new Phar($fname);
+var_dump(file_get_contents($pname . '/a'));
+var_dump($phar['a']->isCompressed());
+var_dump($phar['a']->getMetaData());
+var_dump(file_get_contents($pname . '/b'));
+var_dump($phar['b']->isCompressed());
+var_dump($phar['b']->getMetaData());
+var_dump(file_get_contents($pname . '/c'));
+var_dump($phar['c']->isCompressed());
+var_dump($phar['c']->getMetaData());
+var_dump(file_get_contents($pname . '/d'));
+var_dump($phar['d']->isCompressed());
+var_dump($phar['d']->getMetaData());
+$context2 = stream_context_create(array('phar' => array('metadata' => array(4))));
+$fp = fopen($pname . '/b', 'r+', 0, $context2);
+fclose($fp);
+?>
+==AFTER==
+<?php
+var_dump(file_get_contents($pname . '/b'));
+var_dump($phar['b']->isCompressed());
+var_dump($phar['b']->getMetaData());
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php');
+?>
+--EXPECT--
+string(1) "a"
+bool(false)
+string(1) "b"
+bool(false)
+string(1) "c"
+bool(false)
+string(5) "new a"
+bool(false)
+NULL
+string(5) "new b"
+bool(true)
+array(2) {
+ [0]=>
+ int(2)
+ ["hi"]=>
+ int(3)
+}
+string(1) "c"
+bool(false)
+NULL
+string(5) "new d"
+bool(false)
+array(1) {
+ [0]=>
+ int(4)
+}
+==AFTER==
+string(5) "new b"
+bool(true)
+array(1) {
+ [0]=>
+ int(4)
+}
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/phar_decompress.phpt b/ext/phar/tests/phar_decompress.phpt
new file mode 100644
index 0000000000..ae199eb03b
--- /dev/null
+++ b/ext/phar/tests/phar_decompress.phpt
@@ -0,0 +1,69 @@
+--TEST--
+Phar::decompress()
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("zlib")) die("skip zlib not present"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '2.phar.gz';
+$pname = 'phar://' . $fname;
+$file = '<?php __HALT_COMPILER(); ?>';
+
+$files = array();
+$files['a'] = 'a';
+$files['b'] = 'b';
+$files['c'] = 'c';
+
+include 'files/phar_test.inc';
+
+$phar = new Phar($fname);
+
+$gz = $phar->compress(Phar::GZ);
+copy($gz->getPath(), $fname2);
+$a = new Phar($fname2);
+var_dump($a->isCompressed());
+$unc = $a->compress(Phar::NONE);
+echo $unc->getPath() . "\n";
+$unc2 = $gz->decompress();
+echo $unc2->getPath() . "\n";
+$unc3 = $gz->decompress('hooba.phar');
+echo $unc3->getPath() . "\n";
+$gz->decompress(array());
+$zip = $phar->convertToData(Phar::ZIP);
+ini_set('phar.readonly', 1);
+try {
+$gz->decompress();
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+try {
+$zip->decompress();
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.zip');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.hooba.phar');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.gz');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '2.phar.gz');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '2.phar');
+?>
+--EXPECTF--
+int(4096)
+%sphar_decompress2.phar
+%sphar_decompress.phar
+%sphar_decompress.hooba.phar
+
+Warning: Phar::decompress() expects parameter 1 to be string, array given in %sphar_decompress.php on line %d
+Cannot decompress phar archive, phar is read-only
+Cannot decompress zip-based archives with whole-archive compression
+===DONE===
diff --git a/ext/phar/tests/phar_dir_iterate.phpt b/ext/phar/tests/phar_dir_iterate.phpt
new file mode 100644
index 0000000000..2ee2cb5529
--- /dev/null
+++ b/ext/phar/tests/phar_dir_iterate.phpt
@@ -0,0 +1,32 @@
+--TEST--
+Phar object: iterate test with sub-directories and RecursiveIteratorIterator
+--SKIPIF--
+<?php if (!extension_loaded('phar')) die('skip'); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+
+$phar = new Phar($fname);
+$phar['top.txt'] = 'hi';
+$phar['sub/top.txt'] = 'there';
+$phar['another.file.txt'] = 'wowee';
+$newphar = new Phar($fname);
+foreach (new RecursiveIteratorIterator($newphar) as $path => $obj) {
+ var_dump($obj->getPathName());
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php');
+__halt_compiler();
+?>
+--EXPECTF--
+string(%d) "phar://%sphar_dir_iterate.phar.php%canother.file.txt"
+string(%d) "phar://%sphar_dir_iterate.phar.php%csub%ctop.txt"
+string(%d) "phar://%sphar_dir_iterate.phar.php%ctop.txt"
+===DONE===
diff --git a/ext/phar/tests/phar_extract.phpt b/ext/phar/tests/phar_extract.phpt
new file mode 100644
index 0000000000..82e5f8d191
--- /dev/null
+++ b/ext/phar/tests/phar_extract.phpt
@@ -0,0 +1,131 @@
+--TEST--
+Phar: Phar::extractTo()
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/tempmanifest1.phar.php';
+$pname = 'phar://' . $fname;
+
+$a = new Phar($fname);
+$a['file1.txt'] = 'hi';
+$a['file2.txt'] = 'hi2';
+$a['subdir/ectory/file.txt'] = 'hi3';
+$a->mount($pname . '/mount', __FILE__);
+$a->addEmptyDir('one/level');
+
+$a->extractTo(dirname(__FILE__) . '/extract', 'mount');
+$a->extractTo(dirname(__FILE__) . '/extract');
+$out = array();
+foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator(dirname(__FILE__) . '/extract'), RecursiveIteratorIterator::CHILD_FIRST) as $p => $b) {
+ $out[] = $p;
+}
+sort($out);
+foreach ($out as $b) {
+echo "$b\n";
+}
+
+$a->extractTo(dirname(__FILE__) . '/extract1', 'file1.txt');
+var_dump(file_get_contents(dirname(__FILE__) . '/extract1/file1.txt'));
+$a->extractTo(dirname(__FILE__) . '/extract1', 'subdir/ectory/file.txt');
+var_dump(file_get_contents(dirname(__FILE__) . '/extract1/subdir/ectory/file.txt'));
+
+$a->extractTo(dirname(__FILE__) . '/extract2', array('file2.txt', 'one/level'));
+var_dump(file_get_contents(dirname(__FILE__) . '/extract2/file2.txt'));
+var_dump(is_dir(dirname(__FILE__) . '/extract2/one/level'));
+try {
+$a->extractTo(dirname(__FILE__) . '/whatever', 134);
+} catch (Exception $e) {
+echo $e->getMessage(), "\n";
+}
+$a->extractTo(array());
+try {
+$a->extractTo('');
+} catch (Exception $e) {
+echo $e->getMessage(), "\n";
+}
+file_put_contents(dirname(__FILE__) . '/oops', 'I is file');
+try {
+$a->extractTo(dirname(__FILE__) . '/oops', 'file1.txt');
+} catch (Exception $e) {
+echo $e->getMessage(), "\n";
+}
+try {
+$a->extractTo(dirname(__FILE__) . '/oops1', array(array(), 'file1.txt'));
+} catch (Exception $e) {
+echo $e->getMessage(), "\n";
+}
+try {
+$a->extractTo(dirname(__FILE__) . '/extract', 'file1.txt');
+} catch (Exception $e) {
+echo $e->getMessage(), "\n";
+}
+file_put_contents(dirname(__FILE__) . '/extract/file1.txt', 'first');
+var_dump(file_get_contents(dirname(__FILE__) . '/extract/file1.txt'));
+$a->extractTo(dirname(__FILE__) . '/extract', 'file1.txt', true);
+var_dump(file_get_contents(dirname(__FILE__) . '/extract/file1.txt'));
+try {
+$a->extractTo(str_repeat('a', 20000), 'file1.txt');
+} catch (Exception $e) {
+echo $e->getMessage(), "\n";
+}
+$a[str_repeat('a', 20000)] = 'long';
+try {
+$a->extractTo(dirname(__FILE__) . '/extract', str_repeat('a', 20000));
+} catch (Exception $e) {
+echo $e->getMessage(), "\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+@rmdir(dirname(__FILE__) . '/whatever');
+@unlink(dirname(__FILE__) . '/oops');
+@rmdir(dirname(__FILE__) . '/oops1');
+@unlink(dirname(__FILE__) . '/tempmanifest1.phar.php');
+$e = dirname(__FILE__) . '/extract/';
+@unlink($e . 'file1.txt');
+@unlink($e . 'file2.txt');
+@unlink($e . 'subdir/ectory/file.txt');
+@rmdir($e . 'subdir/ectory');
+@rmdir($e . 'subdir');
+@rmdir($e . 'one/level');
+@rmdir($e . 'one');
+@rmdir($e);
+$e = dirname(__FILE__) . '/extract1/';
+@unlink($e . 'file1.txt');
+@unlink($e . 'subdir/ectory/file.txt');
+@rmdir($e . 'subdir/ectory');
+@rmdir($e . 'subdir');
+@rmdir($e);
+$e = dirname(__FILE__) . '/extract2/';
+@unlink($e . 'file2.txt');
+@rmdir($e . 'one/level');
+@rmdir($e . 'one');
+@rmdir($e);
+?>
+--EXPECTF--
+%sextract%cfile1.txt
+%sextract%cfile2.txt
+%sextract%cone
+%sextract%csubdir
+%sextract%csubdir%cectory
+%sextract%csubdir%cectory%cfile.txt
+string(2) "hi"
+string(3) "hi3"
+string(3) "hi2"
+bool(false)
+Invalid argument, expected a filename (string) or array of filenames
+
+Warning: Phar::extractTo() expects parameter 1 to be string, array given in %sphar_extract.php on line %d
+Invalid argument, extraction path must be non-zero length
+Unable to use path "%soops" for extraction, it is a file, must be a directory
+Invalid argument, array of filenames to extract contains non-string value
+Extraction from phar "%stempmanifest1.phar.php" failed: Cannot extract "file1.txt" to "%sextract/file1.txt", path already exists
+string(5) "first"
+string(2) "hi"
+Cannot extract to "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...", destination directory is too long for filesystem
+Extraction from phar "%stempmanifest1.phar.php" failed: Cannot extract "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..." to "%s...", extracted filename is too long for filesystem
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/phar_get_supported_signatures_001.phpt b/ext/phar/tests/phar_get_supported_signatures_001.phpt
new file mode 100644
index 0000000000..f672c0024b
--- /dev/null
+++ b/ext/phar/tests/phar_get_supported_signatures_001.phpt
@@ -0,0 +1,22 @@
+--TEST--
+Phar::getSupportedSignatures()
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (extension_loaded("hash")) die("skip extension hash conflicts"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+var_dump(Phar::getSupportedSignatures());
+?>
+===DONE===
+?>
+--EXPECT--
+array(2) {
+ [0]=>
+ string(3) "MD5"
+ [1]=>
+ string(5) "SHA-1"
+}
+===DONE===
diff --git a/ext/phar/tests/phar_get_supported_signatures_002.phpt b/ext/phar/tests/phar_get_supported_signatures_002.phpt
new file mode 100644
index 0000000000..ba86947d5d
--- /dev/null
+++ b/ext/phar/tests/phar_get_supported_signatures_002.phpt
@@ -0,0 +1,26 @@
+--TEST--
+Phar::getSupportedSignatures()
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("hash")) die("skip extension hash required"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+var_dump(Phar::getSupportedSignatures());
+?>
+===DONE===
+?>
+--EXPECT--
+array(4) {
+ [0]=>
+ string(3) "MD5"
+ [1]=>
+ string(5) "SHA-1"
+ [2]=>
+ string(7) "SHA-256"
+ [3]=>
+ string(7) "SHA-512"
+}
+===DONE===
diff --git a/ext/phar/tests/phar_get_supportedcomp1.phpt b/ext/phar/tests/phar_get_supportedcomp1.phpt
new file mode 100644
index 0000000000..d32e12c0ab
--- /dev/null
+++ b/ext/phar/tests/phar_get_supportedcomp1.phpt
@@ -0,0 +1,22 @@
+--TEST--
+Phar::getSupportedCompression() (bz2 and zlib)
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+<?php if (!extension_loaded("bz2")) die("skip bz2 not available"); ?>
+<?php if (!extension_loaded("zlib")) die("skip zlib not available"); ?>
+--INI--
+phar.require_hash=0
+--FILE--
+<?php
+var_dump(Phar::getSupportedCompression());
+?>
+===DONE===
+--EXPECT--
+array(2) {
+ [0]=>
+ string(2) "GZ"
+ [1]=>
+ string(5) "BZIP2"
+}
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/phar_get_supportedcomp2.phpt b/ext/phar/tests/phar_get_supportedcomp2.phpt
new file mode 100644
index 0000000000..c607724918
--- /dev/null
+++ b/ext/phar/tests/phar_get_supportedcomp2.phpt
@@ -0,0 +1,20 @@
+--TEST--
+Phar::getSupportedCompression() (bz2 only)
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+<?php if (!extension_loaded("bz2")) die("skip bz2 not available"); ?>
+<?php if (extension_loaded("zlib")) die("skip zlib is available"); ?>
+--INI--
+phar.require_hash=0
+--FILE--
+<?php
+var_dump(Phar::getSupportedCompression());
+?>
+===DONE===
+--EXPECT--
+array(1) {
+ [0]=>
+ string(5) "BZIP2"
+}
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/phar_get_supportedcomp3.phpt b/ext/phar/tests/phar_get_supportedcomp3.phpt
new file mode 100644
index 0000000000..c300407f3f
--- /dev/null
+++ b/ext/phar/tests/phar_get_supportedcomp3.phpt
@@ -0,0 +1,20 @@
+--TEST--
+Phar::getSupportedCompression() (zlib only)
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+<?php if (extension_loaded("bz2")) die("skip bz2 is available"); ?>
+<?php if (!extension_loaded("zlib")) die("skip zlib not available"); ?>
+--INI--
+phar.require_hash=0
+--FILE--
+<?php
+var_dump(Phar::getSupportedCompression());
+?>
+===DONE===
+--EXPECT--
+array(1) {
+ [0]=>
+ string(2) "GZ"
+}
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/phar_get_supportedcomp4.phpt b/ext/phar/tests/phar_get_supportedcomp4.phpt
new file mode 100644
index 0000000000..fba2c71bfc
--- /dev/null
+++ b/ext/phar/tests/phar_get_supportedcomp4.phpt
@@ -0,0 +1,16 @@
+--TEST--
+Phar::getSupportedCompression() (none)
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+<?php if (extension_loaded("bz2")) die("skip bz2 is available"); ?>
+<?php if (extension_loaded("zlib")) die("skip zlib is available"); ?>
+--FILE--
+<?php
+var_dump(Phar::getSupportedCompression());
+?>
+===DONE===
+--EXPECT--
+array(0) {
+}
+===DONE===
diff --git a/ext/phar/tests/phar_gobyebye.phpt b/ext/phar/tests/phar_gobyebye.phpt
new file mode 100644
index 0000000000..d55bef0c30
--- /dev/null
+++ b/ext/phar/tests/phar_gobyebye.phpt
@@ -0,0 +1,44 @@
+--TEST--
+Phar: test edge cases of intercepted functions when the underlying phar archive has been unlinkArchive()d
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip");?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+Phar::interceptFileFuncs();
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.2.php';
+$pname = 'phar://' . $fname;
+file_put_contents($fname2, '<?php Phar::unlinkArchive("' . addslashes($fname) . '");');
+file_put_contents($pname . '/foo/hi', '<?php
+include "' . addslashes($fname2) . '";
+readfile("foo/hi");
+fopen("foo/hi", "r");
+echo file_get_contents("foo/hi");
+var_dump(is_file("foo/hi"),is_link("foo/hi"),is_dir("foo/hi"),file_exists("foo/hi"),stat("foo/hi"));
+opendir("foo/hi");
+?>
+');
+include $pname . '/foo/hi';
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.2.php'); ?>
+--EXPECTF--
+Warning: readfile(foo/hi): failed to open stream: No such file or directory in phar://%sphar_gobyebye.phar.php/foo/hi on line %d
+
+Warning: fopen(foo/hi): failed to open stream: No such file or directory in phar://%sphar_gobyebye.phar.php/foo/hi on line %d
+
+Warning: file_get_contents(foo/hi): failed to open stream: No such file or directory in phar://%sphar_gobyebye.phar.php/foo/hi on line %d
+
+Warning: stat(): stat failed for foo/hi in phar://%sphar_gobyebye.phar.php/foo/hi on line %d
+bool(false)
+bool(false)
+bool(false)
+bool(false)
+bool(false)
+
+Warning: opendir(foo/hi): failed to open dir: No such file or directory in phar://%sphar_gobyebye.phar.php/foo/hi on line %d
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/phar_gzip.phpt b/ext/phar/tests/phar_gzip.phpt
new file mode 100644
index 0000000000..f472949c05
--- /dev/null
+++ b/ext/phar/tests/phar_gzip.phpt
@@ -0,0 +1,54 @@
+--TEST--
+Phar: gzipped phar
+--SKIPIF--
+<?php if (!extension_loaded('phar')) die('skip'); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+<?php if (!extension_loaded("zlib")) die("skip zlib not available"); ?>
+<?php if (version_compare(phpversion(), '5.2.6', '<')) die("skip zlib is buggy in PHP < 5.2.6"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/phar_gzip.phar';
+$pname = 'phar://' . $fname;
+$fname2 = dirname(__FILE__) . '/phar_gzip.2.phar';
+$pname2 = 'phar://' . $fname2;
+
+$file = '<?php
+Phar::mapPhar();
+var_dump("it worked");
+include "phar://" . __FILE__ . "/tar_004.php";
+__HALT_COMPILER();';
+
+$files = array();
+$files['tar_004.php'] = '<?php var_dump(__FILE__);';
+$files['internal/file/here'] = "hi there!\n";
+$files['internal/dir/'] = '';
+$files['dir/'] = '';
+$gzip = true;
+
+include 'files/phar_test.inc';
+
+include $fname;
+
+$a = new Phar($fname);
+$a['test'] = 'hi';
+copy($fname, $fname2);
+$a->setAlias('another');
+$b = new Phar($fname2);
+var_dump($b->isFileFormat(Phar::PHAR));
+var_dump($b->isCompressed() == Phar::GZ);
+?>
+===DONE===
+--CLEAN--
+<?php
+@unlink(dirname(__FILE__) . '/phar_gzip.phar');
+@unlink(dirname(__FILE__) . '/phar_gzip.2.phar');
+?>
+--EXPECTF--
+string(9) "it worked"
+string(%d) "phar://%sphar_gzip.phar/tar_004.php"
+bool(true)
+bool(true)
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/phar_isvalidpharfilename.phpt b/ext/phar/tests/phar_isvalidpharfilename.phpt
new file mode 100644
index 0000000000..9c953ee88a
--- /dev/null
+++ b/ext/phar/tests/phar_isvalidpharfilename.phpt
@@ -0,0 +1,140 @@
+--TEST--
+Phar: Phar::isValidPharFilename()
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip");?>
+--INI--
+phar.readonly=1
+--FILE--
+<?php
+chdir(dirname(__FILE__));
+Phar::isValidPharFilename(array());
+echo "*\n";
+var_dump(Phar::isValidPharFilename('*'));
+var_dump(Phar::isValidPharFilename('*', true));
+var_dump(Phar::isValidPharFilename('*', false));
+
+echo "\nboo.phar\n";
+var_dump(Phar::isValidPharFilename('boo.phar'));
+var_dump(Phar::isValidPharFilename('boo.phar', true));
+var_dump(Phar::isValidPharFilename('boo.phar', false));
+
+echo "\nboo.tar\n";
+var_dump(Phar::isValidPharFilename('boo.tar'));
+var_dump(Phar::isValidPharFilename('boo.tar', true));
+var_dump(Phar::isValidPharFilename('boo.tar', false));
+
+echo "\nboo.phar.tar\n";
+var_dump(Phar::isValidPharFilename('boo.phar.tar'));
+var_dump(Phar::isValidPharFilename('boo.phar.tar', true));
+var_dump(Phar::isValidPharFilename('boo.phar.tar', false));
+
+mkdir(dirname(__FILE__) . '/.phar');
+
+echo "\n.phar/boo.tar\n";
+var_dump(Phar::isValidPharFilename('.phar/boo.tar'));
+var_dump(Phar::isValidPharFilename('.phar/boo.tar', true));
+var_dump(Phar::isValidPharFilename('.phar/boo.tar', false));
+
+echo "\n.phar.tar\n";
+var_dump(Phar::isValidPharFilename('.phar.tar'));
+var_dump(Phar::isValidPharFilename('.phar.tar', true));
+var_dump(Phar::isValidPharFilename('.phar.tar', false));
+
+echo "\n.phar.phar\n";
+var_dump(Phar::isValidPharFilename('.phar.phar'));
+var_dump(Phar::isValidPharFilename('.phar.phar', true));
+var_dump(Phar::isValidPharFilename('.phar.phar', false));
+
+echo "\n.phar.phart\n";
+var_dump(Phar::isValidPharFilename('.phar.phart'));
+var_dump(Phar::isValidPharFilename('.phar.phart', true));
+var_dump(Phar::isValidPharFilename('.phar.phart', false));
+
+echo "\nmy.pharmy\n";
+var_dump(Phar::isValidPharFilename('my.pharmy'));
+var_dump(Phar::isValidPharFilename('my.pharmy', true));
+var_dump(Phar::isValidPharFilename('my.pharmy', false));
+
+echo "\nphar.zip\n";
+var_dump(Phar::isValidPharFilename('phar.zip'));
+var_dump(Phar::isValidPharFilename('phar.zip', true));
+var_dump(Phar::isValidPharFilename('phar.zip', false));
+
+echo "\nphar.zip.phar\n";
+var_dump(Phar::isValidPharFilename('phar.zip.phar'));
+var_dump(Phar::isValidPharFilename('phar.zip.phar', true));
+var_dump(Phar::isValidPharFilename('phar.zip.phar', false));
+
+echo "\ndir.phar.php\n";
+var_dump(Phar::isValidPharFilename('dir.phar.php'));
+var_dump(Phar::isValidPharFilename('dir.phar.php', true));
+var_dump(Phar::isValidPharFilename('dir.phar.php', false));
+
+?>
+===DONE===
+--CLEAN--
+<?php
+rmdir(dirname(__FILE__) . '/.phar');
+--EXPECTF--
+Warning: Phar::isValidPharFilename() expects parameter 1 to be string, array given in %sphar_isvalidpharfilename.php on line %d
+*
+bool(false)
+bool(false)
+bool(false)
+
+boo.phar
+bool(true)
+bool(true)
+bool(false)
+
+boo.tar
+bool(false)
+bool(false)
+bool(true)
+
+boo.phar.tar
+bool(true)
+bool(true)
+bool(false)
+
+.phar/boo.tar
+bool(false)
+bool(false)
+bool(true)
+
+.phar.tar
+bool(false)
+bool(false)
+bool(true)
+
+.phar.phar
+bool(true)
+bool(true)
+bool(false)
+
+.phar.phart
+bool(false)
+bool(false)
+bool(true)
+
+my.pharmy
+bool(false)
+bool(false)
+bool(true)
+
+phar.zip
+bool(false)
+bool(false)
+bool(true)
+
+phar.zip.phar
+bool(true)
+bool(true)
+bool(false)
+
+dir.phar.php
+bool(true)
+bool(true)
+bool(false)
+===DONE===
+
diff --git a/ext/phar/tests/phar_magic.phpt b/ext/phar/tests/phar_magic.phpt
new file mode 100644
index 0000000000..f6a0a675ef
--- /dev/null
+++ b/ext/phar/tests/phar_magic.phpt
@@ -0,0 +1,31 @@
+--TEST--
+Phar: include/fopen magic
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$p = new Phar($fname);
+$p['a'] = '<?php include "b/c.php";' . "\n";
+$p['b/c.php'] = '<?php echo "in b\n";$a = fopen("a", "r", true);echo stream_get_contents($a);fclose($a);include dirname(__FILE__) . "/../d";';
+$p['d'] = "in d\n";
+$p->setStub('<?php
+set_include_path("phar://" . __FILE__);
+include "phar://" . __FILE__ . "/a";
+__HALT_COMPILER();');
+include $fname;
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php');
+__HALT_COMPILER();
+?>
+--EXPECTF--
+in b
+<?php include "b/c.php";
+in d
+===DONE===
diff --git a/ext/phar/tests/phar_metadata_read.phpt b/ext/phar/tests/phar_metadata_read.phpt
new file mode 100644
index 0000000000..bda411f740
--- /dev/null
+++ b/ext/phar/tests/phar_metadata_read.phpt
@@ -0,0 +1,95 @@
+--TEST--
+Phar with metadata (read)
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip");?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = "<?php __HALT_COMPILER(); ?>";
+
+$files = array();
+$pmeta = 'hi there';
+$files['a'] = array('cont' => 'a');
+$files['b'] = array('cont' => 'b');
+$files['c'] = array('cont' => 'c', 'meta' => array('hi', 'there'));
+$files['d'] = array('cont' => 'd', 'meta' => array('hi'=>'there','foo'=>'bar'));
+include 'files/phar_test.inc';
+
+foreach($files as $name => $cont) {
+ var_dump(file_get_contents($pname.'/'.$name));
+}
+
+$phar = new Phar($fname);
+var_dump($phar->hasMetaData());
+var_dump($phar->getMetaData());
+var_dump($phar->delMetaData());
+var_dump($phar->getMetaData());
+var_dump($phar->delMetaData());
+var_dump($phar->getMetaData());
+foreach($files as $name => $cont) {
+ echo " meta $name\n";
+ var_dump($phar[$name]->hasMetadata());
+ var_dump($phar[$name]->getMetadata());
+ var_dump($phar[$name]->delMetadata());
+ var_dump($phar[$name]->getMetadata());
+}
+
+unset($phar);
+
+foreach($files as $name => $cont) {
+ var_dump(file_get_contents($pname.'/'.$name));
+}
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECT--
+string(1) "a"
+string(1) "b"
+string(1) "c"
+string(1) "d"
+bool(true)
+string(8) "hi there"
+bool(true)
+NULL
+bool(true)
+NULL
+ meta a
+bool(false)
+NULL
+bool(true)
+NULL
+ meta b
+bool(false)
+NULL
+bool(true)
+NULL
+ meta c
+bool(true)
+array(2) {
+ [0]=>
+ string(2) "hi"
+ [1]=>
+ string(5) "there"
+}
+bool(true)
+NULL
+ meta d
+bool(true)
+array(2) {
+ ["hi"]=>
+ string(5) "there"
+ ["foo"]=>
+ string(3) "bar"
+}
+bool(true)
+NULL
+string(1) "a"
+string(1) "b"
+string(1) "c"
+string(1) "d"
+===DONE===
diff --git a/ext/phar/tests/phar_metadata_write.phpt b/ext/phar/tests/phar_metadata_write.phpt
new file mode 100644
index 0000000000..6df7ba4faf
--- /dev/null
+++ b/ext/phar/tests/phar_metadata_write.phpt
@@ -0,0 +1,71 @@
+--TEST--
+Phar with metadata (write)
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip");?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = "<?php __HALT_COMPILER(); ?>";
+
+$files = array();
+$files['a'] = array('cont' => 'a');
+$files['b'] = array('cont' => 'b', 'meta' => 'hi there');
+$files['c'] = array('cont' => 'c', 'meta' => array('hi', 'there'));
+$files['d'] = array('cont' => 'd', 'meta' => array('hi'=>'there','foo'=>'bar'));
+include 'files/phar_test.inc';
+
+foreach($files as $name => $cont) {
+ var_dump(file_get_contents($pname.'/'.$name));
+}
+
+$phar = new Phar($fname);
+var_dump($phar->getMetadata());
+$phar->setMetadata(array('my' => 'friend'));
+$phar->setMetadata(array('my' => 'friend'));
+var_dump($phar->getMetadata());
+$phar['a']->setMetadata(42);
+$phar['b']->setMetadata(NULL);
+$phar['c']->setMetadata(array(25, 'foo'=>'bar'));
+$phar['d']->setMetadata(true);
+
+foreach($files as $name => $cont) {
+ var_dump($phar[$name]->getMetadata());
+}
+
+unset($phar);
+
+foreach($files as $name => $cont) {
+ var_dump(file_get_contents($pname.'/'.$name));
+}
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECT--
+string(1) "a"
+string(1) "b"
+string(1) "c"
+string(1) "d"
+NULL
+array(1) {
+ ["my"]=>
+ string(6) "friend"
+}
+int(42)
+NULL
+array(2) {
+ [0]=>
+ int(25)
+ ["foo"]=>
+ string(3) "bar"
+}
+bool(true)
+string(1) "a"
+string(1) "b"
+string(1) "c"
+string(1) "d"
+===DONE===
diff --git a/ext/phar/tests/phar_mount.phpt b/ext/phar/tests/phar_mount.phpt
new file mode 100644
index 0000000000..80f8cda389
--- /dev/null
+++ b/ext/phar/tests/phar_mount.phpt
@@ -0,0 +1,63 @@
+--TEST--
+Phar: Phar::mount
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar';
+
+$a = new Phar($fname);
+$a['index.php'] = '<?php
+Phar::mount("testit", "' . addslashes(__FILE__) . '");
+try {
+Phar::mount("testit", "' . addslashes(__FILE__) . '");
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+try {
+Phar::mount("' . addslashes($pname) . '/testit1", "' . addslashes(__FILE__) . '");
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+?>';
+$a->setStub('<?php
+set_include_path("phar://" . __FILE__);
+include "index.php";
+__HALT_COMPILER();');
+Phar::mount($pname . '/testit1', __FILE__);
+include $fname;
+// test copying of a phar with mounted entries
+$b = $a->convertToExecutable(Phar::TAR);
+$b->setStub('<?php
+set_include_path("phar://" . __FILE__);
+include "index.php";
+__HALT_COMPILER();');
+try {
+include $fname2;
+} catch (Exception $e) {
+echo $e->getMessage(),"\n";
+}
+try {
+Phar::mount($pname . '/oops', '/home/oops/../../etc/passwd:');
+} catch (Exception $e) {
+echo $e->getMessage(),"\n";
+}
+Phar::mount($pname . '/testit2', $pname . '/testit1');
+echo substr($a['testit2']->getContent(),0, 50),"\n";
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar'); ?>
+--EXPECTF--
+Mounting of testit to %sphar_mount.php within phar %sphar_mount.phar.php failed
+Can only mount internal paths within a phar archive, use a relative path instead of "phar://%sphar_mount.phar.php/testit1"
+Mounting of testit to %sphar_mount.php within phar %sphar_mount.phar.tar failed
+Mounting of /oops to /home/oops/../../etc/passwd: within phar %sphar_mount.phar.php failed
+<?php
+$fname = dirname(__FILE__) . '/' . basename(
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/phar_offset_get_error.phpt b/ext/phar/tests/phar_offset_get_error.phpt
new file mode 100755
index 0000000000..ad0223697d
--- /dev/null
+++ b/ext/phar/tests/phar_offset_get_error.phpt
@@ -0,0 +1,37 @@
+--TEST--
+Phar: ignore filenames starting with / on offsetSet
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=1
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://'.$fname;
+$iname = '/file.txt';
+$ename = '/error/..';
+
+$p = new Phar($fname);
+$p[$iname] = "foobar\n";
+
+try
+{
+ $p[$ename] = "foobar\n";
+}
+catch(Exception $e)
+{
+ echo $e->getMessage() . "\n";
+}
+
+include($pname . $iname);
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECT--
+Entry /error/.. does not exist and cannot be created: phar error: invalid path "/error/.." contains upper directory reference
+foobar
+===DONE===
diff --git a/ext/phar/tests/phar_oo_001.phpt b/ext/phar/tests/phar_oo_001.phpt
new file mode 100755
index 0000000000..81d57d1bfc
--- /dev/null
+++ b/ext/phar/tests/phar_oo_001.phpt
@@ -0,0 +1,54 @@
+--TEST--
+Phar object: basics
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+
+require_once 'files/phar_oo_test.inc';
+
+$phar = new Phar($fname);
+var_dump($phar->getVersion());
+var_dump(count($phar));
+
+class MyPhar extends Phar
+{
+ function __construct()
+ {
+ }
+}
+
+try
+{
+ $phar = new MyPhar();
+ var_dump($phar->getVersion());
+}
+catch (BadMethodCallException $e)
+{
+ var_dump($e->getMessage());
+}
+try {
+ $phar = new Phar('test.phar');
+ $phar->__construct('oops');
+} catch (BadMethodCallException $e)
+{
+ var_dump($e->getMessage());
+}
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/files/phar_oo_test.phar.php');
+__halt_compiler();
+?>
+--EXPECT--
+string(5) "1.0.0"
+int(5)
+string(50) "Cannot call method on an uninitialized Phar object"
+string(29) "Cannot call constructor twice"
+===DONE===
diff --git a/ext/phar/tests/phar_oo_002.phpt b/ext/phar/tests/phar_oo_002.phpt
new file mode 100755
index 0000000000..9bb28689d9
--- /dev/null
+++ b/ext/phar/tests/phar_oo_002.phpt
@@ -0,0 +1,137 @@
+--TEST--
+Phar object: iterator & entries
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+--INI--
+phar.readonly=1
+phar.require_hash=0
+--FILE--
+<?php
+
+require_once 'files/phar_oo_test.inc';
+
+$phar = new Phar($fname);
+$phar->setInfoClass('SplFileInfo');
+foreach($phar as $name => $ent)
+{
+ var_dump(str_replace(str_replace('\\', '/', dirname(__FILE__)), '*', $name));
+ var_dump($ent->getFilename());
+ var_dump($ent->getSize());
+ var_dump($ent->getType());
+ var_dump($ent->isWritable());
+ var_dump($ent->isReadable());
+ var_dump($ent->isExecutable());
+ var_dump($ent->isFile());
+ var_dump($ent->isDir());
+ var_dump($ent->isLink());
+ var_dump($ent->getCTime());
+ var_dump($ent->getMTime());
+ var_dump($ent->getATime());
+}
+
+echo "==RECURSIVE==\n";
+
+$phar = new Phar($fname);
+foreach(new RecursiveIteratorIterator($phar) as $name => $ent)
+{
+ var_dump(str_replace(str_replace('\\', '/', dirname(__FILE__)), '*', $name));
+ var_dump(str_replace('\\', '/', $ent->getFilename()));
+ var_dump($ent->getCompressedSize());
+ var_dump($ent->isCRCChecked());
+ var_dump($ent->isCRCChecked() ? $ent->getCRC32() : NULL);
+ var_dump($ent->getPharFlags());
+}
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/files/phar_oo_test.phar.php');
+__halt_compiler();
+?>
+--EXPECTF--
+string(42) "phar://*/files/phar_oo_test.phar.php%ca.php"
+string(5) "a.php"
+int(32)
+string(4) "file"
+bool(false)
+bool(true)
+bool(false)
+bool(true)
+bool(false)
+bool(false)
+int(1141214400)
+int(1141214400)
+int(1141214400)
+string(38) "phar://*/files/phar_oo_test.phar.php%cb"
+string(1) "b"
+int(0)
+string(3) "dir"
+bool(false)
+bool(true)
+bool(false)
+bool(false)
+bool(true)
+bool(false)
+int(1141214400)
+int(1141214400)
+int(1141214400)
+string(42) "phar://*/files/phar_oo_test.phar.php%cb.php"
+string(5) "b.php"
+int(32)
+string(4) "file"
+bool(false)
+bool(true)
+bool(false)
+bool(true)
+bool(false)
+bool(false)
+int(1141214400)
+int(1141214400)
+int(1141214400)
+string(42) "phar://*/files/phar_oo_test.phar.php%ce.php"
+string(5) "e.php"
+int(32)
+string(4) "file"
+bool(false)
+bool(true)
+bool(false)
+bool(true)
+bool(false)
+bool(false)
+int(1141214400)
+int(1141214400)
+int(1141214400)
+==RECURSIVE==
+string(42) "phar://*/files/phar_oo_test.phar.php%ca.php"
+string(5) "a.php"
+int(32)
+bool(false)
+NULL
+int(0)
+string(44) "phar://*/files/phar_oo_test.phar.php%cb%cc.php"
+string(5) "c.php"
+int(34)
+bool(false)
+NULL
+int(0)
+string(44) "phar://*/files/phar_oo_test.phar.php%cb%cd.php"
+string(5) "d.php"
+int(34)
+bool(false)
+NULL
+int(0)
+string(42) "phar://*/files/phar_oo_test.phar.php%cb.php"
+string(5) "b.php"
+int(32)
+bool(false)
+NULL
+int(0)
+string(42) "phar://*/files/phar_oo_test.phar.php%ce.php"
+string(5) "e.php"
+int(32)
+bool(false)
+NULL
+int(0)
+===DONE===
diff --git a/ext/phar/tests/phar_oo_003.phpt b/ext/phar/tests/phar_oo_003.phpt
new file mode 100755
index 0000000000..9d24b1919b
--- /dev/null
+++ b/ext/phar/tests/phar_oo_003.phpt
@@ -0,0 +1,45 @@
+--TEST--
+Phar object: entry & openFile()
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+--INI--
+phar.require_hash=0
+--FILE--
+<?php
+
+require_once 'files/phar_oo_test.inc';
+
+$phar = new Phar($fname);
+$phar->setInfoClass();
+foreach($phar as $name => $ent)
+{
+ var_dump($ent->getFilename());
+ if ($ent->isDir()) {
+ var_dump('DIR');
+ } else {
+ var_dump($ent->openFile()->fgets());
+ include $ent->getPathName();
+ }
+}
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/files/phar_oo_test.phar.php');
+__halt_compiler();
+?>
+--EXPECT--
+string(5) "a.php"
+string(32) "<?php echo "This is a.php\n"; ?>"
+This is a.php
+string(1) "b"
+string(3) "DIR"
+string(5) "b.php"
+string(32) "<?php echo "This is b.php\n"; ?>"
+This is b.php
+string(5) "e.php"
+string(32) "<?php echo "This is e.php\n"; ?>"
+This is e.php
+===DONE===
diff --git a/ext/phar/tests/phar_oo_004.phpt b/ext/phar/tests/phar_oo_004.phpt
new file mode 100755
index 0000000000..4f72b3678d
--- /dev/null
+++ b/ext/phar/tests/phar_oo_004.phpt
@@ -0,0 +1,126 @@
+--TEST--
+Phar and DirectoryIterator
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+--INI--
+phar.require_hash=0
+--FILE--
+<?php
+
+require_once 'files/phar_oo_test.inc';
+
+$it = new DirectoryIterator('phar://'.$fname);
+
+foreach($it as $name => $ent)
+{
+ var_dump($name);
+ var_dump($ent->getFilename());
+ var_dump($ent->isDir());
+ var_dump($ent->isDot());
+}
+
+?>
+===MANUAL===
+<?php
+
+class MyDirectoryIterator extends DirectoryIterator
+{
+ function __construct($dir)
+ {
+ echo __METHOD__ . "\n";
+ parent::__construct($dir);
+ }
+
+ function rewind()
+ {
+ echo __METHOD__ . "\n";
+ parent::rewind();
+ }
+
+ function valid()
+ {
+ echo __METHOD__ . "\n";
+ return parent::valid();
+ }
+
+ function key()
+ {
+ echo __METHOD__ . "\n";
+ return parent::key();
+ }
+
+ function current()
+ {
+ echo __METHOD__ . "\n";
+ return parent::current();
+ }
+
+ function next()
+ {
+ echo __METHOD__ . "\n";
+ parent::next();
+ }
+}
+
+$it = new MyDirectoryIterator('phar://'.$fname);
+
+foreach($it as $name => $ent)
+{
+ var_dump($name);
+ var_dump($ent->getFilename());
+}
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/files/phar_oo_test.phar.php');
+__halt_compiler();
+?>
+--EXPECT--
+int(0)
+string(5) "a.php"
+bool(false)
+bool(false)
+int(1)
+string(1) "b"
+bool(true)
+bool(false)
+int(2)
+string(5) "b.php"
+bool(false)
+bool(false)
+int(3)
+string(5) "e.php"
+bool(false)
+bool(false)
+===MANUAL===
+MyDirectoryIterator::__construct
+MyDirectoryIterator::rewind
+MyDirectoryIterator::valid
+MyDirectoryIterator::current
+MyDirectoryIterator::key
+int(0)
+string(5) "a.php"
+MyDirectoryIterator::next
+MyDirectoryIterator::valid
+MyDirectoryIterator::current
+MyDirectoryIterator::key
+int(1)
+string(1) "b"
+MyDirectoryIterator::next
+MyDirectoryIterator::valid
+MyDirectoryIterator::current
+MyDirectoryIterator::key
+int(2)
+string(5) "b.php"
+MyDirectoryIterator::next
+MyDirectoryIterator::valid
+MyDirectoryIterator::current
+MyDirectoryIterator::key
+int(3)
+string(5) "e.php"
+MyDirectoryIterator::next
+MyDirectoryIterator::valid
+===DONE===
diff --git a/ext/phar/tests/phar_oo_005.phpt b/ext/phar/tests/phar_oo_005.phpt
new file mode 100755
index 0000000000..687cf59d07
--- /dev/null
+++ b/ext/phar/tests/phar_oo_005.phpt
@@ -0,0 +1,60 @@
+--TEST--
+Phar and RecursiveDirectoryIterator
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+--INI--
+phar.require_hash=0
+--FILE--
+<?php
+
+require_once 'files/phar_oo_test.inc';
+$fname = str_replace('\\', '/', $fname);
+
+$it = new RecursiveDirectoryIterator('phar://'.$fname);
+$it = new RecursiveIteratorIterator($it);
+
+foreach($it as $name => $ent)
+{
+ var_dump(str_replace(array('\\', $fname), array('/', '*'), $name));
+ var_dump(str_replace(array('\\', $fname), array('/', '*'), $ent->getPathname()));
+ var_dump(str_replace('\\', '/', $it->getSubPath()));
+ var_dump(str_replace('\\', '/', $it->getSubPathName()));
+ $sub = $it->getPathInfo();
+ var_dump(str_replace('\\', '/', $sub->getFilename()));
+}
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/files/phar_oo_test.phar.php');
+__halt_compiler();
+?>
+--EXPECT--
+string(14) "phar://*/a.php"
+string(14) "phar://*/a.php"
+string(0) ""
+string(5) "a.php"
+string(21) "phar_oo_test.phar.php"
+string(16) "phar://*/b/c.php"
+string(16) "phar://*/b/c.php"
+string(1) "b"
+string(7) "b/c.php"
+string(1) "b"
+string(16) "phar://*/b/d.php"
+string(16) "phar://*/b/d.php"
+string(1) "b"
+string(7) "b/d.php"
+string(1) "b"
+string(14) "phar://*/b.php"
+string(14) "phar://*/b.php"
+string(0) ""
+string(5) "b.php"
+string(21) "phar_oo_test.phar.php"
+string(14) "phar://*/e.php"
+string(14) "phar://*/e.php"
+string(0) ""
+string(5) "e.php"
+string(21) "phar_oo_test.phar.php"
+===DONE===
diff --git a/ext/phar/tests/phar_oo_006.phpt b/ext/phar/tests/phar_oo_006.phpt
new file mode 100755
index 0000000000..556c98ce0b
--- /dev/null
+++ b/ext/phar/tests/phar_oo_006.phpt
@@ -0,0 +1,52 @@
+--TEST--
+Phar object: array access
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+--INI--
+phar.require_hash=0
+--FILE--
+<?php
+
+require_once 'files/phar_oo_test.inc';
+
+class MyFile extends SplFileObject
+{
+ function __construct($what)
+ {
+ echo __METHOD__ . "($what)\n";
+ parent::__construct($what);
+ }
+}
+
+$phar = new Phar($fname);
+try
+{
+ $phar->setFileClass('SplFileInfo');
+}
+catch (UnexpectedValueException $e)
+{
+ echo $e->getMessage() . "\n";
+}
+$phar->setInfoClass('MyFile');
+
+echo $phar['a.php']->getFilename() . "\n";
+echo $phar['b/c.php']->getFilename() . "\n";
+echo $phar['b.php']->getFilename() . "\n";
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/files/phar_oo_test.phar.php');
+__halt_compiler();
+?>
+--EXPECTF--
+SplFileInfo::setFileClass() expects parameter 1 to be a class name derived from SplFileObject, 'SplFileInfo' given
+MyFile::__construct(phar://%s/a.php)
+a.php
+MyFile::__construct(phar://%s/b/c.php)
+c.php
+MyFile::__construct(phar://%s/b.php)
+b.php
+===DONE===
diff --git a/ext/phar/tests/phar_oo_007.phpt b/ext/phar/tests/phar_oo_007.phpt
new file mode 100755
index 0000000000..48807660ff
--- /dev/null
+++ b/ext/phar/tests/phar_oo_007.phpt
@@ -0,0 +1,87 @@
+--TEST--
+Phar object: access through SplFileObject
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+--INI--
+phar.require_hash=0
+--FILE--
+<?php
+
+require_once 'files/phar_oo_test.inc';
+
+class MyFile extends SplFileObject
+{
+ function __construct($name)
+ {
+ echo __METHOD__ . "(" . str_replace(str_replace('\\', '/', dirname(__FILE__)), '*', $name) . ")\n";
+ parent::__construct($name);
+ }
+}
+
+$phar = new Phar($fname);
+$phar->setInfoClass('MyFile');
+
+$f = $phar['a.php'];
+
+$s = $f->fstat();
+
+var_dump($s['atime']);
+var_dump($s['ctime']);
+var_dump($s['mtime']);
+
+var_dump($f->ftell());
+var_dump($f->eof());
+var_dump($f->fgets());
+var_dump($f->eof());
+var_dump($f->fseek(20));
+var_dump($f->ftell());
+var_dump($f->fgets());
+var_dump($f->rewind());
+var_dump($f->ftell());
+var_dump($f->fgets());
+var_dump($f->ftell());
+
+?>
+===AGAIN===
+<?php
+
+$f = $phar['a.php'];
+
+var_dump($f->ftell());
+var_dump($f->eof());
+var_dump($f->fgets());
+var_dump($f->eof());
+
+//unset($f); without unset we check for working refcounting
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/files/phar_oo_test.phar.php');
+__halt_compiler();
+?>
+--EXPECTF--
+MyFile::__construct(phar://*/files/phar_oo_test.phar.php/a.php)
+int(1141214400)
+int(1141214400)
+int(1141214400)
+int(0)
+bool(false)
+string(32) "<?php echo "This is a.php\n"; ?>"
+bool(true)
+int(0)
+int(20)
+string(12) "a.php\n"; ?>"
+NULL
+int(0)
+string(32) "<?php echo "This is a.php\n"; ?>"
+int(32)
+===AGAIN===
+MyFile::__construct(phar://*/files/phar_oo_test.phar.php/a.php)
+int(0)
+bool(false)
+string(32) "<?php echo "This is a.php\n"; ?>"
+bool(true)
+===DONE===
diff --git a/ext/phar/tests/phar_oo_008.phpt b/ext/phar/tests/phar_oo_008.phpt
new file mode 100755
index 0000000000..80d1ece0ca
--- /dev/null
+++ b/ext/phar/tests/phar_oo_008.phpt
@@ -0,0 +1,119 @@
+--TEST--
+Phar object: iterating via SplFileObject
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+--INI--
+phar.require_hash=0
+--FILE--
+<?php
+
+$pharconfig = 1;
+
+require_once 'files/phar_oo_test.inc';
+
+$phar = new Phar($fname);
+$phar->setInfoClass('SplFileObject');
+
+$f = $phar['a.csv'];
+echo "===1===\n";
+foreach($f as $k => $v)
+{
+ echo "$k=>$v\n";
+}
+
+$f->setFlags(SplFileObject::DROP_NEW_LINE);
+
+echo "===2===\n";
+foreach($f as $k => $v)
+{
+ echo "$k=>$v\n";
+}
+
+class MyCSVFile extends SplFileObject
+{
+ function current()
+ {
+ return parent::fgetcsv(',', '"');
+ }
+}
+
+$phar->setInfoClass('MyCSVFile');
+$v = $phar['a.csv'];
+
+echo "===3===\n";
+while(!$v->eof())
+{
+ echo $v->key() . "=>" . join('|',$v->fgetcsv()) . "\n";
+}
+
+echo "===4===\n";
+$v->rewind();
+while(!$v->eof())
+{
+ $l = $v->fgetcsv();
+ echo $v->key() . "=>" . join('|',$l) . "\n";
+}
+
+echo "===5===\n";
+foreach($v as $k => $d)
+{
+ echo "$k=>" . join('|',$d) . "\n";
+}
+
+class MyCSVFile2 extends SplFileObject
+{
+ function getCurrentLine()
+ {
+ echo __METHOD__ . "\n";
+ return parent::fgetcsv(',', '"');
+ }
+}
+
+$phar->setInfoClass('MyCSVFile2');
+$v = $phar['a.csv'];
+
+echo "===6===\n";
+foreach($v as $k => $d)
+{
+ echo "$k=>" . join('|',$d) . "\n";
+}
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/files/phar_oo_test.phar.php');
+__halt_compiler();
+?>
+--EXPECTF--
+===1===
+0=>1,2,3
+
+1=>2,a,b
+
+2=>3,"c","'e'"
+===2===
+0=>1,2,3
+1=>2,a,b
+2=>3,"c","'e'"
+===3===
+0=>1|2|3
+0=>2|a|b
+1=>3|c|'e'
+===4===
+0=>1|2|3
+1=>2|a|b
+2=>3|c|'e'
+===5===
+0=>1|2|3
+1=>2|a|b
+2=>3|c|'e'
+===6===
+MyCSVFile2::getCurrentLine
+1=>1|2|3
+MyCSVFile2::getCurrentLine
+3=>2|a|b
+MyCSVFile2::getCurrentLine
+5=>3|c|'e'
+===DONE===
diff --git a/ext/phar/tests/phar_oo_009.phpt b/ext/phar/tests/phar_oo_009.phpt
new file mode 100755
index 0000000000..6abd03ee30
--- /dev/null
+++ b/ext/phar/tests/phar_oo_009.phpt
@@ -0,0 +1,56 @@
+--TEST--
+Phar object: iterating via SplFileObject and reading csv
+--SKIPIF--
+<?php if (!extension_loaded('phar')) die('skip'); ?>
+<?php if (!defined('SplFileObject::READ_CSV') || !defined('SplFileObject::SKIP_EMPTY')) die('skip newer SPL version is required'); ?>
+--INI--
+phar.require_hash=0
+--FILE--
+<?php
+
+$pharconfig = 2;
+
+require_once 'files/phar_oo_test.inc';
+
+$phar = new Phar($fname);
+$phar->setInfoClass('SplFileObject');
+
+$f = $phar['a.csv'];
+$f->setFlags(SplFileObject::SKIP_EMPTY | SplFileObject::DROP_NEW_LINE);
+foreach($f as $k => $v)
+{
+ echo "$k=>$v\n";
+}
+
+?>
+===CSV===
+<?php
+
+$f->setFlags(SplFileObject::SKIP_EMPTY | SplFileObject::DROP_NEW_LINE | SplFileObject::READ_CSV);
+foreach($f as $k => $v)
+{
+ echo "$k=>" . join('|', $v) . "\n";
+}
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/files/phar_oo_test.phar.php');
+__halt_compiler();
+?>
+--EXPECTF--
+0=>1,2,3
+1=>2,a,b
+2=>3,"c","'e'"
+3=>4
+4=>5,5
+5=>7,777
+===CSV===
+0=>1|2|3
+1=>2|a|b
+2=>3|c|'e'
+3=>4
+4=>5|5
+6=>7|777
+===DONE===
diff --git a/ext/phar/tests/phar_oo_010.phpt b/ext/phar/tests/phar_oo_010.phpt
new file mode 100755
index 0000000000..4e4435a7bb
--- /dev/null
+++ b/ext/phar/tests/phar_oo_010.phpt
@@ -0,0 +1,55 @@
+--TEST--
+Phar object: ArrayAccess and isset
+--SKIPIF--
+<?php if (!extension_loaded('phar')) die('skip'); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+--INI--
+phar.require_hash=0
+--FILE--
+<?php
+
+$pharconfig = 0;
+
+require_once 'files/phar_oo_test.inc';
+
+$phar = new Phar($fname);
+
+var_dump(isset($phar['a.php']));
+var_dump(isset($phar['b.php']));
+var_dump(isset($phar['b/c.php']));
+var_dump(isset($phar['b/d.php']));
+var_dump(isset($phar['e.php']));
+
+?>
+===DIR===
+<?php
+var_dump(isset($phar['b']));
+?>
+===NA===
+<?php
+var_dump(isset($phar['a']));
+var_dump(isset($phar['b/c']));
+var_dump(isset($phar[12]));
+var_dump(isset($phar['b']));
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/files/phar_oo_test.phar.php');
+__halt_compiler();
+?>
+--EXPECTF--
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+===DIR===
+bool(false)
+===NA===
+bool(false)
+bool(false)
+bool(false)
+bool(false)
+===DONE===
diff --git a/ext/phar/tests/phar_oo_011.phpt b/ext/phar/tests/phar_oo_011.phpt
new file mode 100644
index 0000000000..236009b7e4
--- /dev/null
+++ b/ext/phar/tests/phar_oo_011.phpt
@@ -0,0 +1,34 @@
+--TEST--
+Phar object: add file
+--SKIPIF--
+<?php if (!extension_loaded('phar')) die('skip'); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+
+$pharconfig = 0;
+
+require_once 'files/phar_oo_test.inc';
+
+$phar = new Phar($fname);
+$phar->setInfoClass('SplFileObject');
+
+$phar['f.php'] = 'hi';
+var_dump(isset($phar['f.php']));
+echo $phar['f.php'];
+echo "\n";
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/files/phar_oo_test.phar.php');
+__halt_compiler();
+?>
+--EXPECT--
+bool(true)
+hi
+===DONE===
diff --git a/ext/phar/tests/phar_oo_011b.phpt b/ext/phar/tests/phar_oo_011b.phpt
new file mode 100755
index 0000000000..37a0e570a5
--- /dev/null
+++ b/ext/phar/tests/phar_oo_011b.phpt
@@ -0,0 +1,39 @@
+--TEST--
+Phar object: add file
+--SKIPIF--
+<?php if (!extension_loaded('phar')) die('skip'); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+--INI--
+phar.readonly=1
+phar.require_hash=0
+--FILE--
+<?php
+
+try
+{
+ $pharconfig = 0;
+
+ require_once 'files/phar_oo_test.inc';
+
+ $phar = new Phar($fname);
+
+ $phar['f.php'] = 'hi';
+ var_dump(isset($phar['f.php']));
+ echo $phar['f.php'];
+ echo "\n";
+}
+catch (BadMethodCallException $e)
+{
+ echo "Exception: " . $e->getMessage() . "\n";
+}
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/files/phar_oo_test.phar.php');
+__halt_compiler();
+?>
+--EXPECTF--
+Exception: Write operations disabled by INI setting
+===DONE===
diff --git a/ext/phar/tests/phar_oo_012.phpt b/ext/phar/tests/phar_oo_012.phpt
new file mode 100644
index 0000000000..e79ac0960e
--- /dev/null
+++ b/ext/phar/tests/phar_oo_012.phpt
@@ -0,0 +1,37 @@
+--TEST--
+Phar object: unset file
+--SKIPIF--
+<?php if (!extension_loaded('phar')) die('skip'); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+
+$pharconfig = 0;
+
+require_once 'files/phar_oo_test.inc';
+
+$phar = new Phar($fname);
+$phar->setInfoClass('SplFileObject');
+
+$phar['f.php'] = 'hi';
+var_dump(isset($phar['f.php']));
+echo $phar['f.php'];
+echo "\n";
+unset($phar['f.php']);
+var_dump(isset($phar['f.php']));
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/files/phar_oo_test.phar.php');
+__halt_compiler();
+?>
+--EXPECT--
+bool(true)
+hi
+bool(false)
+===DONE===
diff --git a/ext/phar/tests/phar_oo_012_confirm.phpt b/ext/phar/tests/phar_oo_012_confirm.phpt
new file mode 100644
index 0000000000..58a3be87b3
--- /dev/null
+++ b/ext/phar/tests/phar_oo_012_confirm.phpt
@@ -0,0 +1,40 @@
+--TEST--
+Phar object: unset file (confirm disk file is changed)
+--SKIPIF--
+<?php if (!extension_loaded('phar')) die('skip'); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+
+$pharconfig = 0;
+
+require_once 'files/phar_oo_test.inc';
+
+$phar = new Phar($fname);
+$phar->setInfoClass('SplFileObject');
+
+$phar['f.php'] = 'hi';
+var_dump(isset($phar['f.php']));
+echo $phar['f.php'];
+echo "\n";
+$md5 = md5_file($fname);
+unset($phar['f.php']);
+$md52 = md5_file($fname);
+if ($md5 == $md52) echo 'File on disk has not changed';
+var_dump(isset($phar['f.php']));
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/files/phar_oo_test.phar.php');
+__halt_compiler();
+?>
+--EXPECT--
+bool(true)
+hi
+bool(false)
+===DONE===
diff --git a/ext/phar/tests/phar_oo_012b.phpt b/ext/phar/tests/phar_oo_012b.phpt
new file mode 100755
index 0000000000..01cf776986
--- /dev/null
+++ b/ext/phar/tests/phar_oo_012b.phpt
@@ -0,0 +1,42 @@
+--TEST--
+Phar object: unset file
+--SKIPIF--
+<?php if (!extension_loaded('phar')) die('skip'); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+--INI--
+phar.readonly=1
+phar.require_hash=0
+--FILE--
+<?php
+
+try
+{
+ $pharconfig = 0;
+
+ require_once 'files/phar_oo_test.inc';
+
+ $phar = new Phar($fname);
+ $phar->setInfoClass('SplFileObject');
+
+ $phar['f.php'] = 'hi';
+ var_dump(isset($phar['f.php']));
+ echo $phar['f.php'];
+ echo "\n";
+ unset($phar['f.php']);
+ var_dump(isset($phar['f.php']));
+}
+catch (BadMethodCallException $e)
+{
+ echo "Exception: " . $e->getMessage() . "\n";
+}
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/files/phar_oo_test.phar.php');
+__halt_compiler();
+?>
+--EXPECTF--
+Exception: Write operations disabled by INI setting
+===DONE===
diff --git a/ext/phar/tests/phar_oo_compressallbz2.phpt b/ext/phar/tests/phar_oo_compressallbz2.phpt
new file mode 100644
index 0000000000..3f52227194
--- /dev/null
+++ b/ext/phar/tests/phar_oo_compressallbz2.phpt
@@ -0,0 +1,66 @@
+--TEST--
+Phar::compressFiles(Phar::BZ2)
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("bz2")) die("skip bz2 not present"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = '<?php __HALT_COMPILER(); ?>';
+
+$files = array();
+$files['a'] = 'a';
+$files['b'] = 'b';
+$files['c'] = 'c';
+
+include 'files/phar_test.inc';
+
+$phar = new Phar($fname);
+
+var_dump(file_get_contents($pname . '/a'));
+var_dump($phar['a']->isCompressed());
+var_dump(file_get_contents($pname . '/b'));
+var_dump($phar['b']->isCompressed());
+var_dump(file_get_contents($pname . '/c'));
+var_dump($phar['c']->isCompressed());
+
+$phar = new Phar($fname);
+$phar->compressFiles(Phar::BZ2);
+var_dump(file_get_contents($pname . '/a'));
+var_dump($phar['a']->isCompressed(Phar::GZ));
+var_dump($phar['a']->isCompressed(Phar::BZ2));
+var_dump(file_get_contents($pname . '/b'));
+var_dump($phar['b']->isCompressed(Phar::GZ));
+var_dump($phar['b']->isCompressed(Phar::BZ2));
+var_dump(file_get_contents($pname . '/c'));
+var_dump($phar['c']->isCompressed(Phar::GZ));
+var_dump($phar['b']->isCompressed(Phar::BZ2));
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php');
+?>
+--EXPECTF--
+string(1) "a"
+bool(false)
+string(1) "b"
+bool(false)
+string(1) "c"
+bool(false)
+string(1) "a"
+bool(false)
+bool(true)
+string(1) "b"
+bool(false)
+bool(true)
+string(1) "c"
+bool(false)
+bool(true)
+===DONE===
diff --git a/ext/phar/tests/phar_oo_compressallgz.phpt b/ext/phar/tests/phar_oo_compressallgz.phpt
new file mode 100644
index 0000000000..55e7435f95
--- /dev/null
+++ b/ext/phar/tests/phar_oo_compressallgz.phpt
@@ -0,0 +1,71 @@
+--TEST--
+Phar::compressFiles(Phar::GZ)
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("zlib")) die("skip zlib not present"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = '<?php __HALT_COMPILER(); ?>';
+
+$files = array();
+$files['a'] = 'a';
+$files['b'] = 'b';
+$files['c'] = 'c';
+
+include 'files/phar_test.inc';
+
+$phar = new Phar($fname);
+
+var_dump(file_get_contents($pname . '/a'));
+var_dump($phar['a']->isCompressed());
+var_dump(file_get_contents($pname . '/b'));
+var_dump($phar['b']->isCompressed());
+var_dump(file_get_contents($pname . '/c'));
+var_dump($phar['c']->isCompressed());
+
+$phar = new Phar($fname);
+$phar->compressFiles(Phar::GZ);
+var_dump(file_get_contents($pname . '/a'));
+var_dump($phar['a']->isCompressed(Phar::GZ));
+var_dump($phar['a']->isCompressed(Phar::BZ2));
+var_dump(file_get_contents($pname . '/b'));
+var_dump($phar['b']->isCompressed(Phar::GZ));
+var_dump($phar['b']->isCompressed(Phar::BZ2));
+var_dump(file_get_contents($pname . '/c'));
+var_dump($phar['c']->isCompressed(Phar::GZ));
+var_dump($phar['b']->isCompressed(Phar::BZ2));
+try {
+$phar->compressFiles(25);
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php');
+?>
+--EXPECTF--
+string(1) "a"
+bool(false)
+string(1) "b"
+bool(false)
+string(1) "c"
+bool(false)
+string(1) "a"
+bool(true)
+bool(false)
+string(1) "b"
+bool(true)
+bool(false)
+string(1) "c"
+bool(true)
+bool(false)
+Unknown compression specified, please pass one of Phar::GZ or Phar::BZ2
+===DONE===
diff --git a/ext/phar/tests/phar_oo_compressed_001.phpt b/ext/phar/tests/phar_oo_compressed_001.phpt
new file mode 100644
index 0000000000..af02012573
--- /dev/null
+++ b/ext/phar/tests/phar_oo_compressed_001.phpt
@@ -0,0 +1,68 @@
+--TEST--
+Phar: PharFileInfo::compress(Phar::GZ)
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("zlib")) die("skip zlib not present"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = '<?php __HALT_COMPILER(); ?>';
+
+$files = array();
+$files['a'] = 'a';
+$files['b'] = 'b';
+$files['c'] = 'c';
+
+include 'files/phar_test.inc';
+
+$phar = new Phar($fname);
+
+var_dump(file_get_contents($pname . '/a'));
+var_dump($phar['a']->isCompressed());
+var_dump(file_get_contents($pname . '/b'));
+var_dump($phar['b']->isCompressed());
+var_dump(file_get_contents($pname . '/c'));
+var_dump($phar['c']->isCompressed());
+
+$phar['a'] = 'new a';
+$phar['a']->decompress();
+$phar['b'] = 'new b';
+$phar['b']->compress(Phar::GZ);
+$phar['d'] = 'new d';
+
+$phar = new Phar($fname);
+var_dump(file_get_contents($pname . '/a'));
+var_dump($phar['a']->isCompressed());
+var_dump(file_get_contents($pname . '/b'));
+var_dump($phar['b']->isCompressed());
+var_dump(file_get_contents($pname . '/c'));
+var_dump($phar['c']->isCompressed());
+var_dump(file_get_contents($pname . '/d'));
+var_dump($phar['d']->isCompressed());
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php');
+?>
+--EXPECTF--
+string(1) "a"
+bool(false)
+string(1) "b"
+bool(false)
+string(1) "c"
+bool(false)
+string(5) "new a"
+bool(false)
+string(5) "new b"
+bool(true)
+string(1) "c"
+bool(false)
+string(5) "new d"
+bool(false)
+===DONE===
diff --git a/ext/phar/tests/phar_oo_compressed_001b.phpt b/ext/phar/tests/phar_oo_compressed_001b.phpt
new file mode 100755
index 0000000000..6d4c732862
--- /dev/null
+++ b/ext/phar/tests/phar_oo_compressed_001b.phpt
@@ -0,0 +1,68 @@
+--TEST--
+Phar: PharFileInfo::compress(Phar::BZ2)
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("bz2")) die("skip bz2 not present"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = '<?php __HALT_COMPILER(); ?>';
+
+$files = array();
+$files['a'] = 'a';
+$files['b'] = 'b';
+$files['c'] = 'c';
+
+include 'files/phar_test.inc';
+
+$phar = new Phar($fname);
+
+var_dump(file_get_contents($pname . '/a'));
+var_dump($phar['a']->isCompressed());
+var_dump(file_get_contents($pname . '/b'));
+var_dump($phar['b']->isCompressed());
+var_dump(file_get_contents($pname . '/c'));
+var_dump($phar['c']->isCompressed());
+
+$phar['a'] = 'new a';
+$phar['a']->decompress();
+$phar['b'] = 'new b';
+$phar['b']->compress(Phar::BZ2);
+$phar['d'] = 'new d';
+
+$phar = new Phar($fname);
+var_dump(file_get_contents($pname . '/a'));
+var_dump($phar['a']->isCompressed());
+var_dump(file_get_contents($pname . '/b'));
+var_dump($phar['b']->isCompressed());
+var_dump(file_get_contents($pname . '/c'));
+var_dump($phar['c']->isCompressed());
+var_dump(file_get_contents($pname . '/d'));
+var_dump($phar['d']->isCompressed());
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php');
+?>
+--EXPECTF--
+string(1) "a"
+bool(false)
+string(1) "b"
+bool(false)
+string(1) "c"
+bool(false)
+string(5) "new a"
+bool(false)
+string(5) "new b"
+bool(true)
+string(1) "c"
+bool(false)
+string(5) "new d"
+bool(false)
+===DONE===
diff --git a/ext/phar/tests/phar_oo_compressed_002.phpt b/ext/phar/tests/phar_oo_compressed_002.phpt
new file mode 100755
index 0000000000..d03d6f1a98
--- /dev/null
+++ b/ext/phar/tests/phar_oo_compressed_002.phpt
@@ -0,0 +1,73 @@
+--TEST--
+Phar: context/compress=GZ
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("zlib")) die("skip zlib not present"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = '<?php __HALT_COMPILER(); ?>';
+
+$files = array();
+$files['a'] = 'a';
+$files['b'] = 'b';
+$files['c'] = 'c';
+
+include 'files/phar_test.inc';
+
+$phar = new Phar($fname);
+
+var_dump(file_get_contents($pname . '/a'));
+var_dump($phar['a']->isCompressed());
+var_dump(file_get_contents($pname . '/b'));
+var_dump($phar['b']->isCompressed());
+var_dump(file_get_contents($pname . '/c'));
+var_dump($phar['c']->isCompressed());
+
+$context = stream_context_create(array('phar'=>array('compress'=>Phar::GZ)));
+
+file_put_contents($pname . '/b', 'new b');
+file_put_contents($pname . '/c', 'new c', 0, $context);
+file_put_contents($pname . '/d', 'new d');
+file_put_contents($pname . '/e', 'new e', 0, $context);
+
+$phar = new Phar($fname);
+var_dump(file_get_contents($pname . '/a'));
+var_dump($phar['a']->isCompressed());
+var_dump(file_get_contents($pname . '/b'));
+var_dump($phar['b']->isCompressed());
+var_dump(file_get_contents($pname . '/c'));
+var_dump($phar['c']->isCompressed());
+var_dump(file_get_contents($pname . '/d'));
+var_dump($phar['d']->isCompressed());
+var_dump(file_get_contents($pname . '/e'));
+var_dump($phar['e']->isCompressed());
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php');
+?>
+--EXPECTF--
+string(1) "a"
+bool(false)
+string(1) "b"
+bool(false)
+string(1) "c"
+bool(false)
+string(1) "a"
+bool(false)
+string(5) "new b"
+bool(false)
+string(5) "new c"
+bool(true)
+string(5) "new d"
+bool(false)
+string(5) "new e"
+bool(true)
+===DONE===
diff --git a/ext/phar/tests/phar_oo_compressed_002b.phpt b/ext/phar/tests/phar_oo_compressed_002b.phpt
new file mode 100755
index 0000000000..0e167012b7
--- /dev/null
+++ b/ext/phar/tests/phar_oo_compressed_002b.phpt
@@ -0,0 +1,73 @@
+--TEST--
+Phar: context/compress=BZip2
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("bz2")) die("skip bz2 not present"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = '<?php __HALT_COMPILER(); ?>';
+
+$files = array();
+$files['a'] = 'a';
+$files['b'] = 'b';
+$files['c'] = 'c';
+
+include 'files/phar_test.inc';
+
+$phar = new Phar($fname);
+
+var_dump(file_get_contents($pname . '/a'));
+var_dump($phar['a']->isCompressed());
+var_dump(file_get_contents($pname . '/b'));
+var_dump($phar['b']->isCompressed());
+var_dump(file_get_contents($pname . '/c'));
+var_dump($phar['c']->isCompressed());
+
+$context = stream_context_create(array('phar'=>array('compress'=>Phar::BZ2)));
+
+file_put_contents($pname . '/b', 'new b');
+file_put_contents($pname . '/c', 'new c', 0, $context);
+file_put_contents($pname . '/d', 'new d');
+file_put_contents($pname . '/e', 'new e', 0, $context);
+
+$phar = new Phar($fname);
+var_dump(file_get_contents($pname . '/a'));
+var_dump($phar['a']->isCompressed());
+var_dump(file_get_contents($pname . '/b'));
+var_dump($phar['b']->isCompressed());
+var_dump(file_get_contents($pname . '/c'));
+var_dump($phar['c']->isCompressed());
+var_dump(file_get_contents($pname . '/d'));
+var_dump($phar['d']->isCompressed());
+var_dump(file_get_contents($pname . '/e'));
+var_dump($phar['e']->isCompressed());
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php');
+?>
+--EXPECTF--
+string(1) "a"
+bool(false)
+string(1) "b"
+bool(false)
+string(1) "c"
+bool(false)
+string(1) "a"
+bool(false)
+string(5) "new b"
+bool(false)
+string(5) "new c"
+bool(true)
+string(5) "new d"
+bool(false)
+string(5) "new e"
+bool(true)
+===DONE===
diff --git a/ext/phar/tests/phar_oo_getcontents.phpt b/ext/phar/tests/phar_oo_getcontents.phpt
new file mode 100644
index 0000000000..e42bca46fc
--- /dev/null
+++ b/ext/phar/tests/phar_oo_getcontents.phpt
@@ -0,0 +1,39 @@
+--TEST--
+Phar object: getContent()
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+
+$phar = new Phar($fname);
+$phar['a/b'] = 'file contents
+this works';
+$phar->addEmptyDir('hi');
+echo $phar['a/b']->getContent() . "\n";
+try {
+echo $phar['a']->getContent(), "\n";
+} catch (Exception $e) {
+echo $e->getMessage(), "\n";
+}
+try {
+echo $phar['hi']->getContent(), "\n";
+} catch (Exception $e) {
+echo $e->getMessage(), "\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php');
+__halt_compiler();
+?>
+--EXPECTF--
+file contents
+this works
+Phar error: Cannot retrieve contents, "a" in phar "%sphar_oo_getcontents.phar.php" is a directory
+Phar error: Cannot retrieve contents, "hi" in phar "%sphar_oo_getcontents.phar.php" is a directory
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/phar_oo_getcontentsgz.phpt b/ext/phar/tests/phar_oo_getcontentsgz.phpt
new file mode 100644
index 0000000000..a480a69637
--- /dev/null
+++ b/ext/phar/tests/phar_oo_getcontentsgz.phpt
@@ -0,0 +1,34 @@
+--TEST--
+Phar object: getContent() (verify it works with compression)
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+<?php if (!extension_loaded("zlib")) die("skip zlib not available"); ?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.2.phar.php';
+
+$phar = new Phar($fname);
+$phar['a'] = 'file contents
+this works';
+$phar['a']->compress(Phar::GZ);
+copy($fname, $fname2);
+$phar2 = new Phar($fname2);
+var_dump($phar2['a']->isCompressed());
+echo $phar2['a']->getContent() . "\n";
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.2.phar.php');
+__halt_compiler();
+?>
+--EXPECT--
+bool(true)
+file contents
+this works
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/phar_oo_getmodified.phpt b/ext/phar/tests/phar_oo_getmodified.phpt
new file mode 100644
index 0000000000..d531393281
--- /dev/null
+++ b/ext/phar/tests/phar_oo_getmodified.phpt
@@ -0,0 +1,36 @@
+--TEST--
+Phar::getModified()
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("zlib")) die("skip zlib not present"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = '<?php __HALT_COMPILER(); ?>';
+
+$files = array();
+$files['a'] = 'a';
+$files['b'] = 'b';
+$files['c'] = 'c';
+
+include 'files/phar_test.inc';
+
+$phar = new Phar($fname);
+var_dump($phar->getModified());
+$phar->compressFiles(Phar::GZ);
+var_dump($phar->getModified());
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php');
+?>
+--EXPECTF--
+bool(false)
+bool(true)
+===DONE===
diff --git a/ext/phar/tests/phar_oo_iswriteable.phpt b/ext/phar/tests/phar_oo_iswriteable.phpt
new file mode 100644
index 0000000000..9fbca2c9ea
--- /dev/null
+++ b/ext/phar/tests/phar_oo_iswriteable.phpt
@@ -0,0 +1,84 @@
+--TEST--
+Phar::isWriteable
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.1.phar.php';
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.tar';
+$pname = 'phar://hio';
+$file = '<?php include "' . $pname . '/a.php"; __HALT_COMPILER(); ?>';
+
+$files = array();
+$files['a.php'] = '<?php echo "This is a\n"; include "'.$pname.'/b.php"; ?>';
+$files['dir/'] = '';
+$hasdir = 1;
+include 'files/phar_test.inc';
+$a = new Phar($fname);
+$b = new PharData($fname2);
+$b['test'] = 'hi';
+
+var_dump($a['a.php']->isWritable());
+var_dump($a['a.php']->isReadable());
+$a['a.php']->chmod(000);
+var_dump($a['a.php']->isWritable());
+var_dump($a['a.php']->isReadable());
+$a['a.php']->chmod(0666);
+var_dump($a['a.php']->isWritable());
+var_dump($a['a.php']->isReadable());
+ini_set('phar.readonly',1);
+clearstatcache();
+var_dump($a['a.php']->isWritable());
+var_dump($a['a.php']->isReadable());
+ini_set('phar.readonly',0);
+clearstatcache();
+var_dump($a['a.php']->isWritable());
+var_dump($a['a.php']->isReadable());
+?>
+archive
+<?php
+ini_set('phar.readonly',0);
+$p = new Phar('doesnotexisthere.phar');
+var_dump($p->isWritable());
+clearstatcache();
+var_dump($a->isWritable());
+var_dump($b->isWritable());
+ini_set('phar.readonly',1);
+clearstatcache();
+var_dump($a->isWritable());
+var_dump($b->isWritable());
+chmod($fname2, 000);
+clearstatcache();
+var_dump($a->isWritable());
+var_dump($b->isWritable());
+chmod($fname2, 0666);
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.1.phar.php');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.tar');
+?>
+--EXPECT--
+bool(true)
+bool(true)
+bool(false)
+bool(false)
+bool(true)
+bool(true)
+bool(false)
+bool(true)
+bool(true)
+bool(true)
+archive
+bool(true)
+bool(true)
+bool(true)
+bool(false)
+bool(true)
+bool(false)
+bool(false)
+===DONE===
diff --git a/ext/phar/tests/phar_oo_nosig.phpt b/ext/phar/tests/phar_oo_nosig.phpt
new file mode 100644
index 0000000000..d99222e12c
--- /dev/null
+++ b/ext/phar/tests/phar_oo_nosig.phpt
@@ -0,0 +1,24 @@
+--TEST--
+Phar::getSignature() no signature
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+--INI--
+phar.require_hash=0
+--FILE--
+<?php
+
+require_once 'files/phar_oo_test.inc';
+
+$phar = new Phar($fname);
+var_dump($phar->getSignature());
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/files/phar_oo_test.phar.php');
+__halt_compiler();
+?>
+--EXPECT--
+bool(false)
+===DONE===
diff --git a/ext/phar/tests/phar_oo_uncompressall.phpt b/ext/phar/tests/phar_oo_uncompressall.phpt
new file mode 100644
index 0000000000..19cf953197
--- /dev/null
+++ b/ext/phar/tests/phar_oo_uncompressall.phpt
@@ -0,0 +1,80 @@
+--TEST--
+Phar::decompressFiles()
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("zlib")) die("skip zlib not present"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = '<?php __HALT_COMPILER(); ?>';
+
+$files = array();
+$files['a'] = 'a';
+$files['b'] = 'b';
+$files['c'] = 'c';
+
+include 'files/phar_test.inc';
+
+$phar = new Phar($fname);
+
+var_dump(file_get_contents($pname . '/a'));
+var_dump($phar['a']->isCompressed());
+var_dump(file_get_contents($pname . '/b'));
+var_dump($phar['b']->isCompressed());
+var_dump(file_get_contents($pname . '/c'));
+var_dump($phar['c']->isCompressed());
+
+$phar = new Phar($fname);
+$phar->compressFiles(Phar::GZ);
+var_dump(file_get_contents($pname . '/a'));
+var_dump($phar['a']->isCompressed(Phar::GZ));
+var_dump($phar['a']->isCompressed(Phar::BZ2));
+var_dump(file_get_contents($pname . '/b'));
+var_dump($phar['b']->isCompressed(Phar::GZ));
+var_dump($phar['b']->isCompressed(Phar::BZ2));
+var_dump(file_get_contents($pname . '/c'));
+var_dump($phar['c']->isCompressed(Phar::GZ));
+var_dump($phar['b']->isCompressed(Phar::BZ2));
+
+$phar->decompressFiles();
+var_dump(file_get_contents($pname . '/a'));
+var_dump($phar['a']->isCompressed());
+var_dump(file_get_contents($pname . '/b'));
+var_dump($phar['a']->isCompressed());
+var_dump(file_get_contents($pname . '/c'));
+var_dump($phar['a']->isCompressed());
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php');
+?>
+--EXPECTF--
+string(1) "a"
+bool(false)
+string(1) "b"
+bool(false)
+string(1) "c"
+bool(false)
+string(1) "a"
+bool(true)
+bool(false)
+string(1) "b"
+bool(true)
+bool(false)
+string(1) "c"
+bool(true)
+bool(false)
+string(1) "a"
+bool(false)
+string(1) "b"
+bool(false)
+string(1) "c"
+bool(false)
+===DONE===
diff --git a/ext/phar/tests/phar_running.phpt b/ext/phar/tests/phar_running.phpt
new file mode 100644
index 0000000000..2d132b9ac7
--- /dev/null
+++ b/ext/phar/tests/phar_running.phpt
@@ -0,0 +1,29 @@
+--TEST--
+Phar: Phar::running()
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+
+$phar = new Phar($fname);
+$phar['index.php'] = '<?php
+Phar::running(array());
+var_dump(Phar::running());
+var_dump(Phar::running(false));
+?>';
+include $pname . '/index.php';
+var_dump(Phar::running());
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECTF--
+Warning: Phar::running() expects parameter 1 to be boolean, array given in phar://%sphar_running.phar.php/index.php on line 2
+string(%d) "phar://%sphar_running.phar.php"
+string(%d) "%sphar_running.phar.php"
+string(0) ""
+===DONE===
diff --git a/ext/phar/tests/phar_setalias.phpt b/ext/phar/tests/phar_setalias.phpt
new file mode 100644
index 0000000000..ef9fa283d5
--- /dev/null
+++ b/ext/phar/tests/phar_setalias.phpt
@@ -0,0 +1,36 @@
+--TEST--
+Phar::setAlias()
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = '<?php echo "first stub\n"; __HALT_COMPILER(); ?>';
+
+$files = array();
+$files['a'] = 'a';
+$files['b'] = 'b';
+$files['c'] = 'c';
+
+include 'files/phar_test.inc';
+
+$phar = new Phar($fname);
+echo $phar->getAlias() . "\n";
+$phar->setAlias('test');
+echo $phar->getAlias() . "\n";
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phartmp.php');
+__HALT_COMPILER();
+?>
+--EXPECT--
+hio
+test
+===DONE===
diff --git a/ext/phar/tests/phar_setalias2.phpt b/ext/phar/tests/phar_setalias2.phpt
new file mode 100644
index 0000000000..901e4d2ebd
--- /dev/null
+++ b/ext/phar/tests/phar_setalias2.phpt
@@ -0,0 +1,51 @@
+--TEST--
+Phar::setAlias() error
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = '<?php echo "first stub\n"; __HALT_COMPILER(); ?>';
+
+$files = array();
+$files['a'] = 'a';
+$files['b'] = 'b';
+$files['c'] = 'c';
+
+include 'files/phar_test.inc';
+
+$phar = new Phar($fname);
+echo $phar->getAlias() . "\n";
+$phar->setAlias('test');
+echo $phar->getAlias() . "\n";
+$b = $phar;
+$phar = new Phar(dirname(__FILE__) . '/notphar.phar');
+try {
+ $phar->setAlias('test');
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+try {
+ $b = new Phar(dirname(__FILE__) . '/nope.phar', 0, 'test');
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phartmp.php');
+unlink(dirname(__FILE__) . '/notphar.phar');
+__HALT_COMPILER();
+?>
+--EXPECTF--
+hio
+test
+alias "test" is already used for archive "%sphar_setalias2.phar.php" and cannot be used for other archives
+alias "test" is already used for archive "%sphar_setalias2.phar.php" cannot be overloaded with "%snope.phar"
+===DONE===
diff --git a/ext/phar/tests/phar_setdefaultstub.phpt b/ext/phar/tests/phar_setdefaultstub.phpt
new file mode 100644
index 0000000000..a36c005eac
--- /dev/null
+++ b/ext/phar/tests/phar_setdefaultstub.phpt
@@ -0,0 +1,944 @@
+--TEST--
+Phar: Phar::setDefaultStub() with and without arg
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar';
+
+$phar = new Phar($fname);
+$phar['a.php'] = '<php echo "this is a\n"; ?>';
+$phar['b.php'] = '<php echo "this is b\n"; ?>';
+$phar->setDefaultStub();
+$phar->stopBuffering();
+
+var_dump($phar->getStub());
+
+echo "============================================================================\n";
+echo "============================================================================\n";
+
+$phar->setDefaultStub('my/custom/thingy.php');
+$phar->stopBuffering();
+var_dump($phar->getStub());
+
+echo "============================================================================\n";
+echo "============================================================================\n";
+
+$phar->setDefaultStub('my/custom/thingy.php', 'the/web.php');
+$phar->stopBuffering();
+var_dump($phar->getStub());
+
+echo "============================================================================\n";
+echo "============================================================================\n";
+
+try {
+ $phar->setDefaultStub(str_repeat('a', 400));
+ $phar->stopBuffering();
+ var_dump(strlen($phar->getStub()));
+
+ $phar->setDefaultStub(str_repeat('a', 401));
+ $phar->stopBuffering();
+ var_dump(strlen($phar->getStub()));
+
+} catch(Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar');
+?>
+--EXPECT--
+string(6653) "<?php
+
+$web = 'index.php';
+
+if (in_array('phar', stream_get_wrappers()) && class_exists('Phar', 0)) {
+Phar::interceptFileFuncs();
+set_include_path('phar://' . __FILE__ . PATH_SEPARATOR . get_include_path());
+Phar::webPhar(null, $web);
+include 'phar://' . __FILE__ . '/' . Extract_Phar::START;
+return;
+}
+
+if (@(isset($_SERVER['REQUEST_URI']) && isset($_SERVER['REQUEST_METHOD']) && ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'POST'))) {
+Extract_Phar::go(true);
+$mimes = array(
+'phps' => 2,
+'c' => 'text/plain',
+'cc' => 'text/plain',
+'cpp' => 'text/plain',
+'c++' => 'text/plain',
+'dtd' => 'text/plain',
+'h' => 'text/plain',
+'log' => 'text/plain',
+'rng' => 'text/plain',
+'txt' => 'text/plain',
+'xsd' => 'text/plain',
+'php' => 1,
+'inc' => 1,
+'avi' => 'video/avi',
+'bmp' => 'image/bmp',
+'css' => 'text/css',
+'gif' => 'image/gif',
+'htm' => 'text/html',
+'html' => 'text/html',
+'htmls' => 'text/html',
+'ico' => 'image/x-ico',
+'jpe' => 'image/jpeg',
+'jpg' => 'image/jpeg',
+'jpeg' => 'image/jpeg',
+'js' => 'application/x-javascript',
+'midi' => 'audio/midi',
+'mid' => 'audio/midi',
+'mod' => 'audio/mod',
+'mov' => 'movie/quicktime',
+'mp3' => 'audio/mp3',
+'mpg' => 'video/mpeg',
+'mpeg' => 'video/mpeg',
+'pdf' => 'application/pdf',
+'png' => 'image/png',
+'swf' => 'application/shockwave-flash',
+'tif' => 'image/tiff',
+'tiff' => 'image/tiff',
+'wav' => 'audio/wav',
+'xbm' => 'image/xbm',
+'xml' => 'text/xml',
+);
+
+header("Cache-Control: no-cache, must-revalidate");
+header("Pragma: no-cache");
+
+$basename = basename(__FILE__);
+if (!strpos($_SERVER['REQUEST_URI'], $basename)) {
+chdir(Extract_Phar::$temp);
+include $web;
+return;
+}
+$pt = substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], $basename) + strlen($basename));
+if (!$pt || $pt == '/') {
+$pt = $web;
+header('HTTP/1.1 301 Moved Permanently');
+header('Location: ' . $_SERVER['REQUEST_URI'] . '/' . $pt);
+exit;
+}
+$a = realpath(Extract_Phar::$temp . DIRECTORY_SEPARATOR . $pt);
+if (!$a || strlen(dirname($a)) < strlen(Extract_Phar::$temp)) {
+header('HTTP/1.0 404 Not Found');
+echo "<html>\n <head>\n <title>File Not Found<title>\n </head>\n <body>\n <h1>404 - File ", $pt, " Not Found</h1>\n </body>\n</html>";
+exit;
+}
+$b = pathinfo($a);
+if (!isset($b['extension'])) {
+header('Content-Type: text/plain');
+header('Content-Length: ' . filesize($a));
+readfile($a);
+exit;
+}
+if (isset($mimes[$b['extension']])) {
+if ($mimes[$b['extension']] === 1) {
+include $a;
+exit;
+}
+if ($mimes[$b['extension']] === 2) {
+highlight_file($a);
+exit;
+}
+header('Content-Type: ' .$mimes[$b['extension']]);
+header('Content-Length: ' . filesize($a));
+readfile($a);
+exit;
+}
+}
+
+class Extract_Phar
+{
+static $temp;
+static $origdir;
+const GZ = 0x1000;
+const BZ2 = 0x2000;
+const MASK = 0x3000;
+const START = 'index.php';
+const LEN = 6653;
+
+static function go($return = false)
+{
+$fp = fopen(__FILE__, 'rb');
+fseek($fp, self::LEN);
+$L = unpack('V', $a = fread($fp, 4));
+$m = '';
+
+do {
+$read = 8192;
+if ($L[1] - strlen($m) < 8192) {
+$read = $L[1] - strlen($m);
+}
+$last = fread($fp, $read);
+$m .= $last;
+} while (strlen($last) && strlen($m) < $L[1]);
+
+if (strlen($m) < $L[1]) {
+die('ERROR: manifest length read was "' .
+strlen($m) .'" should be "' .
+$L[1] . '"');
+}
+
+$info = self::_unpack($m);
+$f = $info['c'];
+
+if ($f & self::GZ) {
+if (!function_exists('gzinflate')) {
+die('Error: zlib extension is not enabled -' .
+' gzinflate() function needed for zlib-compressed .phars');
+}
+}
+
+if ($f & self::BZ2) {
+if (!function_exists('bzdecompress')) {
+die('Error: bzip2 extension is not enabled -' .
+' bzdecompress() function needed for bz2-compressed .phars');
+}
+}
+
+$temp = self::tmpdir();
+
+if (!$temp || !is_writable($temp)) {
+$sessionpath = session_save_path();
+if (strpos ($sessionpath, ";") !== false)
+$sessionpath = substr ($sessionpath, strpos ($sessionpath, ";")+1);
+if (!file_exists($sessionpath) || !is_dir($sessionpath)) {
+die('Could not locate temporary directory to extract phar');
+}
+$temp = $sessionpath;
+}
+
+$temp .= '/pharextract/'.basename(__FILE__, '.phar');
+self::$temp = $temp;
+self::$origdir = getcwd();
+@mkdir($temp, 0777, true);
+$temp = realpath($temp);
+
+if (!file_exists($temp . DIRECTORY_SEPARATOR . md5_file(__FILE__))) {
+self::_removeTmpFiles($temp, getcwd());
+@mkdir($temp, 0777, true);
+@file_put_contents($temp . '/' . md5_file(__FILE__), '');
+
+foreach ($info['m'] as $path => $file) {
+$a = !file_exists(dirname($temp . '/' . $path));
+@mkdir(dirname($temp . '/' . $path), 0777, true);
+clearstatcache();
+
+if ($path[strlen($path) - 1] == '/') {
+@mkdir($temp . '/' . $path, 0777);
+} else {
+file_put_contents($temp . '/' . $path, self::extractFile($path, $file, $fp));
+@chmod($temp . '/' . $path, 0666);
+}
+}
+}
+
+chdir($temp);
+
+if (!$return) {
+include self::START;
+}
+}
+
+static function tmpdir()
+{
+if (strpos(PHP_OS, 'WIN') !== false) {
+if ($var = getenv('TMP') ? getenv('TMP') : getenv('TEMP')) {
+return $var;
+}
+if (is_dir('/temp') || mkdir('/temp')) {
+return realpath('/temp');
+}
+return false;
+}
+if ($var = getenv('TMPDIR')) {
+return $var;
+}
+return realpath('/tmp');
+}
+
+static function _unpack($m)
+{
+$info = unpack('V', substr($m, 0, 4));
+ $l = unpack('V', substr($m, 10, 4));
+$m = substr($m, 14 + $l[1]);
+$s = unpack('V', substr($m, 0, 4));
+$o = 0;
+$start = 4 + $s[1];
+$ret['c'] = 0;
+
+for ($i = 0; $i < $info[1]; $i++) {
+ $len = unpack('V', substr($m, $start, 4));
+$start += 4;
+ $savepath = substr($m, $start, $len[1]);
+$start += $len[1];
+ $ret['m'][$savepath] = array_values(unpack('Va/Vb/Vc/Vd/Ve/Vf', substr($m, $start, 24)));
+$ret['m'][$savepath][3] = sprintf('%u', $ret['m'][$savepath][3]
+& 0xffffffff);
+$ret['m'][$savepath][7] = $o;
+$o += $ret['m'][$savepath][2];
+$start += 24 + $ret['m'][$savepath][5];
+$ret['c'] |= $ret['m'][$savepath][4] & self::MASK;
+}
+return $ret;
+}
+
+static function extractFile($path, $entry, $fp)
+{
+$data = '';
+$c = $entry[2];
+
+while ($c) {
+if ($c < 8192) {
+$data .= @fread($fp, $c);
+$c = 0;
+} else {
+$c -= 8192;
+$data .= @fread($fp, 8192);
+}
+}
+
+if ($entry[4] & self::GZ) {
+$data = gzinflate($data);
+} elseif ($entry[4] & self::BZ2) {
+$data = bzdecompress($data);
+}
+
+if (strlen($data) != $entry[0]) {
+die("Invalid internal .phar file (size error " . strlen($data) . " != " .
+$stat[7] . ")");
+}
+
+if ($entry[3] != sprintf("%u", crc32($data) & 0xffffffff)) {
+die("Invalid internal .phar file (checksum error)");
+}
+
+return $data;
+}
+
+static function _removeTmpFiles($temp, $origdir)
+{
+chdir($temp);
+
+foreach (glob('*') as $f) {
+if (file_exists($f)) {
+is_dir($f) ? @rmdir($f) : @unlink($f);
+if (file_exists($f) && is_dir($f)) {
+self::_removeTmpFiles($f, getcwd());
+}
+}
+}
+
+@rmdir($temp);
+clearstatcache();
+chdir($origdir);
+}
+}
+
+Extract_Phar::go();
+__HALT_COMPILER(); ?>
+"
+============================================================================
+============================================================================
+string(6664) "<?php
+
+$web = 'index.php';
+
+if (in_array('phar', stream_get_wrappers()) && class_exists('Phar', 0)) {
+Phar::interceptFileFuncs();
+set_include_path('phar://' . __FILE__ . PATH_SEPARATOR . get_include_path());
+Phar::webPhar(null, $web);
+include 'phar://' . __FILE__ . '/' . Extract_Phar::START;
+return;
+}
+
+if (@(isset($_SERVER['REQUEST_URI']) && isset($_SERVER['REQUEST_METHOD']) && ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'POST'))) {
+Extract_Phar::go(true);
+$mimes = array(
+'phps' => 2,
+'c' => 'text/plain',
+'cc' => 'text/plain',
+'cpp' => 'text/plain',
+'c++' => 'text/plain',
+'dtd' => 'text/plain',
+'h' => 'text/plain',
+'log' => 'text/plain',
+'rng' => 'text/plain',
+'txt' => 'text/plain',
+'xsd' => 'text/plain',
+'php' => 1,
+'inc' => 1,
+'avi' => 'video/avi',
+'bmp' => 'image/bmp',
+'css' => 'text/css',
+'gif' => 'image/gif',
+'htm' => 'text/html',
+'html' => 'text/html',
+'htmls' => 'text/html',
+'ico' => 'image/x-ico',
+'jpe' => 'image/jpeg',
+'jpg' => 'image/jpeg',
+'jpeg' => 'image/jpeg',
+'js' => 'application/x-javascript',
+'midi' => 'audio/midi',
+'mid' => 'audio/midi',
+'mod' => 'audio/mod',
+'mov' => 'movie/quicktime',
+'mp3' => 'audio/mp3',
+'mpg' => 'video/mpeg',
+'mpeg' => 'video/mpeg',
+'pdf' => 'application/pdf',
+'png' => 'image/png',
+'swf' => 'application/shockwave-flash',
+'tif' => 'image/tiff',
+'tiff' => 'image/tiff',
+'wav' => 'audio/wav',
+'xbm' => 'image/xbm',
+'xml' => 'text/xml',
+);
+
+header("Cache-Control: no-cache, must-revalidate");
+header("Pragma: no-cache");
+
+$basename = basename(__FILE__);
+if (!strpos($_SERVER['REQUEST_URI'], $basename)) {
+chdir(Extract_Phar::$temp);
+include $web;
+return;
+}
+$pt = substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], $basename) + strlen($basename));
+if (!$pt || $pt == '/') {
+$pt = $web;
+header('HTTP/1.1 301 Moved Permanently');
+header('Location: ' . $_SERVER['REQUEST_URI'] . '/' . $pt);
+exit;
+}
+$a = realpath(Extract_Phar::$temp . DIRECTORY_SEPARATOR . $pt);
+if (!$a || strlen(dirname($a)) < strlen(Extract_Phar::$temp)) {
+header('HTTP/1.0 404 Not Found');
+echo "<html>\n <head>\n <title>File Not Found<title>\n </head>\n <body>\n <h1>404 - File ", $pt, " Not Found</h1>\n </body>\n</html>";
+exit;
+}
+$b = pathinfo($a);
+if (!isset($b['extension'])) {
+header('Content-Type: text/plain');
+header('Content-Length: ' . filesize($a));
+readfile($a);
+exit;
+}
+if (isset($mimes[$b['extension']])) {
+if ($mimes[$b['extension']] === 1) {
+include $a;
+exit;
+}
+if ($mimes[$b['extension']] === 2) {
+highlight_file($a);
+exit;
+}
+header('Content-Type: ' .$mimes[$b['extension']]);
+header('Content-Length: ' . filesize($a));
+readfile($a);
+exit;
+}
+}
+
+class Extract_Phar
+{
+static $temp;
+static $origdir;
+const GZ = 0x1000;
+const BZ2 = 0x2000;
+const MASK = 0x3000;
+const START = 'my/custom/thingy.php';
+const LEN = 6664;
+
+static function go($return = false)
+{
+$fp = fopen(__FILE__, 'rb');
+fseek($fp, self::LEN);
+$L = unpack('V', $a = fread($fp, 4));
+$m = '';
+
+do {
+$read = 8192;
+if ($L[1] - strlen($m) < 8192) {
+$read = $L[1] - strlen($m);
+}
+$last = fread($fp, $read);
+$m .= $last;
+} while (strlen($last) && strlen($m) < $L[1]);
+
+if (strlen($m) < $L[1]) {
+die('ERROR: manifest length read was "' .
+strlen($m) .'" should be "' .
+$L[1] . '"');
+}
+
+$info = self::_unpack($m);
+$f = $info['c'];
+
+if ($f & self::GZ) {
+if (!function_exists('gzinflate')) {
+die('Error: zlib extension is not enabled -' .
+' gzinflate() function needed for zlib-compressed .phars');
+}
+}
+
+if ($f & self::BZ2) {
+if (!function_exists('bzdecompress')) {
+die('Error: bzip2 extension is not enabled -' .
+' bzdecompress() function needed for bz2-compressed .phars');
+}
+}
+
+$temp = self::tmpdir();
+
+if (!$temp || !is_writable($temp)) {
+$sessionpath = session_save_path();
+if (strpos ($sessionpath, ";") !== false)
+$sessionpath = substr ($sessionpath, strpos ($sessionpath, ";")+1);
+if (!file_exists($sessionpath) || !is_dir($sessionpath)) {
+die('Could not locate temporary directory to extract phar');
+}
+$temp = $sessionpath;
+}
+
+$temp .= '/pharextract/'.basename(__FILE__, '.phar');
+self::$temp = $temp;
+self::$origdir = getcwd();
+@mkdir($temp, 0777, true);
+$temp = realpath($temp);
+
+if (!file_exists($temp . DIRECTORY_SEPARATOR . md5_file(__FILE__))) {
+self::_removeTmpFiles($temp, getcwd());
+@mkdir($temp, 0777, true);
+@file_put_contents($temp . '/' . md5_file(__FILE__), '');
+
+foreach ($info['m'] as $path => $file) {
+$a = !file_exists(dirname($temp . '/' . $path));
+@mkdir(dirname($temp . '/' . $path), 0777, true);
+clearstatcache();
+
+if ($path[strlen($path) - 1] == '/') {
+@mkdir($temp . '/' . $path, 0777);
+} else {
+file_put_contents($temp . '/' . $path, self::extractFile($path, $file, $fp));
+@chmod($temp . '/' . $path, 0666);
+}
+}
+}
+
+chdir($temp);
+
+if (!$return) {
+include self::START;
+}
+}
+
+static function tmpdir()
+{
+if (strpos(PHP_OS, 'WIN') !== false) {
+if ($var = getenv('TMP') ? getenv('TMP') : getenv('TEMP')) {
+return $var;
+}
+if (is_dir('/temp') || mkdir('/temp')) {
+return realpath('/temp');
+}
+return false;
+}
+if ($var = getenv('TMPDIR')) {
+return $var;
+}
+return realpath('/tmp');
+}
+
+static function _unpack($m)
+{
+$info = unpack('V', substr($m, 0, 4));
+ $l = unpack('V', substr($m, 10, 4));
+$m = substr($m, 14 + $l[1]);
+$s = unpack('V', substr($m, 0, 4));
+$o = 0;
+$start = 4 + $s[1];
+$ret['c'] = 0;
+
+for ($i = 0; $i < $info[1]; $i++) {
+ $len = unpack('V', substr($m, $start, 4));
+$start += 4;
+ $savepath = substr($m, $start, $len[1]);
+$start += $len[1];
+ $ret['m'][$savepath] = array_values(unpack('Va/Vb/Vc/Vd/Ve/Vf', substr($m, $start, 24)));
+$ret['m'][$savepath][3] = sprintf('%u', $ret['m'][$savepath][3]
+& 0xffffffff);
+$ret['m'][$savepath][7] = $o;
+$o += $ret['m'][$savepath][2];
+$start += 24 + $ret['m'][$savepath][5];
+$ret['c'] |= $ret['m'][$savepath][4] & self::MASK;
+}
+return $ret;
+}
+
+static function extractFile($path, $entry, $fp)
+{
+$data = '';
+$c = $entry[2];
+
+while ($c) {
+if ($c < 8192) {
+$data .= @fread($fp, $c);
+$c = 0;
+} else {
+$c -= 8192;
+$data .= @fread($fp, 8192);
+}
+}
+
+if ($entry[4] & self::GZ) {
+$data = gzinflate($data);
+} elseif ($entry[4] & self::BZ2) {
+$data = bzdecompress($data);
+}
+
+if (strlen($data) != $entry[0]) {
+die("Invalid internal .phar file (size error " . strlen($data) . " != " .
+$stat[7] . ")");
+}
+
+if ($entry[3] != sprintf("%u", crc32($data) & 0xffffffff)) {
+die("Invalid internal .phar file (checksum error)");
+}
+
+return $data;
+}
+
+static function _removeTmpFiles($temp, $origdir)
+{
+chdir($temp);
+
+foreach (glob('*') as $f) {
+if (file_exists($f)) {
+is_dir($f) ? @rmdir($f) : @unlink($f);
+if (file_exists($f) && is_dir($f)) {
+self::_removeTmpFiles($f, getcwd());
+}
+}
+}
+
+@rmdir($temp);
+clearstatcache();
+chdir($origdir);
+}
+}
+
+Extract_Phar::go();
+__HALT_COMPILER(); ?>
+"
+============================================================================
+============================================================================
+string(6666) "<?php
+
+$web = 'the/web.php';
+
+if (in_array('phar', stream_get_wrappers()) && class_exists('Phar', 0)) {
+Phar::interceptFileFuncs();
+set_include_path('phar://' . __FILE__ . PATH_SEPARATOR . get_include_path());
+Phar::webPhar(null, $web);
+include 'phar://' . __FILE__ . '/' . Extract_Phar::START;
+return;
+}
+
+if (@(isset($_SERVER['REQUEST_URI']) && isset($_SERVER['REQUEST_METHOD']) && ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'POST'))) {
+Extract_Phar::go(true);
+$mimes = array(
+'phps' => 2,
+'c' => 'text/plain',
+'cc' => 'text/plain',
+'cpp' => 'text/plain',
+'c++' => 'text/plain',
+'dtd' => 'text/plain',
+'h' => 'text/plain',
+'log' => 'text/plain',
+'rng' => 'text/plain',
+'txt' => 'text/plain',
+'xsd' => 'text/plain',
+'php' => 1,
+'inc' => 1,
+'avi' => 'video/avi',
+'bmp' => 'image/bmp',
+'css' => 'text/css',
+'gif' => 'image/gif',
+'htm' => 'text/html',
+'html' => 'text/html',
+'htmls' => 'text/html',
+'ico' => 'image/x-ico',
+'jpe' => 'image/jpeg',
+'jpg' => 'image/jpeg',
+'jpeg' => 'image/jpeg',
+'js' => 'application/x-javascript',
+'midi' => 'audio/midi',
+'mid' => 'audio/midi',
+'mod' => 'audio/mod',
+'mov' => 'movie/quicktime',
+'mp3' => 'audio/mp3',
+'mpg' => 'video/mpeg',
+'mpeg' => 'video/mpeg',
+'pdf' => 'application/pdf',
+'png' => 'image/png',
+'swf' => 'application/shockwave-flash',
+'tif' => 'image/tiff',
+'tiff' => 'image/tiff',
+'wav' => 'audio/wav',
+'xbm' => 'image/xbm',
+'xml' => 'text/xml',
+);
+
+header("Cache-Control: no-cache, must-revalidate");
+header("Pragma: no-cache");
+
+$basename = basename(__FILE__);
+if (!strpos($_SERVER['REQUEST_URI'], $basename)) {
+chdir(Extract_Phar::$temp);
+include $web;
+return;
+}
+$pt = substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], $basename) + strlen($basename));
+if (!$pt || $pt == '/') {
+$pt = $web;
+header('HTTP/1.1 301 Moved Permanently');
+header('Location: ' . $_SERVER['REQUEST_URI'] . '/' . $pt);
+exit;
+}
+$a = realpath(Extract_Phar::$temp . DIRECTORY_SEPARATOR . $pt);
+if (!$a || strlen(dirname($a)) < strlen(Extract_Phar::$temp)) {
+header('HTTP/1.0 404 Not Found');
+echo "<html>\n <head>\n <title>File Not Found<title>\n </head>\n <body>\n <h1>404 - File ", $pt, " Not Found</h1>\n </body>\n</html>";
+exit;
+}
+$b = pathinfo($a);
+if (!isset($b['extension'])) {
+header('Content-Type: text/plain');
+header('Content-Length: ' . filesize($a));
+readfile($a);
+exit;
+}
+if (isset($mimes[$b['extension']])) {
+if ($mimes[$b['extension']] === 1) {
+include $a;
+exit;
+}
+if ($mimes[$b['extension']] === 2) {
+highlight_file($a);
+exit;
+}
+header('Content-Type: ' .$mimes[$b['extension']]);
+header('Content-Length: ' . filesize($a));
+readfile($a);
+exit;
+}
+}
+
+class Extract_Phar
+{
+static $temp;
+static $origdir;
+const GZ = 0x1000;
+const BZ2 = 0x2000;
+const MASK = 0x3000;
+const START = 'my/custom/thingy.php';
+const LEN = 6666;
+
+static function go($return = false)
+{
+$fp = fopen(__FILE__, 'rb');
+fseek($fp, self::LEN);
+$L = unpack('V', $a = fread($fp, 4));
+$m = '';
+
+do {
+$read = 8192;
+if ($L[1] - strlen($m) < 8192) {
+$read = $L[1] - strlen($m);
+}
+$last = fread($fp, $read);
+$m .= $last;
+} while (strlen($last) && strlen($m) < $L[1]);
+
+if (strlen($m) < $L[1]) {
+die('ERROR: manifest length read was "' .
+strlen($m) .'" should be "' .
+$L[1] . '"');
+}
+
+$info = self::_unpack($m);
+$f = $info['c'];
+
+if ($f & self::GZ) {
+if (!function_exists('gzinflate')) {
+die('Error: zlib extension is not enabled -' .
+' gzinflate() function needed for zlib-compressed .phars');
+}
+}
+
+if ($f & self::BZ2) {
+if (!function_exists('bzdecompress')) {
+die('Error: bzip2 extension is not enabled -' .
+' bzdecompress() function needed for bz2-compressed .phars');
+}
+}
+
+$temp = self::tmpdir();
+
+if (!$temp || !is_writable($temp)) {
+$sessionpath = session_save_path();
+if (strpos ($sessionpath, ";") !== false)
+$sessionpath = substr ($sessionpath, strpos ($sessionpath, ";")+1);
+if (!file_exists($sessionpath) || !is_dir($sessionpath)) {
+die('Could not locate temporary directory to extract phar');
+}
+$temp = $sessionpath;
+}
+
+$temp .= '/pharextract/'.basename(__FILE__, '.phar');
+self::$temp = $temp;
+self::$origdir = getcwd();
+@mkdir($temp, 0777, true);
+$temp = realpath($temp);
+
+if (!file_exists($temp . DIRECTORY_SEPARATOR . md5_file(__FILE__))) {
+self::_removeTmpFiles($temp, getcwd());
+@mkdir($temp, 0777, true);
+@file_put_contents($temp . '/' . md5_file(__FILE__), '');
+
+foreach ($info['m'] as $path => $file) {
+$a = !file_exists(dirname($temp . '/' . $path));
+@mkdir(dirname($temp . '/' . $path), 0777, true);
+clearstatcache();
+
+if ($path[strlen($path) - 1] == '/') {
+@mkdir($temp . '/' . $path, 0777);
+} else {
+file_put_contents($temp . '/' . $path, self::extractFile($path, $file, $fp));
+@chmod($temp . '/' . $path, 0666);
+}
+}
+}
+
+chdir($temp);
+
+if (!$return) {
+include self::START;
+}
+}
+
+static function tmpdir()
+{
+if (strpos(PHP_OS, 'WIN') !== false) {
+if ($var = getenv('TMP') ? getenv('TMP') : getenv('TEMP')) {
+return $var;
+}
+if (is_dir('/temp') || mkdir('/temp')) {
+return realpath('/temp');
+}
+return false;
+}
+if ($var = getenv('TMPDIR')) {
+return $var;
+}
+return realpath('/tmp');
+}
+
+static function _unpack($m)
+{
+$info = unpack('V', substr($m, 0, 4));
+ $l = unpack('V', substr($m, 10, 4));
+$m = substr($m, 14 + $l[1]);
+$s = unpack('V', substr($m, 0, 4));
+$o = 0;
+$start = 4 + $s[1];
+$ret['c'] = 0;
+
+for ($i = 0; $i < $info[1]; $i++) {
+ $len = unpack('V', substr($m, $start, 4));
+$start += 4;
+ $savepath = substr($m, $start, $len[1]);
+$start += $len[1];
+ $ret['m'][$savepath] = array_values(unpack('Va/Vb/Vc/Vd/Ve/Vf', substr($m, $start, 24)));
+$ret['m'][$savepath][3] = sprintf('%u', $ret['m'][$savepath][3]
+& 0xffffffff);
+$ret['m'][$savepath][7] = $o;
+$o += $ret['m'][$savepath][2];
+$start += 24 + $ret['m'][$savepath][5];
+$ret['c'] |= $ret['m'][$savepath][4] & self::MASK;
+}
+return $ret;
+}
+
+static function extractFile($path, $entry, $fp)
+{
+$data = '';
+$c = $entry[2];
+
+while ($c) {
+if ($c < 8192) {
+$data .= @fread($fp, $c);
+$c = 0;
+} else {
+$c -= 8192;
+$data .= @fread($fp, 8192);
+}
+}
+
+if ($entry[4] & self::GZ) {
+$data = gzinflate($data);
+} elseif ($entry[4] & self::BZ2) {
+$data = bzdecompress($data);
+}
+
+if (strlen($data) != $entry[0]) {
+die("Invalid internal .phar file (size error " . strlen($data) . " != " .
+$stat[7] . ")");
+}
+
+if ($entry[3] != sprintf("%u", crc32($data) & 0xffffffff)) {
+die("Invalid internal .phar file (checksum error)");
+}
+
+return $data;
+}
+
+static function _removeTmpFiles($temp, $origdir)
+{
+chdir($temp);
+
+foreach (glob('*') as $f) {
+if (file_exists($f)) {
+is_dir($f) ? @rmdir($f) : @unlink($f);
+if (file_exists($f) && is_dir($f)) {
+self::_removeTmpFiles($f, getcwd());
+}
+}
+}
+
+@rmdir($temp);
+clearstatcache();
+chdir($origdir);
+}
+}
+
+Extract_Phar::go();
+__HALT_COMPILER(); ?>
+"
+============================================================================
+============================================================================
+int(7044)
+Illegal filename passed in for stub creation, was 401 characters long, and only 400 or less is allowed
+===DONE===
diff --git a/ext/phar/tests/phar_setsignaturealgo1.phpt b/ext/phar/tests/phar_setsignaturealgo1.phpt
new file mode 100644
index 0000000000..edc032e7be
--- /dev/null
+++ b/ext/phar/tests/phar_setsignaturealgo1.phpt
@@ -0,0 +1,69 @@
+--TEST--
+Phar::setSignatureAlgorithm()
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if ( extension_loaded("hash")) die("skip extension hash conflicts"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+$p = new Phar(dirname(__FILE__) . '/brandnewphar.phar', 0, 'brandnewphar.phar');
+$p['file1.txt'] = 'hi';
+var_dump($p->getSignature());
+$p->setSignatureAlgorithm(Phar::MD5);
+var_dump($p->getSignature());
+$p->setSignatureAlgorithm(Phar::SHA1);
+var_dump($p->getSignature());
+try {
+$p->setSignatureAlgorithm(Phar::SHA256);
+var_dump($p->getSignature());
+} catch (Exception $e) {
+echo $e->getMessage();
+}
+try {
+$p->setSignatureAlgorithm(Phar::SHA512);
+var_dump($p->getSignature());
+} catch (Exception $e) {
+echo $e->getMessage();
+}
+try {
+$p->setSignatureAlgorithm(Phar::PGP);
+var_dump($p->getSignature());
+} catch (Exception $e) {
+echo $e->getMessage();
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/brandnewphar.phar');
+?>
+--EXPECTF--
+array(2) {
+ ["hash"]=>
+ string(%d) "%s"
+ ["hash_type"]=>
+ string(5) "SHA-1"
+}
+array(2) {
+ ["hash"]=>
+ string(%d) "%s"
+ ["hash_type"]=>
+ string(3) "MD5"
+}
+array(2) {
+ ["hash"]=>
+ string(%d) "%s"
+ ["hash_type"]=>
+ string(5) "SHA-1"
+}
+string (82) "SHA-256 and SHA-512 signatures are only supported if the hash extension is enabled"
+string (82) "SHA-256 and SHA-512 signatures are only supported if the hash extension is enabled"
+array(2) {
+ ["hash"]=>
+ string(%d) "%s"
+ ["hash_type"]=>
+ string(5) "SHA-1"
+}
+===DONE===
diff --git a/ext/phar/tests/phar_setsignaturealgo2.phpt b/ext/phar/tests/phar_setsignaturealgo2.phpt
new file mode 100644
index 0000000000..cc83281b22
--- /dev/null
+++ b/ext/phar/tests/phar_setsignaturealgo2.phpt
@@ -0,0 +1,79 @@
+--TEST--
+Phar::setSupportedSignatures() with hash
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("hash")) die("skip extension hash required"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+$p = new Phar(dirname(__FILE__) . '/brandnewphar.phar', 0, 'brandnewphar.phar');
+$p['file1.txt'] = 'hi';
+var_dump($p->getSignature());
+$p->setSignatureAlgorithm(Phar::MD5);
+var_dump($p->getSignature());
+$p->setSignatureAlgorithm(Phar::SHA1);
+var_dump($p->getSignature());
+try {
+$p->setSignatureAlgorithm(Phar::SHA256);
+var_dump($p->getSignature());
+} catch (Exception $e) {
+echo $e->getMessage();
+}
+try {
+$p->setSignatureAlgorithm(Phar::SHA512);
+var_dump($p->getSignature());
+} catch (Exception $e) {
+echo $e->getMessage();
+}
+try {
+$p->setSignatureAlgorithm(Phar::PGP);
+var_dump($p->getSignature());
+} catch (Exception $e) {
+echo $e->getMessage();
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/brandnewphar.phar');
+?>
+--EXPECTF--
+array(2) {
+ ["hash"]=>
+ string(%d) "%s"
+ ["hash_type"]=>
+ string(5) "SHA-1"
+}
+array(2) {
+ ["hash"]=>
+ string(%d) "%s"
+ ["hash_type"]=>
+ string(3) "MD5"
+}
+array(2) {
+ ["hash"]=>
+ string(%d) "%s"
+ ["hash_type"]=>
+ string(5) "SHA-1"
+}
+array(2) {
+ ["hash"]=>
+ string(%d) "%s"
+ ["hash_type"]=>
+ string(7) "SHA-256"
+}
+array(2) {
+ ["hash"]=>
+ string(%d) "%s"
+ ["hash_type"]=>
+ string(7) "SHA-512"
+}
+array(2) {
+ ["hash"]=>
+ string(%d) "%s"
+ ["hash_type"]=>
+ string(5) "SHA-1"
+}
+===DONE===
diff --git a/ext/phar/tests/phar_stub.phpt b/ext/phar/tests/phar_stub.phpt
new file mode 100644
index 0000000000..ed306816e2
--- /dev/null
+++ b/ext/phar/tests/phar_stub.phpt
@@ -0,0 +1,92 @@
+--TEST--
+Phar::setStub()
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = '<?php echo "first stub\n"; __HALT_COMPILER(); ?>';
+
+$files = array();
+$files['a'] = 'a';
+$files['b'] = 'b';
+$files['c'] = 'c';
+
+include 'files/phar_test.inc';
+
+$file = '<?php echo "first stub\n"; __HALT_COMPILER(); ?>';
+$fp = fopen($fname, 'rb');
+//// 1
+echo fread($fp, strlen($file)) . "\n";
+fclose($fp);
+$phar = new Phar($fname);
+$file = '<?php echo "second stub\n"; __HALT_COMPILER(); ?>';
+
+//// 2
+$phar->setStub($file);
+$fp = fopen($fname, 'rb');
+echo fread($fp, strlen($file)) . "\n";
+fclose($fp);
+
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phartmp.php';
+$file = '<?php echo "third stub\n"; __HALT_COMPILER(); ?>';
+$fp = fopen($fname2, 'wb');
+fwrite($fp, $file);
+fclose($fp);
+$fp = fopen($fname2, 'rb');
+
+//// 3
+$phar->setStub($fp);
+fclose($fp);
+
+$fp = fopen($fname, 'rb');
+echo fread($fp, strlen($file)) . "\n";
+fclose($fp);
+
+$fp = fopen($fname2, 'ab');
+fwrite($fp, 'booya');
+fclose($fp);
+echo file_get_contents($fname2) . "\n";
+
+$fp = fopen($fname2, 'rb');
+
+//// 4
+$phar->setStub($fp, strlen($file));
+fclose($fp);
+
+$fp = fopen($fname, 'rb');
+echo fread($fp, strlen($file)) . "\n";
+if (fread($fp, strlen('booya')) == 'booya') {
+ echo 'failed - copied booya';
+}
+fclose($fp);
+$phar['testing'] = 'hi';
+
+// ensure stub is not overwritten
+$fp = fopen($fname, 'rb');
+echo fread($fp, strlen($file)) . "\n";
+if (fread($fp, strlen('booya')) == 'booya') {
+ echo 'failed - copied booya';
+}
+fclose($fp);
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phartmp.php');
+__HALT_COMPILER();
+?>
+--EXPECT--
+<?php echo "first stub\n"; __HALT_COMPILER(); ?>
+<?php echo "second stub\n"; __HALT_COMPILER(); ?>
+<?php echo "third stub\n"; __HALT_COMPILER(); ?>
+<?php echo "third stub\n"; __HALT_COMPILER(); ?>booya
+<?php echo "third stub\n"; __HALT_COMPILER(); ?>
+<?php echo "third stub\n"; __HALT_COMPILER(); ?>
+===DONE===
diff --git a/ext/phar/tests/phar_stub_error.phpt b/ext/phar/tests/phar_stub_error.phpt
new file mode 100755
index 0000000000..99f313bc2f
--- /dev/null
+++ b/ext/phar/tests/phar_stub_error.phpt
@@ -0,0 +1,56 @@
+--TEST--
+Phar::setStub()/getStub()
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$stub = '<?php echo "first stub\n"; __HALT_COMPILER(); ?>';
+$file = $stub;
+
+$files = array();
+$files['a'] = 'a';
+
+include 'files/phar_test.inc';
+
+$phar = new Phar($fname);
+var_dump($stub);
+var_dump($phar->getStub());
+var_dump($phar->getStub() == $stub);
+
+$newstub = '<?php echo "second stub\n"; _x_HALT_COMPILER(); ?>';
+try
+{
+ $phar->setStub($newstub);
+}
+catch(exception $e)
+{
+ echo 'Exception: ' . $e->getMessage() . "\n";
+}
+var_dump($phar->getStub());
+var_dump($phar->getStub() == $stub);
+$phar->stopBuffering();
+var_dump($phar->getStub());
+var_dump($phar->getStub() == $stub);
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php');
+__HALT_COMPILER();
+?>
+--EXPECTF--
+string(48) "<?php echo "first stub\n"; __HALT_COMPILER(); ?>"
+string(48) "<?php echo "first stub\n"; __HALT_COMPILER(); ?>"
+bool(true)
+Exception: illegal stub for phar "%sphar_stub_error.phar.php"
+string(48) "<?php echo "first stub\n"; __HALT_COMPILER(); ?>"
+bool(true)
+string(48) "<?php echo "first stub\n"; __HALT_COMPILER(); ?>"
+bool(true)
+===DONE===
diff --git a/ext/phar/tests/phar_stub_write.phpt b/ext/phar/tests/phar_stub_write.phpt
new file mode 100755
index 0000000000..9e5d6d5635
--- /dev/null
+++ b/ext/phar/tests/phar_stub_write.phpt
@@ -0,0 +1,64 @@
+--TEST--
+Phar::setStub()/getStub()
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$stub = '<?php echo "first stub\n"; __HALT_COMPILER(); ?>';
+$file = $stub;
+
+$files = array();
+$files['a'] = 'a';
+$files['b'] = 'b';
+$files['c'] = 'c';
+
+include 'files/phar_test.inc';
+
+$phar = new Phar($fname);
+var_dump($stub);
+var_dump($phar->getStub());
+var_dump($phar->getStub() == $stub);
+
+$stub = '<?php echo "second stub\n"; __HALT_COMPILER(); ?>';
+$sexp = $stub . "\r\n";
+
+$phar->setStub($stub);
+var_dump($phar->getStub());
+var_dump($phar->getStub() == $stub);
+var_dump($phar->getStub() == $sexp);
+$phar->stopBuffering();
+var_dump($phar->getStub());
+var_dump($phar->getStub() == $stub);
+var_dump($phar->getStub() == $sexp);
+
+$phar = new Phar($fname);
+var_dump($phar->getStub() == $stub);
+var_dump($phar->getStub() == $sexp);
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php');
+__HALT_COMPILER();
+?>
+--EXPECT--
+string(48) "<?php echo "first stub\n"; __HALT_COMPILER(); ?>"
+string(48) "<?php echo "first stub\n"; __HALT_COMPILER(); ?>"
+bool(true)
+string(51) "<?php echo "second stub\n"; __HALT_COMPILER(); ?>
+"
+bool(false)
+bool(true)
+string(51) "<?php echo "second stub\n"; __HALT_COMPILER(); ?>
+"
+bool(false)
+bool(true)
+bool(false)
+bool(true)
+===DONE===
diff --git a/ext/phar/tests/phar_stub_write_file.phpt b/ext/phar/tests/phar_stub_write_file.phpt
new file mode 100755
index 0000000000..c5a0a1eba9
--- /dev/null
+++ b/ext/phar/tests/phar_stub_write_file.phpt
@@ -0,0 +1,65 @@
+--TEST--
+Phar::setStub()/getStub() from file
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+allow_url_fopen=1
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$stub = '<?php echo "first stub\n"; __HALT_COMPILER(); ?>';
+$file = $stub;
+
+$files = array();
+$files['a'] = 'a';
+$files['b'] = 'b';
+$files['c'] = 'c';
+
+include 'files/phar_test.inc';
+
+$phar = new Phar($fname);
+var_dump($stub);
+var_dump($phar->getStub());
+var_dump($phar->getStub() == $stub);
+
+$stub = '<?php echo "second stub\n"; __HALT_COMPILER(); ?>';
+$sexp = $stub . "\r\n";
+$stub = fopen('data://,'.$stub, 'r');
+$phar->setStub($stub);
+var_dump($phar->getStub());
+var_dump($phar->getStub() == $stub);
+var_dump($phar->getStub() == $sexp);
+$phar->stopBuffering();
+var_dump($phar->getStub());
+var_dump($phar->getStub() == $stub);
+var_dump($phar->getStub() == $sexp);
+
+$phar = new Phar($fname);
+var_dump($phar->getStub() == $stub);
+var_dump($phar->getStub() == $sexp);
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php');
+__HALT_COMPILER();
+?>
+--EXPECT--
+string(48) "<?php echo "first stub\n"; __HALT_COMPILER(); ?>"
+string(48) "<?php echo "first stub\n"; __HALT_COMPILER(); ?>"
+bool(true)
+string(51) "<?php echo "second stub\n"; __HALT_COMPILER(); ?>
+"
+bool(false)
+bool(true)
+string(51) "<?php echo "second stub\n"; __HALT_COMPILER(); ?>
+"
+bool(false)
+bool(true)
+bool(false)
+bool(true)
+===DONE===
diff --git a/ext/phar/tests/phar_unlinkarchive.phpt b/ext/phar/tests/phar_unlinkarchive.phpt
new file mode 100644
index 0000000000..910ef873d2
--- /dev/null
+++ b/ext/phar/tests/phar_unlinkarchive.phpt
@@ -0,0 +1,108 @@
+--TEST--
+Phar::unlinkArchive()
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+
+try {
+Phar::unlinkArchive("");
+} catch (Exception $e) {
+echo $e->getMessage(),"\n";
+}
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar';
+$pdname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar';
+
+try {
+Phar::unlinkArchive($fname);
+} catch (Exception $e) {
+echo $e->getMessage(),"\n";
+}
+file_put_contents($pdname, 'blahblah');
+try {
+Phar::unlinkArchive($pdname);
+} catch (Exception $e) {
+echo $e->getMessage(),"\n";
+}
+Phar::unlinkArchive(array());
+
+$pname = 'phar://' . $fname;
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.zip';
+$fname3 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.2.phar.zip';
+$stub = '<?php echo "first stub\n"; __HALT_COMPILER(); ?>';
+$file = $stub;
+
+$files = array();
+$files['a'] = 'a';
+$files['b'] = 'b';
+$files['c'] = 'c';
+
+include 'files/phar_test.inc';
+
+$phar = new Phar($fname);
+var_dump($phar->isFileFormat(Phar::ZIP));
+var_dump($phar->getStub());
+try {
+Phar::unlinkArchive($fname);
+} catch (Exception $e) {
+echo $e->getMessage(),"\n";
+}
+$phar = $phar->convertToExecutable(Phar::ZIP);
+var_dump($phar->isFileFormat(Phar::ZIP));
+var_dump($phar->getStub());
+
+copy($fname2, $fname3);
+
+$phar = new Phar($fname3);
+var_dump($phar->isFileFormat(Phar::ZIP));
+var_dump($phar->getStub());
+
+Phar::unlinkArchive($fname);
+var_dump(file_exists($fname));
+$phar = new Phar($fname);
+var_dump(count($phar));
+$phar['evil.php'] = '<?php
+try {
+Phar::unlinkArchive(Phar::running(false));
+} catch (Exception $e) {echo $e->getMessage(),"\n";}
+var_dump(Phar::running(false));
+include Phar::running(true) . "/another.php";
+?>';
+$phar['another.php'] = "hi\n";
+unset($phar);
+include $pname . '/evil.php';
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.2.phar.zip');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.zip');
+__HALT_COMPILER();
+?>
+--EXPECTF--
+Unknown phar archive ""
+Unknown phar archive "%sphar_unlinkarchive.phar"
+Unknown phar archive "%sphar_unlinkarchive.phar.tar": internal corruption of phar "%sphar_unlinkarchive.phar.tar" (truncated entry)
+
+Warning: Phar::unlinkArchive() expects parameter 1 to be string, array given in %sphar_unlinkarchive.php on line %d
+bool(false)
+string(48) "<?php echo "first stub\n"; __HALT_COMPILER(); ?>"
+phar archive "%sphar_unlinkarchive.phar" has open file handles or objects. fclose() all file handles, and unset() all objects prior to calling unlinkArchive()
+bool(true)
+string(60) "<?php // zip-based phar archive stub file
+__HALT_COMPILER();"
+bool(true)
+string(60) "<?php // zip-based phar archive stub file
+__HALT_COMPILER();"
+bool(false)
+int(0)
+phar archive "%sphar_unlinkarchive.phar" cannot be unlinked from within itself
+string(%d) "%sphar_unlinkarchive.phar"
+hi
+===DONE===
diff --git a/ext/phar/tests/pharfileinfo_chmod.phpt b/ext/phar/tests/pharfileinfo_chmod.phpt
new file mode 100644
index 0000000000..e99be5d6b9
--- /dev/null
+++ b/ext/phar/tests/pharfileinfo_chmod.phpt
@@ -0,0 +1,33 @@
+--TEST--
+Phar: PharFileInfo::chmod extra code coverage
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar';
+$pname = 'phar://' . $fname;
+
+$phar = new Phar($fname);
+
+$phar['a/b'] = 'hi there';
+
+$b = $phar['a/b'];
+try {
+$phar['a']->chmod(066);
+} catch (Exception $e) {
+echo $e->getMessage(), "\n";
+}
+$b->chmod(array());
+lstat($pname . '/a/b'); // sets BG(CurrentLStatFile)
+$b->chmod(0666);
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar'); ?>
+--EXPECTF--
+Phar entry "a" is a temporary directory (not an actual entry in the archive), cannot chmod
+
+Warning: PharFileInfo::chmod() expects parameter 1 to be long, array given in %spharfileinfo_chmod.php on line %d
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/pharfileinfo_compression.phpt b/ext/phar/tests/pharfileinfo_compression.phpt
new file mode 100644
index 0000000000..fbac499127
--- /dev/null
+++ b/ext/phar/tests/pharfileinfo_compression.phpt
@@ -0,0 +1,94 @@
+--TEST--
+Phar: PharFileInfo compression-related methods
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("zlib")) die("skip no zlib"); ?>
+<?php if (!extension_loaded("bz2")) die("skip no bz2"); ?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar';
+$pname = 'phar://' . $fname;
+
+$phar = new Phar($fname);
+
+$phar['a/b'] = 'hi there';
+
+$b = $phar['a/b'];
+
+$b->isCompressed(array());
+try {
+$b->isCompressed(25);
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+try {
+$b->compress(25);
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+$tar = $phar->convertToData(Phar::TAR);
+
+$c = $tar['a/b'];
+try {
+$c->compress(Phar::GZ);
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+try {
+$phar['a']->compress(Phar::GZ);
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+ini_set('phar.readonly', 1);
+try {
+$b->compress(Phar::GZ);
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+ini_set('phar.readonly', 0);
+var_dump($b->compress(Phar::GZ));
+var_dump($b->compress(Phar::GZ));
+var_dump($b->compress(Phar::BZ2));
+var_dump($b->compress(Phar::BZ2));
+
+echo "decompress\n";
+
+ini_set('phar.readonly', 1);
+try {
+$phar['a/b']->decompress();
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+ini_set('phar.readonly', 0);
+try {
+$phar['a']->decompress();
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+var_dump($b->decompress());
+var_dump($b->decompress());
+
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar'); ?>
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.tar'); ?>
+--EXPECTF--
+Warning: PharFileInfo::isCompressed() expects parameter 1 to be long, array given in %spharfileinfo_compression.php on line 11
+Unknown compression type specified
+Unknown compression type specified
+Cannot compress with Gzip compression, not possible with tar-based phar archives
+Phar entry is a directory, cannot set compression
+Phar is readonly, cannot change compression
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+decompress
+Phar is readonly, cannot decompress
+Phar entry is a directory, cannot set compression
+bool(true)
+bool(true)
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/pharfileinfo_construct.phpt b/ext/phar/tests/pharfileinfo_construct.phpt
new file mode 100644
index 0000000000..480c1222c4
--- /dev/null
+++ b/ext/phar/tests/pharfileinfo_construct.phpt
@@ -0,0 +1,54 @@
+--TEST--
+Phar: PharFileInfo::__construct
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar';
+$pname = 'phar://' . $fname;
+
+try {
+file_put_contents($fname, 'blah');
+$a = new PharFileInfo($pname . '/oops');
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+unlink($fname);
+}
+
+$a = new PharFileInfo(array());
+
+$a = new Phar($fname);
+$a['a'] = 'hi';
+$b = $a['a'];
+
+try {
+$a = new PharFileInfo($pname . '/oops/I/do/not/exist');
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+
+try {
+$b->__construct('oops');
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+
+try {
+$a = new PharFileInfo(__FILE__);
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar'); ?>
+--EXPECTF--
+Cannot open phar file 'phar://%spharfileinfo_construct.phar/oops': internal corruption of phar "%spharfileinfo_construct.phar" (truncated entry)
+
+Warning: PharFileInfo::__construct() expects parameter 1 to be string, array given in %spharfileinfo_construct.php on line %d
+Cannot access phar file entry '/oops/I/do/not/exist' in archive '%spharfileinfo_construct.phar'
+Cannot call constructor twice
+'%spharfileinfo_construct.php' is not a valid phar archive URL (must have at least phar://filename.phar)
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/pharfileinfo_destruct.phpt b/ext/phar/tests/pharfileinfo_destruct.phpt
new file mode 100644
index 0000000000..48a58c0d09
--- /dev/null
+++ b/ext/phar/tests/pharfileinfo_destruct.phpt
@@ -0,0 +1,25 @@
+--TEST--
+Phar: PharFileInfo::__destruct
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar';
+$pname = 'phar://' . $fname;
+
+$a = new Phar($fname);
+$a['a/subdir/here'] = 'hi';
+
+$b = new PharFileInfo($pname . '/a/subdir');
+unset($b);
+
+$b = new PharFileInfo($pname . '/a/subdir/here');
+unset($b);
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar'); ?>
+--EXPECTF--
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/pharfileinfo_getcrc32.phpt b/ext/phar/tests/pharfileinfo_getcrc32.phpt
new file mode 100644
index 0000000000..dfa12f4ca4
--- /dev/null
+++ b/ext/phar/tests/pharfileinfo_getcrc32.phpt
@@ -0,0 +1,49 @@
+--TEST--
+Phar: PharFileInfo::getCRC32
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar';
+$pname = 'phar://' . $fname;
+$file = "<?php
+Phar::mapPhar('hio');
+__HALT_COMPILER(); ?>";
+
+// compressed file length does not match incompressed lentgh for an uncompressed file
+
+$files = array();
+$files['a/subdir/here'] = array('cont'=>'a','ulen'=>1,'clen'=>1);;
+include 'files/phar_test.inc';
+
+$b = new PharFileInfo($pname . '/a/subdir');
+try {
+var_dump($b->getCRC32());
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+
+$b = new PharFileInfo($pname . '/a/subdir/here');
+try {
+var_dump($b->getCRC32());
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+$a = file_get_contents($pname . '/a/subdir/here');
+try {
+var_dump($b->getCRC32());
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar'); ?>
+--EXPECTF--
+Phar entry is a directory, does not have a CRC
+Phar entry was not CRC checked
+int(%s)
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/pharfileinfo_setmetadata.phpt b/ext/phar/tests/pharfileinfo_setmetadata.phpt
new file mode 100644
index 0000000000..8589fcb1d8
--- /dev/null
+++ b/ext/phar/tests/pharfileinfo_setmetadata.phpt
@@ -0,0 +1,65 @@
+--TEST--
+Phar: PharFileInfo::setMetadata/delMetadata extra code coverage
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar';
+$pname = 'phar://' . $fname;
+
+$phar = new Phar($fname);
+
+$phar['a/b'] = 'hi there';
+$tar = $phar->convertToData(Phar::TAR);
+
+$b = $phar['a/b'];
+try {
+$tar['a/b']->setMetadata('hi');
+} catch (Exception $e) {
+echo $e->getMessage(), "\n";
+}
+try {
+$tar['a/b']->delMetadata();
+} catch (Exception $e) {
+echo $e->getMessage(), "\n";
+}
+try {
+$phar['a']->setMetadata('hi');
+} catch (Exception $e) {
+echo $e->getMessage(), "\n";
+}
+try {
+$phar['a']->delMetadata();
+} catch (Exception $e) {
+echo $e->getMessage(), "\n";
+}
+ini_set('phar.readonly', 1);
+try {
+$b->setMetadata('hi');
+} catch (Exception $e) {
+echo $e->getMessage(), "\n";
+}
+try {
+$b->delMetadata();
+} catch (Exception $e) {
+echo $e->getMessage(), "\n";
+}
+ini_set('phar.readonly', 0);
+$b->setMetadata(1,2,3);
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar'); ?>
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.tar'); ?>
+--EXPECTF--
+Cannot set metadata, not possible with tar-based phar archives
+Cannot delete metadata, not possible with tar-based phar archives
+Phar entry is a temporary directory (not an actual entry in the archive), cannot set metadata
+Phar entry is a temporary directory (not an actual entry in the archive), cannot delete metadata
+Write operations disabled by phar.readonly INI setting
+Write operations disabled by phar.readonly INI setting
+
+Warning: PharFileInfo::setMetadata() expects exactly 1 parameter, 3 given in %spharfileinfo_setmetadata.php on line %d
+===DONE===
diff --git a/ext/phar/tests/phpinfo_001.phpt b/ext/phar/tests/phpinfo_001.phpt
new file mode 100644
index 0000000000..7b31185827
--- /dev/null
+++ b/ext/phar/tests/phpinfo_001.phpt
@@ -0,0 +1,59 @@
+--TEST--
+Phar: phpinfo display 1
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("zlib")) die("skip zlib not loaded"); ?>
+<?php if (!extension_loaded("bz2")) die("skip bz2 not loaded"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+phpinfo(INFO_MODULES);
+ini_set('phar.readonly',1);
+ini_set('phar.require_hash',1);
+phpinfo(INFO_MODULES);
+?>
+===DONE===
+--EXPECTF--
+%aPhar
+
+Phar: PHP Archive support => enabled
+Phar EXT version => %s
+Phar API version => 1.1.1
+CVS revision => %sRevision: %s $
+Phar-based phar archives => enabled
+Tar-based phar archives => enabled
+ZIP-based phar archives => enabled
+gzip compression => enabled
+bzip2 compression => enabled
+
+
+Phar based on pear/PHP_Archive, original concept by Davey Shafik.
+Phar fully realized by Gregory Beaver and Marcus Boerger.
+Portions of tar implementation Copyright (c) 2003-2007 Tim Kientzle.
+Directive => Local Value => Master Value
+phar.readonly => Off => Off
+phar.require_hash => Off => Off
+%a
+Phar
+
+Phar: PHP Archive support => enabled
+Phar EXT version => %s
+Phar API version => 1.1.1
+CVS revision => %sRevision: %s $
+Phar-based phar archives => enabled
+Tar-based phar archives => enabled
+ZIP-based phar archives => enabled
+gzip compression => enabled
+bzip2 compression => enabled
+
+
+Phar based on pear/PHP_Archive, original concept by Davey Shafik.
+Phar fully realized by Gregory Beaver and Marcus Boerger.
+Portions of tar implementation Copyright (c) 2003-2007 Tim Kientzle.
+Directive => Local Value => Master Value
+phar.readonly => On => Off
+phar.require_hash => On => Off
+%a
+===DONE===
diff --git a/ext/phar/tests/phpinfo_002.phpt b/ext/phar/tests/phpinfo_002.phpt
new file mode 100644
index 0000000000..1e0e567aff
--- /dev/null
+++ b/ext/phar/tests/phpinfo_002.phpt
@@ -0,0 +1,37 @@
+--TEST--
+Phar: phpinfo display 2
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("zlib")) die("skip zlib not loaded"); ?>
+<?php if (!extension_loaded("bz2")) die("skip bz2 not loaded"); ?>
+--INI--
+phar.readonly=1
+phar.require_hash=1
+--FILE--
+<?php
+phpinfo(INFO_MODULES);
+?>
+===DONE===
+--EXPECTF--
+%a
+Phar
+
+Phar: PHP Archive support => enabled
+Phar EXT version => %s
+Phar API version => 1.1.1
+CVS revision => %sRevision: %s $
+Phar-based phar archives => enabled
+Tar-based phar archives => enabled
+ZIP-based phar archives => enabled
+gzip compression => enabled
+bzip2 compression => enabled
+
+
+Phar based on pear/PHP_Archive, original concept by Davey Shafik.
+Phar fully realized by Gregory Beaver and Marcus Boerger.
+Portions of tar implementation Copyright (c) 2003-2007 Tim Kientzle.
+Directive => Local Value => Master Value
+phar.readonly => On => On
+phar.require_hash => On => On
+%a
+===DONE===
diff --git a/ext/phar/tests/phpinfo_003.phpt b/ext/phar/tests/phpinfo_003.phpt
new file mode 100644
index 0000000000..5894c83ea8
--- /dev/null
+++ b/ext/phar/tests/phpinfo_003.phpt
@@ -0,0 +1,37 @@
+--TEST--
+Phar: phpinfo display 3
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (extension_loaded("zlib")) die("skip zlib loaded"); ?>
+<?php if (extension_loaded("bz2")) die("skip bz2 loaded"); ?>
+--INI--
+phar.readonly=1
+phar.require_hash=1
+--FILE--
+<?php
+phpinfo(INFO_MODULES);
+?>
+===DONE===
+--EXPECTF--
+%a
+Phar
+
+Phar: PHP Archive support => enabled
+Phar EXT version => %s
+Phar API version => 1.1.1
+CVS revision => $Revision$
+Phar-based phar archives => enabled
+Tar-based phar archives => enabled
+ZIP-based phar archives => enabled
+gzip compression => disabled (install ext/zlib)
+bzip2 compression => disabled (install pecl/bz2)
+
+
+Phar based on pear/PHP_Archive, original concept by Davey Shafik.
+Phar fully realized by Gregory Beaver and Marcus Boerger.
+Portions of tar implementation Copyright (c) 2003-2007 Tim Kientzle.
+Directive => Local Value => Master Value
+phar.readonly => On => On
+phar.require_hash => On => On
+%a
+===DONE===
diff --git a/ext/phar/tests/phpinfo_004.phpt b/ext/phar/tests/phpinfo_004.phpt
new file mode 100644
index 0000000000..1dbccda889
--- /dev/null
+++ b/ext/phar/tests/phpinfo_004.phpt
@@ -0,0 +1,66 @@
+--TEST--
+Phar: phpinfo display 4
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("zlib")) die("skip zlib not loaded"); ?>
+<?php if (!extension_loaded("bz2")) die("skip bz2 not loaded"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--POST--
+a=b
+--FILE--
+<?php
+phpinfo(INFO_MODULES);
+ini_set('phar.readonly',1);
+ini_set('phar.require_hash',1);
+phpinfo(INFO_MODULES);
+?>
+===DONE===
+--EXPECTF--
+%a<br />
+<h2><a name="module_Phar">Phar</a></h2>
+<table border="0" cellpadding="3" width="600">
+<tr class="h"><th>Phar: PHP Archive support</th><th>enabled</th></tr>
+<tr><td class="e">Phar EXT version </td><td class="v">%s </td></tr>
+<tr><td class="e">Phar API version </td><td class="v">1.1.1 </td></tr>
+<tr><td class="e">CVS revision </td><td class="v">%sRevision: %s $ </td></tr>
+<tr><td class="e">Phar-based phar archives </td><td class="v">enabled </td></tr>
+<tr><td class="e">Tar-based phar archives </td><td class="v">enabled </td></tr>
+<tr><td class="e">ZIP-based phar archives </td><td class="v">enabled </td></tr>
+<tr><td class="e">gzip compression </td><td class="v">enabled </td></tr>
+<tr><td class="e">bzip2 compression </td><td class="v">enabled </td></tr>
+</table><br />
+<table border="0" cellpadding="3" width="600">
+<tr class="v"><td>
+Phar based on pear/PHP_Archive, original concept by Davey Shafik.<br />Phar fully realized by Gregory Beaver and Marcus Boerger.<br />Portions of tar implementation Copyright (c) 2003-2007 Tim Kientzle.</td></tr>
+</table><br />
+<table border="0" cellpadding="3" width="600">
+<tr class="h"><th>Directive</th><th>Local Value</th><th>Master Value</th></tr>
+<tr><td class="e">phar.readonly</td><td class="v">Off</td><td class="v">Off</td></tr>
+<tr><td class="e">phar.require_hash</td><td class="v">Off</td><td class="v">Off</td></tr>
+</table><br />
+%a<br />
+<h2><a name="module_Phar">Phar</a></h2>
+<table border="0" cellpadding="3" width="600">
+<tr class="h"><th>Phar: PHP Archive support</th><th>enabled</th></tr>
+<tr><td class="e">Phar EXT version </td><td class="v">%s </td></tr>
+<tr><td class="e">Phar API version </td><td class="v">1.1.1 </td></tr>
+<tr><td class="e">CVS revision </td><td class="v">%sRevision: %s $ </td></tr>
+<tr><td class="e">Phar-based phar archives </td><td class="v">enabled </td></tr>
+<tr><td class="e">Tar-based phar archives </td><td class="v">enabled </td></tr>
+<tr><td class="e">ZIP-based phar archives </td><td class="v">enabled </td></tr>
+<tr><td class="e">gzip compression </td><td class="v">enabled </td></tr>
+<tr><td class="e">bzip2 compression </td><td class="v">enabled </td></tr>
+</table><br />
+<table border="0" cellpadding="3" width="600">
+<tr class="v"><td>
+Phar based on pear/PHP_Archive, original concept by Davey Shafik.<br />Phar fully realized by Gregory Beaver and Marcus Boerger.<br />Portions of tar implementation Copyright (c) 2003-2007 Tim Kientzle.</td></tr>
+</table><br />
+<table border="0" cellpadding="3" width="600">
+<tr class="h"><th>Directive</th><th>Local Value</th><th>Master Value</th></tr>
+<tr><td class="e">phar.readonly</td><td class="v">On</td><td class="v">Off</td></tr>
+<tr><td class="e">phar.require_hash</td><td class="v">On</td><td class="v">Off</td></tr>
+</table><br />
+%a<br />
+</div></body></html>===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/readfile.phpt b/ext/phar/tests/readfile.phpt
new file mode 100644
index 0000000000..60fdad1792
--- /dev/null
+++ b/ext/phar/tests/readfile.phpt
@@ -0,0 +1,30 @@
+--TEST--
+Phar: test readfile() interception
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip");?>
+--INI--
+phar.require_hash=1
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$a = new Phar($fname);
+$a['index.php'] = '<?php
+readfile("dir/file1.txt");
+readfile("file1.txt", true);
+?>';
+$a['dir/file1.txt'] = 'hi';
+$a['dir/file2.txt'] = 'hi2';
+$a['dir/file3.txt'] = 'hi3';
+$a->setStub('<?php
+Phar::interceptFileFuncs();
+set_include_path("phar://" . __FILE__ . "/dir" . PATH_SEPARATOR . "phar://" . __FILE__);
+include "index.php";
+__HALT_COMPILER();');
+include $fname;
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECT--
+hihi===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/readfile_edgecases.phpt b/ext/phar/tests/readfile_edgecases.phpt
new file mode 100644
index 0000000000..1a78d7b5b0
--- /dev/null
+++ b/ext/phar/tests/readfile_edgecases.phpt
@@ -0,0 +1,62 @@
+--TEST--
+Phar: test edge cases of readfile() function interception
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip");?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+Phar::interceptFileFuncs();
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+
+readfile(array());
+chdir(dirname(__FILE__));
+file_put_contents($fname, "blah\n");
+file_put_contents("foob", "test\n");
+readfile($fname);
+unlink($fname);
+mkdir($pname . '/oops');
+file_put_contents($pname . '/foo/hi', '<?php
+readfile("foo/" . basename(__FILE__));
+$context = stream_context_create();
+readfile("foob");
+set_include_path("' . addslashes(dirname(__FILE__)) . '");
+readfile("foob", true);
+readfile("./hi", 0, $context);
+readfile("../oops");
+?>
+');
+include $pname . '/foo/hi';
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+<?php rmdir(dirname(__FILE__) . '/poo'); ?>
+<?php unlink(dirname(__FILE__) . '/foob'); ?>
+--EXPECTF--
+Warning: readfile() expects parameter 1 to be string, array given in %sreadfile_edgecases.php on line %d
+blah
+<?php
+readfile("foo/" . basename(__FILE__));
+$context = stream_context_create();
+readfile("foob");
+set_include_path("%stests");
+readfile("foob", true);
+readfile("./hi", 0, $context);
+readfile("../oops");
+?>
+test
+test
+<?php
+readfile("foo/" . basename(__FILE__));
+$context = stream_context_create();
+readfile("foob");
+set_include_path("%stests");
+readfile("foob", true);
+readfile("./hi", 0, $context);
+readfile("../oops");
+?>
+
+Warning: readfile(phar://%sreadfile_edgecases.phar.php/oops): failed to open stream: phar error: path "oops" is a directory in phar://%sreadfile_edgecases.phar.php/foo/hi on line %d
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/refcount1.phpt b/ext/phar/tests/refcount1.phpt
new file mode 100644
index 0000000000..234d49111c
--- /dev/null
+++ b/ext/phar/tests/refcount1.phpt
@@ -0,0 +1,62 @@
+--TEST--
+Phar: test that refcounting avoids problems with deleting a file
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+<?php if (version_compare(PHP_VERSION, "5.3", "<")) die("skip requires 5.3 or later"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = "<?php __HALT_COMPILER(); ?>";
+
+$files = array();
+$files['a.php'] = '<?php echo "This is a\n"; ?>';
+$files['b.php'] = '<?php echo "This is b\n"; ?>';
+$files['b/c.php'] = '<?php echo "This is b/c\n"; ?>';
+include 'files/phar_test.inc';
+
+$fp = fopen($pname . '/b/c.php', 'wb');
+fwrite($fp, "extra");
+fclose($fp);
+echo "===CLOSE===\n";
+$p = new Phar($fname);
+$b = fopen($pname . '/b/c.php', 'rb');
+$a = $p['b/c.php'];
+var_dump($a);
+var_dump(fread($b, 20));
+rewind($b);
+echo "===UNLINK===\n";
+unlink($pname . '/b/c.php');
+var_dump($a);
+var_dump(fread($b, 20));
+include $pname . '/b/c.php';
+?>
+
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECTF--
+===CLOSE===
+object(PharFileInfo)#%d (2) {
+ ["pathName":"SplFileInfo":private]=>
+ string(%d) "phar://%srefcount1.phar.php/b"
+ ["fileName":"SplFileInfo":private]=>
+ string(%d) "phar://%srefcount1.phar.php/b/c.php"
+}
+string(5) "extra"
+===UNLINK===
+
+Warning: unlink(): phar error: "b/c.php" in phar "%srefcount1.phar.php", has open file pointers, cannot unlink in %srefcount1.php on line %d
+object(PharFileInfo)#%d (2) {
+ ["pathName":"SplFileInfo":private]=>
+ string(%d) "phar://%srefcount1.phar.php/b"
+ ["fileName":"SplFileInfo":private]=>
+ string(%s) "phar://%srefcount1.phar.php/b/c.php"
+}
+string(5) "extra"
+extra
+===DONE===
diff --git a/ext/phar/tests/refcount1_5_2.phpt b/ext/phar/tests/refcount1_5_2.phpt
new file mode 100755
index 0000000000..bf2c2b76b3
--- /dev/null
+++ b/ext/phar/tests/refcount1_5_2.phpt
@@ -0,0 +1,64 @@
+--TEST--
+Phar: test that refcounting avoids problems with deleting a file
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+<?php if (version_compare(PHP_VERSION, "5.3", ">")) die("skip requires 5.2 or earlier"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar';
+$alias = 'phar://' . $fname;
+
+$phar = new Phar($fname);
+$phar->setStub("<?php __HALT_COMPILER(); ?>");
+$phar->setAlias('hio');
+
+$files = array();
+
+$files['a.php'] = '<?php echo "This is a\n"; ?>';
+$files['b.php'] = '<?php echo "This is b\n"; ?>';
+$files['b/c.php'] = '<?php echo "This is b/c\n"; ?>';
+
+foreach ($files as $n => $file) {
+ $phar[$n] = $file;
+}
+$phar->stopBuffering();
+
+$fp = fopen($alias . '/b/c.php', 'wb');
+fwrite($fp, "extra");
+fclose($fp);
+
+echo "===CLOSE===\n";
+
+$b = fopen($alias . '/b/c.php', 'rb');
+$a = $phar['b/c.php'];
+var_dump($a);
+var_dump(fread($b, 20));
+rewind($b);
+echo "===UNLINK===\n";
+unlink($alias . '/b/c.php');
+var_dump($a);
+var_dump(fread($b, 20));
+include $alias . '/b/c.php';
+?>
+
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar'); ?>
+--EXPECTF--
+===CLOSE===
+object(PharFileInfo)#%d (0) {
+}
+string(5) "extra"
+===UNLINK===
+
+Warning: unlink(): phar error: "b/c.php" in phar "%sefcount1_5_2.phar", has open file pointers, cannot unlink in %sefcount1_5_2.php on line %d
+object(PharFileInfo)#%d (0) {
+}
+string(5) "extra"
+extra
+===DONE===
diff --git a/ext/phar/tests/rename.phpt b/ext/phar/tests/rename.phpt
new file mode 100644
index 0000000000..c73c98ec81
--- /dev/null
+++ b/ext/phar/tests/rename.phpt
@@ -0,0 +1,32 @@
+--TEST--
+Phar: rename test
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$file = "<?php
+Phar::mapPhar('hio');
+__HALT_COMPILER(); ?>";
+
+$files = array();
+$files['a'] = 'a';
+include 'files/phar_test.inc';
+include $fname;
+
+echo file_get_contents($pname . '/a') . "\n";
+rename($pname . '/a', $pname . '/b');
+echo file_get_contents($pname . '/b') . "\n";
+echo file_get_contents($pname . '/a') . "\n";
+?>
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECTF--
+a
+a
+
+Warning: file_get_contents(phar://%srename.phar.php/a): failed to open stream: phar error: "a" is not a file in phar "%srename.phar.php" in %srename.php on line %d \ No newline at end of file
diff --git a/ext/phar/tests/security.phpt b/ext/phar/tests/security.phpt
new file mode 100644
index 0000000000..2d54db7908
--- /dev/null
+++ b/ext/phar/tests/security.phpt
@@ -0,0 +1,36 @@
+--TEST--
+Phar: test to ensure phar.readonly cannot be circumvented
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip");?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.1.php';
+$a = new Phar($fname);
+$a->setStub('<?php
+Phar::mapPhar();
+$phar = new Phar(__FILE__);
+var_dump($phar->isWritable());
+try {
+$phar["b"] = "should not work!";
+} catch (Exception $e) {
+echo $e->getMessage(),"\n";
+}
+__HALT_COMPILER();
+?>');
+$a['hi'] = 'hi';
+unset($a);
+copy($fname, $fname2);
+Phar::unlinkArchive($fname);
+ini_set('phar.readonly', 1);
+include $fname2;
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.1.php'); ?>
+--EXPECT--
+bool(false)
+Write operations disabled by INI setting
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/stat.phpt b/ext/phar/tests/stat.phpt
new file mode 100644
index 0000000000..020fc24f86
--- /dev/null
+++ b/ext/phar/tests/stat.phpt
@@ -0,0 +1,215 @@
+--TEST--
+Phar: test stat function interceptions
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip");?>
+--INI--
+phar.require_hash=1
+phar.readonly=0
+--FILE--
+<?php
+Phar::interceptFileFuncs();
+var_dump(stat(""));
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.tar';
+$fname3 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar';
+$a = new Phar($fname);
+$a['index.php'] = '<?php
+echo "stat\n";
+var_dump(stat("dir/file1.txt"));
+echo "lstat\n";
+var_dump(lstat("dir/file1.txt"));
+echo "fileperms\n";
+var_dump(fileperms("dir/file1.txt"));
+echo "fileinode\n";
+var_dump(fileinode("dir/file1.txt"));
+echo "filesize\n";
+var_dump(filesize("dir/file1.txt"));
+echo "fileowner\n";
+var_dump(fileowner("dir/file1.txt"));
+echo "filegroup\n";
+var_dump(filegroup("dir/file1.txt"));
+echo "filemtime\n";
+var_dump(filemtime("dir/file1.txt"));
+echo "fileatime\n";
+var_dump(fileatime("dir/file1.txt"));
+echo "filectime\n";
+var_dump(filectime("dir/file1.txt"));
+echo "filetype\n";
+var_dump(filetype("dir/file1.txt"));
+echo "is_writable\n";
+var_dump(is_writable("dir/file1.txt"));
+echo "is_writeable\n";
+var_dump(is_writeable("dir/file1.txt"));
+echo "is_readable\n";
+var_dump(is_readable("dir/file1.txt"));
+echo "is_executable\n";
+var_dump(is_executable("dir/file1.txt"));
+echo "file_exists\n";
+var_dump(file_exists("dir/file1.txt"));
+echo "is_dir\n";
+var_dump(is_dir("dir/file1.txt"));
+echo "is_file\n";
+var_dump(is_file("dir/file1.txt"));
+echo "is_link\n";
+var_dump(is_link("dir/file1.txt"));
+?>';
+$a['dir/file1.txt'] = 'hi';
+$a['dir/file2.txt'] = 'hi2';
+$a['dir/file3.txt'] = 'hi3';
+$a->setStub('<?php
+set_include_path("phar://" . __FILE__ . "/dir" . PATH_SEPARATOR . "phar://" . __FILE__);
+include "index.php";
+__HALT_COMPILER();');
+include $fname;
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECTF--
+bool(false)
+stat
+array(26) {
+ [0]=>
+ int(12)
+ [1]=>
+ int(%d)
+ [2]=>
+ int(33206)
+ [3]=>
+ int(1)
+ [4]=>
+ int(0)
+ [5]=>
+ int(0)
+ [6]=>
+ int(%s)
+ [7]=>
+ int(2)
+ [8]=>
+ int(%d)
+ [9]=>
+ int(%d)
+ [10]=>
+ int(%d)
+ [11]=>
+ int(%s)
+ [12]=>
+ int(%s)
+ ["dev"]=>
+ int(12)
+ ["ino"]=>
+ int(%d)
+ ["mode"]=>
+ int(33206)
+ ["nlink"]=>
+ int(1)
+ ["uid"]=>
+ int(0)
+ ["gid"]=>
+ int(0)
+ ["rdev"]=>
+ int(%s)
+ ["size"]=>
+ int(2)
+ ["atime"]=>
+ int(%d)
+ ["mtime"]=>
+ int(%d)
+ ["ctime"]=>
+ int(%d)
+ ["blksize"]=>
+ int(%s)
+ ["blocks"]=>
+ int(%s)
+}
+lstat
+array(26) {
+ [0]=>
+ int(12)
+ [1]=>
+ int(%d)
+ [2]=>
+ int(33206)
+ [3]=>
+ int(1)
+ [4]=>
+ int(0)
+ [5]=>
+ int(0)
+ [6]=>
+ int(%s)
+ [7]=>
+ int(2)
+ [8]=>
+ int(%d)
+ [9]=>
+ int(%d)
+ [10]=>
+ int(%d)
+ [11]=>
+ int(%s)
+ [12]=>
+ int(%s)
+ ["dev"]=>
+ int(12)
+ ["ino"]=>
+ int(%d)
+ ["mode"]=>
+ int(33206)
+ ["nlink"]=>
+ int(1)
+ ["uid"]=>
+ int(0)
+ ["gid"]=>
+ int(0)
+ ["rdev"]=>
+ int(%s)
+ ["size"]=>
+ int(2)
+ ["atime"]=>
+ int(%d)
+ ["mtime"]=>
+ int(%d)
+ ["ctime"]=>
+ int(%d)
+ ["blksize"]=>
+ int(%s)
+ ["blocks"]=>
+ int(%s)
+}
+fileperms
+int(33206)
+fileinode
+int(%d)
+filesize
+int(2)
+fileowner
+int(0)
+filegroup
+int(0)
+filemtime
+int(%d)
+fileatime
+int(%d)
+filectime
+int(%d)
+filetype
+string(4) "file"
+is_writable
+bool(true)
+is_writeable
+bool(false)
+is_readable
+bool(true)
+is_executable
+bool(false)
+file_exists
+bool(true)
+is_dir
+bool(false)
+is_file
+bool(true)
+is_link
+bool(false)
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/stat2.phpt b/ext/phar/tests/stat2.phpt
new file mode 100644
index 0000000000..6e911028ca
--- /dev/null
+++ b/ext/phar/tests/stat2.phpt
@@ -0,0 +1,60 @@
+--TEST--
+Phar: test stat function interceptions and is_file/is_link edge cases (PHP 5.2)
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip");?>
+<?php if (substr(phpversion(), 0, 3) != '5.2') die("skip PHP 5.2 required for this test");?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+Phar::interceptFileFuncs();
+is_file();
+is_link();
+var_dump(is_file(__FILE__));
+
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.tar';
+$fname3 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar';
+copy(dirname(__FILE__) . '/tar/files/links.tar', $fname2);
+$a = new PharData($fname2);
+$b = $a->convertToExecutable();
+unset($a);
+Phar::unlinkArchive($fname2);
+$b['foo/stat.php'] = '<?php
+echo "is_link\n";
+var_dump(is_link("./stat.php"),is_file("./stat.php"), is_link("./oops"), is_file("./oops"));
+var_dump(is_link("testit/link"), filetype("testit/link"), filetype("testit"), is_file("testit/link"));
+echo "not found\n";
+var_dump(is_link("notfound"));
+echo "dir\n";
+var_dump(is_dir("./bar"), is_file("foo/bar/blah"));
+?>';
+$b->addEmptyDir('foo/bar/blah');
+$b->setStub('<?php
+include "phar://" . __FILE__ . "/foo/stat.php";
+__HALT_COMPILER();');
+include $fname3;
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar'); ?>
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.tar'); ?>
+--EXPECTF--
+Warning: Wrong parameter count for is_file() in %sstat2.php on line %d
+
+Warning: Wrong parameter count for is_link() in %sstat2.php on line %d
+bool(true)
+is_link
+bool(false)
+bool(true)
+bool(false)
+bool(false)
+bool(true)
+string(4) "link"
+string(3) "dir"
+bool(true)
+not found
+bool(false)
+dir
+bool(true)
+bool(false)
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/stat2_5.3.phpt b/ext/phar/tests/stat2_5.3.phpt
new file mode 100644
index 0000000000..58ca54a16a
--- /dev/null
+++ b/ext/phar/tests/stat2_5.3.phpt
@@ -0,0 +1,60 @@
+--TEST--
+Phar: test stat function interceptions and is_file/is_link edge cases (PHP 5.3+)
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip");?>
+<?php if (substr(phpversion(), 0, 3) == '5.2') die("skip PHP 5.3+ required for this test");?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+Phar::interceptFileFuncs();
+is_file();
+is_link();
+var_dump(is_file(__FILE__));
+
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.tar';
+$fname3 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar';
+copy(dirname(__FILE__) . '/tar/files/links.tar', $fname2);
+$a = new PharData($fname2);
+$b = $a->convertToExecutable(Phar::TAR, Phar::NONE, '.3.phar.tar');
+unset($a);
+Phar::unlinkArchive($fname2);
+$b['foo/stat.php'] = '<?php
+echo "is_link\n";
+var_dump(is_link("./stat.php"),is_file("./stat.php"), is_link("./oops"), is_file("./oops"));
+var_dump(is_link("testit/link"), filetype("testit/link"), filetype("testit"), is_file("testit/link"));
+echo "not found\n";
+var_dump(is_link("notfound"));
+echo "dir\n";
+var_dump(is_dir("./bar"), is_file("foo/bar/blah"));
+?>';
+$b->addEmptyDir('foo/bar/blah');
+$b->setStub('<?php
+include "phar://" . __FILE__ . "/foo/stat.php";
+__HALT_COMPILER();');
+include $fname3;
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar'); ?>
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.tar'); ?>
+--EXPECTF--
+Warning: is_file() expects exactly 1 parameter, 0 given in %sstat2_5.3.php on line %d
+
+Warning: is_link() expects exactly 1 parameter, 0 given in %sstat2_5.3.php on line %d
+bool(true)
+is_link
+bool(false)
+bool(true)
+bool(false)
+bool(false)
+bool(true)
+string(4) "link"
+string(3) "dir"
+bool(true)
+not found
+bool(false)
+dir
+bool(true)
+bool(false)
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/tar/033.phpt b/ext/phar/tests/tar/033.phpt
new file mode 100644
index 0000000000..29223e49e3
--- /dev/null
+++ b/ext/phar/tests/tar/033.phpt
@@ -0,0 +1,50 @@
+--TEST--
+Phar::chmod tar-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar';
+$alias = 'phar://hio';
+
+$phar = new Phar($fname);
+$phar['a.php'] = '<?php echo "This is a\n"; include "'.$alias.'/b.php"; ?>';
+$phar->setAlias('hio');
+$phar->addEmptyDir('test');
+$phar->stopBuffering();
+
+try {
+ var_dump($phar['a.php']->isExecutable());
+ $phar['a.php']->chmod(0777);
+ var_dump($phar['a.php']->isExecutable());
+ $phar['a.php']->chmod(0666);
+ var_dump($phar['a.php']->isExecutable());
+ echo "test dir\n";
+ var_dump($phar['test']->isReadable());
+ $phar['test']->chmod(0000);
+ var_dump($phar['test']->isReadable());
+ $phar['test']->chmod(0666);
+ var_dump($phar['test']->isReadable());
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar');
+?>
+--EXPECTF--
+bool(false)
+bool(true)
+bool(false)
+test dir
+bool(true)
+bool(false)
+bool(true)
+===DONE===
diff --git a/ext/phar/tests/tar/033a.phpt b/ext/phar/tests/tar/033a.phpt
new file mode 100644
index 0000000000..09b5446aec
--- /dev/null
+++ b/ext/phar/tests/tar/033a.phpt
@@ -0,0 +1,45 @@
+--TEST--
+Phar::chmod tar-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar';
+$alias = 'phar://hio';
+
+$phar = new Phar($fname);
+$phar['a.php'] = '<?php echo "This is a\n"; include "'.$alias.'/b.php"; ?>';
+$phar->setAlias('hio');
+$phar->addEmptyDir('test');
+$phar->stopBuffering();
+ini_set('phar.readonly', 1);
+
+try {
+ var_dump($phar['a.php']->isExecutable());
+ $phar['a.php']->chmod(0777);
+ var_dump($phar['a.php']->isExecutable());
+ $phar['a.php']->chmod(0666);
+ var_dump($phar['a.php']->isExecutable());
+ echo "test dir\n";
+ var_dump($phar['test']->isReadable());
+ $phar['test']->chmod(0000);
+ var_dump($phar['test']->isReadable());
+ $phar['test']->chmod(0666);
+ var_dump($phar['test']->isReadable());
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar');
+?>
+--EXPECTF--
+bool(false)
+Cannot modify permissions for file "a.php" in phar "%s033a.phar.tar", write operations are prohibited
+===DONE===
diff --git a/ext/phar/tests/tar/alias_acrobatics.phpt b/ext/phar/tests/tar/alias_acrobatics.phpt
new file mode 100644
index 0000000000..d08dc0467c
--- /dev/null
+++ b/ext/phar/tests/tar/alias_acrobatics.phpt
@@ -0,0 +1,46 @@
+--TEST--
+Phar: alias edge cases
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar';
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.2.phar.tar';
+
+$p = new Phar($fname);
+
+$p->setAlias('foo');
+$p['unused'] = 'hi';
+try {
+$a = new Phar($fname2, 0, 'foo');
+} catch (Exception $e) {
+echo $e->getMessage(),"\n";
+}
+copy($fname, $fname2);
+echo "2\n";
+try {
+$a = new Phar($fname2);
+} catch (Exception $e) {
+echo $e->getMessage(),"\n";
+}
+try {
+$b = new Phar($fname, 0, 'another');
+} catch (Exception $e) {
+echo $e->getMessage(),"\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.2.phar.tar');
+?>
+--EXPECTF--
+alias "foo" is already used for archive "%salias_acrobatics.phar.tar" cannot be overloaded with "%salias_acrobatics.2.phar.tar"
+2
+phar error: Unable to add tar-based phar "%salias_acrobatics.2.phar.tar", alias is already in use
+alias "another" is already used for archive "%salias_acrobatics.phar.tar" cannot be overloaded with "%salias_acrobatics.phar.tar"
+===DONE===
diff --git a/ext/phar/tests/tar/badalias.phpt b/ext/phar/tests/tar/badalias.phpt
new file mode 100644
index 0000000000..441fc03ae7
--- /dev/null
+++ b/ext/phar/tests/tar/badalias.phpt
@@ -0,0 +1,25 @@
+--TEST--
+Phar: invalid aliases
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("zlib")) die("skip no zlib"); ?>
+<?php if (!extension_loaded("bz2")) die("skip no bz2"); ?>
+--FILE--
+<?php
+$e = dirname(__FILE__) . '/files/';
+for ($i = 1; $i <= 5; $i++) {
+try {
+new Phar($e . "badalias$i.phar.tar");
+} catch (Exception $ee) {
+echo $ee->getMessage(), "\n";
+}
+}
+?>
+===DONE===
+--EXPECTF--
+phar error: invalid alias "hi/thereaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..." in tar-based phar "%sbadalias1.phar.tar"
+phar error: invalid alias "hi\there" in tar-based phar "%sbadalias2.phar.tar"
+phar error: invalid alias "hi;there" in tar-based phar "%sbadalias3.phar.tar"
+phar error: invalid alias "hi:there" in tar-based phar "%sbadalias4.phar.tar"
+phar error: tar-based phar "%sbadalias5.phar.tar" has alias that is larger than 511 bytes, cannot process
+===DONE===
diff --git a/ext/phar/tests/tar/badchecksum.phpt b/ext/phar/tests/tar/badchecksum.phpt
new file mode 100644
index 0000000000..fae19b153d
--- /dev/null
+++ b/ext/phar/tests/tar/badchecksum.phpt
@@ -0,0 +1,30 @@
+--TEST--
+Phar: tar with bad checksum
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.tar';
+$pname = 'phar://' . $fname;
+
+include dirname(__FILE__) . '/files/corrupt_tarmaker.php.inc';
+$a = new corrupt_tarmaker($fname, 'none');
+$a->init();
+$a->addFile('hithere', 'contents', null, 'checksum');
+$a->close();
+
+try {
+ $p = new PharData($fname);
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.tar');
+?>
+--EXPECTF--
+phar error: "%sbadchecksum.tar" is a corrupted tar file (checksum mismatch of file "hithere")
+===DONE===
diff --git a/ext/phar/tests/tar/bignames.phpt b/ext/phar/tests/tar/bignames.phpt
new file mode 100644
index 0000000000..19d5f638e1
--- /dev/null
+++ b/ext/phar/tests/tar/bignames.phpt
@@ -0,0 +1,35 @@
+--TEST--
+Phar: tar with huge filenames
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.tar';
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.2.tar';
+$pname = 'phar://' . $fname;
+
+$p1 = new PharData($fname);
+$p1[str_repeat('a', 101)] = 'hi';
+$p1[str_repeat('a', 255)] = 'hi2';
+copy($fname, $fname2);
+$p2 = new PharData($fname2);
+echo $p2[str_repeat('a', 101)]->getContent() . "\n";
+echo $p2[str_repeat('a', 255)]->getContent() . "\n";
+
+try {
+ $p2[str_repeat('a', 400)] = 'yuck';
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.tar');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.2.tar');
+?>
+--EXPECTF--
+hi
+hi2
+tar-based phar "%sbignames.2.tar" cannot be created, filename "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" is too long for tar file format
+===DONE===
diff --git a/ext/phar/tests/tar/create_new_and_modify.phpt b/ext/phar/tests/tar/create_new_and_modify.phpt
new file mode 100644
index 0000000000..8062fda769
--- /dev/null
+++ b/ext/phar/tests/tar/create_new_and_modify.phpt
@@ -0,0 +1,45 @@
+--TEST--
+Phar: create and modify tar-based phar
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar.php';
+$pname = 'phar://' . $fname;
+
+@unlink($fname);
+
+file_put_contents($pname . '/a.php', "brand new!\n");
+
+$phar = new Phar($fname);
+var_dump($phar->isFileFormat(Phar::TAR));
+$sig1 = md5_file($fname);
+
+include $pname . '/a.php';
+
+file_put_contents($pname .'/a.php', "modified!\n");
+file_put_contents($pname .'/b.php', "another!\n");
+
+$phar = new Phar($fname);
+$sig2 = md5_file($fname);
+
+var_dump($sig1 != $sig2);
+
+include $pname . '/a.php';
+include $pname . '/b.php';
+
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar.php'); ?>
+--EXPECTF--
+bool(true)
+brand new!
+bool(true)
+modified!
+another!
+===DONE===
diff --git a/ext/phar/tests/tar/create_new_phar_b.phpt b/ext/phar/tests/tar/create_new_phar_b.phpt
new file mode 100644
index 0000000000..a608be4705
--- /dev/null
+++ b/ext/phar/tests/tar/create_new_phar_b.phpt
@@ -0,0 +1,27 @@
+--TEST--
+Phar: create a completely new tar-based phar
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=1
+phar.require_hash=1
+--FILE--
+<?php
+
+file_put_contents('phar://' . dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar/a.php',
+ 'brand new!');
+include 'phar://' . dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar/a.php';
+?>
+
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar'); ?>
+--EXPECTF--
+
+Warning: file_put_contents(phar://%screate_new_phar_b.phar.tar/a.php): failed to open stream: phar error: write operations disabled by INI setting in %screate_new_phar_b.php on line %d
+
+Warning: include(phar://%screate_new_phar_b.phar.tar/a.php): failed to open stream: %s in %screate_new_phar_b.php on line %d
+
+Warning: include(): Failed opening 'phar://%screate_new_phar_b.phar.tar/a.php' for inclusion (include_path='%s') in %screate_new_phar_b.php on line %d
+
+===DONE===
diff --git a/ext/phar/tests/tar/delete.phpt b/ext/phar/tests/tar/delete.phpt
new file mode 100644
index 0000000000..32b2b1e28b
--- /dev/null
+++ b/ext/phar/tests/tar/delete.phpt
@@ -0,0 +1,32 @@
+--TEST--
+Phar: delete test, tar-based phar
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar';
+$alias = 'phar://' . $fname;
+$stub = "<?php
+Phar::mapPhar('hio');
+__HALT_COMPILER(); ?>";
+
+$phar = new Phar($fname);
+$phar['a'] = 'a';
+$phar->setStub($stub);
+$phar->stopBuffering();
+
+echo file_get_contents($alias . '/a') . "\n";
+$phar->delete('a');
+echo file_get_contents($alias . '/a') . "\n";
+
+?>
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar'); ?>
+--EXPECTF--
+a
+
+Warning: file_get_contents(phar://%sdelete.phar.tar/a): failed to open stream: phar error: "a" is not a file in phar "%sdelete.phar.tar" in %sdelete.php on line %d \ No newline at end of file
diff --git a/ext/phar/tests/tar/delete_in_phar.phpt b/ext/phar/tests/tar/delete_in_phar.phpt
new file mode 100644
index 0000000000..91ef4a2046
--- /dev/null
+++ b/ext/phar/tests/tar/delete_in_phar.phpt
@@ -0,0 +1,49 @@
+--TEST--
+Phar: delete a file within a tar-based .phar
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar';
+$alias = 'phar://' . $fname;
+
+$phar = new Phar($fname);
+$phar['a.php'] = '<?php echo "This is a\n"; ?>';
+$phar['b.php'] = '<?php echo "This is b\n"; ?>';
+$phar['b/c.php'] = '<?php echo "This is b/c\n"; ?>';
+$phar->setStub('<?php __HALT_COMPILER(); ?>');
+$phar->stopBuffering();
+
+include $alias . '/a.php';
+include $alias . '/b.php';
+include $alias . '/b/c.php';
+unlink($alias . '/b/c.php');
+
+?>
+===AFTER===
+<?php
+include $alias . '/a.php';
+include $alias . '/b.php';
+include $alias . '/b/c.php';
+?>
+
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar'); ?>
+--EXPECTF--
+This is a
+This is b
+This is b/c
+===AFTER===
+This is a
+This is b
+
+Warning: include(%sdelete_in_phar.phar.tar/b/c.php): failed to open stream: phar error: "b/c.php" is not a file in phar "%sdelete_in_phar.phar.tar" in %sdelete_in_phar.php on line %d
+
+Warning: include(): Failed opening 'phar://%sdelete_in_phar.phar.tar/b/c.php' for inclusion (include_path='%s') in %sdelete_in_phar.php on line %d
+
+===DONE===
diff --git a/ext/phar/tests/tar/delete_in_phar_b.phpt b/ext/phar/tests/tar/delete_in_phar_b.phpt
new file mode 100644
index 0000000000..2af1c66deb
--- /dev/null
+++ b/ext/phar/tests/tar/delete_in_phar_b.phpt
@@ -0,0 +1,49 @@
+--TEST--
+Phar: delete a file within a tar-based .phar
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar';
+$alias = 'phar://' . $fname;
+
+$phar = new Phar($fname);
+$phar['a.php'] = '<?php echo "This is a\n"; ?>';
+$phar['b.php'] = '<?php echo "This is b\n"; ?>';
+$phar['b/c.php'] = '<?php echo "This is b/c\n"; ?>';
+$phar->setStub('<?php __HALT_COMPILER(); ?>');
+$phar->stopBuffering();
+ini_set('phar.readonly', 1);
+
+include $alias . '/a.php';
+include $alias . '/b.php';
+include $alias . '/b/c.php';
+unlink($alias . '/b/c.php');
+
+?>
+===AFTER===
+<?php
+include $alias . '/a.php';
+include $alias . '/b.php';
+include $alias . '/b/c.php';
+?>
+
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar'); ?>
+--EXPECTF--
+This is a
+This is b
+This is b/c
+
+Warning: unlink(): phar error: write operations disabled by INI setting in %sdelete_in_phar_b.php on line %d
+===AFTER===
+This is a
+This is b
+This is b/c
+
+===DONE===
diff --git a/ext/phar/tests/tar/delete_in_phar_confirm.phpt b/ext/phar/tests/tar/delete_in_phar_confirm.phpt
new file mode 100644
index 0000000000..707bcbd0ed
--- /dev/null
+++ b/ext/phar/tests/tar/delete_in_phar_confirm.phpt
@@ -0,0 +1,52 @@
+--TEST--
+Phar: delete a file within a tar-based .phar (confirm disk file is changed)
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar';
+$alias = 'phar://' . $fname;
+
+$phar = new Phar($fname);
+$phar['a.php'] = '<?php echo "This is a\n"; ?>';
+$phar['b.php'] = '<?php echo "This is b\n"; ?>';
+$phar['b/c.php'] = '<?php echo "This is b/c\n"; ?>';
+$phar->setStub('<?php __HALT_COMPILER(); ?>');
+$phar->stopBuffering();
+
+include $alias . '/a.php';
+include $alias . '/b.php';
+include $alias . '/b/c.php';
+$md5 = md5_file($fname);
+unlink($alias . '/b/c.php');
+clearstatcache();
+$md52 = md5_file($fname);
+if ($md5 == $md52) echo 'file was not modified';
+?>
+===AFTER===
+<?php
+include 'phar://' . dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar/a.php';
+include 'phar://' . dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar/b.php';
+include 'phar://' . dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar/b/c.php';
+?>
+
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar'); ?>
+--EXPECTF--
+This is a
+This is b
+This is b/c
+===AFTER===
+This is a
+This is b
+
+Warning: include(%sdelete_in_phar_confirm.phar.tar/b/c.php): failed to open stream: phar error: "b/c.php" is not a file in phar "%sdelete_in_phar_confirm.phar.tar" in %sdelete_in_phar_confirm.php on line %d
+
+Warning: include(): Failed opening 'phar://%sdelete_in_phar_confirm.phar.tar/b/c.php' for inclusion (include_path='%s') in %sdelete_in_phar_confirm.php on line %d
+
+===DONE===
diff --git a/ext/phar/tests/tar/dir.phpt b/ext/phar/tests/tar/dir.phpt
new file mode 100644
index 0000000000..53bf65f9a7
--- /dev/null
+++ b/ext/phar/tests/tar/dir.phpt
@@ -0,0 +1,43 @@
+--TEST--
+Phar: mkdir/rmdir test tar-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar.php';
+$pname = 'phar://' . $fname;
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.1.phar.php';
+$pname2 = 'phar://' . $fname2;
+$fname3 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.2.phar.php';
+$pname3 = 'phar://' . $fname3;
+$phar = new Phar($fname);
+var_dump($phar->isFileFormat(Phar::TAR));
+
+$phar->addEmptyDir('test');
+var_dump($phar['test']->isDir());
+var_dump($phar['test/']->isDir());
+copy($fname, $fname2);
+mkdir($pname . '/another/dir/');
+var_dump($phar['another/dir']->isDir());
+rmdir($pname . '/another/dir/');
+copy($fname, $fname3);
+clearstatcache();
+var_dump(file_exists($pname . '/another/dir/'));
+var_dump(file_exists($pname2 . '/test/'));
+var_dump(file_exists($pname3 . '/another/dir/'));
+?>
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar.php'); ?>
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.1.phar.php'); ?>
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.2.phar.php'); ?>
+--EXPECT--
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(false)
+bool(true)
+bool(false)
diff --git a/ext/phar/tests/tar/exists_as_phar.phpt b/ext/phar/tests/tar/exists_as_phar.phpt
new file mode 100644
index 0000000000..9a8cfc81f0
--- /dev/null
+++ b/ext/phar/tests/tar/exists_as_phar.phpt
@@ -0,0 +1,38 @@
+--TEST--
+Phar: phar-based phar named with ".tar" fails
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar';
+$tname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar';
+$alias = 'phar://hio';
+
+$phar = new Phar($fname);
+$phar['a.php'] = '<?php echo "This is a\n"; include "'.$alias.'/b.php"; ?>';
+$phar->setAlias('hio');
+$phar->addEmptyDir('test');
+$phar->stopBuffering();
+copy($fname, $tname);
+$phar->setAlias('hio2');
+
+try {
+ $p = new Phar($tname);
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar');
+?>
+--EXPECTF--
+phar tar error: "%sexists_as_phar.phar.tar" already exists as a regular phar and must be deleted from disk prior to creating as a tar-based phar
+===DONE===
diff --git a/ext/phar/tests/tar/files/badalias1.phar.tar b/ext/phar/tests/tar/files/badalias1.phar.tar
new file mode 100644
index 0000000000..6cd4716d8f
--- /dev/null
+++ b/ext/phar/tests/tar/files/badalias1.phar.tar
Binary files differ
diff --git a/ext/phar/tests/tar/files/badalias2.phar.tar b/ext/phar/tests/tar/files/badalias2.phar.tar
new file mode 100644
index 0000000000..5face85827
--- /dev/null
+++ b/ext/phar/tests/tar/files/badalias2.phar.tar
Binary files differ
diff --git a/ext/phar/tests/tar/files/badalias3.phar.tar b/ext/phar/tests/tar/files/badalias3.phar.tar
new file mode 100644
index 0000000000..ab36e1f343
--- /dev/null
+++ b/ext/phar/tests/tar/files/badalias3.phar.tar
Binary files differ
diff --git a/ext/phar/tests/tar/files/badalias4.phar.tar b/ext/phar/tests/tar/files/badalias4.phar.tar
new file mode 100644
index 0000000000..c54e31d4fc
--- /dev/null
+++ b/ext/phar/tests/tar/files/badalias4.phar.tar
Binary files differ
diff --git a/ext/phar/tests/tar/files/badalias5.phar.tar b/ext/phar/tests/tar/files/badalias5.phar.tar
new file mode 100644
index 0000000000..dd52b6ac7d
--- /dev/null
+++ b/ext/phar/tests/tar/files/badalias5.phar.tar
Binary files differ
diff --git a/ext/phar/tests/tar/files/biglink.tar b/ext/phar/tests/tar/files/biglink.tar
new file mode 100644
index 0000000000..43bbf58423
--- /dev/null
+++ b/ext/phar/tests/tar/files/biglink.tar
Binary files differ
diff --git a/ext/phar/tests/tar/files/corrupt_tarmaker.php.inc b/ext/phar/tests/tar/files/corrupt_tarmaker.php.inc
new file mode 100644
index 0000000000..b0eba6cc69
--- /dev/null
+++ b/ext/phar/tests/tar/files/corrupt_tarmaker.php.inc
@@ -0,0 +1,177 @@
+<?php
+// stolen from PEAR2_Pyrus_Developer_Creator_Tar by Greg Beaver, the original author, for use in unit tests
+class corrupt_tarmaker
+{
+ /**
+ * Path to archive file
+ *
+ * @var string
+ */
+ protected $archive;
+ /**
+ * Temporary stream used for creating the archive
+ *
+ * @var stream
+ */
+ protected $tmp;
+ protected $path;
+ protected $compress;
+ function __construct($path, $compress = 'zlib')
+ {
+ $this->compress = $compress;
+ if ($compress === 'bz2' && !function_exists('bzopen')) {
+ throw new PEAR2_Pyrus_Developer_Creator_Exception(
+ 'bzip2 extension not available');
+ }
+ if ($compress === 'zlib' && !function_exists('gzopen')) {
+ throw new PEAR2_Pyrus_Developer_Creator_Exception(
+ 'zlib extension not available');
+ }
+ $this->path = $path;
+ }
+
+ /**
+ * save a file inside this package
+ *
+ * This code is modified from Vincent Lascaux's File_Archive
+ * package, which is licensed under the LGPL license.
+ * @param string relative path within the package
+ * @param string|resource file contents or open file handle
+ */
+ function addFile($path, $fileOrStream, $stat = null, $corrupt = null)
+ {
+ clearstatcache();
+ if ($stat === null) {
+ if (is_resource($fileOrStream)) {
+ $stat = fstat($fileOrStream);
+ } else {
+ $stat = array(
+ 'mode' => 0x8000 + 0644,
+ 'uid' => 0,
+ 'gid' => 0,
+ 'size' => strlen($fileOrStream),
+ 'mtime' => time(),
+ );
+ }
+ }
+
+ $link = null;
+ if ($stat['mode'] & 0xA000 && $corrupt === 'symlink') {
+ $type = 2; // Symbolic Link
+ $link = $fileOrStream;
+ $stat['size'] = 0;
+ $fileOrStream = '';
+ } else if ($stat['mode'] & 0xA000) {
+ $type = 1; // Link
+ $link = $fileOrStream;
+ $stat['size'] = 0;
+ $fileOrStream = '';
+ } else if ($stat['mode'] & 0x4000) {
+ $type = 5; // Directory
+ } else if ($stat['mode'] & 0x8000) {
+ $type = 0; // Regular
+ } else {
+ $type = 9; // Unknown
+ }
+
+ $filePrefix = '';
+ if (strlen($path) > 255) {
+ throw new Exception(
+ "$path is too long, must be 255 characters or less"
+ );
+ } else if (strlen($path) > 100) {
+ $filePrefix = substr($path, 0, strlen($path)-100);
+ $path = substr($path, -100);
+ }
+
+ $block = pack('a100a8a8a8a12A12',
+ $path,
+ decoct($stat['mode']),
+ sprintf('%6s ',decoct($stat['uid'])),
+ sprintf('%6s ',decoct($stat['gid'])),
+ sprintf('%11s ',decoct($stat['size'])),
+ sprintf('%11s ',decoct($stat['mtime']))
+ );
+
+ $blockend = pack('a1a100a6a2a32a32a8a8a155a12',
+ $type,
+ $link,
+ 'ustar',
+ '00',
+ 'Pyrus',
+ 'Pyrus',
+ '',
+ '',
+ $filePrefix,
+ '');
+
+ $checkheader = array_merge(str_split($block), str_split($blockend));
+ if (!function_exists('_pear2tarchecksum')) {
+ function _pear2tarchecksum($a, $b) {return $a + ord($b);}
+ }
+ $checksum = 256; // 8 * ord(' ');
+ $checksum += array_reduce($checkheader, '_pear2tarchecksum');
+
+ if ($corrupt === 'checksum') $checksum++;
+ $checksum = pack('a8', sprintf('%6s ', decoct($checksum)));
+
+ fwrite($this->tmp, $block . $checksum . $blockend, 512);
+ if (is_resource($fileOrStream)) {
+ stream_copy_to_stream($fileOrStream, $this->tmp);
+ if ($stat['size'] % 512) {
+ fwrite($this->tmp, str_repeat("\0", 512 - $stat['size'] % 512));
+ }
+ } else {
+ fwrite($this->tmp, $fileOrStream);
+ if (strlen($fileOrStream) && !isset($link) && strlen($fileOrStream) % 512) {
+ fwrite($this->tmp, str_repeat("\0", 512 - strlen($fileOrStream) % 512));
+ }
+ }
+ }
+
+ /**
+ * Initialize the package creator
+ */
+ function init()
+ {
+ switch ($this->compress) {
+ case 'zlib' :
+ $this->tmp = gzopen($this->path, 'wb');
+ break;
+ case 'bz2' :
+ $this->tmp = bzopen($this->path, 'w');
+ break;
+ case 'none' :
+ $this->tmp = fopen($this->path, 'wb');
+ break;
+ default :
+ throw new Exception(
+ 'unknown compression type ' . $this->compress);
+ }
+ }
+
+ /**
+ * Create an internal directory, creating parent directories as needed
+ *
+ * @param string $dir
+ */
+ function mkdir($dir)
+ {
+ $this->addFile($dir, "", array(
+ 'mode' => 0x4000 + 0644,
+ 'uid' => 0,
+ 'gid' => 0,
+ 'size' => 0,
+ 'mtime' => time(),
+ ));
+ }
+
+ /**
+ * Finish saving the package
+ */
+ function close()
+ {
+ fwrite($this->tmp, pack('a1024', ''));
+ fclose($this->tmp);
+ }
+} \ No newline at end of file
diff --git a/ext/phar/tests/tar/files/frontcontroller.phar.inc b/ext/phar/tests/tar/files/frontcontroller.phar.inc
new file mode 100644
index 0000000000..6f426e8864
--- /dev/null
+++ b/ext/phar/tests/tar/files/frontcontroller.phar.inc
@@ -0,0 +1,13 @@
+<?php
+@unlink(dirname(__FILE__) . '/frontcontroller.phar.tar');
+$a = new Phar(dirname(__FILE__) . '/frontcontroller.phar.tar');
+$a['a.php'] = 'hio';
+$a['a.jpg'] = 'hio';
+$a['a.phps'] = '<?php function hio(){}';
+$a['index.php'] = 'here is my index';
+$a->setStub('<?php
+Phar::webPhar();
+echo "oops did not run\n";
+var_dump($_ENV, $_SERVER);
+__HALT_COMPILER();');
+?>
diff --git a/ext/phar/tests/tar/files/frontcontroller.phar.tar b/ext/phar/tests/tar/files/frontcontroller.phar.tar
new file mode 100644
index 0000000000..522d097845
--- /dev/null
+++ b/ext/phar/tests/tar/files/frontcontroller.phar.tar
Binary files differ
diff --git a/ext/phar/tests/tar/files/frontcontroller10.phar.inc b/ext/phar/tests/tar/files/frontcontroller10.phar.inc
new file mode 100644
index 0000000000..5b132fa117
--- /dev/null
+++ b/ext/phar/tests/tar/files/frontcontroller10.phar.inc
@@ -0,0 +1,20 @@
+<?php
+@unlink(dirname(__FILE__) . '/frontcontroller10.phar.tar');
+$a = new Phar(dirname(__FILE__) . '/frontcontroller10.phar.tar');
+$a['index.php'] = '<?php
+var_dump($_SERVER["PHP_SELF"]);
+var_dump($_SERVER["SCRIPT_NAME"]);
+var_dump($_SERVER["SCRIPT_FILENAME"]);
+var_dump($_SERVER["REQUEST_URI"]);
+var_dump($_SERVER["PHAR_PHP_SELF"]);
+var_dump($_SERVER["PHAR_SCRIPT_NAME"]);
+var_dump($_SERVER["PHAR_SCRIPT_FILENAME"]);
+var_dump($_SERVER["PHAR_REQUEST_URI"]);
+';
+$a->setStub('<?php
+Phar::mungServer(array("PHP_SELF", "SCRIPT_NAME", "SCRIPT_FILENAME", "REQUEST_URI", "OOPSIE"));
+Phar::webPhar();
+echo "oops did not run\n";
+var_dump($_ENV, $_SERVER);
+__HALT_COMPILER();');
+?>
diff --git a/ext/phar/tests/tar/files/frontcontroller10.phar.tar b/ext/phar/tests/tar/files/frontcontroller10.phar.tar
new file mode 100644
index 0000000000..d43ed916a1
--- /dev/null
+++ b/ext/phar/tests/tar/files/frontcontroller10.phar.tar
Binary files differ
diff --git a/ext/phar/tests/tar/files/frontcontroller11.phar.inc b/ext/phar/tests/tar/files/frontcontroller11.phar.inc
new file mode 100644
index 0000000000..2fa15f097e
--- /dev/null
+++ b/ext/phar/tests/tar/files/frontcontroller11.phar.inc
@@ -0,0 +1,20 @@
+<?php
+@unlink(dirname(__FILE__) . '/frontcontroller11.phar.tar');
+$a = new Phar(dirname(__FILE__) . '/frontcontroller11.phar.tar');
+$a['index.php'] = '<?php
+var_dump($_SERVER["PHP_SELF"]);
+var_dump($_SERVER["SCRIPT_NAME"]);
+var_dump($_SERVER["SCRIPT_FILENAME"]);
+var_dump($_SERVER["REQUEST_URI"]);
+var_dump($_SERVER["PHAR_PHP_SELF"]);
+var_dump($_SERVER["PHAR_SCRIPT_NAME"]);
+var_dump($_SERVER["PHAR_SCRIPT_FILENAME"]);
+var_dump($_SERVER["PHAR_REQUEST_URI"]);
+';
+$a->setStub('<?php
+Phar::mungServer(array(array(), "SCRIPT_NAME", "SCRIPT_FILENAME", "REQUEST_URI"));
+Phar::webPhar();
+echo "oops did not run\n";
+var_dump($_ENV, $_SERVER);
+__HALT_COMPILER();');
+?>
diff --git a/ext/phar/tests/tar/files/frontcontroller11.phar.tar b/ext/phar/tests/tar/files/frontcontroller11.phar.tar
new file mode 100644
index 0000000000..c8f98a1e78
--- /dev/null
+++ b/ext/phar/tests/tar/files/frontcontroller11.phar.tar
Binary files differ
diff --git a/ext/phar/tests/tar/files/frontcontroller12.phar.inc b/ext/phar/tests/tar/files/frontcontroller12.phar.inc
new file mode 100644
index 0000000000..693ef0aa01
--- /dev/null
+++ b/ext/phar/tests/tar/files/frontcontroller12.phar.inc
@@ -0,0 +1,20 @@
+<?php
+@unlink(dirname(__FILE__) . '/frontcontroller12.phar.tar');
+$a = new Phar(dirname(__FILE__) . '/frontcontroller12.phar.tar');
+$a['index.php'] = '<?php
+var_dump($_SERVER["PHP_SELF"]);
+var_dump($_SERVER["SCRIPT_NAME"]);
+var_dump($_SERVER["SCRIPT_FILENAME"]);
+var_dump($_SERVER["REQUEST_URI"]);
+var_dump($_SERVER["PHAR_PHP_SELF"]);
+var_dump($_SERVER["PHAR_SCRIPT_NAME"]);
+var_dump($_SERVER["PHAR_SCRIPT_FILENAME"]);
+var_dump($_SERVER["PHAR_REQUEST_URI"]);
+';
+$a->setStub('<?php
+Phar::mungServer(array("PHP_SELF", "SCRIPT_NAME", "SCRIPT_FILENAME", "REQUEST_URI"));
+Phar::webPhar();
+echo "oops did not run\n";
+var_dump($_ENV, $_SERVER);
+__HALT_COMPILER();');
+?>
diff --git a/ext/phar/tests/tar/files/frontcontroller12.phar.tar b/ext/phar/tests/tar/files/frontcontroller12.phar.tar
new file mode 100644
index 0000000000..06e7e59b03
--- /dev/null
+++ b/ext/phar/tests/tar/files/frontcontroller12.phar.tar
Binary files differ
diff --git a/ext/phar/tests/tar/files/frontcontroller2.phar.inc b/ext/phar/tests/tar/files/frontcontroller2.phar.inc
new file mode 100644
index 0000000000..8ae1171a38
--- /dev/null
+++ b/ext/phar/tests/tar/files/frontcontroller2.phar.inc
@@ -0,0 +1,12 @@
+<?php
+@unlink(dirname(__FILE__) . '/frontcontroller2.phar.tar');
+$a = new Phar(dirname(__FILE__) . '/frontcontroller2.phar.tar');
+$a['a.php'] = 'hio';
+$a['a.jpg'] = 'hio';
+$a['a.phps'] = '<?php function hio(){}';
+$a->setStub('<?php
+Phar::webPhar("whatever", "a.php");
+echo "oops did not run\n";
+var_dump($_ENV, $_SERVER);
+__HALT_COMPILER();');
+?>
diff --git a/ext/phar/tests/tar/files/frontcontroller2.phar.tar b/ext/phar/tests/tar/files/frontcontroller2.phar.tar
new file mode 100644
index 0000000000..857b116890
--- /dev/null
+++ b/ext/phar/tests/tar/files/frontcontroller2.phar.tar
Binary files differ
diff --git a/ext/phar/tests/tar/files/frontcontroller3.phar.inc b/ext/phar/tests/tar/files/frontcontroller3.phar.inc
new file mode 100644
index 0000000000..9729d0065b
--- /dev/null
+++ b/ext/phar/tests/tar/files/frontcontroller3.phar.inc
@@ -0,0 +1,18 @@
+<?php
+@unlink(dirname(__FILE__) . '/frontcontroller3.phar.tar');
+$a = new Phar(dirname(__FILE__) . '/frontcontroller3.phar.tar');
+$a['a.php'] = 'hio';
+$a['a.jpg'] = 'hio';
+$a['a.phps'] = '<?php function hio(){}';
+$a->setStub('<?php
+function s($a)
+{
+ static $b = array("/hi" => "a.phps");
+ if (isset($b[$a])) return $b[$a];
+ return $a;
+}
+Phar::webPhar("whatever", "/index.php", null, array(), "s");
+echo "oops did not run\n";
+var_dump($_ENV, $_SERVER);
+__HALT_COMPILER();');
+?>
diff --git a/ext/phar/tests/tar/files/frontcontroller3.phar.tar b/ext/phar/tests/tar/files/frontcontroller3.phar.tar
new file mode 100644
index 0000000000..f733884d12
--- /dev/null
+++ b/ext/phar/tests/tar/files/frontcontroller3.phar.tar
Binary files differ
diff --git a/ext/phar/tests/tar/files/frontcontroller4.phar.inc b/ext/phar/tests/tar/files/frontcontroller4.phar.inc
new file mode 100644
index 0000000000..eb1d56f0d4
--- /dev/null
+++ b/ext/phar/tests/tar/files/frontcontroller4.phar.inc
@@ -0,0 +1,18 @@
+<?php
+@unlink(dirname(__FILE__) . '/frontcontroller4.phar.tar');
+$a = new Phar(dirname(__FILE__) . '/frontcontroller4.phar.tar');
+$a['a.php'] = 'hio';
+$a['a.jpg'] = 'hio';
+$a['a.phps'] = '<?php function hio(){}';
+$a->setStub('<?php
+function s($a)
+{
+ static $b = array("/hi" => false);
+ if (isset($b[$a])) return $b[$a];
+ return $a;
+}
+Phar::webPhar("whatever", "index.php", null, array(), "s");
+echo "oops did not run\n";
+var_dump($_ENV, $_SERVER);
+__HALT_COMPILER();');
+?>
diff --git a/ext/phar/tests/tar/files/frontcontroller4.phar.tar b/ext/phar/tests/tar/files/frontcontroller4.phar.tar
new file mode 100644
index 0000000000..5d11af499c
--- /dev/null
+++ b/ext/phar/tests/tar/files/frontcontroller4.phar.tar
Binary files differ
diff --git a/ext/phar/tests/tar/files/frontcontroller5.phar.inc b/ext/phar/tests/tar/files/frontcontroller5.phar.inc
new file mode 100644
index 0000000000..d6204c7d97
--- /dev/null
+++ b/ext/phar/tests/tar/files/frontcontroller5.phar.inc
@@ -0,0 +1,12 @@
+<?php
+@unlink(dirname(__FILE__) . '/frontcontroller5.phar.tar');
+$a = new Phar(dirname(__FILE__) . '/frontcontroller5.phar.tar');
+$a['a.php'] = 'hio';
+$a['a.jpg'] = 'hio';
+$a['a.phps'] = '<?php function hio(){}';
+$a->setStub('<?php
+Phar::webPhar("whatever", "index.php", null, array(0 => "oops"));
+echo "oops did not run\n";
+var_dump($_ENV, $_SERVER);
+__HALT_COMPILER();');
+?>
diff --git a/ext/phar/tests/tar/files/frontcontroller5.phar.tar b/ext/phar/tests/tar/files/frontcontroller5.phar.tar
new file mode 100644
index 0000000000..e6e9015bf8
--- /dev/null
+++ b/ext/phar/tests/tar/files/frontcontroller5.phar.tar
Binary files differ
diff --git a/ext/phar/tests/tar/files/frontcontroller6.phar.inc b/ext/phar/tests/tar/files/frontcontroller6.phar.inc
new file mode 100644
index 0000000000..66212d82e8
--- /dev/null
+++ b/ext/phar/tests/tar/files/frontcontroller6.phar.inc
@@ -0,0 +1,12 @@
+<?php
+@unlink(dirname(__FILE__) . '/frontcontroller6.phar.tar');
+$a = new Phar(dirname(__FILE__) . '/frontcontroller6.phar.tar');
+$a['a.php'] = 'hio';
+$a['a.jpg'] = 'hio';
+$a['a.phps'] = '<?php function hio(){}';
+$a->setStub('<?php
+Phar::webPhar("whatever", "index.php", null, array("blah" => 100));
+echo "oops did not run\n";
+var_dump($_ENV, $_SERVER);
+__HALT_COMPILER();');
+?>
diff --git a/ext/phar/tests/tar/files/frontcontroller6.phar.tar b/ext/phar/tests/tar/files/frontcontroller6.phar.tar
new file mode 100644
index 0000000000..d30b7ab9eb
--- /dev/null
+++ b/ext/phar/tests/tar/files/frontcontroller6.phar.tar
Binary files differ
diff --git a/ext/phar/tests/tar/files/frontcontroller7.phar.inc b/ext/phar/tests/tar/files/frontcontroller7.phar.inc
new file mode 100644
index 0000000000..74adf2c008
--- /dev/null
+++ b/ext/phar/tests/tar/files/frontcontroller7.phar.inc
@@ -0,0 +1,12 @@
+<?php
+@unlink(dirname(__FILE__) . '/frontcontroller7.phar.tar');
+$a = new Phar(dirname(__FILE__) . '/frontcontroller7.phar.tar');
+$a['a.php'] = 'hio';
+$a['a.jpg'] = 'hio';
+$a['a.phps'] = '<?php function hio(){}';
+$a->setStub('<?php
+Phar::webPhar("whatever", "index.php", null, array("blah" => null));
+echo "oops did not run\n";
+var_dump($_ENV, $_SERVER);
+__HALT_COMPILER();');
+?>
diff --git a/ext/phar/tests/tar/files/frontcontroller7.phar.tar b/ext/phar/tests/tar/files/frontcontroller7.phar.tar
new file mode 100644
index 0000000000..c7ccc940c1
--- /dev/null
+++ b/ext/phar/tests/tar/files/frontcontroller7.phar.tar
Binary files differ
diff --git a/ext/phar/tests/tar/files/frontcontroller8.phar.inc b/ext/phar/tests/tar/files/frontcontroller8.phar.inc
new file mode 100644
index 0000000000..f51a762806
--- /dev/null
+++ b/ext/phar/tests/tar/files/frontcontroller8.phar.inc
@@ -0,0 +1,13 @@
+<?php
+@unlink(dirname(__FILE__) . '/frontcontroller8.phar.tar');
+$a = new Phar(dirname(__FILE__) . '/frontcontroller8.phar.tar');
+$a['a.phps'] = 'hio1';
+$a['a.jpg'] = 'hio2';
+$a['a.php'] = '<?php function hio(){}';
+$a['fronk.gronk'] = 'hio3';
+$a->setStub('<?php
+Phar::webPhar("whatever", "index.php", null, array("jpg" => "foo/bar", "phps" => Phar::PHP, "php" => Phar::PHPS));
+echo "oops did not run\n";
+var_dump($_ENV, $_SERVER);
+__HALT_COMPILER();');
+?>
diff --git a/ext/phar/tests/tar/files/frontcontroller8.phar.tar b/ext/phar/tests/tar/files/frontcontroller8.phar.tar
new file mode 100644
index 0000000000..98495717ce
--- /dev/null
+++ b/ext/phar/tests/tar/files/frontcontroller8.phar.tar
Binary files differ
diff --git a/ext/phar/tests/tar/files/frontcontroller9.phar.inc b/ext/phar/tests/tar/files/frontcontroller9.phar.inc
new file mode 100644
index 0000000000..758ce4ff4e
--- /dev/null
+++ b/ext/phar/tests/tar/files/frontcontroller9.phar.inc
@@ -0,0 +1,14 @@
+<?php
+@unlink(dirname(__FILE__) . '/frontcontroller9.phar.tar');
+$a = new Phar(dirname(__FILE__) . '/frontcontroller9.phar.tar');
+$a['a.phps'] = 'hio1';
+$a['a.jpg'] = 'hio2';
+$a['a.php'] = '<?php function hio(){}';
+$a['fronk.gronk'] = 'hio3';
+$a->setStub('<?php
+Phar::mungServer(array());
+Phar::webPhar("whatever", "index.php", null, array("jpg" => "foo/bar", "phps" => Phar::PHP, "php" => Phar::PHPS));
+echo "oops did not run\n";
+var_dump($_ENV, $_SERVER);
+__HALT_COMPILER();');
+?>
diff --git a/ext/phar/tests/tar/files/frontcontroller9.phar.tar b/ext/phar/tests/tar/files/frontcontroller9.phar.tar
new file mode 100644
index 0000000000..481864c1cf
--- /dev/null
+++ b/ext/phar/tests/tar/files/frontcontroller9.phar.tar
Binary files differ
diff --git a/ext/phar/tests/tar/files/links.tar b/ext/phar/tests/tar/files/links.tar
new file mode 100644
index 0000000000..6cd22df2bc
--- /dev/null
+++ b/ext/phar/tests/tar/files/links.tar
Binary files differ
diff --git a/ext/phar/tests/tar/files/make_invalid_tar.php.inc b/ext/phar/tests/tar/files/make_invalid_tar.php.inc
new file mode 100644
index 0000000000..c18bd199b3
--- /dev/null
+++ b/ext/phar/tests/tar/files/make_invalid_tar.php.inc
@@ -0,0 +1,9 @@
+<?php
+include dirname(__FILE__) . '/tarmaker.php.inc';
+class corrupter extends tarmaker {
+function close()
+{
+ fwrite($this->tmp, 'oopsie');
+ fclose($this->tmp);
+}
+} \ No newline at end of file
diff --git a/ext/phar/tests/tar/files/subdirlink.tar b/ext/phar/tests/tar/files/subdirlink.tar
new file mode 100644
index 0000000000..5463a4942d
--- /dev/null
+++ b/ext/phar/tests/tar/files/subdirlink.tar
Binary files differ
diff --git a/ext/phar/tests/tar/files/tarmaker.php.inc b/ext/phar/tests/tar/files/tarmaker.php.inc
new file mode 100644
index 0000000000..902507881a
--- /dev/null
+++ b/ext/phar/tests/tar/files/tarmaker.php.inc
@@ -0,0 +1,169 @@
+<?php
+// stolen from PEAR2_Pyrus_Developer_Creator_Tar by Greg Beaver, the original author, for use in unit tests
+class tarmaker
+{
+ /**
+ * Path to archive file
+ *
+ * @var string
+ */
+ protected $archive;
+ /**
+ * Temporary stream used for creating the archive
+ *
+ * @var stream
+ */
+ protected $tmp;
+ protected $path;
+ protected $compress;
+ function __construct($path, $compress = 'zlib')
+ {
+ $this->compress = $compress;
+ if ($compress === 'bz2' && !function_exists('bzopen')) {
+ throw new PEAR2_Pyrus_Developer_Creator_Exception(
+ 'bzip2 extension not available');
+ }
+ if ($compress === 'zlib' && !function_exists('gzopen')) {
+ throw new PEAR2_Pyrus_Developer_Creator_Exception(
+ 'zlib extension not available');
+ }
+ $this->path = $path;
+ }
+
+ /**
+ * save a file inside this package
+ *
+ * This code is modified from Vincent Lascaux's File_Archive
+ * package, which is licensed under the LGPL license.
+ * @param string relative path within the package
+ * @param string|resource file contents or open file handle
+ */
+ function addFile($path, $fileOrStream, $stat = null)
+ {
+ clearstatcache();
+ if ($stat === null) {
+ if (is_resource($fileOrStream)) {
+ $stat = fstat($fileOrStream);
+ } else {
+ $stat = array(
+ 'mode' => 0x8000 + 0644,
+ 'uid' => 0,
+ 'gid' => 0,
+ 'size' => strlen($fileOrStream),
+ 'mtime' => time(),
+ );
+ }
+ }
+
+ $link = null;
+ if ($stat['mode'] & 0x4000) {
+ $type = 5; // Directory
+ } else if ($stat['mode'] & 0x8000) {
+ $type = 0; // Regular
+ } else if ($stat['mode'] & 0xA000) {
+ $type = 1; // Link
+ $link = @readlink($current);
+ } else {
+ $type = 9; // Unknown
+ }
+
+ $filePrefix = '';
+ if (strlen($path) > 255) {
+ throw new Exception(
+ "$path is too long, must be 255 characters or less"
+ );
+ } else if (strlen($path) > 100) {
+ $filePrefix = substr($path, 0, strlen($path)-100);
+ $path = substr($path, -100);
+ }
+
+ $block = pack('a100a8a8a8a12A12',
+ $path,
+ decoct($stat['mode']),
+ sprintf('%6s ',decoct($stat['uid'])),
+ sprintf('%6s ',decoct($stat['gid'])),
+ sprintf('%11s ',decoct($stat['size'])),
+ sprintf('%11s ',decoct($stat['mtime']))
+ );
+
+ $blockend = pack('a1a100a6a2a32a32a8a8a155a12',
+ $type,
+ $link,
+ 'ustar',
+ '00',
+ 'Pyrus',
+ 'Pyrus',
+ '',
+ '',
+ $filePrefix,
+ '');
+
+ $checkheader = array_merge(str_split($block), str_split($blockend));
+ if (!function_exists('_pear2tarchecksum')) {
+ function _pear2tarchecksum($a, $b) {return $a + ord($b);}
+ }
+ $checksum = 256; // 8 * ord(' ');
+ $checksum += array_reduce($checkheader, '_pear2tarchecksum');
+
+ $checksum = pack('a8', sprintf('%6s ', decoct($checksum)));
+
+ fwrite($this->tmp, $block . $checksum . $blockend, 512);
+ if (is_resource($fileOrStream)) {
+ stream_copy_to_stream($fileOrStream, $this->tmp);
+ if ($stat['size'] % 512) {
+ fwrite($this->tmp, str_repeat("\0", 512 - $stat['size'] % 512));
+ }
+ } else {
+ fwrite($this->tmp, $fileOrStream);
+ if (strlen($fileOrStream) % 512) {
+ fwrite($this->tmp, str_repeat("\0", 512 - strlen($fileOrStream) % 512));
+ }
+ }
+ }
+
+ /**
+ * Initialize the package creator
+ */
+ function init()
+ {
+ switch ($this->compress) {
+ case 'zlib' :
+ $this->tmp = gzopen($this->path, 'wb');
+ break;
+ case 'bz2' :
+ $this->tmp = bzopen($this->path, 'w');
+ break;
+ case 'none' :
+ $this->tmp = fopen($this->path, 'wb');
+ break;
+ default :
+ throw new Exception(
+ 'unknown compression type ' . $this->compress);
+ }
+ }
+
+ /**
+ * Create an internal directory, creating parent directories as needed
+ *
+ * @param string $dir
+ */
+ function mkdir($dir)
+ {
+ $this->addFile($dir, "", array(
+ 'mode' => 0x4000 + 0644,
+ 'uid' => 0,
+ 'gid' => 0,
+ 'size' => 0,
+ 'mtime' => time(),
+ ));
+ }
+
+ /**
+ * Finish saving the package
+ */
+ function close()
+ {
+ fwrite($this->tmp, pack('a1024', ''));
+ fclose($this->tmp);
+ }
+} \ No newline at end of file
diff --git a/ext/phar/tests/tar/files/tinylink.tar b/ext/phar/tests/tar/files/tinylink.tar
new file mode 100644
index 0000000000..741b56c2f5
--- /dev/null
+++ b/ext/phar/tests/tar/files/tinylink.tar
Binary files differ
diff --git a/ext/phar/tests/tar/files/trunc.tar b/ext/phar/tests/tar/files/trunc.tar
new file mode 100644
index 0000000000..2156b5c623
--- /dev/null
+++ b/ext/phar/tests/tar/files/trunc.tar
Binary files differ
diff --git a/ext/phar/tests/tar/frontcontroller1.phar.phpt b/ext/phar/tests/tar/frontcontroller1.phar.phpt
new file mode 100644
index 0000000000..77158169bb
--- /dev/null
+++ b/ext/phar/tests/tar/frontcontroller1.phar.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Phar front controller other tar-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller1.phar.php
+REQUEST_URI=/frontcontroller1.phar.php/a.jpg
+PATH_INFO=/a.jpg
+--FILE_EXTERNAL--
+files/frontcontroller.phar.tar
+--EXPECTHEADERS--
+Content-type: image/jpeg
+Content-length: 3
+--EXPECT--
+hio
diff --git a/ext/phar/tests/tar/frontcontroller10.phar.phpt b/ext/phar/tests/tar/frontcontroller10.phar.phpt
new file mode 100644
index 0000000000..0ca67b3d3e
--- /dev/null
+++ b/ext/phar/tests/tar/frontcontroller10.phar.phpt
@@ -0,0 +1,22 @@
+--TEST--
+Phar front controller rewrite array invalid tar-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller10.phar.php
+REQUEST_URI=/frontcontroller10.phar.php/hi
+PATH_INFO=/hi
+--FILE_EXTERNAL--
+files/frontcontroller4.phar.tar
+--EXPECTHEADERS--
+Content-type: text/html
+Status: 403 Access Denied
+--EXPECT--
+<html>
+ <head>
+ <title>Access Denied</title>
+ </head>
+ <body>
+ <h1>403 - File /hi Access Denied</h1>
+ </body>
+</html> \ No newline at end of file
diff --git a/ext/phar/tests/tar/frontcontroller11.phar.phpt b/ext/phar/tests/tar/frontcontroller11.phar.phpt
new file mode 100644
index 0000000000..3a420f6c85
--- /dev/null
+++ b/ext/phar/tests/tar/frontcontroller11.phar.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Phar front controller mime type extension is not a string tar-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller11.phar.php
+REQUEST_URI=/frontcontroller11.phar.php/a.php
+PATH_INFO=/a.php
+--FILE_EXTERNAL--
+files/frontcontroller5.phar.tar
+--EXPECTHEADERS--
+Content-type: text/html
+--EXPECTF--
+Fatal error: Uncaught exception 'PharException' with message 'Key of MIME type overrides array must be a file extension, was "0"' in %sfrontcontroller11.phar.php:2
+Stack trace:
+#0 %sfrontcontroller11.phar.php(2): Phar::webPhar('whatever', 'index.php', '', Array)
+#1 {main}
+ thrown in %sfrontcontroller11.phar.php on line 2 \ No newline at end of file
diff --git a/ext/phar/tests/tar/frontcontroller12.phar.phpt b/ext/phar/tests/tar/frontcontroller12.phar.phpt
new file mode 100644
index 0000000000..e659434e07
--- /dev/null
+++ b/ext/phar/tests/tar/frontcontroller12.phar.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Phar front controller mime type unknown int tar-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller12.phar.php
+REQUEST_URI=/frontcontroller12.phar.php/a.php
+PATH_INFO=/a.php
+--FILE_EXTERNAL--
+files/frontcontroller6.phar.tar
+--EXPECTHEADERS--
+Content-type: text/html
+--EXPECTF--
+Fatal error: Uncaught exception 'PharException' with message 'Unknown mime type specifier used, only Phar::PHP, Phar::PHPS and a mime type string are allowed' in %sfrontcontroller12.phar.php:2
+Stack trace:
+#0 %sfrontcontroller12.phar.php(2): Phar::webPhar('whatever', 'index.php', '', Array)
+#1 {main}
+ thrown in %sfrontcontroller12.phar.php on line 2 \ No newline at end of file
diff --git a/ext/phar/tests/tar/frontcontroller13.phar.phpt b/ext/phar/tests/tar/frontcontroller13.phar.phpt
new file mode 100644
index 0000000000..0b9d3e3895
--- /dev/null
+++ b/ext/phar/tests/tar/frontcontroller13.phar.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Phar front controller mime type not string/int tar-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller13.phar.php
+REQUEST_URI=/frontcontroller13.phar.php/a.php
+PATH_INFO=/a.php
+--FILE_EXTERNAL--
+files/frontcontroller7.phar.tar
+--EXPECTHEADERS--
+Content-type: text/html
+--EXPECTF--
+Fatal error: Uncaught exception 'PharException' with message 'Unknown mime type specifier used (not a string or int), only Phar::PHP, Phar::PHPS and a mime type string are allowed' in %sfrontcontroller13.phar.php:2
+Stack trace:
+#0 %sfrontcontroller13.phar.php(2): Phar::webPhar('whatever', 'index.php', '', Array)
+#1 {main}
+ thrown in %sfrontcontroller13.phar.php on line 2 \ No newline at end of file
diff --git a/ext/phar/tests/tar/frontcontroller14.phar.phpt b/ext/phar/tests/tar/frontcontroller14.phar.phpt
new file mode 100644
index 0000000000..c40f9b6c34
--- /dev/null
+++ b/ext/phar/tests/tar/frontcontroller14.phar.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Phar front controller mime type override, other tar-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller14.phar.php
+REQUEST_URI=/frontcontroller14.phar.php/a.jpg
+PATH_INFO=/a.jpg
+--FILE_EXTERNAL--
+files/frontcontroller8.phar.tar
+--EXPECTHEADERS--
+Content-type: foo/bar
+Content-length: 4
+--EXPECT--
+hio2
diff --git a/ext/phar/tests/tar/frontcontroller15.phar.phpt b/ext/phar/tests/tar/frontcontroller15.phar.phpt
new file mode 100644
index 0000000000..154117fda4
--- /dev/null
+++ b/ext/phar/tests/tar/frontcontroller15.phar.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Phar front controller mime type override, Phar::PHPS tar-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller15.phar.php
+REQUEST_URI=/frontcontroller15.phar.php/a.php
+PATH_INFO=/a.php
+--FILE_EXTERNAL--
+files/frontcontroller8.phar.tar
+--EXPECTHEADERS--
+Content-type: text/html
+--EXPECT--
+<code><span style="color: #000000">
+<span style="color: #0000BB">&lt;?php&nbsp;</span><span style="color: #007700">function&nbsp;</span><span style="color: #0000BB">hio</span><span style="color: #007700">(){}</span>
+</span>
+</code>
+
diff --git a/ext/phar/tests/tar/frontcontroller16.phar.phpt b/ext/phar/tests/tar/frontcontroller16.phar.phpt
new file mode 100644
index 0000000000..042a695eb3
--- /dev/null
+++ b/ext/phar/tests/tar/frontcontroller16.phar.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Phar front controller mime type override, Phar::PHP tar-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller16.phar.php
+REQUEST_URI=/frontcontroller16.phar.php/a.phps
+PATH_INFO=/a.phps
+--FILE_EXTERNAL--
+files/frontcontroller8.phar.tar
+--EXPECTHEADERS--
+Content-type: text/html
+--EXPECT--
+hio1
+
diff --git a/ext/phar/tests/tar/frontcontroller17.phar.phpt b/ext/phar/tests/tar/frontcontroller17.phar.phpt
new file mode 100644
index 0000000000..17d04baf30
--- /dev/null
+++ b/ext/phar/tests/tar/frontcontroller17.phar.phpt
@@ -0,0 +1,16 @@
+--TEST--
+Phar front controller mime type unknown tar-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller17.phar.php
+REQUEST_URI=/frontcontroller17.phar.php/fronk.gronk
+PATH_INFO=/fronk.gronk
+--FILE_EXTERNAL--
+files/frontcontroller8.phar.tar
+--EXPECTHEADERS--
+Content-type: application/octet-stream
+Content-length: 4
+--EXPECT--
+hio3
+
diff --git a/ext/phar/tests/tar/frontcontroller18.phar.phpt b/ext/phar/tests/tar/frontcontroller18.phar.phpt
new file mode 100644
index 0000000000..c52ce291c7
--- /dev/null
+++ b/ext/phar/tests/tar/frontcontroller18.phar.phpt
@@ -0,0 +1,16 @@
+--TEST--
+Phar front controller $_SERVER munging failure tar-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller18.phar.php
+REQUEST_URI=/frontcontroller18.phar.php/fronk.gronk
+PATH_INFO=/fronk.gronk
+--FILE_EXTERNAL--
+files/frontcontroller9.phar.tar
+--EXPECTF--
+Fatal error: Uncaught exception 'PharException' with message 'No values passed to Phar::mungServer(), expecting an array of any of these strings: PHP_SELF, REQUEST_URI, SCRIPT_FILENAME, SCRIPT_NAME' in %sfrontcontroller18.phar.php:2
+Stack trace:
+#0 %sfrontcontroller18.phar.php(2): Phar::mungServer(Array)
+#1 {main}
+ thrown in %sfrontcontroller18.phar.php on line 2
diff --git a/ext/phar/tests/tar/frontcontroller19.phar.phpt b/ext/phar/tests/tar/frontcontroller19.phar.phpt
new file mode 100644
index 0000000000..6b07438787
--- /dev/null
+++ b/ext/phar/tests/tar/frontcontroller19.phar.phpt
@@ -0,0 +1,16 @@
+--TEST--
+Phar front controller $_SERVER munging failure 2 tar-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller19.phar.php
+REQUEST_URI=/frontcontroller19.phar.php/
+PATH_INFO=/
+--FILE_EXTERNAL--
+files/frontcontroller10.phar.tar
+--EXPECTF--
+Fatal error: Uncaught exception 'PharException' with message 'Too many values passed to Phar::mungServer(), expecting an array of any of these strings: PHP_SELF, REQUEST_URI, SCRIPT_FILENAME, SCRIPT_NAME' in %sfrontcontroller19.phar.php:2
+Stack trace:
+#0 %sfrontcontroller19.phar.php(2): Phar::mungServer(Array)
+#1 {main}
+ thrown in %sfrontcontroller19.phar.php on line 2
diff --git a/ext/phar/tests/tar/frontcontroller2.phar.phpt b/ext/phar/tests/tar/frontcontroller2.phar.phpt
new file mode 100644
index 0000000000..a6b1c780fd
--- /dev/null
+++ b/ext/phar/tests/tar/frontcontroller2.phar.phpt
@@ -0,0 +1,14 @@
+--TEST--
+Phar front controller PHP test tar-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller2.phar.php
+REQUEST_URI=/frontcontroller2.phar.php/a.php
+PATH_INFO=/a.php
+--FILE_EXTERNAL--
+files/frontcontroller.phar.tar
+--EXPECTHEADERS--
+Content-type: text/html
+--EXPECT--
+hio
diff --git a/ext/phar/tests/tar/frontcontroller20.phar.phpt b/ext/phar/tests/tar/frontcontroller20.phar.phpt
new file mode 100644
index 0000000000..3cc470d41b
--- /dev/null
+++ b/ext/phar/tests/tar/frontcontroller20.phar.phpt
@@ -0,0 +1,16 @@
+--TEST--
+Phar front controller $_SERVER munging failure 3 tar-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller20.phar.php
+REQUEST_URI=/frontcontroller20.phar.php/
+PATH_INFO=/
+--FILE_EXTERNAL--
+files/frontcontroller11.phar.tar
+--EXPECTF--
+Fatal error: Uncaught exception 'PharException' with message 'Non-string value passed to Phar::mungServer(), expecting an array of any of these strings: PHP_SELF, REQUEST_URI, SCRIPT_FILENAME, SCRIPT_NAME' in %sfrontcontroller20.phar.php:2
+Stack trace:
+#0 %sfrontcontroller20.phar.php(2): Phar::mungServer(Array)
+#1 {main}
+ thrown in %sfrontcontroller20.phar.php on line 2
diff --git a/ext/phar/tests/tar/frontcontroller21.phar.phpt b/ext/phar/tests/tar/frontcontroller21.phar.phpt
new file mode 100644
index 0000000000..eb21897226
--- /dev/null
+++ b/ext/phar/tests/tar/frontcontroller21.phar.phpt
@@ -0,0 +1,22 @@
+--TEST--
+Phar front controller $_SERVER munging success tar-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller21.phar.php
+REQUEST_URI=/frontcontroller21.phar.php/index.php?test=hi
+PATH_INFO=/index.php
+QUERY_STRING=test=hi
+--FILE_EXTERNAL--
+files/frontcontroller12.phar.tar
+--EXPECTHEADERS--
+Content-type: text/html
+--EXPECTF--
+string(10) "/index.php"
+string(10) "/index.php"
+string(%d) "phar://%sfrontcontroller21.phar.php/index.php"
+string(18) "/index.php?test=hi"
+string(37) "/frontcontroller21.phar.php/index.php"
+string(27) "/frontcontroller21.phar.php"
+string(%d) "%sfrontcontroller21.phar.php"
+string(45) "/frontcontroller21.phar.php/index.php?test=hi" \ No newline at end of file
diff --git a/ext/phar/tests/tar/frontcontroller3.phar.phpt b/ext/phar/tests/tar/frontcontroller3.phar.phpt
new file mode 100644
index 0000000000..dee16ee2b2
--- /dev/null
+++ b/ext/phar/tests/tar/frontcontroller3.phar.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Phar front controller phps tar-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller3.phar.php
+REQUEST_URI=/frontcontroller3.phar.php/a.phps
+PATH_INFO=/a.phps
+--FILE_EXTERNAL--
+files/frontcontroller.phar.tar
+--EXPECTHEADERS--
+Content-type: text/html
+--EXPECT--
+<code><span style="color: #000000">
+<span style="color: #0000BB">&lt;?php&nbsp;</span><span style="color: #007700">function&nbsp;</span><span style="color: #0000BB">hio</span><span style="color: #007700">(){}</span>
+</span>
+</code>
diff --git a/ext/phar/tests/tar/frontcontroller4.phar.phpt b/ext/phar/tests/tar/frontcontroller4.phar.phpt
new file mode 100644
index 0000000000..db4846c69b
--- /dev/null
+++ b/ext/phar/tests/tar/frontcontroller4.phar.phpt
@@ -0,0 +1,13 @@
+--TEST--
+Phar front controller index.php relocate (no /) tar-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller4.phar.php
+REQUEST_URI=/frontcontroller4.phar.php
+--FILE_EXTERNAL--
+files/frontcontroller.phar.tar
+--EXPECTHEADERS--
+Status: 301 Moved Permanently
+Location: /frontcontroller4.phar.php/index.php
+--EXPECT--
diff --git a/ext/phar/tests/tar/frontcontroller5.phar.phpt b/ext/phar/tests/tar/frontcontroller5.phar.phpt
new file mode 100644
index 0000000000..534e66a1e3
--- /dev/null
+++ b/ext/phar/tests/tar/frontcontroller5.phar.phpt
@@ -0,0 +1,14 @@
+--TEST--
+Phar front controller index.php relocate tar-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller5.phar.php
+REQUEST_URI=/frontcontroller5.phar.php/
+PATH_INFO=/
+--FILE_EXTERNAL--
+files/frontcontroller.phar.tar
+--EXPECTHEADERS--
+Status: 301 Moved Permanently
+Location: /frontcontroller5.phar.php/index.php
+--EXPECT--
diff --git a/ext/phar/tests/tar/frontcontroller6.phar.phpt b/ext/phar/tests/tar/frontcontroller6.phar.phpt
new file mode 100644
index 0000000000..5375beef8c
--- /dev/null
+++ b/ext/phar/tests/tar/frontcontroller6.phar.phpt
@@ -0,0 +1,21 @@
+--TEST--
+Phar front controller 404 tar-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller6.phar.php
+REQUEST_URI=/frontcontroller6.phar.php/notfound.php
+PATH_INFO=/notfound.php
+--FILE_EXTERNAL--
+files/frontcontroller.phar.tar
+--EXPECTHEADERS--
+Status: 404 Not Found
+--EXPECT--
+<html>
+ <head>
+ <title>File Not Found</title>
+ </head>
+ <body>
+ <h1>404 - File /notfound.php Not Found</h1>
+ </body>
+</html> \ No newline at end of file
diff --git a/ext/phar/tests/tar/frontcontroller7.phar.phpt b/ext/phar/tests/tar/frontcontroller7.phar.phpt
new file mode 100644
index 0000000000..3b73f2075c
--- /dev/null
+++ b/ext/phar/tests/tar/frontcontroller7.phar.phpt
@@ -0,0 +1,14 @@
+--TEST--
+Phar front controller alternate index file tar-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller7.phar.php
+REQUEST_URI=/frontcontroller7.phar.php/
+PATH_INFO=/
+--FILE_EXTERNAL--
+files/frontcontroller2.phar.tar
+--EXPECTHEADERS--
+Status: 301 Moved Permanently
+Location: /frontcontroller7.phar.php/a.php
+--EXPECT--
diff --git a/ext/phar/tests/tar/frontcontroller8.phar.phpt b/ext/phar/tests/tar/frontcontroller8.phar.phpt
new file mode 100644
index 0000000000..19844cb199
--- /dev/null
+++ b/ext/phar/tests/tar/frontcontroller8.phar.phpt
@@ -0,0 +1,21 @@
+--TEST--
+Phar front controller no index file 404 tar-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller8.phar.php
+REQUEST_URI=/frontcontroller8.phar.php/
+PATH_INFO=/
+--FILE_EXTERNAL--
+files/frontcontroller3.phar.tar
+--EXPECTHEADERS--
+Status: 404 Not Found
+--EXPECT--
+<html>
+ <head>
+ <title>File Not Found</title>
+ </head>
+ <body>
+ <h1>404 - File /index.php Not Found</h1>
+ </body>
+</html> \ No newline at end of file
diff --git a/ext/phar/tests/tar/frontcontroller9.phar.phpt b/ext/phar/tests/tar/frontcontroller9.phar.phpt
new file mode 100644
index 0000000000..080db58f8f
--- /dev/null
+++ b/ext/phar/tests/tar/frontcontroller9.phar.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Phar front controller rewrite array tar-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller9.phar.php
+REQUEST_URI=/frontcontroller9.phar.php/hi
+PATH_INFO=/hi
+--FILE_EXTERNAL--
+files/frontcontroller3.phar.tar
+--EXPECTHEADERS--
+Content-type: text/html
+--EXPECT--
+<code><span style="color: #000000">
+<span style="color: #0000BB">&lt;?php&nbsp;</span><span style="color: #007700">function&nbsp;</span><span style="color: #0000BB">hio</span><span style="color: #007700">(){}</span>
+</span>
+</code> \ No newline at end of file
diff --git a/ext/phar/tests/tar/links.phpt b/ext/phar/tests/tar/links.phpt
new file mode 100644
index 0000000000..73e257b8be
--- /dev/null
+++ b/ext/phar/tests/tar/links.phpt
@@ -0,0 +1,33 @@
+--TEST--
+Phar: tar with hard link and symbolic link
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.tar';
+copy(dirname(__FILE__) . '/files/links.tar', $fname);
+try {
+ $p = new PharData($fname);
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+var_dump($p['testit/link']->getContent());
+var_dump($p['testit/hard']->getContent());
+var_dump($p['testit/file']->getContent());
+$p['testit/link'] = 'overwriting';
+var_dump($p['testit/link']->getContent());
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.tar');
+?>
+--EXPECT--
+string(3) "hi
+"
+string(3) "hi
+"
+string(3) "hi
+"
+string(11) "overwriting"
+===DONE===
diff --git a/ext/phar/tests/tar/links2.phpt b/ext/phar/tests/tar/links2.phpt
new file mode 100644
index 0000000000..1939e002bd
--- /dev/null
+++ b/ext/phar/tests/tar/links2.phpt
@@ -0,0 +1,35 @@
+--TEST--
+Phar: tar with hard link to nowhere
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.tar';
+$pname = 'phar://' . $fname;
+
+include dirname(__FILE__) . '/files/corrupt_tarmaker.php.inc';
+$a = new corrupt_tarmaker($fname, 'none');
+$a->init();
+$a->addFile('hardlink', 'internal/file.txt', array(
+ 'mode' => 0xA000 + 0644,
+ 'uid' => 0,
+ 'gid' => 0,
+ 'size' => 0,
+ 'mtime' => time(),
+ ));
+$a->close();
+
+try {
+ $p = new PharData($fname);
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.tar');
+?>
+--EXPECTF--
+phar error: "%slinks2.tar" is a corrupted tar file - hard link to non-existent file "internal/file.txt"
+===DONE===
diff --git a/ext/phar/tests/tar/links3.phpt b/ext/phar/tests/tar/links3.phpt
new file mode 100644
index 0000000000..2241081660
--- /dev/null
+++ b/ext/phar/tests/tar/links3.phpt
@@ -0,0 +1,19 @@
+--TEST--
+Phar: tar with link to absolute path
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--FILE--
+<?php
+try {
+ $p = new PharData(dirname(__FILE__) . '/files/biglink.tar');
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+echo $p['file.txt']->getContent();
+echo $p['my/file']->getContent();
+?>
+===DONE===
+--EXPECT--
+my file
+my file
+===DONE===
diff --git a/ext/phar/tests/tar/links4.phpt b/ext/phar/tests/tar/links4.phpt
new file mode 100644
index 0000000000..d0783e84ac
--- /dev/null
+++ b/ext/phar/tests/tar/links4.phpt
@@ -0,0 +1,19 @@
+--TEST--
+Phar: tar with link to root directory file from root directory file
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--FILE--
+<?php
+try {
+ $p = new PharData(dirname(__FILE__) . '/files/tinylink.tar');
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+echo $p['file.txt']->getContent();
+echo $p['link.txt']->getContent();
+?>
+===DONE===
+--EXPECT--
+hi
+hi
+===DONE===
diff --git a/ext/phar/tests/tar/links5.phpt b/ext/phar/tests/tar/links5.phpt
new file mode 100644
index 0000000000..262d41d841
--- /dev/null
+++ b/ext/phar/tests/tar/links5.phpt
@@ -0,0 +1,19 @@
+--TEST--
+Phar: tar with relative link to subdirectory file from subdirectory file
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--FILE--
+<?php
+try {
+ $p = new PharData(dirname(__FILE__) . '/files/subdirlink.tar');
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+echo $p['hi/test.txt']->getContent();
+echo $p['hi/link.txt']->getContent();
+?>
+===DONE===
+--EXPECT--
+hi
+hi
+===DONE===
diff --git a/ext/phar/tests/tar/open_for_write_existing.phpt b/ext/phar/tests/tar/open_for_write_existing.phpt
new file mode 100644
index 0000000000..641e5ce21d
--- /dev/null
+++ b/ext/phar/tests/tar/open_for_write_existing.phpt
@@ -0,0 +1,42 @@
+--TEST--
+Phar: fopen a .phar for writing (existing file) tar-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar';
+$alias = 'phar://' . $fname;
+
+$phar = new Phar($fname);
+$phar->setStub("<?php __HALT_COMPILER(); ?>");
+
+$files = array();
+
+$files['a.php'] = '<?php echo "This is a\n"; ?>';
+$files['b.php'] = '<?php echo "This is b\n"; ?>';
+$files['b/c.php'] = '<?php echo "This is b/c\n"; ?>';
+
+foreach ($files as $n => $file) {
+ $phar[$n] = $file;
+}
+
+$phar->stopBuffering();
+
+$fp = fopen($alias . '/b/c.php', 'wb');
+fwrite($fp, 'extra');
+fclose($fp);
+
+include $alias . '/b/c.php';
+
+?>
+
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar'); ?>
+--EXPECT--
+extra
+===DONE===
diff --git a/ext/phar/tests/tar/open_for_write_existing_b.phpt b/ext/phar/tests/tar/open_for_write_existing_b.phpt
new file mode 100755
index 0000000000..54ec5855fb
--- /dev/null
+++ b/ext/phar/tests/tar/open_for_write_existing_b.phpt
@@ -0,0 +1,56 @@
+--TEST--
+Phar: fopen a .phar for writing (existing file) tar-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar';
+$alias = 'phar://' . $fname;
+
+$phar = new Phar($fname);
+$phar->setStub("<?php __HALT_COMPILER(); ?>");
+
+$files = array();
+
+$files['a.php'] = '<?php echo "This is a\n"; ?>';
+$files['b.php'] = '<?php echo "This is b\n"; ?>';
+$files['b/c.php'] = '<?php echo "This is b/c\n"; ?>';
+
+foreach ($files as $n => $file) {
+ $phar[$n] = $file;
+}
+
+$phar->stopBuffering();
+ini_set('phar.readonly', 1);
+
+function err_handler($errno, $errstr, $errfile, $errline) {
+ echo "Catchable fatal error: $errstr in $errfile on line $errline\n";
+}
+
+set_error_handler("err_handler", E_RECOVERABLE_ERROR);
+
+$fp = fopen($alias . '/b/c.php', 'wb');
+fwrite($fp, 'extra');
+fclose($fp);
+
+include $alias . '/b/c.php';
+
+?>
+
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar'); ?>
+--EXPECTF--
+
+Warning: fopen(phar://%sopen_for_write_existing_b.phar.tar/b/c.php): failed to open stream: phar error: write operations disabled by INI setting in %sopen_for_write_existing_b.php on line %d
+
+Warning: fwrite(): supplied argument is not a valid stream resource in %sopen_for_write_existing_b.php on line %d
+
+Warning: fclose(): supplied argument is not a valid stream resource in %spen_for_write_existing_b.php on line %d
+This is b/c
+
+===DONE===
diff --git a/ext/phar/tests/tar/open_for_write_existing_c.phpt b/ext/phar/tests/tar/open_for_write_existing_c.phpt
new file mode 100755
index 0000000000..0e5a181e65
--- /dev/null
+++ b/ext/phar/tests/tar/open_for_write_existing_c.phpt
@@ -0,0 +1,50 @@
+--TEST--
+Phar: fopen a .phar for writing (existing file) tar-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar';
+$alias = 'phar://' . $fname;
+
+$phar = new Phar($fname);
+$phar->setStub("<?php __HALT_COMPILER(); ?>");
+
+$files = array();
+
+$files['a.php'] = '<?php echo "This is a\n"; ?>';
+$files['b.php'] = '<?php echo "This is b\n"; ?>';
+$files['b/c.php'] = '<?php echo "This is b/c\n"; ?>';
+
+foreach ($files as $n => $file) {
+ $phar[$n] = $file;
+}
+
+$phar->stopBuffering();
+ini_set('phar.readonly', 1);
+
+$fp = fopen($alias . '/b/c.php', 'wb');
+fwrite($fp, 'extra');
+fclose($fp);
+
+include $alias . '/b/c.php';
+
+?>
+
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar'); ?>
+--EXPECTF--
+
+Warning: fopen(phar://%sopen_for_write_existing_c.phar.tar/b/c.php): failed to open stream: phar error: write operations disabled by INI setting in %sopen_for_write_existing_c.php on line %d
+
+Warning: fwrite(): supplied argument is not a valid stream resource in %sopen_for_write_existing_c.php on line %d
+
+Warning: fclose(): supplied argument is not a valid stream resource in %sopen_for_write_existing_c.php on line %d
+This is b/c
+
+===DONE===
diff --git a/ext/phar/tests/tar/open_for_write_newfile.phpt b/ext/phar/tests/tar/open_for_write_newfile.phpt
new file mode 100644
index 0000000000..31e9d4a7e9
--- /dev/null
+++ b/ext/phar/tests/tar/open_for_write_newfile.phpt
@@ -0,0 +1,44 @@
+--TEST--
+Phar: fopen a .phar for writing (new file) tar-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar';
+$alias = 'phar://' . $fname;
+
+$phar = new Phar($fname);
+$phar->setStub("<?php __HALT_COMPILER(); ?>");
+
+$files = array();
+
+$files['a.php'] = '<?php echo "This is a\n"; ?>';
+$files['b.php'] = '<?php echo "This is b\n"; ?>';
+$files['b/c.php'] = '<?php echo "This is b/c\n"; ?>';
+
+foreach ($files as $n => $file) {
+ $phar[$n] = $file;
+}
+
+$phar->stopBuffering();
+
+$fp = fopen($alias . '/b/new.php', 'wb');
+fwrite($fp, 'extra');
+fclose($fp);
+
+include $alias . '/b/c.php';
+include $alias . '/b/new.php';
+
+?>
+
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar'); ?>
+--EXPECT--
+This is b/c
+extra
+===DONE===
diff --git a/ext/phar/tests/tar/open_for_write_newfile_b.phpt b/ext/phar/tests/tar/open_for_write_newfile_b.phpt
new file mode 100755
index 0000000000..d3a21b4caf
--- /dev/null
+++ b/ext/phar/tests/tar/open_for_write_newfile_b.phpt
@@ -0,0 +1,61 @@
+--TEST--
+Phar: fopen a .phar for writing (new file) tar-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar';
+$alias = 'phar://' . $fname;
+
+$phar = new Phar($fname);
+$phar->setStub("<?php __HALT_COMPILER(); ?>");
+
+$files = array();
+
+$files['a.php'] = '<?php echo "This is a\n"; ?>';
+$files['b.php'] = '<?php echo "This is b\n"; ?>';
+$files['b/c.php'] = '<?php echo "This is b/c\n"; ?>';
+
+foreach ($files as $n => $file) {
+ $phar[$n] = $file;
+}
+
+$phar->stopBuffering();
+ini_set('phar.readonly', 1);
+
+function err_handler($errno, $errstr, $errfile, $errline) {
+ echo "Catchable fatal error: $errstr in $errfile on line $errline\n";
+}
+
+set_error_handler("err_handler", E_RECOVERABLE_ERROR);
+
+$fp = fopen($alias . '/b/new.php', 'wb');
+fwrite($fp, 'extra');
+fclose($fp);
+
+include $alias . '/b/c.php';
+include $alias . '/b/new.php';
+
+?>
+
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar'); ?>
+--EXPECTF--
+
+Warning: fopen(phar://%sopen_for_write_newfile_b.phar.tar/b/new.php): failed to open stream: phar error: write operations disabled by INI setting in %sopen_for_write_newfile_b.php on line %d
+
+Warning: fwrite(): supplied argument is not a valid stream resource in %sopen_for_write_newfile_b.php on line %d
+
+Warning: fclose(): supplied argument is not a valid stream resource in %sopen_for_write_newfile_b.php on line %d
+This is b/c
+
+Warning: include(phar://%sopen_for_write_newfile_b.phar.tar/b/new.php): failed to open stream: phar error: "b/new.php" is not a file in phar "%sopen_for_write_newfile_b.phar.tar" in %sopen_for_write_newfile_b.php on line %d
+
+Warning: include(): Failed opening 'phar://%sopen_for_write_newfile_b.phar.tar/b/new.php' for inclusion (include_path='%s') in %sopen_for_write_newfile_b.php on line %d
+
+===DONE===
diff --git a/ext/phar/tests/tar/open_for_write_newfile_c.phpt b/ext/phar/tests/tar/open_for_write_newfile_c.phpt
new file mode 100755
index 0000000000..231241c8ad
--- /dev/null
+++ b/ext/phar/tests/tar/open_for_write_newfile_c.phpt
@@ -0,0 +1,54 @@
+--TEST--
+Phar: fopen a .phar for writing (new file) tar-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar';
+$alias = 'phar://' . $fname;
+
+$phar = new Phar($fname);
+$phar->setStub("<?php __HALT_COMPILER(); ?>");
+
+$files = array();
+
+$files['a.php'] = '<?php echo "This is a\n"; ?>';
+$files['b.php'] = '<?php echo "This is b\n"; ?>';
+$files['b/c.php'] = '<?php echo "This is b/c\n"; ?>';
+
+foreach ($files as $n => $file) {
+ $phar[$n] = $file;
+}
+
+$phar->stopBuffering();
+ini_set('phar.readonly', 1);
+
+$fp = fopen($alias . '/b/new.php', 'wb');
+fwrite($fp, 'extra');
+fclose($fp);
+include $alias . '/b/c.php';
+include $alias . '/b/new.php';
+
+?>
+
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar'); ?>
+--EXPECTF--
+
+Warning: fopen(phar://%sopen_for_write_newfile_c.phar.tar/b/new.php): failed to open stream: phar error: write operations disabled by INI setting in %sopen_for_write_newfile_c.php on line %d
+
+Warning: fwrite(): supplied argument is not a valid stream resource in %sopen_for_write_newfile_c.php on line %d
+
+Warning: fclose(): supplied argument is not a valid stream resource in %sopen_for_write_newfile_c.php on line %d
+This is b/c
+
+Warning: include(phar://%sopen_for_write_newfile_c.phar.tar/b/new.php): failed to open stream: phar error: "b/new.php" is not a file in phar "%sopen_for_write_newfile_c.phar.tar" in %sopen_for_write_newfile_c.php on line %d
+
+Warning: include(): Failed opening 'phar://%sopen_for_write_newfile_c.phar.tar/b/new.php' for inclusion (include_path='%s') in %sopen_for_write_newfile_c.php on line %d
+
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/tar/phar_begin_setstub_commit.phpt b/ext/phar/tests/tar/phar_begin_setstub_commit.phpt
new file mode 100755
index 0000000000..c990ff9b98
--- /dev/null
+++ b/ext/phar/tests/tar/phar_begin_setstub_commit.phpt
@@ -0,0 +1,51 @@
+--TEST--
+Phar::startBuffering()/setStub()/stopBuffering() tar-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+$p = new Phar(dirname(__FILE__) . '/brandnewphar.phar.tar', 0, 'brandnewphar.phar');
+var_dump($p->isFileFormat(Phar::TAR));
+//var_dump($p->getStub());
+var_dump($p->isBuffering());
+$p->startBuffering();
+var_dump($p->isBuffering());
+$p['a.php'] = '<?php var_dump("Hello");';
+$p->setStub('<?php var_dump("First"); Phar::mapPhar("brandnewphar.phar"); __HALT_COMPILER(); ?>');
+include 'phar://brandnewphar.phar/a.php';
+var_dump($p->getStub());
+$p['b.php'] = '<?php var_dump("World");';
+$p->setStub('<?php var_dump("Second"); Phar::mapPhar("brandnewphar.phar"); __HALT_COMPILER();');
+include 'phar://brandnewphar.phar/b.php';
+var_dump($p->getStub());
+$p->stopBuffering();
+echo "===COMMIT===\n";
+var_dump($p->isBuffering());
+include 'phar://brandnewphar.phar/a.php';
+include 'phar://brandnewphar.phar/b.php';
+var_dump($p->getStub());
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/brandnewphar.phar.tar');
+?>
+--EXPECT--
+bool(true)
+bool(true)
+bool(false)
+string(5) "Hello"
+string(84) "<?php var_dump("First"); Phar::mapPhar("brandnewphar.phar"); __HALT_COMPILER(); ?>
+"
+string(5) "World"
+string(85) "<?php var_dump("Second"); Phar::mapPhar("brandnewphar.phar"); __HALT_COMPILER(); ?>
+"
+===COMMIT===
+bool(true)
+string(5) "Hello"
+string(5) "World"
+string(85) "<?php var_dump("Second"); Phar::mapPhar("brandnewphar.phar"); __HALT_COMPILER(); ?>
+"
+===DONE===
diff --git a/ext/phar/tests/tar/phar_buildfromiterator4.phpt b/ext/phar/tests/tar/phar_buildfromiterator4.phpt
new file mode 100644
index 0000000000..b7d6d56f64
--- /dev/null
+++ b/ext/phar/tests/tar/phar_buildfromiterator4.phpt
@@ -0,0 +1,66 @@
+--TEST--
+Phar::buildFromIterator() iterator, 1 file passed in tar-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+class myIterator implements Iterator
+{
+ var $a;
+ function __construct(array $a)
+ {
+ $this->a = $a;
+ }
+ function next() {
+ echo "next\n";
+ return next($this->a);
+ }
+ function current() {
+ echo "current\n";
+ return current($this->a);
+ }
+ function key() {
+ echo "key\n";
+ return key($this->a);
+ }
+ function valid() {
+ echo "valid\n";
+ return current($this->a);
+ }
+ function rewind() {
+ echo "rewind\n";
+ return reset($this->a);
+ }
+}
+try {
+ chdir(dirname(__FILE__));
+ $phar = new Phar(dirname(__FILE__) . '/buildfromiterator.phar.tar');
+ var_dump($phar->buildFromIterator(new myIterator(array('a' => basename(__FILE__, 'php') . 'phpt'))));
+ var_dump($phar->isFileFormat(Phar::TAR));
+} catch (Exception $e) {
+ var_dump(get_class($e));
+ echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/buildfromiterator.phar.tar');
+__HALT_COMPILER();
+?>
+--EXPECTF--
+rewind
+valid
+current
+key
+next
+valid
+array(1) {
+ ["a"]=>
+ string(%d) "%sphar_buildfromiterator4.phpt"
+}
+bool(true)
+===DONE===
diff --git a/ext/phar/tests/tar/phar_buildfromiterator5.phpt b/ext/phar/tests/tar/phar_buildfromiterator5.phpt
new file mode 100644
index 0000000000..600bd2ee5c
--- /dev/null
+++ b/ext/phar/tests/tar/phar_buildfromiterator5.phpt
@@ -0,0 +1,59 @@
+--TEST--
+Phar::buildFromIterator() iterator, iterator returns non-string tar-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+class myIterator implements Iterator
+{
+ var $a;
+ function __construct(array $a)
+ {
+ $this->a = $a;
+ }
+ function next() {
+ echo "next\n";
+ return next($this->a);
+ }
+ function current() {
+ echo "current\n";
+ return current($this->a);
+ }
+ function key() {
+ echo "key\n";
+ return key($this->a);
+ }
+ function valid() {
+ echo "valid\n";
+ return current($this->a);
+ }
+ function rewind() {
+ echo "rewind\n";
+ return reset($this->a);
+ }
+}
+try {
+ chdir(dirname(__FILE__));
+ $phar = new Phar(dirname(__FILE__) . '/buildfromiterator.phar.tar');
+ var_dump($phar->buildFromIterator(new myIterator(array('a' => new stdClass))));
+} catch (Exception $e) {
+ var_dump(get_class($e));
+ echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/buildfromiterator.phar.tar');
+__HALT_COMPILER();
+?>
+--EXPECTF--
+rewind
+valid
+current
+string(24) "UnexpectedValueException"
+Iterator myIterator returned an invalid value (must return a string)
+===DONE===
diff --git a/ext/phar/tests/tar/phar_buildfromiterator6.phpt b/ext/phar/tests/tar/phar_buildfromiterator6.phpt
new file mode 100644
index 0000000000..e891a5d065
--- /dev/null
+++ b/ext/phar/tests/tar/phar_buildfromiterator6.phpt
@@ -0,0 +1,60 @@
+--TEST--
+Phar::buildFromIterator() iterator, key is int tar-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+class myIterator implements Iterator
+{
+ var $a;
+ function __construct(array $a)
+ {
+ $this->a = $a;
+ }
+ function next() {
+ echo "next\n";
+ return next($this->a);
+ }
+ function current() {
+ echo "current\n";
+ return current($this->a);
+ }
+ function key() {
+ echo "key\n";
+ return key($this->a);
+ }
+ function valid() {
+ echo "valid\n";
+ return current($this->a);
+ }
+ function rewind() {
+ echo "rewind\n";
+ return reset($this->a);
+ }
+}
+try {
+ chdir(dirname(__FILE__));
+ $phar = new Phar(dirname(__FILE__) . '/buildfromiterator.phar.tar');
+ var_dump($phar->buildFromIterator(new myIterator(array(basename(__FILE__, 'php') . 'phpt'))));
+} catch (Exception $e) {
+ var_dump(get_class($e));
+ echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/buildfromiterator.phar.tar');
+__HALT_COMPILER();
+?>
+--EXPECTF--
+rewind
+valid
+current
+key
+string(24) "UnexpectedValueException"
+Iterator myIterator returned an invalid key (must return a string)
+===DONE===
diff --git a/ext/phar/tests/tar/phar_buildfromiterator7.phpt b/ext/phar/tests/tar/phar_buildfromiterator7.phpt
new file mode 100644
index 0000000000..d64c032d71
--- /dev/null
+++ b/ext/phar/tests/tar/phar_buildfromiterator7.phpt
@@ -0,0 +1,60 @@
+--TEST--
+Phar::buildFromIterator() iterator, file can't be opened tar-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+class myIterator implements Iterator
+{
+ var $a;
+ function __construct(array $a)
+ {
+ $this->a = $a;
+ }
+ function next() {
+ echo "next\n";
+ return next($this->a);
+ }
+ function current() {
+ echo "current\n";
+ return current($this->a);
+ }
+ function key() {
+ echo "key\n";
+ return key($this->a);
+ }
+ function valid() {
+ echo "valid\n";
+ return current($this->a);
+ }
+ function rewind() {
+ echo "rewind\n";
+ return reset($this->a);
+ }
+}
+try {
+ chdir(dirname(__FILE__));
+ $phar = new Phar(dirname(__FILE__) . '/buildfromiterator.phar.tar');
+ var_dump($phar->buildFromIterator(new myIterator(array('a' => basename(__FILE__, 'php') . '/oopsie/there.phpt'))));
+} catch (Exception $e) {
+ var_dump(get_class($e));
+ echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/buildfromiterator.phar.tar');
+__HALT_COMPILER();
+?>
+--EXPECT--
+rewind
+valid
+current
+key
+string(24) "UnexpectedValueException"
+Iterator myIterator returned a file that could not be opened "phar_buildfromiterator7./oopsie/there.phpt"
+===DONE===
diff --git a/ext/phar/tests/tar/phar_buildfromiterator8.phpt b/ext/phar/tests/tar/phar_buildfromiterator8.phpt
new file mode 100644
index 0000000000..f42640f692
--- /dev/null
+++ b/ext/phar/tests/tar/phar_buildfromiterator8.phpt
@@ -0,0 +1,73 @@
+--TEST--
+Phar::buildFromIterator() iterator, SplFileInfo as current tar-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+try {
+ chdir(dirname(__FILE__));
+ $phar = new Phar(dirname(__FILE__) . '/buildfromiterator.phar.tar');
+ $a = $phar->buildFromIterator(new RegexIterator(new DirectoryIterator('.'), '/^frontcontroller\d{0,2}\.phar\.phpt\\z|^\.\\z|^\.\.\\z/'), dirname(__FILE__) . DIRECTORY_SEPARATOR);
+ asort($a);
+ var_dump($a);
+ var_dump($phar->isFileFormat(Phar::TAR));
+} catch (Exception $e) {
+ var_dump(get_class($e));
+ echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/buildfromiterator.phar.tar');
+__HALT_COMPILER();
+?>
+--EXPECTF--
+array(21) {
+ ["frontcontroller1.phar.phpt"]=>
+ string(%d) "%sfrontcontroller1.phar.phpt"
+ ["frontcontroller10.phar.phpt"]=>
+ string(%d) "%sfrontcontroller10.phar.phpt"
+ ["frontcontroller11.phar.phpt"]=>
+ string(%d) "%sfrontcontroller11.phar.phpt"
+ ["frontcontroller12.phar.phpt"]=>
+ string(%d) "%sfrontcontroller12.phar.phpt"
+ ["frontcontroller13.phar.phpt"]=>
+ string(%d) "%sfrontcontroller13.phar.phpt"
+ ["frontcontroller14.phar.phpt"]=>
+ string(%d) "%sfrontcontroller14.phar.phpt"
+ ["frontcontroller15.phar.phpt"]=>
+ string(%d) "%sfrontcontroller15.phar.phpt"
+ ["frontcontroller16.phar.phpt"]=>
+ string(%d) "%sfrontcontroller16.phar.phpt"
+ ["frontcontroller17.phar.phpt"]=>
+ string(%d) "%sfrontcontroller17.phar.phpt"
+ ["frontcontroller18.phar.phpt"]=>
+ string(%d) "%sfrontcontroller18.phar.phpt"
+ ["frontcontroller19.phar.phpt"]=>
+ string(%d) "%sfrontcontroller19.phar.phpt"
+ ["frontcontroller2.phar.phpt"]=>
+ string(%d) "%sfrontcontroller2.phar.phpt"
+ ["frontcontroller20.phar.phpt"]=>
+ string(%d) "%sfrontcontroller20.phar.phpt"
+ ["frontcontroller21.phar.phpt"]=>
+ string(%d) "%sfrontcontroller21.phar.phpt"
+ ["frontcontroller3.phar.phpt"]=>
+ string(%d) "%sfrontcontroller3.phar.phpt"
+ ["frontcontroller4.phar.phpt"]=>
+ string(%d) "%sfrontcontroller4.phar.phpt"
+ ["frontcontroller5.phar.phpt"]=>
+ string(%d) "%sfrontcontroller5.phar.phpt"
+ ["frontcontroller6.phar.phpt"]=>
+ string(%d) "%sfrontcontroller6.phar.phpt"
+ ["frontcontroller7.phar.phpt"]=>
+ string(%d) "%sfrontcontroller7.phar.phpt"
+ ["frontcontroller8.phar.phpt"]=>
+ string(%d) "%sfrontcontroller8.phar.phpt"
+ ["frontcontroller9.phar.phpt"]=>
+ string(%d) "%sfrontcontroller9.phar.phpt"
+}
+bool(true)
+===DONE===
diff --git a/ext/phar/tests/tar/phar_buildfromiterator9.phpt b/ext/phar/tests/tar/phar_buildfromiterator9.phpt
new file mode 100644
index 0000000000..f9deef4d9f
--- /dev/null
+++ b/ext/phar/tests/tar/phar_buildfromiterator9.phpt
@@ -0,0 +1,65 @@
+--TEST--
+Phar::buildFromIterator() iterator, 1 file resource passed in tar-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+class myIterator implements Iterator
+{
+ var $a;
+ function __construct(array $a)
+ {
+ $this->a = $a;
+ }
+ function next() {
+ echo "next\n";
+ return next($this->a);
+ }
+ function current() {
+ echo "current\n";
+ return current($this->a);
+ }
+ function key() {
+ echo "key\n";
+ return key($this->a);
+ }
+ function valid() {
+ echo "valid\n";
+ return current($this->a);
+ }
+ function rewind() {
+ echo "rewind\n";
+ return reset($this->a);
+ }
+}
+try {
+ chdir(dirname(__FILE__));
+ $phar = new Phar(dirname(__FILE__) . '/buildfromiterator.phar.tar');
+ var_dump($phar->buildFromIterator(new myIterator(array('a' => $a = fopen(basename(__FILE__, 'php') . 'phpt', 'r')))));
+ fclose($a);
+} catch (Exception $e) {
+ var_dump(get_class($e));
+ echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/buildfromiterator.phar.tar');
+__HALT_COMPILER();
+?>
+--EXPECTF--
+rewind
+valid
+current
+key
+next
+valid
+array(1) {
+ ["a"]=>
+ string(%d) "[stream]"
+}
+===DONE===
diff --git a/ext/phar/tests/tar/phar_commitwrite.phpt b/ext/phar/tests/tar/phar_commitwrite.phpt
new file mode 100644
index 0000000000..b926b9a081
--- /dev/null
+++ b/ext/phar/tests/tar/phar_commitwrite.phpt
@@ -0,0 +1,44 @@
+--TEST--
+Phar::setStub()/stopBuffering() tar-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+$p = new Phar(dirname(__FILE__) . '/brandnewphar.phar.tar', 0, 'brandnewphar.phar');
+$p['file1.txt'] = 'hi';
+$p->stopBuffering();
+var_dump($p->getStub());
+$p->setStub("<?php
+function __autoload(\$class)
+{
+ include 'phar://' . str_replace('_', '/', \$class);
+}
+Phar::mapPhar('brandnewphar.phar');
+include 'phar://brandnewphar.phar/startup.php';
+__HALT_COMPILER();
+?>");
+var_dump($p->getStub());
+var_dump($p->isFileFormat(Phar::TAR));
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/brandnewphar.phar.tar');
+?>
+--EXPECT--
+string(60) "<?php // tar-based phar archive stub file
+__HALT_COMPILER();"
+string(200) "<?php
+function __autoload($class)
+{
+ include 'phar://' . str_replace('_', '/', $class);
+}
+Phar::mapPhar('brandnewphar.phar');
+include 'phar://brandnewphar.phar/startup.php';
+__HALT_COMPILER(); ?>
+"
+bool(true)
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/tar/phar_convert_phar.phpt b/ext/phar/tests/tar/phar_convert_phar.phpt
new file mode 100644
index 0000000000..6a7d78ea8b
--- /dev/null
+++ b/ext/phar/tests/tar/phar_convert_phar.phpt
@@ -0,0 +1,58 @@
+--TEST--
+Phar::convertToPhar() from tar
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar';
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '2.phar';
+$fname3 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.3.phar';
+
+$phar = new Phar($fname);
+$phar['a.txt'] = 'some text';
+$phar->stopBuffering();
+var_dump($phar->isFileFormat(Phar::TAR));
+var_dump(strlen($phar->getStub()));
+
+$phar = $phar->convertToExecutable(Phar::TAR);
+var_dump($phar->isFileFormat(Phar::TAR));
+var_dump($phar->getStub());
+
+$phar['a'] = 'hi there';
+
+$phar = $phar->convertToExecutable(Phar::PHAR, Phar::NONE, '.3.phar');
+var_dump($phar->isFileFormat(Phar::PHAR));
+var_dump(strlen($phar->getStub()));
+
+copy($fname3, $fname2);
+
+$phar = new Phar($fname2);
+var_dump($phar->isFileFormat(Phar::PHAR));
+var_dump(strlen($phar->getStub()));
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.tar');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.2.phar');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.3.phar');
+__HALT_COMPILER();
+?>
+--EXPECT--
+bool(false)
+int(6651)
+bool(true)
+string(60) "<?php // tar-based phar archive stub file
+__HALT_COMPILER();"
+bool(true)
+int(6651)
+bool(true)
+int(6651)
+===DONE===
diff --git a/ext/phar/tests/tar/phar_convert_phar2.phpt b/ext/phar/tests/tar/phar_convert_phar2.phpt
new file mode 100644
index 0000000000..496948b14c
--- /dev/null
+++ b/ext/phar/tests/tar/phar_convert_phar2.phpt
@@ -0,0 +1,62 @@
+--TEST--
+Phar::convertToPhar() gzipped
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("zlib")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar';
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '2.phar';
+
+$phar = new Phar($fname);
+$phar['a.txt'] = 'some text';
+$phar->stopBuffering();
+var_dump($phar->isFileFormat(Phar::TAR));
+var_dump(strlen($phar->getStub()));
+
+$phar = $phar->convertToExecutable(Phar::TAR);
+var_dump($phar->isFileFormat(Phar::TAR));
+var_dump($phar->getStub());
+
+$phar['a'] = 'hi there';
+
+$phar = $phar->convertToExecutable(Phar::PHAR, Phar::GZ);
+var_dump($phar->isFileFormat(Phar::PHAR));
+var_dump($phar->isCompressed());
+var_dump(strlen($phar->getStub()));
+
+copy($fname . '.gz', $fname2);
+
+$phar = new Phar($fname2);
+var_dump($phar->isFileFormat(Phar::PHAR));
+var_dump($phar->isCompressed() == Phar::GZ);
+var_dump(strlen($phar->getStub()));
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.gz');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar.gz');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '2.phar');
+__HALT_COMPILER();
+?>
+--EXPECT--
+bool(false)
+int(6651)
+bool(true)
+string(60) "<?php // tar-based phar archive stub file
+__HALT_COMPILER();"
+bool(true)
+int(4096)
+int(6651)
+bool(true)
+bool(true)
+int(6651)
+===DONE===
diff --git a/ext/phar/tests/tar/phar_convert_phar3.phpt b/ext/phar/tests/tar/phar_convert_phar3.phpt
new file mode 100644
index 0000000000..f4768194d1
--- /dev/null
+++ b/ext/phar/tests/tar/phar_convert_phar3.phpt
@@ -0,0 +1,62 @@
+--TEST--
+Phar::convertToPhar() bzipped
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("bz2")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar';
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '2.phar';
+
+$phar = new Phar($fname);
+$phar['a.txt'] = 'some text';
+$phar->stopBuffering();
+var_dump($phar->isFileFormat(Phar::TAR));
+var_dump(strlen($phar->getStub()));
+
+$phar = $phar->convertToExecutable(Phar::TAR);
+var_dump($phar->isFileFormat(Phar::TAR));
+var_dump($phar->getStub());
+
+$phar['a'] = 'hi there';
+
+$phar = $phar->convertToExecutable(Phar::PHAR, Phar::BZ2);
+var_dump($phar->isFileFormat(Phar::PHAR));
+var_dump($phar->isCompressed());
+var_dump(strlen($phar->getStub()));
+
+copy($fname . '.bz2', $fname2);
+
+$phar = new Phar($fname2);
+var_dump($phar->isFileFormat(Phar::PHAR));
+var_dump($phar->isCompressed() == Phar::BZ2);
+var_dump(strlen($phar->getStub()));
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.bz2');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '2.phar');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar.bz2');
+__HALT_COMPILER();
+?>
+--EXPECT--
+bool(false)
+int(6651)
+bool(true)
+string(60) "<?php // tar-based phar archive stub file
+__HALT_COMPILER();"
+bool(true)
+int(8192)
+int(6651)
+bool(true)
+bool(true)
+int(6651)
+===DONE===
diff --git a/ext/phar/tests/tar/phar_copy.phpt b/ext/phar/tests/tar/phar_copy.phpt
new file mode 100644
index 0000000000..ed5cdac8bc
--- /dev/null
+++ b/ext/phar/tests/tar/phar_copy.phpt
@@ -0,0 +1,56 @@
+--TEST--
+Phar: copy() tar-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+<?php if (!extension_loaded("zlib")) die("skip zlib not available"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=1
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar.php';
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '2.phar.php';
+
+$pname = 'phar://'.$fname;
+$iname = '/file.txt';
+$ename = '/error/..';
+
+$p = new Phar($fname);
+
+try
+{
+ $p['a'] = 'hi';
+ $p->startBuffering();
+ $p->copy('a', 'b');
+ echo file_get_contents($p['b']->getPathName());
+ $p->copy('b', 'c');
+ $p->stopBuffering();
+ echo file_get_contents($p['c']->getPathName());
+ copy($fname, $fname2);
+ var_dump($p->isFileFormat(Phar::TAR));
+ $p->copy('a', $ename);
+}
+catch(Exception $e)
+{
+ echo $e->getMessage() . "\n";
+}
+ini_set('phar.readonly',1);
+$p2 = new Phar($fname2);
+var_dump($p2->isFileFormat(Phar::TAR));
+echo "\n";
+echo 'a: ' , file_get_contents($p2['a']->getPathName());
+echo 'b: ' ,file_get_contents($p2['b']->getPathName());
+echo 'c: ' ,file_get_contents($p2['c']->getPathName());
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar.php'); ?>
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '2.phar.php'); ?>
+--EXPECTF--
+hihibool(true)
+file "/error/.." contains invalid characters upper directory reference, cannot be copied from "a" in phar %s
+bool(true)
+
+a: hib: hic: hi===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/tar/phar_magic.phpt b/ext/phar/tests/tar/phar_magic.phpt
new file mode 100644
index 0000000000..1bb336f96c
--- /dev/null
+++ b/ext/phar/tests/tar/phar_magic.phpt
@@ -0,0 +1,33 @@
+--TEST--
+Phar: include/fopen magic tar-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar.php';
+$p = new Phar($fname);
+var_dump($p->isFileFormat(Phar::TAR));
+$p['a'] = '<?php include "b/c.php";' . "\n";
+$p['b/c.php'] = '<?php echo "in b\n";$a = fopen("a", "r", true);echo stream_get_contents($a);fclose($a);include dirname(__FILE__) . "/../d";';
+$p['d'] = "in d\n";
+$p->setStub('<?php
+set_include_path("phar://" . __FILE__);
+include "phar://" . __FILE__ . "/a";
+__HALT_COMPILER();');
+include $fname;
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar.php');
+__HALT_COMPILER();
+?>
+--EXPECTF--
+bool(true)
+in b
+<?php include "b/c.php";
+in d
+===DONE===
diff --git a/ext/phar/tests/tar/phar_setalias.phpt b/ext/phar/tests/tar/phar_setalias.phpt
new file mode 100644
index 0000000000..a1bc51154c
--- /dev/null
+++ b/ext/phar/tests/tar/phar_setalias.phpt
@@ -0,0 +1,51 @@
+--TEST--
+Phar::setAlias() tar-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar';
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '2.phar.tar';
+
+$phar = new Phar($fname);
+$phar->setStub('<?php echo "first stub\n"; __HALT_COMPILER(); ?>');
+$phar->setAlias('hio');
+
+$files = array();
+
+$files['a'] = 'a';
+$files['b'] = 'b';
+$files['c'] = 'c';
+
+foreach ($files as $n => $file) {
+ $phar[$n] = $file;
+}
+
+$phar->stopBuffering();
+
+echo $phar->getAlias() . "\n";
+$phar->setAlias('test');
+echo $phar->getAlias() . "\n";
+
+copy($fname, $fname2);
+$phar->setAlias('unused');
+$a = new Phar($fname2);
+echo $a->getAlias() . "\n";
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phartmp.tar');
+__HALT_COMPILER();
+?>
+--EXPECT--
+hio
+test
+test
+===DONE===
diff --git a/ext/phar/tests/tar/phar_setalias2.phpt b/ext/phar/tests/tar/phar_setalias2.phpt
new file mode 100644
index 0000000000..a44cc397c2
--- /dev/null
+++ b/ext/phar/tests/tar/phar_setalias2.phpt
@@ -0,0 +1,53 @@
+--TEST--
+Phar::setAlias() error tar-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar';
+
+$phar = new Phar($fname);
+$phar->setStub('<?php echo "first stub\n"; __HALT_COMPILER(); ?>');
+$phar->setAlias('hio');
+
+$files = array();
+
+$files['a'] = 'a';
+$files['b'] = 'b';
+$files['c'] = 'c';
+
+foreach ($files as $n => $file) {
+ $phar[$n] = $file;
+}
+
+$phar->stopBuffering();
+
+echo $phar->getAlias() . "\n";
+$phar->setAlias('test');
+echo $phar->getAlias() . "\n";
+$b = $phar;
+$phar = new Phar(dirname(__FILE__) . '/notphar.phar');
+
+try {
+ $phar->setAlias('test');
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phartmp.tar');
+__HALT_COMPILER();
+?>
+--EXPECTF--
+hio
+test
+alias "test" is already used for archive "%sphar_setalias2.phar.tar" and cannot be used for other archives
+===DONE===
diff --git a/ext/phar/tests/tar/phar_setdefaultstub.phpt b/ext/phar/tests/tar/phar_setdefaultstub.phpt
new file mode 100644
index 0000000000..c1e6642a17
--- /dev/null
+++ b/ext/phar/tests/tar/phar_setdefaultstub.phpt
@@ -0,0 +1,80 @@
+--TEST--
+Phar: Phar::setDefaultStub() with and without arg, tar-based phar
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar';
+
+$phar = new Phar($fname);
+$phar['a.php'] = '<php echo "this is a\n"; ?>';
+$phar['b.php'] = '<php echo "this is b\n"; ?>';
+$phar->setStub('<?php echo "Hello World\n"; __HALT_COMPILER(); ?>');
+
+var_dump($phar->getStub());
+
+echo "============================================================================\n";
+echo "============================================================================\n";
+
+try {
+ $phar->setDefaultStub();
+ $phar->stopBuffering();
+} catch(Exception $e) {
+ echo $e->getMessage(). "\n";
+}
+
+var_dump($phar->getStub());
+
+echo "============================================================================\n";
+echo "============================================================================\n";
+
+try {
+ $phar->setDefaultStub('my/custom/thingy.php');
+ $phar->stopBuffering();
+} catch(Exception $e) {
+ echo $e->getMessage(). "\n";
+}
+
+var_dump($phar->getStub());
+
+echo "============================================================================\n";
+echo "============================================================================\n";
+
+try {
+ $phar->setDefaultStub('my/custom/thingy.php', 'the/web.php');
+ $phar->stopBuffering();
+} catch(Exception $e) {
+ echo $e->getMessage(). "\n";
+}
+
+var_dump($phar->getStub());
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar');
+?>
+--EXPECTF--
+string(51) "<?php echo "Hello World\n"; __HALT_COMPILER(); ?>
+"
+============================================================================
+============================================================================
+string(60) "<?php // tar-based phar archive stub file
+__HALT_COMPILER();"
+============================================================================
+============================================================================
+
+Warning: Phar::setDefaultStub(): method accepts no arguments for a tar- or zip-based phar stub, 1 given in %sphar_setdefaultstub.php on line %d
+string(60) "<?php // tar-based phar archive stub file
+__HALT_COMPILER();"
+============================================================================
+============================================================================
+
+Warning: Phar::setDefaultStub(): method accepts no arguments for a tar- or zip-based phar stub, 2 given in %sphar_setdefaultstub.php on line %d
+string(60) "<?php // tar-based phar archive stub file
+__HALT_COMPILER();"
+===DONE===
diff --git a/ext/phar/tests/tar/phar_stub.phpt b/ext/phar/tests/tar/phar_stub.phpt
new file mode 100644
index 0000000000..e0d728f6f8
--- /dev/null
+++ b/ext/phar/tests/tar/phar_stub.phpt
@@ -0,0 +1,75 @@
+--TEST--
+Phar::setStub() (tar-based)
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.2.phar.tar.php';
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar.php';
+$pname = 'phar://' . $fname;
+$pname2 = 'phar://' . $fname2;
+
+$p = new Phar($pname2);
+$p->setStub('<?php echo "first stub\n"; __HALT_COMPILER(); ?>');
+$p['a'] = 'a';
+$p['b'] = 'b';
+$p['c'] = 'c';
+copy($fname2, $fname);
+
+$phar = new Phar($fname);
+echo $phar->getStub();
+
+$file = '<?php echo "second stub\n"; __HALT_COMPILER(); ?>';
+
+//// 2
+$phar->setStub($file);
+echo $phar->getStub();
+
+$fname3 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phartmp.php';
+$file = '<?php echo "third stub\n"; __HALT_COMPILER(); ?>';
+$fp = fopen($fname3, 'wb');
+fwrite($fp, $file);
+fclose($fp);
+$fp = fopen($fname3, 'rb');
+
+//// 3
+$phar->setStub($fp);
+fclose($fp);
+
+echo $phar->getStub();
+
+$fp = fopen($fname3, 'ab');
+fwrite($fp, 'booya');
+fclose($fp);
+echo file_get_contents($fname3) . "\n";
+
+$fp = fopen($fname3, 'rb');
+
+//// 4
+$phar->setStub($fp, strlen($file));
+fclose($fp);
+echo $phar->getStub();
+
+$phar['testing'] = 'hi';
+
+echo $phar->getStub();
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar.php');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.2.phar.tar.php');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phartmp.php');
+__HALT_COMPILER();
+?>
+--EXPECT--
+<?php echo "first stub\n"; __HALT_COMPILER(); ?>
+<?php echo "second stub\n"; __HALT_COMPILER(); ?>
+<?php echo "third stub\n"; __HALT_COMPILER(); ?>
+<?php echo "third stub\n"; __HALT_COMPILER(); ?>booya
+<?php echo "third stub\n"; __HALT_COMPILER(); ?>
+<?php echo "third stub\n"; __HALT_COMPILER(); ?>
+===DONE===
diff --git a/ext/phar/tests/tar/phar_stub_error.phpt b/ext/phar/tests/tar/phar_stub_error.phpt
new file mode 100755
index 0000000000..5d35b932fe
--- /dev/null
+++ b/ext/phar/tests/tar/phar_stub_error.phpt
@@ -0,0 +1,57 @@
+--TEST--
+Phar::setStub()/getStub() tar-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar';
+
+$phar = new Phar($fname);
+$phar->setStub($stub = '<?php echo "first stub\n"; __HALT_COMPILER(); ?>' ."\r\n");
+$phar->setAlias('hio');
+$phar['a'] = 'a';
+$phar->stopBuffering();
+
+var_dump($stub);
+var_dump($phar->getStub());
+var_dump($phar->getStub() == $stub);
+
+$newstub = '<?php echo "second stub\n"; _x_HALT_COMPILER(); ?>';
+
+try {
+ $phar->setStub($newstub);
+} catch(exception $e) {
+ echo 'Exception: ' . $e->getMessage() . "\n";
+}
+
+var_dump($phar->getStub());
+var_dump($phar->getStub() == $stub);
+$phar->stopBuffering();
+var_dump($phar->getStub());
+var_dump($phar->getStub() == $stub);
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar');
+__HALT_COMPILER();
+?>
+--EXPECTF--
+string(50) "<?php echo "first stub\n"; __HALT_COMPILER(); ?>
+"
+string(50) "<?php echo "first stub\n"; __HALT_COMPILER(); ?>
+"
+bool(true)
+Exception: illegal stub for tar-based phar "%sphar_stub_error.phar.tar"
+string(50) "<?php echo "first stub\n"; __HALT_COMPILER(); ?>
+"
+bool(true)
+string(50) "<?php echo "first stub\n"; __HALT_COMPILER(); ?>
+"
+bool(true)
+===DONE===
diff --git a/ext/phar/tests/tar/refcount1.phpt b/ext/phar/tests/tar/refcount1.phpt
new file mode 100644
index 0000000000..c6808afb63
--- /dev/null
+++ b/ext/phar/tests/tar/refcount1.phpt
@@ -0,0 +1,74 @@
+--TEST--
+Phar: test that refcounting avoids problems with deleting a file tar-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+<?php if (version_compare(PHP_VERSION, "5.3", "<")) die("skip requires 5.3 or later"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+include dirname(__FILE__) . '/files/tarmaker.php.inc';
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar';
+$alias = 'phar://' . $fname;
+
+$tar = new tarmaker($fname, 'none');
+$tar->init();
+$tar->addFile('.phar/stub.php', "<?php __HALT_COMPILER(); ?>");
+
+$files = array();
+
+$files['a.php'] = '<?php echo "This is a\n"; ?>';
+$files['b.php'] = '<?php echo "This is b\n"; ?>';
+$files['b/c.php'] = '<?php echo "This is b/c\n"; ?>';
+$files['.phar/alias.txt'] = 'hio';
+
+foreach ($files as $n => $file) {
+ $tar->addFile($n, $file);
+}
+
+$tar->close();
+
+$fp = fopen($alias . '/b/c.php', 'wb');
+fwrite($fp, "extra");
+fclose($fp);
+echo "===CLOSE===\n";
+$phar = new Phar($fname);
+$b = fopen($alias . '/b/c.php', 'rb');
+$a = $phar['b/c.php'];
+var_dump($a);
+var_dump(fread($b, 20));
+rewind($b);
+echo "===UNLINK===\n";
+unlink($alias . '/b/c.php');
+var_dump($a);
+var_dump(fread($b, 20));
+include $alias . '/b/c.php';
+
+?>
+
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar'); ?>
+--EXPECTF--
+===CLOSE===
+object(PharFileInfo)#%d (2) {
+ ["pathName":"SplFileInfo":private]=>
+ string(%d) "phar://%srefcount1.phar.tar/b"
+ ["fileName":"SplFileInfo":private]=>
+ string(%d) "phar://%srefcount1.phar.tar/b/c.php"
+}
+string(5) "extra"
+===UNLINK===
+
+Warning: unlink(): phar error: "b/c.php" in phar "%srefcount1.phar.tar", has open file pointers, cannot unlink in %srefcount1.php on line %d
+object(PharFileInfo)#%d (2) {
+ ["pathName":"SplFileInfo":private]=>
+ string(%d) "phar://%srefcount1.phar.tar/b"
+ ["fileName":"SplFileInfo":private]=>
+ string(%s) "phar://%srefcount1.phar.tar/b/c.php"
+}
+string(5) "extra"
+extra
+===DONE===
diff --git a/ext/phar/tests/tar/refcount1_5_2.phpt b/ext/phar/tests/tar/refcount1_5_2.phpt
new file mode 100755
index 0000000000..18587d91ad
--- /dev/null
+++ b/ext/phar/tests/tar/refcount1_5_2.phpt
@@ -0,0 +1,64 @@
+--TEST--
+Phar: test that refcounting avoids problems with deleting a file tar-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+<?php if (version_compare(PHP_VERSION, "5.3", ">")) die("skip requires 5.2 or earlier"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar';
+$alias = 'phar://' . $fname;
+
+$phar = new Phar($fname);
+$phar->setStub("<?php __HALT_COMPILER(); ?>");
+$phar->setAlias('hio');
+
+$files = array();
+
+$files['a.php'] = '<?php echo "This is a\n"; ?>';
+$files['b.php'] = '<?php echo "This is b\n"; ?>';
+$files['b/c.php'] = '<?php echo "This is b/c\n"; ?>';
+
+foreach ($files as $n => $file) {
+ $phar[$n] = $file;
+}
+$phar->stopBuffering();
+
+$fp = fopen($alias . '/b/c.php', 'wb');
+fwrite($fp, "extra");
+fclose($fp);
+
+echo "===CLOSE===\n";
+
+$b = fopen($alias . '/b/c.php', 'rb');
+$a = $phar['b/c.php'];
+var_dump($a);
+var_dump(fread($b, 20));
+rewind($b);
+echo "===UNLINK===\n";
+unlink($alias . '/b/c.php');
+var_dump($a);
+var_dump(fread($b, 20));
+include $alias . '/b/c.php';
+?>
+
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar'); ?>
+--EXPECTF--
+===CLOSE===
+object(PharFileInfo)#%d (0) {
+}
+string(5) "extra"
+===UNLINK===
+
+Warning: unlink(): phar error: "b/c.php" in phar "%sefcount1_5_2.phar.tar", has open file pointers, cannot unlink in %sefcount1_5_2.php on line %d
+object(PharFileInfo)#%d (0) {
+}
+string(5) "extra"
+extra
+===DONE===
diff --git a/ext/phar/tests/tar/rename.phpt b/ext/phar/tests/tar/rename.phpt
new file mode 100644
index 0000000000..96588a6596
--- /dev/null
+++ b/ext/phar/tests/tar/rename.phpt
@@ -0,0 +1,42 @@
+--TEST--
+Phar: rename test tar-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+include dirname(__FILE__) . '/files/tarmaker.php.inc';
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar';
+$alias = 'phar://' . $fname;
+
+$tar = new tarmaker($fname, 'none');
+$tar->init();
+$tar->addFile('.phar/stub.php', "<?php
+Phar::mapPhar('hio');
+__HALT_COMPILER(); ?>");
+
+$files = array();
+$files['a'] = 'a';
+
+foreach ($files as $n => $file) {
+ $tar->addFile($n, $file);
+}
+
+$tar->close();
+
+include $fname;
+
+echo file_get_contents($alias . '/a') . "\n";
+rename($alias . '/a', $alias . '/b');
+echo file_get_contents($alias . '/b') . "\n";
+echo file_get_contents($alias . '/a') . "\n";
+?>
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar'); ?>
+--EXPECTF--
+a
+a
+
+Warning: file_get_contents(phar://%srename.phar.tar/a): failed to open stream: phar error: "a" is not a file in phar "%srename.phar.tar" in %srename.php on line %d
diff --git a/ext/phar/tests/tar/tar_001.phpt b/ext/phar/tests/tar/tar_001.phpt
new file mode 100644
index 0000000000..500058b70d
--- /dev/null
+++ b/ext/phar/tests/tar/tar_001.phpt
@@ -0,0 +1,31 @@
+--TEST--
+Phar: tar-based phar corrupted
+--SKIPIF--
+<?php if (!extension_loaded('phar')) die('skip'); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+--FILE--
+<?php
+include dirname(__FILE__) . '/files/make_invalid_tar.php.inc';
+
+$tar = new corrupter(dirname(__FILE__) . '/tar_001.phar.tar', 'none');
+$tar->init();
+$tar->addFile('tar_001.phpt', __FILE__);
+$tar->close();
+
+$tar = fopen('phar://' . dirname(__FILE__) . '/tar_001.phar.tar/tar_001.phpt', 'rb');
+try {
+ $phar = new Phar(dirname(__FILE__) . '/tar_001.phar.tar');
+ echo "should not execute\n";
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+@unlink(dirname(__FILE__) . '/tar_001.phar.tar');
+?>
+--EXPECTF--
+Warning: fopen(phar://%star_001.phar.tar/tar_001.phpt): failed to open stream: phar error: "%star_001.phar.tar" is a corrupted tar file (truncated) in %star_001.php on line 9
+phar error: "%star_001.phar.tar" is a corrupted tar file (truncated)
+===DONE===
diff --git a/ext/phar/tests/tar/tar_002.phpt b/ext/phar/tests/tar/tar_002.phpt
new file mode 100644
index 0000000000..75fc220b40
--- /dev/null
+++ b/ext/phar/tests/tar/tar_002.phpt
@@ -0,0 +1,34 @@
+--TEST--
+Phar: tar-based phar corrupted 2
+--SKIPIF--
+<?php if (!extension_loaded('phar')) die('skip'); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+include dirname(__FILE__) . '/files/make_invalid_tar.php.inc';
+
+$tar = new corrupter(dirname(__FILE__) . '/tar_002.phar.tar', 'none');
+$tar->init();
+$tar->addFile('tar_002.phpt', __FILE__);
+$tar->close();
+
+$tar = fopen('phar://' . dirname(__FILE__) . '/tar_002.phar.tar/tar_002.phpt', 'rb');
+
+try {
+ $phar = new Phar(dirname(__FILE__) . '/tar_002.phar.tar');
+ echo "should not execute\n";
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+@unlink(dirname(__FILE__) . '/tar_002.phar.tar');
+?>
+--EXPECTF--
+Warning: fopen(phar://%star_002.phar.tar/tar_002.phpt): failed to open stream: phar error: "%star_002.phar.tar" is a corrupted tar file (truncated) in %star_002.php on line 9
+phar error: "%star_002.phar.tar" is a corrupted tar file (truncated)
+===DONE===
diff --git a/ext/phar/tests/tar/tar_003.phpt b/ext/phar/tests/tar/tar_003.phpt
new file mode 100644
index 0000000000..47f1d6ca9b
--- /dev/null
+++ b/ext/phar/tests/tar/tar_003.phpt
@@ -0,0 +1,74 @@
+--TEST--
+Phar: tar-based phar, valid 1
+--SKIPIF--
+<?php if (!extension_loaded('phar')) die('skip'); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+include dirname(__FILE__) . '/files/tarmaker.php.inc';
+
+$fname = dirname(__FILE__) . '/tar_003.phar.tar';
+$alias = 'phar://' . $fname;
+
+$tar = new tarmaker($fname, 'none');
+$tar->init();
+$tar->addFile('.phar/stub.php', "<?php // tar-based phar archive stub file\n__HALT_COMPILER();");
+$tar->addFile('tar_003.phpt', $g = fopen(__FILE__, 'r'));
+$tar->addFile('internal/file/here', "hi there!\n");
+$tar->mkDir('internal/dir');
+$tar->mkDir('dir');
+$tar->close();
+
+fclose($g);
+
+echo file_get_contents($alias . '/internal/file/here');
+
+try {
+$tar = opendir($alias . '/');
+} catch (Exception $e) {
+echo $e->getMessage()."\n";
+}
+
+while (false !== ($v = readdir($tar))) {
+ echo (is_file($alias . '/' . $v) ? "file\n" : "dir\n");
+ echo $v . "\n";
+}
+closedir($tar);
+
+/* ensure none of the dir tar files were freed */
+echo "second round\n";
+$tar = opendir($alias . '/');
+while (false !== ($v = readdir($tar))) {
+ echo (is_file($alias . '/' . $v) ? "file\n" : "dir\n");
+ echo $v . "\n";
+}
+closedir($tar);
+
+?>
+===DONE===
+--CLEAN--
+<?php
+@unlink(dirname(__FILE__) . '/tar_003.phar.tar');
+?>
+--EXPECT--
+hi there!
+dir
+.phar
+dir
+dir
+dir
+internal
+file
+tar_003.phpt
+second round
+dir
+.phar
+dir
+dir
+dir
+internal
+file
+tar_003.phpt
+===DONE===
diff --git a/ext/phar/tests/tar/tar_004.phpt b/ext/phar/tests/tar/tar_004.phpt
new file mode 100644
index 0000000000..2dd7ba169f
--- /dev/null
+++ b/ext/phar/tests/tar/tar_004.phpt
@@ -0,0 +1,38 @@
+--TEST--
+Phar: tar-based phar, tar phar with stub, mapPhar()
+--SKIPIF--
+<?php if (!extension_loaded('phar')) die('skip'); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+include dirname(__FILE__) . '/files/tarmaker.php.inc';
+
+$fname = dirname(__FILE__) . '/tar_004.phar.tar';
+$alias = 'phar://' . $fname;
+
+$tar = new tarmaker($fname, 'none');
+$tar->init();
+$tar->addFile('tar_004.php', '<?php var_dump(__FILE__);');
+$tar->addFile('internal/file/here', "hi there!\n");
+$tar->mkDir('internal/dir');
+$tar->mkDir('dir');
+$tar->addFile('.phar/stub.php', '<?php
+Phar::mapPhar();
+var_dump("it worked");
+include "phar://" . __FILE__ . "/tar_004.php";
+');
+$tar->close();
+
+include $fname;
+?>
+===DONE===
+--CLEAN--
+<?php
+@unlink(dirname(__FILE__) . '/tar_004.phar.tar');
+?>
+--EXPECTF--
+string(9) "it worked"
+string(%d) "phar://%star_004.phar.tar/tar_004.php"
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/tar/tar_bz2.phpt b/ext/phar/tests/tar/tar_bz2.phpt
new file mode 100644
index 0000000000..ad14541431
--- /dev/null
+++ b/ext/phar/tests/tar/tar_bz2.phpt
@@ -0,0 +1,54 @@
+--TEST--
+Phar: tar-based phar, bzipped tar
+--SKIPIF--
+<?php if (!extension_loaded('phar')) die('skip'); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+<?php if (!extension_loaded("bz2")) die("skip bz2 not available"); ?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+include dirname(__FILE__) . '/files/tarmaker.php.inc';
+
+$fname = dirname(__FILE__) . '/tar_bz2.phar';
+$alias = 'phar://' . $fname;
+$fname2 = dirname(__FILE__) . '/tar_bz2.phar.tar';
+$alias2 = 'phar://' . $fname2;
+
+$tar = new tarmaker($fname, 'bz2');
+$tar->init();
+$tar->addFile('tar_004.php', '<?php var_dump(__FILE__);');
+$tar->addFile('internal/file/here', "hi there!\n");
+$tar->mkDir('internal/dir');
+$tar->mkDir('dir');
+$tar->addFile('.phar/stub.php', '<?php
+Phar::mapPhar();
+var_dump("it worked");
+include "phar://" . __FILE__ . "/tar_004.php";
+');
+$tar->close();
+
+include $fname;
+
+$phar = new Phar($fname);
+$phar['test'] = 'hi';
+
+copy($fname, $fname2);
+
+$phar2 = new Phar($fname2);
+var_dump($phar2->isFileFormat(Phar::TAR));
+var_dump($phar2->isCompressed() == Phar::BZ2);
+
+?>
+===DONE===
+--CLEAN--
+<?php
+@unlink(dirname(__FILE__) . '/tar_bz2.phar');
+@unlink(dirname(__FILE__) . '/tar_bz2.phar.tar');
+?>
+--EXPECTF--
+string(9) "it worked"
+string(%d) "phar://%star_bz2.phar/tar_004.php"
+bool(true)
+bool(true)
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/tar/tar_gzip.phpt b/ext/phar/tests/tar/tar_gzip.phpt
new file mode 100644
index 0000000000..8287ee7f06
--- /dev/null
+++ b/ext/phar/tests/tar/tar_gzip.phpt
@@ -0,0 +1,51 @@
+--TEST--
+Phar: tar-based phar, gzipped tar
+--SKIPIF--
+<?php if (!extension_loaded('phar')) die('skip'); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+<?php if (!extension_loaded("zlib")) die("skip zlib not available"); ?>
+<?php if (version_compare(phpversion(), '5.2.6', '<')) die("skip zlib is buggy in PHP < 5.2.6"); ?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+include dirname(__FILE__) . '/files/tarmaker.php.inc';
+$fname = dirname(__FILE__) . '/tar_gzip.phar';
+$pname = 'phar://' . $fname;
+$fname2 = dirname(__FILE__) . '/tar_gzip.phar.tar';
+$pname2 = 'phar://' . $fname2;
+
+$a = new tarmaker($fname, 'zlib');
+$a->init();
+$a->addFile('tar_004.php', '<?php var_dump(__FILE__);');
+$a->addFile('internal/file/here', "hi there!\n");
+$a->mkDir('internal/dir');
+$a->mkDir('dir');
+$a->addFile('.phar/stub.php', '<?php
+Phar::mapPhar();
+var_dump("it worked");
+include "phar://" . __FILE__ . "/tar_004.php";
+');
+$a->close();
+
+include $fname;
+
+$a = new Phar($fname);
+$a['test'] = 'hi';
+copy($fname, $fname2);
+$b = new Phar($fname2);
+var_dump($b->isFileFormat(Phar::TAR));
+var_dump($b->isCompressed() == Phar::GZ);
+?>
+===DONE===
+--CLEAN--
+<?php
+@unlink(dirname(__FILE__) . '/tar_gzip.phar');
+@unlink(dirname(__FILE__) . '/tar_gzip.phar.tar');
+?>
+--EXPECTF--
+string(9) "it worked"
+string(%d) "phar://%star_gzip.phar/tar_004.php"
+bool(true)
+bool(true)
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/tar/tar_makebz2.phpt b/ext/phar/tests/tar/tar_makebz2.phpt
new file mode 100644
index 0000000000..f703b46924
--- /dev/null
+++ b/ext/phar/tests/tar/tar_makebz2.phpt
@@ -0,0 +1,40 @@
+--TEST--
+Phar: tar-based phar, make new bzipped tar
+--SKIPIF--
+<?php if (!extension_loaded('phar')) die('skip'); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+<?php if (!extension_loaded("bz2")) die("skip bz2 not available"); ?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/tar_makebz2.phar.tar';
+$fname2 = dirname(__FILE__) . '/tar_makebz2.phar.tar.bz2';
+$fname3 = dirname(__FILE__) . '/tar_makebz2_b.phar.tar.bz2';
+
+$phar = new Phar($fname);
+$phar['test'] = 'hi';
+var_dump($phar->isFileFormat(Phar::TAR));
+$phar = $phar->compress(Phar::BZ2);
+
+copy($fname2, $fname3);
+
+$phar2 = new Phar($fname3);
+var_dump($phar2->isFileFormat(Phar::TAR));
+var_dump($phar2->isCompressed() == Phar::BZ2);
+
+?>
+===DONE===
+--CLEAN--
+<?php
+@unlink(dirname(__FILE__) . '/tar_makebz2.phar.bz2');
+@unlink(dirname(__FILE__) . '/tar_makebz2.phar.tar');
+@unlink(dirname(__FILE__) . '/tar_makebz2.phar.tar.bz2');
+@unlink(dirname(__FILE__) . '/tar_makebz2_b.phar.tar.bz2');
+?>
+--EXPECTF--
+bool(true)
+bool(true)
+bool(true)
+===DONE===
diff --git a/ext/phar/tests/tar/tar_makegz.phpt b/ext/phar/tests/tar/tar_makegz.phpt
new file mode 100644
index 0000000000..46fe177611
--- /dev/null
+++ b/ext/phar/tests/tar/tar_makegz.phpt
@@ -0,0 +1,41 @@
+--TEST--
+Phar: tar-based phar, make new gzipped tar
+--SKIPIF--
+<?php if (!extension_loaded('phar')) die('skip'); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+<?php if (!extension_loaded("zlib")) die("skip zlib not available"); ?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/tar_makegz.phar.tar';
+$fname2 = dirname(__FILE__) . '/tar_makegz.phar.tar.gz';
+$fname3 = dirname(__FILE__) . '/tar_makegz_b.phar.tar.gz';
+
+$phar = new Phar($fname);
+$phar['test'] = 'hi';
+var_dump($phar->isFileFormat(Phar::TAR));
+$phar = $phar->compress(Phar::GZ);
+
+
+copy($fname2, $fname3);
+
+$phar2 = new Phar($fname3);
+var_dump($phar2->isFileFormat(Phar::TAR));
+var_dump($phar2->isCompressed() == Phar::GZ);
+
+?>
+===DONE===
+--CLEAN--
+<?php
+@unlink(dirname(__FILE__) . '/tar_makegz.phar.gz');
+@unlink(dirname(__FILE__) . '/tar_makegz.phar.tar');
+@unlink(dirname(__FILE__) . '/tar_makegz.phar.tar.gz');
+@unlink(dirname(__FILE__) . '/tar_makegz_b.phar.tar.gz');
+?>
+--EXPECTF--
+bool(true)
+bool(true)
+bool(true)
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/tar/tar_nostub.phpt b/ext/phar/tests/tar/tar_nostub.phpt
new file mode 100644
index 0000000000..a107a37deb
--- /dev/null
+++ b/ext/phar/tests/tar/tar_nostub.phpt
@@ -0,0 +1,48 @@
+--TEST--
+Phar: tar-based phar, third-party tar with no stub, Phar->getStub()
+--SKIPIF--
+<?php if (!extension_loaded('phar')) die('skip'); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+--INI--
+phar.readonly=1
+--FILE--
+<?php
+include dirname(__FILE__) . '/files/tarmaker.php.inc';
+$fname = dirname(__FILE__) . '/tar_004.phar.tar';
+$alias = 'phar://' . $fname;
+$fname2 = dirname(__FILE__) . '/tar_004.tar';
+
+$tar = new tarmaker($fname, 'none');
+$tar->init();
+$tar->addFile('tar_004.php', '<?php var_dump(__FILE__);');
+$tar->addFile('internal/file/here', "hi there!\n");
+$tar->close();
+
+try {
+ $phar = new Phar($fname);
+ var_dump($phar->getStub());
+} catch (Exception $e) {
+ echo $e->getMessage()."\n";
+}
+
+copy($fname, $fname2);
+
+try {
+ $phar = new PharData($fname2);
+ var_dump($phar->getStub());
+} catch (Exception $e) {
+ echo $e->getMessage()."\n";
+}
+
+?>
+===DONE===
+--CLEAN--
+<?php
+@unlink(dirname(__FILE__) . '/tar_004.phar.tar');
+@unlink(dirname(__FILE__) . '/tar_004.tar');
+?>
+--EXPECTF--
+RecursiveDirectoryIterator::__construct(phar://%star_004.phar.tar/): failed to open dir: '%star_004.phar.tar' is not a phar archive. Use PharData::__construct() for a standard zip or tar archive
+phar url "phar://%star_004.phar.tar/" is unknown
+string(0) ""
+===DONE===
diff --git a/ext/phar/tests/tar/truncated.phpt b/ext/phar/tests/tar/truncated.phpt
new file mode 100644
index 0000000000..fbcabb7986
--- /dev/null
+++ b/ext/phar/tests/tar/truncated.phpt
@@ -0,0 +1,22 @@
+--TEST--
+Phar: truncated tar
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--FILE--
+<?php
+try {
+ $p = new PharData(dirname(__FILE__) . '/files/trunc.tar');
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar');
+?>
+--EXPECTF--
+phar error: "%strunc.tar" is a corrupted tar file (truncated)
+===DONE===
diff --git a/ext/phar/tests/test_alias_unset.phpt b/ext/phar/tests/test_alias_unset.phpt
new file mode 100644
index 0000000000..0127d8bba2
--- /dev/null
+++ b/ext/phar/tests/test_alias_unset.phpt
@@ -0,0 +1,45 @@
+--TEST--
+Phar: test for the odd case where we intend to remove an archive from memory
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.2.phar.php';
+$pname2 = 'phar://' . $fname2;
+
+$phar = new Phar($fname);
+$phar->setAlias('first');
+$phar['file1.txt'] = 'hi';
+unset($phar);
+
+$phar2 = new Phar($fname2);
+$phar2->setAlias('first'); // this works because there are no references to $fname open
+$phar2['file1.txt'] = 'hi';
+unset($phar2);
+
+$a = fopen($pname . '/file1.txt', 'r'); // this works because there are no references to $fname2 open
+try {
+$phar2 = new Phar($fname2); // fails because references open to $fname
+} catch (Exception $e) {
+echo $e->getMessage(),"\n";
+}
+fclose($a);
+$phar2 = new Phar($fname2); // succeeds because all refs are closed
+var_dump($phar2->getAlias());
+
+$a = file_get_contents($pname . '/file1.txt'); // this fails because $fname2 ref exists
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.2.phar.php'); ?>
+--EXPECTF--
+Cannot open archive "%stest_alias_unset.2.phar.php", alias is already in use by existing archive
+string(5) "first"
+
+Warning: file_get_contents(phar://%sfile1.txt): failed to open stream: Cannot open archive "%stest_alias_unset.phar.php", alias is already in use by existing archive in %stest_alias_unset.php on line %d
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/test_signaturealgos.phpt b/ext/phar/tests/test_signaturealgos.phpt
new file mode 100644
index 0000000000..74f9e639ae
--- /dev/null
+++ b/ext/phar/tests/test_signaturealgos.phpt
@@ -0,0 +1,30 @@
+--TEST--
+Phar: verify signature parsing works
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("hash")) die("skip extension hash conflicts"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+$a = new Phar(dirname(__FILE__) . '/files/sha1.phar');
+$r = $a->getSignature();
+var_dump($r['hash_type']);
+$a = new Phar(dirname(__FILE__) . '/files/sha512.phar');
+$r = $a->getSignature();
+var_dump($r['hash_type']);
+$a = new Phar(dirname(__FILE__) . '/files/sha256.phar');
+$r = $a->getSignature();
+var_dump($r['hash_type']);
+$a = new Phar(dirname(__FILE__) . '/files/md5.phar');
+$r = $a->getSignature();
+var_dump($r['hash_type']);
+?>
+===DONE===
+--EXPECT--
+string(5) "SHA-1"
+string(7) "SHA-512"
+string(7) "SHA-256"
+string(3) "MD5"
+===DONE===
diff --git a/ext/phar/tests/test_unset.phpt b/ext/phar/tests/test_unset.phpt
new file mode 100644
index 0000000000..3da537c13c
--- /dev/null
+++ b/ext/phar/tests/test_unset.phpt
@@ -0,0 +1,42 @@
+--TEST--
+Phar: ensure unset() works properly on a non-flushed phar archive
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.2.phar.php';
+
+if (file_exists($fname)) unlink($fname);
+if (file_exists($fname2)) unlink($fname2);
+
+$phar = new Phar($fname); // no entries, never flushed
+$phar->setAlias('first');
+$phar->setMetadata('hi');
+unset($phar);
+
+$phar = new Phar($fname2);
+$phar['b'] = 'whatever'; // flushed
+try {
+ $phar->setAlias('first');
+} catch(Exception $e) {
+ echo $e->getMessage()."\n";
+}
+
+$phar = new Phar($fname);
+var_dump($phar->getMetadata());
+var_dump($phar->getAlias());
+var_dump(file_exists($fname));
+
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.2.phar.php'); ?>
+--EXPECTF--
+NULL
+string(%d) "%stest_unset.phar.php"
+bool(false)
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/webphar_compilefail.phpt b/ext/phar/tests/webphar_compilefail.phpt
new file mode 100644
index 0000000000..ab5532d6be
--- /dev/null
+++ b/ext/phar/tests/webphar_compilefail.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Phar: Phar::webPhar, open compiled file fails
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip");?>
+--INI--
+phar.readonly=1
+--FILE--
+<?php
+try {
+Phar::webPhar('oopsiedaisy.phar', '/index.php');
+} catch (Exception $e) {
+echo $e->getMessage() . "\n";
+}
+__HALT_COMPILER();
+?>
+--EXPECTF--
+internal corruption of phar "%swebphar_compilefail.php" (truncated manifest at manifest length) \ No newline at end of file
diff --git a/ext/phar/tests/withphar.phpt b/ext/phar/tests/withphar.phpt
new file mode 100644
index 0000000000..c422fa9843
--- /dev/null
+++ b/ext/phar/tests/withphar.phpt
@@ -0,0 +1,14 @@
+--TEST--
+Phar: phar run with pecl/phar with default stub
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--FILE--
+<?php
+include dirname(__FILE__) . '/files/nophar.phar';
+?>
+===DONE===
+--EXPECT--
+in b
+<?php include "b/c.php";
+in d
+===DONE===
diff --git a/ext/phar/tests/withphar_web.phpt b/ext/phar/tests/withphar_web.phpt
new file mode 100644
index 0000000000..45acf13d7f
--- /dev/null
+++ b/ext/phar/tests/withphar_web.phpt
@@ -0,0 +1,14 @@
+--TEST--
+Phar: default web stub, with phar extension
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip");?>
+--ENV--
+SCRIPT_NAME=/withphar_web.php
+REQUEST_URI=/withphar_web.php/web.php
+PATH_INFO=/web.php
+--FILE_EXTERNAL--
+files/nophar.phar
+--EXPECTHEADERS--
+Content-type: text/html
+--EXPECT--
+web
diff --git a/ext/phar/tests/zf_test.phpt b/ext/phar/tests/zf_test.phpt
new file mode 100644
index 0000000000..99e5c4f6e7
--- /dev/null
+++ b/ext/phar/tests/zf_test.phpt
@@ -0,0 +1,49 @@
+--TEST--
+Phar: test broken app
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+
+$file = "zfapp";
+$orig_file = dirname(__FILE__) . "/files/$file.tgz";
+$tgz_file = dirname(__FILE__) . "/$file.tgz";
+$phar_file = dirname(__FILE__) . "/$file.phar.tar.gz";
+copy($orig_file, $tgz_file);
+
+$phar = new PharData($tgz_file);
+$phar = $phar->convertToExecutable();
+
+$phar = new Phar($phar_file);
+$phar->startBuffering();
+$phar->setStub("<?php
+Phar::interceptFileFuncs();
+Phar::webPhar('$file.phar', 'html/index.php');
+echo 'BlogApp is intended to be executed from a web browser\n';
+exit -1;
+__HALT_COMPILER();
+");
+$phar->stopBuffering();
+
+foreach(new RecursiveIteratorIterator($phar) as $path) {
+ echo str_replace('\\', '/', $path->getPathName()) . "\n";
+}
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/zfapp.tgz');
+unlink(dirname(__FILE__) . '/zfapp.phar.tar.gz');
+?>
+--EXPECTF--
+phar://%szfapp.phar.tar.gz/.phar/stub.php
+phar://%szfapp.phar.tar.gz/application/default/controllers/ErrorController.php
+phar://%szfapp.phar.tar.gz/application/default/controllers/IndexController.php
+phar://%szfapp.phar.tar.gz/application/default/views/scripts/error/error.phtml
+phar://%szfapp.phar.tar.gz/application/default/views/scripts/index/index.phtml
+phar://%szfapp.phar.tar.gz/html/.htaccess
+phar://%szfapp.phar.tar.gz/html/index.php
+===DONE===
diff --git a/ext/phar/tests/zip/033.phpt b/ext/phar/tests/zip/033.phpt
new file mode 100644
index 0000000000..c980758a83
--- /dev/null
+++ b/ext/phar/tests/zip/033.phpt
@@ -0,0 +1,56 @@
+--TEST--
+Phar::chmod zip-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.zip';
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.2.phar.zip';
+$alias = 'phar://hio';
+
+$phar = new Phar($fname);
+$phar['a.php'] = '<?php echo "This is a\n"; include "'.$alias.'/b.php"; ?>';
+$phar->setAlias('hio');
+$phar->addEmptyDir('test');
+$phar->stopBuffering();
+
+try {
+ var_dump($phar['a.php']->isExecutable());
+ $phar['a.php']->chmod(0777);
+ copy($fname, $fname2);
+ $phar->setAlias('unused');
+ $phar2 = new Phar($fname2);
+ var_dump($phar2['a.php']->isExecutable());
+ $phar['a.php']->chmod(0666);
+ var_dump($phar['a.php']->isExecutable());
+ echo "test dir\n";
+ var_dump($phar['test']->isDir());
+ var_dump($phar['test']->isReadable());
+ $phar['test']->chmod(0000);
+ var_dump($phar['test']->isReadable());
+ $phar['test']->chmod(0666);
+ var_dump($phar['test']->isReadable());
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.zip');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.2.phar.zip');
+?>
+--EXPECT--
+bool(false)
+bool(true)
+bool(false)
+test dir
+bool(true)
+bool(true)
+bool(false)
+bool(true)
+===DONE===
diff --git a/ext/phar/tests/zip/033a.phpt b/ext/phar/tests/zip/033a.phpt
new file mode 100644
index 0000000000..429d3bdd98
--- /dev/null
+++ b/ext/phar/tests/zip/033a.phpt
@@ -0,0 +1,45 @@
+--TEST--
+Phar::chmod zip-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.zip';
+$alias = 'phar://hio';
+
+$phar = new Phar($fname);
+$phar['a.php'] = '<?php echo "This is a\n"; include "'.$alias.'/b.php"; ?>';
+$phar->setAlias('hio');
+$phar->addEmptyDir('test');
+$phar->stopBuffering();
+ini_set('phar.readonly', 1);
+
+try {
+ var_dump($phar['a.php']->isExecutable());
+ $phar['a.php']->chmod(0777);
+ var_dump($phar['a.php']->isExecutable());
+ $phar['a.php']->chmod(0666);
+ var_dump($phar['a.php']->isExecutable());
+ echo "test dir\n";
+ var_dump($phar['test']->isExecutable());
+ $phar['test']->chmod(0777);
+ var_dump($phar['test']->isExecutable());
+ $phar['test']->chmod(0666);
+ var_dump($phar['test']->isExecutable());
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.zip');
+?>
+--EXPECTF--
+bool(false)
+Cannot modify permissions for file "a.php" in phar "%sa.phar.zip", write operations are prohibited
+===DONE===
diff --git a/ext/phar/tests/zip/alias_acrobatics.phpt b/ext/phar/tests/zip/alias_acrobatics.phpt
new file mode 100644
index 0000000000..2a58e39efc
--- /dev/null
+++ b/ext/phar/tests/zip/alias_acrobatics.phpt
@@ -0,0 +1,46 @@
+--TEST--
+Phar: alias edge cases
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.zip';
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.2.phar.zip';
+
+$p = new Phar($fname);
+
+$p->setAlias('foo');
+$p['unused'] = 'hi';
+try {
+$a = new Phar($fname2, 0, 'foo');
+} catch (Exception $e) {
+echo $e->getMessage(),"\n";
+}
+copy($fname, $fname2);
+echo "2\n";
+try {
+$a = new Phar($fname2);
+} catch (Exception $e) {
+echo $e->getMessage(),"\n";
+}
+try {
+$b = new Phar($fname, 0, 'another');
+} catch (Exception $e) {
+echo $e->getMessage(),"\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.zip');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.2.phar.zip');
+?>
+--EXPECTF--
+alias "foo" is already used for archive "%salias_acrobatics.phar.zip" cannot be overloaded with "%salias_acrobatics.2.phar.zip"
+2
+phar error: Unable to add zip-based phar "%salias_acrobatics.2.phar.zip" with implicit alias, alias is already in use
+alias "another" is already used for archive "%salias_acrobatics.phar.zip" cannot be overloaded with "%salias_acrobatics.phar.zip"
+===DONE===
diff --git a/ext/phar/tests/zip/all.phpt b/ext/phar/tests/zip/all.phpt
new file mode 100644
index 0000000000..84bbfc36be
--- /dev/null
+++ b/ext/phar/tests/zip/all.phpt
@@ -0,0 +1,62 @@
+--TEST--
+Phar: test that creation of zip-based phar generates valid zip with all bells/whistles
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+<?php if (!extension_loaded("zlib")) die("skip zlib not available"); ?>
+<?php if (!extension_loaded("bz2")) die("skip bz2 not available"); ?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.zip.php';
+$pname = 'phar://' . $fname;
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.2.phar.zip.php';
+$pname2 = 'phar://' . $fname2;
+
+$phar = new Phar($fname);
+
+$phar->setMetadata('hi there');
+$phar['a'] = 'hi';
+$phar['a']->setMetadata('a meta');
+$phar['b'] = 'hi2';
+$phar['b']->compress(Phar::GZ);
+$phar['c'] = 'hi3';
+$phar['c']->compress(Phar::BZ2);
+$phar['b']->chmod(0444);
+$phar->setStub("<?php ok __HALT_COMPILER();");
+$phar->setAlias("hime");
+unset($phar);
+copy($fname, $fname2);
+Phar::unlinkArchive($fname);
+var_dump(file_exists($fname), file_exists($pname . '/a'));
+
+$phar = new Phar($fname2);
+var_dump($phar['a']->getContent(), $phar['b']->getContent(), $phar['c']->getContent());
+var_dump($phar['a']->isCompressed(), $phar['b']->isCompressed() == Phar::GZ, $phar['c']->isCompressed() == Phar::BZ2);
+var_dump((string) decoct(fileperms($pname2 . '/b')));
+var_dump($phar->getStub());
+var_dump($phar->getAlias());
+var_dump($phar->getMetadata());
+var_dump($phar['a']->getMetadata());
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.2.phar.zip.php'); ?>
+--EXPECT--
+bool(false)
+bool(false)
+string(2) "hi"
+string(3) "hi2"
+string(3) "hi3"
+bool(false)
+bool(true)
+bool(true)
+string(6) "100444"
+string(32) "<?php ok __HALT_COMPILER(); ?>
+"
+string(4) "hime"
+string(8) "hi there"
+string(6) "a meta"
+===DONE===
diff --git a/ext/phar/tests/zip/badalias.phpt b/ext/phar/tests/zip/badalias.phpt
new file mode 100644
index 0000000000..0291c4b089
--- /dev/null
+++ b/ext/phar/tests/zip/badalias.phpt
@@ -0,0 +1,25 @@
+--TEST--
+Phar: invalid aliases
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("zlib")) die("skip no zlib"); ?>
+<?php if (!extension_loaded("bz2")) die("skip no bz2"); ?>
+--FILE--
+<?php
+$e = dirname(__FILE__) . '/files/';
+for ($i = 1; $i <= 5; $i++) {
+try {
+new Phar($e . "badalias$i.phar.zip");
+} catch (Exception $ee) {
+echo $ee->getMessage(), "\n";
+}
+}
+?>
+===DONE===
+--EXPECTF--
+phar error: invalid alias "hi/there" in zip-based phar "%sbadalias1.phar.zip"
+phar error: invalid alias "hi\there" in zip-based phar "%sbadalias2.phar.zip"
+phar error: invalid alias "hi\there" in zip-based phar "%sbadalias3.phar.zip"
+phar error: invalid alias "hi;there" in zip-based phar "%sbadalias4.phar.zip"
+phar error: invalid alias "hi:there" in zip-based phar "%sbadalias5.phar.zip"
+===DONE===
diff --git a/ext/phar/tests/zip/corrupt_001.phpt b/ext/phar/tests/zip/corrupt_001.phpt
new file mode 100644
index 0000000000..0b019c6d83
--- /dev/null
+++ b/ext/phar/tests/zip/corrupt_001.phpt
@@ -0,0 +1,23 @@
+--TEST--
+Phar: corrupted zip (count mismatch)
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+--FILE--
+<?php
+try {
+ new PharData(dirname(__FILE__) . '/files/count1.zip');
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+try {
+ new PharData(dirname(__FILE__) . '/files/count2.zip');
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--EXPECTF--
+phar error: corrupt zip archive, conflicting file count in end of central directory record in zip-based phar "%scount1.zip"
+phar error: corrupt zip archive, conflicting file count in end of central directory record in zip-based phar "%scount2.zip"
+===DONE===
diff --git a/ext/phar/tests/zip/corrupt_002.phpt b/ext/phar/tests/zip/corrupt_002.phpt
new file mode 100644
index 0000000000..86a271231d
--- /dev/null
+++ b/ext/phar/tests/zip/corrupt_002.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Phar: corrupted zip (no end of zip record)
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+--FILE--
+<?php
+try {
+ new PharData(dirname(__FILE__) . '/files/nozipend.zip');
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--EXPECTF--
+phar error: end of central directory not found in zip-based phar "%snozipend.zip"
+===DONE===
diff --git a/ext/phar/tests/zip/corrupt_003.phpt b/ext/phar/tests/zip/corrupt_003.phpt
new file mode 100644
index 0000000000..c41e0153d8
--- /dev/null
+++ b/ext/phar/tests/zip/corrupt_003.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Phar: corrupted zip (truncated file comment)
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+--FILE--
+<?php
+try {
+ new PharData(dirname(__FILE__) . '/files/filecomment.zip');
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--EXPECTF--
+phar error: corrupt zip archive, zip file comment truncated in zip-based phar "%sfilecomment.zip"
+===DONE===
diff --git a/ext/phar/tests/zip/corrupt_004.phpt b/ext/phar/tests/zip/corrupt_004.phpt
new file mode 100644
index 0000000000..3760e8f9ae
--- /dev/null
+++ b/ext/phar/tests/zip/corrupt_004.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Phar: corrupted zip (central directory offset incorrect)
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+--FILE--
+<?php
+try {
+ new PharData(dirname(__FILE__) . '/files/cdir_offset.zip');
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--EXPECTF--
+phar error: corrupted central directory entry, no magic signature in zip-based phar "%scdir_offset.zip"
+===DONE===
diff --git a/ext/phar/tests/zip/corrupt_005.phpt b/ext/phar/tests/zip/corrupt_005.phpt
new file mode 100644
index 0000000000..6b5d31d967
--- /dev/null
+++ b/ext/phar/tests/zip/corrupt_005.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Phar: encrypted zip
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+--FILE--
+<?php
+try {
+ new PharData(dirname(__FILE__) . '/files/encrypted.zip');
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--EXPECTF--
+phar error: Cannot process encrypted zip files in zip-based phar "%sencrypted.zip"
+===DONE===
diff --git a/ext/phar/tests/zip/corrupt_006.phpt b/ext/phar/tests/zip/corrupt_006.phpt
new file mode 100644
index 0000000000..9c83617a9a
--- /dev/null
+++ b/ext/phar/tests/zip/corrupt_006.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Phar: zip with file created from stdin
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+--FILE--
+<?php
+try {
+ new PharData(dirname(__FILE__) . '/files/stdin.zip');
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--EXPECTF--
+phar error: Cannot process zips created from stdin (zero-length filename) in zip-based phar "%sstdin.zip"
+===DONE===
diff --git a/ext/phar/tests/zip/corrupt_007.phpt b/ext/phar/tests/zip/corrupt_007.phpt
new file mode 100644
index 0000000000..80c9139025
--- /dev/null
+++ b/ext/phar/tests/zip/corrupt_007.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Phar: corrupted zip (truncated filename record)
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+--FILE--
+<?php
+try {
+ new PharData(dirname(__FILE__) . '/files/truncfilename.zip');
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--EXPECTF--
+phar error: corrupted central directory entry, no magic signature in zip-based phar "%struncfilename.zip"
+===DONE===
diff --git a/ext/phar/tests/zip/corrupt_008.phpt b/ext/phar/tests/zip/corrupt_008.phpt
new file mode 100644
index 0000000000..5a20f4d2ec
--- /dev/null
+++ b/ext/phar/tests/zip/corrupt_008.phpt
@@ -0,0 +1,101 @@
+--TEST--
+Phar: unsupported compression methods
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+--FILE--
+<?php
+try {
+ new PharData(dirname(__FILE__) . '/files/compress_unsup1.zip');
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+try {
+ new PharData(dirname(__FILE__) . '/files/compress_unsup2.zip');
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+try {
+ new PharData(dirname(__FILE__) . '/files/compress_unsup3.zip');
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+try {
+ new PharData(dirname(__FILE__) . '/files/compress_unsup4.zip');
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+try {
+ new PharData(dirname(__FILE__) . '/files/compress_unsup5.zip');
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+try {
+ new PharData(dirname(__FILE__) . '/files/compress_unsup6.zip');
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+try {
+ new PharData(dirname(__FILE__) . '/files/compress_unsup7.zip');
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+try {
+ new PharData(dirname(__FILE__) . '/files/compress_unsup9.zip');
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+try {
+ new PharData(dirname(__FILE__) . '/files/compress_unsup10.zip');
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+try {
+ new PharData(dirname(__FILE__) . '/files/compress_unsup14.zip');
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+try {
+ new PharData(dirname(__FILE__) . '/files/compress_unsup18.zip');
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+try {
+ new PharData(dirname(__FILE__) . '/files/compress_unsup19.zip');
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+try {
+ new PharData(dirname(__FILE__) . '/files/compress_unsup97.zip');
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+try {
+ new PharData(dirname(__FILE__) . '/files/compress_unsup98.zip');
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+try {
+ new PharData(dirname(__FILE__) . '/files/compress_unsupunknown.zip');
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--EXPECTF--
+phar error: unsupported compression method (Shrunk) used in this zip in zip-based phar "%scompress_unsup1.zip"
+phar error: unsupported compression method (Reduce) used in this zip in zip-based phar "%scompress_unsup2.zip"
+phar error: unsupported compression method (Reduce) used in this zip in zip-based phar "%scompress_unsup3.zip"
+phar error: unsupported compression method (Reduce) used in this zip in zip-based phar "%scompress_unsup4.zip"
+phar error: unsupported compression method (Reduce) used in this zip in zip-based phar "%scompress_unsup5.zip"
+phar error: unsupported compression method (Implode) used in this zip in zip-based phar "%scompress_unsup6.zip"
+phar error: unsupported compression method (Tokenize) used in this zip in zip-based phar "%scompress_unsup7.zip"
+phar error: unsupported compression method (Deflate64) used in this zip in zip-based phar "%scompress_unsup9.zip"
+phar error: unsupported compression method (PKWare Implode/old IBM TERSE) used in this zip in zip-based phar "%scompress_unsup10.zip"
+phar error: unsupported compression method (LZMA) used in this zip in zip-based phar "%scompress_unsup14.zip"
+phar error: unsupported compression method (IBM TERSE) used in this zip in zip-based phar "%scompress_unsup18.zip"
+phar error: unsupported compression method (IBM LZ77) used in this zip in zip-based phar "%scompress_unsup19.zip"
+phar error: unsupported compression method (WavPack) used in this zip in zip-based phar "%scompress_unsup97.zip"
+phar error: unsupported compression method (PPMd) used in this zip in zip-based phar "%scompress_unsup98.zip"
+phar error: unsupported compression method (unknown) used in this zip in zip-based phar "%scompress_unsupunknown.zip"
+===DONE===
diff --git a/ext/phar/tests/zip/create_new_and_modify.phpt b/ext/phar/tests/zip/create_new_and_modify.phpt
new file mode 100644
index 0000000000..5a3ec3317b
--- /dev/null
+++ b/ext/phar/tests/zip/create_new_and_modify.phpt
@@ -0,0 +1,45 @@
+--TEST--
+Phar: create and modify zip-based phar
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.zip.php';
+$pname = 'phar://' . $fname;
+
+@unlink($fname);
+
+file_put_contents($pname . '/a.php', "brand new!\n");
+
+$phar = new Phar($fname);
+var_dump($phar->isFileFormat(Phar::ZIP));
+$sig1 = md5_file($fname);
+
+include $pname . '/a.php';
+
+file_put_contents($pname .'/a.php', "modified!\n");
+file_put_contents($pname .'/b.php', "another!\n");
+
+$phar = new Phar($fname);
+$sig2 = md5_file($fname);
+
+var_dump($sig1 != $sig2);
+
+include $pname . '/a.php';
+include $pname . '/b.php';
+
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.zip.php'); ?>
+--EXPECTF--
+bool(true)
+brand new!
+bool(true)
+modified!
+another!
+===DONE===
diff --git a/ext/phar/tests/zip/create_new_phar_b.phpt b/ext/phar/tests/zip/create_new_phar_b.phpt
new file mode 100644
index 0000000000..e6a5398f64
--- /dev/null
+++ b/ext/phar/tests/zip/create_new_phar_b.phpt
@@ -0,0 +1,27 @@
+--TEST--
+Phar: create a completely new zip-based phar
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=1
+phar.require_hash=1
+--FILE--
+<?php
+
+file_put_contents('phar://' . dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.zip/a.php',
+ 'brand new!');
+include 'phar://' . dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.zip/a.php';
+?>
+
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.zip'); ?>
+--EXPECTF--
+
+Warning: file_put_contents(phar://%screate_new_phar_b.phar.zip/a.php): failed to open stream: phar error: write operations disabled by INI setting in %screate_new_phar_b.php on line %d
+
+Warning: include(phar://%screate_new_phar_b.phar.zip/a.php): failed to open stream: %s in %screate_new_phar_b.php on line %d
+
+Warning: include(): Failed opening 'phar://%screate_new_phar_b.phar.zip/a.php' for inclusion (include_path='%s') in %screate_new_phar_b.php on line %d
+
+===DONE===
diff --git a/ext/phar/tests/zip/delete.phpt b/ext/phar/tests/zip/delete.phpt
new file mode 100644
index 0000000000..06078b3a39
--- /dev/null
+++ b/ext/phar/tests/zip/delete.phpt
@@ -0,0 +1,31 @@
+--TEST--
+Phar: delete test, zip-based phar
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.zip';
+$alias = 'phar://' . $fname;
+$file = "<?php
+Phar::mapPhar('hio');
+__HALT_COMPILER(); ?>";
+
+$phar = new Phar($fname);
+$phar['a'] = 'a';
+$phar->setStub($file);
+$phar->stopBuffering();
+
+echo file_get_contents($alias . '/a') . "\n";
+$phar->delete('a');
+echo file_get_contents($alias . '/a') . "\n";
+?>
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.zip'); ?>
+--EXPECTF--
+a
+
+Warning: file_get_contents(phar://%sdelete.phar.zip/a): failed to open stream: phar error: "a" is not a file in phar "%sdelete.phar.zip" in %sdelete.php on line %d \ No newline at end of file
diff --git a/ext/phar/tests/zip/delete_in_phar.phpt b/ext/phar/tests/zip/delete_in_phar.phpt
new file mode 100644
index 0000000000..b7bda7ca4b
--- /dev/null
+++ b/ext/phar/tests/zip/delete_in_phar.phpt
@@ -0,0 +1,49 @@
+--TEST--
+Phar: delete a file within a zip-based .phar
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.zip';
+$alias = 'phar://' . $fname;
+
+$phar = new Phar($fname);
+$phar['a.php'] = '<?php echo "This is a\n"; ?>';
+$phar['b.php'] = '<?php echo "This is b\n"; ?>';
+$phar['b/c.php'] = '<?php echo "This is b/c\n"; ?>';
+$phar->setStub('<?php __HALT_COMPILER(); ?>');
+$phar->stopBuffering();
+
+include $alias . '/a.php';
+include $alias . '/b.php';
+include $alias . '/b/c.php';
+unlink($alias . '/b/c.php');
+?>
+===AFTER===
+<?php
+include $alias . '/a.php';
+include $alias . '/b.php';
+include $alias . '/b/c.php';
+?>
+
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.zip'); ?>
+--EXPECTF--
+This is a
+This is b
+This is b/c
+===AFTER===
+This is a
+This is b
+
+Warning: include(%sdelete_in_phar.phar.zip/b/c.php): failed to open stream: phar error: "b/c.php" is not a file in phar "%sdelete_in_phar.phar.zip" in %sdelete_in_phar.php on line %d
+
+Warning: include(): Failed opening 'phar://%sdelete_in_phar.phar.zip/b/c.php' for inclusion (include_path='%s') in %sdelete_in_phar.php on line %d
+
+===DONE===
+ \ No newline at end of file
diff --git a/ext/phar/tests/zip/delete_in_phar_b.phpt b/ext/phar/tests/zip/delete_in_phar_b.phpt
new file mode 100644
index 0000000000..7bc3a2bf1a
--- /dev/null
+++ b/ext/phar/tests/zip/delete_in_phar_b.phpt
@@ -0,0 +1,48 @@
+--TEST--
+Phar: delete a file within a zip-based .phar
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.zip';
+$alias = 'phar://' . $fname;
+
+$phar = new Phar($fname);
+$phar['a.php'] = '<?php echo "This is a\n"; ?>';
+$phar['b.php'] = '<?php echo "This is b\n"; ?>';
+$phar['b/c.php'] = '<?php echo "This is b/c\n"; ?>';
+$phar->setStub('<?php __HALT_COMPILER(); ?>');
+$phar->stopBuffering();
+ini_set('phar.readonly', 1);
+
+include $alias . '/a.php';
+include $alias . '/b.php';
+include $alias . '/b/c.php';
+unlink($alias . '/b/c.php');
+?>
+===AFTER===
+<?php
+include $alias . '/a.php';
+include $alias . '/b.php';
+include $alias . '/b/c.php';
+?>
+
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.zip'); ?>
+--EXPECTF--
+This is a
+This is b
+This is b/c
+
+Warning: unlink(): phar error: write operations disabled by INI setting in %sdelete_in_phar_b.php on line %d
+===AFTER===
+This is a
+This is b
+This is b/c
+
+===DONE===
diff --git a/ext/phar/tests/zip/delete_in_phar_confirm.phpt b/ext/phar/tests/zip/delete_in_phar_confirm.phpt
new file mode 100644
index 0000000000..fdd0b42b5c
--- /dev/null
+++ b/ext/phar/tests/zip/delete_in_phar_confirm.phpt
@@ -0,0 +1,53 @@
+--TEST--
+Phar: delete a file within a zip-based .phar (confirm disk file is changed)
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.zip';
+$alias = 'phar://' . $fname;
+
+$phar = new Phar($fname);
+$phar['a.php'] = '<?php echo "This is a\n"; ?>';
+$phar['b.php'] = '<?php echo "This is b\n"; ?>';
+$phar['b/c.php'] = '<?php echo "This is b/c\n"; ?>';
+$phar->setStub('<?php __HALT_COMPILER(); ?>');
+$phar->stopBuffering();
+
+include $alias . '/a.php';
+include $alias . '/b.php';
+include $alias . '/b/c.php';
+
+$md5 = md5_file($fname);
+unlink($alias . '/b/c.php');
+clearstatcache();
+$md52 = md5_file($fname);
+if ($md5 == $md52) echo 'file was not modified';
+?>
+===AFTER===
+<?php
+include 'phar://' . dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.zip/a.php';
+include 'phar://' . dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.zip/b.php';
+include 'phar://' . dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.zip/b/c.php';
+?>
+
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.zip'); ?>
+--EXPECTF--
+This is a
+This is b
+This is b/c
+===AFTER===
+This is a
+This is b
+
+Warning: include(%sdelete_in_phar_confirm.phar.zip/b/c.php): failed to open stream: phar error: "b/c.php" is not a file in phar "%sdelete_in_phar_confirm.phar.zip" in %sdelete_in_phar_confirm.php on line %d
+
+Warning: include(): Failed opening 'phar://%sdelete_in_phar_confirm.phar.zip/b/c.php' for inclusion (include_path='%s') in %sdelete_in_phar_confirm.php on line %d
+
+===DONE===
diff --git a/ext/phar/tests/zip/dir.phpt b/ext/phar/tests/zip/dir.phpt
new file mode 100644
index 0000000000..3cbeacd1c1
--- /dev/null
+++ b/ext/phar/tests/zip/dir.phpt
@@ -0,0 +1,43 @@
+--TEST--
+Phar: mkdir/rmdir test zip-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.zip.php';
+$pname = 'phar://' . $fname;
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.1.phar.php';
+$pname2 = 'phar://' . $fname2;
+$fname3 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.2.phar.php';
+$pname3 = 'phar://' . $fname3;
+$phar = new Phar($fname);
+var_dump($phar->isFileFormat(Phar::ZIP));
+
+$phar->addEmptyDir('test');
+var_dump($phar['test']->isDir());
+var_dump($phar['test/']->isDir());
+copy($fname, $fname2);
+mkdir($pname . '/another/dir/');
+var_dump($phar['another/dir']->isDir());
+rmdir($pname . '/another/dir/');
+copy($fname, $fname3);
+clearstatcache();
+var_dump(file_exists($pname . '/another/dir/'));
+var_dump(file_exists($pname2 . '/test/'));
+var_dump(file_exists($pname3 . '/another/dir/'));
+?>
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.zip.php'); ?>
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.1.phar.php'); ?>
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.2.phar.php'); ?>
+--EXPECT--
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(false)
+bool(true)
+bool(false)
diff --git a/ext/phar/tests/zip/exists_as_phar.phpt b/ext/phar/tests/zip/exists_as_phar.phpt
new file mode 100644
index 0000000000..ccb37e8187
--- /dev/null
+++ b/ext/phar/tests/zip/exists_as_phar.phpt
@@ -0,0 +1,38 @@
+--TEST--
+Phar: phar-based phar named with ".zip" fails
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar';
+$tname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.zip';
+$alias = 'phar://hio';
+
+$phar = new Phar($fname);
+$phar['a.php'] = '<?php echo "This is a\n"; include "'.$alias.'/b.php"; ?>';
+$phar->setAlias('hio');
+$phar->addEmptyDir('test');
+$phar->stopBuffering();
+copy($fname, $tname);
+$phar->setAlias('hio2');
+
+try {
+ $p = new Phar($tname);
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.zip');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar');
+?>
+--EXPECTF--
+phar zip error: phar "%sexists_as_phar.phar.zip" already exists as a regular phar and must be deleted from disk prior to creating as a zip-based phar
+===DONE===
diff --git a/ext/phar/tests/zip/files/badalias1.phar.zip b/ext/phar/tests/zip/files/badalias1.phar.zip
new file mode 100644
index 0000000000..0e3adfc7cf
--- /dev/null
+++ b/ext/phar/tests/zip/files/badalias1.phar.zip
Binary files differ
diff --git a/ext/phar/tests/zip/files/badalias2.phar.zip b/ext/phar/tests/zip/files/badalias2.phar.zip
new file mode 100644
index 0000000000..7b5baaa089
--- /dev/null
+++ b/ext/phar/tests/zip/files/badalias2.phar.zip
Binary files differ
diff --git a/ext/phar/tests/zip/files/badalias3.phar.zip b/ext/phar/tests/zip/files/badalias3.phar.zip
new file mode 100644
index 0000000000..7b5baaa089
--- /dev/null
+++ b/ext/phar/tests/zip/files/badalias3.phar.zip
Binary files differ
diff --git a/ext/phar/tests/zip/files/badalias4.phar.zip b/ext/phar/tests/zip/files/badalias4.phar.zip
new file mode 100644
index 0000000000..49b7be0dae
--- /dev/null
+++ b/ext/phar/tests/zip/files/badalias4.phar.zip
Binary files differ
diff --git a/ext/phar/tests/zip/files/badalias5.phar.zip b/ext/phar/tests/zip/files/badalias5.phar.zip
new file mode 100644
index 0000000000..9f2b0e8282
--- /dev/null
+++ b/ext/phar/tests/zip/files/badalias5.phar.zip
Binary files differ
diff --git a/ext/phar/tests/zip/files/cdir_offset.zip b/ext/phar/tests/zip/files/cdir_offset.zip
new file mode 100644
index 0000000000..9172554f2d
--- /dev/null
+++ b/ext/phar/tests/zip/files/cdir_offset.zip
Binary files differ
diff --git a/ext/phar/tests/zip/files/compress_unsup1.zip b/ext/phar/tests/zip/files/compress_unsup1.zip
new file mode 100644
index 0000000000..bd1f72baf8
--- /dev/null
+++ b/ext/phar/tests/zip/files/compress_unsup1.zip
Binary files differ
diff --git a/ext/phar/tests/zip/files/compress_unsup10.zip b/ext/phar/tests/zip/files/compress_unsup10.zip
new file mode 100644
index 0000000000..2a7f22128c
--- /dev/null
+++ b/ext/phar/tests/zip/files/compress_unsup10.zip
Binary files differ
diff --git a/ext/phar/tests/zip/files/compress_unsup14.zip b/ext/phar/tests/zip/files/compress_unsup14.zip
new file mode 100644
index 0000000000..d4941437d9
--- /dev/null
+++ b/ext/phar/tests/zip/files/compress_unsup14.zip
Binary files differ
diff --git a/ext/phar/tests/zip/files/compress_unsup18.zip b/ext/phar/tests/zip/files/compress_unsup18.zip
new file mode 100644
index 0000000000..7ef221763c
--- /dev/null
+++ b/ext/phar/tests/zip/files/compress_unsup18.zip
Binary files differ
diff --git a/ext/phar/tests/zip/files/compress_unsup19.zip b/ext/phar/tests/zip/files/compress_unsup19.zip
new file mode 100644
index 0000000000..8086d4546f
--- /dev/null
+++ b/ext/phar/tests/zip/files/compress_unsup19.zip
Binary files differ
diff --git a/ext/phar/tests/zip/files/compress_unsup2.zip b/ext/phar/tests/zip/files/compress_unsup2.zip
new file mode 100644
index 0000000000..d827d2d3a2
--- /dev/null
+++ b/ext/phar/tests/zip/files/compress_unsup2.zip
Binary files differ
diff --git a/ext/phar/tests/zip/files/compress_unsup3.zip b/ext/phar/tests/zip/files/compress_unsup3.zip
new file mode 100644
index 0000000000..d4acc60c1f
--- /dev/null
+++ b/ext/phar/tests/zip/files/compress_unsup3.zip
Binary files differ
diff --git a/ext/phar/tests/zip/files/compress_unsup4.zip b/ext/phar/tests/zip/files/compress_unsup4.zip
new file mode 100644
index 0000000000..76a4dc1aef
--- /dev/null
+++ b/ext/phar/tests/zip/files/compress_unsup4.zip
Binary files differ
diff --git a/ext/phar/tests/zip/files/compress_unsup5.zip b/ext/phar/tests/zip/files/compress_unsup5.zip
new file mode 100644
index 0000000000..d42155de53
--- /dev/null
+++ b/ext/phar/tests/zip/files/compress_unsup5.zip
Binary files differ
diff --git a/ext/phar/tests/zip/files/compress_unsup6.zip b/ext/phar/tests/zip/files/compress_unsup6.zip
new file mode 100644
index 0000000000..50846409cd
--- /dev/null
+++ b/ext/phar/tests/zip/files/compress_unsup6.zip
Binary files differ
diff --git a/ext/phar/tests/zip/files/compress_unsup7.zip b/ext/phar/tests/zip/files/compress_unsup7.zip
new file mode 100644
index 0000000000..65c2e23664
--- /dev/null
+++ b/ext/phar/tests/zip/files/compress_unsup7.zip
Binary files differ
diff --git a/ext/phar/tests/zip/files/compress_unsup9.zip b/ext/phar/tests/zip/files/compress_unsup9.zip
new file mode 100644
index 0000000000..df0c767a58
--- /dev/null
+++ b/ext/phar/tests/zip/files/compress_unsup9.zip
Binary files differ
diff --git a/ext/phar/tests/zip/files/compress_unsup97.zip b/ext/phar/tests/zip/files/compress_unsup97.zip
new file mode 100644
index 0000000000..907f365bf7
--- /dev/null
+++ b/ext/phar/tests/zip/files/compress_unsup97.zip
Binary files differ
diff --git a/ext/phar/tests/zip/files/compress_unsup98.zip b/ext/phar/tests/zip/files/compress_unsup98.zip
new file mode 100644
index 0000000000..54f19fb3a0
--- /dev/null
+++ b/ext/phar/tests/zip/files/compress_unsup98.zip
Binary files differ
diff --git a/ext/phar/tests/zip/files/compress_unsupunknown.zip b/ext/phar/tests/zip/files/compress_unsupunknown.zip
new file mode 100644
index 0000000000..170695462a
--- /dev/null
+++ b/ext/phar/tests/zip/files/compress_unsupunknown.zip
Binary files differ
diff --git a/ext/phar/tests/zip/files/corrupt2.php.inc b/ext/phar/tests/zip/files/corrupt2.php.inc
new file mode 100644
index 0000000000..3edf620310
--- /dev/null
+++ b/ext/phar/tests/zip/files/corrupt2.php.inc
@@ -0,0 +1,60 @@
+<?php
+include dirname(__FILE__) . '/corrupt_zipmaker.php.inc';
+$a = new corrupt_zipmaker;
+$a->addFile('hi', null, 'hii');
+$a->addFile('hi2', null, 'hii2', null, null, 'encrypt', 'encrypt');
+$a->writeZip(dirname(__FILE__) . '/encrypted.zip');
+$a = new corrupt_zipmaker;
+$a->addFile('hi', null, 'hii');
+$a->addFile('', null, 'stdin');
+$a->writeZip(dirname(__FILE__) . '/stdin.zip');
+$a = new corrupt_zipmaker;
+$a->addFile('hii', null, 'hii', null, null, 'filename_len', 'filename_len');
+$a->addFile('hi', null, 'hii');
+$a->writeZip(dirname(__FILE__) . '/truncfilename.zip');
+$a = new corrupt_zipmaker;
+$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress');
+$a->writeZip(dirname(__FILE__) . '/compress_unsup1.zip');
+$a = new corrupt_zipmaker;
+$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 2);
+$a->writeZip(dirname(__FILE__) . '/compress_unsup2.zip');
+$a = new corrupt_zipmaker;
+$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 3);
+$a->writeZip(dirname(__FILE__) . '/compress_unsup3.zip');
+$a = new corrupt_zipmaker;
+$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 4);
+$a->writeZip(dirname(__FILE__) . '/compress_unsup4.zip');
+$a = new corrupt_zipmaker;
+$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 5);
+$a->writeZip(dirname(__FILE__) . '/compress_unsup5.zip');
+$a = new corrupt_zipmaker;
+$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 6);
+$a->writeZip(dirname(__FILE__) . '/compress_unsup6.zip');
+$a = new corrupt_zipmaker;
+$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 7);
+$a->writeZip(dirname(__FILE__) . '/compress_unsup7.zip');
+$a = new corrupt_zipmaker;
+$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 9);
+$a->writeZip(dirname(__FILE__) . '/compress_unsup9.zip');
+$a = new corrupt_zipmaker;
+$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 10);
+$a->writeZip(dirname(__FILE__) . '/compress_unsup10.zip');
+$a = new corrupt_zipmaker;
+$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 14);
+$a->writeZip(dirname(__FILE__) . '/compress_unsup14.zip');
+$a = new corrupt_zipmaker;
+$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 18);
+$a->writeZip(dirname(__FILE__) . '/compress_unsup18.zip');
+$a = new corrupt_zipmaker;
+$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 19);
+$a->writeZip(dirname(__FILE__) . '/compress_unsup19.zip');
+$a = new corrupt_zipmaker;
+$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 97);
+$a->writeZip(dirname(__FILE__) . '/compress_unsup97.zip');
+$a = new corrupt_zipmaker;
+$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 98);
+$a->writeZip(dirname(__FILE__) . '/compress_unsup98.zip');
+$a = new corrupt_zipmaker;
+$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 11);
+$a->writeZip(dirname(__FILE__) . '/compress_unsupunknown.zip');
+?>
diff --git a/ext/phar/tests/zip/files/corrupt_count1.php.inc b/ext/phar/tests/zip/files/corrupt_count1.php.inc
new file mode 100644
index 0000000000..314fdef6db
--- /dev/null
+++ b/ext/phar/tests/zip/files/corrupt_count1.php.inc
@@ -0,0 +1,11 @@
+<?php
+include dirname(__FILE__) . '/corrupt_zipmaker.php.inc';
+$a = new corrupt_zipmaker;
+$a->addFile('hi', null, 'hii');
+$a->addFile('hi2', null, 'hii2');
+$a->writeZip(dirname(__FILE__) . '/count1.zip', 'count1');
+$a->writeZip(dirname(__FILE__) . '/count2.zip', 'count2');
+$a->writeZip(dirname(__FILE__) . '/nozipend.zip', 'none');
+$a->writeZip(dirname(__FILE__) . '/filecomment.zip', 'comment');
+$a->writeZip(dirname(__FILE__) . '/cdir_offset.zip', 'cdir_offset');
+?>
diff --git a/ext/phar/tests/zip/files/corrupt_zipmaker.php.inc b/ext/phar/tests/zip/files/corrupt_zipmaker.php.inc
new file mode 100644
index 0000000000..2c1719920d
--- /dev/null
+++ b/ext/phar/tests/zip/files/corrupt_zipmaker.php.inc
@@ -0,0 +1,317 @@
+<?php
+// this corrupt zip maker uses portions of Vincent Lascaux's File_Archive to create
+// specifically corrupted zip archives for unit-testing zip support in the phar extension
+// and was modified by Greg Beaver
+/**
+ * ZIP archive writer
+ *
+ * PHP versions 4 and 5
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330,Boston,MA 02111-1307 USA
+ *
+ * @category File Formats
+ * @package File_Archive
+ * @author Vincent Lascaux <vincentlascaux@php.net>
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id$
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+/**
+ * ZIP archive writer
+ */
+class corrupt_zipmaker
+{
+ /**
+ * @var int Current position in the writer
+ * @access private
+ */
+ var $offset = 0;
+
+ /**
+ * @var string Optionnal comment to add to the zip
+ * @access private
+ */
+ var $comment = "";
+
+ /**
+ * @var string Data written at the end of the ZIP file
+ * @access private
+ */
+ var $central = "";
+
+ /**
+ * @var string Data written at the start of the ZIP file
+ * @access private
+ */
+ var $start = "";
+
+ /**
+ * Set a comment on the ZIP file
+ */
+ function setComment($comment) { $this->comment = $comment; }
+
+ /**
+ * @param int $time Unix timestamp of the date to convert
+ * @return the date formated as a ZIP date
+ */
+ function getMTime($time)
+ {
+ $mtime = ($time !== null ? getdate($time) : getdate());
+ $mtime = preg_replace(
+ "/(..){1}(..){1}(..){1}(..){1}/",
+ "\\x\\4\\x\\3\\x\\2\\x\\1",
+ dechex(($mtime['year']-1980<<25)|
+ ($mtime['mon' ]<<21)|
+ ($mtime['mday' ]<<16)|
+ ($mtime['hours' ]<<11)|
+ ($mtime['minutes']<<5)|
+ ($mtime['seconds']>>1)));
+ eval('$mtime = "'.$mtime.'";');
+ return $mtime;
+ }
+
+ private function getFileEntry($compmethod, $mtime, $crc32, $complength, $uncomplength, $filename, $data, $corrupt, $fakecomp)
+ {
+ switch ($corrupt) {
+ case null :
+ $file = "PK\x03\x04\x14\x00\x00\x00" . pack('v', $compmethod) .
+ $mtime .
+ pack("VVVvv", $crc32, $complength, $uncomplength, strlen($filename), 0x00) .
+ $filename .
+ $data;
+ break;
+ case 'compress' :
+ $file = "PK\x03\x04\x14\x00\x00\x00" . pack('v', $fakecomp) .
+ $mtime .
+ pack("VVVvv", $crc32, $complength, $uncomplength, strlen($filename), 0x00) .
+ $filename .
+ $data;
+ break;
+ case 'encrypt' :
+ $file = "PK\x03\x04\x14\x00\x01\x00" . pack('v', $compmethod) .
+ $mtime .
+ pack("VVVvv", $crc32, $complength, $uncomplength, strlen($filename), 0x00) .
+ $filename .
+ $data;
+ break;
+ case 'crc32' :
+ $file = "PK\x03\x04\x14\x00\x00\x00" . pack('v', $compmethod) .
+ $mtime .
+ pack("VVVvv", $crc32 + 1, $complength, $uncomplength, strlen($filename), 0x00) .
+ $filename .
+ $data;
+ break;
+ case 'complength' :
+ $file = "PK\x03\x04\x14\x00\x00\x00" . pack('v', $compmethod) .
+ $mtime .
+ pack("VVVvv", $crc32, $complength + 1, $uncomplength, strlen($filename), 0x00) .
+ $filename .
+ $data;
+ break;
+ case 'uncomplength' :
+ $file = "PK\x03\x04\x14\x00\x00\x00" . pack('v', $compmethod) .
+ $mtime .
+ pack("VVVvv", $crc32, $complength, $uncomplength - 1, strlen($filename), 0x00) .
+ $filename .
+ $data;
+ break;
+ case 'filename_len' :
+ $file = "PK\x03\x04\x14\x00\x00\x00" . pack('v', $compmethod) .
+ $mtime .
+ pack("VVVvv", $crc32, $complength, $uncomplength, strlen($filename) - 1, 0x00) .
+ $filename .
+ $data;
+ break;
+ case 'extra_len' :
+ $file = "PK\x03\x04\x14\x00\x00\x00" . pack('v', $compmethod) .
+ $mtime .
+ pack("VVVvv", $crc32, $complength, $uncomplength, strlen($filename), 1) .
+ $filename .
+ $data;
+ break;
+ case 'filename' :
+ $file = "PK\x03\x04\x14\x00\x00\x00" . pack('v', $compmethod) .
+ $mtime .
+ pack("VVVvv", $crc32, $complength, $uncomplength, strlen($filename), 0x00) .
+ substr($filename, 1) .
+ $data;
+ break;
+ case 'data' :
+ $file = "PK\x03\x04\x14\x00\x00\x00" . pack('v', $compmethod) .
+ $mtime .
+ pack("VVVvv", $crc32, $complength, $uncomplength, strlen($filename), 0x00) .
+ $filename .
+ substr($data, 1);
+ break;
+ }
+ return $file;
+ }
+
+ private function getCentralEntry($compmethod, $mtime, $crc32, $complength, $uncomplength, $filename, $comment, $corrupt, &$offset, $fakecomp)
+ {
+ settype($comment, 'string');
+ switch ($corrupt) {
+ case null :
+ $central = "PK\x01\x02\x00\x00\x14\x00\x00\x00" . pack('v', $compmethod) .
+ $mtime .
+ pack("VVVvvvvvVV", $crc32, $complength, $uncomplength, strlen($filename), 0x00,strlen($comment),0x00,0x00,
+ 0x0000, $this->offset).
+ $filename . $comment;
+ $offset = strlen($central);
+ break;
+ case 'encrypt' :
+ $central = "PK\x01\x02\x00\x00\x14\x00\x01\x00" . pack('v', $compmethod) .
+ $mtime .
+ pack("VVVvvvvvVV", $crc32, $complength, $uncomplength, strlen($filename), 0x00,strlen($comment),0x00,0x00,
+ 0x0000, $this->offset).
+ $filename . $comment;
+ $offset = strlen($central);
+ break;
+ case 'compress' :
+ $central = "PK\x01\x02\x00\x00\x14\x00\x00\x00" . pack('v', $fakecomp) .
+ $mtime .
+ pack("VVVvvvvvVV", $crc32, $complength, $uncomplength, strlen($filename), 0x00,strlen($comment),0x00,0x00,
+ 0x0000, $this->offset).
+ $filename . $comment;
+ $offset = strlen($central);
+ break;
+ case 'crc32' :
+ $central = "PK\x01\x02\x00\x00\x14\x00\x00\x00" . pack('v', $compmethod) .
+ $mtime .
+ pack("VVVvvvvvVV", $crc32 + 1, $complength, $uncomplength, strlen($filename), 0x00,strlen($comment),0x00,0x00,
+ 0x0000, $this->offset).
+ $filename . $comment;
+ $offset = strlen($central);
+ break;
+ case 'complength' :
+ $central = "PK\x01\x02\x00\x00\x14\x00\x00\x00" . pack('v', $compmethod) .
+ $mtime .
+ pack("VVVvvvvvVV", $crc32, $complength - 1, $uncomplength, strlen($filename), 0x00,strlen($comment),0x00,0x00,
+ 0x0000, $this->offset).
+ $filename . $comment;
+ $offset = strlen($central);
+ break;
+ case 'uncomplength' :
+ $central = "PK\x01\x02\x00\x00\x14\x00\x00\x00" . pack('v', $compmethod) .
+ $mtime .
+ pack("VVVvvvvvVV", $crc32, $complength, $uncomplength - 1, strlen($filename), 0x00,strlen($comment),0x00,0x00,
+ 0x0000, $this->offset).
+ $filename . $comment;
+ $offset = strlen($central);
+ break;
+ case 'filename_len' :
+ $central = "PK\x01\x02\x00\x00\x14\x00\x00\x00" . pack('v', $compmethod) .
+ $mtime .
+ pack("VVVvvvvvVV", $crc32, $complength, $uncomplength, strlen($filename) - 1, 0x00,strlen($comment),0x00,0x00,
+ 0x0000, $this->offset).
+ $filename . $comment;
+ $offset = strlen($central);
+ break;
+ case 'offset' :
+ $central = "PK\x01\x02\x00\x00\x14\x00\x00\x00" . pack('v', $compmethod) .
+ $mtime .
+ pack("VVVvvvvvVV", $crc32, $complength, $uncomplength, strlen($filename), 0x00,strlen($comment),0x00,0x00,
+ 0x0000, $this->offset - 1).
+ $filename . $comment;
+ $offset = strlen($central) - 1;
+ break;
+ case 'comment' :
+ $central = "PK\x01\x02\x00\x00\x14\x00\x00\x00" . pack('v', $compmethod) .
+ $mtime .
+ pack("VVVvvvvvVV", $crc32, $complength, $uncomplength, strlen($filename), 0x00,strlen($comment) + 1,0x00,0x00,
+ 0x0000, $this->offset).
+ $filename . $comment;
+ $offset = strlen($central);
+ break;
+ }
+ return $central;
+ }
+
+ function addFile($filename, $mtime, $data, $comment = null, $compress = null, $filecorrupt = null, $centralcorrupt = null, $fakecomp = 1)
+ {
+ $mtime = $this->getMTime($mtime ? $mtime : null);
+
+ $uncomplength = strlen($data);
+ $crc32 = crc32($data) & 0xFFFFFFFF;
+ $compmethod = 0;
+ switch ($compress) {
+ case 'gz' :
+ $data = gzcompress($data);
+ $compmethod = 8;
+ break;
+ case 'bz2' :
+ $data = bzcompress($data);
+ $compmethod = 12;
+ break;
+ }
+ $complength = strlen($data);
+
+ $this->start .= ($file = $this->getFileEntry($compmethod, $mtime, $crc32, $complength, $uncomplength, $filename, $data, $filecorrupt, $fakecomp));
+
+ $offset = 0;
+ $this->central .= $this->getCentralEntry($compmethod, $mtime, $crc32, $complength, $uncomplength, $filename, $comment, $centralcorrupt, $offset, $fakecomp);
+
+ $this->offset += $offset;
+ $this->count++;
+ }
+
+ function writeZip($zipfile, $corrupt = null)
+ {
+ $write = $this->start . $this->central;
+ switch ($corrupt) {
+ case null :
+ $write .= "PK\x05\x06\x00\x00\x00\x00" .
+ pack("vvVVv", $this->count, $this->count,
+ $this->offset, strlen($this->start),
+ strlen($this->comment)) . $this->comment;
+ break;
+ case 'count1' :
+ $write .= "PK\x05\x06\x00\x00\x00\x00" .
+ pack("vvVVv", $this->count + 1, $this->count,
+ $this->offset, strlen($this->start),
+ strlen($this->comment)) . $this->comment;
+ break;
+ case 'count2' :
+ $write .= "PK\x05\x06\x00\x00\x00\x00" .
+ pack("vvVVv", $this->count, $this->count + 1,
+ $this->offset, strlen($this->start),
+ strlen($this->comment)) . $this->comment;
+ break;
+ case 'cdir_offset' :
+ $write .= "PK\x05\x06\x00\x00\x00\x00" .
+ pack("vvVVv", $this->count, $this->count,
+ $this->offset, strlen($this->start) - 3,
+ strlen($this->comment)) . $this->comment;
+ break;
+ case 'cdir_len' :
+ $write .= "PK\x05\x06\x00\x00\x00\x00" .
+ pack("vvVVv", $this->count, $this->count,
+ $this->offset - 5, strlen($this->start),
+ strlen($this->comment)) . $this->comment;
+ break;
+ case 'comment' :
+ $write .= "PK\x05\x06\x00\x00\x00\x00" .
+ pack("vvVVv", $this->count, $this->count,
+ strlen($this->start), $this->offset + 1,
+ strlen($this->comment) + 1) . $this->comment;
+ break;
+ case 'none' :
+ }
+ file_put_contents($zipfile, $write);
+ }
+}
+?> \ No newline at end of file
diff --git a/ext/phar/tests/zip/files/count1.zip b/ext/phar/tests/zip/files/count1.zip
new file mode 100644
index 0000000000..73b556103a
--- /dev/null
+++ b/ext/phar/tests/zip/files/count1.zip
Binary files differ
diff --git a/ext/phar/tests/zip/files/count2.zip b/ext/phar/tests/zip/files/count2.zip
new file mode 100644
index 0000000000..6aa2619539
--- /dev/null
+++ b/ext/phar/tests/zip/files/count2.zip
Binary files differ
diff --git a/ext/phar/tests/zip/files/encrypted.zip b/ext/phar/tests/zip/files/encrypted.zip
new file mode 100644
index 0000000000..dee73cad37
--- /dev/null
+++ b/ext/phar/tests/zip/files/encrypted.zip
Binary files differ
diff --git a/ext/phar/tests/zip/files/filecomment.zip b/ext/phar/tests/zip/files/filecomment.zip
new file mode 100644
index 0000000000..414b121fdc
--- /dev/null
+++ b/ext/phar/tests/zip/files/filecomment.zip
Binary files differ
diff --git a/ext/phar/tests/zip/files/frontcontroller.phar.inc b/ext/phar/tests/zip/files/frontcontroller.phar.inc
new file mode 100644
index 0000000000..241dceb57b
--- /dev/null
+++ b/ext/phar/tests/zip/files/frontcontroller.phar.inc
@@ -0,0 +1,13 @@
+<?php
+@unlink(dirname(__FILE__) . '/frontcontroller.phar.zip');
+$a = new Phar(dirname(__FILE__) . '/frontcontroller.phar.zip');
+$a['a.php'] = 'hio';
+$a['a.jpg'] = 'hio';
+$a['a.phps'] = '<?php function hio(){}';
+$a['index.php'] = 'here is my index';
+$a->setStub('<?php
+Phar::webPhar();
+echo "oops did not run\n";
+var_dump($_ENV, $_SERVER);
+__HALT_COMPILER();');
+?>
diff --git a/ext/phar/tests/zip/files/frontcontroller.phar.zip b/ext/phar/tests/zip/files/frontcontroller.phar.zip
new file mode 100644
index 0000000000..4ee905dd3a
--- /dev/null
+++ b/ext/phar/tests/zip/files/frontcontroller.phar.zip
Binary files differ
diff --git a/ext/phar/tests/zip/files/frontcontroller10.phar.inc b/ext/phar/tests/zip/files/frontcontroller10.phar.inc
new file mode 100644
index 0000000000..c973cc15d9
--- /dev/null
+++ b/ext/phar/tests/zip/files/frontcontroller10.phar.inc
@@ -0,0 +1,20 @@
+<?php
+@unlink(dirname(__FILE__) . '/frontcontroller10.phar.zip');
+$a = new Phar(dirname(__FILE__) . '/frontcontroller10.phar.zip');
+$a['index.php'] = '<?php
+var_dump($_SERVER["PHP_SELF"]);
+var_dump($_SERVER["SCRIPT_NAME"]);
+var_dump($_SERVER["SCRIPT_FILENAME"]);
+var_dump($_SERVER["REQUEST_URI"]);
+var_dump($_SERVER["PHAR_PHP_SELF"]);
+var_dump($_SERVER["PHAR_SCRIPT_NAME"]);
+var_dump($_SERVER["PHAR_SCRIPT_FILENAME"]);
+var_dump($_SERVER["PHAR_REQUEST_URI"]);
+';
+$a->setStub('<?php
+Phar::mungServer(array("PHP_SELF", "SCRIPT_NAME", "SCRIPT_FILENAME", "REQUEST_URI", "OOPSIE"));
+Phar::webPhar();
+echo "oops did not run\n";
+var_dump($_ENV, $_SERVER);
+__HALT_COMPILER();');
+?>
diff --git a/ext/phar/tests/zip/files/frontcontroller10.phar.zip b/ext/phar/tests/zip/files/frontcontroller10.phar.zip
new file mode 100644
index 0000000000..c37cb381fb
--- /dev/null
+++ b/ext/phar/tests/zip/files/frontcontroller10.phar.zip
Binary files differ
diff --git a/ext/phar/tests/zip/files/frontcontroller11.phar.inc b/ext/phar/tests/zip/files/frontcontroller11.phar.inc
new file mode 100644
index 0000000000..c24a6f14e4
--- /dev/null
+++ b/ext/phar/tests/zip/files/frontcontroller11.phar.inc
@@ -0,0 +1,20 @@
+<?php
+@unlink(dirname(__FILE__) . '/frontcontroller11.phar.zip');
+$a = new Phar(dirname(__FILE__) . '/frontcontroller11.phar.zip');
+$a['index.php'] = '<?php
+var_dump($_SERVER["PHP_SELF"]);
+var_dump($_SERVER["SCRIPT_NAME"]);
+var_dump($_SERVER["SCRIPT_FILENAME"]);
+var_dump($_SERVER["REQUEST_URI"]);
+var_dump($_SERVER["PHAR_PHP_SELF"]);
+var_dump($_SERVER["PHAR_SCRIPT_NAME"]);
+var_dump($_SERVER["PHAR_SCRIPT_FILENAME"]);
+var_dump($_SERVER["PHAR_REQUEST_URI"]);
+';
+$a->setStub('<?php
+Phar::mungServer(array(array(), "SCRIPT_NAME", "SCRIPT_FILENAME", "REQUEST_URI"));
+Phar::webPhar();
+echo "oops did not run\n";
+var_dump($_ENV, $_SERVER);
+__HALT_COMPILER();');
+?>
diff --git a/ext/phar/tests/zip/files/frontcontroller11.phar.zip b/ext/phar/tests/zip/files/frontcontroller11.phar.zip
new file mode 100644
index 0000000000..48e5fc678a
--- /dev/null
+++ b/ext/phar/tests/zip/files/frontcontroller11.phar.zip
Binary files differ
diff --git a/ext/phar/tests/zip/files/frontcontroller12.phar.inc b/ext/phar/tests/zip/files/frontcontroller12.phar.inc
new file mode 100644
index 0000000000..77c4a1dd0e
--- /dev/null
+++ b/ext/phar/tests/zip/files/frontcontroller12.phar.inc
@@ -0,0 +1,20 @@
+<?php
+@unlink(dirname(__FILE__) . '/frontcontroller12.phar.zip');
+$a = new Phar(dirname(__FILE__) . '/frontcontroller12.phar.zip');
+$a['index.php'] = '<?php
+var_dump($_SERVER["PHP_SELF"]);
+var_dump($_SERVER["SCRIPT_NAME"]);
+var_dump($_SERVER["SCRIPT_FILENAME"]);
+var_dump($_SERVER["REQUEST_URI"]);
+var_dump($_SERVER["PHAR_PHP_SELF"]);
+var_dump($_SERVER["PHAR_SCRIPT_NAME"]);
+var_dump($_SERVER["PHAR_SCRIPT_FILENAME"]);
+var_dump($_SERVER["PHAR_REQUEST_URI"]);
+';
+$a->setStub('<?php
+Phar::mungServer(array("PHP_SELF", "SCRIPT_NAME", "SCRIPT_FILENAME", "REQUEST_URI"));
+Phar::webPhar();
+echo "oops did not run\n";
+var_dump($_ENV, $_SERVER);
+__HALT_COMPILER();');
+?>
diff --git a/ext/phar/tests/zip/files/frontcontroller12.phar.zip b/ext/phar/tests/zip/files/frontcontroller12.phar.zip
new file mode 100644
index 0000000000..c086c4d4a4
--- /dev/null
+++ b/ext/phar/tests/zip/files/frontcontroller12.phar.zip
Binary files differ
diff --git a/ext/phar/tests/zip/files/frontcontroller2.phar.inc b/ext/phar/tests/zip/files/frontcontroller2.phar.inc
new file mode 100644
index 0000000000..6cfa052a83
--- /dev/null
+++ b/ext/phar/tests/zip/files/frontcontroller2.phar.inc
@@ -0,0 +1,12 @@
+<?php
+@unlink(dirname(__FILE__) . '/frontcontroller2.phar.zip');
+$a = new Phar(dirname(__FILE__) . '/frontcontroller2.phar.zip');
+$a['a.php'] = 'hio';
+$a['a.jpg'] = 'hio';
+$a['a.phps'] = '<?php function hio(){}';
+$a->setStub('<?php
+Phar::webPhar("whatever", "a.php");
+echo "oops did not run\n";
+var_dump($_ENV, $_SERVER);
+__HALT_COMPILER();');
+?>
diff --git a/ext/phar/tests/zip/files/frontcontroller2.phar.zip b/ext/phar/tests/zip/files/frontcontroller2.phar.zip
new file mode 100644
index 0000000000..7ef43dc000
--- /dev/null
+++ b/ext/phar/tests/zip/files/frontcontroller2.phar.zip
Binary files differ
diff --git a/ext/phar/tests/zip/files/frontcontroller3.phar.inc b/ext/phar/tests/zip/files/frontcontroller3.phar.inc
new file mode 100644
index 0000000000..ab28f7b3d0
--- /dev/null
+++ b/ext/phar/tests/zip/files/frontcontroller3.phar.inc
@@ -0,0 +1,18 @@
+<?php
+@unlink(dirname(__FILE__) . '/frontcontroller3.phar.zip');
+$a = new Phar(dirname(__FILE__) . '/frontcontroller3.phar.zip');
+$a['a.php'] = 'hio';
+$a['a.jpg'] = 'hio';
+$a['a.phps'] = '<?php function hio(){}';
+$a->setStub('<?php
+function s($a)
+{
+ static $b = array("/hi" => "a.phps");
+ if (isset($b[$a])) return $b[$a];
+ return $a;
+}
+Phar::webPhar("whatever", "/index.php", null, array(), "s");
+echo "oops did not run\n";
+var_dump($_ENV, $_SERVER);
+__HALT_COMPILER();');
+?>
diff --git a/ext/phar/tests/zip/files/frontcontroller3.phar.zip b/ext/phar/tests/zip/files/frontcontroller3.phar.zip
new file mode 100644
index 0000000000..40c1d4994b
--- /dev/null
+++ b/ext/phar/tests/zip/files/frontcontroller3.phar.zip
Binary files differ
diff --git a/ext/phar/tests/zip/files/frontcontroller4.phar.inc b/ext/phar/tests/zip/files/frontcontroller4.phar.inc
new file mode 100644
index 0000000000..d78399142e
--- /dev/null
+++ b/ext/phar/tests/zip/files/frontcontroller4.phar.inc
@@ -0,0 +1,18 @@
+<?php
+@unlink(dirname(__FILE__) . '/frontcontroller4.phar.zip');
+$a = new Phar(dirname(__FILE__) . '/frontcontroller4.phar.zip');
+$a['a.php'] = 'hio';
+$a['a.jpg'] = 'hio';
+$a['a.phps'] = '<?php function hio(){}';
+$a->setStub('<?php
+function s($a)
+{
+ static $b = array("/hi" => false);
+ if (isset($b[$a])) return $b[$a];
+ return $a;
+}
+Phar::webPhar("whatever", "index.php", null, array(), "s");
+echo "oops did not run\n";
+var_dump($_ENV, $_SERVER);
+__HALT_COMPILER();');
+?>
diff --git a/ext/phar/tests/zip/files/frontcontroller4.phar.zip b/ext/phar/tests/zip/files/frontcontroller4.phar.zip
new file mode 100644
index 0000000000..4dc83408b0
--- /dev/null
+++ b/ext/phar/tests/zip/files/frontcontroller4.phar.zip
Binary files differ
diff --git a/ext/phar/tests/zip/files/frontcontroller5.phar.inc b/ext/phar/tests/zip/files/frontcontroller5.phar.inc
new file mode 100644
index 0000000000..931fa975e1
--- /dev/null
+++ b/ext/phar/tests/zip/files/frontcontroller5.phar.inc
@@ -0,0 +1,12 @@
+<?php
+@unlink(dirname(__FILE__) . '/frontcontroller5.phar.zip');
+$a = new Phar(dirname(__FILE__) . '/frontcontroller5.phar.zip');
+$a['a.php'] = 'hio';
+$a['a.jpg'] = 'hio';
+$a['a.phps'] = '<?php function hio(){}';
+$a->setStub('<?php
+Phar::webPhar("whatever", "index.php", null, array(0 => "oops"));
+echo "oops did not run\n";
+var_dump($_ENV, $_SERVER);
+__HALT_COMPILER();');
+?>
diff --git a/ext/phar/tests/zip/files/frontcontroller5.phar.zip b/ext/phar/tests/zip/files/frontcontroller5.phar.zip
new file mode 100644
index 0000000000..0ab0472101
--- /dev/null
+++ b/ext/phar/tests/zip/files/frontcontroller5.phar.zip
Binary files differ
diff --git a/ext/phar/tests/zip/files/frontcontroller6.phar.inc b/ext/phar/tests/zip/files/frontcontroller6.phar.inc
new file mode 100644
index 0000000000..3b551f268d
--- /dev/null
+++ b/ext/phar/tests/zip/files/frontcontroller6.phar.inc
@@ -0,0 +1,12 @@
+<?php
+@unlink(dirname(__FILE__) . '/frontcontroller6.phar.zip');
+$a = new Phar(dirname(__FILE__) . '/frontcontroller6.phar.zip');
+$a['a.php'] = 'hio';
+$a['a.jpg'] = 'hio';
+$a['a.phps'] = '<?php function hio(){}';
+$a->setStub('<?php
+Phar::webPhar("whatever", "index.php", null, array("blah" => 100));
+echo "oops did not run\n";
+var_dump($_ENV, $_SERVER);
+__HALT_COMPILER();');
+?>
diff --git a/ext/phar/tests/zip/files/frontcontroller6.phar.zip b/ext/phar/tests/zip/files/frontcontroller6.phar.zip
new file mode 100644
index 0000000000..bf98255fe9
--- /dev/null
+++ b/ext/phar/tests/zip/files/frontcontroller6.phar.zip
Binary files differ
diff --git a/ext/phar/tests/zip/files/frontcontroller7.phar.inc b/ext/phar/tests/zip/files/frontcontroller7.phar.inc
new file mode 100644
index 0000000000..42c10bc739
--- /dev/null
+++ b/ext/phar/tests/zip/files/frontcontroller7.phar.inc
@@ -0,0 +1,12 @@
+<?php
+@unlink(dirname(__FILE__) . '/frontcontroller7.phar.zip');
+$a = new Phar(dirname(__FILE__) . '/frontcontroller7.phar.zip');
+$a['a.php'] = 'hio';
+$a['a.jpg'] = 'hio';
+$a['a.phps'] = '<?php function hio(){}';
+$a->setStub('<?php
+Phar::webPhar("whatever", "index.php", null, array("blah" => null));
+echo "oops did not run\n";
+var_dump($_ENV, $_SERVER);
+__HALT_COMPILER();');
+?>
diff --git a/ext/phar/tests/zip/files/frontcontroller7.phar.zip b/ext/phar/tests/zip/files/frontcontroller7.phar.zip
new file mode 100644
index 0000000000..02fc3e27b6
--- /dev/null
+++ b/ext/phar/tests/zip/files/frontcontroller7.phar.zip
Binary files differ
diff --git a/ext/phar/tests/zip/files/frontcontroller8.phar.inc b/ext/phar/tests/zip/files/frontcontroller8.phar.inc
new file mode 100644
index 0000000000..e04ac414e9
--- /dev/null
+++ b/ext/phar/tests/zip/files/frontcontroller8.phar.inc
@@ -0,0 +1,13 @@
+<?php
+@unlink(dirname(__FILE__) . '/frontcontroller8.phar.zip');
+$a = new Phar(dirname(__FILE__) . '/frontcontroller8.phar.zip');
+$a['a.phps'] = 'hio1';
+$a['a.jpg'] = 'hio2';
+$a['a.php'] = '<?php function hio(){}';
+$a['fronk.gronk'] = 'hio3';
+$a->setStub('<?php
+Phar::webPhar("whatever", "index.php", null, array("jpg" => "foo/bar", "phps" => Phar::PHP, "php" => Phar::PHPS));
+echo "oops did not run\n";
+var_dump($_ENV, $_SERVER);
+__HALT_COMPILER();');
+?>
diff --git a/ext/phar/tests/zip/files/frontcontroller8.phar.zip b/ext/phar/tests/zip/files/frontcontroller8.phar.zip
new file mode 100644
index 0000000000..41952ce745
--- /dev/null
+++ b/ext/phar/tests/zip/files/frontcontroller8.phar.zip
Binary files differ
diff --git a/ext/phar/tests/zip/files/frontcontroller9.phar.inc b/ext/phar/tests/zip/files/frontcontroller9.phar.inc
new file mode 100644
index 0000000000..50440451f7
--- /dev/null
+++ b/ext/phar/tests/zip/files/frontcontroller9.phar.inc
@@ -0,0 +1,14 @@
+<?php
+@unlink(dirname(__FILE__) . '/frontcontroller9.phar.zip');
+$a = new Phar(dirname(__FILE__) . '/frontcontroller9.phar.zip');
+$a['a.phps'] = 'hio1';
+$a['a.jpg'] = 'hio2';
+$a['a.php'] = '<?php function hio(){}';
+$a['fronk.gronk'] = 'hio3';
+$a->setStub('<?php
+Phar::mungServer(array());
+Phar::webPhar("whatever", "index.php", null, array("jpg" => "foo/bar", "phps" => Phar::PHP, "php" => Phar::PHPS));
+echo "oops did not run\n";
+var_dump($_ENV, $_SERVER);
+__HALT_COMPILER();');
+?>
diff --git a/ext/phar/tests/zip/files/frontcontroller9.phar.zip b/ext/phar/tests/zip/files/frontcontroller9.phar.zip
new file mode 100644
index 0000000000..d3f4ff8404
--- /dev/null
+++ b/ext/phar/tests/zip/files/frontcontroller9.phar.zip
Binary files differ
diff --git a/ext/phar/tests/zip/files/make_invalid_tar.php.inc b/ext/phar/tests/zip/files/make_invalid_tar.php.inc
new file mode 100644
index 0000000000..cec8ef7793
--- /dev/null
+++ b/ext/phar/tests/zip/files/make_invalid_tar.php.inc
@@ -0,0 +1,12 @@
+<?php
+include dirname(__FILE__) . '/tarmaker.php.inc';
+class corrupter extends tarmaker {
+function close()
+{
+ parent::close();
+ $fp = fopen($this->path, 'r+b');
+ fseek($fp, 20);
+ fwrite($fp, 'oopsie');
+ fclose($fp);
+}
+} \ No newline at end of file
diff --git a/ext/phar/tests/zip/files/metadata.phar.inc b/ext/phar/tests/zip/files/metadata.phar.inc
new file mode 100644
index 0000000000..932fc961e3
--- /dev/null
+++ b/ext/phar/tests/zip/files/metadata.phar.inc
@@ -0,0 +1,11 @@
+<?php
+@unlink(dirname(__FILE__) . '/metadata.phar.zip');
+$a = new Phar(dirname(__FILE__) . '/metadata.phar.zip');
+$a['a'] = 'a';
+$a['b'] = 'b';
+$a['b']->setMetadata('hi there');
+$a['c'] = 'c';
+$a['c']->setMetadata(array('hi', 'there'));
+$a['d'] = 'd';
+$a['d']->setMetadata(array('hi'=>'there','foo'=>'bar'));
+?>
diff --git a/ext/phar/tests/zip/files/metadata.phar.zip b/ext/phar/tests/zip/files/metadata.phar.zip
new file mode 100644
index 0000000000..3c5cf0065f
--- /dev/null
+++ b/ext/phar/tests/zip/files/metadata.phar.zip
Binary files differ
diff --git a/ext/phar/tests/zip/files/nozipend.zip b/ext/phar/tests/zip/files/nozipend.zip
new file mode 100644
index 0000000000..f97607221c
--- /dev/null
+++ b/ext/phar/tests/zip/files/nozipend.zip
Binary files differ
diff --git a/ext/phar/tests/zip/files/odt.odt b/ext/phar/tests/zip/files/odt.odt
new file mode 100644
index 0000000000..527e09fefc
--- /dev/null
+++ b/ext/phar/tests/zip/files/odt.odt
Binary files differ
diff --git a/ext/phar/tests/zip/files/stdin.zip b/ext/phar/tests/zip/files/stdin.zip
new file mode 100644
index 0000000000..4376eb67fa
--- /dev/null
+++ b/ext/phar/tests/zip/files/stdin.zip
Binary files differ
diff --git a/ext/phar/tests/zip/files/truncfilename.zip b/ext/phar/tests/zip/files/truncfilename.zip
new file mode 100644
index 0000000000..d8a526a4bb
--- /dev/null
+++ b/ext/phar/tests/zip/files/truncfilename.zip
Binary files differ
diff --git a/ext/phar/tests/zip/files/zip.zip b/ext/phar/tests/zip/files/zip.zip
new file mode 100644
index 0000000000..5ee9cae6ac
--- /dev/null
+++ b/ext/phar/tests/zip/files/zip.zip
Binary files differ
diff --git a/ext/phar/tests/zip/files/zipmaker.php.inc b/ext/phar/tests/zip/files/zipmaker.php.inc
new file mode 100644
index 0000000000..aceab0d26b
--- /dev/null
+++ b/ext/phar/tests/zip/files/zipmaker.php.inc
@@ -0,0 +1,70 @@
+<?php
+// stolen from PEAR2_Pyrus_Developer_Creator_Zip by Greg Beaver, the original author, for use in unit tests
+class zipmaker
+{
+ /**
+ * Path to archive file
+ *
+ * @var string
+ */
+ protected $archive;
+ /**
+ * @var ZIPArchive
+ */
+ protected $zip;
+ protected $path;
+ function __construct($path)
+ {
+ if (!class_exists('ZIPArchive')) {
+ throw new Exception(
+ 'Zip extension is not available');
+ }
+ $this->path = $path;
+ }
+
+ /**
+ * save a file inside this package
+ * @param string relative path within the package
+ * @param string|resource file contents or open file handle
+ */
+ function addFile($path, $fileOrStream)
+ {
+ if (is_resource($fileOrStream)) {
+ $this->zip->addFromString($path, stream_get_contents($fileOrStream));
+ } else {
+ $this->zip->addFromString($path, $fileOrStream);
+ }
+ }
+
+ /**
+ * Initialize the package creator
+ */
+ function init()
+ {
+ $this->zip = new ZipArchive;
+ if (true !== $this->zip->open($this->path, ZIPARCHIVE::CREATE)) {
+ throw new Exception(
+ 'Cannot open ZIP archive ' . $this->path
+ );
+ }
+ }
+
+ /**
+ * Create an internal directory, creating parent directories as needed
+ *
+ * This is a no-op for the tar creator
+ * @param string $dir
+ */
+ function mkdir($dir)
+ {
+ $this->zip->addEmptyDir($dir);
+ }
+
+ /**
+ * Finish saving the package
+ */
+ function close()
+ {
+ $this->zip->close();
+ }
+} \ No newline at end of file
diff --git a/ext/phar/tests/zip/frontcontroller1.phar.phpt b/ext/phar/tests/zip/frontcontroller1.phar.phpt
new file mode 100644
index 0000000000..0a6847885d
--- /dev/null
+++ b/ext/phar/tests/zip/frontcontroller1.phar.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Phar front controller other zip-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller1.phar.php
+REQUEST_URI=/frontcontroller1.phar.php/a.jpg
+PATH_INFO=/a.jpg
+--FILE_EXTERNAL--
+files/frontcontroller.phar.zip
+--EXPECTHEADERS--
+Content-type: image/jpeg
+Content-length: 3
+--EXPECT--
+hio
diff --git a/ext/phar/tests/zip/frontcontroller10.phar.phpt b/ext/phar/tests/zip/frontcontroller10.phar.phpt
new file mode 100644
index 0000000000..ffe23bc08e
--- /dev/null
+++ b/ext/phar/tests/zip/frontcontroller10.phar.phpt
@@ -0,0 +1,22 @@
+--TEST--
+Phar front controller rewrite array invalid zip-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller10.phar.php
+REQUEST_URI=/frontcontroller10.phar.php/hi
+PATH_INFO=/hi
+--FILE_EXTERNAL--
+files/frontcontroller4.phar.zip
+--EXPECTHEADERS--
+Content-type: text/html
+Status: 403 Access Denied
+--EXPECT--
+<html>
+ <head>
+ <title>Access Denied</title>
+ </head>
+ <body>
+ <h1>403 - File /hi Access Denied</h1>
+ </body>
+</html> \ No newline at end of file
diff --git a/ext/phar/tests/zip/frontcontroller11.phar.phpt b/ext/phar/tests/zip/frontcontroller11.phar.phpt
new file mode 100644
index 0000000000..f1fd26bb75
--- /dev/null
+++ b/ext/phar/tests/zip/frontcontroller11.phar.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Phar front controller mime type extension is not a string zip-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller11.phar.php
+REQUEST_URI=/frontcontroller11.phar.php/a.php
+PATH_INFO=/a.php
+--FILE_EXTERNAL--
+files/frontcontroller5.phar.zip
+--EXPECTHEADERS--
+Content-type: text/html
+--EXPECTF--
+Fatal error: Uncaught exception 'PharException' with message 'Key of MIME type overrides array must be a file extension, was "0"' in %sfrontcontroller11.phar.php:2
+Stack trace:
+#0 %sfrontcontroller11.phar.php(2): Phar::webPhar('whatever', 'index.php', '', Array)
+#1 {main}
+ thrown in %sfrontcontroller11.phar.php on line 2 \ No newline at end of file
diff --git a/ext/phar/tests/zip/frontcontroller12.phar.phpt b/ext/phar/tests/zip/frontcontroller12.phar.phpt
new file mode 100644
index 0000000000..dc5bcdce78
--- /dev/null
+++ b/ext/phar/tests/zip/frontcontroller12.phar.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Phar front controller mime type unknown int zip-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller12.phar.php
+REQUEST_URI=/frontcontroller12.phar.php/a.php
+PATH_INFO=/a.php
+--FILE_EXTERNAL--
+files/frontcontroller6.phar.zip
+--EXPECTHEADERS--
+Content-type: text/html
+--EXPECTF--
+Fatal error: Uncaught exception 'PharException' with message 'Unknown mime type specifier used, only Phar::PHP, Phar::PHPS and a mime type string are allowed' in %sfrontcontroller12.phar.php:2
+Stack trace:
+#0 %sfrontcontroller12.phar.php(2): Phar::webPhar('whatever', 'index.php', '', Array)
+#1 {main}
+ thrown in %sfrontcontroller12.phar.php on line 2 \ No newline at end of file
diff --git a/ext/phar/tests/zip/frontcontroller13.phar.phpt b/ext/phar/tests/zip/frontcontroller13.phar.phpt
new file mode 100644
index 0000000000..592d662536
--- /dev/null
+++ b/ext/phar/tests/zip/frontcontroller13.phar.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Phar front controller mime type not string/int zip-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller13.phar.php
+REQUEST_URI=/frontcontroller13.phar.php/a.php
+PATH_INFO=/a.php
+--FILE_EXTERNAL--
+files/frontcontroller7.phar.zip
+--EXPECTHEADERS--
+Content-type: text/html
+--EXPECTF--
+Fatal error: Uncaught exception 'PharException' with message 'Unknown mime type specifier used (not a string or int), only Phar::PHP, Phar::PHPS and a mime type string are allowed' in %sfrontcontroller13.phar.php:2
+Stack trace:
+#0 %sfrontcontroller13.phar.php(2): Phar::webPhar('whatever', 'index.php', '', Array)
+#1 {main}
+ thrown in %sfrontcontroller13.phar.php on line 2 \ No newline at end of file
diff --git a/ext/phar/tests/zip/frontcontroller14.phar.phpt b/ext/phar/tests/zip/frontcontroller14.phar.phpt
new file mode 100644
index 0000000000..1caa85bc07
--- /dev/null
+++ b/ext/phar/tests/zip/frontcontroller14.phar.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Phar front controller mime type override, other zip-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller14.phar.php
+REQUEST_URI=/frontcontroller14.phar.php/a.jpg
+PATH_INFO=/a.jpg
+--FILE_EXTERNAL--
+files/frontcontroller8.phar.zip
+--EXPECTHEADERS--
+Content-type: foo/bar
+Content-length: 4
+--EXPECT--
+hio2
diff --git a/ext/phar/tests/zip/frontcontroller15.phar.phpt b/ext/phar/tests/zip/frontcontroller15.phar.phpt
new file mode 100644
index 0000000000..89adc0a106
--- /dev/null
+++ b/ext/phar/tests/zip/frontcontroller15.phar.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Phar front controller mime type override, Phar::PHPS zip-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller15.phar.php
+REQUEST_URI=/frontcontroller15.phar.php/a.php
+PATH_INFO=/a.php
+--FILE_EXTERNAL--
+files/frontcontroller8.phar.zip
+--EXPECTHEADERS--
+Content-type: text/html
+--EXPECT--
+<code><span style="color: #000000">
+<span style="color: #0000BB">&lt;?php&nbsp;</span><span style="color: #007700">function&nbsp;</span><span style="color: #0000BB">hio</span><span style="color: #007700">(){}</span>
+</span>
+</code>
+
diff --git a/ext/phar/tests/zip/frontcontroller16.phar.phpt b/ext/phar/tests/zip/frontcontroller16.phar.phpt
new file mode 100644
index 0000000000..e27faf3931
--- /dev/null
+++ b/ext/phar/tests/zip/frontcontroller16.phar.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Phar front controller mime type override, Phar::PHP zip-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller16.phar.php
+REQUEST_URI=/frontcontroller16.phar.php/a.phps
+PATH_INFO=/a.phps
+--FILE_EXTERNAL--
+files/frontcontroller8.phar.zip
+--EXPECTHEADERS--
+Content-type: text/html
+--EXPECT--
+hio1
+
diff --git a/ext/phar/tests/zip/frontcontroller17.phar.phpt b/ext/phar/tests/zip/frontcontroller17.phar.phpt
new file mode 100644
index 0000000000..f85bec2911
--- /dev/null
+++ b/ext/phar/tests/zip/frontcontroller17.phar.phpt
@@ -0,0 +1,16 @@
+--TEST--
+Phar front controller mime type unknown zip-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller17.phar.php
+REQUEST_URI=/frontcontroller17.phar.php/fronk.gronk
+PATH_INFO=/fronk.gronk
+--FILE_EXTERNAL--
+files/frontcontroller8.phar.zip
+--EXPECTHEADERS--
+Content-type: application/octet-stream
+Content-length: 4
+--EXPECT--
+hio3
+
diff --git a/ext/phar/tests/zip/frontcontroller18.phar.phpt b/ext/phar/tests/zip/frontcontroller18.phar.phpt
new file mode 100644
index 0000000000..c687dd0664
--- /dev/null
+++ b/ext/phar/tests/zip/frontcontroller18.phar.phpt
@@ -0,0 +1,16 @@
+--TEST--
+Phar front controller $_SERVER munging failure zip-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller18.phar.php
+REQUEST_URI=/frontcontroller18.phar.php/fronk.gronk
+PATH_INFO=/fronk.gronk
+--FILE_EXTERNAL--
+files/frontcontroller9.phar.zip
+--EXPECTF--
+Fatal error: Uncaught exception 'PharException' with message 'No values passed to Phar::mungServer(), expecting an array of any of these strings: PHP_SELF, REQUEST_URI, SCRIPT_FILENAME, SCRIPT_NAME' in %sfrontcontroller18.phar.php:2
+Stack trace:
+#0 %sfrontcontroller18.phar.php(2): Phar::mungServer(Array)
+#1 {main}
+ thrown in %sfrontcontroller18.phar.php on line 2
diff --git a/ext/phar/tests/zip/frontcontroller19.phar.phpt b/ext/phar/tests/zip/frontcontroller19.phar.phpt
new file mode 100644
index 0000000000..5b828e9e60
--- /dev/null
+++ b/ext/phar/tests/zip/frontcontroller19.phar.phpt
@@ -0,0 +1,16 @@
+--TEST--
+Phar front controller $_SERVER munging failure 2 zip-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller19.phar.php
+REQUEST_URI=/frontcontroller19.phar.php/
+PATH_INFO=/
+--FILE_EXTERNAL--
+files/frontcontroller10.phar.zip
+--EXPECTF--
+Fatal error: Uncaught exception 'PharException' with message 'Too many values passed to Phar::mungServer(), expecting an array of any of these strings: PHP_SELF, REQUEST_URI, SCRIPT_FILENAME, SCRIPT_NAME' in %sfrontcontroller19.phar.php:2
+Stack trace:
+#0 %sfrontcontroller19.phar.php(2): Phar::mungServer(Array)
+#1 {main}
+ thrown in %sfrontcontroller19.phar.php on line 2
diff --git a/ext/phar/tests/zip/frontcontroller2.phar.phpt b/ext/phar/tests/zip/frontcontroller2.phar.phpt
new file mode 100644
index 0000000000..0e101f6d41
--- /dev/null
+++ b/ext/phar/tests/zip/frontcontroller2.phar.phpt
@@ -0,0 +1,14 @@
+--TEST--
+Phar front controller PHP test zip-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller2.phar.php
+REQUEST_URI=/frontcontroller2.phar.php/a.php
+PATH_INFO=/a.php
+--FILE_EXTERNAL--
+files/frontcontroller.phar.zip
+--EXPECTHEADERS--
+Content-type: text/html
+--EXPECT--
+hio
diff --git a/ext/phar/tests/zip/frontcontroller20.phar.phpt b/ext/phar/tests/zip/frontcontroller20.phar.phpt
new file mode 100644
index 0000000000..1cf54860ac
--- /dev/null
+++ b/ext/phar/tests/zip/frontcontroller20.phar.phpt
@@ -0,0 +1,16 @@
+--TEST--
+Phar front controller $_SERVER munging failure 3 zip-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller20.phar.php
+REQUEST_URI=/frontcontroller20.phar.php/
+PATH_INFO=/
+--FILE_EXTERNAL--
+files/frontcontroller11.phar.zip
+--EXPECTF--
+Fatal error: Uncaught exception 'PharException' with message 'Non-string value passed to Phar::mungServer(), expecting an array of any of these strings: PHP_SELF, REQUEST_URI, SCRIPT_FILENAME, SCRIPT_NAME' in %sfrontcontroller20.phar.php:2
+Stack trace:
+#0 %sfrontcontroller20.phar.php(2): Phar::mungServer(Array)
+#1 {main}
+ thrown in %sfrontcontroller20.phar.php on line 2
diff --git a/ext/phar/tests/zip/frontcontroller21.phar.phpt b/ext/phar/tests/zip/frontcontroller21.phar.phpt
new file mode 100644
index 0000000000..d31b730ab8
--- /dev/null
+++ b/ext/phar/tests/zip/frontcontroller21.phar.phpt
@@ -0,0 +1,22 @@
+--TEST--
+Phar front controller $_SERVER munging success zip-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller21.phar.php
+REQUEST_URI=/frontcontroller21.phar.php/index.php?test=hi
+PATH_INFO=/index.php
+QUERY_STRING=test=hi
+--FILE_EXTERNAL--
+files/frontcontroller12.phar.zip
+--EXPECTHEADERS--
+Content-type: text/html
+--EXPECTF--
+string(10) "/index.php"
+string(10) "/index.php"
+string(%d) "phar://%sfrontcontroller21.phar.php/index.php"
+string(18) "/index.php?test=hi"
+string(37) "/frontcontroller21.phar.php/index.php"
+string(27) "/frontcontroller21.phar.php"
+string(%d) "%sfrontcontroller21.phar.php"
+string(45) "/frontcontroller21.phar.php/index.php?test=hi" \ No newline at end of file
diff --git a/ext/phar/tests/zip/frontcontroller3.phar.phpt b/ext/phar/tests/zip/frontcontroller3.phar.phpt
new file mode 100644
index 0000000000..abe33bb502
--- /dev/null
+++ b/ext/phar/tests/zip/frontcontroller3.phar.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Phar front controller phps zip-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller3.phar.php
+REQUEST_URI=/frontcontroller3.phar.php/a.phps
+PATH_INFO=/a.phps
+--FILE_EXTERNAL--
+files/frontcontroller.phar.zip
+--EXPECTHEADERS--
+Content-type: text/html
+--EXPECT--
+<code><span style="color: #000000">
+<span style="color: #0000BB">&lt;?php&nbsp;</span><span style="color: #007700">function&nbsp;</span><span style="color: #0000BB">hio</span><span style="color: #007700">(){}</span>
+</span>
+</code>
diff --git a/ext/phar/tests/zip/frontcontroller4.phar.phpt b/ext/phar/tests/zip/frontcontroller4.phar.phpt
new file mode 100644
index 0000000000..6c03620c1c
--- /dev/null
+++ b/ext/phar/tests/zip/frontcontroller4.phar.phpt
@@ -0,0 +1,13 @@
+--TEST--
+Phar front controller index.php relocate (no /) zip-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller4.phar.php
+REQUEST_URI=/frontcontroller4.phar.php
+--FILE_EXTERNAL--
+files/frontcontroller.phar.zip
+--EXPECTHEADERS--
+Status: 301 Moved Permanently
+Location: /frontcontroller4.phar.php/index.php
+--EXPECT--
diff --git a/ext/phar/tests/zip/frontcontroller5.phar.phpt b/ext/phar/tests/zip/frontcontroller5.phar.phpt
new file mode 100644
index 0000000000..9597a1c14c
--- /dev/null
+++ b/ext/phar/tests/zip/frontcontroller5.phar.phpt
@@ -0,0 +1,14 @@
+--TEST--
+Phar front controller index.php relocate zip-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller5.phar.php
+REQUEST_URI=/frontcontroller5.phar.php/
+PATH_INFO=/
+--FILE_EXTERNAL--
+files/frontcontroller.phar.zip
+--EXPECTHEADERS--
+Status: 301 Moved Permanently
+Location: /frontcontroller5.phar.php/index.php
+--EXPECT--
diff --git a/ext/phar/tests/zip/frontcontroller6.phar.phpt b/ext/phar/tests/zip/frontcontroller6.phar.phpt
new file mode 100644
index 0000000000..1da20e96d7
--- /dev/null
+++ b/ext/phar/tests/zip/frontcontroller6.phar.phpt
@@ -0,0 +1,21 @@
+--TEST--
+Phar front controller 404 zip-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller6.phar.php
+REQUEST_URI=/frontcontroller6.phar.php/notfound.php
+PATH_INFO=/notfound.php
+--FILE_EXTERNAL--
+files/frontcontroller.phar.zip
+--EXPECTHEADERS--
+Status: 404 Not Found
+--EXPECT--
+<html>
+ <head>
+ <title>File Not Found</title>
+ </head>
+ <body>
+ <h1>404 - File /notfound.php Not Found</h1>
+ </body>
+</html> \ No newline at end of file
diff --git a/ext/phar/tests/zip/frontcontroller7.phar.phpt b/ext/phar/tests/zip/frontcontroller7.phar.phpt
new file mode 100644
index 0000000000..d13cf33c16
--- /dev/null
+++ b/ext/phar/tests/zip/frontcontroller7.phar.phpt
@@ -0,0 +1,14 @@
+--TEST--
+Phar front controller alternate index file zip-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller7.phar.php
+REQUEST_URI=/frontcontroller7.phar.php/
+PATH_INFO=/
+--FILE_EXTERNAL--
+files/frontcontroller2.phar.zip
+--EXPECTHEADERS--
+Status: 301 Moved Permanently
+Location: /frontcontroller7.phar.php/a.php
+--EXPECT--
diff --git a/ext/phar/tests/zip/frontcontroller8.phar.phpt b/ext/phar/tests/zip/frontcontroller8.phar.phpt
new file mode 100644
index 0000000000..1b0d133bc7
--- /dev/null
+++ b/ext/phar/tests/zip/frontcontroller8.phar.phpt
@@ -0,0 +1,21 @@
+--TEST--
+Phar front controller no index file 404 zip-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller8.phar.php
+REQUEST_URI=/frontcontroller8.phar.php/
+PATH_INFO=/
+--FILE_EXTERNAL--
+files/frontcontroller3.phar.zip
+--EXPECTHEADERS--
+Status: 404 Not Found
+--EXPECT--
+<html>
+ <head>
+ <title>File Not Found</title>
+ </head>
+ <body>
+ <h1>404 - File /index.php Not Found</h1>
+ </body>
+</html> \ No newline at end of file
diff --git a/ext/phar/tests/zip/frontcontroller9.phar.phpt b/ext/phar/tests/zip/frontcontroller9.phar.phpt
new file mode 100644
index 0000000000..8c550539fc
--- /dev/null
+++ b/ext/phar/tests/zip/frontcontroller9.phar.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Phar front controller rewrite array zip-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--ENV--
+SCRIPT_NAME=/frontcontroller9.phar.php
+REQUEST_URI=/frontcontroller9.phar.php/hi
+PATH_INFO=/hi
+--FILE_EXTERNAL--
+files/frontcontroller3.phar.zip
+--EXPECTHEADERS--
+Content-type: text/html
+--EXPECT--
+<code><span style="color: #000000">
+<span style="color: #0000BB">&lt;?php&nbsp;</span><span style="color: #007700">function&nbsp;</span><span style="color: #0000BB">hio</span><span style="color: #007700">(){}</span>
+</span>
+</code> \ No newline at end of file
diff --git a/ext/phar/tests/zip/getalias.phpt b/ext/phar/tests/zip/getalias.phpt
new file mode 100644
index 0000000000..9c917633c9
--- /dev/null
+++ b/ext/phar/tests/zip/getalias.phpt
@@ -0,0 +1,59 @@
+--TEST--
+Phar: getAlias() with an existing phar.zip
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.zip';
+
+// sanity check with a virgin phar.zip
+$phar = new Phar($fname);
+var_dump($phar->getAlias());
+unset($phar);
+
+copy(dirname(__FILE__) . '/files/metadata.phar.zip', $fname);
+
+// existing phar.zip, no alias set
+$phar = new Phar($fname);
+var_dump($phar->getAlias());
+
+// check that default alias can be overwritten
+$phar->setAlias('jiminycricket');
+var_dump($phar->getAlias());
+unset($phar);
+
+// existing phar.zip, alias set
+$phar = new Phar($fname);
+var_dump($phar->getAlias());
+
+// check that alias can't be set manually
+try {
+ $phar['.phar/alias.txt'] = 'pinocchio';
+} catch (Exception $e) {
+ echo $e->getMessage()."\n";
+}
+var_dump($phar->getAlias());
+
+// check that user-defined alias can be overwritten
+$phar->setAlias('pinocchio');
+var_dump($phar->getAlias());
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.zip');
+__HALT_COMPILER();
+?>
+--EXPECTF--
+string(%d) "%sgetalias.phar.zip"
+string(%d) "%sgetalias.phar.zip"
+string(13) "jiminycricket"
+string(13) "jiminycricket"
+Cannot set alias ".phar/alias.txt" directly in phar "%sgetalias.phar.zip", use setAlias
+string(13) "jiminycricket"
+string(9) "pinocchio"
+===DONE===
diff --git a/ext/phar/tests/zip/largezip.phpt b/ext/phar/tests/zip/largezip.phpt
new file mode 100644
index 0000000000..a8438eb7b7
--- /dev/null
+++ b/ext/phar/tests/zip/largezip.phpt
@@ -0,0 +1,29 @@
+--TEST--
+Phar: large zip file (zip edge cases)
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip");?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.zip.php';
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.2.phar.zip.php';
+$pname = 'phar://' . $fname;
+$pname2 = 'phar://' . $fname2;
+
+$p = new Phar($fname);
+$p['big'] = str_repeat(str_repeat('hi', 100), 1000);
+$p['big2'] = str_repeat(str_repeat('hi', 100), 1000);
+
+copy($fname, $fname2);
+$p2 = new Phar($fname2);
+var_dump(strlen($p2['big']->getContent()));
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.zip.php'); ?>
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.2.phar.zip.php'); ?>
+--EXPECT--
+int(200000)
+===DONE===
diff --git a/ext/phar/tests/zip/metadata_write_commit.phpt b/ext/phar/tests/zip/metadata_write_commit.phpt
new file mode 100644
index 0000000000..cf0945d153
--- /dev/null
+++ b/ext/phar/tests/zip/metadata_write_commit.phpt
@@ -0,0 +1,85 @@
+--TEST--
+Phar with meta-data (write) zip-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip");?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.zip.php';
+$f2name = dirname(__FILE__) . '/files/metadata.phar.zip';
+$pname = 'phar://' . $fname;
+$p2name = 'phar://' . $f2name;
+
+$file = "<?php __HALT_COMPILER(); ?>";
+
+$files = array();
+$files['a'] = array('cont' => 'a');
+$files['b'] = array('cont' => 'b', 'meta' => 'hi there');
+$files['c'] = array('cont' => 'c', 'meta' => array('hi', 'there'));
+$files['d'] = array('cont' => 'd', 'meta' => array('hi'=>'there','foo'=>'bar'));
+
+foreach($files as $name => $cont) {
+ var_dump(file_get_contents($p2name.'/'.$name));
+}
+
+copy($f2name, $fname);
+$phar = new Phar($fname);
+$phar->startBuffering();
+$phar['a']->setMetadata(42);
+$phar['b']->setMetadata(NULL);
+$phar['c']->setMetadata(array(25, 'foo'=>'bar'));
+$phar['d']->setMetadata(true);
+$phar->setMetadata('hi');
+
+foreach($files as $name => $cont) {
+ var_dump($phar[$name]->getMetadata());
+}
+$phar->stopBuffering();
+
+unset($phar);
+
+$phar = new Phar($fname);
+
+foreach($files as $name => $cont) {
+ var_dump(file_get_contents($pname.'/'.$name));
+}
+
+foreach($files as $name => $cont) {
+ var_dump($phar[$name]->getMetadata());
+}
+var_dump($phar->getMetadata());
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.zip.php'); ?>
+--EXPECT--
+string(1) "a"
+string(1) "b"
+string(1) "c"
+string(1) "d"
+int(42)
+NULL
+array(2) {
+ [0]=>
+ int(25)
+ ["foo"]=>
+ string(3) "bar"
+}
+bool(true)
+string(1) "a"
+string(1) "b"
+string(1) "c"
+string(1) "d"
+int(42)
+NULL
+array(2) {
+ [0]=>
+ int(25)
+ ["foo"]=>
+ string(3) "bar"
+}
+bool(true)
+string(2) "hi"
+===DONE===
diff --git a/ext/phar/tests/zip/notphar.phpt b/ext/phar/tests/zip/notphar.phpt
new file mode 100644
index 0000000000..26dcd71ed9
--- /dev/null
+++ b/ext/phar/tests/zip/notphar.phpt
@@ -0,0 +1,23 @@
+--TEST--
+Phar: a non-executable zip with no stub named .phar.zip
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=1
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.zip';
+$pname = 'phar://' . $fname;
+
+copy(dirname(__FILE__) . '/files/zip.zip', $fname);
+include $fname;
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.zip');
+__HALT_COMPILER();
+?>
+--EXPECTF--
+Warning: include(phar://%snotphar.phar.zip/.phar/stub.php): failed to open stream: '%snotphar.phar.zip' is not a phar archive. Use PharData::__construct() for a standard zip or tar archive in %snotphar.php on line %d
+PK%a \ No newline at end of file
diff --git a/ext/phar/tests/zip/odt.phpt b/ext/phar/tests/zip/odt.phpt
new file mode 100644
index 0000000000..28187f68b7
--- /dev/null
+++ b/ext/phar/tests/zip/odt.phpt
@@ -0,0 +1,34 @@
+--TEST--
+Phar: test a zip archive created by openoffice
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+--FILE--
+<?php
+$a = new PharData(dirname(__FILE__) . '/files/odt.odt');
+foreach (new RecursiveIteratorIterator($a, RecursiveIteratorIterator::LEAVES_ONLY) as $b) {
+ if ($b->isDir()) {
+ echo "dir " . $b->getPathName() . "\n";
+ } else {
+ echo $b->getPathName() . "\n";
+ }
+}
+// this next line is for increased code coverage
+try {
+ $b = new Phar(dirname(__FILE__) . '/files/odt.odt');
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--EXPECTF--
+phar://%sodt.odt%cConfigurations2%caccelerator%ccurrent.xml
+phar://%sodt.odt%cMETA-INF%cmanifest.xml
+phar://%sodt.odt%cThumbnails%cthumbnail.png
+phar://%sodt.odt%ccontent.xml
+phar://%sodt.odt%cmeta.xml
+phar://%sodt.odt%cmimetype
+phar://%sodt.odt%csettings.xml
+phar://%sodt.odt%cstyles.xml
+Cannot create phar '%sodt.odt', file extension (or combination) not recognised
+===DONE===
diff --git a/ext/phar/tests/zip/open_for_write_existing.phpt b/ext/phar/tests/zip/open_for_write_existing.phpt
new file mode 100644
index 0000000000..94f85b4e3f
--- /dev/null
+++ b/ext/phar/tests/zip/open_for_write_existing.phpt
@@ -0,0 +1,39 @@
+--TEST--
+Phar: fopen a .phar for writing (existing file) zip-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.zip';
+$alias = 'phar://' . $fname;
+
+$phar = new Phar($fname);
+$phar->setStub('<?php __HALT_COMPILER(); ?>');
+
+$files = array();
+
+$files['a.php'] = '<?php echo "This is a\n"; ?>';
+$files['b.php'] = '<?php echo "This is b\n"; ?>';
+$files['b/c.php'] = '<?php echo "This is b/c\n"; ?>';
+
+foreach ($files as $n => $file) {
+ $phar[$n] = $file;
+}
+$phar->stopBuffering();
+
+$fp = fopen($alias . '/b/c.php', 'wb');
+fwrite($fp, 'extra');
+fclose($fp);
+include $alias . '/b/c.php';
+?>
+
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.zip'); ?>
+--EXPECT--
+extra
+===DONE===
diff --git a/ext/phar/tests/zip/open_for_write_existing_b.phpt b/ext/phar/tests/zip/open_for_write_existing_b.phpt
new file mode 100755
index 0000000000..347a1ce719
--- /dev/null
+++ b/ext/phar/tests/zip/open_for_write_existing_b.phpt
@@ -0,0 +1,52 @@
+--TEST--
+Phar: fopen a .phar for writing (existing file) zip-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.zip';
+$alias = 'phar://' . $fname;
+
+$phar = new Phar($fname);
+$phar->setStub('<?php __HALT_COMPILER(); ?>');
+
+$files = array();
+
+$files['a.php'] = '<?php echo "This is a\n"; ?>';
+$files['b.php'] = '<?php echo "This is b\n"; ?>';
+$files['b/c.php'] = '<?php echo "This is b/c\n"; ?>';
+
+foreach ($files as $n => $file) {
+ $phar[$n] = $file;
+}
+$phar->stopBuffering();
+
+ini_set('phar.readonly', 1);
+
+function err_handler($errno, $errstr, $errfile, $errline) {
+ echo "Catchable fatal error: $errstr in $errfile on line $errline\n";
+}
+
+set_error_handler("err_handler", E_RECOVERABLE_ERROR);
+
+$fp = fopen($alias . '/b/c.php', 'wb');
+fwrite($fp, 'extra');
+fclose($fp);
+include $alias . '/b/c.php';
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.zip'); ?>
+--EXPECTF--
+
+Warning: fopen(phar://%sopen_for_write_existing_b.phar.zip/b/c.php): failed to open stream: phar error: write operations disabled by INI setting in %sopen_for_write_existing_b.php on line %d
+
+Warning: fwrite(): supplied argument is not a valid stream resource in %spen_for_write_existing_b.php on line %d
+
+Warning: fclose(): supplied argument is not a valid stream resource in %spen_for_write_existing_b.php on line %d
+This is b/c
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/zip/open_for_write_existing_c.phpt b/ext/phar/tests/zip/open_for_write_existing_c.phpt
new file mode 100755
index 0000000000..b66a77b212
--- /dev/null
+++ b/ext/phar/tests/zip/open_for_write_existing_c.phpt
@@ -0,0 +1,46 @@
+--TEST--
+Phar: fopen a .phar for writing (existing file) zip-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.zip';
+$alias = 'phar://' . $fname;
+
+$phar = new Phar($fname);
+$phar->setStub('<?php __HALT_COMPILER(); ?>');
+
+$files = array();
+
+$files['a.php'] = '<?php echo "This is a\n"; ?>';
+$files['b.php'] = '<?php echo "This is b\n"; ?>';
+$files['b/c.php'] = '<?php echo "This is b/c\n"; ?>';
+
+foreach ($files as $n => $file) {
+ $phar[$n] = $file;
+}
+$phar->stopBuffering();
+
+ini_set('phar.readonly', 1);
+
+$fp = fopen($alias . '/b/c.php', 'wb');
+fwrite($fp, 'extra');
+fclose($fp);
+include $alias . '/b/c.php';
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.zip'); ?>
+--EXPECTF--
+
+Warning: fopen(phar://%sopen_for_write_existing_c.phar.zip/b/c.php): failed to open stream: phar error: write operations disabled by INI setting in %sopen_for_write_existing_c.php on line %d
+
+Warning: fwrite(): supplied argument is not a valid stream resource in %sopen_for_write_existing_c.php on line %d
+
+Warning: fclose(): supplied argument is not a valid stream resource in %sopen_for_write_existing_c.php on line %d
+This is b/c
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/zip/open_for_write_newfile.phpt b/ext/phar/tests/zip/open_for_write_newfile.phpt
new file mode 100644
index 0000000000..c3782d4fd3
--- /dev/null
+++ b/ext/phar/tests/zip/open_for_write_newfile.phpt
@@ -0,0 +1,42 @@
+--TEST--
+Phar: fopen a .phar for writing (new file) zip-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.zip';
+$alias = 'phar://' . $fname;
+
+$phar = new Phar($fname);
+$phar->setStub('<?php __HALT_COMPILER(); ?>');
+
+$files = array();
+
+$files['a.php'] = '<?php echo "This is a\n"; ?>';
+$files['b.php'] = '<?php echo "This is b\n"; ?>';
+$files['b/c.php'] = '<?php echo "This is b/c\n"; ?>';
+
+foreach ($files as $n => $file) {
+ $phar[$n] = $file;
+}
+$phar->stopBuffering();
+
+$fp = fopen($alias . '/b/new.php', 'wb');
+fwrite($fp, 'extra');
+fclose($fp);
+
+include $alias . '/b/c.php';
+include $alias . '/b/new.php';
+?>
+
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.zip'); ?>
+--EXPECT--
+This is b/c
+extra
+===DONE===
diff --git a/ext/phar/tests/zip/open_for_write_newfile_b.phpt b/ext/phar/tests/zip/open_for_write_newfile_b.phpt
new file mode 100755
index 0000000000..44ad7487fa
--- /dev/null
+++ b/ext/phar/tests/zip/open_for_write_newfile_b.phpt
@@ -0,0 +1,60 @@
+--TEST--
+Phar: fopen a .phar for writing (new file) zip-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.zip';
+$alias = 'phar://' . $fname;
+
+$phar = new Phar($fname);
+$phar->setStub('<?php __HALT_COMPILER(); ?>');
+
+$files = array();
+
+$files['a.php'] = '<?php echo "This is a\n"; ?>';
+$files['b.php'] = '<?php echo "This is b\n"; ?>';
+$files['b/c.php'] = '<?php echo "This is b/c\n"; ?>';
+
+foreach ($files as $n => $file) {
+ $phar[$n] = $file;
+}
+$phar->stopBuffering();
+
+ini_set('phar.readonly', 1);
+
+function err_handler($errno, $errstr, $errfile, $errline) {
+ echo "Catchable fatal error: $errstr in $errfile on line $errline\n";
+}
+
+set_error_handler("err_handler", E_RECOVERABLE_ERROR);
+
+$fp = fopen($alias . '/b/new.php', 'wb');
+fwrite($fp, 'extra');
+fclose($fp);
+
+include $alias . '/b/c.php';
+include $alias . '/b/new.php';
+?>
+
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.zip'); ?>
+--EXPECTF--
+
+Warning: fopen(phar://%sopen_for_write_newfile_b.phar.zip/b/new.php): failed to open stream: phar error: write operations disabled by INI setting in %sopen_for_write_newfile_b.php on line %d
+
+Warning: fwrite(): supplied argument is not a valid stream resource in %sopen_for_write_newfile_b.php on line %d
+
+Warning: fclose(): supplied argument is not a valid stream resource in %sopen_for_write_newfile_b.php on line %d
+This is b/c
+
+Warning: include(phar://%sopen_for_write_newfile_b.phar.zip/b/new.php): failed to open stream: phar error: "b/new.php" is not a file in phar "%sopen_for_write_newfile_b.phar.zip" in %sopen_for_write_newfile_b.php on line %d
+
+Warning: include(): Failed opening 'phar://%sopen_for_write_newfile_b.phar.zip/b/new.php' for inclusion (include_path='%s') in %sopen_for_write_newfile_b.php on line %d
+
+===DONE===
diff --git a/ext/phar/tests/zip/open_for_write_newfile_c.phpt b/ext/phar/tests/zip/open_for_write_newfile_c.phpt
new file mode 100755
index 0000000000..b664397a99
--- /dev/null
+++ b/ext/phar/tests/zip/open_for_write_newfile_c.phpt
@@ -0,0 +1,54 @@
+--TEST--
+Phar: fopen a .phar for writing (new file) zip-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.zip';
+$alias = 'phar://' . $fname;
+
+$phar = new Phar($fname);
+$phar->setStub('<?php __HALT_COMPILER(); ?>');
+
+$files = array();
+
+$files['a.php'] = '<?php echo "This is a\n"; ?>';
+$files['b.php'] = '<?php echo "This is b\n"; ?>';
+$files['b/c.php'] = '<?php echo "This is b/c\n"; ?>';
+
+foreach ($files as $n => $file) {
+ $phar[$n] = $file;
+}
+$phar->stopBuffering();
+
+ini_set('phar.readonly', 1);
+
+$fp = fopen($alias . '/b/new.php', 'wb');
+fwrite($fp, 'extra');
+fclose($fp);
+
+include $alias . '/b/c.php';
+include $alias . '/b/new.php';
+?>
+
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.zip'); ?>
+--EXPECTF--
+
+Warning: fopen(phar://%sopen_for_write_newfile_c.phar.zip/b/new.php): failed to open stream: phar error: write operations disabled by INI setting in %sopen_for_write_newfile_c.php on line %d
+
+Warning: fwrite(): supplied argument is not a valid stream resource in %sopen_for_write_newfile_c.php on line %d
+
+Warning: fclose(): supplied argument is not a valid stream resource in %sopen_for_write_newfile_c.php on line %d
+This is b/c
+
+Warning: include(phar://%sopen_for_write_newfile_c.phar.zip/b/new.php): failed to open stream: phar error: "b/new.php" is not a file in phar "%sopen_for_write_newfile_c.phar.zip" in %sopen_for_write_newfile_c.php on line %d
+
+Warning: include(): Failed opening 'phar://%sopen_for_write_newfile_c.phar.zip/b/new.php' for inclusion (include_path='%s') in %sopen_for_write_newfile_c.php on line %d
+
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/zip/phar_begin_setstub_commit.phpt b/ext/phar/tests/zip/phar_begin_setstub_commit.phpt
new file mode 100755
index 0000000000..81cf4001c3
--- /dev/null
+++ b/ext/phar/tests/zip/phar_begin_setstub_commit.phpt
@@ -0,0 +1,68 @@
+--TEST--
+Phar::startBuffering()/setStub()/stopBuffering() zip-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+$p = new Phar(dirname(__FILE__) . '/brandnewphar.phar.zip', 0, 'brandnewphar.phar');
+var_dump($p->isFileFormat(Phar::ZIP));
+//var_dump($p->getStub());
+var_dump($p->isBuffering());
+$p->startBuffering();
+var_dump($p->isBuffering());
+$p['a.php'] = '<?php var_dump("Hello");';
+$p->setStub('<?php var_dump("First"); Phar::mapPhar("brandnewphar.phar"); __HALT_COMPILER(); ?>');
+include 'phar://brandnewphar.phar/a.php';
+var_dump($p->getStub());
+$p['b.php'] = '<?php var_dump("World");';
+$p->setStub('<?php var_dump("Second"); Phar::mapPhar("brandnewphar.phar"); __HALT_COMPILER();');
+include 'phar://brandnewphar.phar/b.php';
+var_dump($p->getStub());
+$p->stopBuffering();
+echo "===COMMIT===\n";
+var_dump($p->isBuffering());
+include 'phar://brandnewphar.phar/a.php';
+include 'phar://brandnewphar.phar/b.php';
+var_dump($p->getStub());
+
+// add portion to test setting stub from resource
+file_put_contents(dirname(__FILE__) . '/myfakestub.php', '<?php var_dump("First resource"); Phar::mapPhar("brandnewphar.phar"); __HALT_COMPILER(); ?>');
+$a = fopen(dirname(__FILE__) . '/myfakestub.php', 'rb');
+$p->setStub($a);
+var_dump($p->getStub());
+$c = strlen('<?php var_dump("First resource"); Phar::mapPhar("brandnewphar.phar"); __HALT_COMPILER(); ?>');
+file_put_contents(dirname(__FILE__) . '/myfakestub.php', '<?php var_dump("First resource"); Phar::mapPhar("brandnewphar.phar"); __HALT_COMPILER(); ?>' . 'extra stuff');
+fseek($a, 0);
+$p->setStub($a, $c);
+var_dump($p->getStub());
+fclose($a);
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/brandnewphar.phar.zip');
+unlink(dirname(__FILE__) . '/myfakestub.php');
+?>
+--EXPECT--
+bool(true)
+bool(true)
+bool(false)
+string(5) "Hello"
+string(84) "<?php var_dump("First"); Phar::mapPhar("brandnewphar.phar"); __HALT_COMPILER(); ?>
+"
+string(5) "World"
+string(85) "<?php var_dump("Second"); Phar::mapPhar("brandnewphar.phar"); __HALT_COMPILER(); ?>
+"
+===COMMIT===
+bool(true)
+string(5) "Hello"
+string(5) "World"
+string(85) "<?php var_dump("Second"); Phar::mapPhar("brandnewphar.phar"); __HALT_COMPILER(); ?>
+"
+string(93) "<?php var_dump("First resource"); Phar::mapPhar("brandnewphar.phar"); __HALT_COMPILER(); ?>
+"
+string(93) "<?php var_dump("First resource"); Phar::mapPhar("brandnewphar.phar"); __HALT_COMPILER(); ?>
+"
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/zip/phar_buildfromiterator4.phpt b/ext/phar/tests/zip/phar_buildfromiterator4.phpt
new file mode 100644
index 0000000000..cc11fe5537
--- /dev/null
+++ b/ext/phar/tests/zip/phar_buildfromiterator4.phpt
@@ -0,0 +1,66 @@
+--TEST--
+Phar::buildFromIterator() iterator, 1 file passed in zip-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+class myIterator implements Iterator
+{
+ var $a;
+ function __construct(array $a)
+ {
+ $this->a = $a;
+ }
+ function next() {
+ echo "next\n";
+ return next($this->a);
+ }
+ function current() {
+ echo "current\n";
+ return current($this->a);
+ }
+ function key() {
+ echo "key\n";
+ return key($this->a);
+ }
+ function valid() {
+ echo "valid\n";
+ return current($this->a);
+ }
+ function rewind() {
+ echo "rewind\n";
+ return reset($this->a);
+ }
+}
+try {
+ chdir(dirname(__FILE__));
+ $phar = new Phar(dirname(__FILE__) . '/buildfromiterator.phar.zip');
+ var_dump($phar->buildFromIterator(new myIterator(array('a' => basename(__FILE__, 'php') . 'phpt'))));
+ var_dump($phar->isFileFormat(Phar::ZIP));
+} catch (Exception $e) {
+ var_dump(get_class($e));
+ echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/buildfromiterator.phar.zip');
+__HALT_COMPILER();
+?>
+--EXPECTF--
+rewind
+valid
+current
+key
+next
+valid
+array(1) {
+ ["a"]=>
+ string(%d) "%sphar_buildfromiterator4.phpt"
+}
+bool(true)
+===DONE===
diff --git a/ext/phar/tests/zip/phar_buildfromiterator5.phpt b/ext/phar/tests/zip/phar_buildfromiterator5.phpt
new file mode 100644
index 0000000000..450ada100d
--- /dev/null
+++ b/ext/phar/tests/zip/phar_buildfromiterator5.phpt
@@ -0,0 +1,59 @@
+--TEST--
+Phar::buildFromIterator() iterator, iterator returns non-string zip-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+class myIterator implements Iterator
+{
+ var $a;
+ function __construct(array $a)
+ {
+ $this->a = $a;
+ }
+ function next() {
+ echo "next\n";
+ return next($this->a);
+ }
+ function current() {
+ echo "current\n";
+ return current($this->a);
+ }
+ function key() {
+ echo "key\n";
+ return key($this->a);
+ }
+ function valid() {
+ echo "valid\n";
+ return current($this->a);
+ }
+ function rewind() {
+ echo "rewind\n";
+ return reset($this->a);
+ }
+}
+try {
+ chdir(dirname(__FILE__));
+ $phar = new Phar(dirname(__FILE__) . '/buildfromiterator.phar.zip');
+ var_dump($phar->buildFromIterator(new myIterator(array('a' => new stdClass))));
+} catch (Exception $e) {
+ var_dump(get_class($e));
+ echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/buildfromiterator.phar.zip');
+__HALT_COMPILER();
+?>
+--EXPECTF--
+rewind
+valid
+current
+string(24) "UnexpectedValueException"
+Iterator myIterator returned an invalid value (must return a string)
+===DONE===
diff --git a/ext/phar/tests/zip/phar_buildfromiterator6.phpt b/ext/phar/tests/zip/phar_buildfromiterator6.phpt
new file mode 100644
index 0000000000..2dfb04dbf0
--- /dev/null
+++ b/ext/phar/tests/zip/phar_buildfromiterator6.phpt
@@ -0,0 +1,60 @@
+--TEST--
+Phar::buildFromIterator() iterator, key is int zip-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+class myIterator implements Iterator
+{
+ var $a;
+ function __construct(array $a)
+ {
+ $this->a = $a;
+ }
+ function next() {
+ echo "next\n";
+ return next($this->a);
+ }
+ function current() {
+ echo "current\n";
+ return current($this->a);
+ }
+ function key() {
+ echo "key\n";
+ return key($this->a);
+ }
+ function valid() {
+ echo "valid\n";
+ return current($this->a);
+ }
+ function rewind() {
+ echo "rewind\n";
+ return reset($this->a);
+ }
+}
+try {
+ chdir(dirname(__FILE__));
+ $phar = new Phar(dirname(__FILE__) . '/buildfromiterator.phar.zip');
+ var_dump($phar->buildFromIterator(new myIterator(array(basename(__FILE__, 'php') . 'phpt'))));
+} catch (Exception $e) {
+ var_dump(get_class($e));
+ echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/buildfromiterator.phar.zip');
+__HALT_COMPILER();
+?>
+--EXPECTF--
+rewind
+valid
+current
+key
+string(24) "UnexpectedValueException"
+Iterator myIterator returned an invalid key (must return a string)
+===DONE===
diff --git a/ext/phar/tests/zip/phar_buildfromiterator7.phpt b/ext/phar/tests/zip/phar_buildfromiterator7.phpt
new file mode 100644
index 0000000000..16ba6d61b9
--- /dev/null
+++ b/ext/phar/tests/zip/phar_buildfromiterator7.phpt
@@ -0,0 +1,60 @@
+--TEST--
+Phar::buildFromIterator() iterator, file can't be opened zip-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+class myIterator implements Iterator
+{
+ var $a;
+ function __construct(array $a)
+ {
+ $this->a = $a;
+ }
+ function next() {
+ echo "next\n";
+ return next($this->a);
+ }
+ function current() {
+ echo "current\n";
+ return current($this->a);
+ }
+ function key() {
+ echo "key\n";
+ return key($this->a);
+ }
+ function valid() {
+ echo "valid\n";
+ return current($this->a);
+ }
+ function rewind() {
+ echo "rewind\n";
+ return reset($this->a);
+ }
+}
+try {
+ chdir(dirname(__FILE__));
+ $phar = new Phar(dirname(__FILE__) . '/buildfromiterator.phar.zip');
+ var_dump($phar->buildFromIterator(new myIterator(array('a' => basename(__FILE__, 'php') . '/oopsie/there.phpt'))));
+} catch (Exception $e) {
+ var_dump(get_class($e));
+ echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/buildfromiterator.phar.zip');
+__HALT_COMPILER();
+?>
+--EXPECT--
+rewind
+valid
+current
+key
+string(24) "UnexpectedValueException"
+Iterator myIterator returned a file that could not be opened "phar_buildfromiterator7./oopsie/there.phpt"
+===DONE===
diff --git a/ext/phar/tests/zip/phar_buildfromiterator8.phpt b/ext/phar/tests/zip/phar_buildfromiterator8.phpt
new file mode 100644
index 0000000000..d2b1be2087
--- /dev/null
+++ b/ext/phar/tests/zip/phar_buildfromiterator8.phpt
@@ -0,0 +1,73 @@
+--TEST--
+Phar::buildFromIterator() iterator, SplFileInfo as current zip-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+try {
+ chdir(dirname(__FILE__));
+ $phar = new Phar(dirname(__FILE__) . '/buildfromiterator.phar.zip');
+ $a = $phar->buildFromIterator(new RegexIterator(new DirectoryIterator('.'), '/^frontcontroller\d{0,2}\.phar\.phpt\\z|^\.\\z|^\.\.\\z/'), dirname(__FILE__) . DIRECTORY_SEPARATOR);
+ asort($a);
+ var_dump($a);
+ var_dump($phar->isFileFormat(Phar::ZIP));
+} catch (Exception $e) {
+ var_dump(get_class($e));
+ echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/buildfromiterator.phar.zip');
+__HALT_COMPILER();
+?>
+--EXPECTF--
+array(21) {
+ ["frontcontroller1.phar.phpt"]=>
+ string(%d) "%sfrontcontroller1.phar.phpt"
+ ["frontcontroller10.phar.phpt"]=>
+ string(%d) "%sfrontcontroller10.phar.phpt"
+ ["frontcontroller11.phar.phpt"]=>
+ string(%d) "%sfrontcontroller11.phar.phpt"
+ ["frontcontroller12.phar.phpt"]=>
+ string(%d) "%sfrontcontroller12.phar.phpt"
+ ["frontcontroller13.phar.phpt"]=>
+ string(%d) "%sfrontcontroller13.phar.phpt"
+ ["frontcontroller14.phar.phpt"]=>
+ string(%d) "%sfrontcontroller14.phar.phpt"
+ ["frontcontroller15.phar.phpt"]=>
+ string(%d) "%sfrontcontroller15.phar.phpt"
+ ["frontcontroller16.phar.phpt"]=>
+ string(%d) "%sfrontcontroller16.phar.phpt"
+ ["frontcontroller17.phar.phpt"]=>
+ string(%d) "%sfrontcontroller17.phar.phpt"
+ ["frontcontroller18.phar.phpt"]=>
+ string(%d) "%sfrontcontroller18.phar.phpt"
+ ["frontcontroller19.phar.phpt"]=>
+ string(%d) "%sfrontcontroller19.phar.phpt"
+ ["frontcontroller2.phar.phpt"]=>
+ string(%d) "%sfrontcontroller2.phar.phpt"
+ ["frontcontroller20.phar.phpt"]=>
+ string(%d) "%sfrontcontroller20.phar.phpt"
+ ["frontcontroller21.phar.phpt"]=>
+ string(%d) "%sfrontcontroller21.phar.phpt"
+ ["frontcontroller3.phar.phpt"]=>
+ string(%d) "%sfrontcontroller3.phar.phpt"
+ ["frontcontroller4.phar.phpt"]=>
+ string(%d) "%sfrontcontroller4.phar.phpt"
+ ["frontcontroller5.phar.phpt"]=>
+ string(%d) "%sfrontcontroller5.phar.phpt"
+ ["frontcontroller6.phar.phpt"]=>
+ string(%d) "%sfrontcontroller6.phar.phpt"
+ ["frontcontroller7.phar.phpt"]=>
+ string(%d) "%sfrontcontroller7.phar.phpt"
+ ["frontcontroller8.phar.phpt"]=>
+ string(%d) "%sfrontcontroller8.phar.phpt"
+ ["frontcontroller9.phar.phpt"]=>
+ string(%d) "%sfrontcontroller9.phar.phpt"
+}
+bool(true)
+===DONE===
diff --git a/ext/phar/tests/zip/phar_buildfromiterator9.phpt b/ext/phar/tests/zip/phar_buildfromiterator9.phpt
new file mode 100644
index 0000000000..0b56307545
--- /dev/null
+++ b/ext/phar/tests/zip/phar_buildfromiterator9.phpt
@@ -0,0 +1,65 @@
+--TEST--
+Phar::buildFromIterator() iterator, 1 file resource passed in
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+class myIterator implements Iterator
+{
+ var $a;
+ function __construct(array $a)
+ {
+ $this->a = $a;
+ }
+ function next() {
+ echo "next\n";
+ return next($this->a);
+ }
+ function current() {
+ echo "current\n";
+ return current($this->a);
+ }
+ function key() {
+ echo "key\n";
+ return key($this->a);
+ }
+ function valid() {
+ echo "valid\n";
+ return current($this->a);
+ }
+ function rewind() {
+ echo "rewind\n";
+ return reset($this->a);
+ }
+}
+try {
+ chdir(dirname(__FILE__));
+ $phar = new Phar(dirname(__FILE__) . '/buildfromiterator.phar');
+ var_dump($phar->buildFromIterator(new myIterator(array('a' => $a = fopen(basename(__FILE__, 'php') . 'phpt', 'r')))));
+ fclose($a);
+} catch (Exception $e) {
+ var_dump(get_class($e));
+ echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/buildfromiterator.phar');
+__HALT_COMPILER();
+?>
+--EXPECTF--
+rewind
+valid
+current
+key
+next
+valid
+array(1) {
+ ["a"]=>
+ string(%d) "[stream]"
+}
+===DONE===
diff --git a/ext/phar/tests/zip/phar_commitwrite.phpt b/ext/phar/tests/zip/phar_commitwrite.phpt
new file mode 100644
index 0000000000..84bccb9fae
--- /dev/null
+++ b/ext/phar/tests/zip/phar_commitwrite.phpt
@@ -0,0 +1,44 @@
+--TEST--
+Phar::setStub()/stopBuffering() zip-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+$p = new Phar(dirname(__FILE__) . '/brandnewphar.phar.zip', 0, 'brandnewphar.phar');
+$p['file1.txt'] = 'hi';
+$p->stopBuffering();
+var_dump($p->getStub());
+$p->setStub("<?php
+function __autoload(\$class)
+{
+ include 'phar://' . str_replace('_', '/', \$class);
+}
+Phar::mapPhar('brandnewphar.phar');
+include 'phar://brandnewphar.phar/startup.php';
+__HALT_COMPILER();
+?>");
+var_dump($p->getStub());
+var_dump($p->isFileFormat(Phar::ZIP));
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/brandnewphar.phar.zip');
+?>
+--EXPECT--
+string(60) "<?php // zip-based phar archive stub file
+__HALT_COMPILER();"
+string(200) "<?php
+function __autoload($class)
+{
+ include 'phar://' . str_replace('_', '/', $class);
+}
+Phar::mapPhar('brandnewphar.phar');
+include 'phar://brandnewphar.phar/startup.php';
+__HALT_COMPILER(); ?>
+"
+bool(true)
+===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/zip/phar_convert_phar.phpt b/ext/phar/tests/zip/phar_convert_phar.phpt
new file mode 100644
index 0000000000..815656dbf6
--- /dev/null
+++ b/ext/phar/tests/zip/phar_convert_phar.phpt
@@ -0,0 +1,57 @@
+--TEST--
+Phar::convertToPhar() from zip
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar';
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '2.phar';
+$fname3 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.3.phar';
+
+$phar = new Phar($fname);
+$phar['a.txt'] = 'some text';
+$phar->stopBuffering();
+var_dump($phar->isFileFormat(Phar::ZIP));
+var_dump(strlen($phar->getStub()));
+
+$phar = $phar->convertToExecutable(Phar::ZIP);
+var_dump($phar->isFileFormat(Phar::ZIP));
+var_dump($phar->getStub());
+
+$phar['a'] = 'hi there';
+
+$phar = $phar->convertToExecutable(Phar::PHAR, Phar::NONE, '.3.phar');
+var_dump($phar->isFileFormat(Phar::PHAR));
+var_dump(strlen($phar->getStub()));
+
+copy($fname3, $fname2);
+
+$phar = new Phar($fname2);
+var_dump($phar->isFileFormat(Phar::PHAR));
+var_dump(strlen($phar->getStub()));
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.zip');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '2.phar');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.3.phar');
+__HALT_COMPILER();
+?>
+--EXPECT--
+bool(false)
+int(6651)
+bool(true)
+string(60) "<?php // zip-based phar archive stub file
+__HALT_COMPILER();"
+bool(true)
+int(6651)
+bool(true)
+int(6651)
+===DONE===
diff --git a/ext/phar/tests/zip/phar_copy.phpt b/ext/phar/tests/zip/phar_copy.phpt
new file mode 100644
index 0000000000..14034c92c0
--- /dev/null
+++ b/ext/phar/tests/zip/phar_copy.phpt
@@ -0,0 +1,55 @@
+--TEST--
+Phar: copy() zip-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=1
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.zip.php';
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '2.phar.php';
+
+$pname = 'phar://'.$fname;
+$iname = '/file.txt';
+$ename = '/error/..';
+
+$p = new Phar($fname);
+
+try
+{
+ $p['a'] = 'hi';
+ $p->startBuffering();
+ $p->copy('a', 'b');
+ echo file_get_contents($p['b']->getPathName());
+ $p->copy('b', 'c');
+ $p->stopBuffering();
+ echo file_get_contents($p['c']->getPathName());
+ copy($fname, $fname2);
+ var_dump($p->isFileFormat(Phar::ZIP));
+ $p->copy('a', $ename);
+}
+catch(Exception $e)
+{
+ echo $e->getMessage() . "\n";
+}
+ini_set('phar.readonly',1);
+$p2 = new Phar($fname2);
+var_dump($p2->isFileFormat(Phar::ZIP));
+echo "\n";
+echo 'a: ' , file_get_contents($p2['a']->getPathName());
+echo 'b: ' ,file_get_contents($p2['b']->getPathName());
+echo 'c: ' ,file_get_contents($p2['c']->getPathName());
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.zip.php'); ?>
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '2.phar.php'); ?>
+--EXPECTF--
+hihibool(true)
+file "/error/.." contains invalid characters upper directory reference, cannot be copied from "a" in phar %s
+bool(true)
+
+a: hib: hic: hi===DONE=== \ No newline at end of file
diff --git a/ext/phar/tests/zip/phar_magic.phpt b/ext/phar/tests/zip/phar_magic.phpt
new file mode 100644
index 0000000000..4a17207376
--- /dev/null
+++ b/ext/phar/tests/zip/phar_magic.phpt
@@ -0,0 +1,33 @@
+--TEST--
+Phar: include/fopen magic zip-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.zip.php';
+$p = new Phar($fname);
+var_dump($p->isFileFormat(Phar::ZIP));
+$p['a'] = '<?php include "b/c.php";' . "\n";
+$p['b/c.php'] = '<?php echo "in b\n";$a = fopen("a", "r", true);echo stream_get_contents($a);fclose($a);include dirname(__FILE__) . "/../d";';
+$p['d'] = "in d\n";
+$p->setStub('<?php
+set_include_path("phar://" . __FILE__);
+include "phar://" . __FILE__ . "/a";
+__HALT_COMPILER();');
+include $fname;
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.zip.php');
+__HALT_COMPILER();
+?>
+--EXPECTF--
+bool(true)
+in b
+<?php include "b/c.php";
+in d
+===DONE===
diff --git a/ext/phar/tests/zip/phar_oo_compressallbz2.phpt b/ext/phar/tests/zip/phar_oo_compressallbz2.phpt
new file mode 100644
index 0000000000..d6b0a8f4cf
--- /dev/null
+++ b/ext/phar/tests/zip/phar_oo_compressallbz2.phpt
@@ -0,0 +1,70 @@
+--TEST--
+Phar::compressFiles(Phar::BZ2) zip format
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("bz2")) die("skip bz2 not present"); ?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.zip.php';
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.zip';
+$pname = 'phar://' . $fname;
+$pname2 = 'phar://' . $fname2;
+
+$phar = new Phar($fname);
+$phar['a'] = 'a';
+$phar['b'] = 'b';
+$phar['c'] = 'c';
+
+var_dump(file_get_contents($pname . '/a'));
+var_dump($phar['a']->isCompressed());
+var_dump(file_get_contents($pname . '/b'));
+var_dump($phar['b']->isCompressed());
+var_dump(file_get_contents($pname . '/c'));
+var_dump($phar['c']->isCompressed());
+
+$phar->compressFiles(Phar::BZ2);
+var_dump(file_get_contents($pname . '/a'));
+var_dump($phar['a']->isCompressed(Phar::GZ));
+var_dump($phar['a']->isCompressed(Phar::BZ2));
+var_dump(file_get_contents($pname . '/b'));
+var_dump($phar['b']->isCompressed(Phar::GZ));
+var_dump($phar['b']->isCompressed(Phar::BZ2));
+var_dump(file_get_contents($pname . '/c'));
+var_dump($phar['c']->isCompressed(Phar::GZ));
+var_dump($phar['b']->isCompressed(Phar::BZ2));
+$phar['d'] = 'hi'; // increases code coverage by having ufp open
+copy($fname, $fname2);
+$c = new Phar($fname2);
+var_dump(file_get_contents($pname2 . '/a'));
+var_dump($c['a']->isCompressed(Phar::GZ));
+var_dump($c['a']->isCompressed(Phar::BZ2));
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.zip.php');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.zip');
+?>
+--EXPECTF--
+string(1) "a"
+bool(false)
+string(1) "b"
+bool(false)
+string(1) "c"
+bool(false)
+string(1) "a"
+bool(false)
+bool(true)
+string(1) "b"
+bool(false)
+bool(true)
+string(1) "c"
+bool(false)
+bool(true)
+string(1) "a"
+bool(false)
+bool(true)
+===DONE===
diff --git a/ext/phar/tests/zip/phar_oo_compressallgz.phpt b/ext/phar/tests/zip/phar_oo_compressallgz.phpt
new file mode 100644
index 0000000000..47dddac487
--- /dev/null
+++ b/ext/phar/tests/zip/phar_oo_compressallgz.phpt
@@ -0,0 +1,58 @@
+--TEST--
+Phar::compressFiles(Phar::GZ) zip format
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("zlib")) die("skip zlib not present"); ?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.zip.php';
+$pname = 'phar://' . $fname;
+
+$phar = new Phar($fname);
+$phar['a'] = 'a';
+$phar['b'] = 'b';
+$phar['c'] = 'c';
+
+var_dump(file_get_contents($pname . '/a'));
+var_dump($phar['a']->isCompressed());
+var_dump(file_get_contents($pname . '/b'));
+var_dump($phar['b']->isCompressed());
+var_dump(file_get_contents($pname . '/c'));
+var_dump($phar['c']->isCompressed());
+
+$phar->compressFiles(Phar::GZ);
+var_dump(file_get_contents($pname . '/a'));
+var_dump($phar['a']->isCompressed(Phar::BZ2));
+var_dump($phar['a']->isCompressed(Phar::GZ));
+var_dump(file_get_contents($pname . '/b'));
+var_dump($phar['b']->isCompressed(Phar::BZ2));
+var_dump($phar['b']->isCompressed(Phar::GZ));
+var_dump(file_get_contents($pname . '/c'));
+var_dump($phar['b']->isCompressed(Phar::BZ2));
+var_dump($phar['c']->isCompressed(Phar::GZ));
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.zip.php');
+?>
+--EXPECTF--
+string(1) "a"
+bool(false)
+string(1) "b"
+bool(false)
+string(1) "c"
+bool(false)
+string(1) "a"
+bool(false)
+bool(true)
+string(1) "b"
+bool(false)
+bool(true)
+string(1) "c"
+bool(false)
+bool(true)
+===DONE===
diff --git a/ext/phar/tests/zip/phar_setalias.phpt b/ext/phar/tests/zip/phar_setalias.phpt
new file mode 100644
index 0000000000..1a39633863
--- /dev/null
+++ b/ext/phar/tests/zip/phar_setalias.phpt
@@ -0,0 +1,62 @@
+--TEST--
+Phar::setAlias() zip-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("zlib")) die("skip no zlib"); ?>
+<?php if (!extension_loaded("bz2")) die("skip no bz2"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.zip';
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '2.phar.zip';
+$fname3 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '3.phar.zip';
+
+$phar = new Phar($fname);
+$phar->setStub('<?php echo "first stub\n"; __HALT_COMPILER(); ?>');
+$phar->setAlias('hio');
+
+$files = array();
+
+$files['a'] = 'a';
+$files['b'] = 'b';
+$files['c'] = 'c';
+
+foreach ($files as $n => $file) {
+ $phar[$n] = $file;
+}
+$phar->stopBuffering();
+
+echo $phar->getAlias() . "\n";
+$phar->setAlias('test');
+echo $phar->getAlias() . "\n";
+
+// test compression
+
+$phar->compressFiles(Phar::GZ);
+copy($fname, $fname2);
+$phar->setAlias('unused');
+$p2 = new Phar($fname2);
+echo $p2->getAlias(), "\n";
+$p2->compressFiles(Phar::BZ2);
+copy($fname2, $fname3);
+$p2->setAlias('unused2');
+$p3 = new Phar($fname3);
+echo $p3->getAlias(), "\n";
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.zip');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '2.phar.zip');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '3.phar.zip');
+__HALT_COMPILER();
+?>
+--EXPECT--
+hio
+test
+test
+test
+===DONE===
diff --git a/ext/phar/tests/zip/phar_setalias2.phpt b/ext/phar/tests/zip/phar_setalias2.phpt
new file mode 100644
index 0000000000..c89f4c777a
--- /dev/null
+++ b/ext/phar/tests/zip/phar_setalias2.phpt
@@ -0,0 +1,49 @@
+--TEST--
+Phar::setAlias() error zip-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.zip';
+
+$phar = new Phar($fname);
+$phar->setStub('<?php echo "first stub\n"; __HALT_COMPILER(); ?>');
+$phar->setAlias('hio');
+
+$files = array();
+
+$files['a'] = 'a';
+$files['b'] = 'b';
+$files['c'] = 'c';
+
+foreach ($files as $n => $file) {
+ $phar[$n] = $file;
+}
+$phar->stopBuffering();
+
+echo $phar->getAlias() . "\n";
+$phar->setAlias('test');
+echo $phar->getAlias() . "\n";
+$b = $phar;
+$phar = new Phar(dirname(__FILE__) . '/notphar.phar');
+try {
+ $phar->setAlias('test');
+} catch (Exception $e) {
+ echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.zip');
+__HALT_COMPILER();
+?>
+--EXPECTF--
+hio
+test
+alias "test" is already used for archive "%sphar_setalias2.phar.zip" and cannot be used for other archives
+===DONE===
diff --git a/ext/phar/tests/zip/phar_setdefaultstub.phpt b/ext/phar/tests/zip/phar_setdefaultstub.phpt
new file mode 100644
index 0000000000..e21d764487
--- /dev/null
+++ b/ext/phar/tests/zip/phar_setdefaultstub.phpt
@@ -0,0 +1,80 @@
+--TEST--
+Phar: Phar::setDefaultStub() with and without arg, zip-based phar
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.zip';
+
+$phar = new Phar($fname);
+$phar['a.php'] = '<php echo "this is a\n"; ?>';
+$phar['b.php'] = '<php echo "this is b\n"; ?>';
+$phar->setStub('<?php echo "Hello World\n"; __HALT_COMPILER(); ?>');
+
+var_dump($phar->getStub());
+
+echo "============================================================================\n";
+echo "============================================================================\n";
+
+try {
+ $phar->setDefaultStub();
+ $phar->stopBuffering();
+} catch(Exception $e) {
+ echo $e->getMessage(). "\n";
+}
+
+var_dump($phar->getStub());
+
+echo "============================================================================\n";
+echo "============================================================================\n";
+
+try {
+ $phar->setDefaultStub('my/custom/thingy.php');
+ $phar->stopBuffering();
+} catch(Exception $e) {
+ echo $e->getMessage(). "\n";
+}
+
+var_dump($phar->getStub());
+
+echo "============================================================================\n";
+echo "============================================================================\n";
+
+try {
+ $phar->setDefaultStub('my/custom/thingy.php', 'the/web.php');
+ $phar->stopBuffering();
+} catch(Exception $e) {
+ echo $e->getMessage(). "\n";
+}
+
+var_dump($phar->getStub());
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.zip');
+?>
+--EXPECTF--
+string(51) "<?php echo "Hello World\n"; __HALT_COMPILER(); ?>
+"
+============================================================================
+============================================================================
+string(60) "<?php // zip-based phar archive stub file
+__HALT_COMPILER();"
+============================================================================
+============================================================================
+
+Warning: Phar::setDefaultStub(): method accepts no arguments for a tar- or zip-based phar stub, 1 given in %sphar_setdefaultstub.php on line %d
+string(60) "<?php // zip-based phar archive stub file
+__HALT_COMPILER();"
+============================================================================
+============================================================================
+
+Warning: Phar::setDefaultStub(): method accepts no arguments for a tar- or zip-based phar stub, 2 given in %sphar_setdefaultstub.php on line %d
+string(60) "<?php // zip-based phar archive stub file
+__HALT_COMPILER();"
+===DONE===
diff --git a/ext/phar/tests/zip/phar_stub.phpt b/ext/phar/tests/zip/phar_stub.phpt
new file mode 100644
index 0000000000..a2a6aa6f2a
--- /dev/null
+++ b/ext/phar/tests/zip/phar_stub.phpt
@@ -0,0 +1,75 @@
+--TEST--
+Phar::setStub() (zip-based)
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.2.phar.zip.php';
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.zip.php';
+$pname = 'phar://' . $fname;
+$pname2 = 'phar://' . $fname2;
+
+$p = new Phar($pname2);
+$p->setStub('<?php echo "first stub\n"; __HALT_COMPILER(); ?>');
+$p['a'] = 'a';
+$p['b'] = 'b';
+$p['c'] = 'c';
+copy($fname2, $fname);
+
+$phar = new Phar($fname);
+echo $phar->getStub();
+
+$file = '<?php echo "second stub\n"; __HALT_COMPILER(); ?>';
+
+//// 2
+$phar->setStub($file);
+echo $phar->getStub();
+
+$fname3 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phartmp.php';
+$file = '<?php echo "third stub\n"; __HALT_COMPILER(); ?>';
+$fp = fopen($fname3, 'wb');
+fwrite($fp, $file);
+fclose($fp);
+$fp = fopen($fname3, 'rb');
+
+//// 3
+$phar->setStub($fp);
+fclose($fp);
+
+echo $phar->getStub();
+
+$fp = fopen($fname3, 'ab');
+fwrite($fp, 'booya');
+fclose($fp);
+echo file_get_contents($fname3) . "\n";
+
+$fp = fopen($fname3, 'rb');
+
+//// 4
+$phar->setStub($fp, strlen($file));
+fclose($fp);
+echo $phar->getStub();
+
+$phar['testing'] = 'hi';
+
+echo $phar->getStub();
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.zip.php');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.2.phar.zip.php');
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phartmp.php');
+__HALT_COMPILER();
+?>
+--EXPECT--
+<?php echo "first stub\n"; __HALT_COMPILER(); ?>
+<?php echo "second stub\n"; __HALT_COMPILER(); ?>
+<?php echo "third stub\n"; __HALT_COMPILER(); ?>
+<?php echo "third stub\n"; __HALT_COMPILER(); ?>booya
+<?php echo "third stub\n"; __HALT_COMPILER(); ?>
+<?php echo "third stub\n"; __HALT_COMPILER(); ?>
+===DONE===
diff --git a/ext/phar/tests/zip/phar_stub_error.phpt b/ext/phar/tests/zip/phar_stub_error.phpt
new file mode 100755
index 0000000000..268130df40
--- /dev/null
+++ b/ext/phar/tests/zip/phar_stub_error.phpt
@@ -0,0 +1,58 @@
+--TEST--
+Phar::setStub()/getStub() zip-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.zip';
+
+$phar = new Phar($fname);
+$phar->setStub($stub = '<?php echo "first stub\n"; __HALT_COMPILER(); ?>' . "\r\n");
+$phar->setAlias('hio');
+$phar['a'] = 'a';
+$phar->stopBuffering();
+
+var_dump($stub);
+var_dump($phar->getStub());
+var_dump($phar->getStub() == $stub);
+
+$newstub = '<?php echo "second stub\n"; _x_HALT_COMPILER(); ?>';
+try
+{
+ $phar->setStub($newstub);
+}
+catch(exception $e)
+{
+ echo 'Exception: ' . $e->getMessage() . "\n";
+}
+var_dump($phar->getStub());
+var_dump($phar->getStub() == $stub);
+$phar->stopBuffering();
+var_dump($phar->getStub());
+var_dump($phar->getStub() == $stub);
+
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.zip');
+__HALT_COMPILER();
+?>
+--EXPECTF--
+string(50) "<?php echo "first stub\n"; __HALT_COMPILER(); ?>
+"
+string(50) "<?php echo "first stub\n"; __HALT_COMPILER(); ?>
+"
+bool(true)
+Exception: illegal stub for zip-based phar "%sphar_stub_error.phar.zip"
+string(50) "<?php echo "first stub\n"; __HALT_COMPILER(); ?>
+"
+bool(true)
+string(50) "<?php echo "first stub\n"; __HALT_COMPILER(); ?>
+"
+bool(true)
+===DONE===
diff --git a/ext/phar/tests/zip/refcount1.phpt b/ext/phar/tests/zip/refcount1.phpt
new file mode 100644
index 0000000000..6d7b7420c6
--- /dev/null
+++ b/ext/phar/tests/zip/refcount1.phpt
@@ -0,0 +1,70 @@
+--TEST--
+Phar: test that refcounting avoids problems with deleting a file zip-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+<?php if (version_compare(PHP_VERSION, "5.3", "<")) die("skip requires 5.3 or later"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.zip';
+$alias = 'phar://' . $fname;
+
+$phar = new Phar($fname);
+$phar->setStub("<?php __HALT_COMPILER(); ?>");
+$phar->setAlias('hio');
+
+$files = array();
+
+$files['a.php'] = '<?php echo "This is a\n"; ?>';
+$files['b.php'] = '<?php echo "This is b\n"; ?>';
+$files['b/c.php'] = '<?php echo "This is b/c\n"; ?>';
+
+foreach ($files as $n => $file) {
+ $phar[$n] = $file;
+}
+$phar->stopBuffering();
+
+$fp = fopen($alias . '/b/c.php', 'wb');
+fwrite($fp, "extra");
+fclose($fp);
+echo "===CLOSE===\n";
+$b = fopen($alias . '/b/c.php', 'rb');
+$a = $phar['b/c.php'];
+var_dump($a);
+var_dump(fread($b, 20));
+rewind($b);
+echo "===UNLINK===\n";
+unlink($alias . '/b/c.php');
+var_dump($a);
+var_dump(fread($b, 20));
+include $alias . '/b/c.php';
+?>
+
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.zip'); ?>
+--EXPECTF--
+===CLOSE===
+object(PharFileInfo)#%d (2) {
+ ["pathName":"SplFileInfo":private]=>
+ string(%d) "phar://%srefcount1.phar.zip/b"
+ ["fileName":"SplFileInfo":private]=>
+ string(%d) "phar://%srefcount1.phar.zip/b/c.php"
+}
+string(5) "extra"
+===UNLINK===
+
+Warning: unlink(): phar error: "b/c.php" in phar "%srefcount1.phar.zip", has open file pointers, cannot unlink in %srefcount1.php on line %d
+object(PharFileInfo)#%d (2) {
+ ["pathName":"SplFileInfo":private]=>
+ string(%d) "phar://%srefcount1.phar.zip/b"
+ ["fileName":"SplFileInfo":private]=>
+ string(%s) "phar://%srefcount1.phar.zip/b/c.php"
+}
+string(5) "extra"
+extra
+===DONE===
diff --git a/ext/phar/tests/zip/refcount1_5_2.phpt b/ext/phar/tests/zip/refcount1_5_2.phpt
new file mode 100755
index 0000000000..f3b2771f44
--- /dev/null
+++ b/ext/phar/tests/zip/refcount1_5_2.phpt
@@ -0,0 +1,64 @@
+--TEST--
+Phar: test that refcounting avoids problems with deleting a file zip-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+<?php if (version_compare(PHP_VERSION, "5.3", ">")) die("skip requires 5.2 or earlier"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.zip';
+$alias = 'phar://' . $fname;
+
+$phar = new Phar($fname);
+$phar->setStub("<?php __HALT_COMPILER(); ?>");
+$phar->setAlias('hio');
+
+$files = array();
+
+$files['a.php'] = '<?php echo "This is a\n"; ?>';
+$files['b.php'] = '<?php echo "This is b\n"; ?>';
+$files['b/c.php'] = '<?php echo "This is b/c\n"; ?>';
+
+foreach ($files as $n => $file) {
+ $phar[$n] = $file;
+}
+$phar->stopBuffering();
+
+$fp = fopen($alias . '/b/c.php', 'wb');
+fwrite($fp, "extra");
+fclose($fp);
+
+echo "===CLOSE===\n";
+
+$b = fopen($alias . '/b/c.php', 'rb');
+$a = $phar['b/c.php'];
+var_dump($a);
+var_dump(fread($b, 20));
+rewind($b);
+echo "===UNLINK===\n";
+unlink($alias . '/b/c.php');
+var_dump($a);
+var_dump(fread($b, 20));
+include $alias . '/b/c.php';
+?>
+
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.zip'); ?>
+--EXPECTF--
+===CLOSE===
+object(PharFileInfo)#%d (0) {
+}
+string(5) "extra"
+===UNLINK===
+
+Warning: unlink(): phar error: "b/c.php" in phar "%sefcount1_5_2.phar.zip", has open file pointers, cannot unlink in %sefcount1_5_2.php on line %d
+object(PharFileInfo)#%d (0) {
+}
+string(5) "extra"
+extra
+===DONE===
diff --git a/ext/phar/tests/zip/rename.phpt b/ext/phar/tests/zip/rename.phpt
new file mode 100644
index 0000000000..9b1f5c98cd
--- /dev/null
+++ b/ext/phar/tests/zip/rename.phpt
@@ -0,0 +1,34 @@
+--TEST--
+Phar: rename test zip-based
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+phar.require_hash=0
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.zip';
+$alias = 'phar://' . $fname;
+
+$phar = new Phar($fname);
+$phar->setStub("<?php
+Phar::mapPhar('hio');
+__HALT_COMPILER(); ?>");
+$phar['a'] = 'a';
+$phar->stopBuffering();
+
+include $fname;
+
+echo file_get_contents($alias . '/a') . "\n";
+rename($alias . '/a', $alias . '/b');
+echo file_get_contents($alias . '/b') . "\n";
+echo file_get_contents($alias . '/a') . "\n";
+?>
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.zip'); ?>
+--EXPECTF--
+a
+a
+
+Warning: file_get_contents(phar://%srename.phar.zip/a): failed to open stream: phar error: "a" is not a file in phar "%srename.phar.zip" in %srename.php on line %d \ No newline at end of file
diff --git a/ext/phar/tests/zip/unixzip.phpt b/ext/phar/tests/zip/unixzip.phpt
new file mode 100644
index 0000000000..374489d013
--- /dev/null
+++ b/ext/phar/tests/zip/unixzip.phpt
@@ -0,0 +1,26 @@
+--TEST--
+Phar: test a zip archive created by unix "zip" command
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+--FILE--
+<?php
+$a = new PharData(dirname(__FILE__) . '/files/zip.zip');
+foreach ($a as $b) {
+ if ($b->isDir()) {
+ echo "dir " . $b->getPathName() . "\n";
+ } else {
+ echo $b->getPathName() . "\n";
+ }
+}
+if (isset($a['notempty/hi.txt'])) {
+ echo $a['notempty/hi.txt']->getPathName() . "\n";
+}
+?>
+===DONE===
+--EXPECTF--
+dir phar://%szip.zip%cempty
+phar://%szip.zip%chi.txt
+dir phar://%szip.zip%cnotempty
+phar://%szip.zip/notempty/hi.txt
+===DONE===
diff --git a/ext/phar/util.c b/ext/phar/util.c
new file mode 100644
index 0000000000..77e83098a4
--- /dev/null
+++ b/ext/phar/util.c
@@ -0,0 +1,1296 @@
+/*
+ +----------------------------------------------------------------------+
+ | phar php single-file executable PHP extension |
+ | utility functions |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 2005-2008 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt. |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gregory Beaver <cellog@php.net> |
+ | Marcus Boerger <helly@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#include "phar_internal.h"
+#if !defined(PHP_VERSION_ID) || PHP_VERSION_ID < 50300
+extern php_stream_wrapper php_stream_phar_wrapper;
+#endif
+
+/* for links to relative location, prepend cwd of the entry */
+static char *phar_get_link_location(phar_entry_info *entry TSRMLS_DC)
+{
+ char *p, *ret = NULL;
+ if (!entry->link) {
+ return NULL;
+ }
+ if (entry->link[0] == '/') {
+ return estrdup(entry->link + 1);
+ }
+ p = strrchr(entry->filename, '/');
+ if (p) {
+ *p = '\0';
+ spprintf(&ret, 0, "%s/%s", entry->filename, entry->link);
+ return ret;
+ }
+ return entry->link;
+}
+
+phar_entry_info *phar_get_link_source(phar_entry_info *entry TSRMLS_DC)
+{
+ phar_entry_info *link_entry;
+ char *link = phar_get_link_location(entry TSRMLS_CC);
+
+ if (!entry->link) {
+ return entry;
+ }
+
+ if (SUCCESS == zend_hash_find(&(entry->phar->manifest), entry->link, strlen(entry->link), (void **)&link_entry) ||
+ SUCCESS == zend_hash_find(&(entry->phar->manifest), link, strlen(link), (void **)&link_entry)) {
+ if (link != entry->link) {
+ efree(link);
+ }
+ return phar_get_link_source(link_entry TSRMLS_CC);
+ } else {
+ if (link != entry->link) {
+ efree(link);
+ }
+ return NULL;
+ }
+}
+
+/* retrieve a phar_entry_info's current file pointer for reading contents */
+php_stream *phar_get_efp(phar_entry_info *entry, int follow_links TSRMLS_DC)
+{
+ if (follow_links && entry->link) {
+ phar_entry_info *link_entry = phar_get_link_source(entry TSRMLS_CC);
+
+ if (link_entry && link_entry != entry) {
+ return phar_get_efp(link_entry, 1 TSRMLS_CC);
+ }
+ }
+ if (entry->fp_type == PHAR_FP) {
+ if (!entry->phar->fp) {
+ /* re-open just in time for cases where our refcount reached 0 on the phar archive */
+ phar_open_archive_fp(entry->phar TSRMLS_CC);
+ }
+ return entry->phar->fp;
+ } else if (entry->fp_type == PHAR_UFP) {
+ return entry->phar->ufp;
+ } else if (entry->fp_type == PHAR_MOD) {
+ return entry->fp;
+ } else {
+ /* temporary manifest entry */
+ if (!entry->fp) {
+ entry->fp = php_stream_open_wrapper(entry->tmp, "rb", STREAM_MUST_SEEK|0, NULL);
+ }
+ return entry->fp;
+ }
+}
+
+int phar_seek_efp(phar_entry_info *entry, off_t offset, int whence, off_t position, int follow_links TSRMLS_DC)
+{
+ php_stream *fp = phar_get_efp(entry, follow_links TSRMLS_CC);
+ off_t temp;
+
+ if (!fp) {
+ return -1;
+ }
+ if (follow_links) {
+ phar_entry_info *t;
+ t = phar_get_link_source(entry TSRMLS_CC);
+ if (t) {
+ entry = t;
+ }
+ }
+ if (entry->is_dir) {
+ return 0;
+ }
+ switch (whence) {
+ case SEEK_END :
+ temp = entry->offset + entry->uncompressed_filesize + offset;
+ break;
+ case SEEK_CUR :
+ temp = entry->offset + position + offset;
+ break;
+ case SEEK_SET :
+ temp = entry->offset + offset;
+ break;
+ }
+ if (temp > entry->offset + (off_t) entry->uncompressed_filesize) {
+ return -1;
+ }
+ if (temp < entry->offset) {
+ return -1;
+ }
+ return php_stream_seek(fp, temp, SEEK_SET);
+}
+
+/* mount an absolute path or uri to a path internal to the phar archive */
+int phar_mount_entry(phar_archive_data *phar, char *filename, int filename_len, char *path, int path_len TSRMLS_DC)
+{
+ phar_entry_info entry = {0};
+ php_stream_statbuf ssb;
+ int is_phar;
+ const char *err;
+
+ if (phar_path_check(&path, &path_len, &err) > pcr_is_ok) {
+ return FAILURE;
+ }
+
+ is_phar = (filename_len > 7 && !memcmp(filename, "phar://", 7));
+
+ entry.phar = phar;
+ entry.filename = estrndup(path, path_len);
+#ifdef PHP_WIN32
+ phar_unixify_path_separators(entry.filename, path_len);
+#endif
+ entry.filename_len = path_len;
+ if (is_phar) {
+ entry.tmp = estrndup(filename, filename_len);
+ } else {
+ entry.tmp = expand_filepath(filename, NULL TSRMLS_CC);
+ if (!entry.tmp) {
+ entry.tmp = estrndup(filename, filename_len);
+ }
+ }
+#if PHP_MAJOR_VERSION < 6
+ if (PG(safe_mode) && !is_phar && (!php_checkuid(entry.tmp, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
+ efree(entry.tmp);
+ efree(entry.filename);
+ return FAILURE;
+ }
+#endif
+
+ filename_len = strlen(entry.tmp);
+ filename = entry.tmp;
+ /* only check openbasedir for files, not for phar streams */
+ if (!is_phar && php_check_open_basedir(filename TSRMLS_CC)) {
+ efree(entry.tmp);
+ efree(entry.filename);
+ return FAILURE;
+ }
+ entry.is_mounted = 1;
+ entry.is_crc_checked = 1;
+ entry.fp_type = PHAR_TMP;
+
+ if (SUCCESS != php_stream_stat_path(filename, &ssb)) {
+ efree(entry.tmp);
+ efree(entry.filename);
+ return FAILURE;
+ }
+ if (ssb.sb.st_mode & S_IFDIR) {
+ entry.is_dir = 1;
+ if (SUCCESS != zend_hash_add(&phar->mounted_dirs, entry.filename, path_len, (void *)&(entry.filename), sizeof(char *), NULL)) {
+ /* directory already mounted */
+ efree(entry.tmp);
+ efree(entry.filename);
+ return FAILURE;
+ }
+ } else {
+ entry.is_dir = 0;
+ entry.uncompressed_filesize = entry.compressed_filesize = ssb.sb.st_size;
+ }
+ entry.flags = ssb.sb.st_mode;
+ if (SUCCESS == zend_hash_add(&phar->manifest, entry.filename, path_len, (void*)&entry, sizeof(phar_entry_info), NULL)) {
+ return SUCCESS;
+ }
+ efree(entry.tmp);
+ efree(entry.filename);
+ return FAILURE;
+}
+
+char *phar_find_in_include_path(char *filename, int filename_len, phar_archive_data **pphar TSRMLS_DC) /* {{{ */
+{
+#if PHP_VERSION_ID >= 50300
+ char *path, *fname, *arch, *entry, *ret, *test;
+ int arch_len, entry_len, fname_len;
+
+ if (pphar) {
+ *pphar = NULL;
+ }
+
+ if (!zend_is_executing(TSRMLS_C) || !PHAR_G(cwd)) {
+ return phar_save_resolve_path(filename, filename_len TSRMLS_CC);
+ }
+ fname = zend_get_executed_filename(TSRMLS_C);
+ fname_len = strlen(fname);
+
+ if (fname_len < 7 || memcmp(fname, "phar://", 7) || SUCCESS != phar_split_fname(fname, strlen(fname), &arch, &arch_len, &entry, &entry_len, 1, 0 TSRMLS_CC)) {
+ return phar_save_resolve_path(filename, filename_len TSRMLS_CC);
+ }
+ efree(entry);
+ if (*filename == '.') {
+ int try_len;
+
+ if (SUCCESS != (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar))) {
+ efree(arch);
+ return phar_save_resolve_path(filename, filename_len TSRMLS_CC);
+ }
+ try_len = filename_len;
+ test = phar_fix_filepath(estrndup(filename, filename_len), &try_len, 1 TSRMLS_CC);
+ if (*test == '/') {
+ if (zend_hash_exists(&((*pphar)->manifest), test + 1, try_len - 1)) {
+ spprintf(&ret, 0, "phar://%s%s", arch, test);
+ efree(arch);
+ efree(test);
+ return ret;
+ }
+ } else {
+ if (zend_hash_exists(&((*pphar)->manifest), test, try_len)) {
+ spprintf(&ret, 0, "phar://%s/%s", arch, test);
+ efree(arch);
+ efree(test);
+ return ret;
+ }
+ }
+ }
+ spprintf(&path, MAXPATHLEN, "phar://%s/%s%c%s", arch, PHAR_G(cwd), DEFAULT_DIR_SEPARATOR, PG(include_path));
+ efree(arch);
+ ret = php_resolve_path(filename, filename_len, path TSRMLS_CC);
+ efree(path);
+ if (ret && strlen(ret) > 8 && !strncmp(ret, "phar://", 7)) {
+ char *arch;
+ int arch_len, ret_len;
+
+ ret_len = strlen(ret);
+ /* found phar:// */
+
+ if (SUCCESS != phar_split_fname(ret, ret_len, &arch, &arch_len, &entry, &entry_len, 1, 0 TSRMLS_CC)) {
+ return ret;
+ }
+ zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar);
+ efree(arch);
+ efree(entry);
+ }
+ return ret;
+#else /* PHP 5.2 */
+ char resolved_path[MAXPATHLEN];
+ char trypath[MAXPATHLEN];
+ char *ptr, *end, *path = PG(include_path);
+ php_stream_wrapper *wrapper;
+ const char *p;
+ int n = 0;
+ char *fname, *arch, *entry, *ret, *test;
+ int arch_len, entry_len;
+
+ if (!filename) {
+ return NULL;
+ }
+
+ if (!zend_is_executing(TSRMLS_C) || !PHAR_G(cwd)) {
+ goto doit;
+ }
+ fname = zend_get_executed_filename(TSRMLS_C);
+ if (SUCCESS != phar_split_fname(fname, strlen(fname), &arch, &arch_len, &entry, &entry_len, 1, 0 TSRMLS_CC)) {
+ goto doit;
+ }
+
+ efree(entry);
+ if (*filename == '.') {
+ phar_archive_data **pphar;
+ int try_len;
+
+ if (SUCCESS != (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar))) {
+ efree(arch);
+ goto doit;
+ }
+ try_len = filename_len;
+ test = phar_fix_filepath(estrndup(filename, filename_len), &try_len, 1 TSRMLS_CC);
+ if (*test == '/') {
+ if (zend_hash_exists(&((*pphar)->manifest), test + 1, try_len - 1)) {
+ spprintf(&ret, 0, "phar://%s%s", arch, test);
+ efree(arch);
+ efree(test);
+ return ret;
+ }
+ } else {
+ if (zend_hash_exists(&((*pphar)->manifest), test, try_len)) {
+ spprintf(&ret, 0, "phar://%s/%s", arch, test);
+ efree(arch);
+ efree(test);
+ return ret;
+ }
+ }
+ efree(test);
+ }
+ efree(arch);
+
+doit:
+ if (*filename == '.' ||
+ IS_ABSOLUTE_PATH(filename, filename_len) ||
+ !path ||
+ !*path) {
+ if (tsrm_realpath(filename, resolved_path TSRMLS_CC)) {
+ return estrdup(resolved_path);
+ } else {
+ return NULL;
+ }
+ }
+ /* test for stream wrappers and return */
+ for (p = filename; p - filename < filename_len && (isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'); ++p, ++n);
+ if (n < filename_len - 3 && (*p == ':') && (!strncmp("//", p+1, 2) || ( filename_len > 4 && !memcmp("data", filename, 4)))) {
+ /* found stream wrapper, this is an absolute path until stream wrappers implement realpath */
+ return estrndup(filename, filename_len);
+ }
+
+ ptr = (char *) path;
+ while (ptr && *ptr) {
+ int len, is_stream_wrapper = 0, maybe_stream = 1;
+
+ end = strchr(ptr, DEFAULT_DIR_SEPARATOR);
+#ifndef PHP_WIN32
+ /* search for stream wrapper */
+ if (end - ptr <= 1) {
+ maybe_stream = 0;
+ goto not_stream;
+ }
+ for (p = ptr, n = 0; p < end && (isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'); ++p, ++n);
+
+ if (n == end - ptr && *p && !strncmp("//", p+1, 2)) {
+ is_stream_wrapper = 1;
+ /* seek to real end of include_path portion */
+ end = strchr(end + 1, DEFAULT_DIR_SEPARATOR);
+ } else {
+ maybe_stream = 0;
+ }
+not_stream:
+#endif
+ if (end) {
+ if ((end-ptr) + 1 + filename_len + 1 >= MAXPATHLEN) {
+ ptr = end + 1;
+ continue;
+ }
+ memcpy(trypath, ptr, end-ptr);
+ len = end-ptr;
+ trypath[end-ptr] = '/';
+ memcpy(trypath+(end-ptr)+1, filename, filename_len+1);
+ ptr = end+1;
+ } else {
+ len = strlen(ptr);
+
+ if (len + 1 + filename_len + 1 >= MAXPATHLEN) {
+ break;
+ }
+ memcpy(trypath, ptr, len);
+ trypath[len] = '/';
+ memcpy(trypath+len+1, filename, filename_len+1);
+ ptr = NULL;
+ }
+
+ if (!is_stream_wrapper && maybe_stream) {
+ /* search for stream wrapper */
+ for (p = trypath, n = 0; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; ++p, ++n);
+ }
+
+ if (is_stream_wrapper || (n < len - 3 && (*p == ':') && (n > 1) && (!strncmp("//", p+1, 2) || !memcmp("data", trypath, 4)))) {
+ char *actual;
+
+ wrapper = php_stream_locate_url_wrapper(trypath, &actual, STREAM_OPEN_FOR_INCLUDE TSRMLS_CC);
+ if (wrapper == &php_plain_files_wrapper) {
+ strncpy(trypath, actual, MAXPATHLEN);
+ } else if (!wrapper) {
+ /* if wrapper is NULL, there was a mal-formed include_path stream wrapper, so skip this ptr */
+ continue;
+ } else {
+ if (wrapper->wops->url_stat) {
+ php_stream_statbuf ssb;
+
+ if (SUCCESS == wrapper->wops->url_stat(wrapper, trypath, 0, &ssb, NULL TSRMLS_CC)) {
+ if (wrapper == &php_stream_phar_wrapper) {
+ char *arch, *entry;
+ int arch_len, entry_len, ret_len;
+
+ ret_len = strlen(trypath);
+ /* found phar:// */
+
+ if (SUCCESS != phar_split_fname(trypath, ret_len, &arch, &arch_len, &entry, &entry_len, 1, 0 TSRMLS_CC)) {
+ return estrndup(trypath, ret_len);
+ }
+ zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar);
+ efree(arch);
+ efree(entry);
+ return estrndup(trypath, ret_len);
+ }
+ return estrdup(trypath);
+ }
+ }
+ continue;
+ }
+ }
+
+ if (tsrm_realpath(trypath, resolved_path TSRMLS_CC)) {
+ return estrdup(resolved_path);
+ }
+ } /* end provided path */
+
+ /* check in calling scripts' current working directory as a fall back case
+ */
+ if (zend_is_executing(TSRMLS_C)) {
+ char *exec_fname = zend_get_executed_filename(TSRMLS_C);
+ int exec_fname_length = strlen(exec_fname);
+ const char *p;
+ int n = 0;
+
+ while ((--exec_fname_length >= 0) && !IS_SLASH(exec_fname[exec_fname_length]));
+ if (exec_fname && exec_fname[0] != '[' &&
+ exec_fname_length > 0 &&
+ exec_fname_length + 1 + filename_len + 1 < MAXPATHLEN) {
+ memcpy(trypath, exec_fname, exec_fname_length + 1);
+ memcpy(trypath+exec_fname_length + 1, filename, filename_len+1);
+
+ /* search for stream wrapper */
+ for (p = trypath; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; ++p, ++n);
+ if (n < exec_fname_length - 3 && (*p == ':') && (n > 1) && (!strncmp("//", p+1, 2) || !memcmp("data", trypath, 4))) {
+ char *actual;
+
+ wrapper = php_stream_locate_url_wrapper(trypath, &actual, STREAM_OPEN_FOR_INCLUDE TSRMLS_CC);
+ if (wrapper == &php_plain_files_wrapper) {
+ /* this should never technically happen, but we'll leave it here for completeness */
+ strncpy(trypath, actual, MAXPATHLEN);
+ } else if (!wrapper) {
+ /* if wrapper is NULL, there was a mal-formed include_path stream wrapper
+ this also should be impossible */
+ return NULL;
+ } else {
+ return estrdup(trypath);
+ }
+ }
+ if (tsrm_realpath(trypath, resolved_path TSRMLS_CC)) {
+ return estrdup(resolved_path);
+ }
+ }
+ }
+
+ return NULL;
+#endif /* PHP 5.2 */
+}
+/* }}} */
+
+/**
+ * Retrieve a copy of the file information on a single file within a phar, or null.
+ * This also transfers the open file pointer, if any, to the entry.
+ *
+ * If the file does not already exist, this will fail. Pre-existing files can be
+ * appended, truncated, or read. For read, if the entry is marked unmodified, it is
+ * assumed that the file pointer, if present, is opened for reading
+ */
+int phar_get_entry_data(phar_entry_data **ret, char *fname, int fname_len, char *path, int path_len, char *mode, char allow_dir, char **error TSRMLS_DC) /* {{{ */
+{
+ phar_archive_data *phar;
+ phar_entry_info *entry;
+ int for_write = mode[0] != 'r' || mode[1] == '+';
+ int for_append = mode[0] == 'a';
+ int for_create = mode[0] != 'r';
+ int for_trunc = mode[0] == 'w';
+
+ if (!ret) {
+ return FAILURE;
+ }
+ *ret = NULL;
+ if (error) {
+ *error = NULL;
+ }
+ if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, error TSRMLS_CC)) {
+ return FAILURE;
+ }
+ if (for_write && PHAR_G(readonly) && !phar->is_data) {
+ if (error) {
+ spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for writing, disabled by ini setting", path, fname);
+ }
+ return FAILURE;
+ }
+ if (!path_len) {
+ if (error) {
+ spprintf(error, 4096, "phar error: file \"\" in phar \"%s\" cannot be empty", fname);
+ }
+ return FAILURE;
+ }
+ if (allow_dir) {
+ if ((entry = phar_get_entry_info_dir(phar, path, path_len, allow_dir, for_create && !PHAR_G(readonly) && !phar->is_data ? NULL : error TSRMLS_CC)) == NULL) {
+ if (for_create && (!PHAR_G(readonly) || phar->is_data)) {
+ return SUCCESS;
+ }
+ return FAILURE;
+ }
+ } else {
+ if ((entry = phar_get_entry_info(phar, path, path_len, for_create && !PHAR_G(readonly) && !phar->is_data ? NULL : error TSRMLS_CC)) == NULL) {
+ if (for_create && (!PHAR_G(readonly) || phar->is_data)) {
+ return SUCCESS;
+ }
+ return FAILURE;
+ }
+ }
+ if (entry->is_modified && !for_write) {
+ if (error) {
+ spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for reading, writable file pointers are open", path, fname);
+ }
+ return FAILURE;
+ }
+ if (entry->fp_refcount && for_write) {
+ if (error) {
+ spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for writing, readable file pointers are open", path, fname);
+ }
+ return FAILURE;
+ }
+ if (entry->is_deleted) {
+ if (!for_create) {
+ return FAILURE;
+ }
+ entry->is_deleted = 0;
+ }
+ if (entry->is_dir) {
+ *ret = (phar_entry_data *) emalloc(sizeof(phar_entry_data));
+ (*ret)->position = 0;
+ (*ret)->fp = NULL;
+ (*ret)->phar = phar;
+ (*ret)->for_write = for_write;
+ (*ret)->internal_file = entry;
+ (*ret)->is_zip = entry->is_zip;
+ (*ret)->is_tar = entry->is_tar;
+ ++(entry->phar->refcount);
+ ++(entry->fp_refcount);
+ return SUCCESS;
+ }
+ if (entry->fp_type == PHAR_MOD) {
+ if (for_trunc) {
+ if (FAILURE == phar_create_writeable_entry(phar, entry, error TSRMLS_CC)) {
+ return FAILURE;
+ }
+ } else if (for_append) {
+ phar_seek_efp(entry, 0, SEEK_END, 0, 0 TSRMLS_CC);
+ }
+ } else {
+ if (entry->link) {
+ efree(entry->link);
+ entry->link = NULL;
+ entry->tar_type = (entry->tar_type ? TAR_FILE : 0);
+ }
+ if (for_write) {
+ if (for_trunc) {
+ if (FAILURE == phar_create_writeable_entry(phar, entry, error TSRMLS_CC)) {
+ return FAILURE;
+ }
+ } else {
+ if (FAILURE == phar_separate_entry_fp(entry, error TSRMLS_CC)) {
+ return FAILURE;
+ }
+ }
+ } else {
+ if (FAILURE == phar_open_entry_fp(entry, error, 1 TSRMLS_CC)) {
+ return FAILURE;
+ }
+ }
+ }
+ *ret = (phar_entry_data *) emalloc(sizeof(phar_entry_data));
+ (*ret)->position = 0;
+ (*ret)->phar = phar;
+ (*ret)->for_write = for_write;
+ (*ret)->internal_file = entry;
+ (*ret)->is_zip = entry->is_zip;
+ (*ret)->is_tar = entry->is_tar;
+ (*ret)->fp = phar_get_efp(entry, 1 TSRMLS_CC);
+ (*ret)->zero = entry->offset;
+ ++(entry->fp_refcount);
+ ++(entry->phar->refcount);
+ return SUCCESS;
+}
+/* }}} */
+
+/**
+ * Create a new dummy file slot within a writeable phar for a newly created file
+ */
+phar_entry_data *phar_get_or_create_entry_data(char *fname, int fname_len, char *path, int path_len, char *mode, char allow_dir, char **error TSRMLS_DC) /* {{{ */
+{
+ phar_archive_data *phar;
+ phar_entry_info *entry, etemp;
+ phar_entry_data *ret;
+ const char *pcr_error;
+ char is_dir;
+
+#ifdef PHP_WIN32
+ phar_unixify_path_separators(path, path_len);
+#endif
+
+ is_dir = (path_len > 0 && path != NULL) ? path[path_len - 1] == '/' : 0;
+
+ if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, error TSRMLS_CC)) {
+ return NULL;
+ }
+
+ if (FAILURE == phar_get_entry_data(&ret, fname, fname_len, path, path_len, mode, allow_dir, error TSRMLS_CC)) {
+ return NULL;
+ } else if (ret) {
+ return ret;
+ }
+
+ if (phar_path_check(&path, &path_len, &pcr_error) > pcr_is_ok) {
+ if (error) {
+ spprintf(error, 0, "phar error: invalid path \"%s\" contains %s", path, pcr_error);
+ }
+ return NULL;
+ }
+
+ /* create a new phar data holder */
+ ret = (phar_entry_data *) emalloc(sizeof(phar_entry_data));
+
+ /* create an entry, this is a new file */
+ memset(&etemp, 0, sizeof(phar_entry_info));
+ etemp.filename_len = path_len;
+ etemp.fp_type = PHAR_MOD;
+ etemp.fp = php_stream_fopen_tmpfile();
+ if (!etemp.fp) {
+ if (error) {
+ spprintf(error, 0, "phar error: unable to create temporary file");
+ }
+ return NULL;
+ }
+ etemp.fp_refcount = 1;
+
+ if (allow_dir == 2) {
+ etemp.is_dir = 1;
+ etemp.flags = etemp.old_flags = PHAR_ENT_PERM_DEF_DIR;
+ if (is_dir) {
+ etemp.filename_len--; /* strip trailing / */
+ path_len--;
+ }
+ } else {
+ etemp.flags = etemp.old_flags = PHAR_ENT_PERM_DEF_FILE;
+ }
+ etemp.is_modified = 1;
+ etemp.timestamp = time(0);
+ etemp.is_crc_checked = 1;
+ etemp.phar = phar;
+ etemp.filename = estrndup(path, path_len);
+ etemp.is_zip = phar->is_zip;
+ if (phar->is_tar) {
+ etemp.is_tar = phar->is_tar;
+ etemp.tar_type = TAR_FILE;
+ }
+ if (FAILURE == zend_hash_add(&phar->manifest, etemp.filename, path_len, (void*)&etemp, sizeof(phar_entry_info), (void **) &entry)) {
+ if (error) {
+ spprintf(error, 0, "phar error: unable to add new entry \"%s\" to phar \"%s\"", etemp.filename, phar->fname);
+ }
+ return NULL;
+ }
+
+ if (!entry) {
+ php_stream_close(etemp.fp);
+ efree(etemp.filename);
+ return NULL;
+ }
+
+ ++(phar->refcount);
+ ret->phar = phar;
+ ret->fp = entry->fp;
+ ret->position = ret->zero = 0;
+ ret->for_write = 1;
+ ret->is_zip = entry->is_zip;
+ ret->is_tar = entry->is_tar;
+ ret->internal_file = entry;
+ return ret;
+}
+/* }}} */
+
+/* initialize a phar_archive_data's read-only fp for existing phar data */
+int phar_open_archive_fp(phar_archive_data *phar TSRMLS_DC)
+{
+ if (phar->fp) {
+ return SUCCESS;
+ }
+
+#if PHP_MAJOR_VERSION < 6
+ if (PG(safe_mode) && (!php_checkuid(phar->fname, NULL, CHECKUID_ALLOW_ONLY_FILE))) {
+ return FAILURE;
+ }
+#endif
+
+ if (php_check_open_basedir(phar->fname TSRMLS_CC)) {
+ return FAILURE;
+ }
+
+ phar->fp = php_stream_open_wrapper(phar->fname, "rb", IGNORE_URL|STREAM_MUST_SEEK|0, NULL);
+ if (!phar->fp) {
+ return FAILURE;
+ }
+ return SUCCESS;
+}
+
+/* copy file data from an existing to a new phar_entry_info that is not in the manifest */
+int phar_copy_entry_fp(phar_entry_info *source, phar_entry_info *dest, char **error TSRMLS_DC)
+{
+ phar_entry_info *link;
+
+ if (FAILURE == phar_open_entry_fp(source, error, 1 TSRMLS_CC)) {
+ return FAILURE;
+ }
+ if (dest->link) {
+ efree(dest->link);
+ dest->link = NULL;
+ dest->tar_type = (dest->tar_type ? TAR_FILE : 0);
+ }
+ dest->fp_type = PHAR_MOD;
+ dest->offset = 0;
+ dest->is_modified = 1;
+ dest->fp = php_stream_fopen_tmpfile();
+
+ phar_seek_efp(source, 0, SEEK_SET, 0, 1 TSRMLS_CC);
+ link = phar_get_link_source(source TSRMLS_CC);
+ if (!link) {
+ link = source;
+ }
+ if (link->uncompressed_filesize != php_stream_copy_to_stream(phar_get_efp(link, 0 TSRMLS_CC), dest->fp, link->uncompressed_filesize)) {
+ php_stream_close(dest->fp);
+ dest->fp_type = PHAR_FP;
+ if (error) {
+ spprintf(error, 4096, "phar error: unable to copy contents of file \"%s\" to \"%s\" in phar archive \"%s\"", source->filename, dest->filename, source->phar->fname);
+ }
+ return FAILURE;
+ }
+ return SUCCESS;
+}
+
+/* open and decompress a compressed phar entry
+ */
+int phar_open_entry_fp(phar_entry_info *entry, char **error, int follow_links TSRMLS_DC)
+{
+ php_stream_filter *filter;
+ phar_archive_data *phar = entry->phar;
+ char *filtername;
+ off_t loc;
+
+ if (follow_links && entry->link) {
+ phar_entry_info *link_entry = phar_get_link_source(entry TSRMLS_CC);
+
+ if (link_entry && link_entry != entry) {
+ return phar_open_entry_fp(link_entry, error, 1 TSRMLS_CC);
+ }
+ }
+ if (entry->fp_type == PHAR_TMP) {
+ if (!entry->fp) {
+ entry->fp = php_stream_open_wrapper(entry->tmp, "rb", STREAM_MUST_SEEK|0, NULL);
+ }
+ return SUCCESS;
+ }
+ if (entry->fp_type != PHAR_FP) {
+ /* either newly created or already modified */
+ return SUCCESS;
+ }
+ if (!phar->fp) {
+ if (FAILURE == phar_open_archive_fp(phar TSRMLS_CC)) {
+ spprintf(error, 4096, "phar error: Cannot open phar archive \"%s\" for reading", phar->fname);
+ return FAILURE;
+ }
+ }
+ if ((entry->old_flags && !(entry->old_flags & PHAR_ENT_COMPRESSION_MASK)) || !(entry->flags & PHAR_ENT_COMPRESSION_MASK)) {
+ return SUCCESS;
+ }
+ if (!phar->ufp) {
+ phar->ufp = php_stream_fopen_tmpfile();
+ if (!phar->ufp) {
+ spprintf(error, 4096, "phar error: Cannot open temporary file for decompressing phar archive \"%s\" file \"%s\"", phar->fname, entry->filename);
+ return FAILURE;
+ }
+ }
+
+ if ((filtername = phar_decompress_filter(entry, 0)) != NULL) {
+ filter = php_stream_filter_create(filtername, NULL, php_stream_is_persistent(phar->ufp) TSRMLS_CC);
+ } else {
+ filter = NULL;
+ }
+ if (!filter) {
+ spprintf(error, 4096, "phar error: unable to read phar \"%s\" (cannot create %s filter while decompressing file \"%s\")", phar->fname, phar_decompress_filter(entry, 1), entry->filename);
+ return FAILURE;
+ }
+ /* now we can safely use proper decompression */
+ /* save the new offset location within ufp */
+ php_stream_seek(phar->ufp, 0, SEEK_END);
+ loc = php_stream_tell(phar->ufp);
+ php_stream_filter_append(&phar->ufp->writefilters, filter);
+ php_stream_seek(phar->fp, entry->offset, SEEK_SET);
+ if (php_stream_copy_to_stream(phar->fp, phar->ufp, entry->compressed_filesize) != entry->compressed_filesize) {
+ spprintf(error, 4096, "phar error: internal corruption of phar \"%s\" (actual filesize mismatch on file \"%s\")", phar->fname, entry->filename);
+ php_stream_filter_remove(filter, 1 TSRMLS_CC);
+ return FAILURE;
+ }
+ php_stream_filter_flush(filter, 1);
+ php_stream_flush(phar->ufp);
+ php_stream_filter_remove(filter, 1 TSRMLS_CC);
+ if (php_stream_tell(phar->ufp) - loc != (off_t) entry->uncompressed_filesize) {
+ spprintf(error, 4096, "phar error: internal corruption of phar \"%s\" (actual filesize mismatch on file \"%s\")", phar->fname, entry->filename);
+ return FAILURE;
+ }
+
+ entry->old_flags = entry->flags;
+ entry->fp_type = PHAR_UFP;
+ /* this is now the new location of the file contents within this fp */
+ entry->offset = loc;
+
+ return SUCCESS;
+}
+
+#if defined(PHP_VERSION_ID) && PHP_VERSION_ID < 50202
+typedef struct {
+ char *data;
+ size_t fpos;
+ size_t fsize;
+ size_t smax;
+ int mode;
+ php_stream **owner_ptr;
+} php_stream_memory_data;
+#endif
+
+int phar_create_writeable_entry(phar_archive_data *phar, phar_entry_info *entry, char **error TSRMLS_DC) /* {{{ */
+{
+ if (entry->fp_type == PHAR_MOD) {
+ /* already newly created, truncate */
+#if PHP_VERSION_ID >= 50202
+ php_stream_truncate_set_size(entry->fp, 0);
+#else
+ if (php_stream_is(entry->fp, PHP_STREAM_IS_TEMP)) {
+ if (php_stream_is(*(php_stream**)entry->fp->abstract, PHP_STREAM_IS_MEMORY)) {
+ php_stream *inner = *(php_stream**)entry->fp->abstract;
+ php_stream_memory_data *memfp = (php_stream_memory_data*)inner->abstract;
+ memfp->fpos = 0;
+ memfp->fsize = 0;
+ } else if (php_stream_is(*(php_stream**)entry->fp->abstract, PHP_STREAM_IS_STDIO)) {
+ php_stream_truncate_set_size(*(php_stream**)entry->fp->abstract, 0);
+ } else {
+ if (error) {
+ spprintf(error, 0, "phar error: file \"%s\" cannot be opened for writing, no truncate support", phar->fname);
+ }
+ return FAILURE;
+ }
+ } else if (php_stream_is(entry->fp, PHP_STREAM_IS_STDIO)) {
+ php_stream_truncate_set_size(entry->fp, 0);
+ } else {
+ if (error) {
+ spprintf(error, 0, "phar error: file \"%s\" cannot be opened for writing, no truncate support", phar->fname);
+ }
+ return FAILURE;
+ }
+#endif
+ entry->old_flags = entry->flags;
+ entry->is_modified = 1;
+ phar->is_modified = 1;
+ /* reset file size */
+ entry->uncompressed_filesize = 0;
+ entry->compressed_filesize = 0;
+ entry->crc32 = 0;
+ entry->flags = PHAR_ENT_PERM_DEF_FILE;
+ entry->fp_type = PHAR_MOD;
+ entry->offset = 0;
+ return SUCCESS;
+ }
+ if (error) {
+ *error = NULL;
+ }
+ /* open a new temp file for writing */
+ if (entry->link) {
+ efree(entry->link);
+ entry->link = NULL;
+ entry->tar_type = (entry->tar_type ? TAR_FILE : 0);
+ }
+ entry->fp = php_stream_fopen_tmpfile();
+ if (!entry->fp) {
+ if (error) {
+ spprintf(error, 0, "phar error: unable to create temporary file");
+ }
+ return FAILURE;
+ }
+ entry->old_flags = entry->flags;
+ entry->is_modified = 1;
+ phar->is_modified = 1;
+ /* reset file size */
+ entry->uncompressed_filesize = 0;
+ entry->compressed_filesize = 0;
+ entry->crc32 = 0;
+ entry->flags = PHAR_ENT_PERM_DEF_FILE;
+ entry->fp_type = PHAR_MOD;
+ entry->offset = 0;
+ return SUCCESS;
+}
+/* }}} */
+
+int phar_separate_entry_fp(phar_entry_info *entry, char **error TSRMLS_DC)
+{
+ php_stream *fp;
+ phar_entry_info *link;
+
+ if (FAILURE == phar_open_entry_fp(entry, error, 1 TSRMLS_CC)) {
+ return FAILURE;
+ }
+
+ if (entry->fp_type == PHAR_MOD) {
+ return SUCCESS;
+ }
+
+ fp = php_stream_fopen_tmpfile();
+ phar_seek_efp(entry, 0, SEEK_SET, 0, 1 TSRMLS_CC);
+ link = phar_get_link_source(entry TSRMLS_CC);
+ if (!link) {
+ link = entry;
+ }
+ if (link->uncompressed_filesize != php_stream_copy_to_stream(phar_get_efp(link, 0 TSRMLS_CC), fp, link->uncompressed_filesize)) {
+ if (error) {
+ spprintf(error, 4096, "phar error: cannot separate entry file \"%s\" contents in phar archive \"%s\" for write access", entry->filename, entry->phar->fname);
+ }
+ return FAILURE;
+ }
+
+ if (entry->link) {
+ efree(entry->link);
+ entry->link = NULL;
+ entry->tar_type = (entry->tar_type ? TAR_FILE : 0);
+ }
+
+ entry->offset = 0;
+ entry->fp = fp;
+ entry->fp_type = PHAR_MOD;
+ entry->is_modified = 1;
+ return SUCCESS;
+}
+
+/**
+ * helper function to open an internal file's fp just-in-time
+ */
+phar_entry_info * phar_open_jit(phar_archive_data *phar, phar_entry_info *entry, php_stream *fp,
+ char **error, int for_write TSRMLS_DC)
+{
+ if (error) {
+ *error = NULL;
+ }
+ /* seek to start of internal file and read it */
+ if (FAILURE == phar_open_entry_fp(entry, error, 1 TSRMLS_CC)) {
+ return NULL;
+ }
+ if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 1 TSRMLS_CC)) {
+ spprintf(error, 4096, "phar error: cannot seek to start of file \"%s\" in phar \"%s\"", entry->filename, phar->fname);
+ return NULL;
+ }
+ return entry;
+}
+
+int phar_free_alias(phar_archive_data *phar, char *alias, int alias_len TSRMLS_DC) /* {{{ */
+{
+ if (phar->refcount) {
+ return FAILURE;
+ }
+ /* this archive has no open references, so emit an E_STRICT and remove it */
+ if (zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), phar->fname, phar->fname_len) != SUCCESS) {
+ return FAILURE;
+ }
+ return SUCCESS;
+}
+/* }}} */
+
+/**
+ * Looks up a phar archive in the filename map, connecting it to the alias
+ * (if any) or returns null
+ */
+int phar_get_archive(phar_archive_data **archive, char *fname, int fname_len, char *alias, int alias_len, char **error TSRMLS_DC) /* {{{ */
+{
+ phar_archive_data *fd, **fd_ptr;
+ char *my_realpath, *save;
+ int save_len;
+
+ phar_request_initialize(TSRMLS_C);
+
+ if (error) {
+ *error = NULL;
+ }
+ *archive = NULL;
+ if (alias && alias_len) {
+ if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void**)&fd_ptr)) {
+ if (fname && (fname_len != (*fd_ptr)->fname_len || strncmp(fname, (*fd_ptr)->fname, fname_len))) {
+ if (error) {
+ spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, (*fd_ptr)->fname, fname);
+ }
+ if (SUCCESS == phar_free_alias(*fd_ptr, alias, alias_len TSRMLS_CC)) {
+ efree(*error);
+ *error = NULL;
+ }
+ return FAILURE;
+ }
+ *archive = *fd_ptr;
+ return SUCCESS;
+ }
+ }
+ my_realpath = NULL;
+ save = fname;
+ save_len = fname_len;
+ if (fname && fname_len) {
+ if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len, (void**)&fd_ptr)) {
+ *archive = *fd_ptr;
+ fd = *fd_ptr;
+ if (alias && alias_len) {
+ if (!fd->is_temporary_alias && (alias_len != fd->alias_len || memcmp(fd->alias, alias, alias_len))) {
+ if (error) {
+ spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, (*fd_ptr)->fname, fname);
+ }
+ return FAILURE;
+ }
+ if (fd->alias_len && SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), fd->alias, fd->alias_len, (void**)&fd_ptr)) {
+ zend_hash_del(&(PHAR_GLOBALS->phar_alias_map), fd->alias, fd->alias_len);
+ }
+ zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void*)&fd, sizeof(phar_archive_data*), NULL);
+ }
+ return SUCCESS;
+ }
+ if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), save, save_len, (void**)&fd_ptr)) {
+ *archive = *fd_ptr;
+ return SUCCESS;
+ }
+
+ /* not found, try converting \ to / */
+ my_realpath = expand_filepath(fname, my_realpath TSRMLS_CC);
+ if (my_realpath) {
+ fname_len = strlen(my_realpath);
+ fname = my_realpath;
+ } else {
+ return FAILURE;
+ }
+#ifdef PHP_WIN32
+ phar_unixify_path_separators(fname, fname_len);
+#endif
+ if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len, (void**)&fd_ptr)) {
+ *archive = *fd_ptr;
+ fd = *fd_ptr;
+ if (alias && alias_len) {
+ zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void*)&fd, sizeof(phar_archive_data*), NULL);
+ }
+ efree(my_realpath);
+ return SUCCESS;
+ }
+ efree(my_realpath);
+ }
+ return FAILURE;
+}
+/* }}} */
+
+/**
+ * Determine which stream compression filter (if any) we need to read this file
+ */
+char * phar_compress_filter(phar_entry_info * entry, int return_unknown) /* {{{ */
+{
+ switch (entry->flags & PHAR_ENT_COMPRESSION_MASK) {
+ case PHAR_ENT_COMPRESSED_GZ:
+ return "zlib.deflate";
+ case PHAR_ENT_COMPRESSED_BZ2:
+ return "bzip2.compress";
+ default:
+ return return_unknown ? "unknown" : NULL;
+ }
+}
+/* }}} */
+
+/**
+ * Determine which stream decompression filter (if any) we need to read this file
+ */
+char * phar_decompress_filter(phar_entry_info * entry, int return_unknown) /* {{{ */
+{
+ php_uint32 flags;
+
+ if (entry->is_modified) {
+ flags = entry->old_flags;
+ } else {
+ flags = entry->flags;
+ }
+ switch (flags & PHAR_ENT_COMPRESSION_MASK) {
+ case PHAR_ENT_COMPRESSED_GZ:
+ return "zlib.inflate";
+ case PHAR_ENT_COMPRESSED_BZ2:
+ return "bzip2.decompress";
+ default:
+ return return_unknown ? "unknown" : NULL;
+ }
+}
+/* }}} */
+
+/**
+ * retrieve information on a file contained within a phar, or null if it ain't there
+ */
+phar_entry_info *phar_get_entry_info(phar_archive_data *phar, char *path, int path_len, char **error TSRMLS_DC) /* {{{ */
+{
+ return phar_get_entry_info_dir(phar, path, path_len, 0, error TSRMLS_CC);
+}
+/* }}} */
+/**
+ * retrieve information on a file or directory contained within a phar, or null if none found
+ * allow_dir is 0 for none, 1 for both empty directories in the phar and temp directories, and 2 for only
+ * valid pre-existing empty directory entries
+ */
+phar_entry_info *phar_get_entry_info_dir(phar_archive_data *phar, char *path, int path_len, char dir, char **error TSRMLS_DC) /* {{{ */
+{
+ const char *pcr_error;
+ phar_entry_info *entry;
+ char is_dir;
+
+#ifdef PHP_WIN32
+ phar_unixify_path_separators(path, path_len);
+#endif
+
+ is_dir = path_len && (path[path_len - 1] == '/');
+
+ if (error) {
+ *error = NULL;
+ }
+
+ if (!path_len && !dir) {
+ if (error) {
+ spprintf(error, 4096, "phar error: invalid path \"%s\" must not be empty", path);
+ }
+ return NULL;
+ }
+ if (phar_path_check(&path, &path_len, &pcr_error) > pcr_is_ok) {
+ if (error) {
+ spprintf(error, 4096, "phar error: invalid path \"%s\" contains %s", path, pcr_error);
+ }
+ return NULL;
+ }
+
+ if (!phar->manifest.arBuckets) {
+ return NULL;
+ }
+ if (is_dir) {
+ path_len--;
+ }
+ if (SUCCESS == zend_hash_find(&phar->manifest, path, path_len, (void**)&entry)) {
+ if (entry->is_deleted) {
+ /* entry is deleted, but has not been flushed to disk yet */
+ return NULL;
+ }
+ if (entry->is_dir && !dir) {
+ if (error) {
+ spprintf(error, 4096, "phar error: path \"%s\" is a directory", path);
+ }
+ return NULL;
+ }
+ if (!entry->is_dir && dir == 2) {
+ /* user requested a directory, we must return one */
+ if (error) {
+ spprintf(error, 4096, "phar error: path \"%s\" exists and is a not a directory", path);
+ }
+ return NULL;
+ }
+ return entry;
+ } else if (phar->mounted_dirs.arBuckets && zend_hash_num_elements(&phar->mounted_dirs)) {
+ char *key;
+ ulong unused;
+ uint keylen;
+
+ zend_hash_internal_pointer_reset(&phar->mounted_dirs);
+ while (FAILURE != zend_hash_has_more_elements(&phar->mounted_dirs)) {
+ if (HASH_KEY_NON_EXISTANT == zend_hash_get_current_key_ex(&phar->mounted_dirs, &key, &keylen, &unused, 0, NULL)) {
+ break;
+ }
+ if ((int)keylen >= path_len || strncmp(key, path, keylen)) {
+ continue;
+ } else {
+ char *test;
+ int test_len;
+ phar_entry_info *entry;
+ php_stream_statbuf ssb;
+
+ if (SUCCESS != zend_hash_find(&phar->manifest, key, keylen, (void **) &entry)) {
+ if (error) {
+ spprintf(error, 4096, "phar internal error: mounted path \"%s\" could not be retrieved from manifest", key);
+ }
+ return NULL;
+ }
+ if (!entry->tmp || !entry->is_mounted) {
+ if (error) {
+ spprintf(error, 4096, "phar internal error: mounted path \"%s\" is not properly initialized as a mounted path", key);
+ }
+ return NULL;
+ }
+ test_len = spprintf(&test, MAXPATHLEN, "%s%s", entry->tmp, path + keylen);
+ if (SUCCESS != php_stream_stat_path(test, &ssb)) {
+ efree(test);
+ return NULL;
+ }
+ if (ssb.sb.st_mode & S_IFDIR && !dir) {
+ efree(test);
+ if (error) {
+ spprintf(error, 4096, "phar error: path \"%s\" is a directory", path);
+ }
+ return NULL;
+ }
+ if ((ssb.sb.st_mode & S_IFDIR) == 0 && dir) {
+ efree(test);
+ /* user requested a directory, we must return one */
+ if (error) {
+ spprintf(error, 4096, "phar error: path \"%s\" exists and is a not a directory", path);
+ }
+ return NULL;
+ }
+ /* mount the file just in time */
+ if (SUCCESS != phar_mount_entry(phar, test, test_len, path, path_len TSRMLS_CC)) {
+ efree(test);
+ if (error) {
+ spprintf(error, 4096, "phar error: path \"%s\" exists as file \"%s\" and could not be mounted", path, test);
+ }
+ return NULL;
+ }
+ efree(test);
+ if (SUCCESS != zend_hash_find(&phar->manifest, path, path_len, (void**)&entry)) {
+ if (error) {
+ spprintf(error, 4096, "phar error: path \"%s\" exists as file \"%s\" and could not be retrieved after being mounted", path, test);
+ }
+ return NULL;
+ }
+ return entry;
+ }
+ }
+ }
+ if (dir) {
+ /* try to find a directory */
+ HashTable *manifest;
+ char *key;
+ uint keylen;
+ ulong unused;
+
+ if (!path_len) {
+ path = "/";
+ }
+ manifest = &phar->manifest;
+ zend_hash_internal_pointer_reset(manifest);
+ while (FAILURE != zend_hash_has_more_elements(manifest)) {
+ if (HASH_KEY_NON_EXISTANT == zend_hash_get_current_key_ex(manifest, &key, &keylen, &unused, 0, NULL)) {
+ break;
+ }
+ if (0 != memcmp(key, path, path_len)) {
+ /* entry in directory not found */
+ if (SUCCESS != zend_hash_move_forward(manifest)) {
+ break;
+ }
+ continue;
+ } else {
+ if (key[path_len] != '/') {
+ if (SUCCESS != zend_hash_move_forward(manifest)) {
+ break;
+ }
+ continue;
+ }
+ /* found a file in this path */
+ entry = (phar_entry_info *) ecalloc(1, sizeof(phar_entry_info));
+ /* this next line tells PharFileInfo->__destruct() to efree the filename */
+ entry->is_temp_dir = entry->is_dir = 1;
+ entry->filename = (char *) estrndup(path, path_len + 1);
+ entry->filename_len = path_len;
+ entry->phar = phar;
+ return entry;
+ }
+ }
+ }
+ return NULL;
+}
+/* }}} */
diff --git a/ext/phar/zip.c b/ext/phar/zip.c
new file mode 100644
index 0000000000..0261033ff9
--- /dev/null
+++ b/ext/phar/zip.c
@@ -0,0 +1,1100 @@
+/*
+ +----------------------------------------------------------------------+
+ | ZIP archive support for Phar |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 2007-2008 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt. |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Gregory Beaver <cellog@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#include "phar_internal.h"
+
+#ifdef WORDS_BIGENDIAN
+# define PHAR_GET_32(buffer) (((((unsigned char*)(buffer))[3]) << 24) \
+ | ((((unsigned char*)(buffer))[2]) << 16) \
+ | ((((unsigned char*)(buffer))[1]) << 8) \
+ | (((unsigned char*)(buffer))[0])))
+# define PHAR_GET_16(buffer) (((((unsigned char*)(buffer))[1]) << 8) \
+ | (((unsigned char*)(buffer))[0]))
+# define PHAR_SET_32(buffer) PHAR_GET_32(buffer)
+# define PHAR_SET_16(buffer) PHAR_GET_16(buffer)
+#else
+# define PHAR_GET_32(buffer) (buffer)
+# define PHAR_GET_16(buffer) (buffer)
+# define PHAR_SET_32(buffer) (buffer)
+# define PHAR_SET_16(buffer) (buffer)
+#endif
+
+static int phar_zip_process_extra(php_stream *fp, phar_entry_info *entry, php_uint16 len TSRMLS_DC)
+{
+ union {
+ phar_zip_extra_field_header header;
+ phar_zip_unix3 unix3;
+ } h;
+ int read;
+
+ do {
+ if (sizeof(h.header) != php_stream_read(fp, (char *) &h.header, sizeof(h.header))) {
+ return FAILURE;
+ }
+ if (h.header.tag[0] != 'n' || h.header.tag[1] != 'u') {
+ /* skip to next header */
+ php_stream_seek(fp, PHAR_GET_16(h.header.size), SEEK_CUR);
+ len -= PHAR_GET_16(h.header.size) + 4;
+ continue;
+ }
+ /* unix3 header found */
+ read = php_stream_read(fp, (char *) &(h.unix3.crc32), sizeof(h.unix3) - sizeof(h.header));
+ len -= read + 4;
+ if (sizeof(h.unix3) - sizeof(h.header) != read) {
+ return FAILURE;
+ }
+ if (PHAR_GET_16(h.unix3.size) > sizeof(h.unix3) - 4) {
+ /* skip symlink filename - we may add this support in later */
+ php_stream_seek(fp, h.unix3.size - sizeof(h.unix3.size), SEEK_CUR);
+ }
+ /* set permissions */
+ entry->flags &= PHAR_ENT_COMPRESSION_MASK;
+ if (entry->is_dir) {
+ entry->flags |= PHAR_GET_16(h.unix3.perms) & PHAR_ENT_PERM_MASK;
+ } else {
+ entry->flags |= PHAR_GET_16(h.unix3.perms) & PHAR_ENT_PERM_MASK;
+ }
+ } while (len);
+ return SUCCESS;
+}
+
+/*
+ extracted from libzip
+ zip_dirent.c -- read directory entry (local or central), clean dirent
+ Copyright (C) 1999, 2003, 2004, 2005 Dieter Baron and Thomas Klausner
+
+ This function is part of libzip, a library to manipulate ZIP archives.
+ The authors can be contacted at <nih@giga.or.at>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ 3. The names of the authors may not be used to endorse or promote
+ products derived from this software without specific prior
+ written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
+ OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+static time_t phar_zip_d2u_time(int dtime, int ddate)
+{
+ struct tm *tm, tmbuf;
+ time_t now;
+
+ now = time(NULL);
+ tm = php_localtime_r(&now, &tmbuf);
+
+ tm->tm_year = ((ddate>>9)&127) + 1980 - 1900;
+ tm->tm_mon = ((ddate>>5)&15) - 1;
+ tm->tm_mday = ddate&31;
+
+ tm->tm_hour = (dtime>>11)&31;
+ tm->tm_min = (dtime>>5)&63;
+ tm->tm_sec = (dtime<<1)&62;
+
+ return mktime(tm);
+}
+
+static void phar_zip_u2d_time(time_t time, php_uint16 *dtime, php_uint16 *ddate)
+{
+ struct tm *tm, tmbuf;
+
+ tm = php_localtime_r(&time, &tmbuf);
+ *ddate = ((tm->tm_year+1900-1980)<<9) + ((tm->tm_mon+1)<<5) + tm->tm_mday;
+ *dtime = ((tm->tm_hour)<<11) + ((tm->tm_min)<<5) + ((tm->tm_sec)>>1);
+}
+
+/**
+ * Does not check for a previously opened phar in the cache.
+ *
+ * Parse a new one and add it to the cache, returning either SUCCESS or
+ * FAILURE, and setting pphar to the pointer to the manifest entry
+ *
+ * This is used by phar_open_fp to process a zip-based phar, but can be called
+ * directly.
+ */
+int phar_open_zipfile(php_stream *fp, char *fname, int fname_len, char *alias, int alias_len, phar_archive_data** pphar, char **error TSRMLS_DC) /* {{{ */
+{
+ phar_zip_dir_end locator;
+ char buf[sizeof(locator) + 65536];
+ long size;
+ size_t read;
+ php_uint16 i;
+ phar_archive_data *mydata = NULL;
+ phar_entry_info entry = {0};
+ char *p = buf, *ext, *actual_alias = NULL;
+
+ size = php_stream_tell(fp);
+ if (size > sizeof(locator) + 65536) {
+ /* seek to max comment length + end of central directory record */
+ size = sizeof(locator) + 65536;
+ if (FAILURE == php_stream_seek(fp, -size, SEEK_END)) {
+ php_stream_close(fp);
+ if (error) {
+ spprintf(error, 4096, "phar error: unable to search for end of central directory in zip-based phar \"%s\"", fname);
+ }
+ return FAILURE;
+ }
+ } else {
+ php_stream_seek(fp, 0, SEEK_SET);
+ }
+ if (!(read = php_stream_read(fp, buf, size))) {
+ php_stream_close(fp);
+ if (error) {
+ spprintf(error, 4096, "phar error: unable to read in data to search for end of central directory in zip-based phar \"%s\"", fname);
+ }
+ return FAILURE;
+ }
+ while ((p=(char *) memchr(p + 1, 'P', (size_t) (size - (p + 1 - buf)))) != NULL) {
+ if (!memcmp(p + 1, "K\5\6", 3)) {
+ memcpy((void *)&locator, (void *) p, sizeof(locator));
+ if (locator.centraldisk != 0 || locator.disknumber != 0) {
+ /* split archives not handled */
+ php_stream_close(fp);
+ if (error) {
+ spprintf(error, 4096, "phar error: split archives spanning multiple zips cannot be processed in zip-based phar \"%s\"", fname);
+ }
+ return FAILURE;
+ }
+ if (locator.counthere != locator.count) {
+ if (error) {
+ spprintf(error, 4096, "phar error: corrupt zip archive, conflicting file count in end of central directory record in zip-based phar \"%s\"", fname);
+ }
+ php_stream_close(fp);
+ return FAILURE;
+ }
+ mydata = ecalloc(sizeof(phar_archive_data), 1);
+
+ /* read in archive comment, if any */
+ if (locator.comment_len) {
+ char *metadata;
+
+ metadata = p + sizeof(locator);
+ if (PHAR_GET_16(locator.comment_len) != size - (metadata - buf)) {
+ if (error) {
+ spprintf(error, 4096, "phar error: corrupt zip archive, zip file comment truncated in zip-based phar \"%s\"", fname);
+ }
+ php_stream_close(fp);
+ efree(mydata);
+ return FAILURE;
+ }
+ if (phar_parse_metadata(&metadata, &mydata->metadata, PHAR_GET_16(locator.comment_len) TSRMLS_CC) == FAILURE) {
+ /* if not valid serialized data, it is a regular string */
+ ALLOC_INIT_ZVAL(mydata->metadata);
+ ZVAL_STRINGL(mydata->metadata, metadata, PHAR_GET_16(locator.comment_len), 1);
+ }
+ } else {
+ mydata->metadata = NULL;
+ }
+ goto foundit;
+ }
+ }
+ php_stream_close(fp);
+ if (error) {
+ spprintf(error, 4096, "phar error: end of central directory not found in zip-based phar \"%s\"", fname);
+ }
+ return FAILURE;
+foundit:
+ mydata->fname = estrndup(fname, fname_len);
+#ifdef PHP_WIN32
+ phar_unixify_path_separators(mydata->fname, fname_len);
+#endif
+ mydata->is_zip = 1;
+ mydata->fname_len = fname_len;
+ ext = strrchr(mydata->fname, '/');
+ if (ext) {
+ mydata->ext = memchr(ext, '.', (mydata->fname + fname_len) - ext);
+ if (mydata->ext == ext) {
+ mydata->ext = memchr(ext + 1, '.', (mydata->fname + fname_len) - ext - 1);
+ }
+ if (mydata->ext) {
+ mydata->ext_len = (mydata->fname + fname_len) - mydata->ext;
+ }
+ }
+ /* clean up on big-endian systems */
+ /* seek to central directory */
+ php_stream_seek(fp, PHAR_GET_32(locator.cdir_offset), SEEK_SET);
+ /* read in central directory */
+ zend_hash_init(&mydata->manifest, sizeof(phar_entry_info),
+ zend_get_hash_value, destroy_phar_manifest_entry, 0);
+ zend_hash_init(&mydata->mounted_dirs, sizeof(char *),
+ zend_get_hash_value, NULL, 0);
+ entry.phar = mydata;
+ entry.is_zip = 1;
+ entry.fp_type = PHAR_FP;
+#define PHAR_ZIP_FAIL(errmsg) \
+ zend_hash_destroy(&mydata->manifest); \
+ mydata->manifest.arBuckets = 0; \
+ zend_hash_destroy(&mydata->mounted_dirs); \
+ mydata->mounted_dirs.arBuckets = 0; \
+ php_stream_close(fp); \
+ if (mydata->metadata) { \
+ zval_dtor(mydata->metadata); \
+ } \
+ if (error) { \
+ spprintf(error, 4096, "phar error: %s in zip-based phar \"%s\"", errmsg, mydata->fname); \
+ } \
+ efree(mydata->fname); \
+ if (mydata->alias) { \
+ efree(mydata->alias); \
+ } \
+ efree(mydata); \
+ return FAILURE;
+
+ /* add each central directory item to the manifest */
+ for (i = 0; i < locator.count; ++i) {
+ phar_zip_central_dir_file zipentry;
+
+ if (sizeof(zipentry) != php_stream_read(fp, (char *) &zipentry, sizeof(zipentry))) {
+ PHAR_ZIP_FAIL("unable to read central directory entry, truncated");
+ }
+ /* clean up for bigendian systems */
+ if (memcmp("PK\1\2", zipentry.signature, 4)) {
+ /* corrupted entry */
+ PHAR_ZIP_FAIL("corrupted central directory entry, no magic signature");
+ }
+ entry.compressed_filesize = PHAR_GET_32(zipentry.compsize);
+ entry.uncompressed_filesize = PHAR_GET_32(zipentry.uncompsize);
+ entry.crc32 = PHAR_GET_32(zipentry.crc32);
+ /* do not PHAR_GET_16 either on the next line */
+ entry.timestamp = phar_zip_d2u_time(zipentry.timestamp, zipentry.datestamp);
+ entry.flags = PHAR_ENT_PERM_DEF_FILE;
+ entry.header_offset = PHAR_GET_32(zipentry.offset);
+ entry.offset = entry.offset_abs = PHAR_GET_32(zipentry.offset) + sizeof(phar_zip_file_header) + PHAR_GET_16(zipentry.filename_len) +
+ PHAR_GET_16(zipentry.extra_len);
+ if (PHAR_GET_16(zipentry.flags) & PHAR_ZIP_FLAG_ENCRYPTED) {
+ PHAR_ZIP_FAIL("Cannot process encrypted zip files");
+ }
+ if (!PHAR_GET_16(zipentry.filename_len)) {
+ PHAR_ZIP_FAIL("Cannot process zips created from stdin (zero-length filename)");
+ }
+ entry.filename_len = PHAR_GET_16(zipentry.filename_len);
+ entry.filename = (char *) emalloc(entry.filename_len + 1);
+ if (entry.filename_len != php_stream_read(fp, entry.filename, entry.filename_len)) {
+ efree(entry.filename);
+ PHAR_ZIP_FAIL("unable to read in filename from central directory, truncated");
+ }
+ entry.filename[entry.filename_len] = '\0';
+ if (entry.filename[entry.filename_len - 1] == '/') {
+ entry.is_dir = 1;
+ entry.filename_len--;
+ entry.flags |= PHAR_ENT_PERM_DEF_DIR;
+ } else {
+ entry.is_dir = 0;
+ }
+ if (PHAR_GET_16(zipentry.extra_len)) {
+ off_t loc = php_stream_tell(fp);
+ if (FAILURE == phar_zip_process_extra(fp, &entry, PHAR_GET_16(zipentry.extra_len) TSRMLS_CC)) {
+ efree(entry.filename);
+ PHAR_ZIP_FAIL("Unable to process extra field header for file in central directory");
+ }
+ php_stream_seek(fp, loc + PHAR_GET_16(zipentry.extra_len), SEEK_SET);
+ }
+ switch (zipentry.compressed) {
+ case PHAR_ZIP_COMP_NONE :
+ /* compression flag already set */
+ break;
+ case PHAR_ZIP_COMP_DEFLATE :
+ entry.flags |= PHAR_ENT_COMPRESSED_GZ;
+ if (!phar_has_zlib) {
+ efree(entry.filename);
+ PHAR_ZIP_FAIL("zlib extension is required");
+ }
+ break;
+ case PHAR_ZIP_COMP_BZIP2 :
+ entry.flags |= PHAR_ENT_COMPRESSED_BZ2;
+ if (!phar_has_bz2) {
+ efree(entry.filename);
+ PHAR_ZIP_FAIL("bzip2 extension is required");
+ }
+ break;
+ case 1 :
+ efree(entry.filename);
+ PHAR_ZIP_FAIL("unsupported compression method (Shrunk) used in this zip");
+ case 2 :
+ case 3 :
+ case 4 :
+ case 5 :
+ efree(entry.filename);
+ PHAR_ZIP_FAIL("unsupported compression method (Reduce) used in this zip");
+ case 6 :
+ efree(entry.filename);
+ PHAR_ZIP_FAIL("unsupported compression method (Implode) used in this zip");
+ case 7 :
+ efree(entry.filename);
+ PHAR_ZIP_FAIL("unsupported compression method (Tokenize) used in this zip");
+ case 9 :
+ efree(entry.filename);
+ PHAR_ZIP_FAIL("unsupported compression method (Deflate64) used in this zip");
+ case 10 :
+ efree(entry.filename);
+ PHAR_ZIP_FAIL("unsupported compression method (PKWare Implode/old IBM TERSE) used in this zip");
+ case 14 :
+ efree(entry.filename);
+ PHAR_ZIP_FAIL("unsupported compression method (LZMA) used in this zip");
+ case 18 :
+ efree(entry.filename);
+ PHAR_ZIP_FAIL("unsupported compression method (IBM TERSE) used in this zip");
+ case 19 :
+ efree(entry.filename);
+ PHAR_ZIP_FAIL("unsupported compression method (IBM LZ77) used in this zip");
+ case 97 :
+ efree(entry.filename);
+ PHAR_ZIP_FAIL("unsupported compression method (WavPack) used in this zip");
+ case 98 :
+ efree(entry.filename);
+ PHAR_ZIP_FAIL("unsupported compression method (PPMd) used in this zip");
+ default :
+ efree(entry.filename);
+ PHAR_ZIP_FAIL("unsupported compression method (unknown) used in this zip");
+ }
+ /* get file metadata */
+ if (zipentry.comment_len) {
+ if (PHAR_GET_16(zipentry.comment_len) != php_stream_read(fp, buf, PHAR_GET_16(zipentry.comment_len))) {
+ efree(entry.filename);
+ PHAR_ZIP_FAIL("unable to read in file comment, truncated");
+ }
+ p = buf;
+ if (phar_parse_metadata(&p, &(entry.metadata), PHAR_GET_16(zipentry.comment_len) TSRMLS_CC) == FAILURE) {
+ /* if not valid serialized data, it is a regular string */
+ ALLOC_INIT_ZVAL(entry.metadata);
+ ZVAL_STRINGL(entry.metadata, buf, PHAR_GET_16(zipentry.comment_len), 1);
+ }
+ } else {
+ entry.metadata = NULL;
+ }
+ if (!actual_alias && entry.filename_len == sizeof(".phar/alias.txt")-1 && !strncmp(entry.filename, ".phar/alias.txt", sizeof(".phar/alias.txt")-1)) {
+ php_stream_filter *filter;
+ off_t saveloc;
+
+ /* archive alias found, seek to file contents, do not validate local header. Potentially risky, but
+ not very. */
+ saveloc = php_stream_tell(fp);
+ php_stream_seek(fp, PHAR_GET_32(zipentry.offset) + sizeof(phar_zip_file_header) + entry.filename_len + PHAR_GET_16(zipentry.extra_len), SEEK_SET);
+ mydata->alias_len = entry.uncompressed_filesize;
+ if (entry.flags & PHAR_ENT_COMPRESSED_GZ) {
+ filter = php_stream_filter_create("zlib.inflate", NULL, php_stream_is_persistent(fp) TSRMLS_CC);
+ if (!filter) {
+ efree(entry.filename);
+ PHAR_ZIP_FAIL("unable to decompress alias, zlib filter creation failed");
+ }
+ php_stream_filter_append(&fp->readfilters, filter);
+ if (!(entry.uncompressed_filesize = php_stream_copy_to_mem(fp, &actual_alias, entry.uncompressed_filesize, 0)) || !actual_alias) {
+ efree(entry.filename);
+ PHAR_ZIP_FAIL("unable to read in alias, truncated");
+ }
+ php_stream_filter_flush(filter, 1);
+ php_stream_filter_remove(filter, 1 TSRMLS_CC);
+ } else if (entry.flags & PHAR_ENT_COMPRESSED_BZ2) {
+ php_stream_filter *filter;
+ filter = php_stream_filter_create("bzip2.decompress", NULL, php_stream_is_persistent(fp) TSRMLS_CC);
+ if (!filter) {
+ efree(entry.filename);
+ PHAR_ZIP_FAIL("unable to read in alias, bzip2 filter creation failed");
+ }
+ php_stream_filter_append(&fp->readfilters, filter);
+ php_stream_filter_append(&fp->readfilters, filter);
+ if (!(entry.uncompressed_filesize = php_stream_copy_to_mem(fp, &actual_alias, entry.uncompressed_filesize, 0)) || !actual_alias) {
+ efree(entry.filename);
+ PHAR_ZIP_FAIL("unable to read in alias, truncated");
+ }
+ php_stream_filter_flush(filter, 1);
+ php_stream_filter_remove(filter, 1 TSRMLS_CC);
+ } else {
+ if (!(entry.uncompressed_filesize = php_stream_copy_to_mem(fp, &actual_alias, entry.uncompressed_filesize, 0)) || !actual_alias) {
+ efree(entry.filename);
+ PHAR_ZIP_FAIL("unable to read in alias, truncated");
+ }
+ }
+
+ /* return to central directory parsing */
+ php_stream_seek(fp, saveloc, SEEK_SET);
+ }
+ zend_hash_add(&mydata->manifest, entry.filename, entry.filename_len, (void *)&entry,sizeof(phar_entry_info), NULL);
+ }
+ mydata->fp = fp;
+ zend_hash_add(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len, (void*)&mydata, sizeof(phar_archive_data*), NULL);
+ if (actual_alias) {
+ phar_archive_data **fd_ptr;
+
+ if (!phar_validate_alias(actual_alias, mydata->alias_len)) {
+ if (error) {
+ spprintf(error, 4096, "phar error: invalid alias \"%s\" in zip-based phar \"%s\"", actual_alias, fname);
+ }
+ efree(actual_alias);
+ zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len);
+ return FAILURE;
+ }
+ mydata->is_temporary_alias = 0;
+ if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), actual_alias, mydata->alias_len, (void **)&fd_ptr)) {
+ if (SUCCESS != phar_free_alias(*fd_ptr, actual_alias, mydata->alias_len TSRMLS_CC)) {
+ if (error) {
+ spprintf(error, 4096, "phar error: Unable to add zip-based phar \"%s\" with implicit alias, alias is already in use", fname);
+ }
+ efree(actual_alias);
+ zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len);
+ return FAILURE;
+ }
+ }
+ mydata->alias = actual_alias;
+ zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), actual_alias, mydata->alias_len, (void*)&mydata, sizeof(phar_archive_data*), NULL);
+ } else {
+ phar_archive_data **fd_ptr;
+
+ if (alias_len) {
+ if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void **)&fd_ptr)) {
+ if (SUCCESS != phar_free_alias(*fd_ptr, alias, alias_len TSRMLS_CC)) {
+ if (error) {
+ spprintf(error, 4096, "phar error: Unable to add zip-based phar \"%s\" with explicit alias, alias is already in use", fname);
+ }
+ zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len);
+ return FAILURE;
+ }
+ }
+ zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), actual_alias, mydata->alias_len, (void*)&mydata, sizeof(phar_archive_data*), NULL);
+ mydata->alias = estrndup(alias, alias_len);
+ mydata->alias_len = alias_len;
+ } else {
+ mydata->alias = estrndup(mydata->fname, fname_len);
+ mydata->alias_len = fname_len;
+ }
+ mydata->is_temporary_alias = 1;
+ }
+ if (pphar) {
+ *pphar = mydata;
+ }
+ return SUCCESS;
+}
+/* }}} */
+
+/**
+ * Create or open a zip-based phar for writing
+ */
+int phar_open_or_create_zip(char *fname, int fname_len, char *alias, int alias_len, int is_data, int options, phar_archive_data** pphar, char **error TSRMLS_DC) /* {{{ */
+{
+ phar_archive_data *phar;
+ int ret = phar_create_or_parse_filename(fname, fname_len, alias, alias_len, is_data, options, &phar, error TSRMLS_CC);
+
+ if (FAILURE == ret) {
+ return FAILURE;
+ }
+
+ if (pphar) {
+ *pphar = phar;
+ }
+
+ phar->is_data = is_data;
+
+ if (phar->is_zip) {
+ return ret;
+ }
+
+ if (phar->is_brandnew) {
+ phar->internal_file_start = 0;
+ phar->is_zip = 1;
+ return SUCCESS;
+ }
+
+ /* we've reached here - the phar exists and is a regular phar */
+ if (error) {
+ spprintf(error, 4096, "phar zip error: phar \"%s\" already exists as a regular phar and must be deleted from disk prior to creating as a zip-based phar", fname);
+ }
+ return FAILURE;
+}
+/* }}} */
+
+struct _phar_zip_pass {
+ php_stream *filefp;
+ php_stream *centralfp;
+ php_stream *old;
+ int free_fp;
+ int free_ufp;
+ char **error;
+};
+/* perform final modification of zip contents for each file in the manifest before saving */
+static int phar_zip_changed_apply(void *data, void *arg TSRMLS_DC) /* {{{ */
+{
+ phar_entry_info *entry;
+ phar_zip_file_header local;
+ phar_zip_unix3 perms;
+ phar_zip_central_dir_file central;
+ struct _phar_zip_pass *p;
+ php_uint32 newcrc32;
+ off_t offset;
+
+ entry = (phar_entry_info *)data;
+ p = (struct _phar_zip_pass*) arg;
+ if (entry->is_mounted) {
+ return ZEND_HASH_APPLY_KEEP;
+ }
+ if (entry->is_deleted) {
+ if (entry->fp_refcount <= 0) {
+ return ZEND_HASH_APPLY_REMOVE;
+ } else {
+ /* we can't delete this in-memory until it is closed */
+ return ZEND_HASH_APPLY_KEEP;
+ }
+ }
+ memset(&local, 0, sizeof(local));
+ memset(&central, 0, sizeof(central));
+ memset(&perms, 0, sizeof(perms));
+ strncpy(local.signature, "PK\3\4", 4);
+ strncpy(central.signature, "PK\1\2", 4);
+ central.extra_len = local.extra_len = PHAR_SET_16(sizeof(perms));
+ perms.tag[0] = 'n';
+ perms.tag[1] = 'u';
+ perms.size = PHAR_SET_16(sizeof(perms) - 4);
+ perms.perms = PHAR_SET_16(entry->flags & PHAR_ENT_PERM_MASK);
+ perms.crc32 = ~0;
+ CRC32(perms.crc32, (char)perms.perms & 0xFF);
+ CRC32(perms.crc32, (char)perms.perms & 0xFF00 >> 8);
+ perms.crc32 = PHAR_SET_32(~(perms.crc32));
+ if (entry->flags & PHAR_ENT_COMPRESSED_GZ) {
+ local.compressed = central.compressed = PHAR_SET_16(PHAR_ZIP_COMP_DEFLATE);
+ }
+ if (entry->flags & PHAR_ENT_COMPRESSED_BZ2) {
+ local.compressed = central.compressed = PHAR_SET_16(PHAR_ZIP_COMP_BZIP2);
+ }
+ /* do not use PHAR_SET_16 on either field of the next line */
+ phar_zip_u2d_time(entry->timestamp, &local.timestamp, &local.datestamp);
+ central.timestamp = local.timestamp;
+ central.datestamp = local.datestamp;
+ central.filename_len = local.filename_len = PHAR_SET_16(entry->filename_len + (entry->is_dir ? 1 : 0));
+ central.offset = PHAR_SET_32(php_stream_tell(p->filefp));
+ /* do extra field for perms later */
+ if (entry->is_modified) {
+ php_uint32 loc;
+ php_stream_filter *filter;
+ php_stream *efp;
+
+ if (entry->is_dir) {
+ entry->is_modified = 0;
+ if (entry->fp_type == PHAR_MOD && entry->fp != entry->phar->fp && entry->fp != entry->phar->ufp) {
+ php_stream_close(entry->fp);
+ entry->fp = NULL;
+ entry->fp_type = PHAR_FP;
+ }
+ goto continue_dir;
+ }
+ if (FAILURE == phar_open_entry_fp(entry, p->error, 0 TSRMLS_CC)) {
+ spprintf(p->error, 0, "unable to open file contents of file \"%s\" in zip-based phar \"%s\"", entry->filename, entry->phar->fname);
+ return ZEND_HASH_APPLY_STOP;
+ }
+ if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC)) {
+ spprintf(p->error, 0, "unable to seek to start of file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname);
+ return ZEND_HASH_APPLY_STOP;
+ }
+ efp = phar_get_efp(entry, 0 TSRMLS_CC);
+
+ newcrc32 = ~0;
+ for (loc = 0;loc < entry->uncompressed_filesize; ++loc) {
+ CRC32(newcrc32, php_stream_getc(efp));
+ }
+ entry->crc32 = ~newcrc32;
+ central.uncompsize = local.uncompsize = PHAR_SET_32(entry->uncompressed_filesize);
+ if (!(entry->flags & PHAR_ENT_COMPRESSION_MASK)) {
+ /* not compressed */
+ entry->compressed_filesize = entry->uncompressed_filesize;
+ central.compsize = local.compsize = PHAR_SET_32(entry->compressed_filesize);
+ goto not_compressed;
+ }
+ filter = php_stream_filter_create(phar_compress_filter(entry, 0), NULL, 0 TSRMLS_CC);
+ if (!filter) {
+ if (entry->flags & PHAR_ENT_COMPRESSED_GZ) {
+ spprintf(p->error, 0, "unable to gzip compress file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname);
+ } else {
+ spprintf(p->error, 0, "unable to bzip2 compress file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname);
+ }
+ return ZEND_HASH_APPLY_STOP;
+ }
+
+ /* create new file that holds the compressed version */
+ /* work around inability to specify freedom in write and strictness
+ in read count */
+ entry->cfp = php_stream_fopen_tmpfile();
+ if (!entry->cfp) {
+ spprintf(p->error, 0, "unable to create temporary file for file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
+ return ZEND_HASH_APPLY_STOP;
+ }
+ php_stream_flush(efp);
+ if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC)) {
+ spprintf(p->error, 0, "unable to seek to start of file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname);
+ return ZEND_HASH_APPLY_STOP;
+ }
+ php_stream_filter_append((&entry->cfp->writefilters), filter);
+ if (entry->uncompressed_filesize != php_stream_copy_to_stream(efp, entry->cfp, entry->uncompressed_filesize)) {
+ spprintf(p->error, 0, "unable to copy compressed file contents of file \"%s\" while creating new phar \"%s\"", entry->filename, entry->phar->fname);
+ return ZEND_HASH_APPLY_STOP;
+ }
+ php_stream_filter_flush(filter, 1);
+ php_stream_flush(entry->cfp);
+ php_stream_filter_remove(filter, 1 TSRMLS_CC);
+ php_stream_seek(entry->cfp, 0, SEEK_END);
+ entry->compressed_filesize = (php_uint32) php_stream_tell(entry->cfp);
+ central.compsize = local.compsize = PHAR_SET_32(entry->compressed_filesize);
+ /* generate crc on compressed file */
+ php_stream_rewind(entry->cfp);
+ entry->old_flags = entry->flags;
+ entry->is_modified = 1;
+ } else {
+ central.uncompsize = local.uncompsize = PHAR_SET_32(entry->uncompressed_filesize);
+ central.compsize = local.compsize = PHAR_SET_32(entry->compressed_filesize);
+ if (-1 == php_stream_seek(p->old, entry->offset_abs, SEEK_SET)) {
+ spprintf(p->error, 0, "unable to seek to start of file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
+ return ZEND_HASH_APPLY_STOP;
+ }
+ }
+not_compressed:
+ central.crc32 = local.crc32 = PHAR_SET_32(entry->crc32);
+continue_dir:
+ /* set file metadata */
+ if (entry->metadata) {
+ php_serialize_data_t metadata_hash;
+
+ if (entry->metadata_str.c) {
+ smart_str_free(&entry->metadata_str);
+ }
+ entry->metadata_str.c = 0;
+ entry->metadata_str.len = 0;
+ PHP_VAR_SERIALIZE_INIT(metadata_hash);
+ php_var_serialize(&entry->metadata_str, &entry->metadata, &metadata_hash TSRMLS_CC);
+ PHP_VAR_SERIALIZE_DESTROY(metadata_hash);
+ central.comment_len = PHAR_SET_16(entry->metadata_str.len);
+ }
+ entry->header_offset = php_stream_tell(p->filefp);
+ offset = entry->header_offset + sizeof(local) + entry->filename_len + (entry->is_dir ? 1 : 0) + sizeof(perms);
+ if (sizeof(local) != php_stream_write(p->filefp, (char *)&local, sizeof(local))) {
+ spprintf(p->error, 0, "unable to write local file header of file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname);
+ return ZEND_HASH_APPLY_STOP;
+ }
+ if (sizeof(central) != php_stream_write(p->centralfp, (char *)&central, sizeof(central))) {
+ spprintf(p->error, 0, "unable to write central directory entry for file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
+ return ZEND_HASH_APPLY_STOP;
+ }
+ if (entry->is_dir) {
+ if (entry->filename_len != php_stream_write(p->filefp, entry->filename, entry->filename_len)) {
+ spprintf(p->error, 0, "unable to write filename to local directory entry for directory \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
+ return ZEND_HASH_APPLY_STOP;
+ }
+ if (1 != php_stream_write(p->filefp, "/", 1)) {
+ spprintf(p->error, 0, "unable to write filename to local directory entry for directory \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
+ return ZEND_HASH_APPLY_STOP;
+ }
+ if (entry->filename_len != php_stream_write(p->centralfp, entry->filename, entry->filename_len)) {
+ spprintf(p->error, 0, "unable to write filename to central directory entry for directory \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
+ return ZEND_HASH_APPLY_STOP;
+ }
+ if (1 != php_stream_write(p->centralfp, "/", 1)) {
+ spprintf(p->error, 0, "unable to write filename to central directory entry for directory \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
+ return ZEND_HASH_APPLY_STOP;
+ }
+ } else {
+ if (entry->filename_len != php_stream_write(p->filefp, entry->filename, entry->filename_len)) {
+ spprintf(p->error, 0, "unable to write filename to local directory entry for file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
+ return ZEND_HASH_APPLY_STOP;
+ }
+ if (entry->filename_len != php_stream_write(p->centralfp, entry->filename, entry->filename_len)) {
+ spprintf(p->error, 0, "unable to write filename to central directory entry for file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
+ return ZEND_HASH_APPLY_STOP;
+ }
+ }
+ if (sizeof(perms) != php_stream_write(p->filefp, (char *)&perms, sizeof(perms))) {
+ spprintf(p->error, 0, "unable to write local extra permissions file header of file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname);
+ return ZEND_HASH_APPLY_STOP;
+ }
+ if (sizeof(perms) != php_stream_write(p->centralfp, (char *)&perms, sizeof(perms))) {
+ spprintf(p->error, 0, "unable to write central extra permissions file header of file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname);
+ return ZEND_HASH_APPLY_STOP;
+ }
+ if (entry->is_modified) {
+ if (entry->cfp) {
+ if (entry->compressed_filesize != php_stream_copy_to_stream(entry->cfp, p->filefp, entry->compressed_filesize)) {
+ spprintf(p->error, 0, "unable to write compressed contents of file \"%s\" in zip-based phar \"%s\"", entry->filename, entry->phar->fname);
+ return ZEND_HASH_APPLY_STOP;
+ }
+ php_stream_close(entry->cfp);
+ entry->cfp = NULL;
+ } else {
+ if (FAILURE == phar_open_entry_fp(entry, p->error, 0 TSRMLS_CC)) {
+ return ZEND_HASH_APPLY_STOP;
+ }
+ phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC);
+ if (entry->uncompressed_filesize != php_stream_copy_to_stream(phar_get_efp(entry, 0 TSRMLS_CC), p->filefp, entry->uncompressed_filesize)) {
+ spprintf(p->error, 0, "unable to write contents of file \"%s\" in zip-based phar \"%s\"", entry->filename, entry->phar->fname);
+ return ZEND_HASH_APPLY_STOP;
+ }
+ }
+ if (entry->fp_type == PHAR_MOD && entry->fp != entry->phar->fp && entry->fp != entry->phar->ufp && entry->fp_refcount == 0) {
+ php_stream_close(entry->fp);
+ }
+ entry->is_modified = 0;
+ } else {
+ if (entry->fp_refcount) {
+ /* open file pointers refer to this fp, do not free the stream */
+ switch (entry->fp_type) {
+ case PHAR_FP:
+ p->free_fp = 0;
+ break;
+ case PHAR_UFP:
+ p->free_ufp = 0;
+ default:
+ break;
+ }
+ }
+ if (!entry->is_dir && entry->compressed_filesize && entry->compressed_filesize != php_stream_copy_to_stream(p->old, p->filefp, entry->compressed_filesize)) {
+ spprintf(p->error, 0, "unable to copy contents of file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
+ return ZEND_HASH_APPLY_STOP;
+ }
+ }
+ entry->fp = NULL;
+ entry->offset = entry->offset_abs = offset;
+ entry->fp_type = PHAR_FP;
+ if (entry->metadata_str.c) {
+ if (entry->metadata_str.len != php_stream_write(p->centralfp, entry->metadata_str.c, entry->metadata_str.len)) {
+ spprintf(p->error, 0, "unable to write metadata as file comment for file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
+ smart_str_free(&entry->metadata_str);
+ return ZEND_HASH_APPLY_STOP;
+ }
+ smart_str_free(&entry->metadata_str);
+ }
+ return ZEND_HASH_APPLY_KEEP;
+}
+/* }}} */
+
+int phar_zip_flush(phar_archive_data *phar, char *user_stub, long len, int defaultstub, char **error TSRMLS_DC) /* {{{ */
+{
+ char *pos;
+ smart_str main_metadata_str = {0};
+ static const char newstub[] = "<?php // zip-based phar archive stub file\n__HALT_COMPILER();";
+ php_stream *stubfile, *oldfile;
+ php_serialize_data_t metadata_hash;
+ int free_user_stub, closeoldfile = 0;
+ phar_entry_info entry = {0};
+ char *temperr = NULL;
+ struct _phar_zip_pass pass;
+ phar_zip_dir_end eocd;
+
+ pass.error = &temperr;
+ entry.flags = PHAR_ENT_PERM_DEF_FILE;
+ entry.timestamp = time(NULL);
+ entry.is_modified = 1;
+ entry.is_zip = 1;
+ entry.phar = phar;
+ entry.fp_type = PHAR_MOD;
+
+ if (phar->is_data) {
+ goto nostub;
+ }
+
+ /* set alias */
+ if (!phar->is_temporary_alias && phar->alias_len) {
+ entry.fp = php_stream_fopen_tmpfile();
+ if (phar->alias_len != (int)php_stream_write(entry.fp, phar->alias, phar->alias_len)) {
+ if (error) {
+ spprintf(error, 0, "unable to set alias in zip-based phar \"%s\"", phar->fname);
+ }
+ return EOF;
+ }
+ entry.uncompressed_filesize = entry.compressed_filesize = phar->alias_len;
+ entry.filename = estrndup(".phar/alias.txt", sizeof(".phar/alias.txt")-1);
+ entry.filename_len = sizeof(".phar/alias.txt")-1;
+ if (SUCCESS != zend_hash_update(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL)) {
+ if (error) {
+ spprintf(error, 0, "unable to set alias in zip-based phar \"%s\"", phar->fname);
+ }
+ return EOF;
+ }
+ } else {
+ zend_hash_del(&phar->manifest, ".phar/alias.txt", sizeof(".phar/alias.txt")-1);
+ }
+ /* register alias */
+ if (phar->alias_len) {
+ if (FAILURE == phar_get_archive(&phar, phar->fname, phar->fname_len, phar->alias, phar->alias_len, error TSRMLS_CC)) {
+ return EOF;
+ }
+ }
+
+ /* set stub */
+ if (user_stub && !defaultstub) {
+ if (len < 0) {
+ /* resource passed in */
+ if (!(php_stream_from_zval_no_verify(stubfile, (zval **)user_stub))) {
+ if (error) {
+ spprintf(error, 0, "unable to access resource to copy stub to new zip-based phar \"%s\"", phar->fname);
+ }
+ return EOF;
+ }
+ if (len == -1) {
+ len = PHP_STREAM_COPY_ALL;
+ } else {
+ len = -len;
+ }
+ user_stub = 0;
+ if (!(len = php_stream_copy_to_mem(stubfile, &user_stub, len, 0)) || !user_stub) {
+ if (error) {
+ spprintf(error, 0, "unable to read resource to copy stub to new zip-based phar \"%s\"", phar->fname);
+ }
+ return EOF;
+ }
+ free_user_stub = 1;
+ } else {
+ free_user_stub = 0;
+ }
+ if ((pos = strstr(user_stub, "__HALT_COMPILER();")) == NULL)
+ {
+ if (error) {
+ spprintf(error, 0, "illegal stub for zip-based phar \"%s\"", phar->fname);
+ }
+ if (free_user_stub) {
+ efree(user_stub);
+ }
+ return EOF;
+ }
+ len = pos - user_stub + 18;
+ entry.fp = php_stream_fopen_tmpfile();
+ entry.uncompressed_filesize = len + 5;
+
+ if ((size_t)len != php_stream_write(entry.fp, user_stub, len)
+ || 5 != php_stream_write(entry.fp, " ?>\r\n", 5)) {
+ if (error) {
+ spprintf(error, 0, "unable to create stub from string in new zip-based phar \"%s\"", phar->fname);
+ }
+ if (free_user_stub) {
+ efree(user_stub);
+ }
+ php_stream_close(entry.fp);
+ return EOF;
+ }
+ entry.filename = estrndup(".phar/stub.php", sizeof(".phar/stub.php")-1);
+ entry.filename_len = sizeof(".phar/stub.php")-1;
+ if (SUCCESS != zend_hash_update(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL)) {
+ if (free_user_stub) {
+ efree(user_stub);
+ }
+ if (error) {
+ spprintf(error, 0, "unable to set stub in zip-based phar \"%s\"", phar->fname);
+ }
+ return EOF;
+ }
+ if (free_user_stub) {
+ efree(user_stub);
+ }
+ } else {
+ /* Either this is a brand new phar (add the stub), or the default stub is required (overwrite the stub) */
+ entry.fp = php_stream_fopen_tmpfile();
+
+ if (sizeof(newstub)-1 != php_stream_write(entry.fp, newstub, sizeof(newstub)-1)) {
+ php_stream_close(entry.fp);
+ if (error) {
+ spprintf(error, 0, "unable to %s stub in%szip-based phar \"%s\", failed", user_stub ? "overwrite" : "create", user_stub ? " " : " new ", phar->fname);
+ }
+ return EOF;
+ }
+
+ entry.uncompressed_filesize = entry.compressed_filesize = sizeof(newstub) - 1;
+ entry.filename = estrndup(".phar/stub.php", sizeof(".phar/stub.php")-1);
+ entry.filename_len = sizeof(".phar/stub.php")-1;
+
+ if (!defaultstub) {
+ if (!zend_hash_exists(&phar->manifest, ".phar/stub.php", sizeof(".phar/stub.php")-1)) {
+ if (SUCCESS != zend_hash_add(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL)) {
+ php_stream_close(entry.fp);
+ efree(entry.filename);
+ if (error) {
+ spprintf(error, 0, "unable to create stub in zip-based phar \"%s\"", phar->fname);
+ }
+ return EOF;
+ }
+ } else {
+ php_stream_close(entry.fp);
+ efree(entry.filename);
+ }
+ } else {
+ if (SUCCESS != zend_hash_update(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL)) {
+ php_stream_close(entry.fp);
+ efree(entry.filename);
+ if (error) {
+ spprintf(error, 0, "unable to overwrite stub in zip-based phar \"%s\"", phar->fname);
+ }
+ return EOF;
+ }
+ }
+ }
+
+nostub:
+
+ if (phar->fp && !phar->is_brandnew) {
+ oldfile = phar->fp;
+ closeoldfile = 0;
+ php_stream_rewind(oldfile);
+ } else {
+ oldfile = php_stream_open_wrapper(phar->fname, "rb", 0, NULL);
+ closeoldfile = oldfile != NULL;
+ }
+
+ /* save modified files to the zip */
+ pass.old = oldfile;
+ pass.filefp = php_stream_fopen_tmpfile();
+ if (!pass.filefp) {
+ if (closeoldfile) {
+ php_stream_close(oldfile);
+ }
+ if (error) {
+ spprintf(error, 4096, "phar zip flush of \"%s\" failed: unable to open temporary file", phar->fname);
+ }
+ return EOF;
+ }
+ pass.centralfp = php_stream_fopen_tmpfile();
+ if (!pass.centralfp) {
+ if (closeoldfile) {
+ php_stream_close(oldfile);
+ }
+ if (error) {
+ spprintf(error, 4096, "phar zip flush of \"%s\" failed: unable to open temporary file", phar->fname);
+ }
+ return EOF;
+ }
+ pass.free_fp = pass.free_ufp = 1;
+ memset(&eocd, 0, sizeof(eocd));
+
+ strncpy(eocd.signature, "PK\5\6", 4);
+ eocd.counthere = eocd.count = zend_hash_num_elements(&phar->manifest);
+ zend_hash_apply_with_argument(&phar->manifest, phar_zip_changed_apply, (void *) &pass TSRMLS_CC);
+ if (temperr) {
+ php_stream_close(pass.filefp);
+ php_stream_close(pass.centralfp);
+ if (closeoldfile) {
+ php_stream_close(oldfile);
+ }
+ if (error) {
+ spprintf(error, 4096, "phar zip flush of \"%s\" failed: %s", phar->fname, temperr);
+ }
+ efree(temperr);
+ return EOF;
+ }
+
+ /* save zip */
+ eocd.cdir_size = php_stream_tell(pass.centralfp);
+ eocd.cdir_offset = php_stream_tell(pass.filefp);
+ php_stream_seek(pass.centralfp, 0, SEEK_SET);
+ if (eocd.cdir_size != php_stream_copy_to_stream(pass.centralfp, pass.filefp, PHP_STREAM_COPY_ALL)) {
+ php_stream_close(pass.filefp);
+ php_stream_close(pass.centralfp);
+ if (error) {
+ spprintf(error, 4096, "phar zip flush of \"%s\" failed: unable to write central-directory", phar->fname);
+ }
+ if (closeoldfile) {
+ php_stream_close(oldfile);
+ }
+ return EOF;
+ }
+ php_stream_close(pass.centralfp);
+ if (phar->metadata) {
+ /* set phar metadata */
+ PHP_VAR_SERIALIZE_INIT(metadata_hash);
+ php_var_serialize(&main_metadata_str, &phar->metadata, &metadata_hash TSRMLS_CC);
+ PHP_VAR_SERIALIZE_DESTROY(metadata_hash);
+ eocd.comment_len = PHAR_SET_16(main_metadata_str.len);
+ if (sizeof(eocd) != php_stream_write(pass.filefp, (char *)&eocd, sizeof(eocd))) {
+ php_stream_close(pass.filefp);
+ if (error) {
+ spprintf(error, 4096, "phar zip flush of \"%s\" failed: unable to write end of central-directory", phar->fname);
+ }
+ if (closeoldfile) {
+ php_stream_close(oldfile);
+ }
+ smart_str_free(&main_metadata_str);
+ return EOF;
+ }
+ if (main_metadata_str.len != php_stream_write(pass.filefp, main_metadata_str.c, main_metadata_str.len)) {
+ php_stream_close(pass.filefp);
+ if (error) {
+ spprintf(error, 4096, "phar zip flush of \"%s\" failed: unable to write metadata to zip comment", phar->fname);
+ }
+ if (closeoldfile) {
+ php_stream_close(oldfile);
+ }
+ smart_str_free(&main_metadata_str);
+ return EOF;
+ }
+ smart_str_free(&main_metadata_str);
+ } else {
+ if (sizeof(eocd) != php_stream_write(pass.filefp, (char *)&eocd, sizeof(eocd))) {
+ php_stream_close(pass.filefp);
+ if (error) {
+ spprintf(error, 4096, "phar zip flush of \"%s\" failed: unable to write end of central-directory", phar->fname);
+ }
+ if (closeoldfile) {
+ php_stream_close(oldfile);
+ }
+ return EOF;
+ }
+ }
+ if (phar->fp && pass.free_fp) {
+ php_stream_close(phar->fp);
+ }
+ if (phar->ufp) {
+ if (pass.free_ufp) {
+ php_stream_close(phar->ufp);
+ }
+ phar->ufp = NULL;
+ }
+ /* re-open */
+ phar->is_brandnew = 0;
+ if (phar->donotflush) {
+ /* deferred flush */
+ phar->fp = pass.filefp;
+ } else {
+ phar->fp = php_stream_open_wrapper(phar->fname, "w+b", IGNORE_URL|STREAM_MUST_SEEK|REPORT_ERRORS, NULL);
+ if (!phar->fp) {
+ if (closeoldfile) {
+ php_stream_close(oldfile);
+ }
+ phar->fp = pass.filefp;
+ if (error) {
+ spprintf(error, 4096, "unable to open new phar \"%s\" for writing", phar->fname);
+ }
+ return EOF;
+ }
+ php_stream_rewind(pass.filefp);
+ php_stream_copy_to_stream(pass.filefp, phar->fp, PHP_STREAM_COPY_ALL);
+ /* we could also reopen the file in "rb" mode but there is no need for that */
+ php_stream_close(pass.filefp);
+ }
+
+ if (closeoldfile) {
+ php_stream_close(oldfile);
+ }
+ return EOF;
+}
+/* }}} */