PageRenderTime 75ms CodeModel.GetById 32ms RepoModel.GetById 0ms app.codeStats 1ms

/ext/phar/phar_object.c

http://github.com/infusion/PHP
C | 5438 lines | 4157 code | 809 blank | 472 comment | 1052 complexity | f071aaab42bfcb662350e9d7403a9637 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, LGPL-2.1, BSD-3-Clause

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. +----------------------------------------------------------------------+
  3. | phar php single-file executable PHP extension |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2005-2011 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. /* $Id: phar_object.c 309222 2011-03-14 14:12:42Z felipe $ */
  20. #include "phar_internal.h"
  21. #include "func_interceptors.h"
  22. static zend_class_entry *phar_ce_archive;
  23. static zend_class_entry *phar_ce_data;
  24. static zend_class_entry *phar_ce_PharException;
  25. #if HAVE_SPL
  26. static zend_class_entry *phar_ce_entry;
  27. #endif
  28. #if PHP_MAJOR_VERSION > 5 || ((PHP_MAJOR_VERSION == 5) && (PHP_MINOR_VERSION >= 3))
  29. # define PHAR_ARG_INFO
  30. #else
  31. # define PHAR_ARG_INFO static
  32. #endif
  33. static int phar_file_type(HashTable *mimes, char *file, char **mime_type TSRMLS_DC) /* {{{ */
  34. {
  35. char *ext;
  36. phar_mime_type *mime;
  37. ext = strrchr(file, '.');
  38. if (!ext) {
  39. *mime_type = "text/plain";
  40. /* no file extension = assume text/plain */
  41. return PHAR_MIME_OTHER;
  42. }
  43. ++ext;
  44. if (SUCCESS != zend_hash_find(mimes, ext, strlen(ext), (void **) &mime)) {
  45. *mime_type = "application/octet-stream";
  46. return PHAR_MIME_OTHER;
  47. }
  48. *mime_type = mime->mime;
  49. return mime->type;
  50. }
  51. /* }}} */
  52. static void phar_mung_server_vars(char *fname, char *entry, int entry_len, char *basename, int request_uri_len TSRMLS_DC) /* {{{ */
  53. {
  54. #if PHP_MAJOR_VERSION >= 6
  55. int is_unicode = 0;
  56. #endif
  57. HashTable *_SERVER;
  58. zval **stuff;
  59. char *path_info;
  60. int basename_len = strlen(basename);
  61. int code;
  62. zval *temp;
  63. /* "tweak" $_SERVER variables requested in earlier call to Phar::mungServer() */
  64. if (!PG(http_globals)[TRACK_VARS_SERVER]) {
  65. return;
  66. }
  67. _SERVER = Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_SERVER]);
  68. /* PATH_INFO and PATH_TRANSLATED should always be munged */
  69. #if PHP_MAJOR_VERSION >= 6
  70. if (phar_find_key(_SERVER, "PATH_INFO", sizeof("PATH_INFO"), (void **) &stuff TSRMLS_CC)) {
  71. if (Z_TYPE_PP(stuff) == IS_UNICODE) {
  72. is_unicode = 1;
  73. zval_unicode_to_string(*stuff TSRMLS_CC);
  74. } else {
  75. is_unicode = 0;
  76. }
  77. #else
  78. if (SUCCESS == zend_hash_find(_SERVER, "PATH_INFO", sizeof("PATH_INFO"), (void **) &stuff)) {
  79. #endif
  80. path_info = Z_STRVAL_PP(stuff);
  81. code = Z_STRLEN_PP(stuff);
  82. if (Z_STRLEN_PP(stuff) > entry_len && !memcmp(Z_STRVAL_PP(stuff), entry, entry_len)) {
  83. ZVAL_STRINGL(*stuff, Z_STRVAL_PP(stuff) + entry_len, request_uri_len, 1);
  84. MAKE_STD_ZVAL(temp);
  85. ZVAL_STRINGL(temp, path_info, code, 0);
  86. #if PHP_MAJOR_VERSION >= 6
  87. if (is_unicode) {
  88. zval_string_to_unicode(*stuff TSRMLS_CC);
  89. }
  90. #endif
  91. zend_hash_update(_SERVER, "PHAR_PATH_INFO", sizeof("PHAR_PATH_INFO"), &temp, sizeof(zval **), NULL);
  92. }
  93. }
  94. #if PHP_MAJOR_VERSION >= 6
  95. if (phar_find_key(_SERVER, "PATH_TRANSLATED", sizeof("PATH_TRANSLATED"), (void **) &stuff TSRMLS_CC)) {
  96. if (Z_TYPE_PP(stuff) == IS_UNICODE) {
  97. is_unicode = 1;
  98. zval_unicode_to_string(*stuff TSRMLS_CC);
  99. } else {
  100. is_unicode = 0;
  101. }
  102. #else
  103. if (SUCCESS == zend_hash_find(_SERVER, "PATH_TRANSLATED", sizeof("PATH_TRANSLATED"), (void **) &stuff)) {
  104. #endif
  105. path_info = Z_STRVAL_PP(stuff);
  106. code = Z_STRLEN_PP(stuff);
  107. Z_STRLEN_PP(stuff) = spprintf(&(Z_STRVAL_PP(stuff)), 4096, "phar://%s%s", fname, entry);
  108. MAKE_STD_ZVAL(temp);
  109. ZVAL_STRINGL(temp, path_info, code, 0);
  110. #if PHP_MAJOR_VERSION >= 6
  111. if (is_unicode) {
  112. zval_string_to_unicode(*stuff TSRMLS_CC);
  113. }
  114. #endif
  115. zend_hash_update(_SERVER, "PHAR_PATH_TRANSLATED", sizeof("PHAR_PATH_TRANSLATED"), (void *) &temp, sizeof(zval **), NULL);
  116. }
  117. if (!PHAR_GLOBALS->phar_SERVER_mung_list) {
  118. return;
  119. }
  120. if (PHAR_GLOBALS->phar_SERVER_mung_list & PHAR_MUNG_REQUEST_URI) {
  121. #if PHP_MAJOR_VERSION >= 6
  122. if (phar_find_key(_SERVER, "REQUEST_URI", sizeof("REQUEST_URI"), (void **) &stuff TSRMLS_CC)) {
  123. if (Z_TYPE_PP(stuff) == IS_UNICODE) {
  124. is_unicode = 1;
  125. zval_unicode_to_string(*stuff TSRMLS_CC);
  126. } else {
  127. is_unicode = 0;
  128. }
  129. #else
  130. if (SUCCESS == zend_hash_find(_SERVER, "REQUEST_URI", sizeof("REQUEST_URI"), (void **) &stuff)) {
  131. #endif
  132. path_info = Z_STRVAL_PP(stuff);
  133. code = Z_STRLEN_PP(stuff);
  134. if (Z_STRLEN_PP(stuff) > basename_len && !memcmp(Z_STRVAL_PP(stuff), basename, basename_len)) {
  135. ZVAL_STRINGL(*stuff, Z_STRVAL_PP(stuff) + basename_len, Z_STRLEN_PP(stuff) - basename_len, 1);
  136. MAKE_STD_ZVAL(temp);
  137. ZVAL_STRINGL(temp, path_info, code, 0);
  138. #if PHP_MAJOR_VERSION >= 6
  139. if (is_unicode) {
  140. zval_string_to_unicode(*stuff TSRMLS_CC);
  141. }
  142. #endif
  143. zend_hash_update(_SERVER, "PHAR_REQUEST_URI", sizeof("PHAR_REQUEST_URI"), (void *) &temp, sizeof(zval **), NULL);
  144. }
  145. }
  146. }
  147. if (PHAR_GLOBALS->phar_SERVER_mung_list & PHAR_MUNG_PHP_SELF) {
  148. #if PHP_MAJOR_VERSION >= 6
  149. if (phar_find_key(_SERVER, "PHP_SELF", sizeof("PHP_SELF"), (void **) &stuff TSRMLS_CC)) {
  150. if (Z_TYPE_PP(stuff) == IS_UNICODE) {
  151. is_unicode = 1;
  152. zval_unicode_to_string(*stuff TSRMLS_CC);
  153. } else {
  154. is_unicode = 0;
  155. }
  156. #else
  157. if (SUCCESS == zend_hash_find(_SERVER, "PHP_SELF", sizeof("PHP_SELF"), (void **) &stuff)) {
  158. #endif
  159. path_info = Z_STRVAL_PP(stuff);
  160. code = Z_STRLEN_PP(stuff);
  161. if (Z_STRLEN_PP(stuff) > basename_len && !memcmp(Z_STRVAL_PP(stuff), basename, basename_len)) {
  162. ZVAL_STRINGL(*stuff, Z_STRVAL_PP(stuff) + basename_len, Z_STRLEN_PP(stuff) - basename_len, 1);
  163. MAKE_STD_ZVAL(temp);
  164. ZVAL_STRINGL(temp, path_info, code, 0);
  165. #if PHP_MAJOR_VERSION >= 6
  166. if (is_unicode) {
  167. zval_string_to_unicode(*stuff TSRMLS_CC);
  168. }
  169. #endif
  170. zend_hash_update(_SERVER, "PHAR_PHP_SELF", sizeof("PHAR_PHP_SELF"), (void *) &temp, sizeof(zval **), NULL);
  171. }
  172. }
  173. }
  174. if (PHAR_GLOBALS->phar_SERVER_mung_list & PHAR_MUNG_SCRIPT_NAME) {
  175. #if PHP_MAJOR_VERSION >= 6
  176. if (phar_find_key(_SERVER, "SCRIPT_NAME", sizeof("SCRIPT_NAME"), (void **) &stuff TSRMLS_CC)) {
  177. if (Z_TYPE_PP(stuff) == IS_UNICODE) {
  178. is_unicode = 1;
  179. zval_unicode_to_string(*stuff TSRMLS_CC);
  180. } else {
  181. is_unicode = 0;
  182. }
  183. #else
  184. if (SUCCESS == zend_hash_find(_SERVER, "SCRIPT_NAME", sizeof("SCRIPT_NAME"), (void **) &stuff)) {
  185. #endif
  186. path_info = Z_STRVAL_PP(stuff);
  187. code = Z_STRLEN_PP(stuff);
  188. ZVAL_STRINGL(*stuff, entry, entry_len, 1);
  189. MAKE_STD_ZVAL(temp);
  190. ZVAL_STRINGL(temp, path_info, code, 0);
  191. #if PHP_MAJOR_VERSION >= 6
  192. if (is_unicode) {
  193. zval_string_to_unicode(*stuff TSRMLS_CC);
  194. }
  195. #endif
  196. zend_hash_update(_SERVER, "PHAR_SCRIPT_NAME", sizeof("PHAR_SCRIPT_NAME"), (void *) &temp, sizeof(zval **), NULL);
  197. }
  198. }
  199. if (PHAR_GLOBALS->phar_SERVER_mung_list & PHAR_MUNG_SCRIPT_FILENAME) {
  200. #if PHP_MAJOR_VERSION >= 6
  201. if (phar_find_key(_SERVER, "SCRIPT_FILENAME", sizeof("SCRIPT_FILENAME"), (void **) &stuff TSRMLS_CC)) {
  202. if (Z_TYPE_PP(stuff) == IS_UNICODE) {
  203. is_unicode = 1;
  204. zval_unicode_to_string(*stuff TSRMLS_CC);
  205. } else {
  206. is_unicode = 0;
  207. }
  208. #else
  209. if (SUCCESS == zend_hash_find(_SERVER, "SCRIPT_FILENAME", sizeof("SCRIPT_FILENAME"), (void **) &stuff)) {
  210. #endif
  211. path_info = Z_STRVAL_PP(stuff);
  212. code = Z_STRLEN_PP(stuff);
  213. Z_STRLEN_PP(stuff) = spprintf(&(Z_STRVAL_PP(stuff)), 4096, "phar://%s%s", fname, entry);
  214. MAKE_STD_ZVAL(temp);
  215. ZVAL_STRINGL(temp, path_info, code, 0);
  216. #if PHP_MAJOR_VERSION >= 6
  217. if (is_unicode) {
  218. zval_string_to_unicode(*stuff TSRMLS_CC);
  219. }
  220. #endif
  221. zend_hash_update(_SERVER, "PHAR_SCRIPT_FILENAME", sizeof("PHAR_SCRIPT_FILENAME"), (void *) &temp, sizeof(zval **), NULL);
  222. }
  223. }
  224. }
  225. /* }}} */
  226. static int phar_file_action(phar_archive_data *phar, phar_entry_info *info, char *mime_type, int code, char *entry, int entry_len, char *arch, char *basename, char *ru, int ru_len TSRMLS_DC) /* {{{ */
  227. {
  228. char *name = NULL, buf[8192], *cwd;
  229. zend_syntax_highlighter_ini syntax_highlighter_ini;
  230. sapi_header_line ctr = {0};
  231. size_t got;
  232. int dummy = 1, name_len;
  233. zend_file_handle file_handle;
  234. zend_op_array *new_op_array;
  235. zval *result = NULL;
  236. php_stream *fp;
  237. off_t position;
  238. switch (code) {
  239. case PHAR_MIME_PHPS:
  240. efree(basename);
  241. /* highlight source */
  242. if (entry[0] == '/') {
  243. name_len = spprintf(&name, 4096, "phar://%s%s", arch, entry);
  244. } else {
  245. name_len = spprintf(&name, 4096, "phar://%s/%s", arch, entry);
  246. }
  247. php_get_highlight_struct(&syntax_highlighter_ini);
  248. highlight_file(name, &syntax_highlighter_ini TSRMLS_CC);
  249. efree(name);
  250. #ifdef PHP_WIN32
  251. efree(arch);
  252. #endif
  253. zend_bailout();
  254. case PHAR_MIME_OTHER:
  255. /* send headers, output file contents */
  256. efree(basename);
  257. ctr.line_len = spprintf(&(ctr.line), 0, "Content-type: %s", mime_type);
  258. sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
  259. efree(ctr.line);
  260. ctr.line_len = spprintf(&(ctr.line), 0, "Content-length: %u", info->uncompressed_filesize);
  261. sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
  262. efree(ctr.line);
  263. if (FAILURE == sapi_send_headers(TSRMLS_C)) {
  264. zend_bailout();
  265. }
  266. /* prepare to output */
  267. fp = phar_get_efp(info, 1 TSRMLS_CC);
  268. if (!fp) {
  269. char *error;
  270. if (!phar_open_jit(phar, info, &error TSRMLS_CC)) {
  271. if (error) {
  272. zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "%s", error);
  273. efree(error);
  274. }
  275. return -1;
  276. }
  277. fp = phar_get_efp(info, 1 TSRMLS_CC);
  278. }
  279. position = 0;
  280. phar_seek_efp(info, 0, SEEK_SET, 0, 1 TSRMLS_CC);
  281. do {
  282. got = php_stream_read(fp, buf, MIN(8192, info->uncompressed_filesize - position));
  283. if (got > 0) {
  284. PHPWRITE(buf, got);
  285. position += got;
  286. if (position == (off_t) info->uncompressed_filesize) {
  287. break;
  288. }
  289. }
  290. } while (1);
  291. zend_bailout();
  292. case PHAR_MIME_PHP:
  293. if (basename) {
  294. phar_mung_server_vars(arch, entry, entry_len, basename, ru_len TSRMLS_CC);
  295. efree(basename);
  296. }
  297. if (entry[0] == '/') {
  298. name_len = spprintf(&name, 4096, "phar://%s%s", arch, entry);
  299. } else {
  300. name_len = spprintf(&name, 4096, "phar://%s/%s", arch, entry);
  301. }
  302. file_handle.type = ZEND_HANDLE_FILENAME;
  303. file_handle.handle.fd = 0;
  304. file_handle.filename = name;
  305. file_handle.opened_path = NULL;
  306. file_handle.free_filename = 0;
  307. PHAR_G(cwd) = NULL;
  308. PHAR_G(cwd_len) = 0;
  309. if (zend_hash_add(&EG(included_files), name, name_len+1, (void *)&dummy, sizeof(int), NULL) == SUCCESS) {
  310. if ((cwd = zend_memrchr(entry, '/', entry_len))) {
  311. PHAR_G(cwd_init) = 1;
  312. if (entry == cwd) {
  313. /* root directory */
  314. PHAR_G(cwd_len) = 0;
  315. PHAR_G(cwd) = NULL;
  316. } else if (entry[0] == '/') {
  317. PHAR_G(cwd_len) = cwd - (entry + 1);
  318. PHAR_G(cwd) = estrndup(entry + 1, PHAR_G(cwd_len));
  319. } else {
  320. PHAR_G(cwd_len) = cwd - entry;
  321. PHAR_G(cwd) = estrndup(entry, PHAR_G(cwd_len));
  322. }
  323. }
  324. new_op_array = zend_compile_file(&file_handle, ZEND_REQUIRE TSRMLS_CC);
  325. if (!new_op_array) {
  326. zend_hash_del(&EG(included_files), name, name_len+1);
  327. }
  328. zend_destroy_file_handle(&file_handle TSRMLS_CC);
  329. } else {
  330. efree(name);
  331. new_op_array = NULL;
  332. }
  333. #ifdef PHP_WIN32
  334. efree(arch);
  335. #endif
  336. if (new_op_array) {
  337. EG(return_value_ptr_ptr) = &result;
  338. EG(active_op_array) = new_op_array;
  339. zend_try {
  340. zend_execute(new_op_array TSRMLS_CC);
  341. if (PHAR_G(cwd)) {
  342. efree(PHAR_G(cwd));
  343. PHAR_G(cwd) = NULL;
  344. PHAR_G(cwd_len) = 0;
  345. }
  346. PHAR_G(cwd_init) = 0;
  347. efree(name);
  348. destroy_op_array(new_op_array TSRMLS_CC);
  349. efree(new_op_array);
  350. if (EG(return_value_ptr_ptr) && *EG(return_value_ptr_ptr)) {
  351. zval_ptr_dtor(EG(return_value_ptr_ptr));
  352. }
  353. } zend_catch {
  354. if (PHAR_G(cwd)) {
  355. efree(PHAR_G(cwd));
  356. PHAR_G(cwd) = NULL;
  357. PHAR_G(cwd_len) = 0;
  358. }
  359. PHAR_G(cwd_init) = 0;
  360. efree(name);
  361. } zend_end_try();
  362. zend_bailout();
  363. }
  364. return PHAR_MIME_PHP;
  365. }
  366. return -1;
  367. }
  368. /* }}} */
  369. static void phar_do_403(char *entry, int entry_len TSRMLS_DC) /* {{{ */
  370. {
  371. sapi_header_line ctr = {0};
  372. ctr.response_code = 403;
  373. ctr.line_len = sizeof("HTTP/1.0 403 Access Denied");
  374. ctr.line = "HTTP/1.0 403 Access Denied";
  375. sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
  376. sapi_send_headers(TSRMLS_C);
  377. 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);
  378. PHPWRITE(entry, entry_len);
  379. PHPWRITE(" Access Denied</h1>\n </body>\n</html>", sizeof(" Access Denied</h1>\n </body>\n</html>") - 1);
  380. }
  381. /* }}} */
  382. static void phar_do_404(phar_archive_data *phar, char *fname, int fname_len, char *f404, int f404_len, char *entry, int entry_len TSRMLS_DC) /* {{{ */
  383. {
  384. sapi_header_line ctr = {0};
  385. phar_entry_info *info;
  386. if (phar && f404_len) {
  387. info = phar_get_entry_info(phar, f404, f404_len, NULL, 1 TSRMLS_CC);
  388. if (info) {
  389. phar_file_action(phar, info, "text/html", PHAR_MIME_PHP, f404, f404_len, fname, NULL, NULL, 0 TSRMLS_CC);
  390. return;
  391. }
  392. }
  393. ctr.response_code = 404;
  394. ctr.line_len = sizeof("HTTP/1.0 404 Not Found")+1;
  395. ctr.line = "HTTP/1.0 404 Not Found";
  396. sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
  397. sapi_send_headers(TSRMLS_C);
  398. 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);
  399. PHPWRITE(entry, entry_len);
  400. PHPWRITE(" Not Found</h1>\n </body>\n</html>", sizeof(" Not Found</h1>\n </body>\n</html>") - 1);
  401. }
  402. /* }}} */
  403. /* post-process REQUEST_URI and retrieve the actual request URI. This is for
  404. cases like http://localhost/blah.phar/path/to/file.php/extra/stuff
  405. which calls "blah.phar" file "path/to/file.php" with PATH_INFO "/extra/stuff" */
  406. static void phar_postprocess_ru_web(char *fname, int fname_len, char **entry, int *entry_len, char **ru, int *ru_len TSRMLS_DC) /* {{{ */
  407. {
  408. char *e = *entry + 1, *u = NULL, *u1 = NULL, *saveu = NULL;
  409. int e_len = *entry_len - 1, u_len = 0;
  410. phar_archive_data **pphar = NULL;
  411. /* we already know we can retrieve the phar if we reach here */
  412. zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len, (void **) &pphar);
  413. if (!pphar && PHAR_G(manifest_cached)) {
  414. zend_hash_find(&cached_phars, fname, fname_len, (void **) &pphar);
  415. }
  416. do {
  417. if (zend_hash_exists(&((*pphar)->manifest), e, e_len)) {
  418. if (u) {
  419. u[0] = '/';
  420. *ru = estrndup(u, u_len+1);
  421. ++u_len;
  422. u[0] = '\0';
  423. } else {
  424. *ru = NULL;
  425. }
  426. *ru_len = u_len;
  427. *entry_len = e_len + 1;
  428. return;
  429. }
  430. if (u) {
  431. u1 = strrchr(e, '/');
  432. u[0] = '/';
  433. saveu = u;
  434. e_len += u_len + 1;
  435. u = u1;
  436. if (!u) {
  437. return;
  438. }
  439. } else {
  440. u = strrchr(e, '/');
  441. if (!u) {
  442. if (saveu) {
  443. saveu[0] = '/';
  444. }
  445. return;
  446. }
  447. }
  448. u[0] = '\0';
  449. u_len = strlen(u + 1);
  450. e_len -= u_len + 1;
  451. if (e_len < 0) {
  452. if (saveu) {
  453. saveu[0] = '/';
  454. }
  455. return;
  456. }
  457. } while (1);
  458. }
  459. /* }}} */
  460. /* {{{ proto void Phar::running([bool retphar = true])
  461. * return the name of the currently running phar archive. If the optional parameter
  462. * is set to true, return the phar:// URL to the currently running phar
  463. */
  464. PHP_METHOD(Phar, running)
  465. {
  466. char *fname, *arch, *entry;
  467. int fname_len, arch_len, entry_len;
  468. zend_bool retphar = 1;
  469. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &retphar) == FAILURE) {
  470. return;
  471. }
  472. fname = zend_get_executed_filename(TSRMLS_C);
  473. fname_len = strlen(fname);
  474. 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)) {
  475. efree(entry);
  476. if (retphar) {
  477. RETVAL_STRINGL(fname, arch_len + 7, 1);
  478. efree(arch);
  479. return;
  480. } else {
  481. RETURN_STRINGL(arch, arch_len, 0);
  482. }
  483. }
  484. RETURN_STRINGL("", 0, 1);
  485. }
  486. /* }}} */
  487. /* {{{ proto void Phar::mount(string pharpath, string externalfile)
  488. * mount an external file or path to a location within the phar. This maps
  489. * an external file or directory to a location within the phar archive, allowing
  490. * reference to an external location as if it were within the phar archive. This
  491. * is useful for writable temp files like databases
  492. */
  493. PHP_METHOD(Phar, mount)
  494. {
  495. char *fname, *arch = NULL, *entry = NULL, *path, *actual;
  496. int fname_len, arch_len, entry_len, path_len, actual_len;
  497. phar_archive_data **pphar;
  498. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &path, &path_len, &actual, &actual_len) == FAILURE) {
  499. return;
  500. }
  501. fname = zend_get_executed_filename(TSRMLS_C);
  502. fname_len = strlen(fname);
  503. #ifdef PHP_WIN32
  504. phar_unixify_path_separators(fname, fname_len);
  505. #endif
  506. 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)) {
  507. efree(entry);
  508. entry = NULL;
  509. if (path_len > 7 && !memcmp(path, "phar://", 7)) {
  510. 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);
  511. efree(arch);
  512. return;
  513. }
  514. carry_on2:
  515. if (SUCCESS != zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **)&pphar)) {
  516. if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_find(&cached_phars, arch, arch_len, (void **)&pphar)) {
  517. if (SUCCESS == phar_copy_on_write(pphar TSRMLS_CC)) {
  518. goto carry_on;
  519. }
  520. }
  521. zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "%s is not a phar archive, cannot mount", arch);
  522. if (arch) {
  523. efree(arch);
  524. }
  525. return;
  526. }
  527. carry_on:
  528. if (SUCCESS != phar_mount_entry(*pphar, actual, actual_len, path, path_len TSRMLS_CC)) {
  529. zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Mounting of %s to %s within phar %s failed", path, actual, arch);
  530. if (path && path == entry) {
  531. efree(entry);
  532. }
  533. if (arch) {
  534. efree(arch);
  535. }
  536. return;
  537. }
  538. if (entry && path && path == entry) {
  539. efree(entry);
  540. }
  541. if (arch) {
  542. efree(arch);
  543. }
  544. return;
  545. } else if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len, (void **)&pphar)) {
  546. goto carry_on;
  547. } else if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_find(&cached_phars, fname, fname_len, (void **)&pphar)) {
  548. if (SUCCESS == phar_copy_on_write(pphar TSRMLS_CC)) {
  549. goto carry_on;
  550. }
  551. goto carry_on;
  552. } else if (SUCCESS == phar_split_fname(path, path_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
  553. path = entry;
  554. path_len = entry_len;
  555. goto carry_on2;
  556. }
  557. zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Mounting of %s to %s failed", path, actual);
  558. }
  559. /* }}} */
  560. /* {{{ proto void Phar::webPhar([string alias, [string index, [string f404, [array mimetypes, [callback rewrites]]]]])
  561. * mapPhar for web-based phars. Reads the currently executed file (a phar)
  562. * and registers its manifest. When executed in the CLI or CGI command-line sapi,
  563. * this works exactly like mapPhar(). When executed by a web-based sapi, this
  564. * reads $_SERVER['REQUEST_URI'] (the actual original value) and parses out the
  565. * intended internal file.
  566. */
  567. PHP_METHOD(Phar, webPhar)
  568. {
  569. zval *mimeoverride = NULL, *rewrite = NULL;
  570. char *alias = NULL, *error, *index_php = NULL, *f404 = NULL, *ru = NULL;
  571. int alias_len = 0, ret, f404_len = 0, free_pathinfo = 0, ru_len = 0;
  572. char *fname, *basename, *path_info, *mime_type = NULL, *entry, *pt;
  573. int fname_len, entry_len, code, index_php_len = 0, not_cgi;
  574. phar_archive_data *phar = NULL;
  575. phar_entry_info *info;
  576. 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) {
  577. return;
  578. }
  579. phar_request_initialize(TSRMLS_C);
  580. fname = zend_get_executed_filename(TSRMLS_C);
  581. fname_len = strlen(fname);
  582. if (phar_open_executed_filename(alias, alias_len, &error TSRMLS_CC) != SUCCESS) {
  583. if (error) {
  584. zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "%s", error);
  585. efree(error);
  586. }
  587. return;
  588. }
  589. /* retrieve requested file within phar */
  590. 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")))) {
  591. return;
  592. }
  593. #ifdef PHP_WIN32
  594. fname = estrndup(fname, fname_len);
  595. phar_unixify_path_separators(fname, fname_len);
  596. #endif
  597. basename = zend_memrchr(fname, '/', fname_len);
  598. if (!basename) {
  599. basename = fname;
  600. } else {
  601. ++basename;
  602. }
  603. if ((strlen(sapi_module.name) == sizeof("cgi-fcgi")-1 && !strncmp(sapi_module.name, "cgi-fcgi", sizeof("cgi-fcgi")-1))
  604. || (strlen(sapi_module.name) == sizeof("cgi")-1 && !strncmp(sapi_module.name, "cgi", sizeof("cgi")-1))) {
  605. if (PG(http_globals)[TRACK_VARS_SERVER]) {
  606. HashTable *_server = Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_SERVER]);
  607. zval **z_script_name, **z_path_info;
  608. if (SUCCESS != zend_hash_find(_server, "SCRIPT_NAME", sizeof("SCRIPT_NAME"), (void**)&z_script_name) ||
  609. IS_STRING != Z_TYPE_PP(z_script_name) ||
  610. !strstr(Z_STRVAL_PP(z_script_name), basename)) {
  611. return;
  612. }
  613. if (SUCCESS == zend_hash_find(_server, "PATH_INFO", sizeof("PATH_INFO"), (void**)&z_path_info) &&
  614. IS_STRING == Z_TYPE_PP(z_path_info)) {
  615. entry_len = Z_STRLEN_PP(z_path_info);
  616. entry = estrndup(Z_STRVAL_PP(z_path_info), entry_len);
  617. path_info = emalloc(Z_STRLEN_PP(z_script_name) + entry_len + 1);
  618. memcpy(path_info, Z_STRVAL_PP(z_script_name), Z_STRLEN_PP(z_script_name));
  619. memcpy(path_info + Z_STRLEN_PP(z_script_name), entry, entry_len + 1);
  620. free_pathinfo = 1;
  621. } else {
  622. entry_len = 0;
  623. entry = estrndup("", 0);
  624. path_info = Z_STRVAL_PP(z_script_name);
  625. }
  626. pt = estrndup(Z_STRVAL_PP(z_script_name), Z_STRLEN_PP(z_script_name));
  627. } else {
  628. char *testit;
  629. testit = sapi_getenv("SCRIPT_NAME", sizeof("SCRIPT_NAME")-1 TSRMLS_CC);
  630. if (!(pt = strstr(testit, basename))) {
  631. efree(testit);
  632. return;
  633. }
  634. path_info = sapi_getenv("PATH_INFO", sizeof("PATH_INFO")-1 TSRMLS_CC);
  635. if (path_info) {
  636. entry = path_info;
  637. entry_len = strlen(entry);
  638. spprintf(&path_info, 0, "%s%s", testit, path_info);
  639. free_pathinfo = 1;
  640. } else {
  641. path_info = testit;
  642. free_pathinfo = 1;
  643. entry = estrndup("", 0);
  644. entry_len = 0;
  645. }
  646. pt = estrndup(testit, (pt - testit) + (fname_len - (basename - fname)));
  647. }
  648. not_cgi = 0;
  649. } else {
  650. path_info = SG(request_info).request_uri;
  651. if (!(pt = strstr(path_info, basename))) {
  652. /* this can happen with rewrite rules - and we have no idea what to do then, so return */
  653. return;
  654. }
  655. entry_len = strlen(path_info);
  656. entry_len -= (pt - path_info) + (fname_len - (basename - fname));
  657. entry = estrndup(pt + (fname_len - (basename - fname)), entry_len);
  658. pt = estrndup(path_info, (pt - path_info) + (fname_len - (basename - fname)));
  659. not_cgi = 1;
  660. }
  661. if (rewrite) {
  662. zend_fcall_info fci;
  663. zend_fcall_info_cache fcc;
  664. zval *params, *retval_ptr, **zp[1];
  665. MAKE_STD_ZVAL(params);
  666. ZVAL_STRINGL(params, entry, entry_len, 1);
  667. zp[0] = &params;
  668. #if PHP_VERSION_ID < 50300
  669. if (FAILURE == zend_fcall_info_init(rewrite, &fci, &fcc TSRMLS_CC)) {
  670. #else
  671. if (FAILURE == zend_fcall_info_init(rewrite, 0, &fci, &fcc, NULL, NULL TSRMLS_CC)) {
  672. #endif
  673. zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar error: invalid rewrite callback");
  674. if (free_pathinfo) {
  675. efree(path_info);
  676. }
  677. return;
  678. }
  679. fci.param_count = 1;
  680. fci.params = zp;
  681. #if PHP_VERSION_ID < 50300
  682. ++(params->refcount);
  683. #else
  684. Z_ADDREF_P(params);
  685. #endif
  686. fci.retval_ptr_ptr = &retval_ptr;
  687. if (FAILURE == zend_call_function(&fci, &fcc TSRMLS_CC)) {
  688. if (!EG(exception)) {
  689. zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar error: failed to call rewrite callback");
  690. }
  691. if (free_pathinfo) {
  692. efree(path_info);
  693. }
  694. return;
  695. }
  696. if (!fci.retval_ptr_ptr || !retval_ptr) {
  697. if (free_pathinfo) {
  698. efree(path_info);
  699. }
  700. zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar error: rewrite callback must return a string or false");
  701. return;
  702. }
  703. switch (Z_TYPE_P(retval_ptr)) {
  704. #if PHP_VERSION_ID >= 60000
  705. case IS_UNICODE:
  706. zval_unicode_to_string(retval_ptr TSRMLS_CC);
  707. /* break intentionally omitted */
  708. #endif
  709. case IS_STRING:
  710. efree(entry);
  711. if (fci.retval_ptr_ptr != &retval_ptr) {
  712. entry = estrndup(Z_STRVAL_PP(fci.retval_ptr_ptr), Z_STRLEN_PP(fci.retval_ptr_ptr));
  713. entry_len = Z_STRLEN_PP(fci.retval_ptr_ptr);
  714. } else {
  715. entry = Z_STRVAL_P(retval_ptr);
  716. entry_len = Z_STRLEN_P(retval_ptr);
  717. }
  718. break;
  719. case IS_BOOL:
  720. phar_do_403(entry, entry_len TSRMLS_CC);
  721. if (free_pathinfo) {
  722. efree(path_info);
  723. }
  724. zend_bailout();
  725. return;
  726. default:
  727. efree(retval_ptr);
  728. if (free_pathinfo) {
  729. efree(path_info);
  730. }
  731. zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar error: rewrite callback must return a string or false");
  732. return;
  733. }
  734. }
  735. if (entry_len) {
  736. phar_postprocess_ru_web(fname, fname_len, &entry, &entry_len, &ru, &ru_len TSRMLS_CC);
  737. }
  738. if (!entry_len || (entry_len == 1 && entry[0] == '/')) {
  739. efree(entry);
  740. /* direct request */
  741. if (index_php_len) {
  742. entry = index_php;
  743. entry_len = index_php_len;
  744. if (entry[0] != '/') {
  745. spprintf(&entry, 0, "/%s", index_php);
  746. ++entry_len;
  747. }
  748. } else {
  749. /* assume "index.php" is starting point */
  750. entry = estrndup("/index.php", sizeof("/index.php"));
  751. entry_len = sizeof("/index.php")-1;
  752. }
  753. if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, NULL TSRMLS_CC) ||
  754. (info = phar_get_entry_info(phar, entry, entry_len, NULL, 0 TSRMLS_CC)) == NULL) {
  755. phar_do_404(phar, fname, fname_len, f404, f404_len, entry, entry_len TSRMLS_CC);
  756. if (free_pathinfo) {
  757. efree(path_info);
  758. }
  759. zend_bailout();
  760. } else {
  761. char *tmp, sa;
  762. sapi_header_line ctr = {0};
  763. ctr.response_code = 301;
  764. ctr.line_len = sizeof("HTTP/1.1 301 Moved Permanently")+1;
  765. ctr.line = "HTTP/1.1 301 Moved Permanently";
  766. sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
  767. if (not_cgi) {
  768. tmp = strstr(path_info, basename) + fname_len;
  769. sa = *tmp;
  770. *tmp = '\0';
  771. }
  772. ctr.response_code = 0;
  773. if (path_info[strlen(path_info)-1] == '/') {
  774. ctr.line_len = spprintf(&(ctr.line), 4096, "Location: %s%s", path_info, entry + 1);
  775. } else {
  776. ctr.line_len = spprintf(&(ctr.line), 4096, "Location: %s%s", path_info, entry);
  777. }
  778. if (not_cgi) {
  779. *tmp = sa;
  780. }
  781. if (free_pathinfo) {
  782. efree(path_info);
  783. }
  784. sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
  785. sapi_send_headers(TSRMLS_C);
  786. efree(ctr.line);
  787. zend_bailout();
  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. #ifdef PHP_WIN32
  794. efree(fname);
  795. #endif
  796. zend_bailout();
  797. }
  798. if (mimeoverride && zend_hash_num_elements(Z_ARRVAL_P(mimeoverride))) {
  799. char *ext = zend_memrchr(entry, '.', entry_len);
  800. zval **val;
  801. if (ext) {
  802. ++ext;
  803. #if PHP_MAJOR_VERSION >= 6
  804. if (phar_find_key(Z_ARRVAL_P(mimeoverride), ext, strlen(ext)+1, (void **) &val TSRMLS_CC)) {
  805. #else
  806. if (SUCCESS == zend_hash_find(Z_ARRVAL_P(mimeoverride), ext, strlen(ext)+1, (void **) &val)) {
  807. #endif
  808. switch (Z_TYPE_PP(val)) {
  809. case IS_LONG:
  810. if (Z_LVAL_PP(val) == PHAR_MIME_PHP || Z_LVAL_PP(val) == PHAR_MIME_PHPS) {
  811. mime_type = "";
  812. code = Z_LVAL_PP(val);
  813. } else {
  814. 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");
  815. #ifdef PHP_WIN32
  816. efree(fname);
  817. #endif
  818. RETURN_FALSE;
  819. }
  820. break;
  821. #if PHP_MAJOR_VERSION >= 6
  822. case IS_UNICODE:
  823. zval_unicode_to_string(*(val) TSRMLS_CC);
  824. /* break intentionally omitted */
  825. #endif
  826. case IS_STRING:
  827. mime_type = Z_STRVAL_PP(val);
  828. code = PHAR_MIME_OTHER;
  829. break;
  830. default:
  831. 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");
  832. #ifdef PHP_WIN32
  833. efree(fname);
  834. #endif
  835. RETURN_FALSE;
  836. }
  837. }
  838. }
  839. }
  840. if (!mime_type) {
  841. code = phar_file_type(&PHAR_G(mime_types), entry, &mime_type TSRMLS_CC);
  842. }
  843. ret = phar_file_action(phar, info, mime_type, code, entry, entry_len, fname, pt, ru, ru_len TSRMLS_CC);
  844. }
  845. /* }}} */
  846. /* {{{ proto void Phar::mungServer(array munglist)
  847. * Defines a list of up to 4 $_SERVER variables that should be modified for execution
  848. * to mask the presence of the phar archive. This should be used in conjunction with
  849. * Phar::webPhar(), and has no effect otherwise
  850. * SCRIPT_NAME, PHP_SELF, REQUEST_URI and SCRIPT_FILENAME
  851. */
  852. PHP_METHOD(Phar, mungServer)
  853. {
  854. zval *mungvalues;
  855. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &mungvalues) == FAILURE) {
  856. return;
  857. }
  858. if (!zend_hash_num_elements(Z_ARRVAL_P(mungvalues))) {
  859. 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");
  860. return;
  861. }
  862. if (zend_hash_num_elements(Z_ARRVAL_P(mungvalues)) > 4) {
  863. 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");
  864. return;
  865. }
  866. phar_request_initialize(TSRMLS_C);
  867. 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))) {
  868. zval **data = NULL;
  869. #if PHP_MAJOR_VERSION >= 6
  870. zval *unicopy = NULL;
  871. #endif
  872. if (SUCCESS != zend_hash_get_current_data(Z_ARRVAL_P(mungvalues), (void **) &data)) {
  873. zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "unable to retrieve array value in Phar::mungServer()");
  874. return;
  875. }
  876. #if PHP_MAJOR_VERSION >= 6
  877. if (Z_TYPE_PP(data) == IS_UNICODE) {
  878. MAKE_STD_ZVAL(unicopy);
  879. *unicopy = **data;
  880. zval_copy_ctor(unicopy);
  881. INIT_PZVAL(unicopy);
  882. zval_unicode_to_string(unicopy TSRMLS_CC);
  883. data = &unicopy;
  884. }
  885. #endif
  886. if (Z_TYPE_PP(data) != IS_STRING) {
  887. 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");
  888. return;
  889. }
  890. if (Z_STRLEN_PP(data) == sizeof("PHP_SELF")-1 && !strncmp(Z_STRVAL_PP(data), "PHP_SELF", sizeof("PHP_SELF")-1)) {
  891. PHAR_GLOBALS->phar_SERVER_mung_list |= PHAR_MUNG_PHP_SELF;
  892. }
  893. if (Z_STRLEN_PP(data) == sizeof("REQUEST_URI")-1) {
  894. if (!strncmp(Z_STRVAL_PP(data), "REQUEST_URI", sizeof("REQUEST_URI")-1)) {
  895. PHAR_GLOBALS->phar_SERVER_mung_list |= PHAR_MUNG_REQUEST_URI;
  896. }
  897. if (!strncmp(Z_STRVAL_PP(data), "SCRIPT_NAME", sizeof("SCRIPT_NAME")-1)) {
  898. PHAR_GLOBALS->phar_SERVER_mung_list |= PHAR_MUNG_SCRIPT_NAME;
  899. }
  900. }
  901. if (Z_STRLEN_PP(data) == sizeof("SCRIPT_FILENAME")-1 && !strncmp(Z_STRVAL_PP(data), "SCRIPT_FILENAME", sizeof("SCRIPT_FILENAME")-1)) {
  902. PHAR_GLOBALS->phar_SERVER_mung_list |= PHAR_MUNG_SCRIPT_FILENAME;
  903. }
  904. #if PHP_MAJOR_VERSION >= 6
  905. if (unicopy) {
  906. zval_ptr_dtor(&unicopy);
  907. }
  908. #endif
  909. }
  910. }
  911. /* }}} */
  912. /* {{{ proto void Phar::interceptFileFuncs()
  913. * instructs phar to intercept fopen, file_get_contents, opendir, and all of the stat-related functions
  914. * and return stat on files within the phar for relative paths
  915. *
  916. * Once called, this cannot be reversed, and continue until the end of the request.
  917. *
  918. * This allows legacy scripts to be pharred unmodified
  919. */
  920. PHP_METHOD(Phar, interceptFileFuncs)
  921. {
  922. phar_intercept_functions(TSRMLS_C);
  923. }
  924. /* }}} */
  925. /* {{{ proto array Phar::createDefaultStub([string indexfile[, string webindexfile]])
  926. * Return a stub that can be used to run a phar-based archive without the phar extension
  927. * indexfile is the CLI startup filename, which defaults to "index.php", webindexfile
  928. * is the web startup filename, and also defaults to "index.php"
  929. */
  930. PHP_METHOD(Phar, createDefaultStub)
  931. {
  932. char *index = NULL, *webindex = NULL, *stub, *error;
  933. int index_len = 0, webindex_len = 0;
  934. size_t stub_len;
  935. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ss", &index, &index_len, &webindex, &webindex_len) == FAILURE) {
  936. return;
  937. }
  938. stub = phar_create_default_stub(index, webindex, &stub_len, &error TSRMLS_CC);
  939. if (error) {
  940. zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "%s", error);
  941. efree(error);
  942. return;
  943. }
  944. RETURN_STRINGL(stub, stub_len, 0);
  945. }
  946. /* }}} */
  947. /* {{{ proto mixed Phar::mapPhar([string alias, [int dataoffset]])
  948. * Reads the currently executed file (a phar) and registers its manifest */
  949. PHP_METHOD(Phar, mapPhar)
  950. {
  951. char *alias = NULL, *error;
  952. int alias_len = 0;
  953. long dataoffset = 0;
  954. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!l", &alias, &alias_len, &dataoffset) == FAILURE) {
  955. return;
  956. }
  957. phar_request_initialize(TSRMLS_C);
  958. RETVAL_BOOL(phar_open_executed_filename(alias, alias_len, &error TSRMLS_CC) == SUCCESS);
  959. if (error) {
  960. zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "%s", error);
  961. efree(error);
  962. }
  963. } /* }}} */
  964. /* {{{ proto mixed Phar::loadPhar(string filename [, string alias])
  965. * Loads any phar archive with an alias */
  966. PHP_METHOD(Phar, loadPhar)
  967. {
  968. char *fname, *alias = NULL, *error;
  969. int fname_len, alias_len = 0;
  970. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s!", &fname, &fname_len, &alias, &alias_len) == FAILURE) {
  971. return;
  972. }
  973. phar_request_initialize(TSRMLS_C);
  974. RETVAL_BOOL(phar_open_from_filename(fname, fname_len, alias, alias_len, REPORT_ERRORS, NULL, &error TSRMLS_CC) == SUCCESS);
  975. if (error) {
  976. zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "%s", error);
  977. efree(error);
  978. }
  979. } /* }}} */
  980. /* {{{ proto string Phar::apiVersion()
  981. * Returns the api version */
  982. PHP_METHOD(Phar, apiVersion)
  983. {
  984. RETURN_STRINGL(PHP_PHAR_API_VERSION, sizeof(PHP_PHAR_API_VERSION)-1, 1);
  985. }
  986. /* }}}*/
  987. /* {{{ proto bool Phar::canCompress([int method])
  988. * Returns whether phar extension supports compression using zlib/bzip2 */
  989. PHP_METHOD(Phar, canCompress)
  990. {
  991. long method = 0;
  992. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &method) == FAILURE) {
  993. return;
  994. }
  995. phar_request_initialize(TSRMLS_C);
  996. switch (method) {
  997. case PHAR_ENT_COMPRESSED_GZ:
  998. if (PHAR_G(has_zlib)) {
  999. RETURN_TRUE;
  1000. } else {
  1001. RETURN_FALSE;
  1002. }
  1003. case PHAR_ENT_COMPRESSED_BZ2:
  1004. if (PHAR_G(has_bz2)) {
  1005. RETURN_TRUE;
  1006. } else {
  1007. RETURN_FALSE;
  1008. }
  1009. default:
  1010. if (PHAR_G(has_zlib) || PHAR_G(has_bz2)) {
  1011. RETURN_TRUE;
  1012. } else {
  1013. RETURN_FALSE;
  1014. }
  1015. }
  1016. }
  1017. /* }}} */
  1018. /* {{{ proto bool Phar::canWrite()
  1019. * Returns whether phar extension supports writing and creating phars */
  1020. PHP_METHOD(Phar, canWrite)
  1021. {
  1022. RETURN_BOOL(!PHAR_G(readonly));
  1023. }
  1024. /* }}} */
  1025. /* {{{ proto bool Phar::isValidPharFilename(string filename[, bool executable = true])
  1026. * Returns whether the given filename is a valid phar filename */
  1027. PHP_METHOD(Phar, isValidPharFilename)
  1028. {
  1029. char *fname;
  1030. const char *ext_str;
  1031. int fname_len, ext_len, is_executable;
  1032. zend_bool executable = 1;
  1033. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &fname, &fname_len, &executable) == FAILURE) {
  1034. return;
  1035. }
  1036. is_executable = executable;
  1037. RETVAL_BOOL(phar_detect_phar_fname_ext(fname, fname_len, &ext_str, &ext_len, is_executable, 2, 1 TSRMLS_CC) == SUCCESS);
  1038. }
  1039. /* }}} */
  1040. #if HAVE_SPL
  1041. /**
  1042. * from spl_directory
  1043. */
  1044. static void phar_spl_foreign_dtor(spl_filesystem_object *object TSRMLS_DC) /* {{{ */
  1045. {
  1046. phar_archive_data *phar = (phar_archive_data *) object->oth;
  1047. if (!phar->is_persistent) {
  1048. phar_archive_delref(phar TSRMLS_CC);
  1049. }
  1050. object->oth = NULL;
  1051. }
  1052. /* }}} */
  1053. /**
  1054. * from spl_directory
  1055. */
  1056. static void phar_spl_foreign_clone(spl_filesystem_object *src, spl_filesystem_object *dst TSRMLS_DC) /* {{{ */
  1057. {
  1058. phar_archive_data *phar_data = (phar_archive_data *) dst->oth;
  1059. if (!phar_data->is_persistent) {
  1060. ++(phar_data->refcount);
  1061. }
  1062. }
  1063. /* }}} */
  1064. static spl_other_handler phar_spl_foreign_handler = {
  1065. phar_spl_foreign_dtor,
  1066. phar_spl_foreign_clone
  1067. };
  1068. #endif /* HAVE_SPL */
  1069. /* {{{ proto void Phar::__construct(string fname [, int flags [, string alias]])
  1070. * Construct a Phar archive object
  1071. *
  1072. * proto void PharData::__construct(string fname [[, int flags [, string alias]], int file format = Phar::TAR])
  1073. * Construct a PharData archive object
  1074. *
  1075. * This function is used as the constructor for both the Phar and PharData
  1076. * classes, hence the two prototypes above.
  1077. */
  1078. PHP_METHOD(Phar, __construct)
  1079. {
  1080. #if !HAVE_SPL
  1081. zend_throw_exception_ex(zend_exception_get_default(TSRMLS_C), 0 TSRMLS_CC, "Cannot instantiate Phar object without SPL extension");
  1082. #else
  1083. char *fname, *alias = NULL, *error, *arch = NULL, *entry = NULL, *save_fname;
  1084. int fname_len, alias_len = 0, arch_len, entry_len, is_data;
  1085. #if PHP_VERSION_ID < 50300
  1086. long flags = 0;
  1087. #else
  1088. long flags = SPL_FILE_DIR_SKIPDOTS|SPL_FILE_DIR_UNIXPATHS;
  1089. #endif
  1090. long format = 0;
  1091. phar_archive_object *phar_obj;
  1092. phar_archive_data *phar_data;
  1093. zval *zobj = getThis(), arg1, arg2;
  1094. phar_obj = (phar_archive_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
  1095. is_data = instanceof_function(Z_OBJCE_P(zobj), phar_ce_data TSRMLS_CC);
  1096. if (is_data) {
  1097. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ls!l", &fname, &fname_len, &flags, &alias, &alias_len, &format) == FAILURE) {
  1098. return;
  1099. }
  1100. } else {
  1101. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ls!", &fname, &fname_len, &flags, &alias, &alias_len) == FAILURE) {
  1102. return;
  1103. }
  1104. }
  1105. if (phar_obj->arc.archive) {
  1106. zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Cannot call constructor twice");
  1107. return;
  1108. }
  1109. save_fname = fname;
  1110. if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, !is_data, 2 TSRMLS_CC)) {
  1111. /* use arch (the basename for the archive) for fname instead of fname */
  1112. /* this allows support for RecursiveDirectoryIterator of subdirectories */
  1113. #ifdef PHP_WIN32
  1114. phar_unixify_path_separators(arch, arch_len);
  1115. #endif
  1116. fname = arch;
  1117. fname_len = arch_len;
  1118. #ifdef PHP_WIN32
  1119. } else {
  1120. arch = estrndup(fname, fname_len);
  1121. arch_len = fname_len;
  1122. fname = arch;
  1123. phar_unixify_path_separators(arch, arch_len);
  1124. #endif
  1125. }
  1126. if (phar_open_or_create_filename(fname, fname_len, alias, alias_len, is_data, REPORT_ERRORS, &phar_data, &error TSRMLS_CC) == FAILURE) {
  1127. if (fname == arch && fname != save_fname) {
  1128. efree(arch);
  1129. fname = save_fname;
  1130. }
  1131. if (entry) {
  1132. efree(entry);
  1133. }
  1134. if (error) {
  1135. zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
  1136. "%s", error);
  1137. efree(error);
  1138. } else {
  1139. zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
  1140. "Phar creation or opening failed");
  1141. }
  1142. return;
  1143. }
  1144. if (is_data && phar_data->is_tar && phar_data->is_brandnew && format == PHAR_FORMAT_ZIP) {
  1145. phar_data->is_zip = 1;
  1146. phar_data->is_tar = 0;
  1147. }
  1148. if (fname == arch) {
  1149. efree(arch);
  1150. fname = save_fname;
  1151. }
  1152. if ((is_data && !phar_data->is_data) || (!is_data && phar_data->is_data)) {
  1153. if (is_data) {
  1154. zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
  1155. "PharData class can only be used for non-executable tar and zip archives");
  1156. } else {
  1157. zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
  1158. "Phar class can only be used for executable tar and zip archives");
  1159. }
  1160. efree(entry);
  1161. return;
  1162. }
  1163. is_data = phar_data->is_data;
  1164. if (!phar_data->is_persistent) {
  1165. ++(phar_data->refcount);
  1166. }
  1167. phar_obj->arc.archive = phar_data;
  1168. phar_obj->spl.oth_handler = &phar_spl_foreign_handler;
  1169. if (entry) {
  1170. fname_len = spprintf(&fname, 0, "phar://%s%s", phar_data->fname, entry);
  1171. efree(entry);
  1172. } else {
  1173. fname_len = spprintf(&fname, 0, "phar://%s", phar_data->fname);
  1174. }
  1175. INIT_PZVAL(&arg1);
  1176. ZVAL_STRINGL(&arg1, fname, fname_len, 0);
  1177. INIT_PZVAL(&arg2);
  1178. ZVAL_LONG(&arg2, flags);
  1179. zend_call_method_with_2_params(&zobj, Z_OBJCE_P(zobj),
  1180. &spl_ce_RecursiveDirectoryIterator->constructor, "__construct", NULL, &arg1, &arg2);
  1181. if (!phar_data->is_persistent) {
  1182. phar_obj->arc.archive->is_data = is_data;
  1183. } else if (!EG(exception)) {
  1184. /* register this guy so we can modify if necessary */
  1185. 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);
  1186. }
  1187. phar_obj->spl.info_class = phar_ce_entry;
  1188. efree(fname);
  1189. #endif /* HAVE_SPL */
  1190. }
  1191. /* }}} */
  1192. /* {{{ proto array Phar::getSupportedSignatures()
  1193. * Return array of supported signature types
  1194. */
  1195. PHP_METHOD(Phar, getSupportedSignatures)
  1196. {
  1197. array_init(return_value);
  1198. add_next_index_stringl(return_value, "MD5", 3, 1);
  1199. add_next_index_stringl(return_value, "SHA-1", 5, 1);
  1200. #ifdef PHAR_HASH_OK
  1201. add_next_index_stringl(return_value, "SHA-256", 7, 1);
  1202. add_next_index_stringl(return_value, "SHA-512", 7, 1);
  1203. #endif
  1204. #if PHAR_HAVE_OPENSSL
  1205. add_next_index_stringl(return_value, "OpenSSL", 7, 1);
  1206. #else
  1207. if (zend_hash_exists(&module_registry, "openssl", sizeof("openssl"))) {
  1208. add_next_index_stringl(return_value, "OpenSSL", 7, 1);
  1209. }
  1210. #endif
  1211. }
  1212. /* }}} */
  1213. /* {{{ proto array Phar::getSupportedCompression()
  1214. * Return array of supported comparession algorithms
  1215. */
  1216. PHP_METHOD(Phar, getSupportedCompression)
  1217. {
  1218. array_init(return_value);
  1219. phar_request_initialize(TSRMLS_C);
  1220. if (PHAR_G(has_zlib)) {
  1221. add_next_index_stringl(return_value, "GZ", 2, 1);
  1222. }
  1223. if (PHAR_G(has_bz2)) {
  1224. add_next_index_stringl(return_value, "BZIP2", 5, 1);
  1225. }
  1226. }
  1227. /* }}} */
  1228. /* {{{ proto array Phar::unlinkArchive(string archive)
  1229. * Completely remove a phar archive from memory and disk
  1230. */
  1231. PHP_METHOD(Phar, unlinkArchive)
  1232. {
  1233. char *fname, *error, *zname, *arch, *entry;
  1234. int fname_len, zname_len, arch_len, entry_len;
  1235. phar_archive_data *phar;
  1236. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &fname, &fname_len) == FAILURE) {
  1237. RETURN_FALSE;
  1238. }
  1239. if (!fname_len) {
  1240. zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Unknown phar archive \"\"");
  1241. return;
  1242. }
  1243. if (FAILURE == phar_open_from_filename(fname, fname_len, NULL, 0, REPORT_ERRORS, &phar, &error TSRMLS_CC)) {
  1244. if (error) {
  1245. zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Unknown phar archive \"%s\": %s", fname, error);
  1246. efree(error);
  1247. } else {
  1248. zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Unknown phar archive \"%s\"", fname);
  1249. }
  1250. return;
  1251. }
  1252. zname = zend_get_executed_filename(TSRMLS_C);
  1253. zname_len = strlen(zname);
  1254. 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)) {
  1255. if (arch_len == fname_len && !memcmp(arch, fname, arch_len)) {
  1256. zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar archive \"%s\" cannot be unlinked from within itself", fname);
  1257. efree(arch);
  1258. efree(entry);
  1259. return;
  1260. }
  1261. efree(arch);
  1262. efree(entry);
  1263. }
  1264. if (phar->is_persistent) {
  1265. zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar archive \"%s\" is in phar.cache_list, cannot unlinkArchive()", fname);
  1266. return;
  1267. }
  1268. if (phar->refcount) {
  1269. 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);
  1270. return;
  1271. }
  1272. fname = estrndup(phar->fname, phar->fname_len);
  1273. /* invalidate phar cache */
  1274. PHAR_G(last_phar) = NULL;
  1275. PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
  1276. phar_archive_delref(phar TSRMLS_CC);
  1277. unlink(fname);
  1278. efree(fname);
  1279. RETURN_TRUE;
  1280. }
  1281. /* }}} */
  1282. #if HAVE_SPL
  1283. #define PHAR_ARCHIVE_OBJECT() \
  1284. phar_archive_object *phar_obj = (phar_archive_object*)zend_object_store_get_object(getThis() TSRMLS_CC); \
  1285. if (!phar_obj->arc.archive) { \
  1286. zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, \
  1287. "Cannot call method on an uninitialized Phar object"); \
  1288. return; \
  1289. }
  1290. /* {{{ proto void Phar::__destruct()
  1291. * if persistent, remove from the cache
  1292. */
  1293. PHP_METHOD(Phar, __destruct)
  1294. {
  1295. phar_archive_object *phar_obj = (phar_archive_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
  1296. if (phar_obj->arc.archive && phar_obj->arc.archive->is_persistent) {
  1297. zend_hash_del(&PHAR_GLOBALS->phar_persist_map, (const char *) phar_obj->arc.archive, sizeof(phar_obj->arc.archive));
  1298. }
  1299. }
  1300. /* }}} */
  1301. struct _phar_t {
  1302. phar_archive_object *p;
  1303. zend_class_entry *c;
  1304. char *b;
  1305. uint l;
  1306. zval *ret;
  1307. int count;
  1308. php_stream *fp;
  1309. };
  1310. static int phar_build(zend_object_iterator *iter, void *puser TSRMLS_DC) /* {{{ */
  1311. {
  1312. zval **value;
  1313. zend_uchar key_type;
  1314. zend_bool close_fp = 1;
  1315. ulong int_key;
  1316. struct _phar_t *p_obj = (struct _phar_t*) puser;
  1317. uint str_key_len, base_len = p_obj->l, fname_len;
  1318. phar_entry_data *data;
  1319. php_stream *fp;
  1320. size_t contents_len;
  1321. char *fname, *error = NULL, *base = p_obj->b, *opened, *save = NULL, *temp = NULL;
  1322. phar_zstr key;
  1323. char *str_key;
  1324. zend_class_entry *ce = p_obj->c;
  1325. phar_archive_object *phar_obj = p_obj->p;
  1326. char *str = "[stream]";
  1327. iter->funcs->get_current_data(iter, &value TSRMLS_CC);
  1328. if (EG(exception)) {
  1329. return ZEND_HASH_APPLY_STOP;
  1330. }
  1331. if (!value) {
  1332. /* failure in get_current_data */
  1333. zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %v returned no value", ce->name);
  1334. return ZEND_HASH_APPLY_STOP;
  1335. }
  1336. switch (Z_TYPE_PP(value)) {
  1337. #if PHP_VERSION_ID >= 60000
  1338. case IS_UNICODE:
  1339. zval_unicode_to_string(*(value) TSRMLS_CC);
  1340. /* break intentionally omitted */
  1341. #endif
  1342. case IS_STRING:
  1343. break;
  1344. case IS_RESOURCE:
  1345. php_stream_from_zval_no_verify(fp, value);
  1346. if (!fp) {
  1347. zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Iterator %v returned an invalid stream handle", ce->name);
  1348. return ZEND_HASH_APPLY_STOP;
  1349. }
  1350. if (iter->funcs->get_current_key) {
  1351. key_type = iter->funcs->get_current_key(iter, &key, &str_key_len, &int_key TSRMLS_CC);
  1352. if (EG(exception)) {
  1353. return ZEND_HASH_APPLY_STOP;
  1354. }
  1355. if (key_type == HASH_KEY_IS_LONG) {
  1356. zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %v returned an invalid key (must return a string)", ce->name);
  1357. return ZEND_HASH_APPLY_STOP;
  1358. }
  1359. if (key_type > 9) { /* IS_UNICODE == 10 */
  1360. #if PHP_VERSION_ID < 60000
  1361. /* this can never happen, but fixes a compile warning */
  1362. spprintf(&str_key, 0, "%s", key);
  1363. #else
  1364. spprintf(&str_key, 0, "%v", key);
  1365. ezfree(key);
  1366. #endif
  1367. } else {
  1368. PHAR_STR(key, str_key);
  1369. }
  1370. save = str_key;
  1371. if (str_key[str_key_len - 1] == '\0') {
  1372. str_key_len--;
  1373. }
  1374. } else {
  1375. zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %v returned an invalid key (must return a string)", ce->name);
  1376. return ZEND_HASH_APPLY_STOP;
  1377. }
  1378. close_fp = 0;
  1379. opened = (char *) estrndup(str, sizeof("[stream]") + 1);
  1380. goto after_open_fp;
  1381. case IS_OBJECT:
  1382. if (instanceof_function(Z_OBJCE_PP(value), spl_ce_SplFileInfo TSRMLS_CC)) {
  1383. char *test = NULL;
  1384. zval dummy;
  1385. spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(*value TSRMLS_CC);
  1386. if (!base_len) {
  1387. zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Iterator %v returns an SplFileInfo object, so base directory must be specified", ce->name);
  1388. return ZEND_HASH_APPLY_STOP;
  1389. }
  1390. switch (intern->type) {
  1391. case SPL_FS_DIR:
  1392. #if PHP_VERSION_ID >= 60000
  1393. test = spl_filesystem_object_get_path(intern, NULL, NULL TSRMLS_CC).s;
  1394. #elif PHP_VERSION_ID >= 50300
  1395. test = spl_filesystem_object_get_path(intern, NULL TSRMLS_CC);
  1396. #else
  1397. test = intern->path;
  1398. #endif
  1399. fname_len = spprintf(&fname, 0, "%s%c%s", test, DEFAULT_SLASH, intern->u.dir.entry.d_name);
  1400. php_stat(fname, fname_len, FS_IS_DIR, &dummy TSRMLS_CC);
  1401. if (Z_BVAL(dummy)) {
  1402. /* ignore directories */
  1403. efree(fname);
  1404. return ZEND_HASH_APPLY_KEEP;
  1405. }
  1406. test = expand_filepath(fname, NULL TSRMLS_CC);
  1407. if (test) {
  1408. efree(fname);
  1409. fname = test;
  1410. fname_len = strlen(fname);
  1411. }
  1412. save = fname;
  1413. goto phar_spl_fileinfo;
  1414. case SPL_FS_INFO:
  1415. case SPL_FS_FILE:
  1416. #if PHP_VERSION_ID >= 60000
  1417. if (intern->file_name_type == IS_UNICODE) {
  1418. zval zv;
  1419. INIT_ZVAL(zv);
  1420. Z_UNIVAL(zv) = intern->file_name;
  1421. Z_UNILEN(zv) = intern->file_name_len;
  1422. Z_TYPE(zv) = IS_UNICODE;
  1423. zval_copy_ctor(&zv);
  1424. zval_unicode_to_string(&zv TSRMLS_CC);
  1425. fname = expand_filepath(Z_STRVAL(zv), NULL TSRMLS_CC);
  1426. ezfree(Z_UNIVAL(zv));
  1427. } else {
  1428. fname = expand_filepath(intern->file_name.s, NULL TSRMLS_CC);
  1429. }
  1430. #else
  1431. fname = expand_filepath(intern->file_name, NULL TSRMLS_CC);
  1432. #endif
  1433. fname_len = strlen(fname);
  1434. save = fname;
  1435. goto phar_spl_fileinfo;

Large files files are truncated, but you can click here to view the full file