root/ext/phar/phar_object.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. phar_file_type
  2. phar_mung_server_vars
  3. phar_file_action
  4. phar_do_403
  5. phar_do_404
  6. phar_postprocess_ru_web
  7. PHP_METHOD
  8. PHP_METHOD
  9. PHP_METHOD
  10. PHP_METHOD
  11. PHP_METHOD
  12. PHP_METHOD
  13. PHP_METHOD
  14. PHP_METHOD
  15. PHP_METHOD
  16. PHP_METHOD
  17. PHP_METHOD
  18. PHP_METHOD
  19. phar_spl_foreign_dtor
  20. phar_spl_foreign_clone
  21. PHP_METHOD
  22. PHP_METHOD
  23. PHP_METHOD
  24. PHP_METHOD
  25. PHP_METHOD
  26. phar_build
  27. PHP_METHOD
  28. PHP_METHOD
  29. PHP_METHOD
  30. PHP_METHOD
  31. phar_copy_file_contents
  32. phar_rename_archive
  33. phar_convert_to_other
  34. PHP_METHOD
  35. PHP_METHOD
  36. PHP_METHOD
  37. PHP_METHOD
  38. PHP_METHOD
  39. PHP_METHOD
  40. PHP_METHOD
  41. PHP_METHOD
  42. PHP_METHOD
  43. PHP_METHOD
  44. PHP_METHOD
  45. PHP_METHOD
  46. PHP_METHOD
  47. PHP_METHOD
  48. PHP_METHOD
  49. PHP_METHOD
  50. PHP_METHOD
  51. phar_set_compression
  52. phar_test_compression
  53. pharobj_set_compression
  54. pharobj_cancompress
  55. PHP_METHOD
  56. PHP_METHOD
  57. PHP_METHOD
  58. PHP_METHOD
  59. PHP_METHOD
  60. PHP_METHOD
  61. PHP_METHOD
  62. phar_add_file
  63. phar_mkdir
  64. PHP_METHOD
  65. PHP_METHOD
  66. PHP_METHOD
  67. PHP_METHOD
  68. PHP_METHOD
  69. PHP_METHOD
  70. PHP_METHOD
  71. PHP_METHOD
  72. PHP_METHOD
  73. PHP_METHOD
  74. phar_extract_file
  75. PHP_METHOD
  76. PHP_METHOD
  77. PHP_METHOD
  78. PHP_METHOD
  79. PHP_METHOD
  80. PHP_METHOD
  81. PHP_METHOD
  82. PHP_METHOD
  83. PHP_METHOD
  84. PHP_METHOD
  85. PHP_METHOD
  86. PHP_METHOD
  87. PHP_METHOD
  88. PHP_METHOD
  89. PHP_METHOD
  90. PHP_METHOD
  91. phar_object_init

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

/* [<][>][^][v][top][bottom][index][help] */