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