Bearsampp 2026.9.23
Loading...
Searching...
No Matches
Tar.php
Go to the documentation of this file.
1<?php
2/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
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// If the PEAR class cannot be loaded via the autoloader,
43// then try to require_once it from the PHP include path.
44if (!class_exists('PEAR')) {
45 require_once 'PEAR.php';
46}
47
48define('ARCHIVE_TAR_ATT_SEPARATOR', 90001);
49define('ARCHIVE_TAR_END_BLOCK', pack("a512", ''));
50
59class Archive_Tar extends PEAR
60{
64 public $_tarname = '';
65
69 public $_compress = false;
70
74 public $_compress_type = 'none';
75
79 public $_separator = ' ';
80
84 public $_file = 0;
85
89 public $_temp_tarname = '';
90
94 public $_ignore_regexp = '';
95
99 public $error_object = null;
100
106 public $_fmt = '';
107
111 protected $buffer_length;
112
129 public function __construct($p_tarname, $p_compress = null, $buffer_length = 512)
130 {
131 parent::__construct();
132
133 $this->_compress = false;
134 $this->_compress_type = 'none';
135 if (($p_compress === null) || ($p_compress == '')) {
136 if (@file_exists($p_tarname)) {
137 if ($fp = @fopen($p_tarname, "rb")) {
138 // look for gzip magic cookie
139 $data = fread($fp, 2);
140 fclose($fp);
141 if ($data == "\37\213") {
142 $this->_compress = true;
143 $this->_compress_type = 'gz';
144 // No sure it's enought for a magic code ....
145 } elseif ($data == "BZ") {
146 $this->_compress = true;
147 $this->_compress_type = 'bz2';
148 } elseif (file_get_contents($p_tarname, false, null, 1, 4) == '7zXZ') {
149 $this->_compress = true;
150 $this->_compress_type = 'lzma2';
151 }
152 }
153 } else {
154 // probably a remote file or some file accessible
155 // through a stream interface
156 if (substr($p_tarname, -2) == 'gz') {
157 $this->_compress = true;
158 $this->_compress_type = 'gz';
159 } elseif ((substr($p_tarname, -3) == 'bz2') ||
160 (substr($p_tarname, -2) == 'bz')
161 ) {
162 $this->_compress = true;
163 $this->_compress_type = 'bz2';
164 } else {
165 if (substr($p_tarname, -2) == 'xz') {
166 $this->_compress = true;
167 $this->_compress_type = 'lzma2';
168 }
169 }
170 }
171 } else {
172 if (($p_compress === true) || ($p_compress == 'gz')) {
173 $this->_compress = true;
174 $this->_compress_type = 'gz';
175 } else {
176 if ($p_compress == 'bz2') {
177 $this->_compress = true;
178 $this->_compress_type = 'bz2';
179 } else {
180 if ($p_compress == 'lzma2') {
181 $this->_compress = true;
182 $this->_compress_type = 'lzma2';
183 } else {
184 $this->_error(
185 "Unsupported compression type '$p_compress'\n" .
186 "Supported types are 'gz', 'bz2' and 'lzma2'.\n"
187 );
188 return false;
189 }
190 }
191 }
192 }
193 $this->_tarname = $p_tarname;
194 if ($this->_compress) { // assert zlib or bz2 or xz extension support
195 if ($this->_compress_type == 'gz') {
196 $extname = 'zlib';
197 } else {
198 if ($this->_compress_type == 'bz2') {
199 $extname = 'bz2';
200 } else {
201 if ($this->_compress_type == 'lzma2') {
202 $extname = 'xz';
203 }
204 }
205 }
206
207 if (!extension_loaded($extname)) {
208 PEAR::loadExtension($extname);
209 }
210 if (!extension_loaded($extname)) {
211 $this->_error(
212 "The extension '$extname' couldn't be found.\n" .
213 "Please make sure your version of PHP was built " .
214 "with '$extname' support.\n"
215 );
216 return false;
217 }
218 }
219
220
221 if (version_compare(PHP_VERSION, "5.5.0-dev") < 0) {
222 $this->_fmt = "a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/" .
223 "a8checksum/a1typeflag/a100link/a6magic/a2version/" .
224 "a32uname/a32gname/a8devmajor/a8devminor/a131prefix";
225 } else {
226 $this->_fmt = "Z100filename/Z8mode/Z8uid/Z8gid/a12size/Z12mtime/" .
227 "Z8checksum/Z1typeflag/Z100link/Z6magic/Z2version/" .
228 "Z32uname/Z32gname/Z8devmajor/Z8devminor/Z131prefix";
229 }
230
231
232 $this->buffer_length = $buffer_length;
233 }
234
235 public function __destruct()
236 {
237 $this->_close();
238 // ----- Look for a local copy to delete
239 if ($this->_temp_tarname != '' && (bool) preg_match('/^tar[[:alnum:]]*\.tmp$/', $this->_temp_tarname)) {
240 @unlink($this->_temp_tarname);
241 }
242 }
243
265 public function create($p_filelist)
266 {
267 return $this->createModify($p_filelist, '', '');
268 }
269
286 public function add($p_filelist)
287 {
288 return $this->addModify($p_filelist, '', '');
289 }
290
297 public function extract($p_path = '', $p_preserve = false, $p_symlinks = true)
298 {
299 return $this->extractModify($p_path, '', $p_preserve, $p_symlinks);
300 }
301
305 public function listContent()
306 {
307 $v_list_detail = array();
308
309 if ($this->_openRead()) {
310 if (!$this->_extractList('', $v_list_detail, "list", '', '')) {
311 unset($v_list_detail);
312 $v_list_detail = 0;
313 }
314 $this->_close();
315 }
316
317 return $v_list_detail;
318 }
319
355 public function createModify($p_filelist, $p_add_dir, $p_remove_dir = '')
356 {
357 $v_result = true;
358
359 if (!$this->_openWrite()) {
360 return false;
361 }
362
363 if ($p_filelist != '') {
364 if (is_array($p_filelist)) {
365 $v_list = $p_filelist;
366 } elseif (is_string($p_filelist)) {
367 $v_list = explode($this->_separator, $p_filelist);
368 } else {
369 $this->_cleanFile();
370 $this->_error('Invalid file list');
371 return false;
372 }
373
374 $v_result = $this->_addList($v_list, $p_add_dir, $p_remove_dir);
375 }
376
377 if ($v_result) {
378 $this->_writeFooter();
379 $this->_close();
380 } else {
381 $this->_cleanFile();
382 }
383
384 return $v_result;
385 }
386
427 public function addModify($p_filelist, $p_add_dir, $p_remove_dir = '')
428 {
429 $v_result = true;
430
431 if (!$this->_isArchive()) {
432 $v_result = $this->createModify(
433 $p_filelist,
434 $p_add_dir,
435 $p_remove_dir
436 );
437 } else {
438 if (is_array($p_filelist)) {
439 $v_list = $p_filelist;
440 } elseif (is_string($p_filelist)) {
441 $v_list = explode($this->_separator, $p_filelist);
442 } else {
443 $this->_error('Invalid file list');
444 return false;
445 }
446
447 $v_result = $this->_append($v_list, $p_add_dir, $p_remove_dir);
448 }
449
450 return $v_result;
451 }
452
480 public function addString($p_filename, $p_string, $p_datetime = false, $p_params = array())
481 {
482 $p_stamp = @$p_params["stamp"] ? $p_params["stamp"] : ($p_datetime ? $p_datetime : time());
483 $p_mode = @$p_params["mode"] ? $p_params["mode"] : 0600;
484 $p_type = @$p_params["type"] ? $p_params["type"] : "";
485 $p_uid = @$p_params["uid"] ? $p_params["uid"] : "";
486 $p_gid = @$p_params["gid"] ? $p_params["gid"] : "";
487 $v_result = true;
488
489 if (!$this->_isArchive()) {
490 if (!$this->_openWrite()) {
491 return false;
492 }
493 $this->_close();
494 }
495
496 if (!$this->_openAppend()) {
497 return false;
498 }
499
500 // Need to check the get back to the temporary file ? ....
501 $v_result = $this->_addString($p_filename, $p_string, $p_datetime, $p_params);
502
503 $this->_writeFooter();
504
505 $this->_close();
506
507 return $v_result;
508 }
509
545 public function extractModify($p_path, $p_remove_path, $p_preserve = false, $p_symlinks = true)
546 {
547 $v_result = true;
548 $v_list_detail = array();
549
550 if ($v_result = $this->_openRead()) {
551 $v_result = $this->_extractList(
552 $p_path,
553 $v_list_detail,
554 "complete",
555 0,
556 $p_remove_path,
557 $p_preserve,
558 $p_symlinks
559 );
560 $this->_close();
561 }
562
563 return $v_result;
564 }
565
574 public function extractInString($p_filename)
575 {
576 if ($this->_openRead()) {
577 $v_result = $this->_extractInString($p_filename);
578 $this->_close();
579 } else {
580 $v_result = null;
581 }
582
583 return $v_result;
584 }
585
607 public function extractList($p_filelist, $p_path = '', $p_remove_path = '', $p_preserve = false, $p_symlinks = true)
608 {
609 $v_result = true;
610 $v_list_detail = array();
611
612 if (is_array($p_filelist)) {
613 $v_list = $p_filelist;
614 } elseif (is_string($p_filelist)) {
615 $v_list = explode($this->_separator, $p_filelist);
616 } else {
617 $this->_error('Invalid string list');
618 return false;
619 }
620
621 if ($v_result = $this->_openRead()) {
622 $v_result = $this->_extractList(
623 $p_path,
624 $v_list_detail,
625 "partial",
626 $v_list,
627 $p_remove_path,
628 $p_preserve,
629 $p_symlinks
630 );
631 $this->_close();
632 }
633
634 return $v_result;
635 }
636
644 public function setAttribute()
645 {
646 $v_result = true;
647
648 // ----- Get the number of variable list of arguments
649 if (($v_size = func_num_args()) == 0) {
650 return true;
651 }
652
653 // ----- Get the arguments
654 $v_att_list = func_get_args();
655
656 // ----- Read the attributes
657 $i = 0;
658 while ($i < $v_size) {
659
660 // ----- Look for next option
661 switch ($v_att_list[$i]) {
662 // ----- Look for options that request a string value
664 // ----- Check the number of parameters
665 if (($i + 1) >= $v_size) {
666 $this->_error(
667 'Invalid number of parameters for '
668 . 'attribute ARCHIVE_TAR_ATT_SEPARATOR'
669 );
670 return false;
671 }
672
673 // ----- Get the value
674 $this->_separator = $v_att_list[$i + 1];
675 $i++;
676 break;
677
678 default :
679 $this->_error('Unknown attribute code ' . $v_att_list[$i] . '');
680 return false;
681 }
682
683 // ----- Next attribute
684 $i++;
685 }
686
687 return $v_result;
688 }
689
697 public function setIgnoreRegexp($regexp)
698 {
699 $this->_ignore_regexp = $regexp;
700 }
701
711 public function setIgnoreList($list)
712 {
713 $list = str_replace(array('#', '.', '^', '$'), array('\#', '\.', '\^', '\$'), $list);
714 $regexp = '#/' . join('$|/', $list) . '#';
715 $this->setIgnoreRegexp($regexp);
716 }
717
721 public function _error($p_message)
722 {
723 $this->error_object = $this->raiseError($p_message);
724 }
725
729 public function _warning($p_message)
730 {
731 $this->error_object = $this->raiseError($p_message);
732 }
733
738 public function _isArchive($p_filename = null)
739 {
740 if ($p_filename == null) {
741 $p_filename = $this->_tarname;
742 }
743 clearstatcache();
744 return @is_file($p_filename) && !@is_link($p_filename);
745 }
746
750 public function _openWrite()
751 {
752 if ($this->_compress_type == 'gz' && function_exists('gzopen')) {
753 $this->_file = @gzopen($this->_tarname, "wb9");
754 } else {
755 if ($this->_compress_type == 'bz2' && function_exists('bzopen')) {
756 $this->_file = @bzopen($this->_tarname, "w");
757 } else {
758 if ($this->_compress_type == 'lzma2' && function_exists('xzopen')) {
759 $this->_file = @xzopen($this->_tarname, 'w');
760 } else {
761 if ($this->_compress_type == 'none') {
762 $this->_file = @fopen($this->_tarname, "wb");
763 } else {
764 $this->_error(
765 'Unknown or missing compression type ('
766 . $this->_compress_type . ')'
767 );
768 return false;
769 }
770 }
771 }
772 }
773
774 if ($this->_file == 0) {
775 $this->_error(
776 'Unable to open in write mode \''
777 . $this->_tarname . '\''
778 );
779 return false;
780 }
781
782 return true;
783 }
784
788 public function _openRead()
789 {
790 if (strtolower(substr($this->_tarname, 0, 7)) == 'http://') {
791
792 // ----- Look if a local copy need to be done
793 if ($this->_temp_tarname == '') {
794 $this->_temp_tarname = uniqid('tar') . '.tmp';
795 if (!$v_file_from = @fopen($this->_tarname, 'rb')) {
796 $this->_error(
797 'Unable to open in read mode \''
798 . $this->_tarname . '\''
799 );
800 $this->_temp_tarname = '';
801 return false;
802 }
803 if (!$v_file_to = @fopen($this->_temp_tarname, 'wb')) {
804 $this->_error(
805 'Unable to open in write mode \''
806 . $this->_temp_tarname . '\''
807 );
808 $this->_temp_tarname = '';
809 return false;
810 }
811 while ($v_data = @fread($v_file_from, 1024)) {
812 @fwrite($v_file_to, $v_data);
813 }
814 @fclose($v_file_from);
815 @fclose($v_file_to);
816 }
817
818 // ----- File to open if the local copy
819 $v_filename = $this->_temp_tarname;
820 } else {
821 // ----- File to open if the normal Tar file
822
823 $v_filename = $this->_tarname;
824 }
825
826 if ($this->_compress_type == 'gz' && function_exists('gzopen')) {
827 $this->_file = @gzopen($v_filename, "rb");
828 } else {
829 if ($this->_compress_type == 'bz2' && function_exists('bzopen')) {
830 $this->_file = @bzopen($v_filename, "r");
831 } else {
832 if ($this->_compress_type == 'lzma2' && function_exists('xzopen')) {
833 $this->_file = @xzopen($v_filename, "r");
834 } else {
835 if ($this->_compress_type == 'none') {
836 $this->_file = @fopen($v_filename, "rb");
837 } else {
838 $this->_error(
839 'Unknown or missing compression type ('
840 . $this->_compress_type . ')'
841 );
842 return false;
843 }
844 }
845 }
846 }
847
848 if ($this->_file == 0) {
849 $this->_error('Unable to open in read mode \'' . $v_filename . '\'');
850 return false;
851 }
852
853 return true;
854 }
855
859 public function _openReadWrite()
860 {
861 if ($this->_compress_type == 'gz') {
862 $this->_file = @gzopen($this->_tarname, "r+b");
863 } else {
864 if ($this->_compress_type == 'bz2') {
865 $this->_error(
866 'Unable to open bz2 in read/write mode \''
867 . $this->_tarname . '\' (limitation of bz2 extension)'
868 );
869 return false;
870 } else {
871 if ($this->_compress_type == 'lzma2') {
872 $this->_error(
873 'Unable to open lzma2 in read/write mode \''
874 . $this->_tarname . '\' (limitation of lzma2 extension)'
875 );
876 return false;
877 } else {
878 if ($this->_compress_type == 'none') {
879 $this->_file = @fopen($this->_tarname, "r+b");
880 } else {
881 $this->_error(
882 'Unknown or missing compression type ('
883 . $this->_compress_type . ')'
884 );
885 return false;
886 }
887 }
888 }
889 }
890
891 if ($this->_file == 0) {
892 $this->_error(
893 'Unable to open in read/write mode \''
894 . $this->_tarname . '\''
895 );
896 return false;
897 }
898
899 return true;
900 }
901
905 public function _close()
906 {
907 //if (isset($this->_file)) {
908 if (is_resource($this->_file)) {
909 if ($this->_compress_type == 'gz') {
910 @gzclose($this->_file);
911 } else {
912 if ($this->_compress_type == 'bz2') {
913 @bzclose($this->_file);
914 } else {
915 if ($this->_compress_type == 'lzma2') {
916 @xzclose($this->_file);
917 } else {
918 if ($this->_compress_type == 'none') {
919 @fclose($this->_file);
920 } else {
921 $this->_error(
922 'Unknown or missing compression type ('
923 . $this->_compress_type . ')'
924 );
925 }
926 }
927 }
928 }
929
930 $this->_file = 0;
931 }
932
933 // ----- Look if a local copy need to be erase
934 // Note that it might be interesting to keep the url for a time : ToDo
935 if ($this->_temp_tarname != '') {
936 @unlink($this->_temp_tarname);
937 $this->_temp_tarname = '';
938 }
939
940 return true;
941 }
942
946 public function _cleanFile()
947 {
948 $this->_close();
949
950 // ----- Look for a local copy
951 if ($this->_temp_tarname != '') {
952 // ----- Remove the local copy but not the remote tarname
953 @unlink($this->_temp_tarname);
954 $this->_temp_tarname = '';
955 } else {
956 // ----- Remove the local tarname file
957 @unlink($this->_tarname);
958 }
959 $this->_tarname = '';
960
961 return true;
962 }
963
969 public function _writeBlock($p_binary_data, $p_len = null)
970 {
971 if (is_resource($this->_file)) {
972 if ($p_len === null) {
973 switch ($this->_compress_type)
974 {
975 case 'gz':
976 $bytes = @gzwrite($this->_file, $p_binary_data);
977 break;
978 case 'bz2':
979 $bytes = @bzwrite($this->_file, $p_binary_data);
980 break;
981 case 'lzma2':
982 $bytes = @xzwrite($this->_file, $p_binary_data);
983 break;
984 case 'none':
985 $bytes = @fwrite($this->_file, $p_binary_data);
986 break;
987 default:
988 $this->_error('Unknown or missing compression type (' . $this->_compress_type . ')');
989 return false;
990 }
991 } else {
992 switch ($this->_compress_type)
993 {
994 case 'gz':
995 $bytes = @gzwrite($this->_file, $p_binary_data, $p_len);
996 break;
997 case 'bz2':
998 $bytes = @bzwrite($this->_file, $p_binary_data, $p_len);
999 break;
1000 case 'lzma2':
1001 $bytes = @xzwrite($this->_file, $p_binary_data, $p_len);
1002 break;
1003 case 'none':
1004 $bytes = @fwrite($this->_file, $p_binary_data, $p_len);
1005 break;
1006 default:
1007 $this->_error('Unknown or missing compression type (' . $this->_compress_type . ')');
1008 return false;
1009 }
1010 }
1011 return $bytes !== false;
1012 }
1013 return true;
1014 }
1015
1019 public function _readBlock()
1020 {
1021 $v_block = null;
1022 if (is_resource($this->_file)) {
1023 if ($this->_compress_type == 'gz') {
1024 $v_block = @gzread($this->_file, 512);
1025 } else {
1026 if ($this->_compress_type == 'bz2') {
1027 $v_block = @bzread($this->_file, 512);
1028 } else {
1029 if ($this->_compress_type == 'lzma2') {
1030 $v_block = @xzread($this->_file, 512);
1031 } else {
1032 if ($this->_compress_type == 'none') {
1033 $v_block = @fread($this->_file, 512);
1034 } else {
1035 $this->_error(
1036 'Unknown or missing compression type ('
1037 . $this->_compress_type . ')'
1038 );
1039 }
1040 }
1041 }
1042 }
1043 }
1044 return $v_block;
1045 }
1046
1051 public function _jumpBlock($p_len = null)
1052 {
1053 if (is_resource($this->_file)) {
1054 if ($p_len === null) {
1055 $p_len = 1;
1056 }
1057
1058 if ($this->_compress_type == 'gz') {
1059 @gzseek($this->_file, gztell($this->_file) + ($p_len * 512));
1060 } else {
1061 if ($this->_compress_type == 'bz2') {
1062 // ----- Replace missing bztell() and bzseek()
1063 for ($i = 0; $i < $p_len; $i++) {
1064 $this->_readBlock();
1065 }
1066 } else {
1067 if ($this->_compress_type == 'lzma2') {
1068 // ----- Replace missing xztell() and xzseek()
1069 for ($i = 0; $i < $p_len; $i++) {
1070 $this->_readBlock();
1071 }
1072 } else {
1073 if ($this->_compress_type == 'none') {
1074 @fseek($this->_file, $p_len * 512, SEEK_CUR);
1075 } else {
1076 $this->_error(
1077 'Unknown or missing compression type ('
1078 . $this->_compress_type . ')'
1079 );
1080 }
1081 }
1082 }
1083 }
1084 }
1085 return true;
1086 }
1087
1091 public function _writeFooter()
1092 {
1093 if (is_resource($this->_file)) {
1094 // ----- Write the last 0 filled block for end of archive
1095 $v_binary_data = pack('a1024', '');
1096 return $this->_writeBlock($v_binary_data);
1097 }
1098 return true;
1099 }
1100
1107 public function _addList($p_list, $p_add_dir, $p_remove_dir)
1108 {
1109 $v_result = true;
1110 $v_header = array();
1111
1112 // ----- Remove potential windows directory separator
1113 $p_add_dir = $this->_translateWinPath($p_add_dir);
1114 $p_remove_dir = $this->_translateWinPath($p_remove_dir, false);
1115
1116 if (!$this->_file) {
1117 $this->_error('Invalid file descriptor');
1118 return false;
1119 }
1120
1121 if (sizeof($p_list) == 0) {
1122 return true;
1123 }
1124
1125 foreach ($p_list as $v_filename) {
1126 if (!$v_result) {
1127 break;
1128 }
1129
1130 // ----- Skip the current tar name
1131 if ($v_filename == $this->_tarname) {
1132 continue;
1133 }
1134
1135 if ($v_filename == '') {
1136 continue;
1137 }
1138
1139 // ----- ignore files and directories matching the ignore regular expression
1140 if ($this->_ignore_regexp && preg_match($this->_ignore_regexp, '/' . $v_filename)) {
1141 $this->_warning("File '$v_filename' ignored");
1142 continue;
1143 }
1144
1145 if (!file_exists($v_filename) && !is_link($v_filename)) {
1146 $this->_warning("File '$v_filename' does not exist");
1147 continue;
1148 }
1149
1150 // ----- Add the file or directory header
1151 if (!$this->_addFile($v_filename, $v_header, $p_add_dir, $p_remove_dir)) {
1152 return false;
1153 }
1154
1155 if (@is_dir($v_filename) && !@is_link($v_filename)) {
1156 if (!($p_hdir = opendir($v_filename))) {
1157 $this->_warning("Directory '$v_filename' can not be read");
1158 continue;
1159 }
1160 while (false !== ($p_hitem = readdir($p_hdir))) {
1161 if (($p_hitem != '.') && ($p_hitem != '..')) {
1162 if ($v_filename != ".") {
1163 $p_temp_list[0] = $v_filename . '/' . $p_hitem;
1164 } else {
1165 $p_temp_list[0] = $p_hitem;
1166 }
1167
1168 $v_result = $this->_addList(
1169 $p_temp_list,
1170 $p_add_dir,
1171 $p_remove_dir
1172 );
1173 }
1174 }
1175
1176 unset($p_temp_list);
1177 unset($p_hdir);
1178 unset($p_hitem);
1179 }
1180 }
1181
1182 return $v_result;
1183 }
1184
1193 public function _addFile($p_filename, &$p_header, $p_add_dir, $p_remove_dir, $v_stored_filename = null)
1194 {
1195 if (!$this->_file) {
1196 $this->_error('Invalid file descriptor');
1197 return false;
1198 }
1199
1200 if ($p_filename == '') {
1201 $this->_error('Invalid file name');
1202 return false;
1203 }
1204
1205 if (is_null($v_stored_filename)) {
1206 // ----- Calculate the stored filename
1207 $p_filename = $this->_translateWinPath($p_filename, false);
1208 $v_stored_filename = $p_filename;
1209
1210 if (strcmp($p_filename, $p_remove_dir) == 0) {
1211 return true;
1212 }
1213
1214 if ($p_remove_dir != '') {
1215 if (substr($p_remove_dir, -1) != '/') {
1216 $p_remove_dir .= '/';
1217 }
1218
1219 if (substr($p_filename, 0, strlen($p_remove_dir)) == $p_remove_dir) {
1220 $v_stored_filename = substr($p_filename, strlen($p_remove_dir));
1221 }
1222 }
1223
1224 $v_stored_filename = $this->_translateWinPath($v_stored_filename);
1225 if ($p_add_dir != '') {
1226 if (substr($p_add_dir, -1) == '/') {
1227 $v_stored_filename = $p_add_dir . $v_stored_filename;
1228 } else {
1229 $v_stored_filename = $p_add_dir . '/' . $v_stored_filename;
1230 }
1231 }
1232
1233 $v_stored_filename = $this->_pathReduction($v_stored_filename);
1234 }
1235
1236 if ($this->_isArchive($p_filename)) {
1237 if (($v_file = @fopen($p_filename, "rb")) == 0) {
1238 $this->_warning(
1239 "Unable to open file '" . $p_filename
1240 . "' in binary read mode"
1241 );
1242 return true;
1243 }
1244
1245 if (!$this->_writeHeader($p_filename, $v_stored_filename)) {
1246 return false;
1247 }
1248
1249 while (($v_buffer = fread($v_file, $this->buffer_length)) != '') {
1250 $buffer_length = strlen("$v_buffer");
1251 if ($buffer_length != $this->buffer_length) {
1252 $pack_size = ((int)($buffer_length / 512) + ($buffer_length % 512 !== 0 ? 1 : 0)) * 512;
1253 $pack_format = sprintf('a%d', $pack_size);
1254 } else {
1255 $pack_format = sprintf('a%d', $this->buffer_length);
1256 }
1257 $v_binary_data = pack($pack_format, "$v_buffer");
1258 if(!$this->_writeBlock($v_binary_data)) {
1259 return false;
1260 }
1261 }
1262
1263 fclose($v_file);
1264 } else {
1265 // ----- Only header for dir
1266 if (!$this->_writeHeader($p_filename, $v_stored_filename)) {
1267 return false;
1268 }
1269 }
1270
1271 return true;
1272 }
1273
1281 public function _addString($p_filename, $p_string, $p_datetime = false, $p_params = array())
1282 {
1283 $p_stamp = @$p_params["stamp"] ? $p_params["stamp"] : ($p_datetime ? $p_datetime : time());
1284 $p_mode = @$p_params["mode"] ? $p_params["mode"] : 0600;
1285 $p_type = @$p_params["type"] ? $p_params["type"] : "";
1286 $p_uid = @$p_params["uid"] ? $p_params["uid"] : 0;
1287 $p_gid = @$p_params["gid"] ? $p_params["gid"] : 0;
1288 if (!$this->_file) {
1289 $this->_error('Invalid file descriptor');
1290 return false;
1291 }
1292
1293 if ($p_filename == '') {
1294 $this->_error('Invalid file name');
1295 return false;
1296 }
1297
1298 // ----- Calculate the stored filename
1299 $p_filename = $this->_translateWinPath($p_filename, false);
1300
1301 // ----- If datetime is not specified, set current time
1302 if ($p_datetime === false) {
1303 $p_datetime = time();
1304 }
1305
1306 if (!$this->_writeHeaderBlock(
1307 $p_filename,
1308 strlen($p_string),
1309 $p_stamp,
1310 $p_mode,
1311 $p_type,
1312 $p_uid,
1313 $p_gid
1314 )
1315 ) {
1316 return false;
1317 }
1318
1319 $i = 0;
1320 while (($v_buffer = substr($p_string, (($i++) * 512), 512)) != '') {
1321 $v_binary_data = pack("a512", $v_buffer);
1322 if (!$this->_writeBlock($v_binary_data)) {
1323 return false;
1324 }
1325 }
1326
1327 return true;
1328 }
1329
1335 public function _writeHeader($p_filename, $p_stored_filename)
1336 {
1337 if ($p_stored_filename == '') {
1338 $p_stored_filename = $p_filename;
1339 }
1340
1341 $v_reduced_filename = $this->_pathReduction($p_stored_filename);
1342
1343 if (strlen($v_reduced_filename) > 99) {
1344 if (!$this->_writeLongHeader($v_reduced_filename, false)) {
1345 return false;
1346 }
1347 }
1348
1349 $v_linkname = '';
1350 if (@is_link($p_filename)) {
1351 $v_linkname = readlink($p_filename);
1352 }
1353
1354 if (strlen($v_linkname) > 99) {
1355 if (!$this->_writeLongHeader($v_linkname, true)) {
1356 return false;
1357 }
1358 }
1359
1360 $v_info = lstat($p_filename);
1361 $v_uid = sprintf("%07s", DecOct($v_info[4]));
1362 $v_gid = sprintf("%07s", DecOct($v_info[5]));
1363 $v_perms = sprintf("%07s", DecOct($v_info['mode'] & 000777));
1364 $v_mtime = sprintf("%011s", DecOct($v_info['mtime']));
1365
1366 if (@is_link($p_filename)) {
1367 $v_typeflag = '2';
1368 $v_size = sprintf("%011s", DecOct(0));
1369 } elseif (@is_dir($p_filename)) {
1370 $v_typeflag = "5";
1371 $v_size = sprintf("%011s", DecOct(0));
1372 } else {
1373 $v_typeflag = '0';
1374 clearstatcache();
1375 $v_size = sprintf("%011s", DecOct($v_info['size']));
1376 }
1377
1378 $v_magic = 'ustar ';
1379 $v_version = ' ';
1380 $v_uname = '';
1381 $v_gname = '';
1382
1383 if (function_exists('posix_getpwuid')) {
1384 $userinfo = posix_getpwuid($v_info[4]);
1385 $groupinfo = posix_getgrgid($v_info[5]);
1386
1387 if (isset($userinfo['name'])) {
1388 $v_uname = $userinfo['name'];
1389 }
1390
1391 if (isset($groupinfo['name'])) {
1392 $v_gname = $groupinfo['name'];
1393 }
1394 }
1395
1396 $v_devmajor = '';
1397 $v_devminor = '';
1398 $v_prefix = '';
1399
1400 $v_binary_data_first = pack(
1401 "a100a8a8a8a12a12",
1402 $v_reduced_filename,
1403 $v_perms,
1404 $v_uid,
1405 $v_gid,
1406 $v_size,
1407 $v_mtime
1408 );
1409 $v_binary_data_last = pack(
1410 "a1a100a6a2a32a32a8a8a155a12",
1411 $v_typeflag,
1412 $v_linkname,
1413 $v_magic,
1414 $v_version,
1415 $v_uname,
1416 $v_gname,
1417 $v_devmajor,
1418 $v_devminor,
1419 $v_prefix,
1420 ''
1421 );
1422
1423 // ----- Calculate the checksum
1424 $v_checksum = 0;
1425 // ..... First part of the header
1426 for ($i = 0; $i < 148; $i++) {
1427 $v_checksum += ord(substr($v_binary_data_first, $i, 1));
1428 }
1429 // ..... Ignore the checksum value and replace it by ' ' (space)
1430 for ($i = 148; $i < 156; $i++) {
1431 $v_checksum += ord(' ');
1432 }
1433 // ..... Last part of the header
1434 for ($i = 156, $j = 0; $i < 512; $i++, $j++) {
1435 $v_checksum += ord(substr($v_binary_data_last, $j, 1));
1436 }
1437
1438 // ----- Write the first 148 bytes of the header in the archive
1439 $this->_writeBlock($v_binary_data_first, 148);
1440
1441 // ----- Write the calculated checksum
1442 $v_checksum = sprintf("%06s\0 ", DecOct($v_checksum));
1443 $v_binary_data = pack("a8", $v_checksum);
1444 $this->_writeBlock($v_binary_data, 8);
1445
1446 // ----- Write the last 356 bytes of the header in the archive
1447 $this->_writeBlock($v_binary_data_last, 356);
1448
1449 return true;
1450 }
1451
1462 public function _writeHeaderBlock(
1463 $p_filename,
1464 $p_size,
1465 $p_mtime = 0,
1466 $p_perms = 0,
1467 $p_type = '',
1468 $p_uid = 0,
1469 $p_gid = 0
1470 )
1471 {
1472 $p_filename = $this->_pathReduction($p_filename);
1473
1474 if (strlen($p_filename) > 99) {
1475 if (!$this->_writeLongHeader($p_filename, false)) {
1476 return false;
1477 }
1478 }
1479
1480 if ($p_type == "5") {
1481 $v_size = sprintf("%011s", DecOct(0));
1482 } else {
1483 $v_size = sprintf("%011s", DecOct($p_size));
1484 }
1485
1486 $v_uid = sprintf("%07s", DecOct($p_uid));
1487 $v_gid = sprintf("%07s", DecOct($p_gid));
1488 $v_perms = sprintf("%07s", DecOct($p_perms & 000777));
1489
1490 $v_mtime = sprintf("%11s", DecOct($p_mtime));
1491
1492 $v_linkname = '';
1493
1494 $v_magic = 'ustar ';
1495
1496 $v_version = ' ';
1497
1498 if (function_exists('posix_getpwuid')) {
1499 $userinfo = posix_getpwuid($p_uid);
1500 $groupinfo = posix_getgrgid($p_gid);
1501
1502 if ($userinfo === false || $groupinfo === false) {
1503 $v_uname = '';
1504 $v_gname = '';
1505 } else {
1506 $v_uname = $userinfo['name'];
1507 $v_gname = $groupinfo['name'];
1508 }
1509 } else {
1510 $v_uname = '';
1511 $v_gname = '';
1512 }
1513
1514 $v_devmajor = '';
1515
1516 $v_devminor = '';
1517
1518 $v_prefix = '';
1519
1520 $v_binary_data_first = pack(
1521 "a100a8a8a8a12A12",
1522 $p_filename,
1523 $v_perms,
1524 $v_uid,
1525 $v_gid,
1526 $v_size,
1527 $v_mtime
1528 );
1529 $v_binary_data_last = pack(
1530 "a1a100a6a2a32a32a8a8a155a12",
1531 $p_type,
1532 $v_linkname,
1533 $v_magic,
1534 $v_version,
1535 $v_uname,
1536 $v_gname,
1537 $v_devmajor,
1538 $v_devminor,
1539 $v_prefix,
1540 ''
1541 );
1542
1543 // ----- Calculate the checksum
1544 $v_checksum = 0;
1545 // ..... First part of the header
1546 for ($i = 0; $i < 148; $i++) {
1547 $v_checksum += ord(substr($v_binary_data_first, $i, 1));
1548 }
1549 // ..... Ignore the checksum value and replace it by ' ' (space)
1550 for ($i = 148; $i < 156; $i++) {
1551 $v_checksum += ord(' ');
1552 }
1553 // ..... Last part of the header
1554 for ($i = 156, $j = 0; $i < 512; $i++, $j++) {
1555 $v_checksum += ord(substr($v_binary_data_last, $j, 1));
1556 }
1557
1558 // ----- Write the first 148 bytes of the header in the archive
1559 $this->_writeBlock($v_binary_data_first, 148);
1560
1561 // ----- Write the calculated checksum
1562 $v_checksum = sprintf("%06s ", DecOct($v_checksum));
1563 $v_binary_data = pack("a8", $v_checksum);
1564 $this->_writeBlock($v_binary_data, 8);
1565
1566 // ----- Write the last 356 bytes of the header in the archive
1567 $this->_writeBlock($v_binary_data_last, 356);
1568
1569 return true;
1570 }
1571
1576 public function _writeLongHeader($p_filename, $is_link = false)
1577 {
1578 $v_uid = sprintf("%07s", 0);
1579 $v_gid = sprintf("%07s", 0);
1580 $v_perms = sprintf("%07s", 0);
1581 $v_size = sprintf("%'011s", DecOct(strlen($p_filename)));
1582 $v_mtime = sprintf("%011s", 0);
1583 $v_typeflag = ($is_link ? 'K' : 'L');
1584 $v_linkname = '';
1585 $v_magic = 'ustar ';
1586 $v_version = ' ';
1587 $v_uname = '';
1588 $v_gname = '';
1589 $v_devmajor = '';
1590 $v_devminor = '';
1591 $v_prefix = '';
1592
1593 $v_binary_data_first = pack(
1594 "a100a8a8a8a12a12",
1595 '././@LongLink',
1596 $v_perms,
1597 $v_uid,
1598 $v_gid,
1599 $v_size,
1600 $v_mtime
1601 );
1602 $v_binary_data_last = pack(
1603 "a1a100a6a2a32a32a8a8a155a12",
1604 $v_typeflag,
1605 $v_linkname,
1606 $v_magic,
1607 $v_version,
1608 $v_uname,
1609 $v_gname,
1610 $v_devmajor,
1611 $v_devminor,
1612 $v_prefix,
1613 ''
1614 );
1615
1616 // ----- Calculate the checksum
1617 $v_checksum = 0;
1618 // ..... First part of the header
1619 for ($i = 0; $i < 148; $i++) {
1620 $v_checksum += ord(substr($v_binary_data_first, $i, 1));
1621 }
1622 // ..... Ignore the checksum value and replace it by ' ' (space)
1623 for ($i = 148; $i < 156; $i++) {
1624 $v_checksum += ord(' ');
1625 }
1626 // ..... Last part of the header
1627 for ($i = 156, $j = 0; $i < 512; $i++, $j++) {
1628 $v_checksum += ord(substr($v_binary_data_last, $j, 1));
1629 }
1630
1631 // ----- Write the first 148 bytes of the header in the archive
1632 $this->_writeBlock($v_binary_data_first, 148);
1633
1634 // ----- Write the calculated checksum
1635 $v_checksum = sprintf("%06s\0 ", DecOct($v_checksum));
1636 $v_binary_data = pack("a8", $v_checksum);
1637 $this->_writeBlock($v_binary_data, 8);
1638
1639 // ----- Write the last 356 bytes of the header in the archive
1640 $this->_writeBlock($v_binary_data_last, 356);
1641
1642 // ----- Write the filename as content of the block
1643 $i = 0;
1644 while (($v_buffer = substr($p_filename, (($i++) * 512), 512)) != '') {
1645 $v_binary_data = pack("a512", "$v_buffer");
1646 $this->_writeBlock($v_binary_data);
1647 }
1648
1649 return true;
1650 }
1651
1657 public function _readHeader($v_binary_data, &$v_header)
1658 {
1659 if (strlen($v_binary_data) == 0) {
1660 $v_header['filename'] = '';
1661 return true;
1662 }
1663
1664 if (strlen($v_binary_data) != 512) {
1665 $v_header['filename'] = '';
1666 $this->_error('Invalid block size : ' . strlen($v_binary_data));
1667 return false;
1668 }
1669
1670 if (!is_array($v_header)) {
1671 $v_header = array();
1672 }
1673 // ----- Calculate the checksum
1674 $v_checksum = 0;
1675 // ..... First part of the header
1676 $v_binary_split = str_split($v_binary_data);
1677 $v_checksum += array_sum(array_map('ord', array_slice($v_binary_split, 0, 148)));
1678 $v_checksum += array_sum(array_map('ord', array(' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',)));
1679 $v_checksum += array_sum(array_map('ord', array_slice($v_binary_split, 156, 512)));
1680
1681
1682 $v_data = unpack($this->_fmt, $v_binary_data);
1683
1684 if (strlen($v_data["prefix"]) > 0) {
1685 $v_data["filename"] = "$v_data[prefix]/$v_data[filename]";
1686 }
1687
1688 // ----- Extract the checksum
1689 $v_data_checksum = trim($v_data['checksum']);
1690 if (!preg_match('/^[0-7]*$/', $v_data_checksum)) {
1691 $this->_error(
1692 'Invalid checksum for file "' . $v_data['filename']
1693 . '" : ' . $v_data_checksum . ' extracted'
1694 );
1695 return false;
1696 }
1697
1698 $v_header['checksum'] = OctDec($v_data_checksum);
1699 if ($v_header['checksum'] != $v_checksum) {
1700 $v_header['filename'] = '';
1701
1702 // ----- Look for last block (empty block)
1703 if (($v_checksum == 256) && ($v_header['checksum'] == 0)) {
1704 return true;
1705 }
1706
1707 $this->_error(
1708 'Invalid checksum for file "' . $v_data['filename']
1709 . '" : ' . $v_checksum . ' calculated, '
1710 . $v_header['checksum'] . ' expected'
1711 );
1712 return false;
1713 }
1714
1715 // ----- Extract the properties
1716 $v_header['filename'] = rtrim($v_data['filename'], "\0");
1717 if ($this->_isMaliciousFilename($v_header['filename'])) {
1718 $this->_error(
1719 'Malicious .tar detected, file "' . $v_header['filename'] .
1720 '" will not install in desired directory tree'
1721 );
1722 return false;
1723 }
1724 $v_header['mode'] = OctDec(trim($v_data['mode']));
1725 $v_header['uid'] = OctDec(trim($v_data['uid']));
1726 $v_header['gid'] = OctDec(trim($v_data['gid']));
1727 $v_header['size'] = $this->_tarRecToSize($v_data['size']);
1728 $v_header['mtime'] = OctDec(trim($v_data['mtime']));
1729 if (($v_header['typeflag'] = $v_data['typeflag']) == "5") {
1730 $v_header['size'] = 0;
1731 }
1732 $v_header['link'] = trim($v_data['link']);
1733 /* ----- All these fields are removed form the header because
1734 they do not carry interesting info
1735 $v_header[magic] = trim($v_data[magic]);
1736 $v_header[version] = trim($v_data[version]);
1737 $v_header[uname] = trim($v_data[uname]);
1738 $v_header[gname] = trim($v_data[gname]);
1739 $v_header[devmajor] = trim($v_data[devmajor]);
1740 $v_header[devminor] = trim($v_data[devminor]);
1741 */
1742
1743 return true;
1744 }
1745
1752 private function _tarRecToSize($tar_size)
1753 {
1754 /*
1755 * First byte of size has a special meaning if bit 7 is set.
1756 *
1757 * Bit 7 indicates base-256 encoding if set.
1758 * Bit 6 is the sign bit.
1759 * Bits 5:0 are most significant value bits.
1760 */
1761 $ch = ord($tar_size[0]);
1762 if ($ch & 0x80) {
1763 // Full 12-bytes record is required.
1764 $rec_str = $tar_size . "\x00";
1765
1766 $size = ($ch & 0x40) ? -1 : 0;
1767 $size = ($size << 6) | ($ch & 0x3f);
1768
1769 for ($num_ch = 1; $num_ch < 12; ++$num_ch) {
1770 $size = ($size * 256) + ord($rec_str[$num_ch]);
1771 }
1772
1773 return $size;
1774
1775 } else {
1776 return OctDec(trim($tar_size));
1777 }
1778 }
1779
1787 private function _isMaliciousFilename($file)
1788 {
1789 if (strpos($file, '://') !== false) {
1790 return true;
1791 }
1792 if (strpos($file, '../') !== false || strpos($file, '..\\') !== false) {
1793 return true;
1794 }
1795 return false;
1796 }
1797
1802 public function _readLongHeader(&$v_header)
1803 {
1804 $v_filename = '';
1805 $v_filesize = $v_header['size'];
1806 $n = floor($v_header['size'] / 512);
1807 for ($i = 0; $i < $n; $i++) {
1808 $v_content = $this->_readBlock();
1809 $v_filename .= $v_content;
1810 }
1811 if (($v_header['size'] % 512) != 0) {
1812 $v_content = $this->_readBlock();
1813 $v_filename .= $v_content;
1814 }
1815
1816 // ----- Read the next header
1817 $v_binary_data = $this->_readBlock();
1818
1819 if (!$this->_readHeader($v_binary_data, $v_header)) {
1820 return false;
1821 }
1822
1823 $v_filename = rtrim(substr($v_filename, 0, $v_filesize), "\0");
1824 $v_header['filename'] = $v_filename;
1825 if ($this->_isMaliciousFilename($v_filename)) {
1826 $this->_error(
1827 'Malicious .tar detected, file "' . $v_filename .
1828 '" will not install in desired directory tree'
1829 );
1830 return false;
1831 }
1832
1833 return true;
1834 }
1835
1844 private function _extractInString($p_filename)
1845 {
1846 $v_result_str = "";
1847
1848 while (strlen($v_binary_data = $this->_readBlock()) != 0) {
1849 if (!$this->_readHeader($v_binary_data, $v_header)) {
1850 return null;
1851 }
1852
1853 if ($v_header['filename'] == '') {
1854 continue;
1855 }
1856
1857 switch ($v_header['typeflag']) {
1858 case 'L':
1859 {
1860 if (!$this->_readLongHeader($v_header)) {
1861 return null;
1862 }
1863 }
1864 break;
1865
1866 case 'K':
1867 {
1868 $v_link_header = $v_header;
1869 if (!$this->_readLongHeader($v_link_header)) {
1870 return null;
1871 }
1872 $v_header['link'] = $v_link_header['filename'];
1873 }
1874 break;
1875 }
1876
1877 if ($v_header['filename'] == $p_filename) {
1878 if ($v_header['typeflag'] == "5") {
1879 $this->_error(
1880 'Unable to extract in string a directory '
1881 . 'entry {' . $v_header['filename'] . '}'
1882 );
1883 return null;
1884 } else {
1885 $n = floor($v_header['size'] / 512);
1886 for ($i = 0; $i < $n; $i++) {
1887 $v_result_str .= $this->_readBlock();
1888 }
1889 if (($v_header['size'] % 512) != 0) {
1890 $v_content = $this->_readBlock();
1891 $v_result_str .= substr(
1892 $v_content,
1893 0,
1894 ($v_header['size'] % 512)
1895 );
1896 }
1897 return $v_result_str;
1898 }
1899 } else {
1900 $this->_jumpBlock(ceil(($v_header['size'] / 512)));
1901 }
1902 }
1903
1904 return null;
1905 }
1906
1917 public function _extractList(
1918 $p_path,
1919 &$p_list_detail,
1920 $p_mode,
1921 $p_file_list,
1922 $p_remove_path,
1923 $p_preserve = false,
1924 $p_symlinks = true
1925 )
1926 {
1927 $v_result = true;
1928 $v_nb = 0;
1929 $v_extract_all = true;
1930 $v_listing = false;
1931
1932 $p_path = $this->_translateWinPath($p_path, false);
1933 if ($p_path == '' || (substr($p_path, 0, 1) != '/'
1934 && substr($p_path, 0, 3) != "../" && !strpos($p_path, ':'))
1935 ) {
1936 $p_path = "./" . $p_path;
1937 }
1938 $p_remove_path = $this->_translateWinPath($p_remove_path);
1939
1940 // ----- Look for path to remove format (should end by /)
1941 if (($p_remove_path != '') && (substr($p_remove_path, -1) != '/')) {
1942 $p_remove_path .= '/';
1943 }
1944 $p_remove_path_size = strlen($p_remove_path);
1945
1946 switch ($p_mode) {
1947 case "complete" :
1948 $v_extract_all = true;
1949 $v_listing = false;
1950 break;
1951 case "partial" :
1952 $v_extract_all = false;
1953 $v_listing = false;
1954 break;
1955 case "list" :
1956 $v_extract_all = false;
1957 $v_listing = true;
1958 break;
1959 default :
1960 $this->_error('Invalid extract mode (' . $p_mode . ')');
1961 return false;
1962 }
1963
1964 clearstatcache();
1965
1966 while (strlen($v_binary_data = $this->_readBlock()) != 0) {
1967 $v_extract_file = false;
1968 $v_extraction_stopped = 0;
1969
1970 if (!$this->_readHeader($v_binary_data, $v_header)) {
1971 return false;
1972 }
1973
1974 if ($v_header['filename'] == '') {
1975 continue;
1976 }
1977
1978 switch ($v_header['typeflag']) {
1979 case 'L':
1980 {
1981 if (!$this->_readLongHeader($v_header)) {
1982 return null;
1983 }
1984 }
1985 break;
1986
1987 case 'K':
1988 {
1989 $v_link_header = $v_header;
1990 if (!$this->_readLongHeader($v_link_header)) {
1991 return null;
1992 }
1993 $v_header['link'] = $v_link_header['filename'];
1994 }
1995 break;
1996 }
1997
1998 // ignore extended / pax headers
1999 if ($v_header['typeflag'] == 'x' || $v_header['typeflag'] == 'g') {
2000 $this->_jumpBlock(ceil(($v_header['size'] / 512)));
2001 continue;
2002 }
2003
2004 if ((!$v_extract_all) && (is_array($p_file_list))) {
2005 // ----- By default no unzip if the file is not found
2006 $v_extract_file = false;
2007
2008 for ($i = 0; $i < sizeof($p_file_list); $i++) {
2009 // ----- Look if it is a directory
2010 if (substr($p_file_list[$i], -1) == '/') {
2011 // ----- Look if the directory is in the filename path
2012 if ((strlen($v_header['filename']) > strlen($p_file_list[$i]))
2013 && (substr($v_header['filename'], 0, strlen($p_file_list[$i]))
2014 == $p_file_list[$i])
2015 ) {
2016 $v_extract_file = true;
2017 break;
2018 }
2019 } // ----- It is a file, so compare the file names
2020 elseif ($p_file_list[$i] == $v_header['filename']) {
2021 $v_extract_file = true;
2022 break;
2023 }
2024 }
2025 } else {
2026 $v_extract_file = true;
2027 }
2028
2029 // ----- Look if this file need to be extracted
2030 if (($v_extract_file) && (!$v_listing)) {
2031 if (($p_remove_path != '')
2032 && (substr($v_header['filename'] . '/', 0, $p_remove_path_size)
2033 == $p_remove_path)
2034 ) {
2035 $v_header['filename'] = substr(
2036 $v_header['filename'],
2037 $p_remove_path_size
2038 );
2039 if ($v_header['filename'] == '') {
2040 continue;
2041 }
2042 }
2043 if (($p_path != './') && ($p_path != '/')) {
2044 while (substr($p_path, -1) == '/') {
2045 $p_path = substr($p_path, 0, strlen($p_path) - 1);
2046 }
2047
2048 if (substr($v_header['filename'], 0, 1) == '/') {
2049 $v_header['filename'] = $p_path . $v_header['filename'];
2050 } else {
2051 $v_header['filename'] = $p_path . '/' . $v_header['filename'];
2052 }
2053 }
2054 if (file_exists($v_header['filename'])) {
2055 if ((@is_dir($v_header['filename']))
2056 && ($v_header['typeflag'] == '')
2057 ) {
2058 $this->_error(
2059 'File ' . $v_header['filename']
2060 . ' already exists as a directory'
2061 );
2062 return false;
2063 }
2064 if (($this->_isArchive($v_header['filename']))
2065 && ($v_header['typeflag'] == "5")
2066 ) {
2067 $this->_error(
2068 'Directory ' . $v_header['filename']
2069 . ' already exists as a file'
2070 );
2071 return false;
2072 }
2073 if (!is_writeable($v_header['filename'])) {
2074 $this->_error(
2075 'File ' . $v_header['filename']
2076 . ' already exists and is write protected'
2077 );
2078 return false;
2079 }
2080 if (filemtime($v_header['filename']) > $v_header['mtime']) {
2081 // To be completed : An error or silent no replace ?
2082 }
2083 } // ----- Check the directory availability and create it if necessary
2084 elseif (($v_result
2085 = $this->_dirCheck(
2086 ($v_header['typeflag'] == "5"
2087 ? $v_header['filename']
2088 : dirname($v_header['filename']))
2089 )) != 1
2090 ) {
2091 $this->_error('Unable to create path for ' . $v_header['filename']);
2092 return false;
2093 }
2094
2095 if ($v_extract_file) {
2096 if ($v_header['typeflag'] == "5") {
2097 if (!@file_exists($v_header['filename'])) {
2098 if (!@mkdir($v_header['filename'], 0775)) {
2099 $this->_error(
2100 'Unable to create directory {'
2101 . $v_header['filename'] . '}'
2102 );
2103 return false;
2104 }
2105 }
2106 } elseif ($v_header['typeflag'] == "2") {
2107 if (!$p_symlinks) {
2108 $this->_warning('Symbolic links are not allowed. '
2109 . 'Unable to extract {'
2110 . $v_header['filename'] . '}'
2111 );
2112 return false;
2113 }
2114 $absolute_link = FALSE;
2115 $link_depth = 0;
2116 if (strpos($v_header['link'], "/") === 0 || strpos($v_header['link'], ':') !== FALSE) {
2117 $absolute_link = TRUE;
2118 }
2119 else {
2120 $s_filename = preg_replace('@^' . preg_quote($p_path) . '@', "", $v_header['filename']);
2121 $s_linkname = str_replace('\\', '/', $v_header['link']);
2122 foreach (explode("/", $s_filename) as $dir) {
2123 if ($dir === "..") {
2124 $link_depth--;
2125 } elseif ($dir !== "" && $dir !== "." ) {
2126 $link_depth++;
2127 }
2128 }
2129 foreach (explode("/", $s_linkname) as $dir){
2130 if ($link_depth <= 0) {
2131 break;
2132 }
2133 if ($dir === "..") {
2134 $link_depth--;
2135 } elseif ($dir !== "" && $dir !== ".") {
2136 $link_depth++;
2137 }
2138 }
2139 }
2140 if ($absolute_link || $link_depth <= 0) {
2141 $this->_error(
2142 'Out-of-path file extraction {'
2143 . $v_header['filename'] . ' --> ' .
2144 $v_header['link'] . '}'
2145 );
2146 return false;
2147 }
2148 if (@file_exists($v_header['filename'])) {
2149 @unlink($v_header['filename']);
2150 }
2151 if (!@symlink($v_header['link'], $v_header['filename'])) {
2152 $this->_error(
2153 'Unable to extract symbolic link {'
2154 . $v_header['filename'] . '}'
2155 );
2156 return false;
2157 }
2158 } else {
2159 if (($v_dest_file = @fopen($v_header['filename'], "wb")) == 0) {
2160 $this->_error(
2161 'Error while opening {' . $v_header['filename']
2162 . '} in write binary mode'
2163 );
2164 return false;
2165 } else {
2166 $n = floor($v_header['size'] / 512);
2167 for ($i = 0; $i < $n; $i++) {
2168 $v_content = $this->_readBlock();
2169 fwrite($v_dest_file, $v_content, 512);
2170 }
2171 if (($v_header['size'] % 512) != 0) {
2172 $v_content = $this->_readBlock();
2173 fwrite($v_dest_file, $v_content, ($v_header['size'] % 512));
2174 }
2175
2176 @fclose($v_dest_file);
2177
2178 if ($p_preserve) {
2179 @chown($v_header['filename'], $v_header['uid']);
2180 @chgrp($v_header['filename'], $v_header['gid']);
2181 }
2182
2183 // ----- Change the file mode, mtime
2184 @touch($v_header['filename'], $v_header['mtime']);
2185 if ($v_header['mode'] & 0111) {
2186 // make file executable, obey umask
2187 $mode = fileperms($v_header['filename']) | (~umask() & 0111);
2188 @chmod($v_header['filename'], $mode);
2189 }
2190 }
2191
2192 // ----- Check the file size
2193 clearstatcache();
2194 if (!is_file($v_header['filename'])) {
2195 $this->_error(
2196 'Extracted file ' . $v_header['filename']
2197 . 'does not exist. Archive may be corrupted.'
2198 );
2199 return false;
2200 }
2201
2202 $filesize = filesize($v_header['filename']);
2203 if ($filesize != $v_header['size']) {
2204 $this->_error(
2205 'Extracted file ' . $v_header['filename']
2206 . ' does not have the correct file size \''
2207 . $filesize
2208 . '\' (' . $v_header['size']
2209 . ' expected). Archive may be corrupted.'
2210 );
2211 return false;
2212 }
2213 }
2214 } else {
2215 $this->_jumpBlock(ceil(($v_header['size'] / 512)));
2216 }
2217 } else {
2218 $this->_jumpBlock(ceil(($v_header['size'] / 512)));
2219 }
2220
2221 /* TBC : Seems to be unused ...
2222 if ($this->_compress)
2223 $v_end_of_file = @gzeof($this->_file);
2224 else
2225 $v_end_of_file = @feof($this->_file);
2226 */
2227
2228 if ($v_listing || $v_extract_file || $v_extraction_stopped) {
2229 // ----- Log extracted files
2230 if (($v_file_dir = dirname($v_header['filename']))
2231 == $v_header['filename']
2232 ) {
2233 $v_file_dir = '';
2234 }
2235 if ((substr($v_header['filename'], 0, 1) == '/') && ($v_file_dir == '')) {
2236 $v_file_dir = '/';
2237 }
2238
2239 $p_list_detail[$v_nb++] = $v_header;
2240 if (is_array($p_file_list) && (count($p_list_detail) == count($p_file_list))) {
2241 return true;
2242 }
2243 }
2244 }
2245
2246 return true;
2247 }
2248
2252 public function _openAppend()
2253 {
2254 if (filesize($this->_tarname) == 0) {
2255 return $this->_openWrite();
2256 }
2257
2258 if ($this->_compress) {
2259 $this->_close();
2260
2261 if (!@rename($this->_tarname, $this->_tarname . ".tmp")) {
2262 $this->_error(
2263 'Error while renaming \'' . $this->_tarname
2264 . '\' to temporary file \'' . $this->_tarname
2265 . '.tmp\''
2266 );
2267 return false;
2268 }
2269
2270 if ($this->_compress_type == 'gz') {
2271 $v_temp_tar = @gzopen($this->_tarname . ".tmp", "rb");
2272 } elseif ($this->_compress_type == 'bz2') {
2273 $v_temp_tar = @bzopen($this->_tarname . ".tmp", "r");
2274 } elseif ($this->_compress_type == 'lzma2') {
2275 $v_temp_tar = @xzopen($this->_tarname . ".tmp", "r");
2276 }
2277
2278
2279 if ($v_temp_tar == 0) {
2280 $this->_error(
2281 'Unable to open file \'' . $this->_tarname
2282 . '.tmp\' in binary read mode'
2283 );
2284 @rename($this->_tarname . ".tmp", $this->_tarname);
2285 return false;
2286 }
2287
2288 if (!$this->_openWrite()) {
2289 @rename($this->_tarname . ".tmp", $this->_tarname);
2290 return false;
2291 }
2292
2293 if ($this->_compress_type == 'gz') {
2294 $end_blocks = 0;
2295
2296 while (!@gzeof($v_temp_tar)) {
2297 $v_buffer = @gzread($v_temp_tar, 512);
2298 if ($v_buffer == ARCHIVE_TAR_END_BLOCK || strlen($v_buffer) == 0) {
2299 $end_blocks++;
2300 // do not copy end blocks, we will re-make them
2301 // after appending
2302 continue;
2303 } elseif ($end_blocks > 0) {
2304 for ($i = 0; $i < $end_blocks; $i++) {
2306 }
2307 $end_blocks = 0;
2308 }
2309 $v_binary_data = pack("a512", $v_buffer);
2310 $this->_writeBlock($v_binary_data);
2311 }
2312
2313 @gzclose($v_temp_tar);
2314 } elseif ($this->_compress_type == 'bz2') {
2315 $end_blocks = 0;
2316
2317 while (strlen($v_buffer = @bzread($v_temp_tar, 512)) > 0) {
2318 if ($v_buffer == ARCHIVE_TAR_END_BLOCK || strlen($v_buffer) == 0) {
2319 $end_blocks++;
2320 // do not copy end blocks, we will re-make them
2321 // after appending
2322 continue;
2323 } elseif ($end_blocks > 0) {
2324 for ($i = 0; $i < $end_blocks; $i++) {
2326 }
2327 $end_blocks = 0;
2328 }
2329 $v_binary_data = pack("a512", $v_buffer);
2330 $this->_writeBlock($v_binary_data);
2331 }
2332
2333 @bzclose($v_temp_tar);
2334 } elseif ($this->_compress_type == 'lzma2') {
2335 $end_blocks = 0;
2336
2337 while (strlen($v_buffer = @xzread($v_temp_tar, 512)) > 0) {
2338 if ($v_buffer == ARCHIVE_TAR_END_BLOCK || strlen($v_buffer) == 0) {
2339 $end_blocks++;
2340 // do not copy end blocks, we will re-make them
2341 // after appending
2342 continue;
2343 } elseif ($end_blocks > 0) {
2344 for ($i = 0; $i < $end_blocks; $i++) {
2346 }
2347 $end_blocks = 0;
2348 }
2349 $v_binary_data = pack("a512", $v_buffer);
2350 $this->_writeBlock($v_binary_data);
2351 }
2352
2353 @xzclose($v_temp_tar);
2354 }
2355
2356 if (!@unlink($this->_tarname . ".tmp")) {
2357 $this->_error(
2358 'Error while deleting temporary file \''
2359 . $this->_tarname . '.tmp\''
2360 );
2361 }
2362 } else {
2363 // ----- For not compressed tar, just add files before the last
2364 // one or two 512 bytes block
2365 if (!$this->_openReadWrite()) {
2366 return false;
2367 }
2368
2369 clearstatcache();
2370 $v_size = filesize($this->_tarname);
2371
2372 // We might have zero, one or two end blocks.
2373 // The standard is two, but we should try to handle
2374 // other cases.
2375 fseek($this->_file, $v_size - 1024);
2376 if (fread($this->_file, 512) == ARCHIVE_TAR_END_BLOCK) {
2377 fseek($this->_file, $v_size - 1024);
2378 } elseif (fread($this->_file, 512) == ARCHIVE_TAR_END_BLOCK) {
2379 fseek($this->_file, $v_size - 512);
2380 }
2381 }
2382
2383 return true;
2384 }
2385
2392 public function _append($p_filelist, $p_add_dir = '', $p_remove_dir = '')
2393 {
2394 if (!$this->_openAppend()) {
2395 return false;
2396 }
2397
2398 if ($this->_addList($p_filelist, $p_add_dir, $p_remove_dir)) {
2399 $this->_writeFooter();
2400 }
2401
2402 $this->_close();
2403
2404 return true;
2405 }
2406
2415 public function _dirCheck($p_dir)
2416 {
2417 clearstatcache();
2418 if ((@is_dir($p_dir)) || ($p_dir == '')) {
2419 return true;
2420 }
2421
2422 $p_parent_dir = dirname($p_dir);
2423
2424 if (($p_parent_dir != $p_dir) &&
2425 ($p_parent_dir != '') &&
2426 (!$this->_dirCheck($p_parent_dir))
2427 ) {
2428 return false;
2429 }
2430
2431 if (!@mkdir($p_dir, 0775)) {
2432 $this->_error("Unable to create directory '$p_dir'");
2433 return false;
2434 }
2435
2436 return true;
2437 }
2438
2447 private function _pathReduction($p_dir)
2448 {
2449 $v_result = '';
2450
2451 // ----- Look for not empty path
2452 if ($p_dir != '') {
2453 // ----- Explode path by directory names
2454 $v_list = explode('/', $p_dir);
2455
2456 // ----- Study directories from last to first
2457 for ($i = sizeof($v_list) - 1; $i >= 0; $i--) {
2458 // ----- Look for current path
2459 if ($v_list[$i] == ".") {
2460 // ----- Ignore this directory
2461 // Should be the first $i=0, but no check is done
2462 } else {
2463 if ($v_list[$i] == "..") {
2464 // ----- Ignore it and ignore the $i-1
2465 $i--;
2466 } else {
2467 if (($v_list[$i] == '')
2468 && ($i != (sizeof($v_list) - 1))
2469 && ($i != 0)
2470 ) {
2471 // ----- Ignore only the double '//' in path,
2472 // but not the first and last /
2473 } else {
2474 $v_result = $v_list[$i] . ($i != (sizeof($v_list) - 1) ? '/'
2475 . $v_result : '');
2476 }
2477 }
2478 }
2479 }
2480 }
2481
2482 if (defined('OS_WINDOWS') && OS_WINDOWS) {
2483 $v_result = strtr($v_result, '\\', '/');
2484 }
2485
2486 return $v_result;
2487 }
2488
2494 public function _translateWinPath($p_path, $p_remove_disk_letter = true)
2495 {
2496 if (defined('OS_WINDOWS') && OS_WINDOWS) {
2497 // ----- Look for potential disk letter
2498 if (($p_remove_disk_letter)
2499 && (($v_position = strpos($p_path, ':')) != false)
2500 ) {
2501 $p_path = substr($p_path, $v_position + 1);
2502 }
2503 // ----- Change potential windows directory separator
2504 if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0, 1) == '\\')) {
2505 $p_path = strtr($p_path, '\\', '/');
2506 }
2507 }
2508 return $p_path;
2509 }
2510}
const ARCHIVE_TAR_END_BLOCK
Definition Tar.php:49
const ARCHIVE_TAR_ATT_SEPARATOR(!class_exists('PEAR'))
Definition Tar.php:48
_tarRecToSize($tar_size)
Definition Tar.php:1752
__construct($p_tarname, $p_compress=null, $buffer_length=512)
Definition Tar.php:129
_readLongHeader(&$v_header)
Definition Tar.php:1802
$_compress_type
Definition Tar.php:74
extractModify($p_path, $p_remove_path, $p_preserve=false, $p_symlinks=true)
Definition Tar.php:545
_extractInString($p_filename)
Definition Tar.php:1844
_addString($p_filename, $p_string, $p_datetime=false, $p_params=array())
Definition Tar.php:1281
create($p_filelist)
Definition Tar.php:265
_translateWinPath($p_path, $p_remove_disk_letter=true)
Definition Tar.php:2494
__destruct()
Definition Tar.php:235
_cleanFile()
Definition Tar.php:946
_openReadWrite()
Definition Tar.php:859
_extractList( $p_path, &$p_list_detail, $p_mode, $p_file_list, $p_remove_path, $p_preserve=false, $p_symlinks=true)
Definition Tar.php:1917
_writeLongHeader($p_filename, $is_link=false)
Definition Tar.php:1576
_openRead()
Definition Tar.php:788
setIgnoreRegexp($regexp)
Definition Tar.php:697
add($p_filelist)
Definition Tar.php:286
_isMaliciousFilename($file)
Definition Tar.php:1787
extract($p_path='', $p_preserve=false, $p_symlinks=true)
Definition Tar.php:297
$_separator
Definition Tar.php:79
_dirCheck($p_dir)
Definition Tar.php:2415
_writeHeaderBlock( $p_filename, $p_size, $p_mtime=0, $p_perms=0, $p_type='', $p_uid=0, $p_gid=0)
Definition Tar.php:1462
setAttribute()
Definition Tar.php:644
$_temp_tarname
Definition Tar.php:89
$_ignore_regexp
Definition Tar.php:94
_warning($p_message)
Definition Tar.php:729
_error($p_message)
Definition Tar.php:721
_openWrite()
Definition Tar.php:750
_pathReduction($p_dir)
Definition Tar.php:2447
listContent()
Definition Tar.php:305
_readBlock()
Definition Tar.php:1019
$error_object
Definition Tar.php:99
extractInString($p_filename)
Definition Tar.php:574
$buffer_length
Definition Tar.php:111
_addFile($p_filename, &$p_header, $p_add_dir, $p_remove_dir, $v_stored_filename=null)
Definition Tar.php:1193
_append($p_filelist, $p_add_dir='', $p_remove_dir='')
Definition Tar.php:2392
_writeHeader($p_filename, $p_stored_filename)
Definition Tar.php:1335
createModify($p_filelist, $p_add_dir, $p_remove_dir='')
Definition Tar.php:355
addModify($p_filelist, $p_add_dir, $p_remove_dir='')
Definition Tar.php:427
extractList($p_filelist, $p_path='', $p_remove_path='', $p_preserve=false, $p_symlinks=true)
Definition Tar.php:607
setIgnoreList($list)
Definition Tar.php:711
_isArchive($p_filename=null)
Definition Tar.php:738
_writeBlock($p_binary_data, $p_len=null)
Definition Tar.php:969
_addList($p_list, $p_add_dir, $p_remove_dir)
Definition Tar.php:1107
_writeFooter()
Definition Tar.php:1091
addString($p_filename, $p_string, $p_datetime=false, $p_params=array())
Definition Tar.php:480
_readHeader($v_binary_data, &$v_header)
Definition Tar.php:1657
_openAppend()
Definition Tar.php:2252
_jumpBlock($p_len=null)
Definition Tar.php:1051
static loadExtension($ext)
Definition PEAR.php:751