For God so loved the world, that He gave His only begotten Son, that all who believe in Him should not perish but have everlasting life
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

5173 lines
209 KiB

  1. <?php
  2. // --------------------------------------------------------------------------------
  3. // PhpConcept Library - Zip Module 2.8.2
  4. // --------------------------------------------------------------------------------
  5. // License GNU/LGPL - Vincent Blavet - August 2009
  6. // http://www.phpconcept.net
  7. // --------------------------------------------------------------------------------
  8. //
  9. // Presentation :
  10. // PclZip is a PHP library that manage ZIP archives.
  11. // So far tests show that archives generated by PclZip are readable by
  12. // WinZip application and other tools.
  13. //
  14. // Description :
  15. // See readme.txt and http://www.phpconcept.net
  16. //
  17. // Warning :
  18. // This library and the associated files are non commercial, non professional
  19. // work.
  20. // It should not have unexpected results. However if any damage is caused by
  21. // this software the author can not be responsible.
  22. // The use of this software is at the risk of the user.
  23. //
  24. // --------------------------------------------------------------------------------
  25. // $Id: pclzip.lib.php,v 1.60 2009/09/30 21:01:04 vblavet Exp $
  26. // --------------------------------------------------------------------------------
  27. // ----- Constants
  28. if (!defined('PCLZIP_READ_BLOCK_SIZE')) {
  29. define('PCLZIP_READ_BLOCK_SIZE', 2048);
  30. }
  31. // ----- File list separator
  32. // In version 1.x of PclZip, the separator for file list is a space
  33. // (which is not a very smart choice, specifically for windows paths !).
  34. // A better separator should be a comma (,). This constant gives you the
  35. // abilty to change that.
  36. // However notice that changing this value, may have impact on existing
  37. // scripts, using space separated filenames.
  38. // Recommanded values for compatibility with older versions :
  39. //define('PCLZIP_SEPARATOR', ' ');
  40. // Recommanded values for smart separation of filenames.
  41. if (!defined('PCLZIP_SEPARATOR')) {
  42. define('PCLZIP_SEPARATOR', ',');
  43. }
  44. // ----- Error configuration
  45. // 0 : PclZip Class integrated error handling
  46. // 1 : PclError external library error handling. By enabling this
  47. // you must ensure that you have included PclError library.
  48. // [2,...] : reserved for futur use
  49. if (!defined('PCLZIP_ERROR_EXTERNAL')) {
  50. define('PCLZIP_ERROR_EXTERNAL', 0);
  51. }
  52. // ----- Optional static temporary directory
  53. // By default temporary files are generated in the script current
  54. // path.
  55. // If defined :
  56. // - MUST BE terminated by a '/'.
  57. // - MUST be a valid, already created directory
  58. // Samples :
  59. // define('PCLZIP_TEMPORARY_DIR', '/temp/');
  60. // define('PCLZIP_TEMPORARY_DIR', 'C:/Temp/');
  61. if (!defined('PCLZIP_TEMPORARY_DIR')) {
  62. define('PCLZIP_TEMPORARY_DIR', '');
  63. }
  64. // ----- Optional threshold ratio for use of temporary files
  65. // Pclzip sense the size of the file to add/extract and decide to
  66. // use or not temporary file. The algorythm is looking for
  67. // memory_limit of PHP and apply a ratio.
  68. // threshold = memory_limit * ratio.
  69. // Recommended values are under 0.5. Default 0.47.
  70. // Samples :
  71. // define('PCLZIP_TEMPORARY_FILE_RATIO', 0.5);
  72. if (!defined('PCLZIP_TEMPORARY_FILE_RATIO')) {
  73. define('PCLZIP_TEMPORARY_FILE_RATIO', 0.47);
  74. }
  75. // --------------------------------------------------------------------------------
  76. // ***** UNDER THIS LINE NOTHING NEEDS TO BE MODIFIED *****
  77. // --------------------------------------------------------------------------------
  78. // ----- Global variables
  79. $g_pclzip_version = "2.8.2";
  80. // ----- Error codes
  81. // -1 : Unable to open file in binary write mode
  82. // -2 : Unable to open file in binary read mode
  83. // -3 : Invalid parameters
  84. // -4 : File does not exist
  85. // -5 : Filename is too long (max. 255)
  86. // -6 : Not a valid zip file
  87. // -7 : Invalid extracted file size
  88. // -8 : Unable to create directory
  89. // -9 : Invalid archive extension
  90. // -10 : Invalid archive format
  91. // -11 : Unable to delete file (unlink)
  92. // -12 : Unable to rename file (rename)
  93. // -13 : Invalid header checksum
  94. // -14 : Invalid archive size
  95. define('PCLZIP_ERR_USER_ABORTED', 2);
  96. define('PCLZIP_ERR_NO_ERROR', 0);
  97. define('PCLZIP_ERR_WRITE_OPEN_FAIL', -1);
  98. define('PCLZIP_ERR_READ_OPEN_FAIL', -2);
  99. define('PCLZIP_ERR_INVALID_PARAMETER', -3);
  100. define('PCLZIP_ERR_MISSING_FILE', -4);
  101. define('PCLZIP_ERR_FILENAME_TOO_LONG', -5);
  102. define('PCLZIP_ERR_INVALID_ZIP', -6);
  103. define('PCLZIP_ERR_BAD_EXTRACTED_FILE', -7);
  104. define('PCLZIP_ERR_DIR_CREATE_FAIL', -8);
  105. define('PCLZIP_ERR_BAD_EXTENSION', -9);
  106. define('PCLZIP_ERR_BAD_FORMAT', -10);
  107. define('PCLZIP_ERR_DELETE_FILE_FAIL', -11);
  108. define('PCLZIP_ERR_RENAME_FILE_FAIL', -12);
  109. define('PCLZIP_ERR_BAD_CHECKSUM', -13);
  110. define('PCLZIP_ERR_INVALID_ARCHIVE_ZIP', -14);
  111. define('PCLZIP_ERR_MISSING_OPTION_VALUE', -15);
  112. define('PCLZIP_ERR_INVALID_OPTION_VALUE', -16);
  113. define('PCLZIP_ERR_ALREADY_A_DIRECTORY', -17);
  114. define('PCLZIP_ERR_UNSUPPORTED_COMPRESSION', -18);
  115. define('PCLZIP_ERR_UNSUPPORTED_ENCRYPTION', -19);
  116. define('PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE', -20);
  117. define('PCLZIP_ERR_DIRECTORY_RESTRICTION', -21);
  118. // ----- Options values
  119. define('PCLZIP_OPT_PATH', 77001);
  120. define('PCLZIP_OPT_ADD_PATH', 77002);
  121. define('PCLZIP_OPT_REMOVE_PATH', 77003);
  122. define('PCLZIP_OPT_REMOVE_ALL_PATH', 77004);
  123. define('PCLZIP_OPT_SET_CHMOD', 77005);
  124. define('PCLZIP_OPT_EXTRACT_AS_STRING', 77006);
  125. define('PCLZIP_OPT_NO_COMPRESSION', 77007);
  126. define('PCLZIP_OPT_BY_NAME', 77008);
  127. define('PCLZIP_OPT_BY_INDEX', 77009);
  128. define('PCLZIP_OPT_BY_EREG', 77010);
  129. define('PCLZIP_OPT_BY_PREG', 77011);
  130. define('PCLZIP_OPT_COMMENT', 77012);
  131. define('PCLZIP_OPT_ADD_COMMENT', 77013);
  132. define('PCLZIP_OPT_PREPEND_COMMENT', 77014);
  133. define('PCLZIP_OPT_EXTRACT_IN_OUTPUT', 77015);
  134. define('PCLZIP_OPT_REPLACE_NEWER', 77016);
  135. define('PCLZIP_OPT_STOP_ON_ERROR', 77017);
  136. // Having big trouble with crypt. Need to multiply 2 long int
  137. // which is not correctly supported by PHP ...
  138. //define('PCLZIP_OPT_CRYPT', 77018);
  139. define('PCLZIP_OPT_EXTRACT_DIR_RESTRICTION', 77019);
  140. define('PCLZIP_OPT_TEMP_FILE_THRESHOLD', 77020);
  141. define('PCLZIP_OPT_ADD_TEMP_FILE_THRESHOLD', 77020); // alias
  142. define('PCLZIP_OPT_TEMP_FILE_ON', 77021);
  143. define('PCLZIP_OPT_ADD_TEMP_FILE_ON', 77021); // alias
  144. define('PCLZIP_OPT_TEMP_FILE_OFF', 77022);
  145. define('PCLZIP_OPT_ADD_TEMP_FILE_OFF', 77022); // alias
  146. // ----- File description attributes
  147. define('PCLZIP_ATT_FILE_NAME', 79001);
  148. define('PCLZIP_ATT_FILE_NEW_SHORT_NAME', 79002);
  149. define('PCLZIP_ATT_FILE_NEW_FULL_NAME', 79003);
  150. define('PCLZIP_ATT_FILE_MTIME', 79004);
  151. define('PCLZIP_ATT_FILE_CONTENT', 79005);
  152. define('PCLZIP_ATT_FILE_COMMENT', 79006);
  153. // ----- Call backs values
  154. define('PCLZIP_CB_PRE_EXTRACT', 78001);
  155. define('PCLZIP_CB_POST_EXTRACT', 78002);
  156. define('PCLZIP_CB_PRE_ADD', 78003);
  157. define('PCLZIP_CB_POST_ADD', 78004);
  158. /* For futur use
  159. define('PCLZIP_CB_PRE_LIST', 78005);
  160. define('PCLZIP_CB_POST_LIST', 78006);
  161. define('PCLZIP_CB_PRE_DELETE', 78007);
  162. define('PCLZIP_CB_POST_DELETE', 78008);
  163. */
  164. // --------------------------------------------------------------------------------
  165. // Class : PclZip
  166. // Description :
  167. // PclZip is the class that represent a Zip archive.
  168. // The public methods allow the manipulation of the archive.
  169. // Attributes :
  170. // Attributes must not be accessed directly.
  171. // Methods :
  172. // PclZip() : Object creator
  173. // create() : Creates the Zip archive
  174. // listContent() : List the content of the Zip archive
  175. // extract() : Extract the content of the archive
  176. // properties() : List the properties of the archive
  177. // --------------------------------------------------------------------------------
  178. class PclZip
  179. {
  180. // ----- Filename of the zip file
  181. public $zipname = '';
  182. // ----- File descriptor of the zip file
  183. public $zip_fd = 0;
  184. // ----- Internal error handling
  185. public $error_code = 1;
  186. public $error_string = '';
  187. // ----- Current status of the magic_quotes_runtime
  188. // This value store the php configuration for magic_quotes
  189. // The class can then disable the magic_quotes and reset it after
  190. public $magic_quotes_status;
  191. // --------------------------------------------------------------------------------
  192. // Function : PclZip()
  193. // Description :
  194. // Creates a PclZip object and set the name of the associated Zip archive
  195. // filename.
  196. // Note that no real action is taken, if the archive does not exist it is not
  197. // created. Use create() for that.
  198. // --------------------------------------------------------------------------------
  199. public function __construct($p_zipname)
  200. {
  201. // ----- Tests the zlib
  202. if (!function_exists('gzopen')) {
  203. die('Abort '.basename(__FILE__).' : Missing zlib extensions');
  204. }
  205. // ----- Set the attributes
  206. $this->zipname = $p_zipname;
  207. $this->zip_fd = 0;
  208. $this->magic_quotes_status = -1;
  209. // ----- Return
  210. return;
  211. }
  212. // --------------------------------------------------------------------------------
  213. // --------------------------------------------------------------------------------
  214. // Function :
  215. // create($p_filelist, $p_add_dir="", $p_remove_dir="")
  216. // create($p_filelist, $p_option, $p_option_value, ...)
  217. // Description :
  218. // This method supports two different synopsis. The first one is historical.
  219. // This method creates a Zip Archive. The Zip file is created in the
  220. // filesystem. The files and directories indicated in $p_filelist
  221. // are added in the archive. See the parameters description for the
  222. // supported format of $p_filelist.
  223. // When a directory is in the list, the directory and its content is added
  224. // in the archive.
  225. // In this synopsis, the function takes an optional variable list of
  226. // options. See bellow the supported options.
  227. // Parameters :
  228. // $p_filelist : An array containing file or directory names, or
  229. // a string containing one filename or one directory name, or
  230. // a string containing a list of filenames and/or directory
  231. // names separated by spaces.
  232. // $p_add_dir : A path to add before the real path of the archived file,
  233. // in order to have it memorized in the archive.
  234. // $p_remove_dir : A path to remove from the real path of the file to archive,
  235. // in order to have a shorter path memorized in the archive.
  236. // When $p_add_dir and $p_remove_dir are set, $p_remove_dir
  237. // is removed first, before $p_add_dir is added.
  238. // Options :
  239. // PCLZIP_OPT_ADD_PATH :
  240. // PCLZIP_OPT_REMOVE_PATH :
  241. // PCLZIP_OPT_REMOVE_ALL_PATH :
  242. // PCLZIP_OPT_COMMENT :
  243. // PCLZIP_CB_PRE_ADD :
  244. // PCLZIP_CB_POST_ADD :
  245. // Return Values :
  246. // 0 on failure,
  247. // The list of the added files, with a status of the add action.
  248. // (see PclZip::listContent() for list entry format)
  249. // --------------------------------------------------------------------------------
  250. public function create($p_filelist)
  251. {
  252. $v_result=1;
  253. // ----- Reset the error handler
  254. $this->privErrorReset();
  255. // ----- Set default values
  256. $v_options = array();
  257. $v_options[PCLZIP_OPT_NO_COMPRESSION] = false;
  258. // ----- Look for variable options arguments
  259. $v_size = func_num_args();
  260. // ----- Look for arguments
  261. if ($v_size > 1) {
  262. // ----- Get the arguments
  263. $v_arg_list = func_get_args();
  264. // ----- Remove from the options list the first argument
  265. array_shift($v_arg_list);
  266. $v_size--;
  267. // ----- Look for first arg
  268. if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
  269. // ----- Parse the options
  270. $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, array (
  271. PCLZIP_OPT_REMOVE_PATH => 'optional',
  272. PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',
  273. PCLZIP_OPT_ADD_PATH => 'optional',
  274. PCLZIP_CB_PRE_ADD => 'optional',
  275. PCLZIP_CB_POST_ADD => 'optional',
  276. PCLZIP_OPT_NO_COMPRESSION => 'optional',
  277. PCLZIP_OPT_COMMENT => 'optional',
  278. PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
  279. PCLZIP_OPT_TEMP_FILE_ON => 'optional',
  280. PCLZIP_OPT_TEMP_FILE_OFF => 'optional'
  281. //, PCLZIP_OPT_CRYPT => 'optional'
  282. ));
  283. if ($v_result != 1) {
  284. return 0;
  285. }
  286. } else {
  287. // ----- Look for 2 args
  288. // Here we need to support the first historic synopsis of the
  289. // method.
  290. // ----- Get the first argument
  291. $v_options[PCLZIP_OPT_ADD_PATH] = $v_arg_list[0];
  292. // ----- Look for the optional second argument
  293. if ($v_size == 2) {
  294. $v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1];
  295. } elseif ($v_size > 2) {
  296. PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments");
  297. return 0;
  298. }
  299. }
  300. }
  301. // ----- Look for default option values
  302. $this->privOptionDefaultThreshold($v_options);
  303. // ----- Init
  304. $v_string_list = array();
  305. $v_att_list = array();
  306. $v_filedescr_list = array();
  307. $p_result_list = array();
  308. // ----- Look if the $p_filelist is really an array
  309. if (is_array($p_filelist)) {
  310. // ----- Look if the first element is also an array
  311. // This will mean that this is a file description entry
  312. if (isset($p_filelist[0]) && is_array($p_filelist[0])) {
  313. $v_att_list = $p_filelist;
  314. } else {
  315. // ----- The list is a list of string names
  316. $v_string_list = $p_filelist;
  317. }
  318. } elseif (is_string($p_filelist)) {
  319. // ----- Look if the $p_filelist is a string
  320. // ----- Create a list from the string
  321. $v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist);
  322. } else {
  323. // ----- Invalid variable type for $p_filelist
  324. PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_filelist");
  325. return 0;
  326. }
  327. // ----- Reformat the string list
  328. if (sizeof($v_string_list) != 0) {
  329. foreach ($v_string_list as $v_string) {
  330. if ($v_string != '') {
  331. $v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string;
  332. } else {
  333. }
  334. }
  335. }
  336. // ----- For each file in the list check the attributes
  337. $v_supported_attributes = array(
  338. PCLZIP_ATT_FILE_NAME => 'mandatory',
  339. PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional',
  340. PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional',
  341. PCLZIP_ATT_FILE_MTIME => 'optional',
  342. PCLZIP_ATT_FILE_CONTENT => 'optional',
  343. PCLZIP_ATT_FILE_COMMENT => 'optional'
  344. );
  345. foreach ($v_att_list as $v_entry) {
  346. $v_result = $this->privFileDescrParseAtt($v_entry, $v_filedescr_list[], $v_options, $v_supported_attributes);
  347. if ($v_result != 1) {
  348. return 0;
  349. }
  350. }
  351. // ----- Expand the filelist (expand directories)
  352. $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options);
  353. if ($v_result != 1) {
  354. return 0;
  355. }
  356. // ----- Call the create fct
  357. $v_result = $this->privCreate($v_filedescr_list, $p_result_list, $v_options);
  358. if ($v_result != 1) {
  359. return 0;
  360. }
  361. // ----- Return
  362. return $p_result_list;
  363. }
  364. // --------------------------------------------------------------------------------
  365. // --------------------------------------------------------------------------------
  366. // Function :
  367. // add($p_filelist, $p_add_dir="", $p_remove_dir="")
  368. // add($p_filelist, $p_option, $p_option_value, ...)
  369. // Description :
  370. // This method supports two synopsis. The first one is historical.
  371. // This methods add the list of files in an existing archive.
  372. // If a file with the same name already exists, it is added at the end of the
  373. // archive, the first one is still present.
  374. // If the archive does not exist, it is created.
  375. // Parameters :
  376. // $p_filelist : An array containing file or directory names, or
  377. // a string containing one filename or one directory name, or
  378. // a string containing a list of filenames and/or directory
  379. // names separated by spaces.
  380. // $p_add_dir : A path to add before the real path of the archived file,
  381. // in order to have it memorized in the archive.
  382. // $p_remove_dir : A path to remove from the real path of the file to archive,
  383. // in order to have a shorter path memorized in the archive.
  384. // When $p_add_dir and $p_remove_dir are set, $p_remove_dir
  385. // is removed first, before $p_add_dir is added.
  386. // Options :
  387. // PCLZIP_OPT_ADD_PATH :
  388. // PCLZIP_OPT_REMOVE_PATH :
  389. // PCLZIP_OPT_REMOVE_ALL_PATH :
  390. // PCLZIP_OPT_COMMENT :
  391. // PCLZIP_OPT_ADD_COMMENT :
  392. // PCLZIP_OPT_PREPEND_COMMENT :
  393. // PCLZIP_CB_PRE_ADD :
  394. // PCLZIP_CB_POST_ADD :
  395. // Return Values :
  396. // 0 on failure,
  397. // The list of the added files, with a status of the add action.
  398. // (see PclZip::listContent() for list entry format)
  399. // --------------------------------------------------------------------------------
  400. public function add($p_filelist)
  401. {
  402. $v_result=1;
  403. // ----- Reset the error handler
  404. $this->privErrorReset();
  405. // ----- Set default values
  406. $v_options = array();
  407. $v_options[PCLZIP_OPT_NO_COMPRESSION] = false;
  408. // ----- Look for variable options arguments
  409. $v_size = func_num_args();
  410. // ----- Look for arguments
  411. if ($v_size > 1) {
  412. // ----- Get the arguments
  413. $v_arg_list = func_get_args();
  414. // ----- Remove form the options list the first argument
  415. array_shift($v_arg_list);
  416. $v_size--;
  417. // ----- Look for first arg
  418. if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
  419. // ----- Parse the options
  420. $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, array (
  421. PCLZIP_OPT_REMOVE_PATH => 'optional',
  422. PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',
  423. PCLZIP_OPT_ADD_PATH => 'optional',
  424. PCLZIP_CB_PRE_ADD => 'optional',
  425. PCLZIP_CB_POST_ADD => 'optional',
  426. PCLZIP_OPT_NO_COMPRESSION => 'optional',
  427. PCLZIP_OPT_COMMENT => 'optional',
  428. PCLZIP_OPT_ADD_COMMENT => 'optional',
  429. PCLZIP_OPT_PREPEND_COMMENT => 'optional',
  430. PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
  431. PCLZIP_OPT_TEMP_FILE_ON => 'optional',
  432. PCLZIP_OPT_TEMP_FILE_OFF => 'optional'
  433. //, PCLZIP_OPT_CRYPT => 'optional'
  434. ));
  435. if ($v_result != 1) {
  436. return 0;
  437. }
  438. } else {
  439. // ----- Look for 2 args
  440. // Here we need to support the first historic synopsis of the
  441. // method.
  442. // ----- Get the first argument
  443. $v_options[PCLZIP_OPT_ADD_PATH] = $v_add_path = $v_arg_list[0];
  444. // ----- Look for the optional second argument
  445. if ($v_size == 2) {
  446. $v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1];
  447. } elseif ($v_size > 2) {
  448. // ----- Error log
  449. PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments");
  450. // ----- Return
  451. return 0;
  452. }
  453. }
  454. }
  455. // ----- Look for default option values
  456. $this->privOptionDefaultThreshold($v_options);
  457. // ----- Init
  458. $v_string_list = array();
  459. $v_att_list = array();
  460. $v_filedescr_list = array();
  461. $p_result_list = array();
  462. // ----- Look if the $p_filelist is really an array
  463. if (is_array($p_filelist)) {
  464. // ----- Look if the first element is also an array
  465. // This will mean that this is a file description entry
  466. if (isset($p_filelist[0]) && is_array($p_filelist[0])) {
  467. $v_att_list = $p_filelist;
  468. } else {
  469. // ----- The list is a list of string names
  470. $v_string_list = $p_filelist;
  471. }
  472. } elseif (is_string($p_filelist)) {
  473. // ----- Look if the $p_filelist is a string
  474. // ----- Create a list from the string
  475. $v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist);
  476. } else {
  477. // ----- Invalid variable type for $p_filelist
  478. PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type '".gettype($p_filelist)."' for p_filelist");
  479. return 0;
  480. }
  481. // ----- Reformat the string list
  482. if (sizeof($v_string_list) != 0) {
  483. foreach ($v_string_list as $v_string) {
  484. $v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string;
  485. }
  486. }
  487. // ----- For each file in the list check the attributes
  488. $v_supported_attributes = array(
  489. PCLZIP_ATT_FILE_NAME => 'mandatory',
  490. PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional',
  491. PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional',
  492. PCLZIP_ATT_FILE_MTIME => 'optional',
  493. PCLZIP_ATT_FILE_CONTENT => 'optional',
  494. PCLZIP_ATT_FILE_COMMENT => 'optional',
  495. );
  496. foreach ($v_att_list as $v_entry) {
  497. $v_result = $this->privFileDescrParseAtt($v_entry, $v_filedescr_list[], $v_options, $v_supported_attributes);
  498. if ($v_result != 1) {
  499. return 0;
  500. }
  501. }
  502. // ----- Expand the filelist (expand directories)
  503. $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options);
  504. if ($v_result != 1) {
  505. return 0;
  506. }
  507. // ----- Call the create fct
  508. $v_result = $this->privAdd($v_filedescr_list, $p_result_list, $v_options);
  509. if ($v_result != 1) {
  510. return 0;
  511. }
  512. // ----- Return
  513. return $p_result_list;
  514. }
  515. // --------------------------------------------------------------------------------
  516. // --------------------------------------------------------------------------------
  517. // Function : listContent()
  518. // Description :
  519. // This public method, gives the list of the files and directories, with their
  520. // properties.
  521. // The properties of each entries in the list are (used also in other functions) :
  522. // filename : Name of the file. For a create or add action it is the filename
  523. // given by the user. For an extract function it is the filename
  524. // of the extracted file.
  525. // stored_filename : Name of the file / directory stored in the archive.
  526. // size : Size of the stored file.
  527. // compressed_size : Size of the file's data compressed in the archive
  528. // (without the headers overhead)
  529. // mtime : Last known modification date of the file (UNIX timestamp)
  530. // comment : Comment associated with the file
  531. // folder : true | false
  532. // index : index of the file in the archive
  533. // status : status of the action (depending of the action) :
  534. // Values are :
  535. // ok : OK !
  536. // filtered : the file / dir is not extracted (filtered by user)
  537. // already_a_directory : the file can not be extracted because a
  538. // directory with the same name already exists
  539. // write_protected : the file can not be extracted because a file
  540. // with the same name already exists and is
  541. // write protected
  542. // newer_exist : the file was not extracted because a newer file exists
  543. // path_creation_fail : the file is not extracted because the folder
  544. // does not exist and can not be created
  545. // write_error : the file was not extracted because there was a
  546. // error while writing the file
  547. // read_error : the file was not extracted because there was a error
  548. // while reading the file
  549. // invalid_header : the file was not extracted because of an archive
  550. // format error (bad file header)
  551. // Note that each time a method can continue operating when there
  552. // is an action error on a file, the error is only logged in the file status.
  553. // Return Values :
  554. // 0 on an unrecoverable failure,
  555. // The list of the files in the archive.
  556. // --------------------------------------------------------------------------------
  557. public function listContent()
  558. {
  559. $v_result=1;
  560. // ----- Reset the error handler
  561. $this->privErrorReset();
  562. // ----- Check archive
  563. if (!$this->privCheckFormat()) {
  564. return(0);
  565. }
  566. // ----- Call the extracting fct
  567. $p_list = array();
  568. if (($v_result = $this->privList($p_list)) != 1) {
  569. unset($p_list);
  570. return(0);
  571. }
  572. // ----- Return
  573. return $p_list;
  574. }
  575. // --------------------------------------------------------------------------------
  576. // --------------------------------------------------------------------------------
  577. // Function :
  578. // extract($p_path="./", $p_remove_path="")
  579. // extract([$p_option, $p_option_value, ...])
  580. // Description :
  581. // This method supports two synopsis. The first one is historical.
  582. // This method extract all the files / directories from the archive to the
  583. // folder indicated in $p_path.
  584. // If you want to ignore the 'root' part of path of the memorized files
  585. // you can indicate this in the optional $p_remove_path parameter.
  586. // By default, if a newer file with the same name already exists, the
  587. // file is not extracted.
  588. //
  589. // If both PCLZIP_OPT_PATH and PCLZIP_OPT_ADD_PATH aoptions
  590. // are used, the path indicated in PCLZIP_OPT_ADD_PATH is append
  591. // at the end of the path value of PCLZIP_OPT_PATH.
  592. // Parameters :
  593. // $p_path : Path where the files and directories are to be extracted
  594. // $p_remove_path : First part ('root' part) of the memorized path
  595. // (if any similar) to remove while extracting.
  596. // Options :
  597. // PCLZIP_OPT_PATH :
  598. // PCLZIP_OPT_ADD_PATH :
  599. // PCLZIP_OPT_REMOVE_PATH :
  600. // PCLZIP_OPT_REMOVE_ALL_PATH :
  601. // PCLZIP_CB_PRE_EXTRACT :
  602. // PCLZIP_CB_POST_EXTRACT :
  603. // Return Values :
  604. // 0 or a negative value on failure,
  605. // The list of the extracted files, with a status of the action.
  606. // (see PclZip::listContent() for list entry format)
  607. // --------------------------------------------------------------------------------
  608. public function extract()
  609. {
  610. $v_result=1;
  611. // ----- Reset the error handler
  612. $this->privErrorReset();
  613. // ----- Check archive
  614. if (!$this->privCheckFormat()) {
  615. return(0);
  616. }
  617. // ----- Set default values
  618. $v_options = array();
  619. // $v_path = "./";
  620. $v_path = '';
  621. $v_remove_path = "";
  622. $v_remove_all_path = false;
  623. // ----- Look for variable options arguments
  624. $v_size = func_num_args();
  625. // ----- Default values for option
  626. $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = false;
  627. // ----- Look for arguments
  628. if ($v_size > 0) {
  629. // ----- Get the arguments
  630. $v_arg_list = func_get_args();
  631. // ----- Look for first arg
  632. if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
  633. // ----- Parse the options
  634. $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, array (
  635. PCLZIP_OPT_PATH => 'optional',
  636. PCLZIP_OPT_REMOVE_PATH => 'optional',
  637. PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',
  638. PCLZIP_OPT_ADD_PATH => 'optional',
  639. PCLZIP_CB_PRE_EXTRACT => 'optional',
  640. PCLZIP_CB_POST_EXTRACT => 'optional',
  641. PCLZIP_OPT_SET_CHMOD => 'optional',
  642. PCLZIP_OPT_BY_NAME => 'optional',
  643. PCLZIP_OPT_BY_EREG => 'optional',
  644. PCLZIP_OPT_BY_PREG => 'optional',
  645. PCLZIP_OPT_BY_INDEX => 'optional',
  646. PCLZIP_OPT_EXTRACT_AS_STRING => 'optional',
  647. PCLZIP_OPT_EXTRACT_IN_OUTPUT => 'optional',
  648. PCLZIP_OPT_REPLACE_NEWER => 'optional',
  649. PCLZIP_OPT_STOP_ON_ERROR => 'optional',
  650. PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional',
  651. PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
  652. PCLZIP_OPT_TEMP_FILE_ON => 'optional',
  653. PCLZIP_OPT_TEMP_FILE_OFF => 'optional'
  654. ));
  655. if ($v_result != 1) {
  656. return 0;
  657. }
  658. // ----- Set the arguments
  659. if (isset($v_options[PCLZIP_OPT_PATH])) {
  660. $v_path = $v_options[PCLZIP_OPT_PATH];
  661. }
  662. if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) {
  663. $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH];
  664. }
  665. if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) {
  666. $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH];
  667. }
  668. if (isset($v_options[PCLZIP_OPT_ADD_PATH])) {
  669. // ----- Check for '/' in last path char
  670. if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) {
  671. $v_path .= '/';
  672. }
  673. $v_path .= $v_options[PCLZIP_OPT_ADD_PATH];
  674. }
  675. } else {
  676. // ----- Look for 2 args
  677. // Here we need to support the first historic synopsis of the
  678. // method.
  679. // ----- Get the first argument
  680. $v_path = $v_arg_list[0];
  681. // ----- Look for the optional second argument
  682. if ($v_size == 2) {
  683. $v_remove_path = $v_arg_list[1];
  684. } elseif ($v_size > 2) {
  685. // ----- Error log
  686. PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments");
  687. // ----- Return
  688. return 0;
  689. }
  690. }
  691. }
  692. // ----- Look for default option values
  693. $this->privOptionDefaultThreshold($v_options);
  694. // ----- Trace
  695. // ----- Call the extracting fct
  696. $p_list = array();
  697. $v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path, $v_remove_all_path, $v_options);
  698. if ($v_result < 1) {
  699. unset($p_list);
  700. return(0);
  701. }
  702. // ----- Return
  703. return $p_list;
  704. }
  705. // --------------------------------------------------------------------------------
  706. // --------------------------------------------------------------------------------
  707. // Function :
  708. // extractByIndex($p_index, $p_path="./", $p_remove_path="")
  709. // extractByIndex($p_index, [$p_option, $p_option_value, ...])
  710. // Description :
  711. // This method supports two synopsis. The first one is historical.
  712. // This method is doing a partial extract of the archive.
  713. // The extracted files or folders are identified by their index in the
  714. // archive (from 0 to n).
  715. // Note that if the index identify a folder, only the folder entry is
  716. // extracted, not all the files included in the archive.
  717. // Parameters :
  718. // $p_index : A single index (integer) or a string of indexes of files to
  719. // extract. The form of the string is "0,4-6,8-12" with only numbers
  720. // and '-' for range or ',' to separate ranges. No spaces or ';'
  721. // are allowed.
  722. // $p_path : Path where the files and directories are to be extracted
  723. // $p_remove_path : First part ('root' part) of the memorized path
  724. // (if any similar) to remove while extracting.
  725. // Options :
  726. // PCLZIP_OPT_PATH :
  727. // PCLZIP_OPT_ADD_PATH :
  728. // PCLZIP_OPT_REMOVE_PATH :
  729. // PCLZIP_OPT_REMOVE_ALL_PATH :
  730. // PCLZIP_OPT_EXTRACT_AS_STRING : The files are extracted as strings and
  731. // not as files.
  732. // The resulting content is in a new field 'content' in the file
  733. // structure.
  734. // This option must be used alone (any other options are ignored).
  735. // PCLZIP_CB_PRE_EXTRACT :
  736. // PCLZIP_CB_POST_EXTRACT :
  737. // Return Values :
  738. // 0 on failure,
  739. // The list of the extracted files, with a status of the action.
  740. // (see PclZip::listContent() for list entry format)
  741. // --------------------------------------------------------------------------------
  742. //function extractByIndex($p_index, options...)
  743. public function extractByIndex($p_index)
  744. {
  745. $v_result=1;
  746. // ----- Reset the error handler
  747. $this->privErrorReset();
  748. // ----- Check archive
  749. if (!$this->privCheckFormat()) {
  750. return(0);
  751. }
  752. // ----- Set default values
  753. $v_options = array();
  754. // $v_path = "./";
  755. $v_path = '';
  756. $v_remove_path = "";
  757. $v_remove_all_path = false;
  758. // ----- Look for variable options arguments
  759. $v_size = func_num_args();
  760. // ----- Default values for option
  761. $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = false;
  762. // ----- Look for arguments
  763. if ($v_size > 1) {
  764. // ----- Get the arguments
  765. $v_arg_list = func_get_args();
  766. // ----- Remove form the options list the first argument
  767. array_shift($v_arg_list);
  768. $v_size--;
  769. // ----- Look for first arg
  770. if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
  771. // ----- Parse the options
  772. $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, array(
  773. PCLZIP_OPT_PATH => 'optional',
  774. PCLZIP_OPT_REMOVE_PATH => 'optional',
  775. PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',
  776. PCLZIP_OPT_EXTRACT_AS_STRING => 'optional',
  777. PCLZIP_OPT_ADD_PATH => 'optional',
  778. PCLZIP_CB_PRE_EXTRACT => 'optional',
  779. PCLZIP_CB_POST_EXTRACT => 'optional',
  780. PCLZIP_OPT_SET_CHMOD => 'optional',
  781. PCLZIP_OPT_REPLACE_NEWER => 'optional',
  782. PCLZIP_OPT_STOP_ON_ERROR => 'optional',
  783. PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional',
  784. PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
  785. PCLZIP_OPT_TEMP_FILE_ON => 'optional',
  786. PCLZIP_OPT_TEMP_FILE_OFF => 'optional'
  787. ));
  788. if ($v_result != 1) {
  789. return 0;
  790. }
  791. // ----- Set the arguments
  792. if (isset($v_options[PCLZIP_OPT_PATH])) {
  793. $v_path = $v_options[PCLZIP_OPT_PATH];
  794. }
  795. if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) {
  796. $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH];
  797. }
  798. if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) {
  799. $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH];
  800. }
  801. if (isset($v_options[PCLZIP_OPT_ADD_PATH])) {
  802. // ----- Check for '/' in last path char
  803. if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) {
  804. $v_path .= '/';
  805. }
  806. $v_path .= $v_options[PCLZIP_OPT_ADD_PATH];
  807. }
  808. if (!isset($v_options[PCLZIP_OPT_EXTRACT_AS_STRING])) {
  809. $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = false;
  810. } else {
  811. }
  812. } else {
  813. // ----- Look for 2 args
  814. // Here we need to support the first historic synopsis of the
  815. // method.
  816. // ----- Get the first argument
  817. $v_path = $v_arg_list[0];
  818. // ----- Look for the optional second argument
  819. if ($v_size == 2) {
  820. $v_remove_path = $v_arg_list[1];
  821. } elseif ($v_size > 2) {
  822. // ----- Error log
  823. PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments");
  824. // ----- Return
  825. return 0;
  826. }
  827. }
  828. }
  829. // ----- Trace
  830. // ----- Trick
  831. // Here I want to reuse extractByRule(), so I need to parse the $p_index
  832. // with privParseOptions()
  833. $v_arg_trick = array (PCLZIP_OPT_BY_INDEX, $p_index);
  834. $v_options_trick = array();
  835. $v_result = $this->privParseOptions($v_arg_trick, sizeof($v_arg_trick), $v_options_trick, array (PCLZIP_OPT_BY_INDEX => 'optional'));
  836. if ($v_result != 1) {
  837. return 0;
  838. }
  839. $v_options[PCLZIP_OPT_BY_INDEX] = $v_options_trick[PCLZIP_OPT_BY_INDEX];
  840. // ----- Look for default option values
  841. $this->privOptionDefaultThreshold($v_options);
  842. // ----- Call the extracting fct
  843. if (($v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path, $v_remove_all_path, $v_options)) < 1) {
  844. return(0);
  845. }
  846. // ----- Return
  847. return $p_list;
  848. }
  849. // --------------------------------------------------------------------------------
  850. // --------------------------------------------------------------------------------
  851. // Function :
  852. // delete([$p_option, $p_option_value, ...])
  853. // Description :
  854. // This method removes files from the archive.
  855. // If no parameters are given, then all the archive is emptied.
  856. // Parameters :
  857. // None or optional arguments.
  858. // Options :
  859. // PCLZIP_OPT_BY_INDEX :
  860. // PCLZIP_OPT_BY_NAME :
  861. // PCLZIP_OPT_BY_EREG :
  862. // PCLZIP_OPT_BY_PREG :
  863. // Return Values :
  864. // 0 on failure,
  865. // The list of the files which are still present in the archive.
  866. // (see PclZip::listContent() for list entry format)
  867. // --------------------------------------------------------------------------------
  868. public function delete()
  869. {
  870. $v_result=1;
  871. // ----- Reset the error handler
  872. $this->privErrorReset();
  873. // ----- Check archive
  874. if (!$this->privCheckFormat()) {
  875. return(0);
  876. }
  877. // ----- Set default values
  878. $v_options = array();
  879. // ----- Look for variable options arguments
  880. $v_size = func_num_args();
  881. // ----- Look for arguments
  882. if ($v_size > 0) {
  883. // ----- Get the arguments
  884. $v_arg_list = func_get_args();
  885. // ----- Parse the options
  886. $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, array (
  887. PCLZIP_OPT_BY_NAME => 'optional',
  888. PCLZIP_OPT_BY_EREG => 'optional',
  889. PCLZIP_OPT_BY_PREG => 'optional',
  890. PCLZIP_OPT_BY_INDEX => 'optional'
  891. ));
  892. if ($v_result != 1) {
  893. return 0;
  894. }
  895. }
  896. // ----- Magic quotes trick
  897. $this->privDisableMagicQuotes();
  898. // ----- Call the delete fct
  899. $v_list = array();
  900. if (($v_result = $this->privDeleteByRule($v_list, $v_options)) != 1) {
  901. $this->privSwapBackMagicQuotes();
  902. unset($v_list);
  903. return(0);
  904. }
  905. // ----- Magic quotes trick
  906. $this->privSwapBackMagicQuotes();
  907. // ----- Return
  908. return $v_list;
  909. }
  910. // --------------------------------------------------------------------------------
  911. // --------------------------------------------------------------------------------
  912. // Function : deleteByIndex()
  913. // Description :
  914. // ***** Deprecated *****
  915. // delete(PCLZIP_OPT_BY_INDEX, $p_index) should be prefered.
  916. // --------------------------------------------------------------------------------
  917. public function deleteByIndex($p_index)
  918. {
  919. $p_list = $this->delete(PCLZIP_OPT_BY_INDEX, $p_index);
  920. // ----- Return
  921. return $p_list;
  922. }
  923. // --------------------------------------------------------------------------------
  924. // --------------------------------------------------------------------------------
  925. // Function : properties()
  926. // Description :
  927. // This method gives the properties of the archive.
  928. // The properties are :
  929. // nb : Number of files in the archive
  930. // comment : Comment associated with the archive file
  931. // status : not_exist, ok
  932. // Parameters :
  933. // None
  934. // Return Values :
  935. // 0 on failure,
  936. // An array with the archive properties.
  937. // --------------------------------------------------------------------------------
  938. public function properties()
  939. {
  940. // ----- Reset the error handler
  941. $this->privErrorReset();
  942. // ----- Magic quotes trick
  943. $this->privDisableMagicQuotes();
  944. // ----- Check archive
  945. if (!$this->privCheckFormat()) {
  946. $this->privSwapBackMagicQuotes();
  947. return(0);
  948. }
  949. // ----- Default properties
  950. $v_prop = array();
  951. $v_prop['comment'] = '';
  952. $v_prop['nb'] = 0;
  953. $v_prop['status'] = 'not_exist';
  954. // ----- Look if file exists
  955. if (@is_file($this->zipname)) {
  956. // ----- Open the zip file
  957. if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0) {
  958. $this->privSwapBackMagicQuotes();
  959. // ----- Error log
  960. PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in binary read mode');
  961. // ----- Return
  962. return 0;
  963. }
  964. // ----- Read the central directory informations
  965. $v_central_dir = array();
  966. if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) {
  967. $this->privSwapBackMagicQuotes();
  968. return 0;
  969. }
  970. // ----- Close the zip file
  971. $this->privCloseFd();
  972. // ----- Set the user attributes
  973. $v_prop['comment'] = $v_central_dir['comment'];
  974. $v_prop['nb'] = $v_central_dir['entries'];
  975. $v_prop['status'] = 'ok';
  976. }
  977. // ----- Magic quotes trick
  978. $this->privSwapBackMagicQuotes();
  979. // ----- Return
  980. return $v_prop;
  981. }
  982. // --------------------------------------------------------------------------------
  983. // --------------------------------------------------------------------------------
  984. // Function : duplicate()
  985. // Description :
  986. // This method creates an archive by copying the content of an other one. If
  987. // the archive already exist, it is replaced by the new one without any warning.
  988. // Parameters :
  989. // $p_archive : The filename of a valid archive, or
  990. // a valid PclZip object.
  991. // Return Values :
  992. // 1 on success.
  993. // 0 or a negative value on error (error code).
  994. // --------------------------------------------------------------------------------
  995. public function duplicate($p_archive)
  996. {
  997. $v_result = 1;
  998. // ----- Reset the error handler
  999. $this->privErrorReset();
  1000. // ----- Look if the $p_archive is a PclZip object
  1001. if ((is_object($p_archive)) && (get_class($p_archive) == 'pclzip')) {
  1002. // ----- Duplicate the archive
  1003. $v_result = $this->privDuplicate($p_archive->zipname);
  1004. } elseif (is_string($p_archive)) {
  1005. // ----- Look if the $p_archive is a string (so a filename)
  1006. // ----- Check that $p_archive is a valid zip file
  1007. // TBC : Should also check the archive format
  1008. if (!is_file($p_archive)) {
  1009. // ----- Error log
  1010. PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "No file with filename '".$p_archive."'");
  1011. $v_result = PCLZIP_ERR_MISSING_FILE;
  1012. } else {
  1013. // ----- Duplicate the archive
  1014. $v_result = $this->privDuplicate($p_archive);
  1015. }
  1016. } else {
  1017. // ----- Invalid variable
  1018. // ----- Error log
  1019. PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add");
  1020. $v_result = PCLZIP_ERR_INVALID_PARAMETER;
  1021. }
  1022. // ----- Return
  1023. return $v_result;
  1024. }
  1025. // --------------------------------------------------------------------------------
  1026. // --------------------------------------------------------------------------------
  1027. // Function : merge()
  1028. // Description :
  1029. // This method merge the $p_archive_to_add archive at the end of the current
  1030. // one ($this).
  1031. // If the archive ($this) does not exist, the merge becomes a duplicate.
  1032. // If the $p_archive_to_add archive does not exist, the merge is a success.
  1033. // Parameters :
  1034. // $p_archive_to_add : It can be directly the filename of a valid zip archive,
  1035. // or a PclZip object archive.
  1036. // Return Values :
  1037. // 1 on success,
  1038. // 0 or negative values on error (see below).
  1039. // --------------------------------------------------------------------------------
  1040. public function merge($p_archive_to_add)
  1041. {
  1042. $v_result = 1;
  1043. // ----- Reset the error handler
  1044. $this->privErrorReset();
  1045. // ----- Check archive
  1046. if (!$this->privCheckFormat()) {
  1047. return(0);
  1048. }
  1049. // ----- Look if the $p_archive_to_add is a PclZip object
  1050. if ((is_object($p_archive_to_add)) && (get_class($p_archive_to_add) == 'pclzip')) {
  1051. // ----- Merge the archive
  1052. $v_result = $this->privMerge($p_archive_to_add);
  1053. } elseif (is_string($p_archive_to_add)) {
  1054. // ----- Look if the $p_archive_to_add is a string (so a filename)
  1055. // ----- Create a temporary archive
  1056. $v_object_archive = new PclZip($p_archive_to_add);
  1057. // ----- Merge the archive
  1058. $v_result = $this->privMerge($v_object_archive);
  1059. } else {
  1060. // ----- Invalid variable
  1061. // ----- Error log
  1062. PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add");
  1063. $v_result = PCLZIP_ERR_INVALID_PARAMETER;
  1064. }
  1065. // ----- Return
  1066. return $v_result;
  1067. }
  1068. // --------------------------------------------------------------------------------
  1069. // --------------------------------------------------------------------------------
  1070. // Function : errorCode()
  1071. // Description :
  1072. // Parameters :
  1073. // --------------------------------------------------------------------------------
  1074. public function errorCode()
  1075. {
  1076. if (PCLZIP_ERROR_EXTERNAL == 1) {
  1077. return(PclErrorCode());
  1078. } else {
  1079. return($this->error_code);
  1080. }
  1081. }
  1082. // --------------------------------------------------------------------------------
  1083. // --------------------------------------------------------------------------------
  1084. // Function : errorName()
  1085. // Description :
  1086. // Parameters :
  1087. // --------------------------------------------------------------------------------
  1088. public function errorName($p_with_code = false)
  1089. {
  1090. $v_name = array(
  1091. PCLZIP_ERR_NO_ERROR => 'PCLZIP_ERR_NO_ERROR',
  1092. PCLZIP_ERR_WRITE_OPEN_FAIL => 'PCLZIP_ERR_WRITE_OPEN_FAIL',
  1093. PCLZIP_ERR_READ_OPEN_FAIL => 'PCLZIP_ERR_READ_OPEN_FAIL',
  1094. PCLZIP_ERR_INVALID_PARAMETER => 'PCLZIP_ERR_INVALID_PARAMETER',
  1095. PCLZIP_ERR_MISSING_FILE => 'PCLZIP_ERR_MISSING_FILE',
  1096. PCLZIP_ERR_FILENAME_TOO_LONG => 'PCLZIP_ERR_FILENAME_TOO_LONG',
  1097. PCLZIP_ERR_INVALID_ZIP => 'PCLZIP_ERR_INVALID_ZIP',
  1098. PCLZIP_ERR_BAD_EXTRACTED_FILE => 'PCLZIP_ERR_BAD_EXTRACTED_FILE',
  1099. PCLZIP_ERR_DIR_CREATE_FAIL => 'PCLZIP_ERR_DIR_CREATE_FAIL',
  1100. PCLZIP_ERR_BAD_EXTENSION => 'PCLZIP_ERR_BAD_EXTENSION',
  1101. PCLZIP_ERR_BAD_FORMAT => 'PCLZIP_ERR_BAD_FORMAT',
  1102. PCLZIP_ERR_DELETE_FILE_FAIL => 'PCLZIP_ERR_DELETE_FILE_FAIL',
  1103. PCLZIP_ERR_RENAME_FILE_FAIL => 'PCLZIP_ERR_RENAME_FILE_FAIL',
  1104. PCLZIP_ERR_BAD_CHECKSUM => 'PCLZIP_ERR_BAD_CHECKSUM',
  1105. PCLZIP_ERR_INVALID_ARCHIVE_ZIP => 'PCLZIP_ERR_INVALID_ARCHIVE_ZIP',
  1106. PCLZIP_ERR_MISSING_OPTION_VALUE => 'PCLZIP_ERR_MISSING_OPTION_VALUE',
  1107. PCLZIP_ERR_INVALID_OPTION_VALUE => 'PCLZIP_ERR_INVALID_OPTION_VALUE',
  1108. PCLZIP_ERR_UNSUPPORTED_COMPRESSION => 'PCLZIP_ERR_UNSUPPORTED_COMPRESSION',
  1109. PCLZIP_ERR_UNSUPPORTED_ENCRYPTION => 'PCLZIP_ERR_UNSUPPORTED_ENCRYPTION',
  1110. PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE => 'PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE',
  1111. PCLZIP_ERR_DIRECTORY_RESTRICTION => 'PCLZIP_ERR_DIRECTORY_RESTRICTION',
  1112. );
  1113. if (isset($v_name[$this->error_code])) {
  1114. $v_value = $v_name[$this->error_code];
  1115. } else {
  1116. $v_value = 'NoName';
  1117. }
  1118. if ($p_with_code) {
  1119. return($v_value.' ('.$this->error_code.')');
  1120. } else {
  1121. return($v_value);
  1122. }
  1123. }
  1124. // --------------------------------------------------------------------------------
  1125. // --------------------------------------------------------------------------------
  1126. // Function : errorInfo()
  1127. // Description :
  1128. // Parameters :
  1129. // --------------------------------------------------------------------------------
  1130. public function errorInfo($p_full = false)
  1131. {
  1132. if (PCLZIP_ERROR_EXTERNAL == 1) {
  1133. return(PclErrorString());
  1134. } else {
  1135. if ($p_full) {
  1136. return($this->errorName(true)." : ".$this->error_string);
  1137. } else {
  1138. return($this->error_string." [code ".$this->error_code."]");
  1139. }
  1140. }
  1141. }
  1142. // --------------------------------------------------------------------------------
  1143. // --------------------------------------------------------------------------------
  1144. // ***** UNDER THIS LINE ARE DEFINED PRIVATE INTERNAL FUNCTIONS *****
  1145. // ***** *****
  1146. // ***** THESES FUNCTIONS MUST NOT BE USED DIRECTLY *****
  1147. // --------------------------------------------------------------------------------
  1148. // --------------------------------------------------------------------------------
  1149. // Function : privCheckFormat()
  1150. // Description :
  1151. // This method check that the archive exists and is a valid zip archive.
  1152. // Several level of check exists. (futur)
  1153. // Parameters :
  1154. // $p_level : Level of check. Default 0.
  1155. // 0 : Check the first bytes (magic codes) (default value))
  1156. // 1 : 0 + Check the central directory (futur)
  1157. // 2 : 1 + Check each file header (futur)
  1158. // Return Values :
  1159. // true on success,
  1160. // false on error, the error code is set.
  1161. // --------------------------------------------------------------------------------
  1162. public function privCheckFormat($p_level = 0)
  1163. {
  1164. $v_result = true;
  1165. // ----- Reset the file system cache
  1166. clearstatcache();
  1167. // ----- Reset the error handler
  1168. $this->privErrorReset();
  1169. // ----- Look if the file exits
  1170. if (!is_file($this->zipname)) {
  1171. // ----- Error log
  1172. PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "Missing archive file '".$this->zipname."'");
  1173. return(false);
  1174. }
  1175. // ----- Check that the file is readeable
  1176. if (!is_readable($this->zipname)) {
  1177. // ----- Error log
  1178. PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to read archive '".$this->zipname."'");
  1179. return(false);
  1180. }
  1181. // ----- Check the magic code
  1182. // TBC
  1183. // ----- Check the central header
  1184. // TBC
  1185. // ----- Check each file header
  1186. // TBC
  1187. // ----- Return
  1188. return $v_result;
  1189. }
  1190. // --------------------------------------------------------------------------------
  1191. // --------------------------------------------------------------------------------
  1192. // Function : privParseOptions()
  1193. // Description :
  1194. // This internal methods reads the variable list of arguments ($p_options_list,
  1195. // $p_size) and generate an array with the options and values ($v_result_list).
  1196. // $v_requested_options contains the options that can be present and those that
  1197. // must be present.
  1198. // $v_requested_options is an array, with the option value as key, and 'optional',
  1199. // or 'mandatory' as value.
  1200. // Parameters :
  1201. // See above.
  1202. // Return Values :
  1203. // 1 on success.
  1204. // 0 on failure.
  1205. // --------------------------------------------------------------------------------
  1206. public function privParseOptions(&$p_options_list, $p_size, &$v_result_list, $v_requested_options = false)
  1207. {
  1208. $v_result=1;
  1209. // ----- Read the options
  1210. $i=0;
  1211. while ($i<$p_size) {
  1212. // ----- Check if the option is supported
  1213. if (!isset($v_requested_options[$p_options_list[$i]])) {
  1214. // ----- Error log
  1215. PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid optional parameter '".$p_options_list[$i]."' for this method");
  1216. // ----- Return
  1217. return PclZip::errorCode();
  1218. }
  1219. // ----- Look for next option
  1220. switch ($p_options_list[$i]) {
  1221. // ----- Look for options that request a path value
  1222. case PCLZIP_OPT_PATH:
  1223. case PCLZIP_OPT_REMOVE_PATH:
  1224. case PCLZIP_OPT_ADD_PATH:
  1225. // ----- Check the number of parameters
  1226. if (($i+1) >= $p_size) {
  1227. // ----- Error log
  1228. PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
  1229. // ----- Return
  1230. return PclZip::errorCode();
  1231. }
  1232. // ----- Get the value
  1233. $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i+1], false);
  1234. $i++;
  1235. break;
  1236. case PCLZIP_OPT_TEMP_FILE_THRESHOLD:
  1237. // ----- Check the number of parameters
  1238. if (($i+1) >= $p_size) {
  1239. PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
  1240. return PclZip::errorCode();
  1241. }
  1242. // ----- Check for incompatible options
  1243. if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) {
  1244. PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'");
  1245. return PclZip::errorCode();
  1246. }
  1247. // ----- Check the value
  1248. $v_value = $p_options_list[$i+1];
  1249. if ((!is_integer($v_value)) || ($v_value<0)) {
  1250. PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Integer expected for option '".PclZipUtilOptionText($p_options_list[$i])."'");
  1251. return PclZip::errorCode();
  1252. }
  1253. // ----- Get the value (and convert it in bytes)
  1254. $v_result_list[$p_options_list[$i]] = $v_value*1048576;
  1255. $i++;
  1256. break;
  1257. case PCLZIP_OPT_TEMP_FILE_ON:
  1258. // ----- Check for incompatible options
  1259. if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) {
  1260. PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'");
  1261. return PclZip::errorCode();
  1262. }
  1263. $v_result_list[$p_options_list[$i]] = true;
  1264. break;
  1265. case PCLZIP_OPT_TEMP_FILE_OFF:
  1266. // ----- Check for incompatible options
  1267. if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_ON])) {
  1268. PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_ON'");
  1269. return PclZip::errorCode();
  1270. }
  1271. // ----- Check for incompatible options
  1272. if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) {
  1273. PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_THRESHOLD'");
  1274. return PclZip::errorCode();
  1275. }
  1276. $v_result_list[$p_options_list[$i]] = true;
  1277. break;
  1278. case PCLZIP_OPT_EXTRACT_DIR_RESTRICTION:
  1279. // ----- Check the number of parameters
  1280. if (($i+1) >= $p_size) {
  1281. // ----- Error log
  1282. PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
  1283. // ----- Return
  1284. return PclZip::errorCode();
  1285. }
  1286. // ----- Get the value
  1287. if (is_string($p_options_list[$i+1]) && ($p_options_list[$i+1] != '')) {
  1288. $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i+1], false);
  1289. $i++;
  1290. } else {
  1291. }
  1292. break;
  1293. // ----- Look for options that request an array of string for value
  1294. case PCLZIP_OPT_BY_NAME:
  1295. // ----- Check the number of parameters
  1296. if (($i+1) >= $p_size) {
  1297. // ----- Error log
  1298. PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
  1299. // ----- Return
  1300. return PclZip::errorCode();
  1301. }
  1302. // ----- Get the value
  1303. if (is_string($p_options_list[$i+1])) {
  1304. $v_result_list[$p_options_list[$i]][0] = $p_options_list[$i+1];
  1305. } elseif (is_array($p_options_list[$i+1])) {
  1306. $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1];
  1307. } else {
  1308. // ----- Error log
  1309. PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
  1310. // ----- Return
  1311. return PclZip::errorCode();
  1312. }
  1313. $i++;
  1314. break;
  1315. // ----- Look for options that request an EREG or PREG expression
  1316. case PCLZIP_OPT_BY_EREG:
  1317. // ereg() is deprecated starting with PHP 5.3. Move PCLZIP_OPT_BY_EREG
  1318. // to PCLZIP_OPT_BY_PREG
  1319. $p_options_list[$i] = PCLZIP_OPT_BY_PREG;
  1320. case PCLZIP_OPT_BY_PREG:
  1321. //case PCLZIP_OPT_CRYPT :
  1322. // ----- Check the number of parameters
  1323. if (($i+1) >= $p_size) {
  1324. // ----- Error log
  1325. PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
  1326. // ----- Return
  1327. return PclZip::errorCode();
  1328. }
  1329. // ----- Get the value
  1330. if (is_string($p_options_list[$i+1])) {
  1331. $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1];
  1332. } else {
  1333. // ----- Error log
  1334. PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
  1335. // ----- Return
  1336. return PclZip::errorCode();
  1337. }
  1338. $i++;
  1339. break;
  1340. // ----- Look for options that takes a string
  1341. case PCLZIP_OPT_COMMENT:
  1342. case PCLZIP_OPT_ADD_COMMENT:
  1343. case PCLZIP_OPT_PREPEND_COMMENT:
  1344. // ----- Check the number of parameters
  1345. if (($i+1) >= $p_size) {
  1346. // ----- Error log
  1347. PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
  1348. // ----- Return
  1349. return PclZip::errorCode();
  1350. }
  1351. // ----- Get the value
  1352. if (is_string($p_options_list[$i+1])) {
  1353. $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1];
  1354. } else {
  1355. // ----- Error log
  1356. PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '" .PclZipUtilOptionText($p_options_list[$i]) ."'");
  1357. // ----- Return
  1358. return PclZip::errorCode();
  1359. }
  1360. $i++;
  1361. break;
  1362. // ----- Look for options that request an array of index
  1363. case PCLZIP_OPT_BY_INDEX:
  1364. // ----- Check the number of parameters
  1365. if (($i+1) >= $p_size) {
  1366. // ----- Error log
  1367. PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
  1368. // ----- Return
  1369. return PclZip::errorCode();
  1370. }
  1371. // ----- Get the value
  1372. $v_work_list = array();
  1373. if (is_string($p_options_list[$i+1])) {
  1374. // ----- Remove spaces
  1375. $p_options_list[$i+1] = strtr($p_options_list[$i+1], ' ', '');
  1376. // ----- Parse items
  1377. $v_work_list = explode(",", $p_options_list[$i+1]);
  1378. } elseif (is_integer($p_options_list[$i+1])) {
  1379. $v_work_list[0] = $p_options_list[$i+1].'-'.$p_options_list[$i+1];
  1380. } elseif (is_array($p_options_list[$i+1])) {
  1381. $v_work_list = $p_options_list[$i+1];
  1382. } else {
  1383. // ----- Error log
  1384. PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Value must be integer, string or array for option '".PclZipUtilOptionText($p_options_list[$i])."'");
  1385. // ----- Return
  1386. return PclZip::errorCode();
  1387. }
  1388. // ----- Reduce the index list
  1389. // each index item in the list must be a couple with a start and
  1390. // an end value : [0,3], [5-5], [8-10], ...
  1391. // ----- Check the format of each item
  1392. $v_sort_flag=false;
  1393. $v_sort_value=0;
  1394. for ($j=0; $j<sizeof($v_work_list); $j++) {
  1395. // ----- Explode the item
  1396. $v_item_list = explode("-", $v_work_list[$j]);
  1397. $v_size_item_list = sizeof($v_item_list);
  1398. // ----- TBC : Here we might check that each item is a
  1399. // real integer ...
  1400. // ----- Look for single value
  1401. if ($v_size_item_list == 1) {
  1402. // ----- Set the option value
  1403. $v_result_list[$p_options_list[$i]][$j]['start'] = $v_item_list[0];
  1404. $v_result_list[$p_options_list[$i]][$j]['end'] = $v_item_list[0];
  1405. } elseif ($v_size_item_list == 2) {
  1406. // ----- Set the option value
  1407. $v_result_list[$p_options_list[$i]][$j]['start'] = $v_item_list[0];
  1408. $v_result_list[$p_options_list[$i]][$j]['end'] = $v_item_list[1];
  1409. } else {
  1410. // ----- Error log
  1411. PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Too many values in index range for option '".PclZipUtilOptionText($p_options_list[$i])."'");
  1412. // ----- Return
  1413. return PclZip::errorCode();
  1414. }
  1415. // ----- Look for list sort
  1416. if ($v_result_list[$p_options_list[$i]][$j]['start'] < $v_sort_value) {
  1417. $v_sort_flag=true;
  1418. // ----- TBC : An automatic sort should be writen ...
  1419. // ----- Error log
  1420. PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Invalid order of index range for option '".PclZipUtilOptionText($p_options_list[$i])."'");
  1421. // ----- Return
  1422. return PclZip::errorCode();
  1423. }
  1424. $v_sort_value = $v_result_list[$p_options_list[$i]][$j]['start'];
  1425. }
  1426. // ----- Sort the items
  1427. if ($v_sort_flag) {
  1428. // TBC : To Be Completed
  1429. }
  1430. // ----- Next option
  1431. $i++;
  1432. break;
  1433. // ----- Look for options that request no value
  1434. case PCLZIP_OPT_REMOVE_ALL_PATH:
  1435. case PCLZIP_OPT_EXTRACT_AS_STRING:
  1436. case PCLZIP_OPT_NO_COMPRESSION:
  1437. case PCLZIP_OPT_EXTRACT_IN_OUTPUT:
  1438. case PCLZIP_OPT_REPLACE_NEWER:
  1439. case PCLZIP_OPT_STOP_ON_ERROR:
  1440. $v_result_list[$p_options_list[$i]] = true;
  1441. break;
  1442. // ----- Look for options that request an octal value
  1443. case PCLZIP_OPT_SET_CHMOD:
  1444. // ----- Check the number of parameters
  1445. if (($i+1) >= $p_size) {
  1446. // ----- Error log
  1447. PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
  1448. // ----- Return
  1449. return PclZip::errorCode();
  1450. }
  1451. // ----- Get the value
  1452. $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1];
  1453. $i++;
  1454. break;
  1455. // ----- Look for options that request a call-back
  1456. case PCLZIP_CB_PRE_EXTRACT:
  1457. case PCLZIP_CB_POST_EXTRACT:
  1458. case PCLZIP_CB_PRE_ADD:
  1459. case PCLZIP_CB_POST_ADD:
  1460. /* for futur use
  1461. case PCLZIP_CB_PRE_DELETE :
  1462. case PCLZIP_CB_POST_DELETE :
  1463. case PCLZIP_CB_PRE_LIST :
  1464. case PCLZIP_CB_POST_LIST :
  1465. */
  1466. // ----- Check the number of parameters
  1467. if (($i+1) >= $p_size) {
  1468. // ----- Error log
  1469. PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
  1470. // ----- Return
  1471. return PclZip::errorCode();
  1472. }
  1473. // ----- Get the value
  1474. $v_function_name = $p_options_list[$i+1];
  1475. // ----- Check that the value is a valid existing function
  1476. if (!function_exists($v_function_name)) {
  1477. // ----- Error log
  1478. PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Function '".$v_function_name."()' is not an existing function for option '".PclZipUtilOptionText($p_options_list[$i])."'");
  1479. // ----- Return
  1480. return PclZip::errorCode();
  1481. }
  1482. // ----- Set the attribute
  1483. $v_result_list[$p_options_list[$i]] = $v_function_name;
  1484. $i++;
  1485. break;
  1486. default:
  1487. // ----- Error log
  1488. PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Unknown parameter '" .$p_options_list[$i]."'");
  1489. // ----- Return
  1490. return PclZip::errorCode();
  1491. }
  1492. // ----- Next options
  1493. $i++;
  1494. }
  1495. // ----- Look for mandatory options
  1496. if ($v_requested_options !== false) {
  1497. for ($key=reset($v_requested_options); $key=key($v_requested_options); $key=next($v_requested_options)) {
  1498. // ----- Look for mandatory option
  1499. if ($v_requested_options[$key] == 'mandatory') {
  1500. // ----- Look if present
  1501. if (!isset($v_result_list[$key])) {
  1502. // ----- Error log
  1503. PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Missing mandatory parameter ".PclZipUtilOptionText($key)."(".$key.")");
  1504. // ----- Return
  1505. return PclZip::errorCode();
  1506. }
  1507. }
  1508. }
  1509. }
  1510. // ----- Look for default values
  1511. if (!isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) {
  1512. }
  1513. // ----- Return
  1514. return $v_result;
  1515. }
  1516. // --------------------------------------------------------------------------------
  1517. // --------------------------------------------------------------------------------
  1518. // Function : privOptionDefaultThreshold()
  1519. // Description :
  1520. // Parameters :
  1521. // Return Values :
  1522. // --------------------------------------------------------------------------------
  1523. public function privOptionDefaultThreshold(&$p_options)
  1524. {
  1525. $v_result=1;
  1526. if (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]) || isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) {
  1527. return $v_result;
  1528. }
  1529. // ----- Get 'memory_limit' configuration value
  1530. $v_memory_limit = ini_get('memory_limit');
  1531. $v_memory_limit = trim($v_memory_limit);
  1532. $last = strtolower(substr($v_memory_limit, -1));
  1533. if ($last == 'g') {
  1534. //$v_memory_limit = $v_memory_limit*1024*1024*1024;
  1535. $v_memory_limit = $v_memory_limit*1073741824;
  1536. }
  1537. if ($last == 'm') {
  1538. //$v_memory_limit = $v_memory_limit*1024*1024;
  1539. $v_memory_limit = $v_memory_limit*1048576;
  1540. }
  1541. if ($last == 'k') {
  1542. $v_memory_limit = $v_memory_limit*1024;
  1543. }
  1544. $p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] = floor($v_memory_limit*PCLZIP_TEMPORARY_FILE_RATIO);
  1545. // ----- Sanity check : No threshold if value lower than 1M
  1546. if ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] < 1048576) {
  1547. unset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]);
  1548. }
  1549. // ----- Return
  1550. return $v_result;
  1551. }
  1552. // --------------------------------------------------------------------------------
  1553. // --------------------------------------------------------------------------------
  1554. // Function : privFileDescrParseAtt()
  1555. // Description :
  1556. // Parameters :
  1557. // Return Values :
  1558. // 1 on success.
  1559. // 0 on failure.
  1560. // --------------------------------------------------------------------------------
  1561. public function privFileDescrParseAtt(&$p_file_list, &$p_filedescr, $v_options, $v_requested_options = false)
  1562. {
  1563. $v_result=1;
  1564. // ----- For each file in the list check the attributes
  1565. foreach ($p_file_list as $v_key => $v_value) {
  1566. // ----- Check if the option is supported
  1567. if (!isset($v_requested_options[$v_key])) {
  1568. // ----- Error log
  1569. PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file attribute '".$v_key."' for this file");
  1570. // ----- Return
  1571. return PclZip::errorCode();
  1572. }
  1573. // ----- Look for attribute
  1574. switch ($v_key) {
  1575. case PCLZIP_ATT_FILE_NAME:
  1576. if (!is_string($v_value)) {
  1577. PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'");
  1578. return PclZip::errorCode();
  1579. }
  1580. $p_filedescr['filename'] = PclZipUtilPathReduction($v_value);
  1581. if ($p_filedescr['filename'] == '') {
  1582. PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty filename for attribute '".PclZipUtilOptionText($v_key)."'");
  1583. return PclZip::errorCode();
  1584. }
  1585. break;
  1586. case PCLZIP_ATT_FILE_NEW_SHORT_NAME:
  1587. if (!is_string($v_value)) {
  1588. PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'");
  1589. return PclZip::errorCode();
  1590. }
  1591. $p_filedescr['new_short_name'] = PclZipUtilPathReduction($v_value);
  1592. if ($p_filedescr['new_short_name'] == '') {
  1593. PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty short filename for attribute '".PclZipUtilOptionText($v_key)."'");
  1594. return PclZip::errorCode();
  1595. }
  1596. break;
  1597. case PCLZIP_ATT_FILE_NEW_FULL_NAME:
  1598. if (!is_string($v_value)) {
  1599. PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'");
  1600. return PclZip::errorCode();
  1601. }
  1602. $p_filedescr['new_full_name'] = PclZipUtilPathReduction($v_value);
  1603. if ($p_filedescr['new_full_name'] == '') {
  1604. PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty full filename for attribute '".PclZipUtilOptionText($v_key)."'");
  1605. return PclZip::errorCode();
  1606. }
  1607. break;
  1608. // ----- Look for options that takes a string
  1609. case PCLZIP_ATT_FILE_COMMENT:
  1610. if (!is_string($v_value)) {
  1611. PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'");
  1612. return PclZip::errorCode();
  1613. }
  1614. $p_filedescr['comment'] = $v_value;
  1615. break;
  1616. case PCLZIP_ATT_FILE_MTIME:
  1617. if (!is_integer($v_value)) {
  1618. PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". Integer expected for attribute '".PclZipUtilOptionText($v_key)."'");
  1619. return PclZip::errorCode();
  1620. }
  1621. $p_filedescr['mtime'] = $v_value;
  1622. break;
  1623. case PCLZIP_ATT_FILE_CONTENT:
  1624. $p_filedescr['content'] = $v_value;
  1625. break;
  1626. default:
  1627. // ----- Error log
  1628. PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Unknown parameter '".$v_key."'");
  1629. // ----- Return
  1630. return PclZip::errorCode();
  1631. }
  1632. // ----- Look for mandatory options
  1633. if ($v_requested_options !== false) {
  1634. for ($key = reset($v_requested_options); $key = key($v_requested_options); $key = next($v_requested_options)) {
  1635. // ----- Look for mandatory option
  1636. if ($v_requested_options[$key] == 'mandatory') {
  1637. // ----- Look if present
  1638. if (!isset($p_file_list[$key])) {
  1639. PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Missing mandatory parameter ".PclZipUtilOptionText($key)."(".$key.")");
  1640. return PclZip::errorCode();
  1641. }
  1642. }
  1643. }
  1644. }
  1645. }
  1646. // ----- Return
  1647. return $v_result;
  1648. }
  1649. // --------------------------------------------------------------------------------
  1650. // --------------------------------------------------------------------------------
  1651. // Function : privFileDescrExpand()
  1652. // Description :
  1653. // This method look for each item of the list to see if its a file, a folder
  1654. // or a string to be added as file. For any other type of files (link, other)
  1655. // just ignore the item.
  1656. // Then prepare the information that will be stored for that file.
  1657. // When its a folder, expand the folder with all the files that are in that
  1658. // folder (recursively).
  1659. // Parameters :
  1660. // Return Values :
  1661. // 1 on success.
  1662. // 0 on failure.
  1663. // --------------------------------------------------------------------------------
  1664. public function privFileDescrExpand(&$p_filedescr_list, &$p_options)
  1665. {
  1666. $v_result=1;
  1667. // ----- Create a result list
  1668. $v_result_list = array();
  1669. // ----- Look each entry
  1670. for ($i=0; $i<sizeof($p_filedescr_list); $i++) {
  1671. // ----- Get filedescr
  1672. $v_descr = $p_filedescr_list[$i];
  1673. // ----- Reduce the filename
  1674. $v_descr['filename'] = PclZipUtilTranslateWinPath($v_descr['filename'], false);
  1675. $v_descr['filename'] = PclZipUtilPathReduction($v_descr['filename']);
  1676. // ----- Look for real file or folder
  1677. if (file_exists($v_descr['filename'])) {
  1678. if (@is_file($v_descr['filename'])) {
  1679. $v_descr['type'] = 'file';
  1680. } elseif (@is_dir($v_descr['filename'])) {
  1681. $v_descr['type'] = 'folder';
  1682. } elseif (@is_link($v_descr['filename'])) {
  1683. // skip
  1684. continue;
  1685. } else {
  1686. // skip
  1687. continue;
  1688. }
  1689. } elseif (isset($v_descr['content'])) {
  1690. // ----- Look for string added as file
  1691. $v_descr['type'] = 'virtual_file';
  1692. } else {
  1693. // ----- Missing file
  1694. // ----- Error log
  1695. PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "File '".$v_descr['filename']."' does not exist");
  1696. // ----- Return
  1697. return PclZip::errorCode();
  1698. }
  1699. // ----- Calculate the stored filename
  1700. $this->privCalculateStoredFilename($v_descr, $p_options);
  1701. // ----- Add the descriptor in result list
  1702. $v_result_list[sizeof($v_result_list)] = $v_descr;
  1703. // ----- Look for folder
  1704. if ($v_descr['type'] == 'folder') {
  1705. // ----- List of items in folder
  1706. $v_dirlist_descr = array();
  1707. $v_dirlist_nb = 0;
  1708. if ($v_folder_handler = @opendir($v_descr['filename'])) {
  1709. while (($v_item_handler = @readdir($v_folder_handler)) !== false) {
  1710. // ----- Skip '.' and '..'
  1711. if (($v_item_handler == '.') || ($v_item_handler == '..')) {
  1712. continue;
  1713. }
  1714. // ----- Compose the full filename
  1715. $v_dirlist_descr[$v_dirlist_nb]['filename'] = $v_descr['filename'].'/'.$v_item_handler;
  1716. // ----- Look for different stored filename
  1717. // Because the name of the folder was changed, the name of the
  1718. // files/sub-folders also change
  1719. if (($v_descr['stored_filename'] != $v_descr['filename'])
  1720. && (!isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH]))) {
  1721. if ($v_descr['stored_filename'] != '') {
  1722. $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_descr['stored_filename'].'/'.$v_item_handler;
  1723. } else {
  1724. $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_item_handler;
  1725. }
  1726. }
  1727. $v_dirlist_nb++;
  1728. }
  1729. @closedir($v_folder_handler);
  1730. } else {
  1731. // TBC : unable to open folder in read mode
  1732. }
  1733. // ----- Expand each element of the list
  1734. if ($v_dirlist_nb != 0) {
  1735. // ----- Expand
  1736. if (($v_result = $this->privFileDescrExpand($v_dirlist_descr, $p_options)) != 1) {
  1737. return $v_result;
  1738. }
  1739. // ----- Concat the resulting list
  1740. $v_result_list = array_merge($v_result_list, $v_dirlist_descr);
  1741. }
  1742. // ----- Free local array
  1743. unset($v_dirlist_descr);
  1744. }
  1745. }
  1746. // ----- Get the result list
  1747. $p_filedescr_list = $v_result_list;
  1748. // ----- Return
  1749. return $v_result;
  1750. }
  1751. // --------------------------------------------------------------------------------
  1752. // --------------------------------------------------------------------------------
  1753. // Function : privCreate()
  1754. // Description :
  1755. // Parameters :
  1756. // Return Values :
  1757. // --------------------------------------------------------------------------------
  1758. public function privCreate($p_filedescr_list, &$p_result_list, &$p_options)
  1759. {
  1760. $v_result=1;
  1761. $v_list_detail = array();
  1762. // ----- Magic quotes trick
  1763. $this->privDisableMagicQuotes();
  1764. // ----- Open the file in write mode
  1765. if (($v_result = $this->privOpenFd('wb')) != 1) {
  1766. // ----- Return
  1767. return $v_result;
  1768. }
  1769. // ----- Add the list of files
  1770. $v_result = $this->privAddList($p_filedescr_list, $p_result_list, $p_options);
  1771. // ----- Close
  1772. $this->privCloseFd();
  1773. // ----- Magic quotes trick
  1774. $this->privSwapBackMagicQuotes();
  1775. // ----- Return
  1776. return $v_result;
  1777. }
  1778. // --------------------------------------------------------------------------------
  1779. // --------------------------------------------------------------------------------
  1780. // Function : privAdd()
  1781. // Description :
  1782. // Parameters :
  1783. // Return Values :
  1784. // --------------------------------------------------------------------------------
  1785. public function privAdd($p_filedescr_list, &$p_result_list, &$p_options)
  1786. {
  1787. $v_result=1;
  1788. $v_list_detail = array();
  1789. // ----- Look if the archive exists or is empty
  1790. if ((!is_file($this->zipname)) || (filesize($this->zipname) == 0)) {
  1791. // ----- Do a create
  1792. $v_result = $this->privCreate($p_filedescr_list, $p_result_list, $p_options);
  1793. // ----- Return
  1794. return $v_result;
  1795. }
  1796. // ----- Magic quotes trick
  1797. $this->privDisableMagicQuotes();
  1798. // ----- Open the zip file
  1799. if (($v_result=$this->privOpenFd('rb')) != 1) {
  1800. // ----- Magic quotes trick
  1801. $this->privSwapBackMagicQuotes();
  1802. // ----- Return
  1803. return $v_result;
  1804. }
  1805. // ----- Read the central directory informations
  1806. $v_central_dir = array();
  1807. if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) {
  1808. $this->privCloseFd();
  1809. $this->privSwapBackMagicQuotes();
  1810. return $v_result;
  1811. }
  1812. // ----- Go to beginning of File
  1813. @rewind($this->zip_fd);
  1814. // ----- Creates a temporay file
  1815. $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp';
  1816. // ----- Open the temporary file in write mode
  1817. if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0) {
  1818. $this->privCloseFd();
  1819. $this->privSwapBackMagicQuotes();
  1820. PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_zip_temp_name.'\' in binary write mode');
  1821. // ----- Return
  1822. return PclZip::errorCode();
  1823. }
  1824. // ----- Copy the files from the archive to the temporary file
  1825. // TBC : Here I should better append the file and go back to erase the central dir
  1826. $v_size = $v_central_dir['offset'];
  1827. while ($v_size != 0) {
  1828. $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
  1829. $v_buffer = fread($this->zip_fd, $v_read_size);
  1830. @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
  1831. $v_size -= $v_read_size;
  1832. }
  1833. // ----- Swap the file descriptor
  1834. // Here is a trick : I swap the temporary fd with the zip fd, in order to use
  1835. // the following methods on the temporary fil and not the real archive
  1836. $v_swap = $this->zip_fd;
  1837. $this->zip_fd = $v_zip_temp_fd;
  1838. $v_zip_temp_fd = $v_swap;
  1839. // ----- Add the files
  1840. $v_header_list = array();
  1841. if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1) {
  1842. fclose($v_zip_temp_fd);
  1843. $this->privCloseFd();
  1844. @unlink($v_zip_temp_name);
  1845. $this->privSwapBackMagicQuotes();
  1846. // ----- Return
  1847. return $v_result;
  1848. }
  1849. // ----- Store the offset of the central dir
  1850. $v_offset = @ftell($this->zip_fd);
  1851. // ----- Copy the block of file headers from the old archive
  1852. $v_size = $v_central_dir['size'];
  1853. while ($v_size != 0) {
  1854. $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
  1855. $v_buffer = @fread($v_zip_temp_fd, $v_read_size);
  1856. @fwrite($this->zip_fd, $v_buffer, $v_read_size);
  1857. $v_size -= $v_read_size;
  1858. }
  1859. // ----- Create the Central Dir files header
  1860. for ($i=0, $v_count=0; $i<sizeof($v_header_list); $i++) {
  1861. // ----- Create the file header
  1862. if ($v_header_list[$i]['status'] == 'ok') {
  1863. if (($v_result = $this->privWriteCentralFileHeader($v_header_list[$i])) != 1) {
  1864. fclose($v_zip_temp_fd);
  1865. $this->privCloseFd();
  1866. @unlink($v_zip_temp_name);
  1867. $this->privSwapBackMagicQuotes();
  1868. // ----- Return
  1869. return $v_result;
  1870. }
  1871. $v_count++;
  1872. }
  1873. // ----- Transform the header to a 'usable' info
  1874. $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]);
  1875. }
  1876. // ----- Zip file comment
  1877. $v_comment = $v_central_dir['comment'];
  1878. if (isset($p_options[PCLZIP_OPT_COMMENT])) {
  1879. $v_comment = $p_options[PCLZIP_OPT_COMMENT];
  1880. }
  1881. if (isset($p_options[PCLZIP_OPT_ADD_COMMENT])) {
  1882. $v_comment = $v_comment.$p_options[PCLZIP_OPT_ADD_COMMENT];
  1883. }
  1884. if (isset($p_options[PCLZIP_OPT_PREPEND_COMMENT])) {
  1885. $v_comment = $p_options[PCLZIP_OPT_PREPEND_COMMENT].$v_comment;
  1886. }
  1887. // ----- Calculate the size of the central header
  1888. $v_size = @ftell($this->zip_fd)-$v_offset;
  1889. // ----- Create the central dir footer
  1890. if (($v_result = $this->privWriteCentralHeader($v_count+$v_central_dir['entries'], $v_size, $v_offset, $v_comment)) != 1) {
  1891. // ----- Reset the file list
  1892. unset($v_header_list);
  1893. $this->privSwapBackMagicQuotes();
  1894. // ----- Return
  1895. return $v_result;
  1896. }
  1897. // ----- Swap back the file descriptor
  1898. $v_swap = $this->zip_fd;
  1899. $this->zip_fd = $v_zip_temp_fd;
  1900. $v_zip_temp_fd = $v_swap;
  1901. // ----- Close
  1902. $this->privCloseFd();
  1903. // ----- Close the temporary file
  1904. @fclose($v_zip_temp_fd);
  1905. // ----- Magic quotes trick
  1906. $this->privSwapBackMagicQuotes();
  1907. // ----- Delete the zip file
  1908. // TBC : I should test the result ...
  1909. @unlink($this->zipname);
  1910. // ----- Rename the temporary file
  1911. // TBC : I should test the result ...
  1912. //@rename($v_zip_temp_name, $this->zipname);
  1913. PclZipUtilRename($v_zip_temp_name, $this->zipname);
  1914. // ----- Return
  1915. return $v_result;
  1916. }
  1917. // --------------------------------------------------------------------------------
  1918. // --------------------------------------------------------------------------------
  1919. // Function : privOpenFd()
  1920. // Description :
  1921. // Parameters :
  1922. // --------------------------------------------------------------------------------
  1923. public function privOpenFd($p_mode)
  1924. {
  1925. $v_result=1;
  1926. // ----- Look if already open
  1927. if ($this->zip_fd != 0) {
  1928. // ----- Error log
  1929. PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Zip file \''.$this->zipname.'\' already open');
  1930. // ----- Return
  1931. return PclZip::errorCode();
  1932. }
  1933. // ----- Open the zip file
  1934. if (($this->zip_fd = @fopen($this->zipname, $p_mode)) == 0) {
  1935. // ----- Error log
  1936. PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in '.$p_mode.' mode');
  1937. // ----- Return
  1938. return PclZip::errorCode();
  1939. }
  1940. // ----- Return
  1941. return $v_result;
  1942. }
  1943. // --------------------------------------------------------------------------------
  1944. // --------------------------------------------------------------------------------
  1945. // Function : privCloseFd()
  1946. // Description :
  1947. // Parameters :
  1948. // --------------------------------------------------------------------------------
  1949. public function privCloseFd()
  1950. {
  1951. $v_result=1;
  1952. if ($this->zip_fd != 0) {
  1953. @fclose($this->zip_fd);
  1954. }
  1955. $this->zip_fd = 0;
  1956. // ----- Return
  1957. return $v_result;
  1958. }
  1959. // --------------------------------------------------------------------------------
  1960. // --------------------------------------------------------------------------------
  1961. // Function : privAddList()
  1962. // Description :
  1963. // $p_add_dir and $p_remove_dir will give the ability to memorize a path which is
  1964. // different from the real path of the file. This is usefull if you want to have PclTar
  1965. // running in any directory, and memorize relative path from an other directory.
  1966. // Parameters :
  1967. // $p_list : An array containing the file or directory names to add in the tar
  1968. // $p_result_list : list of added files with their properties (specially the status field)
  1969. // $p_add_dir : Path to add in the filename path archived
  1970. // $p_remove_dir : Path to remove in the filename path archived
  1971. // Return Values :
  1972. // --------------------------------------------------------------------------------
  1973. // public function privAddList($p_list, &$p_result_list, $p_add_dir, $p_remove_dir, $p_remove_all_dir, &$p_options)
  1974. public function privAddList($p_filedescr_list, &$p_result_list, &$p_options)
  1975. {
  1976. $v_result=1;
  1977. // ----- Add the files
  1978. $v_header_list = array();
  1979. if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1) {
  1980. // ----- Return
  1981. return $v_result;
  1982. }
  1983. // ----- Store the offset of the central dir
  1984. $v_offset = @ftell($this->zip_fd);
  1985. // ----- Create the Central Dir files header
  1986. for ($i=0, $v_count=0; $i<sizeof($v_header_list); $i++) {
  1987. // ----- Create the file header
  1988. if ($v_header_list[$i]['status'] == 'ok') {
  1989. if (($v_result = $this->privWriteCentralFileHeader($v_header_list[$i])) != 1) {
  1990. // ----- Return
  1991. return $v_result;
  1992. }
  1993. $v_count++;
  1994. }
  1995. // ----- Transform the header to a 'usable' info
  1996. $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]);
  1997. }
  1998. // ----- Zip file comment
  1999. $v_comment = '';
  2000. if (isset($p_options[PCLZIP_OPT_COMMENT])) {
  2001. $v_comment = $p_options[PCLZIP_OPT_COMMENT];
  2002. }
  2003. // ----- Calculate the size of the central header
  2004. $v_size = @ftell($this->zip_fd)-$v_offset;
  2005. // ----- Create the central dir footer
  2006. if (($v_result = $this->privWriteCentralHeader($v_count, $v_size, $v_offset, $v_comment)) != 1) {
  2007. // ----- Reset the file list
  2008. unset($v_header_list);
  2009. // ----- Return
  2010. return $v_result;
  2011. }
  2012. // ----- Return
  2013. return $v_result;
  2014. }
  2015. // --------------------------------------------------------------------------------
  2016. // --------------------------------------------------------------------------------
  2017. // Function : privAddFileList()
  2018. // Description :
  2019. // Parameters :
  2020. // $p_filedescr_list : An array containing the file description
  2021. // or directory names to add in the zip
  2022. // $p_result_list : list of added files with their properties (specially the status field)
  2023. // Return Values :
  2024. // --------------------------------------------------------------------------------
  2025. public function privAddFileList($p_filedescr_list, &$p_result_list, &$p_options)
  2026. {
  2027. $v_result=1;
  2028. $v_header = array();
  2029. // ----- Recuperate the current number of elt in list
  2030. $v_nb = sizeof($p_result_list);
  2031. // ----- Loop on the files
  2032. for ($j=0; ($j<sizeof($p_filedescr_list)) && ($v_result==1); $j++) {
  2033. // ----- Format the filename
  2034. $p_filedescr_list[$j]['filename'] = PclZipUtilTranslateWinPath($p_filedescr_list[$j]['filename'], false);
  2035. // ----- Skip empty file names
  2036. // TBC : Can this be possible ? not checked in DescrParseAtt ?
  2037. if ($p_filedescr_list[$j]['filename'] == "") {
  2038. continue;
  2039. }
  2040. // ----- Check the filename
  2041. if (($p_filedescr_list[$j]['type'] != 'virtual_file') && (!file_exists($p_filedescr_list[$j]['filename']))) {
  2042. PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "File '".$p_filedescr_list[$j]['filename']."' does not exist");
  2043. return PclZip::errorCode();
  2044. }
  2045. // ----- Look if it is a file or a dir with no all path remove option
  2046. // or a dir with all its path removed
  2047. // if ( (is_file($p_filedescr_list[$j]['filename']))
  2048. // || ( is_dir($p_filedescr_list[$j]['filename'])
  2049. if (($p_filedescr_list[$j]['type'] == 'file') || ($p_filedescr_list[$j]['type'] == 'virtual_file') || (($p_filedescr_list[$j]['type'] == 'folder') && (!isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH]) || !$p_options[PCLZIP_OPT_REMOVE_ALL_PATH]))) {
  2050. // ----- Add the file
  2051. $v_result = $this->privAddFile($p_filedescr_list[$j], $v_header, $p_options);
  2052. if ($v_result != 1) {
  2053. return $v_result;
  2054. }
  2055. // ----- Store the file infos
  2056. $p_result_list[$v_nb++] = $v_header;
  2057. }
  2058. }
  2059. // ----- Return
  2060. return $v_result;
  2061. }
  2062. // --------------------------------------------------------------------------------
  2063. // --------------------------------------------------------------------------------
  2064. // Function : privAddFile()
  2065. // Description :
  2066. // Parameters :
  2067. // Return Values :
  2068. // --------------------------------------------------------------------------------
  2069. public function privAddFile($p_filedescr, &$p_header, &$p_options)
  2070. {
  2071. $v_result=1;
  2072. // ----- Working variable
  2073. $p_filename = $p_filedescr['filename'];
  2074. // TBC : Already done in the fileAtt check ... ?
  2075. if ($p_filename == "") {
  2076. // ----- Error log
  2077. PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file list parameter (invalid or empty list)");
  2078. // ----- Return
  2079. return PclZip::errorCode();
  2080. }
  2081. // ----- Look for a stored different filename
  2082. /* TBC : Removed
  2083. if (isset($p_filedescr['stored_filename'])) {
  2084. $v_stored_filename = $p_filedescr['stored_filename'];
  2085. }
  2086. else {
  2087. $v_stored_filename = $p_filedescr['stored_filename'];
  2088. }
  2089. */
  2090. // ----- Set the file properties
  2091. clearstatcache();
  2092. $p_header['version'] = 20;
  2093. $p_header['version_extracted'] = 10;
  2094. $p_header['flag'] = 0;
  2095. $p_header['compression'] = 0;
  2096. $p_header['crc'] = 0;
  2097. $p_header['compressed_size'] = 0;
  2098. $p_header['filename_len'] = strlen($p_filename);
  2099. $p_header['extra_len'] = 0;
  2100. $p_header['disk'] = 0;
  2101. $p_header['internal'] = 0;
  2102. $p_header['offset'] = 0;
  2103. $p_header['filename'] = $p_filename;
  2104. // TBC : Removed $p_header['stored_filename'] = $v_stored_filename;
  2105. $p_header['stored_filename'] = $p_filedescr['stored_filename'];
  2106. $p_header['extra'] = '';
  2107. $p_header['status'] = 'ok';
  2108. $p_header['index'] = -1;
  2109. // ----- Look for regular file
  2110. if ($p_filedescr['type']=='file') {
  2111. $p_header['external'] = 0x00000000;
  2112. $p_header['size'] = filesize($p_filename);
  2113. } elseif ($p_filedescr['type']=='folder') {
  2114. // ----- Look for regular folder
  2115. $p_header['external'] = 0x00000010;
  2116. $p_header['mtime'] = filemtime($p_filename);
  2117. $p_header['size'] = filesize($p_filename);
  2118. } elseif ($p_filedescr['type'] == 'virtual_file') {
  2119. // ----- Look for virtual file
  2120. $p_header['external'] = 0x00000000;
  2121. $p_header['size'] = strlen($p_filedescr['content']);
  2122. }
  2123. // ----- Look for filetime
  2124. if (isset($p_filedescr['mtime'])) {
  2125. $p_header['mtime'] = $p_filedescr['mtime'];
  2126. } elseif ($p_filedescr['type'] == 'virtual_file') {
  2127. $p_header['mtime'] = time();
  2128. } else {
  2129. $p_header['mtime'] = filemtime($p_filename);
  2130. }
  2131. // ------ Look for file comment
  2132. if (isset($p_filedescr['comment'])) {
  2133. $p_header['comment_len'] = strlen($p_filedescr['comment']);
  2134. $p_header['comment'] = $p_filedescr['comment'];
  2135. } else {
  2136. $p_header['comment_len'] = 0;
  2137. $p_header['comment'] = '';
  2138. }
  2139. // ----- Look for pre-add callback
  2140. if (isset($p_options[PCLZIP_CB_PRE_ADD])) {
  2141. // ----- Generate a local information
  2142. $v_local_header = array();
  2143. $this->privConvertHeader2FileInfo($p_header, $v_local_header);
  2144. // ----- Call the callback
  2145. // Here I do not use call_user_func() because I need to send a reference to the
  2146. // header.
  2147. // eval('$v_result = '.$p_options[PCLZIP_CB_PRE_ADD].'(PCLZIP_CB_PRE_ADD, $v_local_header);');
  2148. $v_result = $p_options[PCLZIP_CB_PRE_ADD](PCLZIP_CB_PRE_ADD, $v_local_header);
  2149. if ($v_result == 0) {
  2150. // ----- Change the file status
  2151. $p_header['status'] = "skipped";
  2152. $v_result = 1;
  2153. }
  2154. // ----- Update the informations
  2155. // Only some fields can be modified
  2156. if ($p_header['stored_filename'] != $v_local_header['stored_filename']) {
  2157. $p_header['stored_filename'] = PclZipUtilPathReduction($v_local_header['stored_filename']);
  2158. }
  2159. }
  2160. // ----- Look for empty stored filename
  2161. if ($p_header['stored_filename'] == "") {
  2162. $p_header['status'] = "filtered";
  2163. }
  2164. // ----- Check the path length
  2165. if (strlen($p_header['stored_filename']) > 0xFF) {
  2166. $p_header['status'] = 'filename_too_long';
  2167. }
  2168. // ----- Look if no error, or file not skipped
  2169. if ($p_header['status'] == 'ok') {
  2170. // ----- Look for a file
  2171. if ($p_filedescr['type'] == 'file') {
  2172. // ----- Look for using temporary file to zip
  2173. if ((!isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) && (isset($p_options[PCLZIP_OPT_TEMP_FILE_ON]) || (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]) && ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] <= $p_header['size'])))) {
  2174. $v_result = $this->privAddFileUsingTempFile($p_filedescr, $p_header, $p_options);
  2175. if ($v_result < PCLZIP_ERR_NO_ERROR) {
  2176. return $v_result;
  2177. }
  2178. } else {
  2179. // ----- Use "in memory" zip algo
  2180. // ----- Open the source file
  2181. if (($v_file = @fopen($p_filename, "rb")) == 0) {
  2182. PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode");
  2183. return PclZip::errorCode();
  2184. }
  2185. // ----- Read the file content
  2186. $v_content = @fread($v_file, $p_header['size']);
  2187. // ----- Close the file
  2188. @fclose($v_file);
  2189. // ----- Calculate the CRC
  2190. $p_header['crc'] = @crc32($v_content);
  2191. // ----- Look for no compression
  2192. if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) {
  2193. // ----- Set header parameters
  2194. $p_header['compressed_size'] = $p_header['size'];
  2195. $p_header['compression'] = 0;
  2196. } else {
  2197. // ----- Look for normal compression
  2198. // ----- Compress the content
  2199. $v_content = @gzdeflate($v_content);
  2200. // ----- Set header parameters
  2201. $p_header['compressed_size'] = strlen($v_content);
  2202. $p_header['compression'] = 8;
  2203. }
  2204. // ----- Call the header generation
  2205. if (($v_result = $this->privWriteFileHeader($p_header)) != 1) {
  2206. @fclose($v_file);
  2207. return $v_result;
  2208. }
  2209. // ----- Write the compressed (or not) content
  2210. @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']);
  2211. }
  2212. } elseif ($p_filedescr['type'] == 'virtual_file') {
  2213. // ----- Look for a virtual file (a file from string)
  2214. $v_content = $p_filedescr['content'];
  2215. // ----- Calculate the CRC
  2216. $p_header['crc'] = @crc32($v_content);
  2217. // ----- Look for no compression
  2218. if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) {
  2219. // ----- Set header parameters
  2220. $p_header['compressed_size'] = $p_header['size'];
  2221. $p_header['compression'] = 0;
  2222. } else {
  2223. // ----- Look for normal compression
  2224. // ----- Compress the content
  2225. $v_content = @gzdeflate($v_content);
  2226. // ----- Set header parameters
  2227. $p_header['compressed_size'] = strlen($v_content);
  2228. $p_header['compression'] = 8;
  2229. }
  2230. // ----- Call the header generation
  2231. if (($v_result = $this->privWriteFileHeader($p_header)) != 1) {
  2232. @fclose($v_file);
  2233. return $v_result;
  2234. }
  2235. // ----- Write the compressed (or not) content
  2236. @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']);
  2237. } elseif ($p_filedescr['type'] == 'folder') {
  2238. // ----- Look for a directory
  2239. // ----- Look for directory last '/'
  2240. if (@substr($p_header['stored_filename'], -1) != '/') {
  2241. $p_header['stored_filename'] .= '/';
  2242. }
  2243. // ----- Set the file properties
  2244. $p_header['size'] = 0;
  2245. //$p_header['external'] = 0x41FF0010; // Value for a folder : to be checked
  2246. $p_header['external'] = 0x00000010; // Value for a folder : to be checked
  2247. // ----- Call the header generation
  2248. if (($v_result = $this->privWriteFileHeader($p_header)) != 1) {
  2249. return $v_result;
  2250. }
  2251. }
  2252. }
  2253. // ----- Look for post-add callback
  2254. if (isset($p_options[PCLZIP_CB_POST_ADD])) {
  2255. // ----- Generate a local information
  2256. $v_local_header = array();
  2257. $this->privConvertHeader2FileInfo($p_header, $v_local_header);
  2258. // ----- Call the callback
  2259. // Here I do not use call_user_func() because I need to send a reference to the
  2260. // header.
  2261. // eval('$v_result = '.$p_options[PCLZIP_CB_POST_ADD].'(PCLZIP_CB_POST_ADD, $v_local_header);');
  2262. $v_result = $p_options[PCLZIP_CB_POST_ADD](PCLZIP_CB_POST_ADD, $v_local_header);
  2263. if ($v_result == 0) {
  2264. // ----- Ignored
  2265. $v_result = 1;
  2266. }
  2267. // ----- Update the informations
  2268. // Nothing can be modified
  2269. }
  2270. // ----- Return
  2271. return $v_result;
  2272. }
  2273. // --------------------------------------------------------------------------------
  2274. // --------------------------------------------------------------------------------
  2275. // Function : privAddFileUsingTempFile()
  2276. // Description :
  2277. // Parameters :
  2278. // Return Values :
  2279. // --------------------------------------------------------------------------------
  2280. public function privAddFileUsingTempFile($p_filedescr, &$p_header, &$p_options)
  2281. {
  2282. $v_result=PCLZIP_ERR_NO_ERROR;
  2283. // ----- Working variable
  2284. $p_filename = $p_filedescr['filename'];
  2285. // ----- Open the source file
  2286. if (($v_file = @fopen($p_filename, "rb")) == 0) {
  2287. PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode");
  2288. return PclZip::errorCode();
  2289. }
  2290. // ----- Creates a compressed temporary file
  2291. $v_gzip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.gz';
  2292. if (($v_file_compressed = @gzopen($v_gzip_temp_name, "wb")) == 0) {
  2293. fclose($v_file);
  2294. PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary write mode');
  2295. return PclZip::errorCode();
  2296. }
  2297. // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
  2298. $v_size = filesize($p_filename);
  2299. while ($v_size != 0) {
  2300. $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
  2301. $v_buffer = @fread($v_file, $v_read_size);
  2302. //$v_binary_data = pack('a'.$v_read_size, $v_buffer);
  2303. @gzputs($v_file_compressed, $v_buffer, $v_read_size);
  2304. $v_size -= $v_read_size;
  2305. }
  2306. // ----- Close the file
  2307. @fclose($v_file);
  2308. @gzclose($v_file_compressed);
  2309. // ----- Check the minimum file size
  2310. if (filesize($v_gzip_temp_name) < 18) {
  2311. PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'gzip temporary file \''.$v_gzip_temp_name.'\' has invalid filesize - should be minimum 18 bytes');
  2312. return PclZip::errorCode();
  2313. }
  2314. // ----- Extract the compressed attributes
  2315. if (($v_file_compressed = @fopen($v_gzip_temp_name, "rb")) == 0) {
  2316. PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode');
  2317. return PclZip::errorCode();
  2318. }
  2319. // ----- Read the gzip file header
  2320. $v_binary_data = @fread($v_file_compressed, 10);
  2321. $v_data_header = unpack('a1id1/a1id2/a1cm/a1flag/Vmtime/a1xfl/a1os', $v_binary_data);
  2322. // ----- Check some parameters
  2323. $v_data_header['os'] = bin2hex($v_data_header['os']);
  2324. // ----- Read the gzip file footer
  2325. @fseek($v_file_compressed, filesize($v_gzip_temp_name)-8);
  2326. $v_binary_data = @fread($v_file_compressed, 8);
  2327. $v_data_footer = unpack('Vcrc/Vcompressed_size', $v_binary_data);
  2328. // ----- Set the attributes
  2329. $p_header['compression'] = ord($v_data_header['cm']);
  2330. //$p_header['mtime'] = $v_data_header['mtime'];
  2331. $p_header['crc'] = $v_data_footer['crc'];
  2332. $p_header['compressed_size'] = filesize($v_gzip_temp_name)-18;
  2333. // ----- Close the file
  2334. @fclose($v_file_compressed);
  2335. // ----- Call the header generation
  2336. if (($v_result = $this->privWriteFileHeader($p_header)) != 1) {
  2337. return $v_result;
  2338. }
  2339. // ----- Add the compressed data
  2340. if (($v_file_compressed = @fopen($v_gzip_temp_name, "rb")) == 0) {
  2341. PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode');
  2342. return PclZip::errorCode();
  2343. }
  2344. // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
  2345. fseek($v_file_compressed, 10);
  2346. $v_size = $p_header['compressed_size'];
  2347. while ($v_size != 0) {
  2348. $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
  2349. $v_buffer = @fread($v_file_compressed, $v_read_size);
  2350. //$v_binary_data = pack('a'.$v_read_size, $v_buffer);
  2351. @fwrite($this->zip_fd, $v_buffer, $v_read_size);
  2352. $v_size -= $v_read_size;
  2353. }
  2354. // ----- Close the file
  2355. @fclose($v_file_compressed);
  2356. // ----- Unlink the temporary file
  2357. @unlink($v_gzip_temp_name);
  2358. // ----- Return
  2359. return $v_result;
  2360. }
  2361. // --------------------------------------------------------------------------------
  2362. // --------------------------------------------------------------------------------
  2363. // Function : privCalculateStoredFilename()
  2364. // Description :
  2365. // Based on file descriptor properties and global options, this method
  2366. // calculate the filename that will be stored in the archive.
  2367. // Parameters :
  2368. // Return Values :
  2369. // --------------------------------------------------------------------------------
  2370. public function privCalculateStoredFilename(&$p_filedescr, &$p_options)
  2371. {
  2372. $v_result=1;
  2373. // ----- Working variables
  2374. $p_filename = $p_filedescr['filename'];
  2375. if (isset($p_options[PCLZIP_OPT_ADD_PATH])) {
  2376. $p_add_dir = $p_options[PCLZIP_OPT_ADD_PATH];
  2377. } else {
  2378. $p_add_dir = '';
  2379. }
  2380. if (isset($p_options[PCLZIP_OPT_REMOVE_PATH])) {
  2381. $p_remove_dir = $p_options[PCLZIP_OPT_REMOVE_PATH];
  2382. } else {
  2383. $p_remove_dir = '';
  2384. }
  2385. if (isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH])) {
  2386. $p_remove_all_dir = $p_options[PCLZIP_OPT_REMOVE_ALL_PATH];
  2387. } else {
  2388. $p_remove_all_dir = 0;
  2389. }
  2390. // ----- Look for full name change
  2391. if (isset($p_filedescr['new_full_name'])) {
  2392. // ----- Remove drive letter if any
  2393. $v_stored_filename = PclZipUtilTranslateWinPath($p_filedescr['new_full_name']);
  2394. } else {
  2395. // ----- Look for path and/or short name change
  2396. // ----- Look for short name change
  2397. // Its when we cahnge just the filename but not the path
  2398. if (isset($p_filedescr['new_short_name'])) {
  2399. $v_path_info = pathinfo($p_filename);
  2400. $v_dir = '';
  2401. if ($v_path_info['dirname'] != '') {
  2402. $v_dir = $v_path_info['dirname'].'/';
  2403. }
  2404. $v_stored_filename = $v_dir.$p_filedescr['new_short_name'];
  2405. } else {
  2406. // ----- Calculate the stored filename
  2407. $v_stored_filename = $p_filename;
  2408. }
  2409. // ----- Look for all path to remove
  2410. if ($p_remove_all_dir) {
  2411. $v_stored_filename = basename($p_filename);
  2412. } elseif ($p_remove_dir != "") {
  2413. // ----- Look for partial path remove
  2414. if (substr($p_remove_dir, -1) != '/') {
  2415. $p_remove_dir .= "/";
  2416. }
  2417. if ((substr($p_filename, 0, 2) == "./") || (substr($p_remove_dir, 0, 2) == "./")) {
  2418. if ((substr($p_filename, 0, 2) == "./") && (substr($p_remove_dir, 0, 2) != "./")) {
  2419. $p_remove_dir = "./".$p_remove_dir;
  2420. }
  2421. if ((substr($p_filename, 0, 2) != "./") && (substr($p_remove_dir, 0, 2) == "./")) {
  2422. $p_remove_dir = substr($p_remove_dir, 2);
  2423. }
  2424. }
  2425. $v_compare = PclZipUtilPathInclusion($p_remove_dir, $v_stored_filename);
  2426. if ($v_compare > 0) {
  2427. if ($v_compare == 2) {
  2428. $v_stored_filename = "";
  2429. } else {
  2430. $v_stored_filename = substr($v_stored_filename, strlen($p_remove_dir));
  2431. }
  2432. }
  2433. }
  2434. // ----- Remove drive letter if any
  2435. $v_stored_filename = PclZipUtilTranslateWinPath($v_stored_filename);
  2436. // ----- Look for path to add
  2437. if ($p_add_dir != "") {
  2438. if (substr($p_add_dir, -1) == "/") {
  2439. $v_stored_filename = $p_add_dir.$v_stored_filename;
  2440. } else {
  2441. $v_stored_filename = $p_add_dir."/".$v_stored_filename;
  2442. }
  2443. }
  2444. }
  2445. // ----- Filename (reduce the path of stored name)
  2446. $v_stored_filename = PclZipUtilPathReduction($v_stored_filename);
  2447. $p_filedescr['stored_filename'] = $v_stored_filename;
  2448. // ----- Return
  2449. return $v_result;
  2450. }
  2451. // --------------------------------------------------------------------------------
  2452. // --------------------------------------------------------------------------------
  2453. // Function : privWriteFileHeader()
  2454. // Description :
  2455. // Parameters :
  2456. // Return Values :
  2457. // --------------------------------------------------------------------------------
  2458. public function privWriteFileHeader(&$p_header)
  2459. {
  2460. $v_result=1;
  2461. // ----- Store the offset position of the file
  2462. $p_header['offset'] = ftell($this->zip_fd);
  2463. // ----- Transform UNIX mtime to DOS format mdate/mtime
  2464. $v_date = getdate($p_header['mtime']);
  2465. $v_mtime = ($v_date['hours']<<11) + ($v_date['minutes']<<5) + $v_date['seconds']/2;
  2466. $v_mdate = (($v_date['year']-1980)<<9) + ($v_date['mon']<<5) + $v_date['mday'];
  2467. // ----- Packed data
  2468. $v_binary_data = pack("VvvvvvVVVvv", 0x04034b50, $p_header['version_extracted'], $p_header['flag'], $p_header['compression'], $v_mtime, $v_mdate, $p_header['crc'], $p_header['compressed_size'], $p_header['size'], strlen($p_header['stored_filename']), $p_header['extra_len']);
  2469. // ----- Write the first 148 bytes of the header in the archive
  2470. fputs($this->zip_fd, $v_binary_data, 30);
  2471. // ----- Write the variable fields
  2472. if (strlen($p_header['stored_filename']) != 0) {
  2473. fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename']));
  2474. }
  2475. if ($p_header['extra_len'] != 0) {
  2476. fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']);
  2477. }
  2478. // ----- Return
  2479. return $v_result;
  2480. }
  2481. // --------------------------------------------------------------------------------
  2482. // --------------------------------------------------------------------------------
  2483. // Function : privWriteCentralFileHeader()
  2484. // Description :
  2485. // Parameters :
  2486. // Return Values :
  2487. // --------------------------------------------------------------------------------
  2488. public function privWriteCentralFileHeader(&$p_header)
  2489. {
  2490. $v_result=1;
  2491. // TBC
  2492. //for(reset($p_header); $key = key($p_header); next($p_header)) {
  2493. //}
  2494. // ----- Transform UNIX mtime to DOS format mdate/mtime
  2495. $v_date = getdate($p_header['mtime']);
  2496. $v_mtime = ($v_date['hours']<<11) + ($v_date['minutes']<<5) + $v_date['seconds']/2;
  2497. $v_mdate = (($v_date['year']-1980)<<9) + ($v_date['mon']<<5) + $v_date['mday'];
  2498. // ----- Packed data
  2499. $v_binary_data = pack("VvvvvvvVVVvvvvvVV", 0x02014b50, $p_header['version'], $p_header['version_extracted'], $p_header['flag'], $p_header['compression'], $v_mtime, $v_mdate, $p_header['crc'], $p_header['compressed_size'], $p_header['size'], strlen($p_header['stored_filename']), $p_header['extra_len'], $p_header['comment_len'], $p_header['disk'], $p_header['internal'], $p_header['external'], $p_header['offset']);
  2500. // ----- Write the 42 bytes of the header in the zip file
  2501. fputs($this->zip_fd, $v_binary_data, 46);
  2502. // ----- Write the variable fields
  2503. if (strlen($p_header['stored_filename']) != 0) {
  2504. fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename']));
  2505. }
  2506. if ($p_header['extra_len'] != 0) {
  2507. fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']);
  2508. }
  2509. if ($p_header['comment_len'] != 0) {
  2510. fputs($this->zip_fd, $p_header['comment'], $p_header['comment_len']);
  2511. }
  2512. // ----- Return
  2513. return $v_result;
  2514. }
  2515. // --------------------------------------------------------------------------------
  2516. // --------------------------------------------------------------------------------
  2517. // Function : privWriteCentralHeader()
  2518. // Description :
  2519. // Parameters :
  2520. // Return Values :
  2521. // --------------------------------------------------------------------------------
  2522. public function privWriteCentralHeader($p_nb_entries, $p_size, $p_offset, $p_comment)
  2523. {
  2524. $v_result = 1;
  2525. // ----- Packed data
  2526. $v_binary_data = pack("VvvvvVVv", 0x06054b50, 0, 0, $p_nb_entries, $p_nb_entries, $p_size, $p_offset, strlen($p_comment));
  2527. // ----- Write the 22 bytes of the header in the zip file
  2528. fputs($this->zip_fd, $v_binary_data, 22);
  2529. // ----- Write the variable fields
  2530. if (strlen($p_comment) != 0) {
  2531. fputs($this->zip_fd, $p_comment, strlen($p_comment));
  2532. }
  2533. // ----- Return
  2534. return $v_result;
  2535. }
  2536. // --------------------------------------------------------------------------------
  2537. // --------------------------------------------------------------------------------
  2538. // Function : privList()
  2539. // Description :
  2540. // Parameters :
  2541. // Return Values :
  2542. // --------------------------------------------------------------------------------
  2543. public function privList(&$p_list)
  2544. {
  2545. $v_result = 1;
  2546. // ----- Magic quotes trick
  2547. $this->privDisableMagicQuotes();
  2548. // ----- Open the zip file
  2549. if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0) {
  2550. // ----- Magic quotes trick
  2551. $this->privSwapBackMagicQuotes();
  2552. // ----- Error log
  2553. PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in binary read mode');
  2554. // ----- Return
  2555. return PclZip::errorCode();
  2556. }
  2557. // ----- Read the central directory informations
  2558. $v_central_dir = array();
  2559. if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) {
  2560. $this->privSwapBackMagicQuotes();
  2561. return $v_result;
  2562. }
  2563. // ----- Go to beginning of Central Dir
  2564. @rewind($this->zip_fd);
  2565. if (@fseek($this->zip_fd, $v_central_dir['offset'])) {
  2566. $this->privSwapBackMagicQuotes();
  2567. // ----- Error log
  2568. PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
  2569. // ----- Return
  2570. return PclZip::errorCode();
  2571. }
  2572. // ----- Read each entry
  2573. for ($i=0; $i<$v_central_dir['entries']; $i++) {
  2574. // ----- Read the file header
  2575. if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1) {
  2576. $this->privSwapBackMagicQuotes();
  2577. return $v_result;
  2578. }
  2579. $v_header['index'] = $i;
  2580. // ----- Get the only interesting attributes
  2581. $this->privConvertHeader2FileInfo($v_header, $p_list[$i]);
  2582. unset($v_header);
  2583. }
  2584. // ----- Close the zip file
  2585. $this->privCloseFd();
  2586. // ----- Magic quotes trick
  2587. $this->privSwapBackMagicQuotes();
  2588. // ----- Return
  2589. return $v_result;
  2590. }
  2591. // --------------------------------------------------------------------------------
  2592. // --------------------------------------------------------------------------------
  2593. // Function : privConvertHeader2FileInfo()
  2594. // Description :
  2595. // This function takes the file informations from the central directory
  2596. // entries and extract the interesting parameters that will be given back.
  2597. // The resulting file infos are set in the array $p_info
  2598. // $p_info['filename'] : Filename with full path. Given by user (add),
  2599. // extracted in the filesystem (extract).
  2600. // $p_info['stored_filename'] : Stored filename in the archive.
  2601. // $p_info['size'] = Size of the file.
  2602. // $p_info['compressed_size'] = Compressed size of the file.
  2603. // $p_info['mtime'] = Last modification date of the file.
  2604. // $p_info['comment'] = Comment associated with the file.
  2605. // $p_info['folder'] = true/false : indicates if the entry is a folder or not.
  2606. // $p_info['status'] = status of the action on the file.
  2607. // $p_info['crc'] = CRC of the file content.
  2608. // Parameters :
  2609. // Return Values :
  2610. // --------------------------------------------------------------------------------
  2611. public function privConvertHeader2FileInfo($p_header, &$p_info)
  2612. {
  2613. $v_result=1;
  2614. // ----- Get the interesting attributes
  2615. $v_temp_path = PclZipUtilPathReduction($p_header['filename']);
  2616. $p_info['filename'] = $v_temp_path;
  2617. $v_temp_path = PclZipUtilPathReduction($p_header['stored_filename']);
  2618. $p_info['stored_filename'] = $v_temp_path;
  2619. $p_info['size'] = $p_header['size'];
  2620. $p_info['compressed_size'] = $p_header['compressed_size'];
  2621. $p_info['mtime'] = $p_header['mtime'];
  2622. $p_info['comment'] = $p_header['comment'];
  2623. $p_info['folder'] = (($p_header['external']&0x00000010)==0x00000010);
  2624. $p_info['index'] = $p_header['index'];
  2625. $p_info['status'] = $p_header['status'];
  2626. $p_info['crc'] = $p_header['crc'];
  2627. // ----- Return
  2628. return $v_result;
  2629. }
  2630. // --------------------------------------------------------------------------------
  2631. // --------------------------------------------------------------------------------
  2632. // Function : privExtractByRule()
  2633. // Description :
  2634. // Extract a file or directory depending of rules (by index, by name, ...)
  2635. // Parameters :
  2636. // $p_file_list : An array where will be placed the properties of each
  2637. // extracted file
  2638. // $p_path : Path to add while writing the extracted files
  2639. // $p_remove_path : Path to remove (from the file memorized path) while writing the
  2640. // extracted files. If the path does not match the file path,
  2641. // the file is extracted with its memorized path.
  2642. // $p_remove_path does not apply to 'list' mode.
  2643. // $p_path and $p_remove_path are commulative.
  2644. // Return Values :
  2645. // 1 on success,0 or less on error (see error code list)
  2646. // --------------------------------------------------------------------------------
  2647. public function privExtractByRule(&$p_file_list, $p_path, $p_remove_path, $p_remove_all_path, &$p_options)
  2648. {
  2649. $v_result=1;
  2650. // ----- Magic quotes trick
  2651. $this->privDisableMagicQuotes();
  2652. // ----- Check the path
  2653. if (($p_path == "") || ((substr($p_path, 0, 1) != "/") && (substr($p_path, 0, 3) != "../") && (substr($p_path, 1, 2)!=":/"))) {
  2654. $p_path = "./".$p_path;
  2655. }
  2656. // ----- Reduce the path last (and duplicated) '/'
  2657. if (($p_path != "./") && ($p_path != "/")) {
  2658. // ----- Look for the path end '/'
  2659. while (substr($p_path, -1) == "/") {
  2660. $p_path = substr($p_path, 0, strlen($p_path)-1);
  2661. }
  2662. }
  2663. // ----- Look for path to remove format (should end by /)
  2664. if (($p_remove_path != "") && (substr($p_remove_path, -1) != '/')) {
  2665. $p_remove_path .= '/';
  2666. }
  2667. $p_remove_path_size = strlen($p_remove_path);
  2668. // ----- Open the zip file
  2669. if (($v_result = $this->privOpenFd('rb')) != 1) {
  2670. $this->privSwapBackMagicQuotes();
  2671. return $v_result;
  2672. }
  2673. // ----- Read the central directory informations
  2674. $v_central_dir = array();
  2675. if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) {
  2676. // ----- Close the zip file
  2677. $this->privCloseFd();
  2678. $this->privSwapBackMagicQuotes();
  2679. return $v_result;
  2680. }
  2681. // ----- Start at beginning of Central Dir
  2682. $v_pos_entry = $v_central_dir['offset'];
  2683. // ----- Read each entry
  2684. $j_start = 0;
  2685. for ($i=0, $v_nb_extracted=0; $i<$v_central_dir['entries']; $i++) {
  2686. // ----- Read next Central dir entry
  2687. @rewind($this->zip_fd);
  2688. if (@fseek($this->zip_fd, $v_pos_entry)) {
  2689. // ----- Close the zip file
  2690. $this->privCloseFd();
  2691. $this->privSwapBackMagicQuotes();
  2692. // ----- Error log
  2693. PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
  2694. // ----- Return
  2695. return PclZip::errorCode();
  2696. }
  2697. // ----- Read the file header
  2698. $v_header = array();
  2699. if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1) {
  2700. // ----- Close the zip file
  2701. $this->privCloseFd();
  2702. $this->privSwapBackMagicQuotes();
  2703. return $v_result;
  2704. }
  2705. // ----- Store the index
  2706. $v_header['index'] = $i;
  2707. // ----- Store the file position
  2708. $v_pos_entry = ftell($this->zip_fd);
  2709. // ----- Look for the specific extract rules
  2710. $v_extract = false;
  2711. // ----- Look for extract by name rule
  2712. if ((isset($p_options[PCLZIP_OPT_BY_NAME])) && ($p_options[PCLZIP_OPT_BY_NAME] != 0)) {
  2713. // ----- Look if the filename is in the list
  2714. for ($j=0; ($j<sizeof($p_options[PCLZIP_OPT_BY_NAME])) && (!$v_extract); $j++) {
  2715. // ----- Look for a directory
  2716. if (substr($p_options[PCLZIP_OPT_BY_NAME][$j], -1) == "/") {
  2717. // ----- Look if the directory is in the filename path
  2718. if ((strlen($v_header['stored_filename']) > strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) && (substr($v_header['stored_filename'], 0, strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) == $p_options[PCLZIP_OPT_BY_NAME][$j])) {
  2719. $v_extract = true;
  2720. }
  2721. } elseif ($v_header['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) {
  2722. // ----- Look for a filename
  2723. $v_extract = true;
  2724. }
  2725. }
  2726. } elseif ((isset($p_options[PCLZIP_OPT_BY_PREG])) && ($p_options[PCLZIP_OPT_BY_PREG] != "")) {
  2727. // ----- Look for extract by preg rule
  2728. if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header['stored_filename'])) {
  2729. $v_extract = true;
  2730. }
  2731. } elseif ((isset($p_options[PCLZIP_OPT_BY_INDEX])) && ($p_options[PCLZIP_OPT_BY_INDEX] != 0)) {
  2732. // ----- Look for extract by index rule
  2733. // ----- Look if the index is in the list
  2734. for ($j=$j_start; ($j<sizeof($p_options[PCLZIP_OPT_BY_INDEX])) && (!$v_extract); $j++) {
  2735. if (($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i<=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) {
  2736. $v_extract = true;
  2737. }
  2738. if ($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) {
  2739. $j_start = $j+1;
  2740. }
  2741. if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start']>$i) {
  2742. break;
  2743. }
  2744. }
  2745. } else {
  2746. // ----- Look for no rule, which means extract all the archive
  2747. $v_extract = true;
  2748. }
  2749. // ----- Check compression method
  2750. if (($v_extract) && (($v_header['compression'] != 8) && ($v_header['compression'] != 0))) {
  2751. $v_header['status'] = 'unsupported_compression';
  2752. // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
  2753. if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) && ($p_options[PCLZIP_OPT_STOP_ON_ERROR] === true)) {
  2754. $this->privSwapBackMagicQuotes();
  2755. PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_COMPRESSION, "Filename '".$v_header['stored_filename']."' is compressed by an unsupported compression method (".$v_header['compression'].") ");
  2756. return PclZip::errorCode();
  2757. }
  2758. }
  2759. // ----- Check encrypted files
  2760. if (($v_extract) && (($v_header['flag'] & 1) == 1)) {
  2761. $v_header['status'] = 'unsupported_encryption';
  2762. // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
  2763. if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) && ($p_options[PCLZIP_OPT_STOP_ON_ERROR] === true)) {
  2764. $this->privSwapBackMagicQuotes();
  2765. PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION, "Unsupported encryption for filename '".$v_header['stored_filename']."'");
  2766. return PclZip::errorCode();
  2767. }
  2768. }
  2769. // ----- Look for real extraction
  2770. if (($v_extract) && ($v_header['status'] != 'ok')) {
  2771. $v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++]);
  2772. if ($v_result != 1) {
  2773. $this->privCloseFd();
  2774. $this->privSwapBackMagicQuotes();
  2775. return $v_result;
  2776. }
  2777. $v_extract = false;
  2778. }
  2779. // ----- Look for real extraction
  2780. if ($v_extract) {
  2781. // ----- Go to the file position
  2782. @rewind($this->zip_fd);
  2783. if (@fseek($this->zip_fd, $v_header['offset'])) {
  2784. // ----- Close the zip file
  2785. $this->privCloseFd();
  2786. $this->privSwapBackMagicQuotes();
  2787. // ----- Error log
  2788. PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
  2789. // ----- Return
  2790. return PclZip::errorCode();
  2791. }
  2792. // ----- Look for extraction as string
  2793. if ($p_options[PCLZIP_OPT_EXTRACT_AS_STRING]) {
  2794. $v_string = '';
  2795. // ----- Extracting the file
  2796. $v_result1 = $this->privExtractFileAsString($v_header, $v_string, $p_options);
  2797. if ($v_result1 < 1) {
  2798. $this->privCloseFd();
  2799. $this->privSwapBackMagicQuotes();
  2800. return $v_result1;
  2801. }
  2802. // ----- Get the only interesting attributes
  2803. if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted])) != 1) {
  2804. // ----- Close the zip file
  2805. $this->privCloseFd();
  2806. $this->privSwapBackMagicQuotes();
  2807. return $v_result;
  2808. }
  2809. // ----- Set the file content
  2810. $p_file_list[$v_nb_extracted]['content'] = $v_string;
  2811. // ----- Next extracted file
  2812. $v_nb_extracted++;
  2813. // ----- Look for user callback abort
  2814. if ($v_result1 == 2) {
  2815. break;
  2816. }
  2817. } elseif ((isset($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT])) && ($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT])) {
  2818. // ----- Look for extraction in standard output
  2819. // ----- Extracting the file in standard output
  2820. $v_result1 = $this->privExtractFileInOutput($v_header, $p_options);
  2821. if ($v_result1 < 1) {
  2822. $this->privCloseFd();
  2823. $this->privSwapBackMagicQuotes();
  2824. return $v_result1;
  2825. }
  2826. // ----- Get the only interesting attributes
  2827. if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) {
  2828. $this->privCloseFd();
  2829. $this->privSwapBackMagicQuotes();
  2830. return $v_result;
  2831. }
  2832. // ----- Look for user callback abort
  2833. if ($v_result1 == 2) {
  2834. break;
  2835. }
  2836. } else {
  2837. // ----- Look for normal extraction
  2838. // ----- Extracting the file
  2839. $v_result1 = $this->privExtractFile($v_header, $p_path, $p_remove_path, $p_remove_all_path, $p_options);
  2840. if ($v_result1 < 1) {
  2841. $this->privCloseFd();
  2842. $this->privSwapBackMagicQuotes();
  2843. return $v_result1;
  2844. }
  2845. // ----- Get the only interesting attributes
  2846. if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) {
  2847. // ----- Close the zip file
  2848. $this->privCloseFd();
  2849. $this->privSwapBackMagicQuotes();
  2850. return $v_result;
  2851. }
  2852. // ----- Look for user callback abort
  2853. if ($v_result1 == 2) {
  2854. break;
  2855. }
  2856. }
  2857. }
  2858. }
  2859. // ----- Close the zip file
  2860. $this->privCloseFd();
  2861. $this->privSwapBackMagicQuotes();
  2862. // ----- Return
  2863. return $v_result;
  2864. }
  2865. // --------------------------------------------------------------------------------
  2866. // --------------------------------------------------------------------------------
  2867. // Function : privExtractFile()
  2868. // Description :
  2869. // Parameters :
  2870. // Return Values :
  2871. //
  2872. // 1 : ... ?
  2873. // PCLZIP_ERR_USER_ABORTED(2) : User ask for extraction stop in callback
  2874. // --------------------------------------------------------------------------------
  2875. public function privExtractFile(&$p_entry, $p_path, $p_remove_path, $p_remove_all_path, &$p_options)
  2876. {
  2877. $v_result=1;
  2878. // ----- Read the file header
  2879. if (($v_result = $this->privReadFileHeader($v_header)) != 1) {
  2880. // ----- Return
  2881. return $v_result;
  2882. }
  2883. // ----- Check that the file header is coherent with $p_entry info
  2884. if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) {
  2885. // TBC
  2886. }
  2887. // ----- Look for all path to remove
  2888. if ($p_remove_all_path == true) {
  2889. // ----- Look for folder entry that not need to be extracted
  2890. if (($p_entry['external']&0x00000010)==0x00000010) {
  2891. $p_entry['status'] = "filtered";
  2892. return $v_result;
  2893. }
  2894. // ----- Get the basename of the path
  2895. $p_entry['filename'] = basename($p_entry['filename']);
  2896. } elseif ($p_remove_path != "") {
  2897. // ----- Look for path to remove
  2898. if (PclZipUtilPathInclusion($p_remove_path, $p_entry['filename']) == 2) {
  2899. // ----- Change the file status
  2900. $p_entry['status'] = "filtered";
  2901. // ----- Return
  2902. return $v_result;
  2903. }
  2904. $p_remove_path_size = strlen($p_remove_path);
  2905. if (substr($p_entry['filename'], 0, $p_remove_path_size) == $p_remove_path) {
  2906. // ----- Remove the path
  2907. $p_entry['filename'] = substr($p_entry['filename'], $p_remove_path_size);
  2908. }
  2909. }
  2910. // ----- Add the path
  2911. if ($p_path != '') {
  2912. $p_entry['filename'] = $p_path."/".$p_entry['filename'];
  2913. }
  2914. // ----- Check a base_dir_restriction
  2915. if (isset($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION])) {
  2916. $v_inclusion = PclZipUtilPathInclusion($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION], $p_entry['filename']);
  2917. if ($v_inclusion == 0) {
  2918. PclZip::privErrorLog(PCLZIP_ERR_DIRECTORY_RESTRICTION, "Filename '".$p_entry['filename']."' is outside PCLZIP_OPT_EXTRACT_DIR_RESTRICTION");
  2919. return PclZip::errorCode();
  2920. }
  2921. }
  2922. // ----- Look for pre-extract callback
  2923. if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) {
  2924. // ----- Generate a local information
  2925. $v_local_header = array();
  2926. $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
  2927. // ----- Call the callback
  2928. // Here I do not use call_user_func() because I need to send a reference to the
  2929. // header.
  2930. // eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);');
  2931. $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header);
  2932. if ($v_result == 0) {
  2933. // ----- Change the file status
  2934. $p_entry['status'] = "skipped";
  2935. $v_result = 1;
  2936. }
  2937. // ----- Look for abort result
  2938. if ($v_result == 2) {
  2939. // ----- This status is internal and will be changed in 'skipped'
  2940. $p_entry['status'] = "aborted";
  2941. $v_result = PCLZIP_ERR_USER_ABORTED;
  2942. }
  2943. // ----- Update the informations
  2944. // Only some fields can be modified
  2945. $p_entry['filename'] = $v_local_header['filename'];
  2946. }
  2947. // ----- Look if extraction should be done
  2948. if ($p_entry['status'] == 'ok') {
  2949. // ----- Look for specific actions while the file exist
  2950. if (file_exists($p_entry['filename'])) {
  2951. // ----- Look if file is a directory
  2952. if (is_dir($p_entry['filename'])) {
  2953. // ----- Change the file status
  2954. $p_entry['status'] = "already_a_directory";
  2955. // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
  2956. // For historical reason first PclZip implementation does not stop
  2957. // when this kind of error occurs.
  2958. if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) {
  2959. PclZip::privErrorLog(PCLZIP_ERR_ALREADY_A_DIRECTORY, "Filename '".$p_entry['filename']."' is already used by an existing directory");
  2960. return PclZip::errorCode();
  2961. }
  2962. } elseif (!is_writeable($p_entry['filename'])) {
  2963. // ----- Look if file is write protected
  2964. // ----- Change the file status
  2965. $p_entry['status'] = "write_protected";
  2966. // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
  2967. // For historical reason first PclZip implementation does not stop
  2968. // when this kind of error occurs.
  2969. if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) && ($p_options[PCLZIP_OPT_STOP_ON_ERROR] === true)) {
  2970. PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, "Filename '".$p_entry['filename']."' exists and is write protected");
  2971. return PclZip::errorCode();
  2972. }
  2973. } elseif (filemtime($p_entry['filename']) > $p_entry['mtime']) {
  2974. // ----- Look if the extracted file is older
  2975. // ----- Change the file status
  2976. if ((isset($p_options[PCLZIP_OPT_REPLACE_NEWER])) && ($p_options[PCLZIP_OPT_REPLACE_NEWER] === true)) {
  2977. } else {
  2978. $p_entry['status'] = "newer_exist";
  2979. // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
  2980. // For historical reason first PclZip implementation does not stop
  2981. // when this kind of error occurs.
  2982. if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) && ($p_options[PCLZIP_OPT_STOP_ON_ERROR] === true)) {
  2983. PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, "Newer version of '".$p_entry['filename']."' exists and option PCLZIP_OPT_REPLACE_NEWER is not selected");
  2984. return PclZip::errorCode();
  2985. }
  2986. }
  2987. } else {
  2988. }
  2989. } else {
  2990. // ----- Check the directory availability and create it if necessary
  2991. if ((($p_entry['external']&0x00000010)==0x00000010) || (substr($p_entry['filename'], -1) == '/')) {
  2992. $v_dir_to_check = $p_entry['filename'];
  2993. } elseif (!strstr($p_entry['filename'], "/")) {
  2994. $v_dir_to_check = "";
  2995. } else {
  2996. $v_dir_to_check = dirname($p_entry['filename']);
  2997. }
  2998. if (($v_result = $this->privDirCheck($v_dir_to_check, (($p_entry['external']&0x00000010)==0x00000010))) != 1) {
  2999. // ----- Change the file status
  3000. $p_entry['status'] = "path_creation_fail";
  3001. // ----- Return
  3002. //return $v_result;
  3003. $v_result = 1;
  3004. }
  3005. }
  3006. }
  3007. // ----- Look if extraction should be done
  3008. if ($p_entry['status'] == 'ok') {
  3009. // ----- Do the extraction (if not a folder)
  3010. if (!(($p_entry['external']&0x00000010) == 0x00000010)) {
  3011. // ----- Look for not compressed file
  3012. if ($p_entry['compression'] == 0) {
  3013. // ----- Opening destination file
  3014. if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) {
  3015. // ----- Change the file status
  3016. $p_entry['status'] = "write_error";
  3017. // ----- Return
  3018. return $v_result;
  3019. }
  3020. // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
  3021. $v_size = $p_entry['compressed_size'];
  3022. while ($v_size != 0) {
  3023. $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
  3024. $v_buffer = @fread($this->zip_fd, $v_read_size);
  3025. /* Try to speed up the code
  3026. $v_binary_data = pack('a'.$v_read_size, $v_buffer);
  3027. @fwrite($v_dest_file, $v_binary_data, $v_read_size);
  3028. */
  3029. @fwrite($v_dest_file, $v_buffer, $v_read_size);
  3030. $v_size -= $v_read_size;
  3031. }
  3032. // ----- Closing the destination file
  3033. fclose($v_dest_file);
  3034. // ----- Change the file mtime
  3035. touch($p_entry['filename'], $p_entry['mtime']);
  3036. } else {
  3037. // ----- TBC
  3038. // Need to be finished
  3039. if (($p_entry['flag'] & 1) == 1) {
  3040. PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION, 'File \''.$p_entry['filename'].'\' is encrypted. Encrypted files are not supported.');
  3041. return PclZip::errorCode();
  3042. }
  3043. // ----- Look for using temporary file to unzip
  3044. if ((!isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) && (isset($p_options[PCLZIP_OPT_TEMP_FILE_ON]) || (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]) && ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] <= $p_entry['size'])))) {
  3045. $v_result = $this->privExtractFileUsingTempFile($p_entry, $p_options);
  3046. if ($v_result < PCLZIP_ERR_NO_ERROR) {
  3047. return $v_result;
  3048. }
  3049. } else {
  3050. // ----- Look for extract in memory
  3051. // ----- Read the compressed file in a buffer (one shot)
  3052. $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']);
  3053. // ----- Decompress the file
  3054. $v_file_content = @gzinflate($v_buffer);
  3055. unset($v_buffer);
  3056. if ($v_file_content === false) {
  3057. // ----- Change the file status
  3058. // TBC
  3059. $p_entry['status'] = "error";
  3060. return $v_result;
  3061. }
  3062. // ----- Opening destination file
  3063. if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) {
  3064. // ----- Change the file status
  3065. $p_entry['status'] = "write_error";
  3066. return $v_result;
  3067. }
  3068. // ----- Write the uncompressed data
  3069. @fwrite($v_dest_file, $v_file_content, $p_entry['size']);
  3070. unset($v_file_content);
  3071. // ----- Closing the destination file
  3072. @fclose($v_dest_file);
  3073. }
  3074. // ----- Change the file mtime
  3075. @touch($p_entry['filename'], $p_entry['mtime']);
  3076. }
  3077. // ----- Look for chmod option
  3078. if (isset($p_options[PCLZIP_OPT_SET_CHMOD])) {
  3079. // ----- Change the mode of the file
  3080. @chmod($p_entry['filename'], $p_options[PCLZIP_OPT_SET_CHMOD]);
  3081. }
  3082. }
  3083. }
  3084. // ----- Change abort status
  3085. if ($p_entry['status'] == "aborted") {
  3086. $p_entry['status'] = "skipped";
  3087. } elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) {
  3088. // ----- Look for post-extract callback
  3089. // ----- Generate a local information
  3090. $v_local_header = array();
  3091. $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
  3092. // ----- Call the callback
  3093. // Here I do not use call_user_func() because I need to send a reference to the
  3094. // header.
  3095. // eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);');
  3096. $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header);
  3097. // ----- Look for abort result
  3098. if ($v_result == 2) {
  3099. $v_result = PCLZIP_ERR_USER_ABORTED;
  3100. }
  3101. }
  3102. // ----- Return
  3103. return $v_result;
  3104. }
  3105. // --------------------------------------------------------------------------------
  3106. // --------------------------------------------------------------------------------
  3107. // Function : privExtractFileUsingTempFile()
  3108. // Description :
  3109. // Parameters :
  3110. // Return Values :
  3111. // --------------------------------------------------------------------------------
  3112. public function privExtractFileUsingTempFile(&$p_entry, &$p_options)
  3113. {
  3114. $v_result=1;
  3115. // ----- Creates a temporary file
  3116. $v_gzip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.gz';
  3117. if (($v_dest_file = @fopen($v_gzip_temp_name, "wb")) == 0) {
  3118. fclose($v_file);
  3119. PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary write mode');
  3120. return PclZip::errorCode();
  3121. }
  3122. // ----- Write gz file format header
  3123. $v_binary_data = pack('va1a1Va1a1', 0x8b1f, Chr($p_entry['compression']), Chr(0x00), time(), Chr(0x00), Chr(3));
  3124. @fwrite($v_dest_file, $v_binary_data, 10);
  3125. // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
  3126. $v_size = $p_entry['compressed_size'];
  3127. while ($v_size != 0) {
  3128. $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
  3129. $v_buffer = @fread($this->zip_fd, $v_read_size);
  3130. //$v_binary_data = pack('a'.$v_read_size, $v_buffer);
  3131. @fwrite($v_dest_file, $v_buffer, $v_read_size);
  3132. $v_size -= $v_read_size;
  3133. }
  3134. // ----- Write gz file format footer
  3135. $v_binary_data = pack('VV', $p_entry['crc'], $p_entry['size']);
  3136. @fwrite($v_dest_file, $v_binary_data, 8);
  3137. // ----- Close the temporary file
  3138. @fclose($v_dest_file);
  3139. // ----- Opening destination file
  3140. if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) {
  3141. $p_entry['status'] = "write_error";
  3142. return $v_result;
  3143. }
  3144. // ----- Open the temporary gz file
  3145. if (($v_src_file = @gzopen($v_gzip_temp_name, 'rb')) == 0) {
  3146. @fclose($v_dest_file);
  3147. $p_entry['status'] = "read_error";
  3148. PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode');
  3149. return PclZip::errorCode();
  3150. }
  3151. // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
  3152. $v_size = $p_entry['size'];
  3153. while ($v_size != 0) {
  3154. $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
  3155. $v_buffer = @gzread($v_src_file, $v_read_size);
  3156. //$v_binary_data = pack('a'.$v_read_size, $v_buffer);
  3157. @fwrite($v_dest_file, $v_buffer, $v_read_size);
  3158. $v_size -= $v_read_size;
  3159. }
  3160. @fclose($v_dest_file);
  3161. @gzclose($v_src_file);
  3162. // ----- Delete the temporary file
  3163. @unlink($v_gzip_temp_name);
  3164. // ----- Return
  3165. return $v_result;
  3166. }
  3167. // --------------------------------------------------------------------------------
  3168. // --------------------------------------------------------------------------------
  3169. // Function : privExtractFileInOutput()
  3170. // Description :
  3171. // Parameters :
  3172. // Return Values :
  3173. // --------------------------------------------------------------------------------
  3174. public function privExtractFileInOutput(&$p_entry, &$p_options)
  3175. {
  3176. $v_result=1;
  3177. // ----- Read the file header
  3178. if (($v_result = $this->privReadFileHeader($v_header)) != 1) {
  3179. return $v_result;
  3180. }
  3181. // ----- Check that the file header is coherent with $p_entry info
  3182. if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) {
  3183. // TBC
  3184. }
  3185. // ----- Look for pre-extract callback
  3186. if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) {
  3187. // ----- Generate a local information
  3188. $v_local_header = array();
  3189. $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
  3190. // ----- Call the callback
  3191. // Here I do not use call_user_func() because I need to send a reference to the
  3192. // header.
  3193. // eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);');
  3194. $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header);
  3195. if ($v_result == 0) {
  3196. // ----- Change the file status
  3197. $p_entry['status'] = "skipped";
  3198. $v_result = 1;
  3199. }
  3200. // ----- Look for abort result
  3201. if ($v_result == 2) {
  3202. // ----- This status is internal and will be changed in 'skipped'
  3203. $p_entry['status'] = "aborted";
  3204. $v_result = PCLZIP_ERR_USER_ABORTED;
  3205. }
  3206. // ----- Update the informations
  3207. // Only some fields can be modified
  3208. $p_entry['filename'] = $v_local_header['filename'];
  3209. }
  3210. // ----- Trace
  3211. // ----- Look if extraction should be done
  3212. if ($p_entry['status'] == 'ok') {
  3213. // ----- Do the extraction (if not a folder)
  3214. if (!(($p_entry['external']&0x00000010)==0x00000010)) {
  3215. // ----- Look for not compressed file
  3216. if ($p_entry['compressed_size'] == $p_entry['size']) {
  3217. // ----- Read the file in a buffer (one shot)
  3218. $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']);
  3219. // ----- Send the file to the output
  3220. echo $v_buffer;
  3221. unset($v_buffer);
  3222. } else {
  3223. // ----- Read the compressed file in a buffer (one shot)
  3224. $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']);
  3225. // ----- Decompress the file
  3226. $v_file_content = gzinflate($v_buffer);
  3227. unset($v_buffer);
  3228. // ----- Send the file to the output
  3229. echo $v_file_content;
  3230. unset($v_file_content);
  3231. }
  3232. }
  3233. }
  3234. // ----- Change abort status
  3235. if ($p_entry['status'] == "aborted") {
  3236. $p_entry['status'] = "skipped";
  3237. } elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) {
  3238. // ----- Look for post-extract callback
  3239. // ----- Generate a local information
  3240. $v_local_header = array();
  3241. $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
  3242. // ----- Call the callback
  3243. // Here I do not use call_user_func() because I need to send a reference to the
  3244. // header.
  3245. // eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);');
  3246. $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header);
  3247. // ----- Look for abort result
  3248. if ($v_result == 2) {
  3249. $v_result = PCLZIP_ERR_USER_ABORTED;
  3250. }
  3251. }
  3252. return $v_result;
  3253. }
  3254. // --------------------------------------------------------------------------------
  3255. // --------------------------------------------------------------------------------
  3256. // Function : privExtractFileAsString()
  3257. // Description :
  3258. // Parameters :
  3259. // Return Values :
  3260. // --------------------------------------------------------------------------------
  3261. public function privExtractFileAsString(&$p_entry, &$p_string, &$p_options)
  3262. {
  3263. $v_result=1;
  3264. // ----- Read the file header
  3265. $v_header = array();
  3266. if (($v_result = $this->privReadFileHeader($v_header)) != 1) {
  3267. // ----- Return
  3268. return $v_result;
  3269. }
  3270. // ----- Check that the file header is coherent with $p_entry info
  3271. if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) {
  3272. // TBC
  3273. }
  3274. // ----- Look for pre-extract callback
  3275. if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) {
  3276. // ----- Generate a local information
  3277. $v_local_header = array();
  3278. $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
  3279. // ----- Call the callback
  3280. // Here I do not use call_user_func() because I need to send a reference to the
  3281. // header.
  3282. // eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);');
  3283. $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header);
  3284. if ($v_result == 0) {
  3285. // ----- Change the file status
  3286. $p_entry['status'] = "skipped";
  3287. $v_result = 1;
  3288. }
  3289. // ----- Look for abort result
  3290. if ($v_result == 2) {
  3291. // ----- This status is internal and will be changed in 'skipped'
  3292. $p_entry['status'] = "aborted";
  3293. $v_result = PCLZIP_ERR_USER_ABORTED;
  3294. }
  3295. // ----- Update the informations
  3296. // Only some fields can be modified
  3297. $p_entry['filename'] = $v_local_header['filename'];
  3298. }
  3299. // ----- Look if extraction should be done
  3300. if ($p_entry['status'] == 'ok') {
  3301. // ----- Do the extraction (if not a folder)
  3302. if (!(($p_entry['external']&0x00000010)==0x00000010)) {
  3303. // ----- Look for not compressed file
  3304. // if ($p_entry['compressed_size'] == $p_entry['size'])
  3305. if ($p_entry['compression'] == 0) {
  3306. // ----- Reading the file
  3307. $p_string = @fread($this->zip_fd, $p_entry['compressed_size']);
  3308. } else {
  3309. // ----- Reading the file
  3310. $v_data = @fread($this->zip_fd, $p_entry['compressed_size']);
  3311. // ----- Decompress the file
  3312. if (($p_string = @gzinflate($v_data)) === false) {
  3313. // TBC
  3314. }
  3315. }
  3316. // ----- Trace
  3317. } else {
  3318. // TBC : error : can not extract a folder in a string
  3319. }
  3320. }
  3321. // ----- Change abort status
  3322. if ($p_entry['status'] == "aborted") {
  3323. $p_entry['status'] = "skipped";
  3324. } elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) {
  3325. // ----- Look for post-extract callback
  3326. // ----- Generate a local information
  3327. $v_local_header = array();
  3328. $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
  3329. // ----- Swap the content to header
  3330. $v_local_header['content'] = $p_string;
  3331. $p_string = '';
  3332. // ----- Call the callback
  3333. // Here I do not use call_user_func() because I need to send a reference to the
  3334. // header.
  3335. // eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);');
  3336. $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header);
  3337. // ----- Swap back the content to header
  3338. $p_string = $v_local_header['content'];
  3339. unset($v_local_header['content']);
  3340. // ----- Look for abort result
  3341. if ($v_result == 2) {
  3342. $v_result = PCLZIP_ERR_USER_ABORTED;
  3343. }
  3344. }
  3345. // ----- Return
  3346. return $v_result;
  3347. }
  3348. // --------------------------------------------------------------------------------
  3349. // --------------------------------------------------------------------------------
  3350. // Function : privReadFileHeader()
  3351. // Description :
  3352. // Parameters :
  3353. // Return Values :
  3354. // --------------------------------------------------------------------------------
  3355. public function privReadFileHeader(&$p_header)
  3356. {
  3357. $v_result=1;
  3358. // ----- Read the 4 bytes signature
  3359. $v_binary_data = @fread($this->zip_fd, 4);
  3360. $v_data = unpack('Vid', $v_binary_data);
  3361. // ----- Check signature
  3362. if ($v_data['id'] != 0x04034b50) {
  3363. // ----- Error log
  3364. PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure');
  3365. // ----- Return
  3366. return PclZip::errorCode();
  3367. }
  3368. // ----- Read the first 42 bytes of the header
  3369. $v_binary_data = fread($this->zip_fd, 26);
  3370. // ----- Look for invalid block size
  3371. if (strlen($v_binary_data) != 26) {
  3372. $p_header['filename'] = "";
  3373. $p_header['status'] = "invalid_header";
  3374. // ----- Error log
  3375. PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid block size : ".strlen($v_binary_data));
  3376. // ----- Return
  3377. return PclZip::errorCode();
  3378. }
  3379. // ----- Extract the values
  3380. $v_data = unpack('vversion/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len', $v_binary_data);
  3381. // ----- Get filename
  3382. $p_header['filename'] = fread($this->zip_fd, $v_data['filename_len']);
  3383. // ----- Get extra_fields
  3384. if ($v_data['extra_len'] != 0) {
  3385. $p_header['extra'] = fread($this->zip_fd, $v_data['extra_len']);
  3386. } else {
  3387. $p_header['extra'] = '';
  3388. }
  3389. // ----- Extract properties
  3390. $p_header['version_extracted'] = $v_data['version'];
  3391. $p_header['compression'] = $v_data['compression'];
  3392. $p_header['size'] = $v_data['size'];
  3393. $p_header['compressed_size'] = $v_data['compressed_size'];
  3394. $p_header['crc'] = $v_data['crc'];
  3395. $p_header['flag'] = $v_data['flag'];
  3396. $p_header['filename_len'] = $v_data['filename_len'];
  3397. // ----- Recuperate date in UNIX format
  3398. $p_header['mdate'] = $v_data['mdate'];
  3399. $p_header['mtime'] = $v_data['mtime'];
  3400. if ($p_header['mdate'] && $p_header['mtime']) {
  3401. // ----- Extract time
  3402. $v_hour = ($p_header['mtime'] & 0xF800) >> 11;
  3403. $v_minute = ($p_header['mtime'] & 0x07E0) >> 5;
  3404. $v_seconde = ($p_header['mtime'] & 0x001F)*2;
  3405. // ----- Extract date
  3406. $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980;
  3407. $v_month = ($p_header['mdate'] & 0x01E0) >> 5;
  3408. $v_day = $p_header['mdate'] & 0x001F;
  3409. // ----- Get UNIX date format
  3410. $p_header['mtime'] = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year);
  3411. } else {
  3412. $p_header['mtime'] = time();
  3413. }
  3414. // TBC
  3415. //for(reset($v_data); $key = key($v_data); next($v_data)) {
  3416. //}
  3417. // ----- Set the stored filename
  3418. $p_header['stored_filename'] = $p_header['filename'];
  3419. // ----- Set the status field
  3420. $p_header['status'] = "ok";
  3421. // ----- Return
  3422. return $v_result;
  3423. }
  3424. // --------------------------------------------------------------------------------
  3425. // --------------------------------------------------------------------------------
  3426. // Function : privReadCentralFileHeader()
  3427. // Description :
  3428. // Parameters :
  3429. // Return Values :
  3430. // --------------------------------------------------------------------------------
  3431. public function privReadCentralFileHeader(&$p_header)
  3432. {
  3433. $v_result = 1;
  3434. // ----- Read the 4 bytes signature
  3435. $v_binary_data = @fread($this->zip_fd, 4);
  3436. $v_data = unpack('Vid', $v_binary_data);
  3437. // ----- Check signature
  3438. if ($v_data['id'] != 0x02014b50) {
  3439. // ----- Error log
  3440. PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure');
  3441. // ----- Return
  3442. return PclZip::errorCode();
  3443. }
  3444. // ----- Read the first 42 bytes of the header
  3445. $v_binary_data = fread($this->zip_fd, 42);
  3446. // ----- Look for invalid block size
  3447. if (strlen($v_binary_data) != 42) {
  3448. $p_header['filename'] = "";
  3449. $p_header['status'] = "invalid_header";
  3450. // ----- Error log
  3451. PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid block size : ".strlen($v_binary_data));
  3452. // ----- Return
  3453. return PclZip::errorCode();
  3454. }
  3455. // ----- Extract the values
  3456. $p_header = unpack('vversion/vversion_extracted/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len/vcomment_len/vdisk/vinternal/Vexternal/Voffset', $v_binary_data);
  3457. // ----- Get filename
  3458. if ($p_header['filename_len'] != 0) {
  3459. $p_header['filename'] = fread($this->zip_fd, $p_header['filename_len']);
  3460. } else {
  3461. $p_header['filename'] = '';
  3462. }
  3463. // ----- Get extra
  3464. if ($p_header['extra_len'] != 0) {
  3465. $p_header['extra'] = fread($this->zip_fd, $p_header['extra_len']);
  3466. } else {
  3467. $p_header['extra'] = '';
  3468. }
  3469. // ----- Get comment
  3470. if ($p_header['comment_len'] != 0) {
  3471. $p_header['comment'] = fread($this->zip_fd, $p_header['comment_len']);
  3472. } else {
  3473. $p_header['comment'] = '';
  3474. }
  3475. // ----- Extract properties
  3476. // ----- Recuperate date in UNIX format
  3477. //if ($p_header['mdate'] && $p_header['mtime'])
  3478. // TBC : bug : this was ignoring time with 0/0/0
  3479. if (1) {
  3480. // ----- Extract time
  3481. $v_hour = ($p_header['mtime'] & 0xF800) >> 11;
  3482. $v_minute = ($p_header['mtime'] & 0x07E0) >> 5;
  3483. $v_seconde = ($p_header['mtime'] & 0x001F)*2;
  3484. // ----- Extract date
  3485. $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980;
  3486. $v_month = ($p_header['mdate'] & 0x01E0) >> 5;
  3487. $v_day = $p_header['mdate'] & 0x001F;
  3488. // ----- Get UNIX date format
  3489. $p_header['mtime'] = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year);
  3490. } else {
  3491. $p_header['mtime'] = time();
  3492. }
  3493. // ----- Set the stored filename
  3494. $p_header['stored_filename'] = $p_header['filename'];
  3495. // ----- Set default status to ok
  3496. $p_header['status'] = 'ok';
  3497. // ----- Look if it is a directory
  3498. if (substr($p_header['filename'], -1) == '/') {
  3499. //$p_header['external'] = 0x41FF0010;
  3500. $p_header['external'] = 0x00000010;
  3501. }
  3502. // ----- Return
  3503. return $v_result;
  3504. }
  3505. // --------------------------------------------------------------------------------
  3506. // --------------------------------------------------------------------------------
  3507. // Function : privCheckFileHeaders()
  3508. // Description :
  3509. // Parameters :
  3510. // Return Values :
  3511. // 1 on success,
  3512. // 0 on error;
  3513. // --------------------------------------------------------------------------------
  3514. public function privCheckFileHeaders(&$p_local_header, &$p_central_header)
  3515. {
  3516. $v_result=1;
  3517. // ----- Check the static values
  3518. // TBC
  3519. if ($p_local_header['filename'] != $p_central_header['filename']) {
  3520. }
  3521. if ($p_local_header['version_extracted'] != $p_central_header['version_extracted']) {
  3522. }
  3523. if ($p_local_header['flag'] != $p_central_header['flag']) {
  3524. }
  3525. if ($p_local_header['compression'] != $p_central_header['compression']) {
  3526. }
  3527. if ($p_local_header['mtime'] != $p_central_header['mtime']) {
  3528. }
  3529. if ($p_local_header['filename_len'] != $p_central_header['filename_len']) {
  3530. }
  3531. // ----- Look for flag bit 3
  3532. if (($p_local_header['flag'] & 8) == 8) {
  3533. $p_local_header['size'] = $p_central_header['size'];
  3534. $p_local_header['compressed_size'] = $p_central_header['compressed_size'];
  3535. $p_local_header['crc'] = $p_central_header['crc'];
  3536. }
  3537. // ----- Return
  3538. return $v_result;
  3539. }
  3540. // --------------------------------------------------------------------------------
  3541. // --------------------------------------------------------------------------------
  3542. // Function : privReadEndCentralDir()
  3543. // Description :
  3544. // Parameters :
  3545. // Return Values :
  3546. // --------------------------------------------------------------------------------
  3547. public function privReadEndCentralDir(&$p_central_dir)
  3548. {
  3549. $v_result=1;
  3550. // ----- Go to the end of the zip file
  3551. $v_size = filesize($this->zipname);
  3552. @fseek($this->zip_fd, $v_size);
  3553. if (@ftell($this->zip_fd) != $v_size) {
  3554. // ----- Error log
  3555. PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to go to the end of the archive \''.$this->zipname.'\'');
  3556. // ----- Return
  3557. return PclZip::errorCode();
  3558. }
  3559. // ----- First try : look if this is an archive with no commentaries (most of the time)
  3560. // in this case the end of central dir is at 22 bytes of the file end
  3561. $v_found = 0;
  3562. if ($v_size > 26) {
  3563. @fseek($this->zip_fd, $v_size-22);
  3564. if (($v_pos = @ftell($this->zip_fd)) != ($v_size-22)) {
  3565. // ----- Error log
  3566. PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \''.$this->zipname.'\'');
  3567. // ----- Return
  3568. return PclZip::errorCode();
  3569. }
  3570. // ----- Read for bytes
  3571. $v_binary_data = @fread($this->zip_fd, 4);
  3572. $v_data = @unpack('Vid', $v_binary_data);
  3573. // ----- Check signature
  3574. if ($v_data['id'] == 0x06054b50) {
  3575. $v_found = 1;
  3576. }
  3577. $v_pos = ftell($this->zip_fd);
  3578. }
  3579. // ----- Go back to the maximum possible size of the Central Dir End Record
  3580. if (!$v_found) {
  3581. $v_maximum_size = 65557; // 0xFFFF + 22;
  3582. if ($v_maximum_size > $v_size) {
  3583. $v_maximum_size = $v_size;
  3584. }
  3585. @fseek($this->zip_fd, $v_size-$v_maximum_size);
  3586. if (@ftell($this->zip_fd) != ($v_size-$v_maximum_size)) {
  3587. // ----- Error log
  3588. PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \''.$this->zipname.'\'');
  3589. // ----- Return
  3590. return PclZip::errorCode();
  3591. }
  3592. // ----- Read byte per byte in order to find the signature
  3593. $v_pos = ftell($this->zip_fd);
  3594. $v_bytes = 0x00000000;
  3595. while ($v_pos < $v_size) {
  3596. // ----- Read a byte
  3597. $v_byte = @fread($this->zip_fd, 1);
  3598. // ----- Add the byte
  3599. //$v_bytes = ($v_bytes << 8) | Ord($v_byte);
  3600. // Note we mask the old value down such that once shifted we can never end up with more than a 32bit number
  3601. // Otherwise on systems where we have 64bit integers the check below for the magic number will fail.
  3602. $v_bytes = (($v_bytes & 0xFFFFFF) << 8) | Ord($v_byte);
  3603. // ----- Compare the bytes
  3604. if ($v_bytes == 0x504b0506) {
  3605. $v_pos++;
  3606. break;
  3607. }
  3608. $v_pos++;
  3609. }
  3610. // ----- Look if not found end of central dir
  3611. if ($v_pos == $v_size) {
  3612. // ----- Error log
  3613. PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Unable to find End of Central Dir Record signature");
  3614. // ----- Return
  3615. return PclZip::errorCode();
  3616. }
  3617. }
  3618. // ----- Read the first 18 bytes of the header
  3619. $v_binary_data = fread($this->zip_fd, 18);
  3620. // ----- Look for invalid block size
  3621. if (strlen($v_binary_data) != 18) {
  3622. // ----- Error log
  3623. PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid End of Central Dir Record size : ".strlen($v_binary_data));
  3624. // ----- Return
  3625. return PclZip::errorCode();
  3626. }
  3627. // ----- Extract the values
  3628. $v_data = unpack('vdisk/vdisk_start/vdisk_entries/ventries/Vsize/Voffset/vcomment_size', $v_binary_data);
  3629. // ----- Check the global size
  3630. if (($v_pos + $v_data['comment_size'] + 18) != $v_size) {
  3631. // ----- Removed in release 2.2 see readme file
  3632. // The check of the file size is a little too strict.
  3633. // Some bugs where found when a zip is encrypted/decrypted with 'crypt'.
  3634. // While decrypted, zip has training 0 bytes
  3635. if (0) {
  3636. // ----- Error log
  3637. PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'The central dir is not at the end of the archive. Some trailing bytes exists after the archive.');
  3638. // ----- Return
  3639. return PclZip::errorCode();
  3640. }
  3641. }
  3642. // ----- Get comment
  3643. if ($v_data['comment_size'] != 0) {
  3644. $p_central_dir['comment'] = fread($this->zip_fd, $v_data['comment_size']);
  3645. } else {
  3646. $p_central_dir['comment'] = '';
  3647. }
  3648. $p_central_dir['entries'] = $v_data['entries'];
  3649. $p_central_dir['disk_entries'] = $v_data['disk_entries'];
  3650. $p_central_dir['offset'] = $v_data['offset'];
  3651. $p_central_dir['size'] = $v_data['size'];
  3652. $p_central_dir['disk'] = $v_data['disk'];
  3653. $p_central_dir['disk_start'] = $v_data['disk_start'];
  3654. // TBC
  3655. //for(reset($p_central_dir); $key = key($p_central_dir); next($p_central_dir)) {
  3656. //}
  3657. // ----- Return
  3658. return $v_result;
  3659. }
  3660. // --------------------------------------------------------------------------------
  3661. // --------------------------------------------------------------------------------
  3662. // Function : privDeleteByRule()
  3663. // Description :
  3664. // Parameters :
  3665. // Return Values :
  3666. // --------------------------------------------------------------------------------
  3667. public function privDeleteByRule(&$p_result_list, &$p_options)
  3668. {
  3669. $v_result=1;
  3670. $v_list_detail = array();
  3671. // ----- Open the zip file
  3672. if (($v_result=$this->privOpenFd('rb')) != 1) {
  3673. // ----- Return
  3674. return $v_result;
  3675. }
  3676. // ----- Read the central directory informations
  3677. $v_central_dir = array();
  3678. if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) {
  3679. $this->privCloseFd();
  3680. return $v_result;
  3681. }
  3682. // ----- Go to beginning of File
  3683. @rewind($this->zip_fd);
  3684. // ----- Scan all the files
  3685. // ----- Start at beginning of Central Dir
  3686. $v_pos_entry = $v_central_dir['offset'];
  3687. @rewind($this->zip_fd);
  3688. if (@fseek($this->zip_fd, $v_pos_entry)) {
  3689. // ----- Close the zip file
  3690. $this->privCloseFd();
  3691. // ----- Error log
  3692. PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
  3693. // ----- Return
  3694. return PclZip::errorCode();
  3695. }
  3696. // ----- Read each entry
  3697. $v_header_list = array();
  3698. $j_start = 0;
  3699. for ($i=0, $v_nb_extracted=0; $i<$v_central_dir['entries']; $i++) {
  3700. // ----- Read the file header
  3701. $v_header_list[$v_nb_extracted] = array();
  3702. if (($v_result = $this->privReadCentralFileHeader($v_header_list[$v_nb_extracted])) != 1) {
  3703. // ----- Close the zip file
  3704. $this->privCloseFd();
  3705. return $v_result;
  3706. }
  3707. // ----- Store the index
  3708. $v_header_list[$v_nb_extracted]['index'] = $i;
  3709. // ----- Look for the specific extract rules
  3710. $v_found = false;
  3711. // ----- Look for extract by name rule
  3712. if ((isset($p_options[PCLZIP_OPT_BY_NAME])) && ($p_options[PCLZIP_OPT_BY_NAME] != 0)) {
  3713. // ----- Look if the filename is in the list
  3714. for ($j=0; ($j<sizeof($p_options[PCLZIP_OPT_BY_NAME])) && (!$v_found); $j++) {
  3715. // ----- Look for a directory
  3716. if (substr($p_options[PCLZIP_OPT_BY_NAME][$j], -1) == "/") {
  3717. // ----- Look if the directory is in the filename path
  3718. if ((strlen($v_header_list[$v_nb_extracted]['stored_filename']) > strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) && (substr($v_header_list[$v_nb_extracted]['stored_filename'], 0, strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) == $p_options[PCLZIP_OPT_BY_NAME][$j])) {
  3719. $v_found = true;
  3720. } elseif ((($v_header_list[$v_nb_extracted]['external']&0x00000010)==0x00000010) /* Indicates a folder */ && ($v_header_list[$v_nb_extracted]['stored_filename'].'/' == $p_options[PCLZIP_OPT_BY_NAME][$j])) {
  3721. $v_found = true;
  3722. }
  3723. } elseif ($v_header_list[$v_nb_extracted]['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) {
  3724. // ----- Look for a filename
  3725. $v_found = true;
  3726. }
  3727. }
  3728. } elseif ((isset($p_options[PCLZIP_OPT_BY_PREG])) && ($p_options[PCLZIP_OPT_BY_PREG] != "")) {
  3729. // ----- Look for extract by preg rule
  3730. if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header_list[$v_nb_extracted]['stored_filename'])) {
  3731. $v_found = true;
  3732. }
  3733. } elseif ((isset($p_options[PCLZIP_OPT_BY_INDEX])) && ($p_options[PCLZIP_OPT_BY_INDEX] != 0)) {
  3734. // ----- Look for extract by index rule
  3735. // ----- Look if the index is in the list
  3736. for ($j=$j_start; ($j<sizeof($p_options[PCLZIP_OPT_BY_INDEX])) && (!$v_found); $j++) {
  3737. if (($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i<=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) {
  3738. $v_found = true;
  3739. }
  3740. if ($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) {
  3741. $j_start = $j+1;
  3742. }
  3743. if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start']>$i) {
  3744. break;
  3745. }
  3746. }
  3747. } else {
  3748. $v_found = true;
  3749. }
  3750. // ----- Look for deletion
  3751. if ($v_found) {
  3752. unset($v_header_list[$v_nb_extracted]);
  3753. } else {
  3754. $v_nb_extracted++;
  3755. }
  3756. }
  3757. // ----- Look if something need to be deleted
  3758. if ($v_nb_extracted > 0) {
  3759. // ----- Creates a temporay file
  3760. $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp';
  3761. // ----- Creates a temporary zip archive
  3762. $v_temp_zip = new PclZip($v_zip_temp_name);
  3763. // ----- Open the temporary zip file in write mode
  3764. if (($v_result = $v_temp_zip->privOpenFd('wb')) != 1) {
  3765. $this->privCloseFd();
  3766. // ----- Return
  3767. return $v_result;
  3768. }
  3769. // ----- Look which file need to be kept
  3770. for ($i=0; $i<sizeof($v_header_list); $i++) {
  3771. // ----- Calculate the position of the header
  3772. @rewind($this->zip_fd);
  3773. if (@fseek($this->zip_fd, $v_header_list[$i]['offset'])) {
  3774. // ----- Close the zip file
  3775. $this->privCloseFd();
  3776. $v_temp_zip->privCloseFd();
  3777. @unlink($v_zip_temp_name);
  3778. // ----- Error log
  3779. PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
  3780. // ----- Return
  3781. return PclZip::errorCode();
  3782. }
  3783. // ----- Read the file header
  3784. $v_local_header = array();
  3785. if (($v_result = $this->privReadFileHeader($v_local_header)) != 1) {
  3786. // ----- Close the zip file
  3787. $this->privCloseFd();
  3788. $v_temp_zip->privCloseFd();
  3789. @unlink($v_zip_temp_name);
  3790. // ----- Return
  3791. return $v_result;
  3792. }
  3793. // ----- Check that local file header is same as central file header
  3794. if ($this->privCheckFileHeaders($v_local_header, $v_header_list[$i]) != 1) {
  3795. // TBC
  3796. }
  3797. unset($v_local_header);
  3798. // ----- Write the file header
  3799. if (($v_result = $v_temp_zip->privWriteFileHeader($v_header_list[$i])) != 1) {
  3800. // ----- Close the zip file
  3801. $this->privCloseFd();
  3802. $v_temp_zip->privCloseFd();
  3803. @unlink($v_zip_temp_name);
  3804. // ----- Return
  3805. return $v_result;
  3806. }
  3807. // ----- Read/write the data block
  3808. if (($v_result = PclZipUtilCopyBlock($this->zip_fd, $v_temp_zip->zip_fd, $v_header_list[$i]['compressed_size'])) != 1) {
  3809. // ----- Close the zip file
  3810. $this->privCloseFd();
  3811. $v_temp_zip->privCloseFd();
  3812. @unlink($v_zip_temp_name);
  3813. // ----- Return
  3814. return $v_result;
  3815. }
  3816. }
  3817. // ----- Store the offset of the central dir
  3818. $v_offset = @ftell($v_temp_zip->zip_fd);
  3819. // ----- Re-Create the Central Dir files header
  3820. for ($i=0; $i<sizeof($v_header_list); $i++) {
  3821. // ----- Create the file header
  3822. if (($v_result = $v_temp_zip->privWriteCentralFileHeader($v_header_list[$i])) != 1) {
  3823. $v_temp_zip->privCloseFd();
  3824. $this->privCloseFd();
  3825. @unlink($v_zip_temp_name);
  3826. // ----- Return
  3827. return $v_result;
  3828. }
  3829. // ----- Transform the header to a 'usable' info
  3830. $v_temp_zip->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]);
  3831. }
  3832. // ----- Zip file comment
  3833. $v_comment = '';
  3834. if (isset($p_options[PCLZIP_OPT_COMMENT])) {
  3835. $v_comment = $p_options[PCLZIP_OPT_COMMENT];
  3836. }
  3837. // ----- Calculate the size of the central header
  3838. $v_size = @ftell($v_temp_zip->zip_fd)-$v_offset;
  3839. // ----- Create the central dir footer
  3840. if (($v_result = $v_temp_zip->privWriteCentralHeader(sizeof($v_header_list), $v_size, $v_offset, $v_comment)) != 1) {
  3841. // ----- Reset the file list
  3842. unset($v_header_list);
  3843. $v_temp_zip->privCloseFd();
  3844. $this->privCloseFd();
  3845. @unlink($v_zip_temp_name);
  3846. // ----- Return
  3847. return $v_result;
  3848. }
  3849. // ----- Close
  3850. $v_temp_zip->privCloseFd();
  3851. $this->privCloseFd();
  3852. // ----- Delete the zip file
  3853. // TBC : I should test the result ...
  3854. @unlink($this->zipname);
  3855. // ----- Rename the temporary file
  3856. // TBC : I should test the result ...
  3857. //@rename($v_zip_temp_name, $this->zipname);
  3858. PclZipUtilRename($v_zip_temp_name, $this->zipname);
  3859. // ----- Destroy the temporary archive
  3860. unset($v_temp_zip);
  3861. } elseif ($v_central_dir['entries'] != 0) {
  3862. // ----- Remove every files : reset the file
  3863. $this->privCloseFd();
  3864. if (($v_result = $this->privOpenFd('wb')) != 1) {
  3865. return $v_result;
  3866. }
  3867. if (($v_result = $this->privWriteCentralHeader(0, 0, 0, '')) != 1) {
  3868. return $v_result;
  3869. }
  3870. $this->privCloseFd();
  3871. }
  3872. // ----- Return
  3873. return $v_result;
  3874. }
  3875. // --------------------------------------------------------------------------------
  3876. // --------------------------------------------------------------------------------
  3877. // Function : privDirCheck()
  3878. // Description :
  3879. // Check if a directory exists, if not it creates it and all the parents directory
  3880. // which may be useful.
  3881. // Parameters :
  3882. // $p_dir : Directory path to check.
  3883. // Return Values :
  3884. // 1 : OK
  3885. // -1 : Unable to create directory
  3886. // --------------------------------------------------------------------------------
  3887. public function privDirCheck($p_dir, $p_is_dir = false)
  3888. {
  3889. $v_result = 1;
  3890. // ----- Remove the final '/'
  3891. if (($p_is_dir) && (substr($p_dir, -1)=='/')) {
  3892. $p_dir = substr($p_dir, 0, strlen($p_dir)-1);
  3893. }
  3894. // ----- Check the directory availability
  3895. if ((is_dir($p_dir)) || ($p_dir == "")) {
  3896. return 1;
  3897. }
  3898. // ----- Extract parent directory
  3899. $p_parent_dir = dirname($p_dir);
  3900. // ----- Just a check
  3901. if ($p_parent_dir != $p_dir) {
  3902. // ----- Look for parent directory
  3903. if ($p_parent_dir != "") {
  3904. if (($v_result = $this->privDirCheck($p_parent_dir)) != 1) {
  3905. return $v_result;
  3906. }
  3907. }
  3908. }
  3909. // ----- Create the directory
  3910. if (!@mkdir($p_dir, 0777)) {
  3911. // ----- Error log
  3912. PclZip::privErrorLog(PCLZIP_ERR_DIR_CREATE_FAIL, "Unable to create directory '$p_dir'");
  3913. // ----- Return
  3914. return PclZip::errorCode();
  3915. }
  3916. // ----- Return
  3917. return $v_result;
  3918. }
  3919. // --------------------------------------------------------------------------------
  3920. // --------------------------------------------------------------------------------
  3921. // Function : privMerge()
  3922. // Description :
  3923. // If $p_archive_to_add does not exist, the function exit with a success result.
  3924. // Parameters :
  3925. // Return Values :
  3926. // --------------------------------------------------------------------------------
  3927. public function privMerge(&$p_archive_to_add)
  3928. {
  3929. $v_result=1;
  3930. // ----- Look if the archive_to_add exists
  3931. if (!is_file($p_archive_to_add->zipname)) {
  3932. // ----- Nothing to merge, so merge is a success
  3933. $v_result = 1;
  3934. // ----- Return
  3935. return $v_result;
  3936. }
  3937. // ----- Look if the archive exists
  3938. if (!is_file($this->zipname)) {
  3939. // ----- Do a duplicate
  3940. $v_result = $this->privDuplicate($p_archive_to_add->zipname);
  3941. // ----- Return
  3942. return $v_result;
  3943. }
  3944. // ----- Open the zip file
  3945. if (($v_result=$this->privOpenFd('rb')) != 1) {
  3946. // ----- Return
  3947. return $v_result;
  3948. }
  3949. // ----- Read the central directory informations
  3950. $v_central_dir = array();
  3951. if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) {
  3952. $this->privCloseFd();
  3953. return $v_result;
  3954. }
  3955. // ----- Go to beginning of File
  3956. @rewind($this->zip_fd);
  3957. // ----- Open the archive_to_add file
  3958. if (($v_result=$p_archive_to_add->privOpenFd('rb')) != 1) {
  3959. $this->privCloseFd();
  3960. // ----- Return
  3961. return $v_result;
  3962. }
  3963. // ----- Read the central directory informations
  3964. $v_central_dir_to_add = array();
  3965. if (($v_result = $p_archive_to_add->privReadEndCentralDir($v_central_dir_to_add)) != 1) {
  3966. $this->privCloseFd();
  3967. $p_archive_to_add->privCloseFd();
  3968. return $v_result;
  3969. }
  3970. // ----- Go to beginning of File
  3971. @rewind($p_archive_to_add->zip_fd);
  3972. // ----- Creates a temporay file
  3973. $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp';
  3974. // ----- Open the temporary file in write mode
  3975. if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0) {
  3976. $this->privCloseFd();
  3977. $p_archive_to_add->privCloseFd();
  3978. PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_zip_temp_name.'\' in binary write mode');
  3979. // ----- Return
  3980. return PclZip::errorCode();
  3981. }
  3982. // ----- Copy the files from the archive to the temporary file
  3983. // TBC : Here I should better append the file and go back to erase the central dir
  3984. $v_size = $v_central_dir['offset'];
  3985. while ($v_size != 0) {
  3986. $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
  3987. $v_buffer = fread($this->zip_fd, $v_read_size);
  3988. @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
  3989. $v_size -= $v_read_size;
  3990. }
  3991. // ----- Copy the files from the archive_to_add into the temporary file
  3992. $v_size = $v_central_dir_to_add['offset'];
  3993. while ($v_size != 0) {
  3994. $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
  3995. $v_buffer = fread($p_archive_to_add->zip_fd, $v_read_size);
  3996. @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
  3997. $v_size -= $v_read_size;
  3998. }
  3999. // ----- Store the offset of the central dir
  4000. $v_offset = @ftell($v_zip_temp_fd);
  4001. // ----- Copy the block of file headers from the old archive
  4002. $v_size = $v_central_dir['size'];
  4003. while ($v_size != 0) {
  4004. $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
  4005. $v_buffer = @fread($this->zip_fd, $v_read_size);
  4006. @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
  4007. $v_size -= $v_read_size;
  4008. }
  4009. // ----- Copy the block of file headers from the archive_to_add
  4010. $v_size = $v_central_dir_to_add['size'];
  4011. while ($v_size != 0) {
  4012. $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
  4013. $v_buffer = @fread($p_archive_to_add->zip_fd, $v_read_size);
  4014. @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
  4015. $v_size -= $v_read_size;
  4016. }
  4017. // ----- Merge the file comments
  4018. $v_comment = $v_central_dir['comment'].' '.$v_central_dir_to_add['comment'];
  4019. // ----- Calculate the size of the (new) central header
  4020. $v_size = @ftell($v_zip_temp_fd)-$v_offset;
  4021. // ----- Swap the file descriptor
  4022. // Here is a trick : I swap the temporary fd with the zip fd, in order to use
  4023. // the following methods on the temporary fil and not the real archive fd
  4024. $v_swap = $this->zip_fd;
  4025. $this->zip_fd = $v_zip_temp_fd;
  4026. $v_zip_temp_fd = $v_swap;
  4027. // ----- Create the central dir footer
  4028. if (($v_result = $this->privWriteCentralHeader($v_central_dir['entries']+$v_central_dir_to_add['entries'], $v_size, $v_offset, $v_comment)) != 1) {
  4029. $this->privCloseFd();
  4030. $p_archive_to_add->privCloseFd();
  4031. @fclose($v_zip_temp_fd);
  4032. $this->zip_fd = null;
  4033. // ----- Reset the file list
  4034. unset($v_header_list);
  4035. // ----- Return
  4036. return $v_result;
  4037. }
  4038. // ----- Swap back the file descriptor
  4039. $v_swap = $this->zip_fd;
  4040. $this->zip_fd = $v_zip_temp_fd;
  4041. $v_zip_temp_fd = $v_swap;
  4042. // ----- Close
  4043. $this->privCloseFd();
  4044. $p_archive_to_add->privCloseFd();
  4045. // ----- Close the temporary file
  4046. @fclose($v_zip_temp_fd);
  4047. // ----- Delete the zip file
  4048. // TBC : I should test the result ...
  4049. @unlink($this->zipname);
  4050. // ----- Rename the temporary file
  4051. // TBC : I should test the result ...
  4052. //@rename($v_zip_temp_name, $this->zipname);
  4053. PclZipUtilRename($v_zip_temp_name, $this->zipname);
  4054. // ----- Return
  4055. return $v_result;
  4056. }
  4057. // --------------------------------------------------------------------------------
  4058. // --------------------------------------------------------------------------------
  4059. // Function : privDuplicate()
  4060. // Description :
  4061. // Parameters :
  4062. // Return Values :
  4063. // --------------------------------------------------------------------------------
  4064. public function privDuplicate($p_archive_filename)
  4065. {
  4066. $v_result=1;
  4067. // ----- Look if the $p_archive_filename exists
  4068. if (!is_file($p_archive_filename)) {
  4069. // ----- Nothing to duplicate, so duplicate is a success.
  4070. $v_result = 1;
  4071. // ----- Return
  4072. return $v_result;
  4073. }
  4074. // ----- Open the zip file
  4075. if (($v_result=$this->privOpenFd('wb')) != 1) {
  4076. // ----- Return
  4077. return $v_result;
  4078. }
  4079. // ----- Open the temporary file in write mode
  4080. if (($v_zip_temp_fd = @fopen($p_archive_filename, 'rb')) == 0) {
  4081. $this->privCloseFd();
  4082. PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive file \''.$p_archive_filename.'\' in binary write mode');
  4083. // ----- Return
  4084. return PclZip::errorCode();
  4085. }
  4086. // ----- Copy the files from the archive to the temporary file
  4087. // TBC : Here I should better append the file and go back to erase the central dir
  4088. $v_size = filesize($p_archive_filename);
  4089. while ($v_size != 0) {
  4090. $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
  4091. $v_buffer = fread($v_zip_temp_fd, $v_read_size);
  4092. @fwrite($this->zip_fd, $v_buffer, $v_read_size);
  4093. $v_size -= $v_read_size;
  4094. }
  4095. // ----- Close
  4096. $this->privCloseFd();
  4097. // ----- Close the temporary file
  4098. @fclose($v_zip_temp_fd);
  4099. // ----- Return
  4100. return $v_result;
  4101. }
  4102. // --------------------------------------------------------------------------------
  4103. // --------------------------------------------------------------------------------
  4104. // Function : privErrorLog()
  4105. // Description :
  4106. // Parameters :
  4107. // --------------------------------------------------------------------------------
  4108. public function privErrorLog($p_error_code = 0, $p_error_string = '')
  4109. {
  4110. if (PCLZIP_ERROR_EXTERNAL == 1) {
  4111. PclError($p_error_code, $p_error_string);
  4112. } else {
  4113. $this->error_code = $p_error_code;
  4114. $this->error_string = $p_error_string;
  4115. }
  4116. }
  4117. // --------------------------------------------------------------------------------
  4118. // --------------------------------------------------------------------------------
  4119. // Function : privErrorReset()
  4120. // Description :
  4121. // Parameters :
  4122. // --------------------------------------------------------------------------------
  4123. public function privErrorReset()
  4124. {
  4125. if (PCLZIP_ERROR_EXTERNAL == 1) {
  4126. PclErrorReset();
  4127. } else {
  4128. $this->error_code = 0;
  4129. $this->error_string = '';
  4130. }
  4131. }
  4132. // --------------------------------------------------------------------------------
  4133. // --------------------------------------------------------------------------------
  4134. // Function : privDisableMagicQuotes()
  4135. // Description :
  4136. // Parameters :
  4137. // Return Values :
  4138. // --------------------------------------------------------------------------------
  4139. public function privDisableMagicQuotes()
  4140. {
  4141. $v_result=1;
  4142. // ----- Look if function exists
  4143. if ((!function_exists("get_magic_quotes_runtime")) || (!function_exists("set_magic_quotes_runtime"))) {
  4144. return $v_result;
  4145. }
  4146. // ----- Look if already done
  4147. if ($this->magic_quotes_status != -1) {
  4148. return $v_result;
  4149. }
  4150. // ----- Get and memorize the magic_quote value
  4151. $this->magic_quotes_status = @get_magic_quotes_runtime();
  4152. // ----- Disable magic_quotes
  4153. if ($this->magic_quotes_status == 1) {
  4154. @set_magic_quotes_runtime(0);
  4155. }
  4156. // ----- Return
  4157. return $v_result;
  4158. }
  4159. // --------------------------------------------------------------------------------
  4160. // --------------------------------------------------------------------------------
  4161. // Function : privSwapBackMagicQuotes()
  4162. // Description :
  4163. // Parameters :
  4164. // Return Values :
  4165. // --------------------------------------------------------------------------------
  4166. public function privSwapBackMagicQuotes()
  4167. {
  4168. $v_result=1;
  4169. // ----- Look if function exists
  4170. if ((!function_exists("get_magic_quotes_runtime")) || (!function_exists("set_magic_quotes_runtime"))) {
  4171. return $v_result;
  4172. }
  4173. // ----- Look if something to do
  4174. if ($this->magic_quotes_status != -1) {
  4175. return $v_result;
  4176. }
  4177. // ----- Swap back magic_quotes
  4178. if ($this->magic_quotes_status == 1) {
  4179. @set_magic_quotes_runtime($this->magic_quotes_status);
  4180. }
  4181. // ----- Return
  4182. return $v_result;
  4183. }
  4184. // --------------------------------------------------------------------------------
  4185. }
  4186. // End of class
  4187. // --------------------------------------------------------------------------------
  4188. // --------------------------------------------------------------------------------
  4189. // Function : PclZipUtilPathReduction()
  4190. // Description :
  4191. // Parameters :
  4192. // Return Values :
  4193. // --------------------------------------------------------------------------------
  4194. function PclZipUtilPathReduction($p_dir)
  4195. {
  4196. $v_result = "";
  4197. // ----- Look for not empty path
  4198. if ($p_dir != "") {
  4199. // ----- Explode path by directory names
  4200. $v_list = explode("/", $p_dir);
  4201. // ----- Study directories from last to first
  4202. $v_skip = 0;
  4203. for ($i=sizeof($v_list)-1; $i>=0; $i--) {
  4204. // ----- Look for current path
  4205. if ($v_list[$i] == ".") {
  4206. // ----- Ignore this directory
  4207. // Should be the first $i=0, but no check is done
  4208. } elseif ($v_list[$i] == "..") {
  4209. $v_skip++;
  4210. } elseif ($v_list[$i] == "") {
  4211. // ----- First '/' i.e. root slash
  4212. if ($i == 0) {
  4213. $v_result = "/".$v_result;
  4214. if ($v_skip > 0) {
  4215. // ----- It is an invalid path, so the path is not modified
  4216. // TBC
  4217. $v_result = $p_dir;
  4218. $v_skip = 0;
  4219. }
  4220. } elseif ($i == (sizeof($v_list)-1)) {
  4221. // ----- Last '/' i.e. indicates a directory
  4222. $v_result = $v_list[$i];
  4223. } else {
  4224. // ----- Double '/' inside the path
  4225. // ----- Ignore only the double '//' in path,
  4226. // but not the first and last '/'
  4227. }
  4228. } else {
  4229. // ----- Look for item to skip
  4230. if ($v_skip > 0) {
  4231. $v_skip--;
  4232. } else {
  4233. $v_result = $v_list[$i].($i!=(sizeof($v_list)-1)?"/".$v_result:"");
  4234. }
  4235. }
  4236. }
  4237. // ----- Look for skip
  4238. if ($v_skip > 0) {
  4239. while ($v_skip > 0) {
  4240. $v_result = '../'.$v_result;
  4241. $v_skip--;
  4242. }
  4243. }
  4244. }
  4245. // ----- Return
  4246. return $v_result;
  4247. }
  4248. // --------------------------------------------------------------------------------
  4249. // --------------------------------------------------------------------------------
  4250. // Function : PclZipUtilPathInclusion()
  4251. // Description :
  4252. // This function indicates if the path $p_path is under the $p_dir tree. Or,
  4253. // said in an other way, if the file or sub-dir $p_path is inside the dir
  4254. // $p_dir.
  4255. // The function indicates also if the path is exactly the same as the dir.
  4256. // This function supports path with duplicated '/' like '//', but does not
  4257. // support '.' or '..' statements.
  4258. // Parameters :
  4259. // Return Values :
  4260. // 0 if $p_path is not inside directory $p_dir
  4261. // 1 if $p_path is inside directory $p_dir
  4262. // 2 if $p_path is exactly the same as $p_dir
  4263. // --------------------------------------------------------------------------------
  4264. function PclZipUtilPathInclusion($p_dir, $p_path)
  4265. {
  4266. $v_result = 1;
  4267. // ----- Look for path beginning by ./
  4268. if (($p_dir == '.') || ((strlen($p_dir) >=2) && (substr($p_dir, 0, 2) == './'))) {
  4269. $p_dir = PclZipUtilTranslateWinPath(getcwd(), false).'/'.substr($p_dir, 1);
  4270. }
  4271. if (($p_path == '.') || ((strlen($p_path) >=2) && (substr($p_path, 0, 2) == './'))) {
  4272. $p_path = PclZipUtilTranslateWinPath(getcwd(), false).'/'.substr($p_path, 1);
  4273. }
  4274. // ----- Explode dir and path by directory separator
  4275. $v_list_dir = explode("/", $p_dir);
  4276. $v_list_dir_size = sizeof($v_list_dir);
  4277. $v_list_path = explode("/", $p_path);
  4278. $v_list_path_size = sizeof($v_list_path);
  4279. // ----- Study directories paths
  4280. $i = 0;
  4281. $j = 0;
  4282. while (($i < $v_list_dir_size) && ($j < $v_list_path_size) && ($v_result)) {
  4283. // ----- Look for empty dir (path reduction)
  4284. if ($v_list_dir[$i] == '') {
  4285. $i++;
  4286. continue;
  4287. }
  4288. if ($v_list_path[$j] == '') {
  4289. $j++;
  4290. continue;
  4291. }
  4292. // ----- Compare the items
  4293. if (($v_list_dir[$i] != $v_list_path[$j]) && ($v_list_dir[$i] != '') && ($v_list_path[$j] != '')) {
  4294. $v_result = 0;
  4295. }
  4296. // ----- Next items
  4297. $i++;
  4298. $j++;
  4299. }
  4300. // ----- Look if everything seems to be the same
  4301. if ($v_result) {
  4302. // ----- Skip all the empty items
  4303. while (($j < $v_list_path_size) && ($v_list_path[$j] == '')) {
  4304. $j++;
  4305. }
  4306. while (($i < $v_list_dir_size) && ($v_list_dir[$i] == '')) {
  4307. $i++;
  4308. }
  4309. if (($i >= $v_list_dir_size) && ($j >= $v_list_path_size)) {
  4310. // ----- There are exactly the same
  4311. $v_result = 2;
  4312. } elseif ($i < $v_list_dir_size) {
  4313. // ----- The path is shorter than the dir
  4314. $v_result = 0;
  4315. }
  4316. }
  4317. // ----- Return
  4318. return $v_result;
  4319. }
  4320. // --------------------------------------------------------------------------------
  4321. // --------------------------------------------------------------------------------
  4322. // Function : PclZipUtilCopyBlock()
  4323. // Description :
  4324. // Parameters :
  4325. // $p_mode : read/write compression mode
  4326. // 0 : src & dest normal
  4327. // 1 : src gzip, dest normal
  4328. // 2 : src normal, dest gzip
  4329. // 3 : src & dest gzip
  4330. // Return Values :
  4331. // --------------------------------------------------------------------------------
  4332. function PclZipUtilCopyBlock($p_src, $p_dest, $p_size, $p_mode = 0)
  4333. {
  4334. $v_result = 1;
  4335. if ($p_mode==0) {
  4336. while ($p_size != 0) {
  4337. $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE);
  4338. $v_buffer = @fread($p_src, $v_read_size);
  4339. @fwrite($p_dest, $v_buffer, $v_read_size);
  4340. $p_size -= $v_read_size;
  4341. }
  4342. } elseif ($p_mode==1) {
  4343. while ($p_size != 0) {
  4344. $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE);
  4345. $v_buffer = @gzread($p_src, $v_read_size);
  4346. @fwrite($p_dest, $v_buffer, $v_read_size);
  4347. $p_size -= $v_read_size;
  4348. }
  4349. } elseif ($p_mode==2) {
  4350. while ($p_size != 0) {
  4351. $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE);
  4352. $v_buffer = @fread($p_src, $v_read_size);
  4353. @gzwrite($p_dest, $v_buffer, $v_read_size);
  4354. $p_size -= $v_read_size;
  4355. }
  4356. } elseif ($p_mode==3) {
  4357. while ($p_size != 0) {
  4358. $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE);
  4359. $v_buffer = @gzread($p_src, $v_read_size);
  4360. @gzwrite($p_dest, $v_buffer, $v_read_size);
  4361. $p_size -= $v_read_size;
  4362. }
  4363. }
  4364. // ----- Return
  4365. return $v_result;
  4366. }
  4367. // --------------------------------------------------------------------------------
  4368. // --------------------------------------------------------------------------------
  4369. // Function : PclZipUtilRename()
  4370. // Description :
  4371. // This function tries to do a simple rename() function. If it fails, it
  4372. // tries to copy the $p_src file in a new $p_dest file and then unlink the
  4373. // first one.
  4374. // Parameters :
  4375. // $p_src : Old filename
  4376. // $p_dest : New filename
  4377. // Return Values :
  4378. // 1 on success, 0 on failure.
  4379. // --------------------------------------------------------------------------------
  4380. function PclZipUtilRename($p_src, $p_dest)
  4381. {
  4382. $v_result = 1;
  4383. // ----- Try to rename the files
  4384. if (!@rename($p_src, $p_dest)) {
  4385. // ----- Try to copy & unlink the src
  4386. if (!@copy($p_src, $p_dest)) {
  4387. $v_result = 0;
  4388. } elseif (!@unlink($p_src)) {
  4389. $v_result = 0;
  4390. }
  4391. }
  4392. // ----- Return
  4393. return $v_result;
  4394. }
  4395. // --------------------------------------------------------------------------------
  4396. // --------------------------------------------------------------------------------
  4397. // Function : PclZipUtilOptionText()
  4398. // Description :
  4399. // Translate option value in text. Mainly for debug purpose.
  4400. // Parameters :
  4401. // $p_option : the option value.
  4402. // Return Values :
  4403. // The option text value.
  4404. // --------------------------------------------------------------------------------
  4405. function PclZipUtilOptionText($p_option)
  4406. {
  4407. $v_list = get_defined_constants();
  4408. for (reset($v_list); $v_key = key($v_list); next($v_list)) {
  4409. $v_prefix = substr($v_key, 0, 10);
  4410. if ((($v_prefix == 'PCLZIP_OPT') || ($v_prefix == 'PCLZIP_CB_') || ($v_prefix == 'PCLZIP_ATT')) && ($v_list[$v_key] == $p_option)) {
  4411. return $v_key;
  4412. }
  4413. }
  4414. $v_result = 'Unknown';
  4415. return $v_result;
  4416. }
  4417. // --------------------------------------------------------------------------------
  4418. // --------------------------------------------------------------------------------
  4419. // Function : PclZipUtilTranslateWinPath()
  4420. // Description :
  4421. // Translate windows path by replacing '\' by '/' and optionally removing
  4422. // drive letter.
  4423. // Parameters :
  4424. // $p_path : path to translate.
  4425. // $p_remove_disk_letter : true | false
  4426. // Return Values :
  4427. // The path translated.
  4428. // --------------------------------------------------------------------------------
  4429. function PclZipUtilTranslateWinPath($p_path, $p_remove_disk_letter = true)
  4430. {
  4431. if (stristr(php_uname(), 'windows')) {
  4432. // ----- Look for potential disk letter
  4433. if (($p_remove_disk_letter) && (($v_position = strpos($p_path, ':')) != false)) {
  4434. $p_path = substr($p_path, $v_position+1);
  4435. }
  4436. // ----- Change potential windows directory separator
  4437. if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0, 1) == '\\')) {
  4438. $p_path = strtr($p_path, '\\', '/');
  4439. }
  4440. }
  4441. return $p_path;
  4442. }