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

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