Advertisement
Guest User

Untitled

a guest
Apr 23rd, 2014
39
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 67.68 KB | None | 0 0
  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  3.  
  4. /**
  5. * File::CSV
  6. *
  7. * PHP versions 4 and 5
  8. *
  9. * Copyright (c) 1997-2008,
  10. * Vincent Blavet <vincent@phpconcept.net>
  11. * All rights reserved.
  12. *
  13. * Redistribution and use in source and binary forms, with or without
  14. * modification, are permitted provided that the following conditions are met:
  15. *
  16. * * Redistributions of source code must retain the above copyright notice,
  17. * this list of conditions and the following disclaimer.
  18. * * Redistributions in binary form must reproduce the above copyright
  19. * notice, this list of conditions and the following disclaimer in the
  20. * documentation and/or other materials provided with the distribution.
  21. *
  22. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  23. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  24. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  25. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
  26. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  27. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  28. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  29. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  30. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  31. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  32. *
  33. * @category File_Formats
  34. * @package Archive_Tar
  35. * @author Vincent Blavet <vincent@phpconcept.net>
  36. * @copyright 1997-2010 The Authors
  37. * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
  38. * @version CVS: $Id$
  39. * @link http://pear.php.net/package/Archive_Tar
  40. */
  41.  
  42. require_once(_PS_TOOL_DIR_.'pear/PEAR.php');
  43.  
  44. define('ARCHIVE_TAR_ATT_SEPARATOR', 90001);
  45. define('ARCHIVE_TAR_END_BLOCK', pack("a512", ''));
  46.  
  47. /**
  48. * Creates a (compressed) Tar archive
  49. *
  50. * @package Archive_Tar
  51. * @author Vincent Blavet <vincent@phpconcept.net>
  52. * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
  53. * @version $Revision$
  54. */
  55. class Archive_Tar extends PEAR
  56. {
  57. /**
  58. * @var string Name of the Tar
  59. */
  60. var $_tarname='';
  61.  
  62. /**
  63. * @var boolean if true, the Tar file will be gzipped
  64. */
  65. var $_compress=false;
  66.  
  67. /**
  68. * @var string Type of compression : 'none', 'gz' or 'bz2'
  69. */
  70. var $_compress_type='none';
  71.  
  72. /**
  73. * @var string Explode separator
  74. */
  75. var $_separator=' ';
  76.  
  77. /**
  78. * @var file descriptor
  79. */
  80. var $_file=0;
  81.  
  82. /**
  83. * @var string Local Tar name of a remote Tar (http:// or ftp://)
  84. */
  85. var $_temp_tarname='';
  86.  
  87. /**
  88. * @var string regular expression for ignoring files or directories
  89. */
  90. var $_ignore_regexp='';
  91.  
  92. /**
  93. * @var object PEAR_Error object
  94. */
  95. var $error_object=null;
  96.  
  97. // {{{ constructor
  98. /**
  99. * Archive_Tar Class constructor. This flavour of the constructor only
  100. * declare a new Archive_Tar object, identifying it by the name of the
  101. * tar file.
  102. * If the compress argument is set the tar will be read or created as a
  103. * gzip or bz2 compressed TAR file.
  104. *
  105. * @param string $p_tarname The name of the tar archive to create
  106. * @param string $p_compress can be null, 'gz' or 'bz2'. This
  107. * parameter indicates if gzip or bz2 compression
  108. * is required. For compatibility reason the
  109. * boolean value 'true' means 'gz'.
  110. *
  111. * @access public
  112. */
  113. function Archive_Tar($p_tarname, $p_compress = null)
  114. {
  115. $this->PEAR();
  116. $this->_compress = false;
  117. $this->_compress_type = 'none';
  118. if (($p_compress === null) || ($p_compress == '')) {
  119. if (@file_exists($p_tarname)) {
  120. if ($fp = @fopen($p_tarname, "rb")) {
  121. // look for gzip magic cookie
  122. $data = fread($fp, 2);
  123. fclose($fp);
  124. if ($data == "\37\213") {
  125. $this->_compress = true;
  126. $this->_compress_type = 'gz';
  127. // No sure it's enought for a magic code ....
  128. } elseif ($data == "BZ") {
  129. $this->_compress = true;
  130. $this->_compress_type = 'bz2';
  131. }
  132. }
  133. } else {
  134. // probably a remote file or some file accessible
  135. // through a stream interface
  136. if (substr($p_tarname, -2) == 'gz') {
  137. $this->_compress = true;
  138. $this->_compress_type = 'gz';
  139. } elseif ((substr($p_tarname, -3) == 'bz2') ||
  140. (substr($p_tarname, -2) == 'bz')) {
  141. $this->_compress = true;
  142. $this->_compress_type = 'bz2';
  143. }
  144. }
  145. } else {
  146. if (($p_compress === true) || ($p_compress == 'gz')) {
  147. $this->_compress = true;
  148. $this->_compress_type = 'gz';
  149. } else if ($p_compress == 'bz2') {
  150. $this->_compress = true;
  151. $this->_compress_type = 'bz2';
  152. } else {
  153. return $this->_error("Unsupported compression type '$p_compress'\n".
  154. "Supported types are 'gz' and 'bz2'.\n");
  155. return false;
  156. }
  157. }
  158. $this->_tarname = $p_tarname;
  159. if ($this->_compress) { // assert zlib or bz2 extension support
  160. if ($this->_compress_type == 'gz')
  161. $extname = 'zlib';
  162. else if ($this->_compress_type == 'bz2')
  163. $extname = 'bz2';
  164.  
  165. if (!extension_loaded($extname)) {
  166. PEAR::loadExtension($extname);
  167. }
  168. if (!extension_loaded($extname)) {
  169. return $this->_error("The extension '$extname' couldn't be found.\n".
  170. "Please make sure your version of PHP was built ".
  171. "with '$extname' support.\n");
  172. return false;
  173. }
  174. }
  175. }
  176. // }}}
  177.  
  178. // {{{ destructor
  179. function _Archive_Tar()
  180. {
  181. $this->_close();
  182. // ----- Look for a local copy to delete
  183. if ($this->_temp_tarname != '')
  184. @unlink($this->_temp_tarname);
  185. $this->_PEAR();
  186. }
  187. // }}}
  188.  
  189. // {{{ create()
  190. /**
  191. * This method creates the archive file and add the files / directories
  192. * that are listed in $p_filelist.
  193. * If a file with the same name exist and is writable, it is replaced
  194. * by the new tar.
  195. * The method return false and a PEAR error text.
  196. * The $p_filelist parameter can be an array of string, each string
  197. * representing a filename or a directory name with their path if
  198. * needed. It can also be a single string with names separated by a
  199. * single blank.
  200. * For each directory added in the archive, the files and
  201. * sub-directories are also added.
  202. * See also createModify() method for more details.
  203. *
  204. * @param array $p_filelist An array of filenames and directory names, or a
  205. * single string with names separated by a single
  206. * blank space.
  207. *
  208. * @return true on success, false on error.
  209. * @see createModify()
  210. * @access public
  211. */
  212. function create($p_filelist)
  213. {
  214. return $this->createModify($p_filelist, '', '');
  215. }
  216. // }}}
  217.  
  218. // {{{ add()
  219. /**
  220. * This method add the files / directories that are listed in $p_filelist in
  221. * the archive. If the archive does not exist it is created.
  222. * The method return false and a PEAR error text.
  223. * The files and directories listed are only added at the end of the archive,
  224. * even if a file with the same name is already archived.
  225. * See also createModify() method for more details.
  226. *
  227. * @param array $p_filelist An array of filenames and directory names, or a
  228. * single string with names separated by a single
  229. * blank space.
  230. *
  231. * @return true on success, false on error.
  232. * @see createModify()
  233. * @access public
  234. */
  235. function add($p_filelist)
  236. {
  237. return $this->addModify($p_filelist, '', '');
  238. }
  239. // }}}
  240.  
  241. // {{{ extract()
  242. function extract($p_path='', $p_preserve=false)
  243. {
  244. return $this->extractModify($p_path, '', $p_preserve);
  245. }
  246. // }}}
  247.  
  248. // {{{ listContent()
  249. function listContent()
  250. {
  251. $v_list_detail = array();
  252.  
  253. if ($this->_openRead()) {
  254. if (!$this->_extractList('', $v_list_detail, "list", '', '')) {
  255. unset($v_list_detail);
  256. $v_list_detail = 0;
  257. }
  258. $this->_close();
  259. }
  260.  
  261. return $v_list_detail;
  262. }
  263. // }}}
  264.  
  265. // {{{ createModify()
  266. /**
  267. * This method creates the archive file and add the files / directories
  268. * that are listed in $p_filelist.
  269. * If the file already exists and is writable, it is replaced by the
  270. * new tar. It is a create and not an add. If the file exists and is
  271. * read-only or is a directory it is not replaced. The method return
  272. * false and a PEAR error text.
  273. * The $p_filelist parameter can be an array of string, each string
  274. * representing a filename or a directory name with their path if
  275. * needed. It can also be a single string with names separated by a
  276. * single blank.
  277. * The path indicated in $p_remove_dir will be removed from the
  278. * memorized path of each file / directory listed when this path
  279. * exists. By default nothing is removed (empty path '')
  280. * The path indicated in $p_add_dir will be added at the beginning of
  281. * the memorized path of each file / directory listed. However it can
  282. * be set to empty ''. The adding of a path is done after the removing
  283. * of path.
  284. * The path add/remove ability enables the user to prepare an archive
  285. * for extraction in a different path than the origin files are.
  286. * See also addModify() method for file adding properties.
  287. *
  288. * @param array $p_filelist An array of filenames and directory names,
  289. * or a single string with names separated by
  290. * a single blank space.
  291. * @param string $p_add_dir A string which contains a path to be added
  292. * to the memorized path of each element in
  293. * the list.
  294. * @param string $p_remove_dir A string which contains a path to be
  295. * removed from the memorized path of each
  296. * element in the list, when relevant.
  297. *
  298. * @return boolean true on success, false on error.
  299. * @access public
  300. * @see addModify()
  301. */
  302. function createModify($p_filelist, $p_add_dir, $p_remove_dir='')
  303. {
  304. $v_result = true;
  305.  
  306. if (!$this->_openWrite())
  307. return false;
  308.  
  309. if ($p_filelist != '') {
  310. if (is_array($p_filelist))
  311. $v_list = $p_filelist;
  312. elseif (is_string($p_filelist))
  313. $v_list = explode($this->_separator, $p_filelist);
  314. else {
  315. $this->_cleanFile();
  316. return $this->_error('Invalid file list');
  317. return false;
  318. }
  319.  
  320. $v_result = $this->_addList($v_list, $p_add_dir, $p_remove_dir);
  321. }
  322.  
  323. if ($v_result) {
  324. $this->_writeFooter();
  325. $this->_close();
  326. } else
  327. $this->_cleanFile();
  328.  
  329. return $v_result;
  330. }
  331. // }}}
  332.  
  333. // {{{ addModify()
  334. /**
  335. * This method add the files / directories listed in $p_filelist at the
  336. * end of the existing archive. If the archive does not yet exists it
  337. * is created.
  338. * The $p_filelist parameter can be an array of string, each string
  339. * representing a filename or a directory name with their path if
  340. * needed. It can also be a single string with names separated by a
  341. * single blank.
  342. * The path indicated in $p_remove_dir will be removed from the
  343. * memorized path of each file / directory listed when this path
  344. * exists. By default nothing is removed (empty path '')
  345. * The path indicated in $p_add_dir will be added at the beginning of
  346. * the memorized path of each file / directory listed. However it can
  347. * be set to empty ''. The adding of a path is done after the removing
  348. * of path.
  349. * The path add/remove ability enables the user to prepare an archive
  350. * for extraction in a different path than the origin files are.
  351. * If a file/dir is already in the archive it will only be added at the
  352. * end of the archive. There is no update of the existing archived
  353. * file/dir. However while extracting the archive, the last file will
  354. * replace the first one. This results in a none optimization of the
  355. * archive size.
  356. * If a file/dir does not exist the file/dir is ignored. However an
  357. * error text is send to PEAR error.
  358. * If a file/dir is not readable the file/dir is ignored. However an
  359. * error text is send to PEAR error.
  360. *
  361. * @param array $p_filelist An array of filenames and directory
  362. * names, or a single string with names
  363. * separated by a single blank space.
  364. * @param string $p_add_dir A string which contains a path to be
  365. * added to the memorized path of each
  366. * element in the list.
  367. * @param string $p_remove_dir A string which contains a path to be
  368. * removed from the memorized path of
  369. * each element in the list, when
  370. * relevant.
  371. *
  372. * @return true on success, false on error.
  373. * @access public
  374. */
  375. function addModify($p_filelist, $p_add_dir, $p_remove_dir='')
  376. {
  377. $v_result = true;
  378.  
  379. if (!$this->_isArchive())
  380. $v_result = $this->createModify($p_filelist, $p_add_dir,
  381. $p_remove_dir);
  382. else {
  383. if (is_array($p_filelist))
  384. $v_list = $p_filelist;
  385. elseif (is_string($p_filelist))
  386. $v_list = explode($this->_separator, $p_filelist);
  387. else {
  388. return $this->_error('Invalid file list');
  389. return false;
  390. }
  391.  
  392. $v_result = $this->_append($v_list, $p_add_dir, $p_remove_dir);
  393. }
  394.  
  395. return $v_result;
  396. }
  397. // }}}
  398.  
  399. // {{{ addString()
  400. /**
  401. * This method add a single string as a file at the
  402. * end of the existing archive. If the archive does not yet exists it
  403. * is created.
  404. *
  405. * @param string $p_filename A string which contains the full
  406. * filename path that will be associated
  407. * with the string.
  408. * @param string $p_string The content of the file added in
  409. * the archive.
  410. * @param int $p_datetime A custom date/time (unix timestamp)
  411. * for the file (optional).
  412. *
  413. * @return true on success, false on error.
  414. * @access public
  415. */
  416. function addString($p_filename, $p_string, $p_datetime = false)
  417. {
  418. $v_result = true;
  419.  
  420. if (!$this->_isArchive()) {
  421. if (!$this->_openWrite()) {
  422. return false;
  423. }
  424. $this->_close();
  425. }
  426.  
  427. if (!$this->_openAppend())
  428. return false;
  429.  
  430. // Need to check the get back to the temporary file ? ....
  431. $v_result = $this->_addString($p_filename, $p_string, $p_datetime);
  432.  
  433. $this->_writeFooter();
  434.  
  435. $this->_close();
  436.  
  437. return $v_result;
  438. }
  439. // }}}
  440.  
  441. // {{{ extractModify()
  442. /**
  443. * This method extract all the content of the archive in the directory
  444. * indicated by $p_path. When relevant the memorized path of the
  445. * files/dir can be modified by removing the $p_remove_path path at the
  446. * beginning of the file/dir path.
  447. * While extracting a file, if the directory path does not exists it is
  448. * created.
  449. * While extracting a file, if the file already exists it is replaced
  450. * without looking for last modification date.
  451. * While extracting a file, if the file already exists and is write
  452. * protected, the extraction is aborted.
  453. * While extracting a file, if a directory with the same name already
  454. * exists, the extraction is aborted.
  455. * While extracting a directory, if a file with the same name already
  456. * exists, the extraction is aborted.
  457. * While extracting a file/directory if the destination directory exist
  458. * and is write protected, or does not exist but can not be created,
  459. * the extraction is aborted.
  460. * If after extraction an extracted file does not show the correct
  461. * stored file size, the extraction is aborted.
  462. * When the extraction is aborted, a PEAR error text is set and false
  463. * is returned. However the result can be a partial extraction that may
  464. * need to be manually cleaned.
  465. *
  466. * @param string $p_path The path of the directory where the
  467. * files/dir need to by extracted.
  468. * @param string $p_remove_path Part of the memorized path that can be
  469. * removed if present at the beginning of
  470. * the file/dir path.
  471. * @param boolean $p_preserve Preserve user/group ownership of files
  472. *
  473. * @return boolean true on success, false on error.
  474. * @access public
  475. * @see extractList()
  476. */
  477. function extractModify($p_path, $p_remove_path, $p_preserve=false)
  478. {
  479. $v_result = true;
  480. $v_list_detail = array();
  481.  
  482. if ($v_result = $this->_openRead()) {
  483. $v_result = $this->_extractList($p_path, $v_list_detail,
  484. "complete", 0, $p_remove_path, $p_preserve);
  485. $this->_close();
  486. }
  487.  
  488. return $v_result;
  489. }
  490. // }}}
  491.  
  492. // {{{ extractInString()
  493. /**
  494. * This method extract from the archive one file identified by $p_filename.
  495. * The return value is a string with the file content, or NULL on error.
  496. *
  497. * @param string $p_filename The path of the file to extract in a string.
  498. *
  499. * @return a string with the file content or NULL.
  500. * @access public
  501. */
  502. function extractInString($p_filename)
  503. {
  504. if ($this->_openRead()) {
  505. $v_result = $this->_extractInString($p_filename);
  506. $this->_close();
  507. } else {
  508. $v_result = null;
  509. }
  510.  
  511. return $v_result;
  512. }
  513. // }}}
  514.  
  515. // {{{ extractList()
  516. /**
  517. * This method extract from the archive only the files indicated in the
  518. * $p_filelist. These files are extracted in the current directory or
  519. * in the directory indicated by the optional $p_path parameter.
  520. * If indicated the $p_remove_path can be used in the same way as it is
  521. * used in extractModify() method.
  522. *
  523. * @param array $p_filelist An array of filenames and directory names,
  524. * or a single string with names separated
  525. * by a single blank space.
  526. * @param string $p_path The path of the directory where the
  527. * files/dir need to by extracted.
  528. * @param string $p_remove_path Part of the memorized path that can be
  529. * removed if present at the beginning of
  530. * the file/dir path.
  531. * @param boolean $p_preserve Preserve user/group ownership of files
  532. *
  533. * @return true on success, false on error.
  534. * @access public
  535. * @see extractModify()
  536. */
  537. function extractList($p_filelist, $p_path='', $p_remove_path='', $p_preserve=false)
  538. {
  539. $v_result = true;
  540. $v_list_detail = array();
  541.  
  542. if (is_array($p_filelist))
  543. $v_list = $p_filelist;
  544. elseif (is_string($p_filelist))
  545. $v_list = explode($this->_separator, $p_filelist);
  546. else {
  547. return $this->_error('Invalid string list');
  548. return false;
  549. }
  550.  
  551. if ($v_result = $this->_openRead()) {
  552. $v_result = $this->_extractList($p_path, $v_list_detail, "partial",
  553. $v_list, $p_remove_path, $p_preserve);
  554. $this->_close();
  555. }
  556.  
  557. return $v_result;
  558. }
  559. // }}}
  560.  
  561. // {{{ setAttribute()
  562. /**
  563. * This method set specific attributes of the archive. It uses a variable
  564. * list of parameters, in the format attribute code + attribute values :
  565. * $arch->setAttribute(ARCHIVE_TAR_ATT_SEPARATOR, ',');
  566. *
  567. * @param mixed $argv variable list of attributes and values
  568. *
  569. * @return true on success, false on error.
  570. * @access public
  571. */
  572. function setAttribute()
  573. {
  574. $v_result = true;
  575.  
  576. // ----- Get the number of variable list of arguments
  577. if (($v_size = func_num_args()) == 0) {
  578. return true;
  579. }
  580.  
  581. // ----- Get the arguments
  582. $v_att_list = &func_get_args();
  583.  
  584. // ----- Read the attributes
  585. $i=0;
  586. while ($i<$v_size) {
  587.  
  588. // ----- Look for next option
  589. switch ($v_att_list[$i]) {
  590. // ----- Look for options that request a string value
  591. case ARCHIVE_TAR_ATT_SEPARATOR :
  592. // ----- Check the number of parameters
  593. if (($i+1) >= $v_size) {
  594. return $this->_error('Invalid number of parameters for '
  595. .'attribute ARCHIVE_TAR_ATT_SEPARATOR');
  596. return false;
  597. }
  598.  
  599. // ----- Get the value
  600. $this->_separator = $v_att_list[$i+1];
  601. $i++;
  602. break;
  603.  
  604. default :
  605. return $this->_error('Unknow attribute code '.$v_att_list[$i].'');
  606. return false;
  607. }
  608.  
  609. // ----- Next attribute
  610. $i++;
  611. }
  612.  
  613. return $v_result;
  614. }
  615. // }}}
  616.  
  617. // {{{ setIgnoreRegexp()
  618. /**
  619. * This method sets the regular expression for ignoring files and directories
  620. * at import, for example:
  621. * $arch->setIgnoreRegexp("#CVS|\.svn#");
  622. *
  623. * @param string $regexp regular expression defining which files or directories to ignore
  624. *
  625. * @access public
  626. */
  627. function setIgnoreRegexp($regexp)
  628. {
  629. $this->_ignore_regexp = $regexp;
  630. }
  631. // }}}
  632.  
  633. // {{{ setIgnoreList()
  634. /**
  635. * This method sets the regular expression for ignoring all files and directories
  636. * matching the filenames in the array list at import, for example:
  637. * $arch->setIgnoreList(array('CVS', '.svn', 'bin/tool'));
  638. *
  639. * @param array $list a list of file or directory names to ignore
  640. *
  641. * @access public
  642. */
  643. function setIgnoreList($list)
  644. {
  645. $regexp = str_replace(array('#', '.', '^', '$'), array('\#', '\.', '\^', '\$'), $list);
  646. $regexp = '#/'.join('$|/', $list).'#';
  647. $this->setIgnoreRegexp($regexp);
  648. }
  649. // }}}
  650.  
  651. // {{{ _error()
  652. function _error($p_message)
  653. {
  654. $this->error_object = &$this->raiseError($p_message);
  655. return $this->error_object;
  656. }
  657. // }}}
  658.  
  659. // {{{ _warning()
  660. function _warning($p_message)
  661. {
  662. $this->error_object = &$this->raiseError($p_message);
  663. return $this->error_object;
  664. }
  665. // }}}
  666.  
  667. // {{{ _isArchive()
  668. function _isArchive($p_filename=null)
  669. {
  670. if ($p_filename == null) {
  671. $p_filename = $this->_tarname;
  672. }
  673. clearstatcache();
  674. return @is_file($p_filename) && !@is_link($p_filename);
  675. }
  676. // }}}
  677.  
  678. // {{{ _openWrite()
  679. function _openWrite()
  680. {
  681. if ($this->_compress_type == 'gz' && function_exists('gzopen'))
  682. $this->_file = @gzopen($this->_tarname, "wb9");
  683. else if ($this->_compress_type == 'bz2' && function_exists('bzopen'))
  684. $this->_file = @bzopen($this->_tarname, "w");
  685. else if ($this->_compress_type == 'none')
  686. $this->_file = @fopen($this->_tarname, "wb");
  687. else {
  688. return $this->_error('Unknown or missing compression type ('
  689. .$this->_compress_type.')');
  690. return false;
  691. }
  692.  
  693. if ($this->_file == 0) {
  694. return $this->_error('Unable to open in write mode \''
  695. .$this->_tarname.'\'');
  696. return false;
  697. }
  698.  
  699. return true;
  700. }
  701. // }}}
  702.  
  703. // {{{ _openRead()
  704. function _openRead()
  705. {
  706. if (strtolower(substr($this->_tarname, 0, 7)) == 'http://') {
  707.  
  708. // ----- Look if a local copy need to be done
  709. if ($this->_temp_tarname == '') {
  710. $this->_temp_tarname = uniqid('tar').'.tmp';
  711. if (!$v_file_from = @fopen($this->_tarname, 'rb')) {
  712. $this->_temp_tarname = '';
  713. return $this->_error('Unable to open in read mode \''
  714. .$this->_tarname.'\'');
  715. return false;
  716. }
  717. if (!$v_file_to = @fopen($this->_temp_tarname, 'wb')) {
  718. $this->_temp_tarname = '';
  719. return $this->_error('Unable to open in write mode \''
  720. .$this->_temp_tarname.'\'');
  721. return false;
  722. }
  723. while ($v_data = @fread($v_file_from, 1024))
  724. @fwrite($v_file_to, $v_data);
  725. @fclose($v_file_from);
  726. @fclose($v_file_to);
  727. }
  728.  
  729. // ----- File to open if the local copy
  730. $v_filename = $this->_temp_tarname;
  731.  
  732. } else
  733. // ----- File to open if the normal Tar file
  734. $v_filename = $this->_tarname;
  735.  
  736. if ($this->_compress_type == 'gz' && function_exists('gzopen'))
  737. $this->_file = @gzopen($v_filename, "rb");
  738. else if ($this->_compress_type == 'bz2' && function_exists('bzopen'))
  739. $this->_file = @bzopen($v_filename, "r");
  740. else if ($this->_compress_type == 'none')
  741. $this->_file = @fopen($v_filename, "rb");
  742. else {
  743. return $this->_error('Unknown or missing compression type ('
  744. .$this->_compress_type.')');
  745. return false;
  746. }
  747.  
  748. if ($this->_file == 0) {
  749. return $this->_error('Unable to open in read mode \''.$v_filename.'\'');
  750. return false;
  751. }
  752.  
  753. return true;
  754. }
  755. // }}}
  756.  
  757. // {{{ _openReadWrite()
  758. function _openReadWrite()
  759. {
  760. if ($this->_compress_type == 'gz')
  761. $this->_file = @gzopen($this->_tarname, "r+b");
  762. else if ($this->_compress_type == 'bz2') {
  763. return $this->_error('Unable to open bz2 in read/write mode \''
  764. .$this->_tarname.'\' (limitation of bz2 extension)');
  765. return false;
  766. } else if ($this->_compress_type == 'none')
  767. $this->_file = @fopen($this->_tarname, "r+b");
  768. else {
  769. return $this->_error('Unknown or missing compression type ('
  770. .$this->_compress_type.')');
  771. return false;
  772. }
  773.  
  774. if ($this->_file == 0) {
  775. return $this->_error('Unable to open in read/write mode \''
  776. .$this->_tarname.'\'');
  777. return false;
  778. }
  779.  
  780. return true;
  781. }
  782. // }}}
  783.  
  784. // {{{ _close()
  785. function _close()
  786. {
  787. //if (isset($this->_file)) {
  788. if (is_resource($this->_file)) {
  789. if ($this->_compress_type == 'gz')
  790. @gzclose($this->_file);
  791. else if ($this->_compress_type == 'bz2')
  792. @bzclose($this->_file);
  793. else if ($this->_compress_type == 'none')
  794. @fclose($this->_file);
  795. else
  796. $this->_error('Unknown or missing compression type ('
  797. .$this->_compress_type.')');
  798.  
  799. $this->_file = 0;
  800. }
  801.  
  802. // ----- Look if a local copy need to be erase
  803. // Note that it might be interesting to keep the url for a time : ToDo
  804. if ($this->_temp_tarname != '') {
  805. @unlink($this->_temp_tarname);
  806. $this->_temp_tarname = '';
  807. }
  808.  
  809. return true;
  810. }
  811. // }}}
  812.  
  813. // {{{ _cleanFile()
  814. function _cleanFile()
  815. {
  816. $this->_close();
  817.  
  818. // ----- Look for a local copy
  819. if ($this->_temp_tarname != '') {
  820. // ----- Remove the local copy but not the remote tarname
  821. @unlink($this->_temp_tarname);
  822. $this->_temp_tarname = '';
  823. } else {
  824. // ----- Remove the local tarname file
  825. @unlink($this->_tarname);
  826. }
  827. $this->_tarname = '';
  828.  
  829. return true;
  830. }
  831. // }}}
  832.  
  833. // {{{ _writeBlock()
  834. function _writeBlock($p_binary_data, $p_len=null)
  835. {
  836. if (is_resource($this->_file)) {
  837. if ($p_len === null) {
  838. if ($this->_compress_type == 'gz')
  839. @gzputs($this->_file, $p_binary_data);
  840. else if ($this->_compress_type == 'bz2')
  841. @bzwrite($this->_file, $p_binary_data);
  842. else if ($this->_compress_type == 'none')
  843. @fputs($this->_file, $p_binary_data);
  844. else
  845. $this->_error('Unknown or missing compression type ('
  846. .$this->_compress_type.')');
  847. } else {
  848. if ($this->_compress_type == 'gz')
  849. @gzputs($this->_file, $p_binary_data, $p_len);
  850. else if ($this->_compress_type == 'bz2')
  851. @bzwrite($this->_file, $p_binary_data, $p_len);
  852. else if ($this->_compress_type == 'none')
  853. @fputs($this->_file, $p_binary_data, $p_len);
  854. else
  855. $this->_error('Unknown or missing compression type ('
  856. .$this->_compress_type.')');
  857.  
  858. }
  859. }
  860. return true;
  861. }
  862. // }}}
  863.  
  864. // {{{ _readBlock()
  865. function _readBlock()
  866. {
  867. $v_block = null;
  868. if (is_resource($this->_file)) {
  869. if ($this->_compress_type == 'gz')
  870. $v_block = @gzread($this->_file, 512);
  871. else if ($this->_compress_type == 'bz2')
  872. $v_block = @bzread($this->_file, 512);
  873. else if ($this->_compress_type == 'none')
  874. $v_block = @fread($this->_file, 512);
  875. else
  876. return $this->_error('Unknown or missing compression type ('
  877. .$this->_compress_type.')');
  878. }
  879. return $v_block;
  880. }
  881. // }}}
  882.  
  883. // {{{ _jumpBlock()
  884. function _jumpBlock($p_len=null)
  885. {
  886. if (is_resource($this->_file)) {
  887. if ($p_len === null)
  888. $p_len = 1;
  889.  
  890. if ($this->_compress_type == 'gz') {
  891. @gzseek($this->_file, gztell($this->_file)+($p_len*512));
  892. }
  893. else if ($this->_compress_type == 'bz2') {
  894. // ----- Replace missing bztell() and bzseek()
  895. for ($i=0; $i<$p_len; $i++)
  896. $this->_readBlock();
  897. } else if ($this->_compress_type == 'none')
  898. @fseek($this->_file, $p_len*512, SEEK_CUR);
  899. else
  900. return $this->_error('Unknown or missing compression type ('
  901. .$this->_compress_type.')');
  902.  
  903. }
  904. return true;
  905. }
  906. // }}}
  907.  
  908. // {{{ _writeFooter()
  909. function _writeFooter()
  910. {
  911. if (is_resource($this->_file)) {
  912. // ----- Write the last 0 filled block for end of archive
  913. $v_binary_data = pack('a1024', '');
  914. $this->_writeBlock($v_binary_data);
  915. }
  916. return true;
  917. }
  918. // }}}
  919.  
  920. // {{{ _addList()
  921. function _addList($p_list, $p_add_dir, $p_remove_dir)
  922. {
  923. $v_result=true;
  924. $v_header = array();
  925.  
  926. // ----- Remove potential windows directory separator
  927. $p_add_dir = $this->_translateWinPath($p_add_dir);
  928. $p_remove_dir = $this->_translateWinPath($p_remove_dir, false);
  929.  
  930. if (!$this->_file) {
  931. return $this->_error('Invalid file descriptor');
  932. return false;
  933. }
  934.  
  935. if (sizeof($p_list) == 0)
  936. return true;
  937.  
  938. foreach ($p_list as $v_filename) {
  939. if (!$v_result) {
  940. break;
  941. }
  942.  
  943. // ----- Skip the current tar name
  944. if ($v_filename == $this->_tarname)
  945. continue;
  946.  
  947. if ($v_filename == '')
  948. continue;
  949.  
  950. // ----- ignore files and directories matching the ignore regular expression
  951. if ($this->_ignore_regexp && preg_match($this->_ignore_regexp, '/'.$v_filename)) {
  952. $this->_warning("File '$v_filename' ignored");
  953. continue;
  954. }
  955.  
  956. if (!file_exists($v_filename) && !is_link($v_filename)) {
  957. $this->_warning("File '$v_filename' does not exist");
  958. continue;
  959. }
  960.  
  961. // ----- Add the file or directory header
  962. if (!$this->_addFile($v_filename, $v_header, $p_add_dir, $p_remove_dir))
  963. return false;
  964.  
  965. if (@is_dir($v_filename) && !@is_link($v_filename)) {
  966. if (!($p_hdir = opendir($v_filename))) {
  967. $this->_warning("Directory '$v_filename' can not be read");
  968. continue;
  969. }
  970. while (false !== ($p_hitem = readdir($p_hdir))) {
  971. if (($p_hitem != '.') && ($p_hitem != '..')) {
  972. if ($v_filename != ".")
  973. $p_temp_list[0] = $v_filename.'/'.$p_hitem;
  974. else
  975. $p_temp_list[0] = $p_hitem;
  976.  
  977. $v_result = $this->_addList($p_temp_list,
  978. $p_add_dir,
  979. $p_remove_dir);
  980. }
  981. }
  982.  
  983. unset($p_temp_list);
  984. unset($p_hdir);
  985. unset($p_hitem);
  986. }
  987. }
  988.  
  989. return $v_result;
  990. }
  991. // }}}
  992.  
  993. // {{{ _addFile()
  994. function _addFile($p_filename, &$p_header, $p_add_dir, $p_remove_dir)
  995. {
  996. if (!$this->_file) {
  997. return $this->_error('Invalid file descriptor');
  998. return false;
  999. }
  1000.  
  1001. if ($p_filename == '') {
  1002. return $this->_error('Invalid file name');
  1003. return false;
  1004. }
  1005.  
  1006. // ----- Calculate the stored filename
  1007. $p_filename = $this->_translateWinPath($p_filename, false);;
  1008. $v_stored_filename = $p_filename;
  1009. if (strcmp($p_filename, $p_remove_dir) == 0) {
  1010. return true;
  1011. }
  1012. if ($p_remove_dir != '') {
  1013. if (substr($p_remove_dir, -1) != '/')
  1014. $p_remove_dir .= '/';
  1015.  
  1016. if (substr($p_filename, 0, strlen($p_remove_dir)) == $p_remove_dir)
  1017. $v_stored_filename = substr($p_filename, strlen($p_remove_dir));
  1018. }
  1019. $v_stored_filename = $this->_translateWinPath($v_stored_filename);
  1020. if ($p_add_dir != '') {
  1021. if (substr($p_add_dir, -1) == '/')
  1022. $v_stored_filename = $p_add_dir.$v_stored_filename;
  1023. else
  1024. $v_stored_filename = $p_add_dir.'/'.$v_stored_filename;
  1025. }
  1026.  
  1027. $v_stored_filename = $this->_pathReduction($v_stored_filename);
  1028.  
  1029. if ($this->_isArchive($p_filename)) {
  1030. if (($v_file = @fopen($p_filename, "rb")) == 0) {
  1031. $this->_warning("Unable to open file '".$p_filename
  1032. ."' in binary read mode");
  1033. return true;
  1034. }
  1035.  
  1036. if (!$this->_writeHeader($p_filename, $v_stored_filename))
  1037. return false;
  1038.  
  1039. while (($v_buffer = fread($v_file, 512)) != '') {
  1040. $v_binary_data = pack("a512", "$v_buffer");
  1041. $this->_writeBlock($v_binary_data);
  1042. }
  1043.  
  1044. fclose($v_file);
  1045.  
  1046. } else {
  1047. // ----- Only header for dir
  1048. if (!$this->_writeHeader($p_filename, $v_stored_filename))
  1049. return false;
  1050. }
  1051.  
  1052. return true;
  1053. }
  1054. // }}}
  1055.  
  1056. // {{{ _addString()
  1057. function _addString($p_filename, $p_string, $p_datetime = false)
  1058. {
  1059. if (!$this->_file) {
  1060. return $this->_error('Invalid file descriptor');
  1061. return false;
  1062. }
  1063.  
  1064. if ($p_filename == '') {
  1065. return $this->_error('Invalid file name');
  1066. return false;
  1067. }
  1068.  
  1069. // ----- Calculate the stored filename
  1070. $p_filename = $this->_translateWinPath($p_filename, false);;
  1071.  
  1072. // ----- If datetime is not specified, set current time
  1073. if ($p_datetime === false) {
  1074. $p_datetime = time();
  1075. }
  1076.  
  1077. if (!$this->_writeHeaderBlock($p_filename, strlen($p_string),
  1078. $p_datetime, 384, "", 0, 0))
  1079. return false;
  1080.  
  1081. $i=0;
  1082. while (($v_buffer = substr($p_string, (($i++)*512), 512)) != '') {
  1083. $v_binary_data = pack("a512", $v_buffer);
  1084. $this->_writeBlock($v_binary_data);
  1085. }
  1086.  
  1087. return true;
  1088. }
  1089. // }}}
  1090.  
  1091. // {{{ _writeHeader()
  1092. function _writeHeader($p_filename, $p_stored_filename)
  1093. {
  1094. if ($p_stored_filename == '')
  1095. $p_stored_filename = $p_filename;
  1096. $v_reduce_filename = $this->_pathReduction($p_stored_filename);
  1097.  
  1098. if (strlen($v_reduce_filename) > 99) {
  1099. if (!$this->_writeLongHeader($v_reduce_filename))
  1100. return false;
  1101. }
  1102.  
  1103. $v_info = lstat($p_filename);
  1104. $v_uid = sprintf("%07s", DecOct($v_info[4]));
  1105. $v_gid = sprintf("%07s", DecOct($v_info[5]));
  1106. $v_perms = sprintf("%07s", DecOct($v_info['mode'] & 000777));
  1107.  
  1108. $v_mtime = sprintf("%011s", DecOct($v_info['mtime']));
  1109.  
  1110. $v_linkname = '';
  1111.  
  1112. if (@is_link($p_filename)) {
  1113. $v_typeflag = '2';
  1114. $v_linkname = readlink($p_filename);
  1115. $v_size = sprintf("%011s", DecOct(0));
  1116. } elseif (@is_dir($p_filename)) {
  1117. $v_typeflag = "5";
  1118. $v_size = sprintf("%011s", DecOct(0));
  1119. } else {
  1120. $v_typeflag = '0';
  1121. clearstatcache();
  1122. $v_size = sprintf("%011s", DecOct($v_info['size']));
  1123. }
  1124.  
  1125. $v_magic = 'ustar ';
  1126.  
  1127. $v_version = ' ';
  1128.  
  1129. if (function_exists('posix_getpwuid'))
  1130. {
  1131. $userinfo = posix_getpwuid($v_info[4]);
  1132. $groupinfo = posix_getgrgid($v_info[5]);
  1133.  
  1134. $v_uname = $userinfo['name'];
  1135. $v_gname = $groupinfo['name'];
  1136. }
  1137. else
  1138. {
  1139. $v_uname = '';
  1140. $v_gname = '';
  1141. }
  1142.  
  1143. $v_devmajor = '';
  1144.  
  1145. $v_devminor = '';
  1146.  
  1147. $v_prefix = '';
  1148.  
  1149. $v_binary_data_first = pack("a100a8a8a8a12a12",
  1150. $v_reduce_filename, $v_perms, $v_uid,
  1151. $v_gid, $v_size, $v_mtime);
  1152. $v_binary_data_last = pack("a1a100a6a2a32a32a8a8a155a12",
  1153. $v_typeflag, $v_linkname, $v_magic,
  1154. $v_version, $v_uname, $v_gname,
  1155. $v_devmajor, $v_devminor, $v_prefix, '');
  1156.  
  1157. // ----- Calculate the checksum
  1158. $v_checksum = 0;
  1159. // ..... First part of the header
  1160. for ($i=0; $i<148; $i++)
  1161. $v_checksum += ord(substr($v_binary_data_first,$i,1));
  1162. // ..... Ignore the checksum value and replace it by ' ' (space)
  1163. for ($i=148; $i<156; $i++)
  1164. $v_checksum += ord(' ');
  1165. // ..... Last part of the header
  1166. for ($i=156, $j=0; $i<512; $i++, $j++)
  1167. $v_checksum += ord(substr($v_binary_data_last,$j,1));
  1168.  
  1169. // ----- Write the first 148 bytes of the header in the archive
  1170. $this->_writeBlock($v_binary_data_first, 148);
  1171.  
  1172. // ----- Write the calculated checksum
  1173. $v_checksum = sprintf("%06s ", DecOct($v_checksum));
  1174. $v_binary_data = pack("a8", $v_checksum);
  1175. $this->_writeBlock($v_binary_data, 8);
  1176.  
  1177. // ----- Write the last 356 bytes of the header in the archive
  1178. $this->_writeBlock($v_binary_data_last, 356);
  1179.  
  1180. return true;
  1181. }
  1182. // }}}
  1183.  
  1184. // {{{ _writeHeaderBlock()
  1185. function _writeHeaderBlock($p_filename, $p_size, $p_mtime=0, $p_perms=0,
  1186. $p_type='', $p_uid=0, $p_gid=0)
  1187. {
  1188. $p_filename = $this->_pathReduction($p_filename);
  1189.  
  1190. if (strlen($p_filename) > 99) {
  1191. if (!$this->_writeLongHeader($p_filename))
  1192. return false;
  1193. }
  1194.  
  1195. if ($p_type == "5") {
  1196. $v_size = sprintf("%011s", DecOct(0));
  1197. } else {
  1198. $v_size = sprintf("%011s", DecOct($p_size));
  1199. }
  1200.  
  1201. $v_uid = sprintf("%07s", DecOct($p_uid));
  1202. $v_gid = sprintf("%07s", DecOct($p_gid));
  1203. $v_perms = sprintf("%07s", DecOct($p_perms & 000777));
  1204.  
  1205. $v_mtime = sprintf("%11s", DecOct($p_mtime));
  1206.  
  1207. $v_linkname = '';
  1208.  
  1209. $v_magic = 'ustar ';
  1210.  
  1211. $v_version = ' ';
  1212.  
  1213. if (function_exists('posix_getpwuid'))
  1214. {
  1215. $userinfo = posix_getpwuid($p_uid);
  1216. $groupinfo = posix_getgrgid($p_gid);
  1217.  
  1218. $v_uname = $userinfo['name'];
  1219. $v_gname = $groupinfo['name'];
  1220. }
  1221. else
  1222. {
  1223. $v_uname = '';
  1224. $v_gname = '';
  1225. }
  1226.  
  1227. $v_devmajor = '';
  1228.  
  1229. $v_devminor = '';
  1230.  
  1231. $v_prefix = '';
  1232.  
  1233. $v_binary_data_first = pack("a100a8a8a8a12A12",
  1234. $p_filename, $v_perms, $v_uid, $v_gid,
  1235. $v_size, $v_mtime);
  1236. $v_binary_data_last = pack("a1a100a6a2a32a32a8a8a155a12",
  1237. $p_type, $v_linkname, $v_magic,
  1238. $v_version, $v_uname, $v_gname,
  1239. $v_devmajor, $v_devminor, $v_prefix, '');
  1240.  
  1241. // ----- Calculate the checksum
  1242. $v_checksum = 0;
  1243. // ..... First part of the header
  1244. for ($i=0; $i<148; $i++)
  1245. $v_checksum += ord(substr($v_binary_data_first,$i,1));
  1246. // ..... Ignore the checksum value and replace it by ' ' (space)
  1247. for ($i=148; $i<156; $i++)
  1248. $v_checksum += ord(' ');
  1249. // ..... Last part of the header
  1250. for ($i=156, $j=0; $i<512; $i++, $j++)
  1251. $v_checksum += ord(substr($v_binary_data_last,$j,1));
  1252.  
  1253. // ----- Write the first 148 bytes of the header in the archive
  1254. $this->_writeBlock($v_binary_data_first, 148);
  1255.  
  1256. // ----- Write the calculated checksum
  1257. $v_checksum = sprintf("%06s ", DecOct($v_checksum));
  1258. $v_binary_data = pack("a8", $v_checksum);
  1259. $this->_writeBlock($v_binary_data, 8);
  1260.  
  1261. // ----- Write the last 356 bytes of the header in the archive
  1262. $this->_writeBlock($v_binary_data_last, 356);
  1263.  
  1264. return true;
  1265. }
  1266. // }}}
  1267.  
  1268. // {{{ _writeLongHeader()
  1269. function _writeLongHeader($p_filename)
  1270. {
  1271. $v_size = sprintf("%11s ", DecOct(strlen($p_filename)));
  1272.  
  1273. $v_typeflag = 'L';
  1274.  
  1275. $v_linkname = '';
  1276.  
  1277. $v_magic = '';
  1278.  
  1279. $v_version = '';
  1280.  
  1281. $v_uname = '';
  1282.  
  1283. $v_gname = '';
  1284.  
  1285. $v_devmajor = '';
  1286.  
  1287. $v_devminor = '';
  1288.  
  1289. $v_prefix = '';
  1290.  
  1291. $v_binary_data_first = pack("a100a8a8a8a12a12",
  1292. '././@LongLink', 0, 0, 0, $v_size, 0);
  1293. $v_binary_data_last = pack("a1a100a6a2a32a32a8a8a155a12",
  1294. $v_typeflag, $v_linkname, $v_magic,
  1295. $v_version, $v_uname, $v_gname,
  1296. $v_devmajor, $v_devminor, $v_prefix, '');
  1297.  
  1298. // ----- Calculate the checksum
  1299. $v_checksum = 0;
  1300. // ..... First part of the header
  1301. for ($i=0; $i<148; $i++)
  1302. $v_checksum += ord(substr($v_binary_data_first,$i,1));
  1303. // ..... Ignore the checksum value and replace it by ' ' (space)
  1304. for ($i=148; $i<156; $i++)
  1305. $v_checksum += ord(' ');
  1306. // ..... Last part of the header
  1307. for ($i=156, $j=0; $i<512; $i++, $j++)
  1308. $v_checksum += ord(substr($v_binary_data_last,$j,1));
  1309.  
  1310. // ----- Write the first 148 bytes of the header in the archive
  1311. $this->_writeBlock($v_binary_data_first, 148);
  1312.  
  1313. // ----- Write the calculated checksum
  1314. $v_checksum = sprintf("%06s ", DecOct($v_checksum));
  1315. $v_binary_data = pack("a8", $v_checksum);
  1316. $this->_writeBlock($v_binary_data, 8);
  1317.  
  1318. // ----- Write the last 356 bytes of the header in the archive
  1319. $this->_writeBlock($v_binary_data_last, 356);
  1320.  
  1321. // ----- Write the filename as content of the block
  1322. $i=0;
  1323. while (($v_buffer = substr($p_filename, (($i++)*512), 512)) != '') {
  1324. $v_binary_data = pack("a512", "$v_buffer");
  1325. $this->_writeBlock($v_binary_data);
  1326. }
  1327.  
  1328. return true;
  1329. }
  1330. // }}}
  1331.  
  1332. // {{{ _readHeader()
  1333. function _readHeader($v_binary_data, &$v_header)
  1334. {
  1335. if (strlen($v_binary_data)==0) {
  1336. $v_header['filename'] = '';
  1337. return true;
  1338. }
  1339.  
  1340. if (strlen($v_binary_data) != 512) {
  1341. $v_header['filename'] = '';
  1342. return $this->_error('Invalid block size : '.strlen($v_binary_data));
  1343. return false;
  1344. }
  1345.  
  1346. if (!is_array($v_header)) {
  1347. $v_header = array();
  1348. }
  1349. // ----- Calculate the checksum
  1350. $v_checksum = 0;
  1351. // ..... First part of the header
  1352. for ($i=0; $i<148; $i++)
  1353. $v_checksum+=ord(substr($v_binary_data,$i,1));
  1354. // ..... Ignore the checksum value and replace it by ' ' (space)
  1355. for ($i=148; $i<156; $i++)
  1356. $v_checksum += ord(' ');
  1357. // ..... Last part of the header
  1358. for ($i=156; $i<512; $i++)
  1359. $v_checksum+=ord(substr($v_binary_data,$i,1));
  1360.  
  1361. if (version_compare(PHP_VERSION,"5.5.0-dev")<0) {
  1362. $fmt = "a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/" .
  1363. "a8checksum/a1typeflag/a100link/a6magic/a2version/" .
  1364. "a32uname/a32gname/a8devmajor/a8devminor/a131prefix";
  1365. } else {
  1366. $fmt = "Z100filename/Z8mode/Z8uid/Z8gid/Z12size/Z12mtime/" .
  1367. "Z8checksum/Z1typeflag/Z100link/Z6magic/Z2version/" .
  1368. "Z32uname/Z32gname/Z8devmajor/Z8devminor/Z131prefix";
  1369. }
  1370. $v_data = unpack($fmt, $v_binary_data);
  1371.  
  1372. if (strlen($v_data["prefix"]) > 0) {
  1373. $v_data["filename"] = "$v_data[prefix]/$v_data[filename]";
  1374. }
  1375.  
  1376. // ----- Extract the checksum
  1377. $v_header['checksum'] = OctDec(trim($v_data['checksum']));
  1378. if ($v_header['checksum'] != $v_checksum) {
  1379. $v_header['filename'] = '';
  1380.  
  1381. // ----- Look for last block (empty block)
  1382. if (($v_checksum == 256) && ($v_header['checksum'] == 0))
  1383. return true;
  1384.  
  1385. return $this->_error('Invalid checksum for file "'.$v_data['filename']
  1386. .'" : '.$v_checksum.' calculated, '
  1387. .$v_header['checksum'].' expected');
  1388. return false;
  1389. }
  1390.  
  1391. // ----- Extract the properties
  1392. $v_header['filename'] = $v_data['filename'];
  1393. if ($this->_maliciousFilename($v_header['filename'])) {
  1394. return $this->_error('Malicious .tar detected, file "' . $v_header['filename'] .
  1395. '" will not install in desired directory tree');
  1396. return false;
  1397. }
  1398. $v_header['mode'] = OctDec(trim($v_data['mode']));
  1399. $v_header['uid'] = OctDec(trim($v_data['uid']));
  1400. $v_header['gid'] = OctDec(trim($v_data['gid']));
  1401. $v_header['size'] = OctDec(trim($v_data['size']));
  1402. $v_header['mtime'] = OctDec(trim($v_data['mtime']));
  1403. if (($v_header['typeflag'] = $v_data['typeflag']) == "5") {
  1404. $v_header['size'] = 0;
  1405. }
  1406. $v_header['link'] = trim($v_data['link']);
  1407. /* ----- All these fields are removed form the header because
  1408. they do not carry interesting info
  1409. $v_header[magic] = trim($v_data[magic]);
  1410. $v_header[version] = trim($v_data[version]);
  1411. $v_header[uname] = trim($v_data[uname]);
  1412. $v_header[gname] = trim($v_data[gname]);
  1413. $v_header[devmajor] = trim($v_data[devmajor]);
  1414. $v_header[devminor] = trim($v_data[devminor]);
  1415. */
  1416.  
  1417. return true;
  1418. }
  1419. // }}}
  1420.  
  1421. // {{{ _maliciousFilename()
  1422. /**
  1423. * Detect and report a malicious file name
  1424. *
  1425. * @param string $file
  1426. *
  1427. * @return bool
  1428. * @access private
  1429. */
  1430. function _maliciousFilename($file)
  1431. {
  1432. if (strpos($file, '/../') !== false) {
  1433. return true;
  1434. }
  1435. if (strpos($file, '../') === 0) {
  1436. return true;
  1437. }
  1438. return false;
  1439. }
  1440. // }}}
  1441.  
  1442. // {{{ _readLongHeader()
  1443. function _readLongHeader(&$v_header)
  1444. {
  1445. $v_filename = '';
  1446. $n = floor($v_header['size']/512);
  1447. for ($i=0; $i<$n; $i++) {
  1448. $v_content = $this->_readBlock();
  1449. $v_filename .= $v_content;
  1450. }
  1451. if (($v_header['size'] % 512) != 0) {
  1452. $v_content = $this->_readBlock();
  1453. $v_filename .= trim($v_content);
  1454. }
  1455.  
  1456. // ----- Read the next header
  1457. $v_binary_data = $this->_readBlock();
  1458.  
  1459. if (!$this->_readHeader($v_binary_data, $v_header))
  1460. return false;
  1461.  
  1462. $v_filename = trim($v_filename);
  1463. $v_header['filename'] = $v_filename;
  1464. if ($this->_maliciousFilename($v_filename)) {
  1465. return $this->_error('Malicious .tar detected, file "' . $v_filename .
  1466. '" will not install in desired directory tree');
  1467. return false;
  1468. }
  1469.  
  1470. return true;
  1471. }
  1472. // }}}
  1473.  
  1474. // {{{ _extractInString()
  1475. /**
  1476. * This method extract from the archive one file identified by $p_filename.
  1477. * The return value is a string with the file content, or null on error.
  1478. *
  1479. * @param string $p_filename The path of the file to extract in a string.
  1480. *
  1481. * @return a string with the file content or null.
  1482. * @access private
  1483. */
  1484. function _extractInString($p_filename)
  1485. {
  1486. $v_result_str = "";
  1487.  
  1488. While (strlen($v_binary_data = $this->_readBlock()) != 0)
  1489. {
  1490. if (!$this->_readHeader($v_binary_data, $v_header))
  1491. return null;
  1492.  
  1493. if ($v_header['filename'] == '')
  1494. continue;
  1495.  
  1496. // ----- Look for long filename
  1497. if ($v_header['typeflag'] == 'L') {
  1498. if (!$this->_readLongHeader($v_header))
  1499. return null;
  1500. }
  1501.  
  1502. if ($v_header['filename'] == $p_filename) {
  1503. if ($v_header['typeflag'] == "5") {
  1504. return $this->_error('Unable to extract in string a directory '
  1505. .'entry {'.$v_header['filename'].'}');
  1506. return null;
  1507. } else {
  1508. $n = floor($v_header['size']/512);
  1509. for ($i=0; $i<$n; $i++) {
  1510. $v_result_str .= $this->_readBlock();
  1511. }
  1512. if (($v_header['size'] % 512) != 0) {
  1513. $v_content = $this->_readBlock();
  1514. $v_result_str .= substr($v_content, 0,
  1515. ($v_header['size'] % 512));
  1516. }
  1517. return $v_result_str;
  1518. }
  1519. } else {
  1520. $this->_jumpBlock(ceil(($v_header['size']/512)));
  1521. }
  1522. }
  1523.  
  1524. return null;
  1525. }
  1526. // }}}
  1527.  
  1528. // {{{ _extractList()
  1529. function _extractList($p_path, &$p_list_detail, $p_mode,
  1530. $p_file_list, $p_remove_path, $p_preserve=false)
  1531. {
  1532. $v_result=true;
  1533. $v_nb = 0;
  1534. $v_extract_all = true;
  1535. $v_listing = false;
  1536.  
  1537. $p_path = $this->_translateWinPath($p_path, false);
  1538. if ($p_path == '' || (substr($p_path, 0, 1) != '/'
  1539. && substr($p_path, 0, 3) != "../" && !strpos($p_path, ':'))) {
  1540. $p_path = "./".$p_path;
  1541. }
  1542. $p_remove_path = $this->_translateWinPath($p_remove_path);
  1543.  
  1544. // ----- Look for path to remove format (should end by /)
  1545. if (($p_remove_path != '') && (substr($p_remove_path, -1) != '/'))
  1546. $p_remove_path .= '/';
  1547. $p_remove_path_size = strlen($p_remove_path);
  1548.  
  1549. switch ($p_mode) {
  1550. case "complete" :
  1551. $v_extract_all = true;
  1552. $v_listing = false;
  1553. break;
  1554. case "partial" :
  1555. $v_extract_all = false;
  1556. $v_listing = false;
  1557. break;
  1558. case "list" :
  1559. $v_extract_all = false;
  1560. $v_listing = true;
  1561. break;
  1562. default :
  1563. return $this->_error('Invalid extract mode ('.$p_mode.')');
  1564. return false;
  1565. }
  1566.  
  1567. clearstatcache();
  1568.  
  1569. while (strlen($v_binary_data = $this->_readBlock()) != 0)
  1570. {
  1571. $v_extract_file = FALSE;
  1572. $v_extraction_stopped = 0;
  1573.  
  1574. if (!$this->_readHeader($v_binary_data, $v_header))
  1575. return false;
  1576.  
  1577. if ($v_header['filename'] == '') {
  1578. continue;
  1579. }
  1580.  
  1581. // ----- Look for long filename
  1582. if ($v_header['typeflag'] == 'L') {
  1583. if (!$this->_readLongHeader($v_header))
  1584. return false;
  1585. }
  1586.  
  1587. if ((!$v_extract_all) && (is_array($p_file_list))) {
  1588. // ----- By default no unzip if the file is not found
  1589. $v_extract_file = false;
  1590.  
  1591. for ($i=0; $i<sizeof($p_file_list); $i++) {
  1592. // ----- Look if it is a directory
  1593. if (substr($p_file_list[$i], -1) == '/') {
  1594. // ----- Look if the directory is in the filename path
  1595. if ((strlen($v_header['filename']) > strlen($p_file_list[$i]))
  1596. && (substr($v_header['filename'], 0, strlen($p_file_list[$i]))
  1597. == $p_file_list[$i])) {
  1598. $v_extract_file = true;
  1599. break;
  1600. }
  1601. }
  1602.  
  1603. // ----- It is a file, so compare the file names
  1604. elseif ($p_file_list[$i] == $v_header['filename']) {
  1605. $v_extract_file = true;
  1606. break;
  1607. }
  1608. }
  1609. } else {
  1610. $v_extract_file = true;
  1611. }
  1612.  
  1613. // ----- Look if this file need to be extracted
  1614. if (($v_extract_file) && (!$v_listing))
  1615. {
  1616. if (($p_remove_path != '')
  1617. && (substr($v_header['filename'].'/', 0, $p_remove_path_size)
  1618. == $p_remove_path)) {
  1619. $v_header['filename'] = substr($v_header['filename'],
  1620. $p_remove_path_size);
  1621. if( $v_header['filename'] == '' ){
  1622. continue;
  1623. }
  1624. }
  1625. if (($p_path != './') && ($p_path != '/')) {
  1626. while (substr($p_path, -1) == '/')
  1627. $p_path = substr($p_path, 0, strlen($p_path)-1);
  1628.  
  1629. if (substr($v_header['filename'], 0, 1) == '/')
  1630. $v_header['filename'] = $p_path.$v_header['filename'];
  1631. else
  1632. $v_header['filename'] = $p_path.'/'.$v_header['filename'];
  1633. }
  1634. if (file_exists($v_header['filename'])) {
  1635. if ( (@is_dir($v_header['filename']))
  1636. && ($v_header['typeflag'] == '')) {
  1637. return $this->_error('File '.$v_header['filename']
  1638. .' already exists as a directory');
  1639. return false;
  1640. }
  1641. if ( ($this->_isArchive($v_header['filename']))
  1642. && ($v_header['typeflag'] == "5")) {
  1643. return $this->_error('Directory '.$v_header['filename']
  1644. .' already exists as a file');
  1645. return false;
  1646. }
  1647. if (!is_writeable($v_header['filename'])) {
  1648. return $this->_error('File '.$v_header['filename']
  1649. .' already exists and is write protected');
  1650. return false;
  1651. }
  1652. if (@filemtime($v_header['filename']) > $v_header['mtime']) {
  1653. // To be completed : An error or silent no replace ?
  1654. }
  1655. }
  1656.  
  1657. // ----- Check the directory availability and create it if necessary
  1658. elseif (($v_result
  1659. = $this->_dirCheck(($v_header['typeflag'] == "5"
  1660. ?$v_header['filename']
  1661. :dirname($v_header['filename'])))) != 1) {
  1662. return $this->_error('Unable to create path for '.$v_header['filename']);
  1663. return false;
  1664. }
  1665.  
  1666. if ($v_extract_file) {
  1667. if ($v_header['typeflag'] == "5") {
  1668. if (!@file_exists($v_header['filename'])) {
  1669. if (!@mkdir($v_header['filename'], 0777)) {
  1670. return $this->_error('Unable to create directory {'
  1671. .$v_header['filename'].'}');
  1672. return false;
  1673. }
  1674. }
  1675. } elseif ($v_header['typeflag'] == "2") {
  1676. if (@file_exists($v_header['filename'])) {
  1677. @unlink($v_header['filename']);
  1678. }
  1679. if (!@symlink($v_header['link'], $v_header['filename'])) {
  1680. return $this->_error('Unable to extract symbolic link {'
  1681. .$v_header['filename'].'}');
  1682. return false;
  1683. }
  1684. } else {
  1685. if (($v_dest_file = @fopen($v_header['filename'], "wb")) == 0) {
  1686. return $this->_error('Error while opening {'.$v_header['filename']
  1687. .'} in write binary mode');
  1688. return false;
  1689. } else {
  1690. $n = floor($v_header['size']/512);
  1691. for ($i=0; $i<$n; $i++) {
  1692. $v_content = $this->_readBlock();
  1693. fwrite($v_dest_file, $v_content, 512);
  1694. }
  1695. if (($v_header['size'] % 512) != 0) {
  1696. $v_content = $this->_readBlock();
  1697. fwrite($v_dest_file, $v_content, ($v_header['size'] % 512));
  1698. }
  1699.  
  1700. @fclose($v_dest_file);
  1701.  
  1702. if ($p_preserve) {
  1703. @chown($v_header['filename'], $v_header['uid']);
  1704. @chgrp($v_header['filename'], $v_header['gid']);
  1705. }
  1706.  
  1707. // ----- Change the file mode, mtime
  1708. @touch($v_header['filename'], $v_header['mtime']);
  1709. if ($v_header['mode'] & 0111) {
  1710. // make file executable, obey umask
  1711. $mode = fileperms($v_header['filename']) | (~umask() & 0111);
  1712. @chmod($v_header['filename'], $mode);
  1713. }
  1714. }
  1715.  
  1716. // ----- Check the file size
  1717. clearstatcache();
  1718. if (!is_file($v_header['filename'])) {
  1719. return $this->_error('Extracted file '.$v_header['filename']
  1720. .'does not exist. Archive may be corrupted.');
  1721. return false;
  1722. }
  1723.  
  1724. $filesize = filesize($v_header['filename']);
  1725. if ($filesize != $v_header['size']) {
  1726. return $this->_error('Extracted file '.$v_header['filename']
  1727. .' does not have the correct file size \''
  1728. .$filesize
  1729. .'\' ('.$v_header['size']
  1730. .' expected). Archive may be corrupted.');
  1731. return false;
  1732. }
  1733. }
  1734. } else {
  1735. $this->_jumpBlock(ceil(($v_header['size']/512)));
  1736. }
  1737. } else {
  1738. $this->_jumpBlock(ceil(($v_header['size']/512)));
  1739. }
  1740.  
  1741. /* TBC : Seems to be unused ...
  1742. if ($this->_compress)
  1743. $v_end_of_file = @gzeof($this->_file);
  1744. else
  1745. $v_end_of_file = @feof($this->_file);
  1746. */
  1747.  
  1748. if ($v_listing || $v_extract_file || $v_extraction_stopped) {
  1749. // ----- Log extracted files
  1750. if (($v_file_dir = dirname($v_header['filename']))
  1751. == $v_header['filename'])
  1752. $v_file_dir = '';
  1753. if ((substr($v_header['filename'], 0, 1) == '/') && ($v_file_dir == ''))
  1754. $v_file_dir = '/';
  1755.  
  1756. $p_list_detail[$v_nb++] = $v_header;
  1757. if (is_array($p_file_list) && (count($p_list_detail) == count($p_file_list))) {
  1758. return true;
  1759. }
  1760. }
  1761. }
  1762.  
  1763. return true;
  1764. }
  1765. // }}}
  1766.  
  1767. // {{{ _openAppend()
  1768. function _openAppend()
  1769. {
  1770. if (filesize($this->_tarname) == 0)
  1771. return $this->_openWrite();
  1772.  
  1773. if ($this->_compress) {
  1774. $this->_close();
  1775.  
  1776. if (!@rename($this->_tarname, $this->_tarname.".tmp")) {
  1777. return $this->_error('Error while renaming \''.$this->_tarname
  1778. .'\' to temporary file \''.$this->_tarname
  1779. .'.tmp\'');
  1780. return false;
  1781. }
  1782.  
  1783. if ($this->_compress_type == 'gz')
  1784. $v_temp_tar = @gzopen($this->_tarname.".tmp", "rb");
  1785. elseif ($this->_compress_type == 'bz2')
  1786. $v_temp_tar = @bzopen($this->_tarname.".tmp", "r");
  1787.  
  1788. if ($v_temp_tar == 0) {
  1789. return $this->_error('Unable to open file \''.$this->_tarname
  1790. .'.tmp\' in binary read mode');
  1791. @rename($this->_tarname.".tmp", $this->_tarname);
  1792. return false;
  1793. }
  1794.  
  1795. if (!$this->_openWrite()) {
  1796. @rename($this->_tarname.".tmp", $this->_tarname);
  1797. return false;
  1798. }
  1799.  
  1800. if ($this->_compress_type == 'gz') {
  1801. $end_blocks = 0;
  1802.  
  1803. while (!@gzeof($v_temp_tar)) {
  1804. $v_buffer = @gzread($v_temp_tar, 512);
  1805. if ($v_buffer == ARCHIVE_TAR_END_BLOCK || strlen($v_buffer) == 0) {
  1806. $end_blocks++;
  1807. // do not copy end blocks, we will re-make them
  1808. // after appending
  1809. continue;
  1810. } elseif ($end_blocks > 0) {
  1811. for ($i = 0; $i < $end_blocks; $i++) {
  1812. $this->_writeBlock(ARCHIVE_TAR_END_BLOCK);
  1813. }
  1814. $end_blocks = 0;
  1815. }
  1816. $v_binary_data = pack("a512", $v_buffer);
  1817. $this->_writeBlock($v_binary_data);
  1818. }
  1819.  
  1820. @gzclose($v_temp_tar);
  1821. }
  1822. elseif ($this->_compress_type == 'bz2') {
  1823. $end_blocks = 0;
  1824.  
  1825. while (strlen($v_buffer = @bzread($v_temp_tar, 512)) > 0) {
  1826. if ($v_buffer == ARCHIVE_TAR_END_BLOCK || strlen($v_buffer) == 0) {
  1827. $end_blocks++;
  1828. // do not copy end blocks, we will re-make them
  1829. // after appending
  1830. continue;
  1831. } elseif ($end_blocks > 0) {
  1832. for ($i = 0; $i < $end_blocks; $i++) {
  1833. $this->_writeBlock(ARCHIVE_TAR_END_BLOCK);
  1834. }
  1835. $end_blocks = 0;
  1836. }
  1837. $v_binary_data = pack("a512", $v_buffer);
  1838. $this->_writeBlock($v_binary_data);
  1839. }
  1840.  
  1841. @bzclose($v_temp_tar);
  1842. }
  1843.  
  1844. if (!@unlink($this->_tarname.".tmp")) {
  1845. return $this->_error('Error while deleting temporary file \''
  1846. .$this->_tarname.'.tmp\'');
  1847. }
  1848.  
  1849. } else {
  1850. // ----- For not compressed tar, just add files before the last
  1851. // one or two 512 bytes block
  1852. if (!$this->_openReadWrite())
  1853. return false;
  1854.  
  1855. clearstatcache();
  1856. $v_size = filesize($this->_tarname);
  1857.  
  1858. // We might have zero, one or two end blocks.
  1859. // The standard is two, but we should try to handle
  1860. // other cases.
  1861. fseek($this->_file, $v_size - 1024);
  1862. if (fread($this->_file, 512) == ARCHIVE_TAR_END_BLOCK) {
  1863. fseek($this->_file, $v_size - 1024);
  1864. }
  1865. elseif (fread($this->_file, 512) == ARCHIVE_TAR_END_BLOCK) {
  1866. fseek($this->_file, $v_size - 512);
  1867. }
  1868. }
  1869.  
  1870. return true;
  1871. }
  1872. // }}}
  1873.  
  1874. // {{{ _append()
  1875. function _append($p_filelist, $p_add_dir='', $p_remove_dir='')
  1876. {
  1877. if (!$this->_openAppend())
  1878. return false;
  1879.  
  1880. if ($this->_addList($p_filelist, $p_add_dir, $p_remove_dir))
  1881. $this->_writeFooter();
  1882.  
  1883. $this->_close();
  1884.  
  1885. return true;
  1886. }
  1887. // }}}
  1888.  
  1889. // {{{ _dirCheck()
  1890.  
  1891. /**
  1892. * Check if a directory exists and create it (including parent
  1893. * dirs) if not.
  1894. *
  1895. * @param string $p_dir directory to check
  1896. *
  1897. * @return bool true if the directory exists or was created
  1898. */
  1899. function _dirCheck($p_dir)
  1900. {
  1901. clearstatcache();
  1902. if ((@is_dir($p_dir)) || ($p_dir == ''))
  1903. return true;
  1904.  
  1905. $p_parent_dir = dirname($p_dir);
  1906.  
  1907. if (($p_parent_dir != $p_dir) &&
  1908. ($p_parent_dir != '') &&
  1909. (!$this->_dirCheck($p_parent_dir)))
  1910. return false;
  1911.  
  1912. if (!@mkdir($p_dir, 0777)) {
  1913. return $this->_error("Unable to create directory '$p_dir'");
  1914. return false;
  1915. }
  1916.  
  1917. return true;
  1918. }
  1919.  
  1920. // }}}
  1921.  
  1922. // {{{ _pathReduction()
  1923.  
  1924. /**
  1925. * Compress path by changing for example "/dir/foo/../bar" to "/dir/bar",
  1926. * rand emove double slashes.
  1927. *
  1928. * @param string $p_dir path to reduce
  1929. *
  1930. * @return string reduced path
  1931. *
  1932. * @access private
  1933. *
  1934. */
  1935. function _pathReduction($p_dir)
  1936. {
  1937. $v_result = '';
  1938.  
  1939. // ----- Look for not empty path
  1940. if ($p_dir != '') {
  1941. // ----- Explode path by directory names
  1942. $v_list = explode('/', $p_dir);
  1943.  
  1944. // ----- Study directories from last to first
  1945. for ($i=sizeof($v_list)-1; $i>=0; $i--) {
  1946. // ----- Look for current path
  1947. if ($v_list[$i] == ".") {
  1948. // ----- Ignore this directory
  1949. // Should be the first $i=0, but no check is done
  1950. }
  1951. else if ($v_list[$i] == "..") {
  1952. // ----- Ignore it and ignore the $i-1
  1953. $i--;
  1954. }
  1955. else if ( ($v_list[$i] == '')
  1956. && ($i!=(sizeof($v_list)-1))
  1957. && ($i!=0)) {
  1958. // ----- Ignore only the double '//' in path,
  1959. // but not the first and last /
  1960. } else {
  1961. $v_result = $v_list[$i].($i!=(sizeof($v_list)-1)?'/'
  1962. .$v_result:'');
  1963. }
  1964. }
  1965. }
  1966.  
  1967. if (defined('OS_WINDOWS') && OS_WINDOWS) {
  1968. $v_result = strtr($v_result, '\\', '/');
  1969. }
  1970.  
  1971. return $v_result;
  1972. }
  1973.  
  1974. // }}}
  1975.  
  1976. // {{{ _translateWinPath()
  1977. function _translateWinPath($p_path, $p_remove_disk_letter=true)
  1978. {
  1979. if (defined('OS_WINDOWS') && OS_WINDOWS) {
  1980. // ----- Look for potential disk letter
  1981. if ( ($p_remove_disk_letter)
  1982. && (($v_position = strpos($p_path, ':')) != false)) {
  1983. $p_path = substr($p_path, $v_position+1);
  1984. }
  1985. // ----- Change potential windows directory separator
  1986. if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0,1) == '\\')) {
  1987. $p_path = strtr($p_path, '\\', '/');
  1988. }
  1989. }
  1990. return $p_path;
  1991. }
  1992. // }}}
  1993.  
  1994. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement