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