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