PageRenderTime 50ms CodeModel.GetById 9ms RepoModel.GetById 0ms app.codeStats 1ms

/ext/zip/php_zip.c

http://github.com/php/php-src
C | 3380 lines | 2542 code | 515 blank | 323 comment | 537 complexity | 16a439257a40511c3f950f39ac4a4335 MD5 | raw file
Possible License(s): BSD-2-Clause, BSD-3-Clause, MPL-2.0-no-copyleft-exception, LGPL-2.1

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

  1. /*
  2. +----------------------------------------------------------------------+
  3. | Copyright (c) The PHP Group |
  4. +----------------------------------------------------------------------+
  5. | This source file is subject to version 3.01 of the PHP license, |
  6. | that is bundled with this package in the file LICENSE, and is |
  7. | available through the world-wide-web at the following url: |
  8. | http://www.php.net/license/3_01.txt. |
  9. | If you did not receive a copy of the PHP license and are unable to |
  10. | obtain it through the world-wide-web, please send a note to |
  11. | license@php.net so we can mail you a copy immediately. |
  12. +----------------------------------------------------------------------+
  13. | Author: Piere-Alain Joye <pierre@php.net> |
  14. +----------------------------------------------------------------------+
  15. */
  16. #ifdef HAVE_CONFIG_H
  17. #include "config.h"
  18. #endif
  19. #include "php.h"
  20. #include "php_ini.h"
  21. #include "ext/standard/info.h"
  22. #include "ext/standard/file.h"
  23. #include "ext/standard/php_string.h"
  24. #include "ext/pcre/php_pcre.h"
  25. #include "ext/standard/php_filestat.h"
  26. #include "zend_interfaces.h"
  27. #include "php_zip.h"
  28. #include "php_zip_arginfo.h"
  29. /* zip_open is a macro for renaming libzip zipopen, so we need to use PHP_NAMED_FUNCTION */
  30. static PHP_NAMED_FUNCTION(zif_zip_open);
  31. static PHP_NAMED_FUNCTION(zif_zip_read);
  32. static PHP_NAMED_FUNCTION(zif_zip_close);
  33. static PHP_NAMED_FUNCTION(zif_zip_entry_read);
  34. static PHP_NAMED_FUNCTION(zif_zip_entry_filesize);
  35. static PHP_NAMED_FUNCTION(zif_zip_entry_name);
  36. static PHP_NAMED_FUNCTION(zif_zip_entry_compressedsize);
  37. static PHP_NAMED_FUNCTION(zif_zip_entry_compressionmethod);
  38. static PHP_NAMED_FUNCTION(zif_zip_entry_open);
  39. static PHP_NAMED_FUNCTION(zif_zip_entry_close);
  40. #ifdef HAVE_GLOB
  41. #ifndef PHP_WIN32
  42. #include <glob.h>
  43. #else
  44. #include "win32/glob.h"
  45. #endif
  46. #endif
  47. /* {{{ Resource le */
  48. static int le_zip_dir;
  49. #define le_zip_dir_name "Zip Directory"
  50. static int le_zip_entry;
  51. #define le_zip_entry_name "Zip Entry"
  52. /* }}} */
  53. /* {{{ PHP_ZIP_STAT_INDEX(za, index, flags, sb) */
  54. #define PHP_ZIP_STAT_INDEX(za, index, flags, sb) \
  55. if (zip_stat_index(za, index, flags, &sb) != 0) { \
  56. RETURN_FALSE; \
  57. }
  58. /* }}} */
  59. /* {{{ PHP_ZIP_STAT_PATH(za, path, path_len, flags, sb) */
  60. #define PHP_ZIP_STAT_PATH(za, path, path_len, flags, sb) \
  61. if (path_len < 1) { \
  62. php_error_docref(NULL, E_NOTICE, "Empty string as entry name"); \
  63. RETURN_FALSE; \
  64. } \
  65. if (zip_stat(za, path, flags, &sb) != 0) { \
  66. RETURN_FALSE; \
  67. }
  68. /* }}} */
  69. /* {{{ PHP_ZIP_SET_FILE_COMMENT(za, index, comment, comment_len) */
  70. #define PHP_ZIP_SET_FILE_COMMENT(za, index, comment, comment_len) \
  71. if (comment_len == 0) { \
  72. /* Passing NULL remove the existing comment */ \
  73. if (zip_file_set_comment(za, index, NULL, 0, 0) < 0) { \
  74. RETURN_FALSE; \
  75. } \
  76. } else if (zip_file_set_comment(za, index, comment, comment_len, 0) < 0) { \
  77. RETURN_FALSE; \
  78. } \
  79. RETURN_TRUE;
  80. /* }}} */
  81. # define add_ascii_assoc_string add_assoc_string
  82. # define add_ascii_assoc_long add_assoc_long
  83. /* Flatten a path by making a relative path (to .)*/
  84. static char * php_zip_make_relative_path(char *path, size_t path_len) /* {{{ */
  85. {
  86. char *path_begin = path;
  87. size_t i;
  88. if (path_len < 1 || path == NULL) {
  89. return NULL;
  90. }
  91. if (IS_SLASH(path[0])) {
  92. return path + 1;
  93. }
  94. i = path_len;
  95. while (1) {
  96. while (i > 0 && !IS_SLASH(path[i])) {
  97. i--;
  98. }
  99. if (!i) {
  100. return path;
  101. }
  102. if (i >= 2 && (path[i -1] == '.' || path[i -1] == ':')) {
  103. /* i is the position of . or :, add 1 for / */
  104. path_begin = path + i + 1;
  105. break;
  106. }
  107. i--;
  108. }
  109. return path_begin;
  110. }
  111. /* }}} */
  112. # define CWD_STATE_ALLOC(l) emalloc(l)
  113. # define CWD_STATE_FREE(s) efree(s)
  114. /* {{{ php_zip_extract_file */
  115. static int php_zip_extract_file(struct zip * za, char *dest, char *file, size_t file_len)
  116. {
  117. php_stream_statbuf ssb;
  118. struct zip_file *zf;
  119. struct zip_stat sb;
  120. char b[8192];
  121. int n, ret;
  122. php_stream *stream;
  123. char *fullpath;
  124. char *file_dirname_fullpath;
  125. char file_dirname[MAXPATHLEN];
  126. size_t dir_len, len;
  127. int is_dir_only = 0;
  128. char *path_cleaned;
  129. size_t path_cleaned_len;
  130. cwd_state new_state;
  131. zend_string *file_basename;
  132. new_state.cwd = CWD_STATE_ALLOC(1);
  133. new_state.cwd[0] = '\0';
  134. new_state.cwd_length = 0;
  135. /* Clean/normlize the path and then transform any path (absolute or relative)
  136. to a path relative to cwd (../../mydir/foo.txt > mydir/foo.txt)
  137. */
  138. virtual_file_ex(&new_state, file, NULL, CWD_EXPAND);
  139. path_cleaned = php_zip_make_relative_path(new_state.cwd, new_state.cwd_length);
  140. if(!path_cleaned) {
  141. return 0;
  142. }
  143. path_cleaned_len = strlen(path_cleaned);
  144. if (path_cleaned_len >= MAXPATHLEN || zip_stat(za, file, 0, &sb) != 0) {
  145. return 0;
  146. }
  147. /* it is a directory only, see #40228 */
  148. if (path_cleaned_len > 1 && IS_SLASH(path_cleaned[path_cleaned_len - 1])) {
  149. len = spprintf(&file_dirname_fullpath, 0, "%s/%s", dest, path_cleaned);
  150. is_dir_only = 1;
  151. } else {
  152. memcpy(file_dirname, path_cleaned, path_cleaned_len);
  153. dir_len = php_dirname(file_dirname, path_cleaned_len);
  154. if (!dir_len || (dir_len == 1 && file_dirname[0] == '.')) {
  155. len = spprintf(&file_dirname_fullpath, 0, "%s", dest);
  156. } else {
  157. len = spprintf(&file_dirname_fullpath, 0, "%s/%s", dest, file_dirname);
  158. }
  159. file_basename = php_basename(path_cleaned, path_cleaned_len, NULL, 0);
  160. if (ZIP_OPENBASEDIR_CHECKPATH(file_dirname_fullpath)) {
  161. efree(file_dirname_fullpath);
  162. zend_string_release_ex(file_basename, 0);
  163. CWD_STATE_FREE(new_state.cwd);
  164. return 0;
  165. }
  166. }
  167. /* let see if the path already exists */
  168. if (php_stream_stat_path_ex(file_dirname_fullpath, PHP_STREAM_URL_STAT_QUIET, &ssb, NULL) < 0) {
  169. ret = php_stream_mkdir(file_dirname_fullpath, 0777, PHP_STREAM_MKDIR_RECURSIVE|REPORT_ERRORS, NULL);
  170. if (!ret) {
  171. efree(file_dirname_fullpath);
  172. if (!is_dir_only) {
  173. zend_string_release_ex(file_basename, 0);
  174. CWD_STATE_FREE(new_state.cwd);
  175. }
  176. return 0;
  177. }
  178. }
  179. /* it is a standalone directory, job done */
  180. if (is_dir_only) {
  181. efree(file_dirname_fullpath);
  182. CWD_STATE_FREE(new_state.cwd);
  183. return 1;
  184. }
  185. len = spprintf(&fullpath, 0, "%s/%s", file_dirname_fullpath, ZSTR_VAL(file_basename));
  186. if (!len) {
  187. efree(file_dirname_fullpath);
  188. zend_string_release_ex(file_basename, 0);
  189. CWD_STATE_FREE(new_state.cwd);
  190. return 0;
  191. } else if (len > MAXPATHLEN) {
  192. php_error_docref(NULL, E_WARNING, "Full extraction path exceed MAXPATHLEN (%i)", MAXPATHLEN);
  193. efree(file_dirname_fullpath);
  194. zend_string_release_ex(file_basename, 0);
  195. CWD_STATE_FREE(new_state.cwd);
  196. return 0;
  197. }
  198. /* check again the full path, not sure if it
  199. * is required, does a file can have a different
  200. * safemode status as its parent folder?
  201. */
  202. if (ZIP_OPENBASEDIR_CHECKPATH(fullpath)) {
  203. efree(fullpath);
  204. efree(file_dirname_fullpath);
  205. zend_string_release_ex(file_basename, 0);
  206. CWD_STATE_FREE(new_state.cwd);
  207. return 0;
  208. }
  209. zf = zip_fopen(za, file, 0);
  210. if (zf == NULL) {
  211. n = -1;
  212. goto done;
  213. }
  214. stream = php_stream_open_wrapper(fullpath, "w+b", REPORT_ERRORS, NULL);
  215. if (stream == NULL) {
  216. n = -1;
  217. zip_fclose(zf);
  218. goto done;
  219. }
  220. n = 0;
  221. while ((n=zip_fread(zf, b, sizeof(b))) > 0) {
  222. php_stream_write(stream, b, n);
  223. }
  224. if (stream->wrapper->wops->stream_metadata) {
  225. struct utimbuf ut;
  226. ut.modtime = ut.actime = sb.mtime;
  227. stream->wrapper->wops->stream_metadata(stream->wrapper, fullpath, PHP_STREAM_META_TOUCH, &ut, NULL);
  228. }
  229. php_stream_close(stream);
  230. n = zip_fclose(zf);
  231. done:
  232. efree(fullpath);
  233. zend_string_release_ex(file_basename, 0);
  234. efree(file_dirname_fullpath);
  235. CWD_STATE_FREE(new_state.cwd);
  236. if (n<0) {
  237. return 0;
  238. } else {
  239. return 1;
  240. }
  241. }
  242. /* }}} */
  243. static int php_zip_add_file(ze_zip_object *obj, const char *filename, size_t filename_len,
  244. char *entry_name, size_t entry_name_len, /* unused if replace >= 0 */
  245. zip_uint64_t offset_start, zip_uint64_t offset_len,
  246. zend_long replace, /* index to replace, add new file if < 0 */
  247. zip_flags_t flags
  248. ) /* {{{ */
  249. {
  250. struct zip_source *zs;
  251. char resolved_path[MAXPATHLEN];
  252. zval exists_flag;
  253. if (ZIP_OPENBASEDIR_CHECKPATH(filename)) {
  254. return -1;
  255. }
  256. if (!expand_filepath(filename, resolved_path)) {
  257. return -1;
  258. }
  259. php_stat(resolved_path, strlen(resolved_path), FS_EXISTS, &exists_flag);
  260. if (Z_TYPE(exists_flag) == IS_FALSE) {
  261. return -1;
  262. }
  263. zs = zip_source_file(obj->za, resolved_path, offset_start, offset_len);
  264. if (!zs) {
  265. return -1;
  266. }
  267. /* Replace */
  268. if (replace >= 0) {
  269. if (zip_file_replace(obj->za, replace, zs, flags) < 0) {
  270. zip_source_free(zs);
  271. return -1;
  272. }
  273. zip_error_clear(obj->za);
  274. return 1;
  275. }
  276. /* Add */
  277. obj->last_id = zip_file_add(obj->za, entry_name, zs, flags);
  278. if (obj->last_id < 0) {
  279. zip_source_free(zs);
  280. return -1;
  281. }
  282. zip_error_clear(obj->za);
  283. return 1;
  284. }
  285. /* }}} */
  286. typedef struct {
  287. zend_long remove_all_path;
  288. char *remove_path;
  289. size_t remove_path_len;
  290. char *add_path;
  291. size_t add_path_len;
  292. zip_flags_t flags;
  293. zip_int32_t comp_method;
  294. zip_uint32_t comp_flags;
  295. #ifdef HAVE_ENCRYPTION
  296. zip_int16_t enc_method;
  297. char *enc_password;
  298. #endif
  299. } zip_options;
  300. static int php_zip_parse_options(zval *options, zip_options *opts)
  301. /* {{{ */
  302. {
  303. zval *option;
  304. /* default values */
  305. memset(opts, 0, sizeof(zip_options));
  306. opts->flags = ZIP_FL_OVERWRITE;
  307. opts->comp_method = -1; /* -1 to not change default */
  308. #ifdef HAVE_ENCRYPTION
  309. opts->enc_method = -1; /* -1 to not change default */
  310. #endif
  311. if ((option = zend_hash_str_find(Z_ARRVAL_P(options), "remove_all_path", sizeof("remove_all_path") - 1)) != NULL) {
  312. opts->remove_all_path = zval_get_long(option);
  313. }
  314. if ((option = zend_hash_str_find(Z_ARRVAL_P(options), "comp_method", sizeof("comp_method") - 1)) != NULL) {
  315. opts->comp_method = zval_get_long(option);
  316. if ((option = zend_hash_str_find(Z_ARRVAL_P(options), "comp_flags", sizeof("comp_flags") - 1)) != NULL) {
  317. opts->comp_flags = zval_get_long(option);
  318. }
  319. }
  320. #ifdef HAVE_ENCRYPTION
  321. if ((option = zend_hash_str_find(Z_ARRVAL_P(options), "enc_method", sizeof("enc_method") - 1)) != NULL) {
  322. opts->enc_method = zval_get_long(option);
  323. if ((option = zend_hash_str_find(Z_ARRVAL_P(options), "enc_password", sizeof("enc_password") - 1)) != NULL) {
  324. if (Z_TYPE_P(option) != IS_STRING) {
  325. php_error_docref(NULL, E_WARNING, "enc_password option expected to be a string");
  326. return -1;
  327. }
  328. opts->enc_password = Z_STRVAL_P(option);
  329. }
  330. }
  331. #endif
  332. if ((option = zend_hash_str_find(Z_ARRVAL_P(options), "remove_path", sizeof("remove_path") - 1)) != NULL) {
  333. if (Z_TYPE_P(option) != IS_STRING) {
  334. php_error_docref(NULL, E_WARNING, "remove_path option expected to be a string");
  335. return -1;
  336. }
  337. if (Z_STRLEN_P(option) < 1) {
  338. php_error_docref(NULL, E_NOTICE, "Empty string given as remove_path option");
  339. return -1;
  340. }
  341. if (Z_STRLEN_P(option) >= MAXPATHLEN) {
  342. php_error_docref(NULL, E_WARNING, "remove_path string is too long (max: %d, %zd given)",
  343. MAXPATHLEN - 1, Z_STRLEN_P(option));
  344. return -1;
  345. }
  346. opts->remove_path_len = Z_STRLEN_P(option);
  347. opts->remove_path = Z_STRVAL_P(option);
  348. }
  349. if ((option = zend_hash_str_find(Z_ARRVAL_P(options), "add_path", sizeof("add_path") - 1)) != NULL) {
  350. if (Z_TYPE_P(option) != IS_STRING) {
  351. php_error_docref(NULL, E_WARNING, "add_path option expected to be a string");
  352. return -1;
  353. }
  354. if (Z_STRLEN_P(option) < 1) {
  355. php_error_docref(NULL, E_NOTICE, "Empty string given as the add_path option");
  356. return -1;
  357. }
  358. if (Z_STRLEN_P(option) >= MAXPATHLEN) {
  359. php_error_docref(NULL, E_WARNING, "add_path string too long (max: %d, %zd given)",
  360. MAXPATHLEN - 1, Z_STRLEN_P(option));
  361. return -1;
  362. }
  363. opts->add_path_len = Z_STRLEN_P(option);
  364. opts->add_path = Z_STRVAL_P(option);
  365. }
  366. if ((option = zend_hash_str_find(Z_ARRVAL_P(options), "flags", sizeof("flags") - 1)) != NULL) {
  367. if (Z_TYPE_P(option) != IS_LONG) {
  368. php_error_docref(NULL, E_WARNING, "flags option expected to be a integer");
  369. return -1;
  370. }
  371. opts->flags = Z_LVAL_P(option);
  372. }
  373. return 1;
  374. }
  375. /* }}} */
  376. /* {{{ REGISTER_ZIP_CLASS_CONST_LONG */
  377. #define REGISTER_ZIP_CLASS_CONST_LONG(const_name, value) \
  378. zend_declare_class_constant_long(zip_class_entry, const_name, sizeof(const_name)-1, (zend_long)value);
  379. /* }}} */
  380. /* {{{ ZIP_FROM_OBJECT */
  381. #define ZIP_FROM_OBJECT(intern, object) \
  382. { \
  383. ze_zip_object *obj = Z_ZIP_P(object); \
  384. intern = obj->za; \
  385. if (!intern) { \
  386. zend_value_error("Invalid or uninitialized Zip object"); \
  387. RETURN_THROWS(); \
  388. } \
  389. }
  390. /* }}} */
  391. /* {{{ RETURN_SB(sb) */
  392. #ifdef HAVE_ENCRYPTION
  393. #define RETURN_SB(sb) \
  394. { \
  395. array_init(return_value); \
  396. add_ascii_assoc_string(return_value, "name", (char *)(sb)->name); \
  397. add_ascii_assoc_long(return_value, "index", (zend_long) (sb)->index); \
  398. add_ascii_assoc_long(return_value, "crc", (zend_long) (sb)->crc); \
  399. add_ascii_assoc_long(return_value, "size", (zend_long) (sb)->size); \
  400. add_ascii_assoc_long(return_value, "mtime", (zend_long) (sb)->mtime); \
  401. add_ascii_assoc_long(return_value, "comp_size", (zend_long) (sb)->comp_size); \
  402. add_ascii_assoc_long(return_value, "comp_method", (zend_long) (sb)->comp_method); \
  403. add_ascii_assoc_long(return_value, "encryption_method", (zend_long) (sb)->encryption_method); \
  404. }
  405. #else
  406. #define RETURN_SB(sb) \
  407. { \
  408. array_init(return_value); \
  409. add_ascii_assoc_string(return_value, "name", (char *)(sb)->name); \
  410. add_ascii_assoc_long(return_value, "index", (zend_long) (sb)->index); \
  411. add_ascii_assoc_long(return_value, "crc", (zend_long) (sb)->crc); \
  412. add_ascii_assoc_long(return_value, "size", (zend_long) (sb)->size); \
  413. add_ascii_assoc_long(return_value, "mtime", (zend_long) (sb)->mtime); \
  414. add_ascii_assoc_long(return_value, "comp_size", (zend_long) (sb)->comp_size); \
  415. add_ascii_assoc_long(return_value, "comp_method", (zend_long) (sb)->comp_method); \
  416. }
  417. #endif
  418. /* }}} */
  419. static zend_long php_zip_status(ze_zip_object *obj) /* {{{ */
  420. {
  421. int zep = obj->err_zip; /* saved err if closed */
  422. if (obj->za) {
  423. #if LIBZIP_VERSION_MAJOR < 1
  424. int syp;
  425. zip_error_get(obj->za, &zep, &syp);
  426. #else
  427. zip_error_t *err;
  428. err = zip_get_error(obj->za);
  429. zep = zip_error_code_zip(err);
  430. zip_error_fini(err);
  431. #endif
  432. }
  433. return zep;
  434. }
  435. /* }}} */
  436. static zend_long php_zip_last_id(ze_zip_object *obj) /* {{{ */
  437. {
  438. return obj->last_id;
  439. }
  440. /* }}} */
  441. static zend_long php_zip_status_sys(ze_zip_object *obj) /* {{{ */
  442. {
  443. int syp = obj->err_sys; /* saved err if closed */
  444. if (obj->za) {
  445. #if LIBZIP_VERSION_MAJOR < 1
  446. int zep;
  447. zip_error_get(obj->za, &zep, &syp);
  448. #else
  449. zip_error_t *err;
  450. err = zip_get_error(obj->za);
  451. syp = zip_error_code_system(err);
  452. zip_error_fini(err);
  453. #endif
  454. }
  455. return syp;
  456. }
  457. /* }}} */
  458. static zend_long php_zip_get_num_files(ze_zip_object *obj) /* {{{ */
  459. {
  460. if (obj->za) {
  461. zip_int64_t num = zip_get_num_entries(obj->za, 0);
  462. return MIN(num, ZEND_LONG_MAX);
  463. }
  464. return 0;
  465. }
  466. /* }}} */
  467. static char * php_zipobj_get_filename(ze_zip_object *obj, int *len) /* {{{ */
  468. {
  469. if (obj && obj->filename) {
  470. *len = strlen(obj->filename);
  471. return obj->filename;
  472. }
  473. return NULL;
  474. }
  475. /* }}} */
  476. static char * php_zipobj_get_zip_comment(ze_zip_object *obj, int *len) /* {{{ */
  477. {
  478. if (obj->za) {
  479. return (char *)zip_get_archive_comment(obj->za, len, 0);
  480. }
  481. return NULL;
  482. }
  483. /* }}} */
  484. #ifdef HAVE_GLOB /* {{{ */
  485. #ifndef GLOB_ONLYDIR
  486. #define GLOB_ONLYDIR (1<<30)
  487. #define GLOB_EMULATE_ONLYDIR
  488. #define GLOB_FLAGMASK (~GLOB_ONLYDIR)
  489. #else
  490. #define GLOB_FLAGMASK (~0)
  491. #endif
  492. #ifndef GLOB_BRACE
  493. # define GLOB_BRACE 0
  494. #endif
  495. #ifndef GLOB_MARK
  496. # define GLOB_MARK 0
  497. #endif
  498. #ifndef GLOB_NOSORT
  499. # define GLOB_NOSORT 0
  500. #endif
  501. #ifndef GLOB_NOCHECK
  502. # define GLOB_NOCHECK 0
  503. #endif
  504. #ifndef GLOB_NOESCAPE
  505. # define GLOB_NOESCAPE 0
  506. #endif
  507. #ifndef GLOB_ERR
  508. # define GLOB_ERR 0
  509. #endif
  510. /* This is used for checking validity of passed flags (passing invalid flags causes segfault in glob()!! */
  511. #define GLOB_AVAILABLE_FLAGS (0 | GLOB_BRACE | GLOB_MARK | GLOB_NOSORT | GLOB_NOCHECK | GLOB_NOESCAPE | GLOB_ERR | GLOB_ONLYDIR)
  512. #endif /* }}} */
  513. int php_zip_glob(char *pattern, int pattern_len, zend_long flags, zval *return_value) /* {{{ */
  514. {
  515. #ifdef HAVE_GLOB
  516. int cwd_skip = 0;
  517. #ifdef ZTS
  518. char cwd[MAXPATHLEN];
  519. char work_pattern[MAXPATHLEN];
  520. char *result;
  521. #endif
  522. glob_t globbuf;
  523. size_t n;
  524. int ret;
  525. if (pattern_len >= MAXPATHLEN) {
  526. php_error_docref(NULL, E_WARNING, "Pattern exceeds the maximum allowed length of %d characters", MAXPATHLEN);
  527. return -1;
  528. }
  529. if ((GLOB_AVAILABLE_FLAGS & flags) != flags) {
  530. php_error_docref(NULL, E_WARNING, "At least one of the passed flags is invalid or not supported on this platform");
  531. return -1;
  532. }
  533. #ifdef ZTS
  534. if (!IS_ABSOLUTE_PATH(pattern, pattern_len)) {
  535. result = VCWD_GETCWD(cwd, MAXPATHLEN);
  536. if (!result) {
  537. cwd[0] = '\0';
  538. }
  539. #ifdef PHP_WIN32
  540. if (IS_SLASH(*pattern)) {
  541. cwd[2] = '\0';
  542. }
  543. #endif
  544. cwd_skip = strlen(cwd)+1;
  545. snprintf(work_pattern, MAXPATHLEN, "%s%c%s", cwd, DEFAULT_SLASH, pattern);
  546. pattern = work_pattern;
  547. }
  548. #endif
  549. globbuf.gl_offs = 0;
  550. if (0 != (ret = glob(pattern, flags & GLOB_FLAGMASK, NULL, &globbuf))) {
  551. #ifdef GLOB_NOMATCH
  552. if (GLOB_NOMATCH == ret) {
  553. /* Some glob implementation simply return no data if no matches
  554. were found, others return the GLOB_NOMATCH error code.
  555. We don't want to treat GLOB_NOMATCH as an error condition
  556. so that PHP glob() behaves the same on both types of
  557. implementations and so that 'foreach (glob() as ...'
  558. can be used for simple glob() calls without further error
  559. checking.
  560. */
  561. array_init(return_value);
  562. return 0;
  563. }
  564. #endif
  565. return 0;
  566. }
  567. /* now catch the FreeBSD style of "no matches" */
  568. if (!globbuf.gl_pathc || !globbuf.gl_pathv) {
  569. array_init(return_value);
  570. return 0;
  571. }
  572. /* we assume that any glob pattern will match files from one directory only
  573. so checking the dirname of the first match should be sufficient */
  574. if (ZIP_OPENBASEDIR_CHECKPATH(globbuf.gl_pathv[0])) {
  575. return -1;
  576. }
  577. array_init(return_value);
  578. for (n = 0; n < globbuf.gl_pathc; n++) {
  579. /* we need to do this every time since GLOB_ONLYDIR does not guarantee that
  580. * all directories will be filtered. GNU libc documentation states the
  581. * following:
  582. * If the information about the type of the file is easily available
  583. * non-directories will be rejected but no extra work will be done to
  584. * determine the information for each file. I.e., the caller must still be
  585. * able to filter directories out.
  586. */
  587. if (flags & GLOB_ONLYDIR) {
  588. zend_stat_t s;
  589. if (0 != VCWD_STAT(globbuf.gl_pathv[n], &s)) {
  590. continue;
  591. }
  592. if (S_IFDIR != (s.st_mode & S_IFMT)) {
  593. continue;
  594. }
  595. }
  596. add_next_index_string(return_value, globbuf.gl_pathv[n]+cwd_skip);
  597. }
  598. ret = globbuf.gl_pathc;
  599. globfree(&globbuf);
  600. return ret;
  601. #else
  602. zend_throw_error(NULL, "Glob support is not available");
  603. return 0;
  604. #endif /* HAVE_GLOB */
  605. }
  606. /* }}} */
  607. int php_zip_pcre(zend_string *regexp, char *path, int path_len, zval *return_value) /* {{{ */
  608. {
  609. #ifdef ZTS
  610. char cwd[MAXPATHLEN];
  611. char work_path[MAXPATHLEN];
  612. char *result;
  613. #endif
  614. int files_cnt;
  615. zend_string **namelist;
  616. pcre2_match_context *mctx = php_pcre_mctx();
  617. #ifdef ZTS
  618. if (!IS_ABSOLUTE_PATH(path, path_len)) {
  619. result = VCWD_GETCWD(cwd, MAXPATHLEN);
  620. if (!result) {
  621. cwd[0] = '\0';
  622. }
  623. #ifdef PHP_WIN32
  624. if (IS_SLASH(*path)) {
  625. cwd[2] = '\0';
  626. }
  627. #endif
  628. snprintf(work_path, MAXPATHLEN, "%s%c%s", cwd, DEFAULT_SLASH, path);
  629. path = work_path;
  630. }
  631. #endif
  632. if (ZIP_OPENBASEDIR_CHECKPATH(path)) {
  633. return -1;
  634. }
  635. files_cnt = php_stream_scandir(path, &namelist, NULL, (void *) php_stream_dirent_alphasort);
  636. if (files_cnt > 0) {
  637. pcre2_code *re = NULL;
  638. pcre2_match_data *match_data = NULL;
  639. uint32_t i, capture_count;
  640. int rc;
  641. re = pcre_get_compiled_regex(regexp, &capture_count);
  642. if (!re) {
  643. php_error_docref(NULL, E_WARNING, "Invalid expression");
  644. return -1;
  645. }
  646. array_init(return_value);
  647. /* only the files, directories are ignored */
  648. for (i = 0; i < files_cnt; i++) {
  649. zend_stat_t s;
  650. char fullpath[MAXPATHLEN];
  651. size_t namelist_len = ZSTR_LEN(namelist[i]);
  652. if ((namelist_len == 1 && ZSTR_VAL(namelist[i])[0] == '.') ||
  653. (namelist_len == 2 && ZSTR_VAL(namelist[i])[0] == '.' && ZSTR_VAL(namelist[i])[1] == '.')) {
  654. zend_string_release_ex(namelist[i], 0);
  655. continue;
  656. }
  657. if ((path_len + namelist_len + 1) >= MAXPATHLEN) {
  658. php_error_docref(NULL, E_WARNING, "add_path string too long (max: %u, %zu given)",
  659. MAXPATHLEN - 1, (path_len + namelist_len + 1));
  660. zend_string_release_ex(namelist[i], 0);
  661. break;
  662. }
  663. match_data = php_pcre_create_match_data(capture_count, re);
  664. if (!match_data) {
  665. /* Allocation failed, but can proceed to the next pattern. */
  666. zend_string_release_ex(namelist[i], 0);
  667. continue;
  668. }
  669. rc = pcre2_match(re, (PCRE2_SPTR)ZSTR_VAL(namelist[i]), ZSTR_LEN(namelist[i]), 0, 0, match_data, mctx);
  670. php_pcre_free_match_data(match_data);
  671. /* 0 means that the vector is too small to hold all the captured substring offsets */
  672. if (rc < 0) {
  673. zend_string_release_ex(namelist[i], 0);
  674. continue;
  675. }
  676. snprintf(fullpath, MAXPATHLEN, "%s%c%s", path, DEFAULT_SLASH, ZSTR_VAL(namelist[i]));
  677. if (0 != VCWD_STAT(fullpath, &s)) {
  678. php_error_docref(NULL, E_WARNING, "Cannot read <%s>", fullpath);
  679. zend_string_release_ex(namelist[i], 0);
  680. continue;
  681. }
  682. if (S_IFDIR == (s.st_mode & S_IFMT)) {
  683. zend_string_release_ex(namelist[i], 0);
  684. continue;
  685. }
  686. add_next_index_string(return_value, fullpath);
  687. zend_string_release_ex(namelist[i], 0);
  688. }
  689. efree(namelist);
  690. }
  691. return files_cnt;
  692. }
  693. /* }}} */
  694. /* {{{ zend_function_entry */
  695. static const zend_function_entry zip_functions[] = {
  696. ZEND_RAW_FENTRY("zip_open", zif_zip_open, arginfo_zip_open, 0)
  697. ZEND_RAW_FENTRY("zip_close", zif_zip_close, arginfo_zip_close, 0)
  698. ZEND_RAW_FENTRY("zip_read", zif_zip_read, arginfo_zip_read, 0)
  699. PHP_FE(zip_entry_open, arginfo_zip_entry_open)
  700. PHP_FE(zip_entry_close, arginfo_zip_entry_close)
  701. PHP_FE(zip_entry_read, arginfo_zip_entry_read)
  702. PHP_FE(zip_entry_filesize, arginfo_zip_entry_filesize)
  703. PHP_FE(zip_entry_name, arginfo_zip_entry_name)
  704. PHP_FE(zip_entry_compressedsize, arginfo_zip_entry_compressedsize)
  705. PHP_FE(zip_entry_compressionmethod, arginfo_zip_entry_compressionmethod)
  706. #ifdef PHP_FE_END
  707. PHP_FE_END
  708. #else
  709. {NULL,NULL,NULL}
  710. #endif
  711. };
  712. /* }}} */
  713. /* {{{ ZE2 OO definitions */
  714. static zend_class_entry *zip_class_entry;
  715. static zend_object_handlers zip_object_handlers;
  716. static HashTable zip_prop_handlers;
  717. typedef zend_long (*zip_read_int_t)(ze_zip_object *obj);
  718. typedef char *(*zip_read_const_char_t)(ze_zip_object *obj, int *len);
  719. typedef struct _zip_prop_handler {
  720. zip_read_int_t read_int_func;
  721. zip_read_const_char_t read_const_char_func;
  722. int type;
  723. } zip_prop_handler;
  724. /* }}} */
  725. static void php_zip_register_prop_handler(HashTable *prop_handler, char *name, zip_read_int_t read_int_func, zip_read_const_char_t read_char_func, int rettype) /* {{{ */
  726. {
  727. zip_prop_handler hnd;
  728. zend_string *str;
  729. zval tmp;
  730. hnd.read_const_char_func = read_char_func;
  731. hnd.read_int_func = read_int_func;
  732. hnd.type = rettype;
  733. str = zend_string_init_interned(name, strlen(name), 1);
  734. zend_hash_add_mem(prop_handler, str, &hnd, sizeof(zip_prop_handler));
  735. /* Register for reflection */
  736. ZVAL_NULL(&tmp);
  737. zend_declare_property_ex(zip_class_entry, str, &tmp, ZEND_ACC_PUBLIC, NULL);
  738. zend_string_release_ex(str, 1);
  739. }
  740. /* }}} */
  741. static zval *php_zip_property_reader(ze_zip_object *obj, zip_prop_handler *hnd, zval *rv) /* {{{ */
  742. {
  743. const char *retchar = NULL;
  744. zend_long retint = 0;
  745. int len = 0;
  746. if (hnd->read_const_char_func) {
  747. retchar = hnd->read_const_char_func(obj, &len);
  748. } else if (hnd->read_int_func) {
  749. retint = hnd->read_int_func(obj);
  750. }
  751. switch (hnd->type) {
  752. case IS_STRING:
  753. if (retchar) {
  754. ZVAL_STRINGL(rv, (char *) retchar, len);
  755. } else {
  756. ZVAL_EMPTY_STRING(rv);
  757. }
  758. break;
  759. /* case IS_TRUE */
  760. case IS_FALSE:
  761. ZVAL_BOOL(rv, retint);
  762. break;
  763. case IS_LONG:
  764. ZVAL_LONG(rv, retint);
  765. break;
  766. default:
  767. ZVAL_NULL(rv);
  768. }
  769. return rv;
  770. }
  771. /* }}} */
  772. static zval *php_zip_get_property_ptr_ptr(zend_object *object, zend_string *name, int type, void **cache_slot) /* {{{ */
  773. {
  774. ze_zip_object *obj;
  775. zval *retval = NULL;
  776. zip_prop_handler *hnd = NULL;
  777. obj = php_zip_fetch_object(object);
  778. if (obj->prop_handler != NULL) {
  779. hnd = zend_hash_find_ptr(obj->prop_handler, name);
  780. }
  781. if (hnd == NULL) {
  782. retval = zend_std_get_property_ptr_ptr(object, name, type, cache_slot);
  783. }
  784. return retval;
  785. }
  786. /* }}} */
  787. static zval *php_zip_read_property(zend_object *object, zend_string *name, int type, void **cache_slot, zval *rv) /* {{{ */
  788. {
  789. ze_zip_object *obj;
  790. zval *retval = NULL;
  791. zip_prop_handler *hnd = NULL;
  792. obj = php_zip_fetch_object(object);
  793. if (obj->prop_handler != NULL) {
  794. hnd = zend_hash_find_ptr(obj->prop_handler, name);
  795. }
  796. if (hnd != NULL) {
  797. retval = php_zip_property_reader(obj, hnd, rv);
  798. if (retval == NULL) {
  799. retval = &EG(uninitialized_zval);
  800. }
  801. } else {
  802. retval = zend_std_read_property(object, name, type, cache_slot, rv);
  803. }
  804. return retval;
  805. }
  806. /* }}} */
  807. static int php_zip_has_property(zend_object *object, zend_string *name, int type, void **cache_slot) /* {{{ */
  808. {
  809. ze_zip_object *obj;
  810. zip_prop_handler *hnd = NULL;
  811. int retval = 0;
  812. obj = php_zip_fetch_object(object);
  813. if (obj->prop_handler != NULL) {
  814. hnd = zend_hash_find_ptr(obj->prop_handler, name);
  815. }
  816. if (hnd != NULL) {
  817. zval tmp, *prop;
  818. if (type == 2) {
  819. retval = 1;
  820. } else if ((prop = php_zip_property_reader(obj, hnd, &tmp)) != NULL) {
  821. if (type == 1) {
  822. retval = zend_is_true(&tmp);
  823. } else if (type == 0) {
  824. retval = (Z_TYPE(tmp) != IS_NULL);
  825. }
  826. }
  827. zval_ptr_dtor(&tmp);
  828. } else {
  829. retval = zend_std_has_property(object, name, type, cache_slot);
  830. }
  831. return retval;
  832. }
  833. /* }}} */
  834. static HashTable *php_zip_get_gc(zend_object *object, zval **gc_data, int *gc_data_count) /* {{{ */
  835. {
  836. *gc_data = NULL;
  837. *gc_data_count = 0;
  838. return zend_std_get_properties(object);
  839. }
  840. /* }}} */
  841. static HashTable *php_zip_get_properties(zend_object *object)/* {{{ */
  842. {
  843. ze_zip_object *obj;
  844. HashTable *props;
  845. zip_prop_handler *hnd;
  846. zend_string *key;
  847. obj = php_zip_fetch_object(object);
  848. props = zend_std_get_properties(object);
  849. if (obj->prop_handler == NULL) {
  850. return NULL;
  851. }
  852. ZEND_HASH_FOREACH_STR_KEY_PTR(obj->prop_handler, key, hnd) {
  853. zval *ret, val;
  854. ret = php_zip_property_reader(obj, hnd, &val);
  855. if (ret == NULL) {
  856. ret = &EG(uninitialized_zval);
  857. }
  858. zend_hash_update(props, key, ret);
  859. } ZEND_HASH_FOREACH_END();
  860. return props;
  861. }
  862. /* }}} */
  863. #ifdef HAVE_PROGRESS_CALLBACK
  864. static void _php_zip_progress_callback_free(void *ptr)
  865. {
  866. ze_zip_object *obj = ptr;
  867. if (!Z_ISUNDEF(obj->progress_callback)) {
  868. zval_ptr_dtor(&obj->progress_callback);
  869. ZVAL_UNDEF(&obj->progress_callback);
  870. }
  871. }
  872. #endif
  873. #ifdef HAVE_CANCEL_CALLBACK
  874. static void _php_zip_cancel_callback_free(void *ptr)
  875. {
  876. ze_zip_object *obj = ptr;
  877. if (!Z_ISUNDEF(obj->cancel_callback)) {
  878. zval_ptr_dtor(&obj->cancel_callback);
  879. ZVAL_UNDEF(&obj->cancel_callback);
  880. }
  881. }
  882. #endif
  883. static void php_zip_object_free_storage(zend_object *object) /* {{{ */
  884. {
  885. ze_zip_object * intern = php_zip_fetch_object(object);
  886. int i;
  887. if (!intern) {
  888. return;
  889. }
  890. if (intern->za) {
  891. if (zip_close(intern->za) != 0) {
  892. php_error_docref(NULL, E_WARNING, "Cannot destroy the zip context: %s", zip_strerror(intern->za));
  893. zip_discard(intern->za);
  894. }
  895. }
  896. if (intern->buffers_cnt>0) {
  897. for (i=0; i<intern->buffers_cnt; i++) {
  898. efree(intern->buffers[i]);
  899. }
  900. efree(intern->buffers);
  901. }
  902. #ifdef HAVE_PROGRESS_CALLBACK
  903. /* if not properly called by libzip */
  904. _php_zip_progress_callback_free(intern);
  905. #endif
  906. #ifdef HAVE_CANCEL_CALLBACK
  907. /* if not properly called by libzip */
  908. _php_zip_cancel_callback_free(intern);
  909. #endif
  910. intern->za = NULL;
  911. zend_object_std_dtor(&intern->zo);
  912. if (intern->filename) {
  913. efree(intern->filename);
  914. }
  915. }
  916. /* }}} */
  917. static zend_object *php_zip_object_new(zend_class_entry *class_type) /* {{{ */
  918. {
  919. ze_zip_object *intern;
  920. intern = zend_object_alloc(sizeof(ze_zip_object), class_type);
  921. intern->prop_handler = &zip_prop_handlers;
  922. zend_object_std_init(&intern->zo, class_type);
  923. object_properties_init(&intern->zo, class_type);
  924. intern->zo.handlers = &zip_object_handlers;
  925. intern->last_id = -1;
  926. return &intern->zo;
  927. }
  928. /* }}} */
  929. /* {{{ Resource dtors */
  930. /* {{{ php_zip_free_dir */
  931. static void php_zip_free_dir(zend_resource *rsrc)
  932. {
  933. zip_rsrc * zip_int = (zip_rsrc *) rsrc->ptr;
  934. if (zip_int) {
  935. if (zip_int->za) {
  936. if (zip_close(zip_int->za) != 0) {
  937. php_error_docref(NULL, E_WARNING, "Cannot destroy the zip context");
  938. }
  939. zip_int->za = NULL;
  940. }
  941. efree(rsrc->ptr);
  942. rsrc->ptr = NULL;
  943. }
  944. }
  945. /* }}} */
  946. /* {{{ php_zip_free_entry */
  947. static void php_zip_free_entry(zend_resource *rsrc)
  948. {
  949. zip_read_rsrc *zr_rsrc = (zip_read_rsrc *) rsrc->ptr;
  950. if (zr_rsrc) {
  951. if (zr_rsrc->zf) {
  952. zip_fclose(zr_rsrc->zf);
  953. zr_rsrc->zf = NULL;
  954. }
  955. efree(zr_rsrc);
  956. rsrc->ptr = NULL;
  957. }
  958. }
  959. /* }}} */
  960. /* }}}*/
  961. /* reset macro */
  962. /* {{{ function prototypes */
  963. static PHP_MINIT_FUNCTION(zip);
  964. static PHP_MSHUTDOWN_FUNCTION(zip);
  965. static PHP_MINFO_FUNCTION(zip);
  966. /* }}} */
  967. /* {{{ zip_module_entry
  968. */
  969. zend_module_entry zip_module_entry = {
  970. STANDARD_MODULE_HEADER,
  971. "zip",
  972. zip_functions,
  973. PHP_MINIT(zip),
  974. PHP_MSHUTDOWN(zip),
  975. NULL,
  976. NULL,
  977. PHP_MINFO(zip),
  978. PHP_ZIP_VERSION,
  979. STANDARD_MODULE_PROPERTIES
  980. };
  981. /* }}} */
  982. #ifdef COMPILE_DL_ZIP
  983. ZEND_GET_MODULE(zip)
  984. #endif
  985. /* set macro */
  986. /* {{{ proto resource zip_open(string filename)
  987. Create new zip using source uri for output */
  988. static PHP_NAMED_FUNCTION(zif_zip_open)
  989. {
  990. char resolved_path[MAXPATHLEN + 1];
  991. zip_rsrc *rsrc_int;
  992. int err = 0;
  993. zend_string *filename;
  994. if (zend_parse_parameters(ZEND_NUM_ARGS(), "P", &filename) == FAILURE) {
  995. RETURN_THROWS();
  996. }
  997. if (ZSTR_LEN(filename) == 0) {
  998. php_error_docref(NULL, E_WARNING, "Empty string as source");
  999. RETURN_FALSE;
  1000. }
  1001. if (ZIP_OPENBASEDIR_CHECKPATH(ZSTR_VAL(filename))) {
  1002. RETURN_FALSE;
  1003. }
  1004. if(!expand_filepath(ZSTR_VAL(filename), resolved_path)) {
  1005. RETURN_FALSE;
  1006. }
  1007. rsrc_int = (zip_rsrc *)emalloc(sizeof(zip_rsrc));
  1008. rsrc_int->za = zip_open(resolved_path, 0, &err);
  1009. if (rsrc_int->za == NULL) {
  1010. efree(rsrc_int);
  1011. RETURN_LONG((zend_long)err);
  1012. }
  1013. rsrc_int->index_current = 0;
  1014. rsrc_int->num_files = zip_get_num_entries(rsrc_int->za, 0);
  1015. RETURN_RES(zend_register_resource(rsrc_int, le_zip_dir));
  1016. }
  1017. /* }}} */
  1018. /* {{{ proto void zip_close(resource zip)
  1019. Close a Zip archive */
  1020. static PHP_NAMED_FUNCTION(zif_zip_close)
  1021. {
  1022. zval * zip;
  1023. zip_rsrc *z_rsrc = NULL;
  1024. if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &zip) == FAILURE) {
  1025. RETURN_THROWS();
  1026. }
  1027. if ((z_rsrc = (zip_rsrc *)zend_fetch_resource(Z_RES_P(zip), le_zip_dir_name, le_zip_dir)) == NULL) {
  1028. RETURN_THROWS();
  1029. }
  1030. /* really close the zip will break BC :-D */
  1031. zend_list_close(Z_RES_P(zip));
  1032. }
  1033. /* }}} */
  1034. /* {{{ proto resource zip_read(resource zip)
  1035. Returns the next file in the archive */
  1036. static PHP_NAMED_FUNCTION(zif_zip_read)
  1037. {
  1038. zval *zip_dp;
  1039. zip_read_rsrc *zr_rsrc;
  1040. int ret;
  1041. zip_rsrc *rsrc_int;
  1042. if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &zip_dp) == FAILURE) {
  1043. RETURN_THROWS();
  1044. }
  1045. if ((rsrc_int = (zip_rsrc *)zend_fetch_resource(Z_RES_P(zip_dp), le_zip_dir_name, le_zip_dir)) == NULL) {
  1046. RETURN_THROWS();
  1047. }
  1048. if (rsrc_int && rsrc_int->za) {
  1049. if (rsrc_int->index_current >= rsrc_int->num_files) {
  1050. RETURN_FALSE;
  1051. }
  1052. zr_rsrc = emalloc(sizeof(zip_read_rsrc));
  1053. ret = zip_stat_index(rsrc_int->za, rsrc_int->index_current, 0, &zr_rsrc->sb);
  1054. if (ret != 0) {
  1055. efree(zr_rsrc);
  1056. RETURN_FALSE;
  1057. }
  1058. zr_rsrc->zf = zip_fopen_index(rsrc_int->za, rsrc_int->index_current, 0);
  1059. if (zr_rsrc->zf) {
  1060. rsrc_int->index_current++;
  1061. RETURN_RES(zend_register_resource(zr_rsrc, le_zip_entry));
  1062. } else {
  1063. efree(zr_rsrc);
  1064. RETURN_FALSE;
  1065. }
  1066. } else {
  1067. RETURN_FALSE;
  1068. }
  1069. }
  1070. /* }}} */
  1071. /* {{{ proto bool zip_entry_open(resource zip_dp, resource zip_entry [, string mode])
  1072. Open a Zip File, pointed by the resource entry */
  1073. /* Dummy function to follow the old API */
  1074. static PHP_NAMED_FUNCTION(zif_zip_entry_open)
  1075. {
  1076. zval * zip;
  1077. zval * zip_entry;
  1078. char *mode = NULL;
  1079. size_t mode_len = 0;
  1080. zip_read_rsrc * zr_rsrc;
  1081. zip_rsrc *z_rsrc;
  1082. if (zend_parse_parameters(ZEND_NUM_ARGS(), "rr|s", &zip, &zip_entry, &mode, &mode_len) == FAILURE) {
  1083. RETURN_THROWS();
  1084. }
  1085. if ((zr_rsrc = (zip_read_rsrc *)zend_fetch_resource(Z_RES_P(zip_entry), le_zip_entry_name, le_zip_entry)) == NULL) {
  1086. RETURN_THROWS();
  1087. }
  1088. if ((z_rsrc = (zip_rsrc *)zend_fetch_resource(Z_RES_P(zip), le_zip_dir_name, le_zip_dir)) == NULL) {
  1089. RETURN_THROWS();
  1090. }
  1091. if (zr_rsrc->zf != NULL) {
  1092. RETURN_TRUE;
  1093. } else {
  1094. RETURN_FALSE;
  1095. }
  1096. }
  1097. /* }}} */
  1098. /* {{{ proto bool zip_entry_close(resource zip_ent)
  1099. Close a zip entry */
  1100. static PHP_NAMED_FUNCTION(zif_zip_entry_close)
  1101. {
  1102. zval * zip_entry;
  1103. zip_read_rsrc * zr_rsrc;
  1104. if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &zip_entry) == FAILURE) {
  1105. RETURN_THROWS();
  1106. }
  1107. if ((zr_rsrc = (zip_read_rsrc *)zend_fetch_resource(Z_RES_P(zip_entry), le_zip_entry_name, le_zip_entry)) == NULL) {
  1108. RETURN_THROWS();
  1109. }
  1110. RETURN_BOOL(SUCCESS == zend_list_close(Z_RES_P(zip_entry)));
  1111. }
  1112. /* }}} */
  1113. /* {{{ proto mixed zip_entry_read(resource zip_entry [, int len])
  1114. Read from an open directory entry */
  1115. static PHP_NAMED_FUNCTION(zif_zip_entry_read)
  1116. {
  1117. zval * zip_entry;
  1118. zend_long len = 0;
  1119. zip_read_rsrc * zr_rsrc;
  1120. zend_string *buffer;
  1121. int n = 0;
  1122. if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|l", &zip_entry, &len) == FAILURE) {
  1123. RETURN_THROWS();
  1124. }
  1125. if ((zr_rsrc = (zip_read_rsrc *)zend_fetch_resource(Z_RES_P(zip_entry), le_zip_entry_name, le_zip_entry)) == NULL) {
  1126. RETURN_THROWS();
  1127. }
  1128. if (len <= 0) {
  1129. len = 1024;
  1130. }
  1131. if (zr_rsrc->zf) {
  1132. buffer = zend_string_safe_alloc(1, len, 0, 0);
  1133. n = zip_fread(zr_rsrc->zf, ZSTR_VAL(buffer), ZSTR_LEN(buffer));
  1134. if (n > 0) {
  1135. ZSTR_VAL(buffer)[n] = '\0';
  1136. ZSTR_LEN(buffer) = n;
  1137. RETURN_NEW_STR(buffer);
  1138. } else {
  1139. zend_string_efree(buffer);
  1140. RETURN_EMPTY_STRING();
  1141. }
  1142. } else {
  1143. RETURN_FALSE;
  1144. }
  1145. }
  1146. /* }}} */
  1147. static void php_zip_entry_get_info(INTERNAL_FUNCTION_PARAMETERS, int opt) /* {{{ */
  1148. {
  1149. zval * zip_entry;
  1150. zip_read_rsrc * zr_rsrc;
  1151. if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &zip_entry) == FAILURE) {
  1152. RETURN_THROWS();
  1153. }
  1154. if ((zr_rsrc = (zip_read_rsrc *)zend_fetch_resource(Z_RES_P(zip_entry), le_zip_entry_name, le_zip_entry)) == NULL) {
  1155. RETURN_THROWS();
  1156. }
  1157. if (!zr_rsrc->zf) {
  1158. RETURN_FALSE;
  1159. }
  1160. switch (opt) {
  1161. case 0:
  1162. RETURN_STRING((char *)zr_rsrc->sb.name);
  1163. case 1:
  1164. RETURN_LONG((zend_long) (zr_rsrc->sb.comp_size));
  1165. case 2:
  1166. RETURN_LONG((zend_long) (zr_rsrc->sb.size));
  1167. case 3:
  1168. switch (zr_rsrc->sb.comp_method) {
  1169. case 0:
  1170. RETURN_STRING("stored");
  1171. case 1:
  1172. RETURN_STRING("shrunk");
  1173. case 2:
  1174. case 3:
  1175. case 4:
  1176. case 5:
  1177. RETURN_STRING("reduced");
  1178. case 6:
  1179. RETURN_STRING("imploded");
  1180. case 7:
  1181. RETURN_STRING("tokenized");
  1182. break;
  1183. case 8:
  1184. RETURN_STRING("deflated");
  1185. case 9:
  1186. RETURN_STRING("deflatedX");
  1187. break;
  1188. case 10:
  1189. RETURN_STRING("implodedX");
  1190. default:
  1191. RETURN_FALSE;
  1192. }
  1193. }
  1194. }
  1195. /* }}} */
  1196. /* {{{ proto string zip_entry_name(resource zip_entry)
  1197. Return the name given a ZZip entry */
  1198. static PHP_NAMED_FUNCTION(zif_zip_entry_name)
  1199. {
  1200. php_zip_entry_get_info(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
  1201. }
  1202. /* }}} */
  1203. /* {{{ proto int zip_entry_compressedsize(resource zip_entry)
  1204. Return the compressed size of a ZZip entry */
  1205. static PHP_NAMED_FUNCTION(zif_zip_entry_compressedsize)
  1206. {
  1207. php_zip_entry_get_info(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
  1208. }
  1209. /* }}} */
  1210. /* {{{ proto int zip_entry_filesize(resource zip_entry)
  1211. Return the actual filesize of a ZZip entry */
  1212. static PHP_NAMED_FUNCTION(zif_zip_entry_filesize)
  1213. {
  1214. php_zip_entry_get_info(INTERNAL_FUNCTION_PARAM_PASSTHRU, 2);
  1215. }
  1216. /* }}} */
  1217. /* {{{ proto string zip_entry_compressionmethod(resource zip_entry)
  1218. Return a string containing the compression method used on a particular entry */
  1219. static PHP_NAMED_FUNCTION(zif_zip_entry_compressionmethod)
  1220. {
  1221. php_zip_entry_get_info(INTERNAL_FUNCTION_PARAM_PASSTHRU, 3);
  1222. }
  1223. /* }}} */
  1224. /* {{{ proto mixed ZipArchive::open(string source [, int flags])
  1225. Create new zip using source uri for output, return TRUE on success or the error code */
  1226. static ZIPARCHIVE_METHOD(open)
  1227. {
  1228. struct zip *intern;
  1229. int err = 0;
  1230. zend_long flags = 0;
  1231. char *resolved_path;
  1232. zend_string *filename;
  1233. zval *self = ZEND_THIS;
  1234. ze_zip_object *ze_obj;
  1235. if (zend_parse_parameters(ZEND_NUM_ARGS(), "P|l", &filename, &flags) == FAILURE) {
  1236. RETURN_THROWS();
  1237. }
  1238. /* We do not use ZIP_FROM_OBJECT, zip init function here */
  1239. ze_obj = Z_ZIP_P(self);
  1240. if (ZSTR_LEN(filename) == 0) {
  1241. php_error_docref(NULL, E_WARNING, "Empty string as source");
  1242. RETURN_FALSE;
  1243. }
  1244. if (ZIP_OPENBASEDIR_CHECKPATH(ZSTR_VAL(filename))) {
  1245. RETURN_FALSE;
  1246. }
  1247. if (!(resolved_path = expand_filepath(ZSTR_VAL(filename), NULL))) {
  1248. RETURN_FALSE;
  1249. }
  1250. if (ze_obj->za) {
  1251. /* we already have an opened zip, free it */
  1252. if (zip_close(ze_obj->za) != 0) {
  1253. php_error_docref(NULL, E_WARNING, "Empty string as source");
  1254. efree(resolved_path);
  1255. RETURN_FALSE;
  1256. }
  1257. ze_obj->za = NULL;
  1258. }
  1259. if (ze_obj->filename) {
  1260. efree(ze_obj->filename);
  1261. ze_obj->filename = NULL;
  1262. }
  1263. /* reduce BC break introduce in libzip 1.6.0
  1264. "Do not accept empty files as valid zip archives any longer" */
  1265. /* open for write without option to empty the archive */
  1266. if ((flags & (ZIP_TRUNCATE | ZIP_RDONLY)) == 0) {
  1267. zend_stat_t st;
  1268. /* exists and is empty */
  1269. if (VCWD_STAT(resolved_path, &st) == 0 && st.st_size == 0) {
  1270. php_error_docref(NULL, E_DEPRECATED, "Using empty file as ZipArchive is deprecated");
  1271. flags |= ZIP_TRUNCATE;
  1272. }
  1273. }
  1274. intern = zip_open(resolved_path, flags, &err);
  1275. if (!intern || err) {
  1276. efree(resolved_path);
  1277. RETURN_LONG((zend_long)err);
  1278. }
  1279. ze_obj->filename = resolved_path;
  1280. ze_obj->filename_len = strlen(resolved_path);
  1281. ze_obj->za = intern;
  1282. RETURN_TRUE;
  1283. }
  1284. /* }}} */
  1285. /* {{{ proto resource ZipArchive::setPassword(string password)
  1286. Set the password for the active archive */
  1287. static ZIPARCHIVE_METHOD(setPassword)
  1288. {
  1289. struct zip *intern;
  1290. zval *self = ZEND_THIS;
  1291. char *password;
  1292. size_t password_len;
  1293. if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &password, &password_len) == FAILURE) {
  1294. RETURN_THROWS();
  1295. }
  1296. ZIP_FROM_OBJECT(intern, self);
  1297. if (password_len < 1) {
  1298. RETURN_FALSE;
  1299. }
  1300. int res = zip_set_default_password(intern, (const char *)password);
  1301. if (res == 0) {
  1302. RETURN_TRUE;
  1303. } else {
  1304. RETURN_FALSE;
  1305. }
  1306. }
  1307. /* }}} */
  1308. /* {{{ proto bool ZipArchive::close()
  1309. close the zip archive */
  1310. static ZIPARCHIVE_METHOD(close)
  1311. {
  1312. struct zip *intern;
  1313. zval *self = ZEND_THIS;
  1314. ze_zip_object *ze_obj;
  1315. int err;
  1316. if (zend_parse_parameters_none() == FAILURE) {
  1317. RETURN_THROWS();
  1318. }
  1319. ZIP_FROM_OBJECT(intern, self);
  1320. ze_obj = Z_ZIP_P(self);
  1321. err = zip_close(intern);
  1322. if (err) {
  1323. php_error_docref(NULL, E_WARNING, "%s", zip_strerror(intern));
  1324. /* Save error for property reader */
  1325. #if LIBZIP_VERSION_MAJOR < 1
  1326. zip_error_get(intern, &ze_obj->err_zip, &ze_obj->err_sys);
  1327. #else
  1328. {
  1329. zip_error_t *ziperr;
  1330. ziperr = zip_get_error(intern);
  1331. ze_obj->err_zip = zip_error_code_zip(ziperr);
  1332. ze_obj->err_sys = zip_error_code_system(ziperr);
  1333. zip_error_fini(ziperr);
  1334. }
  1335. #endif
  1336. zip_discard(intern);
  1337. } else {
  1338. ze_obj->err_zip = 0;
  1339. ze_obj->err_sys = 0;
  1340. }
  1341. efree(ze_obj->filename);
  1342. ze_obj->filename = NULL;
  1343. ze_obj->filename_len = 0;
  1344. ze_obj->za = NULL;
  1345. if (!err) {
  1346. RETURN_TRUE;
  1347. } else {
  1348. RETURN_FALSE;
  1349. }
  1350. }
  1351. /* }}} */
  1352. /* {{{ proto bool ZipArchive::count()
  1353. close the zip archive */
  1354. static ZIPARCHIVE_METHOD(count)
  1355. {
  1356. struct zip *intern;
  1357. zval *self = ZEND_THIS;
  1358. zip_int64_t num;
  1359. if (zend_parse_parameters_none() == FAILURE) {
  1360. RETURN_THROWS();
  1361. }
  1362. ZIP_FROM_OBJECT(intern, self);
  1363. num = zip_get_num_entries(intern, 0);
  1364. RETVAL_LONG(MIN(num, ZEND_LONG_MAX));
  1365. }
  1366. /* }}} */
  1367. /* {{{ proto string ZipArchive::getStatusString()
  1368. * Returns the status error message, system and/or zip messages */
  1369. static ZIPARCHIVE_METHOD(getStatusString)
  1370. {
  1371. zval *self = ZEND_THIS;
  1372. #if LIBZIP_VERSION_MAJOR < 1
  1373. int zep, syp, len;
  1374. char error_string[128];
  1375. #endif
  1376. ze_zip_object *ze_obj;
  1377. if (zend_parse_parameters_none() == FAILURE) {
  1378. RETURN_THROWS();
  1379. }
  1380. ze_obj = Z_ZIP_P(self); /* not ZIP_FROM_OBJECT as we can use saved error after close */
  1381. #if LIBZIP_VERSION_MAJOR < 1
  1382. if (ze_obj->za) {
  1383. zip_error_get(ze_obj->za, &zep, &syp);
  1384. len = zip_error_to_str(error_string, 128, zep, syp);
  1385. } else {
  1386. len = zip_error_to_str(error_string, 128, ze_obj->err_zip, ze_obj->err_sys);
  1387. }
  1388. RETVAL_STRINGL(error_string, len);
  1389. #else
  1390. if (ze_obj->za) {
  1391. zip_error_t *err;
  1392. err = zip_get_error(ze_obj->za);
  1393. RETVAL_STRING(zip_error_strerror(err));
  1394. zip_error_fini(err);
  1395. } else {
  1396. zip_error_t err;
  1397. zip_error_init(&err);
  1398. zip_error_set(&err, ze_obj->err_zip, ze_obj->err_sys);
  1399. RETVAL_STRING(zip_error_strerror(&err));
  1400. zip_error_fini(&err);
  1401. }
  1402. #endif
  1403. }
  1404. /* }}} */
  1405. /* {{{ proto bool ZipArchive::addEmptyDir(string dirname [, bool flags = 0])
  1406. Returns the index of the entry named filename in the archive */
  1407. static ZIPARCHIVE_METHOD(addEmptyDir)
  1408. {
  1409. struct zip *intern;
  1410. zval *self = ZEND_THIS;
  1411. char *dirname;
  1412. size_t dirname_len;
  1413. char *s;
  1414. zend_long flags = 0;
  1415. if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|l",
  1416. &dirname, &dirname_len, &flags) == FAILURE) {
  1417. RETURN_THROWS();
  1418. }
  1419. ZIP_FROM_OBJECT(intern, self);
  1420. if (dirname_len<1) {
  1421. RETURN_FALSE;
  1422. }
  1423. if (dirname[dirname_len-1] != '/') {
  1424. s=(char *)safe_emalloc(dirname_len, 1, 2);
  1425. strcpy(s, dirname);
  1426. s[dirname_len] = '/';
  1427. s[dirname_len+1] = '\0';
  1428. } else {
  1429. s = dirname;
  1430. }
  1431. if ((Z_ZIP_P(self)->last_id = zip_dir_add(intern, (const char *)s, flags)) == -1) {
  1432. RETVAL_FALSE;
  1433. } else {
  1434. zip_error_clear(intern);
  1435. RETVAL_TRUE;
  1436. }
  1437. if (s != dirname) {
  1438. efree(s);
  1439. }
  1440. }
  1441. /* }}} */
  1442. static void php_zip_add_from_pattern(INTERNAL_FUNCTION_PARAMETERS, int type) /* {{{ */
  1443. {
  1444. zval *self = ZEND_THIS;
  1445. char *path = ".";
  1446. size_t path_len = 1;
  1447. zend_long glob_flags = 0;
  1448. zval *options = NULL;
  1449. zip_options opts;
  1450. int found;
  1451. zend_string *pattern;
  1452. /* 1 == glob, 2 == pcre */
  1453. if (type == 1) {
  1454. if (zend_parse_parameters(ZEND_NUM_ARGS(), "P|la",
  1455. &pattern, &glob_flags, &options) == FAILURE) {
  1456. RETURN_THROWS();
  1457. }
  1458. } else {
  1459. if (zend_parse_parameters(ZEND_NUM_ARGS(), "P|sa",
  1460. &pattern, &path, &path_len, &options) == FAILURE) {
  1461. RETURN_THROWS();
  1462. }
  1463. }
  1464. if (ZSTR_LEN(pattern) == 0) {
  1465. php_error_docref(NULL, E_NOTICE, "Empty string as pattern");
  1466. RETURN_FALSE;
  1467. }
  1468. if (options && zend_hash_num_elements(Z_ARRVAL_P(options)) > 0 && (php_zip_parse_options(options, &opts) < 0)) {
  1469. RETURN_FALSE;
  1470. }
  1471. if (type == 1) {
  1472. found = php_zip_glob(ZSTR_VAL(pattern), ZSTR_LEN(pattern), glob_flags, return_value);
  1473. } else {
  1474. found = php_zip_pcre(pattern, path, path_len, return_value);
  1475. }
  1476. if (found > 0) {
  1477. int i;
  1478. zval *zval_file;
  1479. ze_zip_object *ze_obj;
  1480. ze_obj = Z_ZIP_P(self);
  1481. for (i = 0; i < found; i++) {
  1482. char *file_stripped, *entry_name;
  1483. size_t entry_name_len, file_stripped_len;
  1484. char entry_name_buf[MAXPATHLEN];
  1485. zend_string *basename = NULL;
  1486. if ((zval_file = zend_hash_index_find(Z_ARRVAL_P(return_value), i)) != NULL) {
  1487. if (opts.remove_all_path) {
  1488. basename = php_basename(Z_STRVAL_P(zval_file), Z_STRLEN_P(zval_file), NULL, 0);
  1489. file_stripped = ZSTR_VAL(basename);
  1490. file_stripped_len = ZSTR_LEN(basename);
  1491. } else if (opts.remove_path && strstr(Z_STRVAL_P(zval_file), opts.remove_path) != NULL) {
  1492. if (IS_SLASH(Z_STRVAL_P(zval_file)[opts.remove_path_len])) {
  1493. file_stripped = Z_STRVAL_P(zval_file) + opts.remove_path_len + 1;
  1494. file_stripped_len = Z_STRLEN_P(zval_file) - opts.remove_path_len - 1;
  1495. } else {
  1496. file_stripped = Z_STRVAL_P(zval_file) + opts.remove_path_len;
  1497. file_stripped_len = Z_STRLEN_P(zval_file) - opts.remove_path_len;
  1498. }
  1499. } else {
  1500. file_stripped = Z_STRVAL_P(zval_file);
  1501. file_stripped_len = Z_STRLEN_P(zval_file);
  1502. }
  1503. if (opts.add_path) {
  1504. if ((opts.add_path_len + file_stripped_len) > MAXPATHLEN) {
  1505. php_error_docref(NULL, E_WARNING, "Entry name too long (max: %d, %zd given)",
  1506. MAXPATHLEN - 1, (opts.add_path_len + file_stripped_len));
  1507. zend_array_destroy(Z_ARR_P(return_value));
  1508. RETURN_FALSE;
  1509. }
  1510. snprintf(entry_name_buf, MAXPATHLEN, "%s%s", opts.add_path, file_stripped);
  1511. } else {
  1512. snprintf(entry_name_buf, MAXPATHLEN, "%s", file_stripped);
  1513. }
  1514. entry_name = entry_name_buf;
  1515. entry_name_len = strlen(entry_name);
  1516. if (basename) {
  1517. zend_string_release_ex(basename, 0);
  1518. basename = NULL;
  1519. }
  1520. if (php_zip_add_file(ze_obj, Z_STRVAL_P(zval_file), Z_STRLEN_P(zval_file),
  1521. entry_name, entry_name_len, 0, 0, -1, opts.flags) < 0) {
  1522. zend_array_destroy(Z_ARR_P(return_value));
  1523. RETURN_FALSE;
  1524. }
  1525. if (opts.comp_method >= 0) {
  1526. if (zip_set_file_compression(ze_obj->za, ze_obj->last_id, opts.comp_method, opts.comp_flags)) {
  1527. zend_array_destroy(Z_ARR_P(return_value));
  1528. RETURN_FALSE;
  1529. }
  1530. }
  1531. #ifdef HAVE_ENCRYPTION
  1532. if (opts.enc_method >= 0) {
  1533. if (zip_file_set_encryption(ze_obj->za, ze_obj->last_id, opts.enc_method, opts.enc_password)) {
  1534. zend_array_destroy(Z_ARR_P(return_value));
  1535. RETURN_FALSE;
  1536. }
  1537. }
  1538. #endif
  1539. }
  1540. }
  1541. }
  1542. }
  1543. /* }}} */
  1544. /* {{{ proto bool ZipArchive::addGlob(string pattern[,int flags [, array options]])
  1545. Add files matching the glob pattern. See php's glob for the pattern syntax. */
  1546. static ZIPARCHIVE_METHOD(addGlob)
  1547. {
  1548. php_zip_add_from_pattern(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
  1549. }
  1550. /* }}} */
  1551. /* {{{ proto bool ZipArchive::addPattern(string pattern[, string path [, array options]])
  1552. Add files matching the pcre pattern. See php's pcre for the pattern syntax. */
  1553. static ZIPARCHIVE_METHOD(addPattern)
  1554. {
  1555. php_zip_add_from_pattern(INTERNAL_FUNCTION_PARAM_PASSTHRU, 2);
  1556. }
  1557. /* }}} */
  1558. /* {{{ proto bool ZipArchive::addFile(string filepath[, string entryname[, int start [, int length [, int flags = FL_OVERWRITE]]]])
  1559. Add a file in a Zip archive using its path and the name to use. */
  1560. static ZIPARCHIVE_METHOD(addFile)
  1561. {
  1562. zval *self = ZEND_THIS;
  1563. char *entry_name = NULL;
  1564. size_t entry_name_len = 0;
  1565. zend_long offset_start = 0, offset_len = 0;
  1566. zend_string *filename;
  1567. zend_long flags = ZIP_FL_OVERWRITE;
  1568. if (zend_parse_parameters(ZEND_NUM_ARGS(), "P|slll",
  1569. &filename, &entry_name, &entry_name_len, &offset_start, &offset_len, &flags) == FAILURE) {
  1570. RETURN_THROWS();
  1571. }
  1572. if (ZSTR_LEN(filename) == 0) {
  1573. php_error_docref(NULL, E_NOTICE, "Empty string as filename");
  1574. RETURN_FALSE;
  1575. }
  1576. if (entry_name_len == 0) {
  1577. entry_name = ZSTR_VAL(filename);
  1578. entry_name_len = ZSTR_LEN(filename);
  1579. }
  1580. if (php_zip_add_file(Z_ZIP_P(self), ZSTR_VAL(filename), ZSTR_LEN(filename),
  1581. entry_name, entry_name_len, offset_start, offset_len, -1, flags) < 0) {
  1582. RETURN_FALSE;
  1583. } else {
  1584. RETURN_TRUE;
  1585. }
  1586. }
  1587. /* }}} */
  1588. /* {{{ proto bool ZipArchive::replaceFile(string filepath, int index[, int start [, int length [, int flags = 0]]])
  1589. Add a file in a Zip archive using its path and the name to use. */
  1590. static ZIPARCHIVE_METHOD(replaceFile)
  1591. {
  1592. zval *self = ZEND_THIS;
  1593. zend_long index;
  1594. zend_long offset_start = 0, offset_len = 0;
  1595. zend_string *filename;
  1596. zend_long flags = 0;
  1597. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Pl|lll",
  1598. &filename, &index, &offset_start, &offset_len, &flags) == FAILURE) {
  1599. RETURN_THROWS();
  1600. }
  1601. if (ZSTR_LEN(filename) == 0) {
  1602. php_error_docref(NULL, E_NOTICE, "Empty string as filename");
  1603. RETURN_FALSE;
  1604. }
  1605. if (index < 0) {
  1606. php_error_docref(NULL, E_NOTICE, "Invalid negative index");
  1607. RETURN_FALSE;
  1608. }
  1609. if (php_zip_add_file(Z_ZIP_P(self), ZSTR_VAL(filename), ZSTR_LEN(filename),
  1610. NULL, 0, offset_start, offset_len, index, flags) < 0) {
  1611. RETURN_FALSE;
  1612. } else {
  1613. RETURN_TRUE;
  1614. }
  1615. }
  1616. /* }}} */
  1617. /* {{{ proto bool ZipArchive::addFromString(string name, string content [, int flags = FL_OVERWRITE])
  1618. Add a file using content and the entry name */
  1619. static ZIPARCHIVE_METHOD(addFromString)
  1620. {
  1621. struct zip *intern;
  1622. zval *self = ZEND_THIS;
  1623. zend_string *buffer;
  1624. char *name;
  1625. size_t name_len;
  1626. ze_zip_object *ze_obj;
  1627. struct zip_source *zs;
  1628. int pos = 0;
  1629. zend_long flags = ZIP_FL_OVERWRITE;
  1630. if (zend_parse_parameters(ZEND_NUM_ARGS(), "sS|l",
  1631. &name, &name_len, &buffer, &flags) == FAILURE) {
  1632. RETURN_THROWS();
  1633. }
  1634. ZIP_FROM_OBJECT(intern, self);
  1635. ze_obj = Z_ZIP_P(self);
  1636. if (ze_obj->buffers_cnt) {
  1637. ze_obj->buffers = (char **)safe_erealloc(ze_obj->buffers, sizeof(char *), (ze_obj->buffers_cnt+1), 0);
  1638. pos = ze_obj->buffers_cnt++;
  1639. } else {
  1640. ze_obj->buffers = (char **)emalloc(sizeof(char *));
  1641. ze_obj->buffers_cnt++;
  1642. pos = 0;
  1643. }
  1644. ze_obj->buffers[pos] = (char *)safe_emalloc(ZSTR_LEN(buffer), 1, 1);
  1645. memcpy(ze_obj->buffers[pos], ZSTR_VAL(buffer), ZSTR_LEN(buffer) + 1);
  1646. zs = zip_source_buffer(intern, ze_obj->buffers[pos], ZSTR_LEN(buffer), 0);
  1647. if (zs == NULL) {
  1648. RETURN_FALSE;
  1649. }
  1650. ze_obj->last_id = zip_file_add(intern, name, zs, flags);
  1651. if (ze_obj->last_id == -1) {
  1652. zip_source_free(zs);
  1653. RETURN_FALSE;
  1654. } else {
  1655. zip_error_clear(intern);
  1656. RETURN_TRUE;
  1657. }
  1658. }
  1659. /* }}} */
  1660. /* {{{ proto array ZipArchive::statName(string filename[, int flags])
  1661. Returns the information about a the zip entry filename */
  1662. static ZIPARCHIVE_METHOD(statName)
  1663. {
  1664. struct zip *intern;
  1665. zval *self = ZEND_THIS;
  1666. zend_long flags = 0;
  1667. struct zip_stat sb;
  1668. zend_string *name;
  1669. if (zend_parse_parameters(ZEND_NUM_ARGS(), "P|l", &name, &flags) == FAILURE) {
  1670. RETURN_THROWS();
  1671. }
  1672. ZIP_FROM_OBJECT(intern, self);
  1673. PHP_ZIP_STAT_PATH(intern, ZSTR_VAL(name), ZSTR_LEN(name), flags, sb);
  1674. RETURN_SB(&sb);
  1675. }
  1676. /* }}} */
  1677. /* {{{ proto resource ZipArchive::statIndex(int ind…

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