Open Journal Systems  3.3.0
Tar.php
1 <?php
2 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3 
42 // If the PEAR class cannot be loaded via the autoloader,
43 // then try to require_once it from the PHP include path.
44 if (!class_exists('PEAR')) {
45  require_once 'PEAR.php';
46 }
47 
48 define('ARCHIVE_TAR_ATT_SEPARATOR', 90001);
49 define('ARCHIVE_TAR_END_BLOCK', pack("a512", ''));
50 
51 if (!function_exists('gzopen') && function_exists('gzopen64')) {
52  function gzopen($filename, $mode, $use_include_path = 0)
53  {
54  return gzopen64($filename, $mode, $use_include_path);
55  }
56 }
57 
58 if (!function_exists('gztell') && function_exists('gztell64')) {
59  function gztell($zp)
60  {
61  return gztell64($zp);
62  }
63 }
64 
65 if (!function_exists('gzseek') && function_exists('gzseek64')) {
66  function gzseek($zp, $offset, $whence = SEEK_SET)
67  {
68  return gzseek64($zp, $offset, $whence);
69  }
70 }
71 
80 class Archive_Tar extends PEAR
81 {
85  public $_tarname = '';
86 
90  public $_compress = false;
91 
95  public $_compress_type = 'none';
96 
100  public $_separator = ' ';
101 
105  public $_file = 0;
106 
110  public $_temp_tarname = '';
111 
115  public $_ignore_regexp = '';
116 
120  public $error_object = null;
121 
127  public $_fmt = '';
128 
132  protected $buffer_length;
133 
150  public function __construct($p_tarname, $p_compress = null, $buffer_length = 512)
151  {
152  parent::__construct();
153 
154  $this->_compress = false;
155  $this->_compress_type = 'none';
156  if (($p_compress === null) || ($p_compress == '')) {
157  if (@file_exists($p_tarname)) {
158  if ($fp = @fopen($p_tarname, "rb")) {
159  // look for gzip magic cookie
160  $data = fread($fp, 2);
161  fclose($fp);
162  if ($data == "\37\213") {
163  $this->_compress = true;
164  $this->_compress_type = 'gz';
165  // No sure it's enought for a magic code ....
166  } elseif ($data == "BZ") {
167  $this->_compress = true;
168  $this->_compress_type = 'bz2';
169  } elseif (file_get_contents($p_tarname, false, null, 1, 4) == '7zXZ') {
170  $this->_compress = true;
171  $this->_compress_type = 'lzma2';
172  }
173  }
174  } else {
175  // probably a remote file or some file accessible
176  // through a stream interface
177  if (substr($p_tarname, -2) == 'gz') {
178  $this->_compress = true;
179  $this->_compress_type = 'gz';
180  } elseif ((substr($p_tarname, -3) == 'bz2') ||
181  (substr($p_tarname, -2) == 'bz')
182  ) {
183  $this->_compress = true;
184  $this->_compress_type = 'bz2';
185  } else {
186  if (substr($p_tarname, -2) == 'xz') {
187  $this->_compress = true;
188  $this->_compress_type = 'lzma2';
189  }
190  }
191  }
192  } else {
193  if (($p_compress === true) || ($p_compress == 'gz')) {
194  $this->_compress = true;
195  $this->_compress_type = 'gz';
196  } else {
197  if ($p_compress == 'bz2') {
198  $this->_compress = true;
199  $this->_compress_type = 'bz2';
200  } else {
201  if ($p_compress == 'lzma2') {
202  $this->_compress = true;
203  $this->_compress_type = 'lzma2';
204  } else {
205  $this->_error(
206  "Unsupported compression type '$p_compress'\n" .
207  "Supported types are 'gz', 'bz2' and 'lzma2'.\n"
208  );
209  return false;
210  }
211  }
212  }
213  }
214  $this->_tarname = $p_tarname;
215  if ($this->_compress) { // assert zlib or bz2 or xz extension support
216  if ($this->_compress_type == 'gz') {
217  $extname = 'zlib';
218  } else {
219  if ($this->_compress_type == 'bz2') {
220  $extname = 'bz2';
221  } else {
222  if ($this->_compress_type == 'lzma2') {
223  $extname = 'xz';
224  }
225  }
226  }
227 
228  if (!extension_loaded($extname)) {
229  PEAR::loadExtension($extname);
230  }
231  if (!extension_loaded($extname)) {
232  $this->_error(
233  "The extension '$extname' couldn't be found.\n" .
234  "Please make sure your version of PHP was built " .
235  "with '$extname' support.\n"
236  );
237  return false;
238  }
239  }
240 
241 
242  if (version_compare(PHP_VERSION, "5.5.0-dev") < 0) {
243  $this->_fmt = "a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/" .
244  "a8checksum/a1typeflag/a100link/a6magic/a2version/" .
245  "a32uname/a32gname/a8devmajor/a8devminor/a131prefix";
246  } else {
247  $this->_fmt = "Z100filename/Z8mode/Z8uid/Z8gid/Z12size/Z12mtime/" .
248  "Z8checksum/Z1typeflag/Z100link/Z6magic/Z2version/" .
249  "Z32uname/Z32gname/Z8devmajor/Z8devminor/Z131prefix";
250  }
251 
252 
253  $this->buffer_length = $buffer_length;
254  }
255 
256  public function __destruct()
257  {
258  $this->_close();
259  // ----- Look for a local copy to delete
260  if ($this->_temp_tarname != '') {
261  @unlink($this->_temp_tarname);
262  }
263  }
264 
286  public function create($p_filelist)
287  {
288  return $this->createModify($p_filelist, '', '');
289  }
290 
307  public function add($p_filelist)
308  {
309  return $this->addModify($p_filelist, '', '');
310  }
311 
318  public function extract($p_path = '', $p_preserve = false, $p_symlinks = true)
319  {
320  return $this->extractModify($p_path, '', $p_preserve, $p_symlinks);
321  }
322 
326  public function listContent()
327  {
328  $v_list_detail = array();
329 
330  if ($this->_openRead()) {
331  if (!$this->_extractList('', $v_list_detail, "list", '', '')) {
332  unset($v_list_detail);
333  $v_list_detail = 0;
334  }
335  $this->_close();
336  }
337 
338  return $v_list_detail;
339  }
340 
376  public function createModify($p_filelist, $p_add_dir, $p_remove_dir = '')
377  {
378  $v_result = true;
379 
380  if (!$this->_openWrite()) {
381  return false;
382  }
383 
384  if ($p_filelist != '') {
385  if (is_array($p_filelist)) {
386  $v_list = $p_filelist;
387  } elseif (is_string($p_filelist)) {
388  $v_list = explode($this->_separator, $p_filelist);
389  } else {
390  $this->_cleanFile();
391  $this->_error('Invalid file list');
392  return false;
393  }
394 
395  $v_result = $this->_addList($v_list, $p_add_dir, $p_remove_dir);
396  }
397 
398  if ($v_result) {
399  $this->_writeFooter();
400  $this->_close();
401  } else {
402  $this->_cleanFile();
403  }
404 
405  return $v_result;
406  }
407 
448  public function addModify($p_filelist, $p_add_dir, $p_remove_dir = '')
449  {
450  $v_result = true;
451 
452  if (!$this->_isArchive()) {
453  $v_result = $this->createModify(
454  $p_filelist,
455  $p_add_dir,
456  $p_remove_dir
457  );
458  } else {
459  if (is_array($p_filelist)) {
460  $v_list = $p_filelist;
461  } elseif (is_string($p_filelist)) {
462  $v_list = explode($this->_separator, $p_filelist);
463  } else {
464  $this->_error('Invalid file list');
465  return false;
466  }
467 
468  $v_result = $this->_append($v_list, $p_add_dir, $p_remove_dir);
469  }
470 
471  return $v_result;
472  }
473 
501  public function addString($p_filename, $p_string, $p_datetime = false, $p_params = array())
502  {
503  $p_stamp = @$p_params["stamp"] ? $p_params["stamp"] : ($p_datetime ? $p_datetime : time());
504  $p_mode = @$p_params["mode"] ? $p_params["mode"] : 0600;
505  $p_type = @$p_params["type"] ? $p_params["type"] : "";
506  $p_uid = @$p_params["uid"] ? $p_params["uid"] : "";
507  $p_gid = @$p_params["gid"] ? $p_params["gid"] : "";
508  $v_result = true;
509 
510  if (!$this->_isArchive()) {
511  if (!$this->_openWrite()) {
512  return false;
513  }
514  $this->_close();
515  }
516 
517  if (!$this->_openAppend()) {
518  return false;
519  }
520 
521  // Need to check the get back to the temporary file ? ....
522  $v_result = $this->_addString($p_filename, $p_string, $p_datetime, $p_params);
523 
524  $this->_writeFooter();
525 
526  $this->_close();
527 
528  return $v_result;
529  }
530 
566  public function extractModify($p_path, $p_remove_path, $p_preserve = false, $p_symlinks = true)
567  {
568  $v_result = true;
569  $v_list_detail = array();
570 
571  if ($v_result = $this->_openRead()) {
572  $v_result = $this->_extractList(
573  $p_path,
574  $v_list_detail,
575  "complete",
576  0,
577  $p_remove_path,
578  $p_preserve,
579  $p_symlinks
580  );
581  $this->_close();
582  }
583 
584  return $v_result;
585  }
586 
595  public function extractInString($p_filename)
596  {
597  if ($this->_openRead()) {
598  $v_result = $this->_extractInString($p_filename);
599  $this->_close();
600  } else {
601  $v_result = null;
602  }
603 
604  return $v_result;
605  }
606 
628  public function extractList($p_filelist, $p_path = '', $p_remove_path = '', $p_preserve = false, $p_symlinks = true)
629  {
630  $v_result = true;
631  $v_list_detail = array();
632 
633  if (is_array($p_filelist)) {
634  $v_list = $p_filelist;
635  } elseif (is_string($p_filelist)) {
636  $v_list = explode($this->_separator, $p_filelist);
637  } else {
638  $this->_error('Invalid string list');
639  return false;
640  }
641 
642  if ($v_result = $this->_openRead()) {
643  $v_result = $this->_extractList(
644  $p_path,
645  $v_list_detail,
646  "partial",
647  $v_list,
648  $p_remove_path,
649  $p_preserve,
650  $p_symlinks
651  );
652  $this->_close();
653  }
654 
655  return $v_result;
656  }
657 
665  public function setAttribute()
666  {
667  $v_result = true;
668 
669  // ----- Get the number of variable list of arguments
670  if (($v_size = func_num_args()) == 0) {
671  return true;
672  }
673 
674  // ----- Get the arguments
675  $v_att_list = func_get_args();
676 
677  // ----- Read the attributes
678  $i = 0;
679  while ($i < $v_size) {
680 
681  // ----- Look for next option
682  switch ($v_att_list[$i]) {
683  // ----- Look for options that request a string value
684  case ARCHIVE_TAR_ATT_SEPARATOR :
685  // ----- Check the number of parameters
686  if (($i + 1) >= $v_size) {
687  $this->_error(
688  'Invalid number of parameters for '
689  . 'attribute ARCHIVE_TAR_ATT_SEPARATOR'
690  );
691  return false;
692  }
693 
694  // ----- Get the value
695  $this->_separator = $v_att_list[$i + 1];
696  $i++;
697  break;
698 
699  default :
700  $this->_error('Unknown attribute code ' . $v_att_list[$i] . '');
701  return false;
702  }
703 
704  // ----- Next attribute
705  $i++;
706  }
707 
708  return $v_result;
709  }
710 
718  public function setIgnoreRegexp($regexp)
719  {
720  $this->_ignore_regexp = $regexp;
721  }
722 
732  public function setIgnoreList($list)
733  {
734  $regexp = str_replace(array('#', '.', '^', '$'), array('\#', '\.', '\^', '\$'), $list);
735  $regexp = '#/' . join('$|/', $list) . '#';
736  $this->setIgnoreRegexp($regexp);
737  }
738 
742  public function _error($p_message)
743  {
744  $this->error_object = $this->raiseError($p_message);
745  }
746 
750  public function _warning($p_message)
751  {
752  $this->error_object = $this->raiseError($p_message);
753  }
754 
759  public function _isArchive($p_filename = null)
760  {
761  if ($p_filename == null) {
762  $p_filename = $this->_tarname;
763  }
764  clearstatcache();
765  return @is_file($p_filename) && !@is_link($p_filename);
766  }
767 
771  public function _openWrite()
772  {
773  if ($this->_compress_type == 'gz' && function_exists('gzopen')) {
774  $this->_file = @gzopen($this->_tarname, "wb9");
775  } else {
776  if ($this->_compress_type == 'bz2' && function_exists('bzopen')) {
777  $this->_file = @bzopen($this->_tarname, "w");
778  } else {
779  if ($this->_compress_type == 'lzma2' && function_exists('xzopen')) {
780  $this->_file = @xzopen($this->_tarname, 'w');
781  } else {
782  if ($this->_compress_type == 'none') {
783  $this->_file = @fopen($this->_tarname, "wb");
784  } else {
785  $this->_error(
786  'Unknown or missing compression type ('
787  . $this->_compress_type . ')'
788  );
789  return false;
790  }
791  }
792  }
793  }
794 
795  if ($this->_file == 0) {
796  $this->_error(
797  'Unable to open in write mode \''
798  . $this->_tarname . '\''
799  );
800  return false;
801  }
802 
803  return true;
804  }
805 
809  public function _openRead()
810  {
811  if (strtolower(substr($this->_tarname, 0, 7)) == 'http://') {
812 
813  // ----- Look if a local copy need to be done
814  if ($this->_temp_tarname == '') {
815  $this->_temp_tarname = uniqid('tar') . '.tmp';
816  if (!$v_file_from = @fopen($this->_tarname, 'rb')) {
817  $this->_error(
818  'Unable to open in read mode \''
819  . $this->_tarname . '\''
820  );
821  $this->_temp_tarname = '';
822  return false;
823  }
824  if (!$v_file_to = @fopen($this->_temp_tarname, 'wb')) {
825  $this->_error(
826  'Unable to open in write mode \''
827  . $this->_temp_tarname . '\''
828  );
829  $this->_temp_tarname = '';
830  return false;
831  }
832  while ($v_data = @fread($v_file_from, 1024)) {
833  @fwrite($v_file_to, $v_data);
834  }
835  @fclose($v_file_from);
836  @fclose($v_file_to);
837  }
838 
839  // ----- File to open if the local copy
840  $v_filename = $this->_temp_tarname;
841  } else {
842  // ----- File to open if the normal Tar file
843 
844  $v_filename = $this->_tarname;
845  }
846 
847  if ($this->_compress_type == 'gz' && function_exists('gzopen')) {
848  $this->_file = @gzopen($v_filename, "rb");
849  } else {
850  if ($this->_compress_type == 'bz2' && function_exists('bzopen')) {
851  $this->_file = @bzopen($v_filename, "r");
852  } else {
853  if ($this->_compress_type == 'lzma2' && function_exists('xzopen')) {
854  $this->_file = @xzopen($v_filename, "r");
855  } else {
856  if ($this->_compress_type == 'none') {
857  $this->_file = @fopen($v_filename, "rb");
858  } else {
859  $this->_error(
860  'Unknown or missing compression type ('
861  . $this->_compress_type . ')'
862  );
863  return false;
864  }
865  }
866  }
867  }
868 
869  if ($this->_file == 0) {
870  $this->_error('Unable to open in read mode \'' . $v_filename . '\'');
871  return false;
872  }
873 
874  return true;
875  }
876 
880  public function _openReadWrite()
881  {
882  if ($this->_compress_type == 'gz') {
883  $this->_file = @gzopen($this->_tarname, "r+b");
884  } else {
885  if ($this->_compress_type == 'bz2') {
886  $this->_error(
887  'Unable to open bz2 in read/write mode \''
888  . $this->_tarname . '\' (limitation of bz2 extension)'
889  );
890  return false;
891  } else {
892  if ($this->_compress_type == 'lzma2') {
893  $this->_error(
894  'Unable to open lzma2 in read/write mode \''
895  . $this->_tarname . '\' (limitation of lzma2 extension)'
896  );
897  return false;
898  } else {
899  if ($this->_compress_type == 'none') {
900  $this->_file = @fopen($this->_tarname, "r+b");
901  } else {
902  $this->_error(
903  'Unknown or missing compression type ('
904  . $this->_compress_type . ')'
905  );
906  return false;
907  }
908  }
909  }
910  }
911 
912  if ($this->_file == 0) {
913  $this->_error(
914  'Unable to open in read/write mode \''
915  . $this->_tarname . '\''
916  );
917  return false;
918  }
919 
920  return true;
921  }
922 
926  public function _close()
927  {
928  //if (isset($this->_file)) {
929  if (is_resource($this->_file)) {
930  if ($this->_compress_type == 'gz') {
931  @gzclose($this->_file);
932  } else {
933  if ($this->_compress_type == 'bz2') {
934  @bzclose($this->_file);
935  } else {
936  if ($this->_compress_type == 'lzma2') {
937  @xzclose($this->_file);
938  } else {
939  if ($this->_compress_type == 'none') {
940  @fclose($this->_file);
941  } else {
942  $this->_error(
943  'Unknown or missing compression type ('
944  . $this->_compress_type . ')'
945  );
946  }
947  }
948  }
949  }
950 
951  $this->_file = 0;
952  }
953 
954  // ----- Look if a local copy need to be erase
955  // Note that it might be interesting to keep the url for a time : ToDo
956  if ($this->_temp_tarname != '') {
957  @unlink($this->_temp_tarname);
958  $this->_temp_tarname = '';
959  }
960 
961  return true;
962  }
963 
967  public function _cleanFile()
968  {
969  $this->_close();
970 
971  // ----- Look for a local copy
972  if ($this->_temp_tarname != '') {
973  // ----- Remove the local copy but not the remote tarname
974  @unlink($this->_temp_tarname);
975  $this->_temp_tarname = '';
976  } else {
977  // ----- Remove the local tarname file
978  @unlink($this->_tarname);
979  }
980  $this->_tarname = '';
981 
982  return true;
983  }
984 
990  public function _writeBlock($p_binary_data, $p_len = null)
991  {
992  if (is_resource($this->_file)) {
993  if ($p_len === null) {
994  if ($this->_compress_type == 'gz') {
995  @gzputs($this->_file, $p_binary_data);
996  } else {
997  if ($this->_compress_type == 'bz2') {
998  @bzwrite($this->_file, $p_binary_data);
999  } else {
1000  if ($this->_compress_type == 'lzma2') {
1001  @xzwrite($this->_file, $p_binary_data);
1002  } else {
1003  if ($this->_compress_type == 'none') {
1004  @fputs($this->_file, $p_binary_data);
1005  } else {
1006  $this->_error(
1007  'Unknown or missing compression type ('
1008  . $this->_compress_type . ')'
1009  );
1010  }
1011  }
1012  }
1013  }
1014  } else {
1015  if ($this->_compress_type == 'gz') {
1016  @gzputs($this->_file, $p_binary_data, $p_len);
1017  } else {
1018  if ($this->_compress_type == 'bz2') {
1019  @bzwrite($this->_file, $p_binary_data, $p_len);
1020  } else {
1021  if ($this->_compress_type == 'lzma2') {
1022  @xzwrite($this->_file, $p_binary_data, $p_len);
1023  } else {
1024  if ($this->_compress_type == 'none') {
1025  @fputs($this->_file, $p_binary_data, $p_len);
1026  } else {
1027  $this->_error(
1028  'Unknown or missing compression type ('
1029  . $this->_compress_type . ')'
1030  );
1031  }
1032  }
1033  }
1034  }
1035  }
1036  }
1037  return true;
1038  }
1039 
1043  public function _readBlock()
1044  {
1045  $v_block = null;
1046  if (is_resource($this->_file)) {
1047  if ($this->_compress_type == 'gz') {
1048  $v_block = @gzread($this->_file, 512);
1049  } else {
1050  if ($this->_compress_type == 'bz2') {
1051  $v_block = @bzread($this->_file, 512);
1052  } else {
1053  if ($this->_compress_type == 'lzma2') {
1054  $v_block = @xzread($this->_file, 512);
1055  } else {
1056  if ($this->_compress_type == 'none') {
1057  $v_block = @fread($this->_file, 512);
1058  } else {
1059  $this->_error(
1060  'Unknown or missing compression type ('
1061  . $this->_compress_type . ')'
1062  );
1063  }
1064  }
1065  }
1066  }
1067  }
1068  return $v_block;
1069  }
1070 
1075  public function _jumpBlock($p_len = null)
1076  {
1077  if (is_resource($this->_file)) {
1078  if ($p_len === null) {
1079  $p_len = 1;
1080  }
1081 
1082  if ($this->_compress_type == 'gz') {
1083  @gzseek($this->_file, gztell($this->_file) + ($p_len * 512));
1084  } else {
1085  if ($this->_compress_type == 'bz2') {
1086  // ----- Replace missing bztell() and bzseek()
1087  for ($i = 0; $i < $p_len; $i++) {
1088  $this->_readBlock();
1089  }
1090  } else {
1091  if ($this->_compress_type == 'lzma2') {
1092  // ----- Replace missing xztell() and xzseek()
1093  for ($i = 0; $i < $p_len; $i++) {
1094  $this->_readBlock();
1095  }
1096  } else {
1097  if ($this->_compress_type == 'none') {
1098  @fseek($this->_file, $p_len * 512, SEEK_CUR);
1099  } else {
1100  $this->_error(
1101  'Unknown or missing compression type ('
1102  . $this->_compress_type . ')'
1103  );
1104  }
1105  }
1106  }
1107  }
1108  }
1109  return true;
1110  }
1111 
1115  public function _writeFooter()
1116  {
1117  if (is_resource($this->_file)) {
1118  // ----- Write the last 0 filled block for end of archive
1119  $v_binary_data = pack('a1024', '');
1120  $this->_writeBlock($v_binary_data);
1121  }
1122  return true;
1123  }
1124 
1131  public function _addList($p_list, $p_add_dir, $p_remove_dir)
1132  {
1133  $v_result = true;
1134  $v_header = array();
1135 
1136  // ----- Remove potential windows directory separator
1137  $p_add_dir = $this->_translateWinPath($p_add_dir);
1138  $p_remove_dir = $this->_translateWinPath($p_remove_dir, false);
1139 
1140  if (!$this->_file) {
1141  $this->_error('Invalid file descriptor');
1142  return false;
1143  }
1144 
1145  if (sizeof($p_list) == 0) {
1146  return true;
1147  }
1148 
1149  foreach ($p_list as $v_filename) {
1150  if (!$v_result) {
1151  break;
1152  }
1153 
1154  // ----- Skip the current tar name
1155  if ($v_filename == $this->_tarname) {
1156  continue;
1157  }
1158 
1159  if ($v_filename == '') {
1160  continue;
1161  }
1162 
1163  // ----- ignore files and directories matching the ignore regular expression
1164  if ($this->_ignore_regexp && preg_match($this->_ignore_regexp, '/' . $v_filename)) {
1165  $this->_warning("File '$v_filename' ignored");
1166  continue;
1167  }
1168 
1169  if (!file_exists($v_filename) && !is_link($v_filename)) {
1170  $this->_warning("File '$v_filename' does not exist");
1171  continue;
1172  }
1173 
1174  // ----- Add the file or directory header
1175  if (!$this->_addFile($v_filename, $v_header, $p_add_dir, $p_remove_dir)) {
1176  return false;
1177  }
1178 
1179  if (@is_dir($v_filename) && !@is_link($v_filename)) {
1180  if (!($p_hdir = opendir($v_filename))) {
1181  $this->_warning("Directory '$v_filename' can not be read");
1182  continue;
1183  }
1184  while (false !== ($p_hitem = readdir($p_hdir))) {
1185  if (($p_hitem != '.') && ($p_hitem != '..')) {
1186  if ($v_filename != ".") {
1187  $p_temp_list[0] = $v_filename . '/' . $p_hitem;
1188  } else {
1189  $p_temp_list[0] = $p_hitem;
1190  }
1191 
1192  $v_result = $this->_addList(
1193  $p_temp_list,
1194  $p_add_dir,
1195  $p_remove_dir
1196  );
1197  }
1198  }
1199 
1200  unset($p_temp_list);
1201  unset($p_hdir);
1202  unset($p_hitem);
1203  }
1204  }
1205 
1206  return $v_result;
1207  }
1208 
1217  public function _addFile($p_filename, &$p_header, $p_add_dir, $p_remove_dir, $v_stored_filename = null)
1218  {
1219  if (!$this->_file) {
1220  $this->_error('Invalid file descriptor');
1221  return false;
1222  }
1223 
1224  if ($p_filename == '') {
1225  $this->_error('Invalid file name');
1226  return false;
1227  }
1228 
1229  if (is_null($v_stored_filename)) {
1230  // ----- Calculate the stored filename
1231  $p_filename = $this->_translateWinPath($p_filename, false);
1232  $v_stored_filename = $p_filename;
1233 
1234  if (strcmp($p_filename, $p_remove_dir) == 0) {
1235  return true;
1236  }
1237 
1238  if ($p_remove_dir != '') {
1239  if (substr($p_remove_dir, -1) != '/') {
1240  $p_remove_dir .= '/';
1241  }
1242 
1243  if (substr($p_filename, 0, strlen($p_remove_dir)) == $p_remove_dir) {
1244  $v_stored_filename = substr($p_filename, strlen($p_remove_dir));
1245  }
1246  }
1248  $v_stored_filename = $this->_translateWinPath($v_stored_filename);
1249  if ($p_add_dir != '') {
1250  if (substr($p_add_dir, -1) == '/') {
1251  $v_stored_filename = $p_add_dir . $v_stored_filename;
1252  } else {
1253  $v_stored_filename = $p_add_dir . '/' . $v_stored_filename;
1254  }
1255  }
1256 
1257  $v_stored_filename = $this->_pathReduction($v_stored_filename);
1258  }
1259 
1260  if ($this->_isArchive($p_filename)) {
1261  if (($v_file = @fopen($p_filename, "rb")) == 0) {
1262  $this->_warning(
1263  "Unable to open file '" . $p_filename
1264  . "' in binary read mode"
1265  );
1266  return true;
1267  }
1268 
1269  if (!$this->_writeHeader($p_filename, $v_stored_filename)) {
1270  return false;
1271  }
1272 
1273  while (($v_buffer = fread($v_file, $this->buffer_length)) != '') {
1274  $buffer_length = strlen("$v_buffer");
1275  if ($buffer_length != $this->buffer_length) {
1276  $pack_size = ((int)($buffer_length / 512) + 1) * 512;
1277  $pack_format = sprintf('a%d', $pack_size);
1278  } else {
1279  $pack_format = sprintf('a%d', $this->buffer_length);
1280  }
1281  $v_binary_data = pack($pack_format, "$v_buffer");
1282  $this->_writeBlock($v_binary_data);
1283  }
1284 
1285  fclose($v_file);
1286  } else {
1287  // ----- Only header for dir
1288  if (!$this->_writeHeader($p_filename, $v_stored_filename)) {
1289  return false;
1290  }
1291  }
1292 
1293  return true;
1294  }
1295 
1303  public function _addString($p_filename, $p_string, $p_datetime = false, $p_params = array())
1304  {
1305  $p_stamp = @$p_params["stamp"] ? $p_params["stamp"] : ($p_datetime ? $p_datetime : time());
1306  $p_mode = @$p_params["mode"] ? $p_params["mode"] : 0600;
1307  $p_type = @$p_params["type"] ? $p_params["type"] : "";
1308  $p_uid = @$p_params["uid"] ? $p_params["uid"] : 0;
1309  $p_gid = @$p_params["gid"] ? $p_params["gid"] : 0;
1310  if (!$this->_file) {
1311  $this->_error('Invalid file descriptor');
1312  return false;
1313  }
1314 
1315  if ($p_filename == '') {
1316  $this->_error('Invalid file name');
1317  return false;
1318  }
1319 
1320  // ----- Calculate the stored filename
1321  $p_filename = $this->_translateWinPath($p_filename, false);
1322 
1323  // ----- If datetime is not specified, set current time
1324  if ($p_datetime === false) {
1325  $p_datetime = time();
1326  }
1327 
1328  if (!$this->_writeHeaderBlock(
1329  $p_filename,
1330  strlen($p_string),
1331  $p_stamp,
1332  $p_mode,
1333  $p_type,
1334  $p_uid,
1335  $p_gid
1336  )
1337  ) {
1338  return false;
1339  }
1340 
1341  $i = 0;
1342  while (($v_buffer = substr($p_string, (($i++) * 512), 512)) != '') {
1343  $v_binary_data = pack("a512", $v_buffer);
1344  $this->_writeBlock($v_binary_data);
1345  }
1346 
1347  return true;
1348  }
1349 
1355  public function _writeHeader($p_filename, $p_stored_filename)
1356  {
1357  if ($p_stored_filename == '') {
1358  $p_stored_filename = $p_filename;
1359  }
1360 
1361  $v_reduced_filename = $this->_pathReduction($p_stored_filename);
1362 
1363  if (strlen($v_reduced_filename) > 99) {
1364  if (!$this->_writeLongHeader($v_reduced_filename, false)) {
1365  return false;
1366  }
1367  }
1368 
1369  $v_linkname = '';
1370  if (@is_link($p_filename)) {
1371  $v_linkname = readlink($p_filename);
1372  }
1373 
1374  if (strlen($v_linkname) > 99) {
1375  if (!$this->_writeLongHeader($v_linkname, true)) {
1376  return false;
1377  }
1378  }
1379 
1380  $v_info = lstat($p_filename);
1381  $v_uid = sprintf("%07s", DecOct($v_info[4]));
1382  $v_gid = sprintf("%07s", DecOct($v_info[5]));
1383  $v_perms = sprintf("%07s", DecOct($v_info['mode'] & 000777));
1384  $v_mtime = sprintf("%011s", DecOct($v_info['mtime']));
1386  if (@is_link($p_filename)) {
1387  $v_typeflag = '2';
1388  $v_size = sprintf("%011s", DecOct(0));
1389  } elseif (@is_dir($p_filename)) {
1390  $v_typeflag = "5";
1391  $v_size = sprintf("%011s", DecOct(0));
1392  } else {
1393  $v_typeflag = '0';
1394  clearstatcache();
1395  $v_size = sprintf("%011s", DecOct($v_info['size']));
1396  }
1397 
1398  $v_magic = 'ustar ';
1399  $v_version = ' ';
1400 
1401  if (function_exists('posix_getpwuid')) {
1402  $userinfo = posix_getpwuid($v_info[4]);
1403  $groupinfo = posix_getgrgid($v_info[5]);
1404 
1405  $v_uname = $userinfo['name'];
1406  $v_gname = $groupinfo['name'];
1407  } else {
1408  $v_uname = '';
1409  $v_gname = '';
1410  }
1411 
1412  $v_devmajor = '';
1413  $v_devminor = '';
1414  $v_prefix = '';
1415 
1416  $v_binary_data_first = pack(
1417  "a100a8a8a8a12a12",
1418  $v_reduced_filename,
1419  $v_perms,
1420  $v_uid,
1421  $v_gid,
1422  $v_size,
1423  $v_mtime
1424  );
1425  $v_binary_data_last = pack(
1426  "a1a100a6a2a32a32a8a8a155a12",
1427  $v_typeflag,
1428  $v_linkname,
1429  $v_magic,
1430  $v_version,
1431  $v_uname,
1432  $v_gname,
1433  $v_devmajor,
1434  $v_devminor,
1435  $v_prefix,
1436  ''
1437  );
1438 
1439  // ----- Calculate the checksum
1440  $v_checksum = 0;
1441  // ..... First part of the header
1442  for ($i = 0; $i < 148; $i++) {
1443  $v_checksum += ord(substr($v_binary_data_first, $i, 1));
1444  }
1445  // ..... Ignore the checksum value and replace it by ' ' (space)
1446  for ($i = 148; $i < 156; $i++) {
1447  $v_checksum += ord(' ');
1448  }
1449  // ..... Last part of the header
1450  for ($i = 156, $j = 0; $i < 512; $i++, $j++) {
1451  $v_checksum += ord(substr($v_binary_data_last, $j, 1));
1452  }
1453 
1454  // ----- Write the first 148 bytes of the header in the archive
1455  $this->_writeBlock($v_binary_data_first, 148);
1456 
1457  // ----- Write the calculated checksum
1458  $v_checksum = sprintf("%06s\0 ", DecOct($v_checksum));
1459  $v_binary_data = pack("a8", $v_checksum);
1460  $this->_writeBlock($v_binary_data, 8);
1461 
1462  // ----- Write the last 356 bytes of the header in the archive
1463  $this->_writeBlock($v_binary_data_last, 356);
1464 
1465  return true;
1466  }
1467 
1478  public function _writeHeaderBlock(
1479  $p_filename,
1480  $p_size,
1481  $p_mtime = 0,
1482  $p_perms = 0,
1483  $p_type = '',
1484  $p_uid = 0,
1485  $p_gid = 0
1486  )
1487  {
1488  $p_filename = $this->_pathReduction($p_filename);
1489 
1490  if (strlen($p_filename) > 99) {
1491  if (!$this->_writeLongHeader($p_filename, false)) {
1492  return false;
1493  }
1494  }
1495 
1496  if ($p_type == "5") {
1497  $v_size = sprintf("%011s", DecOct(0));
1498  } else {
1499  $v_size = sprintf("%011s", DecOct($p_size));
1500  }
1501 
1502  $v_uid = sprintf("%07s", DecOct($p_uid));
1503  $v_gid = sprintf("%07s", DecOct($p_gid));
1504  $v_perms = sprintf("%07s", DecOct($p_perms & 000777));
1505 
1506  $v_mtime = sprintf("%11s", DecOct($p_mtime));
1507 
1508  $v_linkname = '';
1509 
1510  $v_magic = 'ustar ';
1511 
1512  $v_version = ' ';
1513 
1514  if (function_exists('posix_getpwuid')) {
1515  $userinfo = posix_getpwuid($p_uid);
1516  $groupinfo = posix_getgrgid($p_gid);
1517 
1518  $v_uname = $userinfo['name'];
1519  $v_gname = $groupinfo['name'];
1520  } else {
1521  $v_uname = '';
1522  $v_gname = '';
1523  }
1524 
1525  $v_devmajor = '';
1526 
1527  $v_devminor = '';
1528 
1529  $v_prefix = '';
1530 
1531  $v_binary_data_first = pack(
1532  "a100a8a8a8a12A12",
1533  $p_filename,
1534  $v_perms,
1535  $v_uid,
1536  $v_gid,
1537  $v_size,
1538  $v_mtime
1539  );
1540  $v_binary_data_last = pack(
1541  "a1a100a6a2a32a32a8a8a155a12",
1542  $p_type,
1543  $v_linkname,
1544  $v_magic,
1545  $v_version,
1546  $v_uname,
1547  $v_gname,
1548  $v_devmajor,
1549  $v_devminor,
1550  $v_prefix,
1551  ''
1552  );
1553 
1554  // ----- Calculate the checksum
1555  $v_checksum = 0;
1556  // ..... First part of the header
1557  for ($i = 0; $i < 148; $i++) {
1558  $v_checksum += ord(substr($v_binary_data_first, $i, 1));
1559  }
1560  // ..... Ignore the checksum value and replace it by ' ' (space)
1561  for ($i = 148; $i < 156; $i++) {
1562  $v_checksum += ord(' ');
1563  }
1564  // ..... Last part of the header
1565  for ($i = 156, $j = 0; $i < 512; $i++, $j++) {
1566  $v_checksum += ord(substr($v_binary_data_last, $j, 1));
1567  }
1568 
1569  // ----- Write the first 148 bytes of the header in the archive
1570  $this->_writeBlock($v_binary_data_first, 148);
1571 
1572  // ----- Write the calculated checksum
1573  $v_checksum = sprintf("%06s ", DecOct($v_checksum));
1574  $v_binary_data = pack("a8", $v_checksum);
1575  $this->_writeBlock($v_binary_data, 8);
1576 
1577  // ----- Write the last 356 bytes of the header in the archive
1578  $this->_writeBlock($v_binary_data_last, 356);
1579 
1580  return true;
1581  }
1582 
1587  public function _writeLongHeader($p_filename, $is_link = false)
1588  {
1589  $v_uid = sprintf("%07s", 0);
1590  $v_gid = sprintf("%07s", 0);
1591  $v_perms = sprintf("%07s", 0);
1592  $v_size = sprintf("%'011s", DecOct(strlen($p_filename)));
1593  $v_mtime = sprintf("%011s", 0);
1594  $v_typeflag = ($is_link ? 'K' : 'L');
1595  $v_linkname = '';
1596  $v_magic = 'ustar ';
1597  $v_version = ' ';
1598  $v_uname = '';
1599  $v_gname = '';
1600  $v_devmajor = '';
1601  $v_devminor = '';
1602  $v_prefix = '';
1603 
1604  $v_binary_data_first = pack(
1605  "a100a8a8a8a12a12",
1606  '././@LongLink',
1607  $v_perms,
1608  $v_uid,
1609  $v_gid,
1610  $v_size,
1611  $v_mtime
1612  );
1613  $v_binary_data_last = pack(
1614  "a1a100a6a2a32a32a8a8a155a12",
1615  $v_typeflag,
1616  $v_linkname,
1617  $v_magic,
1618  $v_version,
1619  $v_uname,
1620  $v_gname,
1621  $v_devmajor,
1622  $v_devminor,
1623  $v_prefix,
1624  ''
1625  );
1626 
1627  // ----- Calculate the checksum
1628  $v_checksum = 0;
1629  // ..... First part of the header
1630  for ($i = 0; $i < 148; $i++) {
1631  $v_checksum += ord(substr($v_binary_data_first, $i, 1));
1632  }
1633  // ..... Ignore the checksum value and replace it by ' ' (space)
1634  for ($i = 148; $i < 156; $i++) {
1635  $v_checksum += ord(' ');
1636  }
1637  // ..... Last part of the header
1638  for ($i = 156, $j = 0; $i < 512; $i++, $j++) {
1639  $v_checksum += ord(substr($v_binary_data_last, $j, 1));
1640  }
1641 
1642  // ----- Write the first 148 bytes of the header in the archive
1643  $this->_writeBlock($v_binary_data_first, 148);
1644 
1645  // ----- Write the calculated checksum
1646  $v_checksum = sprintf("%06s\0 ", DecOct($v_checksum));
1647  $v_binary_data = pack("a8", $v_checksum);
1648  $this->_writeBlock($v_binary_data, 8);
1649 
1650  // ----- Write the last 356 bytes of the header in the archive
1651  $this->_writeBlock($v_binary_data_last, 356);
1652 
1653  // ----- Write the filename as content of the block
1654  $i = 0;
1655  while (($v_buffer = substr($p_filename, (($i++) * 512), 512)) != '') {
1656  $v_binary_data = pack("a512", "$v_buffer");
1657  $this->_writeBlock($v_binary_data);
1658  }
1659 
1660  return true;
1661  }
1662 
1668  public function _readHeader($v_binary_data, &$v_header)
1669  {
1670  if (strlen($v_binary_data) == 0) {
1671  $v_header['filename'] = '';
1672  return true;
1673  }
1674 
1675  if (strlen($v_binary_data) != 512) {
1676  $v_header['filename'] = '';
1677  $this->_error('Invalid block size : ' . strlen($v_binary_data));
1678  return false;
1679  }
1680 
1681  if (!is_array($v_header)) {
1682  $v_header = array();
1683  }
1684  // ----- Calculate the checksum
1685  $v_checksum = 0;
1686  // ..... First part of the header
1687  $v_binary_split = str_split($v_binary_data);
1688  $v_checksum += array_sum(array_map('ord', array_slice($v_binary_split, 0, 148)));
1689  $v_checksum += array_sum(array_map('ord', array(' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',)));
1690  $v_checksum += array_sum(array_map('ord', array_slice($v_binary_split, 156, 512)));
1691 
1692 
1693  $v_data = unpack($this->_fmt, $v_binary_data);
1694 
1695  if (strlen($v_data["prefix"]) > 0) {
1696  $v_data["filename"] = "$v_data[prefix]/$v_data[filename]";
1697  }
1699  // ----- Extract the checksum
1700  $v_data_checksum = trim($v_data['checksum']);
1701  if (!preg_match('/^[0-7]*$/', $v_data_checksum)) {
1702  $this->_error(
1703  'Invalid checksum for file "' . $v_data['filename']
1704  . '" : ' . $v_data_checksum . ' extracted'
1705  );
1706  return false;
1707  }
1708 
1709  $v_header['checksum'] = OctDec($v_data_checksum);
1710  if ($v_header['checksum'] != $v_checksum) {
1711  $v_header['filename'] = '';
1712 
1713  // ----- Look for last block (empty block)
1714  if (($v_checksum == 256) && ($v_header['checksum'] == 0)) {
1715  return true;
1716  }
1717 
1718  $this->_error(
1719  'Invalid checksum for file "' . $v_data['filename']
1720  . '" : ' . $v_checksum . ' calculated, '
1721  . $v_header['checksum'] . ' expected'
1722  );
1723  return false;
1724  }
1725 
1726  // ----- Extract the properties
1727  $v_header['filename'] = rtrim($v_data['filename'], "\0");
1728  if ($this->_maliciousFilename($v_header['filename'])) {
1729  $this->_error(
1730  'Malicious .tar detected, file "' . $v_header['filename'] .
1731  '" will not install in desired directory tree'
1732  );
1733  return false;
1734  }
1735  $v_header['mode'] = OctDec(trim($v_data['mode']));
1736  $v_header['uid'] = OctDec(trim($v_data['uid']));
1737  $v_header['gid'] = OctDec(trim($v_data['gid']));
1738  $v_header['size'] = $this->_tarRecToSize($v_data['size']);
1739  $v_header['mtime'] = OctDec(trim($v_data['mtime']));
1740  if (($v_header['typeflag'] = $v_data['typeflag']) == "5") {
1741  $v_header['size'] = 0;
1742  }
1743  $v_header['link'] = trim($v_data['link']);
1744  /* ----- All these fields are removed form the header because
1745  they do not carry interesting info
1746  $v_header[magic] = trim($v_data[magic]);
1747  $v_header[version] = trim($v_data[version]);
1748  $v_header[uname] = trim($v_data[uname]);
1749  $v_header[gname] = trim($v_data[gname]);
1750  $v_header[devmajor] = trim($v_data[devmajor]);
1751  $v_header[devminor] = trim($v_data[devminor]);
1752  */
1753 
1754  return true;
1755  }
1756 
1763  private function _tarRecToSize($tar_size)
1764  {
1765  /*
1766  * First byte of size has a special meaning if bit 7 is set.
1767  *
1768  * Bit 7 indicates base-256 encoding if set.
1769  * Bit 6 is the sign bit.
1770  * Bits 5:0 are most significant value bits.
1771  */
1772  $ch = ord($tar_size[0]);
1773  if ($ch & 0x80) {
1774  // Full 12-bytes record is required.
1775  $rec_str = $tar_size . "\x00";
1776 
1777  $size = ($ch & 0x40) ? -1 : 0;
1778  $size = ($size << 6) | ($ch & 0x3f);
1779 
1780  for ($num_ch = 1; $num_ch < 12; ++$num_ch) {
1781  $size = ($size * 256) + ord($rec_str[$num_ch]);
1782  }
1783 
1784  return $size;
1785 
1786  } else {
1787  return OctDec(trim($tar_size));
1788  }
1789  }
1790 
1798  private function _maliciousFilename($file)
1799  {
1800  if (strpos($file, 'phar://') === 0) {
1801  return true;
1802  }
1803  if (strpos($file, '../') !== false || strpos($file, '..\\') !== false) {
1804  return true;
1805  }
1806  return false;
1807  }
1808 
1813  public function _readLongHeader(&$v_header)
1814  {
1815  $v_filename = '';
1816  $v_filesize = $v_header['size'];
1817  $n = floor($v_header['size'] / 512);
1818  for ($i = 0; $i < $n; $i++) {
1819  $v_content = $this->_readBlock();
1820  $v_filename .= $v_content;
1821  }
1822  if (($v_header['size'] % 512) != 0) {
1823  $v_content = $this->_readBlock();
1824  $v_filename .= $v_content;
1825  }
1826 
1827  // ----- Read the next header
1828  $v_binary_data = $this->_readBlock();
1829 
1830  if (!$this->_readHeader($v_binary_data, $v_header)) {
1831  return false;
1832  }
1833 
1834  $v_filename = rtrim(substr($v_filename, 0, $v_filesize), "\0");
1835  $v_header['filename'] = $v_filename;
1836  if ($this->_maliciousFilename($v_filename)) {
1837  $this->_error(
1838  'Malicious .tar detected, file "' . $v_filename .
1839  '" will not install in desired directory tree'
1840  );
1841  return false;
1842  }
1844  return true;
1845  }
1846 
1855  private function _extractInString($p_filename)
1856  {
1857  $v_result_str = "";
1858 
1859  while (strlen($v_binary_data = $this->_readBlock()) != 0) {
1860  if (!$this->_readHeader($v_binary_data, $v_header)) {
1861  return null;
1862  }
1863 
1864  if ($v_header['filename'] == '') {
1865  continue;
1866  }
1867 
1868  switch ($v_header['typeflag']) {
1869  case 'L':
1870  {
1871  if (!$this->_readLongHeader($v_header)) {
1872  return null;
1873  }
1874  }
1875  break;
1876 
1877  case 'K':
1878  {
1879  $v_link_header = $v_header;
1880  if (!$this->_readLongHeader($v_link_header)) {
1881  return null;
1882  }
1883  $v_header['link'] = $v_link_header['filename'];
1884  }
1885  break;
1886  }
1887 
1888  if ($v_header['filename'] == $p_filename) {
1889  if ($v_header['typeflag'] == "5") {
1890  $this->_error(
1891  'Unable to extract in string a directory '
1892  . 'entry {' . $v_header['filename'] . '}'
1893  );
1894  return null;
1895  } else {
1896  $n = floor($v_header['size'] / 512);
1897  for ($i = 0; $i < $n; $i++) {
1898  $v_result_str .= $this->_readBlock();
1899  }
1900  if (($v_header['size'] % 512) != 0) {
1901  $v_content = $this->_readBlock();
1902  $v_result_str .= substr(
1903  $v_content,
1904  0,
1905  ($v_header['size'] % 512)
1906  );
1907  }
1908  return $v_result_str;
1909  }
1910  } else {
1911  $this->_jumpBlock(ceil(($v_header['size'] / 512)));
1912  }
1913  }
1914 
1915  return null;
1916  }
1917 
1928  public function _extractList(
1929  $p_path,
1930  &$p_list_detail,
1931  $p_mode,
1932  $p_file_list,
1933  $p_remove_path,
1934  $p_preserve = false,
1935  $p_symlinks = true
1936  )
1937  {
1938  $v_result = true;
1939  $v_nb = 0;
1940  $v_extract_all = true;
1941  $v_listing = false;
1942 
1943  $p_path = $this->_translateWinPath($p_path, false);
1944  if ($p_path == '' || (substr($p_path, 0, 1) != '/'
1945  && substr($p_path, 0, 3) != "../" && !strpos($p_path, ':'))
1946  ) {
1947  $p_path = "./" . $p_path;
1948  }
1949  $p_remove_path = $this->_translateWinPath($p_remove_path);
1950 
1951  // ----- Look for path to remove format (should end by /)
1952  if (($p_remove_path != '') && (substr($p_remove_path, -1) != '/')) {
1953  $p_remove_path .= '/';
1954  }
1955  $p_remove_path_size = strlen($p_remove_path);
1956 
1957  switch ($p_mode) {
1958  case "complete" :
1959  $v_extract_all = true;
1960  $v_listing = false;
1961  break;
1962  case "partial" :
1963  $v_extract_all = false;
1964  $v_listing = false;
1965  break;
1966  case "list" :
1967  $v_extract_all = false;
1968  $v_listing = true;
1969  break;
1970  default :
1971  $this->_error('Invalid extract mode (' . $p_mode . ')');
1972  return false;
1973  }
1974 
1975  clearstatcache();
1976 
1977  while (strlen($v_binary_data = $this->_readBlock()) != 0) {
1978  $v_extract_file = false;
1979  $v_extraction_stopped = 0;
1980 
1981  if (!$this->_readHeader($v_binary_data, $v_header)) {
1982  return false;
1983  }
1984 
1985  if ($v_header['filename'] == '') {
1986  continue;
1987  }
1988 
1989  switch ($v_header['typeflag']) {
1990  case 'L':
1991  {
1992  if (!$this->_readLongHeader($v_header)) {
1993  return null;
1994  }
1995  }
1996  break;
1997 
1998  case 'K':
1999  {
2000  $v_link_header = $v_header;
2001  if (!$this->_readLongHeader($v_link_header)) {
2002  return null;
2003  }
2004  $v_header['link'] = $v_link_header['filename'];
2005  }
2006  break;
2007  }
2008 
2009  // ignore extended / pax headers
2010  if ($v_header['typeflag'] == 'x' || $v_header['typeflag'] == 'g') {
2011  $this->_jumpBlock(ceil(($v_header['size'] / 512)));
2012  continue;
2013  }
2014 
2015  if ((!$v_extract_all) && (is_array($p_file_list))) {
2016  // ----- By default no unzip if the file is not found
2017  $v_extract_file = false;
2018 
2019  for ($i = 0; $i < sizeof($p_file_list); $i++) {
2020  // ----- Look if it is a directory
2021  if (substr($p_file_list[$i], -1) == '/') {
2022  // ----- Look if the directory is in the filename path
2023  if ((strlen($v_header['filename']) > strlen($p_file_list[$i]))
2024  && (substr($v_header['filename'], 0, strlen($p_file_list[$i]))
2025  == $p_file_list[$i])
2026  ) {
2027  $v_extract_file = true;
2028  break;
2029  }
2030  } // ----- It is a file, so compare the file names
2031  elseif ($p_file_list[$i] == $v_header['filename']) {
2032  $v_extract_file = true;
2033  break;
2034  }
2035  }
2036  } else {
2037  $v_extract_file = true;
2038  }
2039 
2040  // ----- Look if this file need to be extracted
2041  if (($v_extract_file) && (!$v_listing)) {
2042  if (($p_remove_path != '')
2043  && (substr($v_header['filename'] . '/', 0, $p_remove_path_size)
2044  == $p_remove_path)
2045  ) {
2046  $v_header['filename'] = substr(
2047  $v_header['filename'],
2048  $p_remove_path_size
2049  );
2050  if ($v_header['filename'] == '') {
2051  continue;
2052  }
2053  }
2054  if (($p_path != './') && ($p_path != '/')) {
2055  while (substr($p_path, -1) == '/') {
2056  $p_path = substr($p_path, 0, strlen($p_path) - 1);
2057  }
2058 
2059  if (substr($v_header['filename'], 0, 1) == '/') {
2060  $v_header['filename'] = $p_path . $v_header['filename'];
2061  } else {
2062  $v_header['filename'] = $p_path . '/' . $v_header['filename'];
2063  }
2064  }
2065  if (file_exists($v_header['filename'])) {
2066  if ((@is_dir($v_header['filename']))
2067  && ($v_header['typeflag'] == '')
2068  ) {
2069  $this->_error(
2070  'File ' . $v_header['filename']
2071  . ' already exists as a directory'
2072  );
2073  return false;
2074  }
2075  if (($this->_isArchive($v_header['filename']))
2076  && ($v_header['typeflag'] == "5")
2077  ) {
2078  $this->_error(
2079  'Directory ' . $v_header['filename']
2080  . ' already exists as a file'
2081  );
2082  return false;
2083  }
2084  if (!is_writeable($v_header['filename'])) {
2085  $this->_error(
2086  'File ' . $v_header['filename']
2087  . ' already exists and is write protected'
2088  );
2089  return false;
2090  }
2091  if (filemtime($v_header['filename']) > $v_header['mtime']) {
2092  // To be completed : An error or silent no replace ?
2093  }
2094  } // ----- Check the directory availability and create it if necessary
2095  elseif (($v_result
2096  = $this->_dirCheck(
2097  ($v_header['typeflag'] == "5"
2098  ? $v_header['filename']
2099  : dirname($v_header['filename']))
2100  )) != 1
2101  ) {
2102  $this->_error('Unable to create path for ' . $v_header['filename']);
2103  return false;
2104  }
2105 
2106  if ($v_extract_file) {
2107  if ($v_header['typeflag'] == "5") {
2108  if (!@file_exists($v_header['filename'])) {
2109  if (!@mkdir($v_header['filename'], 0777)) {
2110  $this->_error(
2111  'Unable to create directory {'
2112  . $v_header['filename'] . '}'
2113  );
2114  return false;
2115  }
2116  }
2117  } elseif ($v_header['typeflag'] == "2") {
2118  if (!$p_symlinks) {
2119  $this->_warning('Symbolic links are not allowed. '
2120  . 'Unable to extract {'
2121  . $v_header['filename'] . '}'
2122  );
2123  return false;
2124  }
2125  if (@file_exists($v_header['filename'])) {
2126  @unlink($v_header['filename']);
2127  }
2128  if (!@symlink($v_header['link'], $v_header['filename'])) {
2129  $this->_error(
2130  'Unable to extract symbolic link {'
2131  . $v_header['filename'] . '}'
2132  );
2133  return false;
2134  }
2135  } else {
2136  if (($v_dest_file = @fopen($v_header['filename'], "wb")) == 0) {
2137  $this->_error(
2138  'Error while opening {' . $v_header['filename']
2139  . '} in write binary mode'
2140  );
2141  return false;
2142  } else {
2143  $n = floor($v_header['size'] / 512);
2144  for ($i = 0; $i < $n; $i++) {
2145  $v_content = $this->_readBlock();
2146  fwrite($v_dest_file, $v_content, 512);
2147  }
2148  if (($v_header['size'] % 512) != 0) {
2149  $v_content = $this->_readBlock();
2150  fwrite($v_dest_file, $v_content, ($v_header['size'] % 512));
2151  }
2152 
2153  @fclose($v_dest_file);
2154 
2155  if ($p_preserve) {
2156  @chown($v_header['filename'], $v_header['uid']);
2157  @chgrp($v_header['filename'], $v_header['gid']);
2158  }
2159 
2160  // ----- Change the file mode, mtime
2161  @touch($v_header['filename'], $v_header['mtime']);
2162  if ($v_header['mode'] & 0111) {
2163  // make file executable, obey umask
2164  $mode = fileperms($v_header['filename']) | (~umask() & 0111);
2165  @chmod($v_header['filename'], $mode);
2166  }
2167  }
2168 
2169  // ----- Check the file size
2170  clearstatcache();
2171  if (!is_file($v_header['filename'])) {
2172  $this->_error(
2173  'Extracted file ' . $v_header['filename']
2174  . 'does not exist. Archive may be corrupted.'
2175  );
2176  return false;
2177  }
2178 
2179  $filesize = filesize($v_header['filename']);
2180  if ($filesize != $v_header['size']) {
2181  $this->_error(
2182  'Extracted file ' . $v_header['filename']
2183  . ' does not have the correct file size \''
2184  . $filesize
2185  . '\' (' . $v_header['size']
2186  . ' expected). Archive may be corrupted.'
2187  );
2188  return false;
2189  }
2190  }
2191  } else {
2192  $this->_jumpBlock(ceil(($v_header['size'] / 512)));
2193  }
2194  } else {
2195  $this->_jumpBlock(ceil(($v_header['size'] / 512)));
2196  }
2197 
2198  /* TBC : Seems to be unused ...
2199  if ($this->_compress)
2200  $v_end_of_file = @gzeof($this->_file);
2201  else
2202  $v_end_of_file = @feof($this->_file);
2203  */
2204 
2205  if ($v_listing || $v_extract_file || $v_extraction_stopped) {
2206  // ----- Log extracted files
2207  if (($v_file_dir = dirname($v_header['filename']))
2208  == $v_header['filename']
2209  ) {
2210  $v_file_dir = '';
2211  }
2212  if ((substr($v_header['filename'], 0, 1) == '/') && ($v_file_dir == '')) {
2213  $v_file_dir = '/';
2214  }
2215 
2216  $p_list_detail[$v_nb++] = $v_header;
2217  if (is_array($p_file_list) && (count($p_list_detail) == count($p_file_list))) {
2218  return true;
2219  }
2220  }
2221  }
2222 
2223  return true;
2224  }
2225 
2229  public function _openAppend()
2230  {
2231  if (filesize($this->_tarname) == 0) {
2232  return $this->_openWrite();
2233  }
2234 
2235  if ($this->_compress) {
2236  $this->_close();
2237 
2238  if (!@rename($this->_tarname, $this->_tarname . ".tmp")) {
2239  $this->_error(
2240  'Error while renaming \'' . $this->_tarname
2241  . '\' to temporary file \'' . $this->_tarname
2242  . '.tmp\''
2243  );
2244  return false;
2245  }
2246 
2247  if ($this->_compress_type == 'gz') {
2248  $v_temp_tar = @gzopen($this->_tarname . ".tmp", "rb");
2249  } elseif ($this->_compress_type == 'bz2') {
2250  $v_temp_tar = @bzopen($this->_tarname . ".tmp", "r");
2251  } elseif ($this->_compress_type == 'lzma2') {
2252  $v_temp_tar = @xzopen($this->_tarname . ".tmp", "r");
2253  }
2254 
2255 
2256  if ($v_temp_tar == 0) {
2257  $this->_error(
2258  'Unable to open file \'' . $this->_tarname
2259  . '.tmp\' in binary read mode'
2260  );
2261  @rename($this->_tarname . ".tmp", $this->_tarname);
2262  return false;
2263  }
2264 
2265  if (!$this->_openWrite()) {
2266  @rename($this->_tarname . ".tmp", $this->_tarname);
2267  return false;
2268  }
2269 
2270  if ($this->_compress_type == 'gz') {
2271  $end_blocks = 0;
2272 
2273  while (!@gzeof($v_temp_tar)) {
2274  $v_buffer = @gzread($v_temp_tar, 512);
2275  if ($v_buffer == ARCHIVE_TAR_END_BLOCK || strlen($v_buffer) == 0) {
2276  $end_blocks++;
2277  // do not copy end blocks, we will re-make them
2278  // after appending
2279  continue;
2280  } elseif ($end_blocks > 0) {
2281  for ($i = 0; $i < $end_blocks; $i++) {
2282  $this->_writeBlock(ARCHIVE_TAR_END_BLOCK);
2283  }
2284  $end_blocks = 0;
2285  }
2286  $v_binary_data = pack("a512", $v_buffer);
2287  $this->_writeBlock($v_binary_data);
2288  }
2289 
2290  @gzclose($v_temp_tar);
2291  } elseif ($this->_compress_type == 'bz2') {
2292  $end_blocks = 0;
2293 
2294  while (strlen($v_buffer = @bzread($v_temp_tar, 512)) > 0) {
2295  if ($v_buffer == ARCHIVE_TAR_END_BLOCK || strlen($v_buffer) == 0) {
2296  $end_blocks++;
2297  // do not copy end blocks, we will re-make them
2298  // after appending
2299  continue;
2300  } elseif ($end_blocks > 0) {
2301  for ($i = 0; $i < $end_blocks; $i++) {
2302  $this->_writeBlock(ARCHIVE_TAR_END_BLOCK);
2303  }
2304  $end_blocks = 0;
2305  }
2306  $v_binary_data = pack("a512", $v_buffer);
2307  $this->_writeBlock($v_binary_data);
2308  }
2309 
2310  @bzclose($v_temp_tar);
2311  } elseif ($this->_compress_type == 'lzma2') {
2312  $end_blocks = 0;
2313 
2314  while (strlen($v_buffer = @xzread($v_temp_tar, 512)) > 0) {
2315  if ($v_buffer == ARCHIVE_TAR_END_BLOCK || strlen($v_buffer) == 0) {
2316  $end_blocks++;
2317  // do not copy end blocks, we will re-make them
2318  // after appending
2319  continue;
2320  } elseif ($end_blocks > 0) {
2321  for ($i = 0; $i < $end_blocks; $i++) {
2322  $this->_writeBlock(ARCHIVE_TAR_END_BLOCK);
2323  }
2324  $end_blocks = 0;
2325  }
2326  $v_binary_data = pack("a512", $v_buffer);
2327  $this->_writeBlock($v_binary_data);
2328  }
2329 
2330  @xzclose($v_temp_tar);
2331  }
2332 
2333  if (!@unlink($this->_tarname . ".tmp")) {
2334  $this->_error(
2335  'Error while deleting temporary file \''
2336  . $this->_tarname . '.tmp\''
2337  );
2338  }
2339  } else {
2340  // ----- For not compressed tar, just add files before the last
2341  // one or two 512 bytes block
2342  if (!$this->_openReadWrite()) {
2343  return false;
2344  }
2345 
2346  clearstatcache();
2347  $v_size = filesize($this->_tarname);
2348 
2349  // We might have zero, one or two end blocks.
2350  // The standard is two, but we should try to handle
2351  // other cases.
2352  fseek($this->_file, $v_size - 1024);
2353  if (fread($this->_file, 512) == ARCHIVE_TAR_END_BLOCK) {
2354  fseek($this->_file, $v_size - 1024);
2355  } elseif (fread($this->_file, 512) == ARCHIVE_TAR_END_BLOCK) {
2356  fseek($this->_file, $v_size - 512);
2357  }
2358  }
2359 
2360  return true;
2361  }
2362 
2369  public function _append($p_filelist, $p_add_dir = '', $p_remove_dir = '')
2370  {
2371  if (!$this->_openAppend()) {
2372  return false;
2373  }
2374 
2375  if ($this->_addList($p_filelist, $p_add_dir, $p_remove_dir)) {
2376  $this->_writeFooter();
2377  }
2378 
2379  $this->_close();
2380 
2381  return true;
2382  }
2383 
2392  public function _dirCheck($p_dir)
2393  {
2394  clearstatcache();
2395  if ((@is_dir($p_dir)) || ($p_dir == '')) {
2396  return true;
2397  }
2398 
2399  $p_parent_dir = dirname($p_dir);
2400 
2401  if (($p_parent_dir != $p_dir) &&
2402  ($p_parent_dir != '') &&
2403  (!$this->_dirCheck($p_parent_dir))
2404  ) {
2405  return false;
2406  }
2407 
2408  if (!@mkdir($p_dir, 0777)) {
2409  $this->_error("Unable to create directory '$p_dir'");
2410  return false;
2411  }
2412 
2413  return true;
2414  }
2415 
2424  private function _pathReduction($p_dir)
2425  {
2426  $v_result = '';
2427 
2428  // ----- Look for not empty path
2429  if ($p_dir != '') {
2430  // ----- Explode path by directory names
2431  $v_list = explode('/', $p_dir);
2432 
2433  // ----- Study directories from last to first
2434  for ($i = sizeof($v_list) - 1; $i >= 0; $i--) {
2435  // ----- Look for current path
2436  if ($v_list[$i] == ".") {
2437  // ----- Ignore this directory
2438  // Should be the first $i=0, but no check is done
2439  } else {
2440  if ($v_list[$i] == "..") {
2441  // ----- Ignore it and ignore the $i-1
2442  $i--;
2443  } else {
2444  if (($v_list[$i] == '')
2445  && ($i != (sizeof($v_list) - 1))
2446  && ($i != 0)
2447  ) {
2448  // ----- Ignore only the double '//' in path,
2449  // but not the first and last /
2450  } else {
2451  $v_result = $v_list[$i] . ($i != (sizeof($v_list) - 1) ? '/'
2452  . $v_result : '');
2453  }
2454  }
2455  }
2456  }
2457  }
2458 
2459  if (defined('OS_WINDOWS') && OS_WINDOWS) {
2460  $v_result = strtr($v_result, '\\', '/');
2461  }
2462 
2463  return $v_result;
2464  }
2465 
2471  public function _translateWinPath($p_path, $p_remove_disk_letter = true)
2472  {
2473  if (defined('OS_WINDOWS') && OS_WINDOWS) {
2474  // ----- Look for potential disk letter
2475  if (($p_remove_disk_letter)
2476  && (($v_position = strpos($p_path, ':')) != false)
2477  ) {
2478  $p_path = substr($p_path, $v_position + 1);
2479  }
2480  // ----- Change potential windows directory separator
2481  if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0, 1) == '\\')) {
2482  $p_path = strtr($p_path, '\\', '/');
2483  }
2484  }
2485  return $p_path;
2486  }
2487 }
Archive_Tar\_readBlock
_readBlock()
Definition: Tar.php:1073
Archive_Tar\$_separator
$_separator
Definition: Tar.php:112
Archive_Tar\listContent
listContent()
Definition: Tar.php:356
PEAR
Archive_Tar\createModify
createModify($p_filelist, $p_add_dir, $p_remove_dir='')
Definition: Tar.php:406
Archive_Tar\_translateWinPath
_translateWinPath($p_path, $p_remove_disk_letter=true)
Definition: Tar.php:2501
Archive_Tar\extractModify
extractModify($p_path, $p_remove_path, $p_preserve=false, $p_symlinks=true)
Definition: Tar.php:596
Archive_Tar\_dirCheck
_dirCheck($p_dir)
Definition: Tar.php:2422
Archive_Tar\_addString
_addString($p_filename, $p_string, $p_datetime=false, $p_params=array())
Definition: Tar.php:1333
Archive_Tar\$_compress_type
$_compress_type
Definition: Tar.php:104
Archive_Tar\extractInString
extractInString($p_filename)
Definition: Tar.php:625
Archive_Tar\$buffer_length
$buffer_length
Definition: Tar.php:162
Archive_Tar\_jumpBlock
_jumpBlock($p_len=null)
Definition: Tar.php:1105
Archive_Tar\setAttribute
setAttribute()
Definition: Tar.php:695
Archive_Tar\_writeHeader
_writeHeader($p_filename, $p_stored_filename)
Definition: Tar.php:1385
Archive_Tar\_extractList
_extractList( $p_path, &$p_list_detail, $p_mode, $p_file_list, $p_remove_path, $p_preserve=false, $p_symlinks=true)
Definition: Tar.php:1958
Archive_Tar\_openWrite
_openWrite()
Definition: Tar.php:801
Archive_Tar\_openReadWrite
_openReadWrite()
Definition: Tar.php:910
Archive_Tar\_openAppend
_openAppend()
Definition: Tar.php:2259
Archive_Tar\$_compress
$_compress
Definition: Tar.php:96
Archive_Tar\extractList
extractList($p_filelist, $p_path='', $p_remove_path='', $p_preserve=false, $p_symlinks=true)
Definition: Tar.php:658
Archive_Tar\_writeHeaderBlock
_writeHeaderBlock( $p_filename, $p_size, $p_mtime=0, $p_perms=0, $p_type='', $p_uid=0, $p_gid=0)
Definition: Tar.php:1508
Archive_Tar\setIgnoreRegexp
setIgnoreRegexp($regexp)
Definition: Tar.php:748
Archive_Tar\_error
_error($p_message)
Definition: Tar.php:772
Archive_Tar\_addList
_addList($p_list, $p_add_dir, $p_remove_dir)
Definition: Tar.php:1161
Archive_Tar\$_file
$_file
Definition: Tar.php:120
Archive_Tar\_readHeader
_readHeader($v_binary_data, &$v_header)
Definition: Tar.php:1698
Archive_Tar\add
add($p_filelist)
Definition: Tar.php:337
Archive_Tar\create
create($p_filelist)
Definition: Tar.php:316
Archive_Tar\$_tarname
$_tarname
Definition: Tar.php:88
PEAR\loadExtension
static loadExtension($ext)
Definition: PEAR.php:759
Archive_Tar\_readLongHeader
_readLongHeader(&$v_header)
Definition: Tar.php:1843
Archive_Tar\_writeBlock
_writeBlock($p_binary_data, $p_len=null)
Definition: Tar.php:1020
Archive_Tar\_isArchive
_isArchive($p_filename=null)
Definition: Tar.php:789
Archive_Tar\_cleanFile
_cleanFile()
Definition: Tar.php:997
Archive_Tar\_warning
_warning($p_message)
Definition: Tar.php:780
Archive_Tar\_openRead
_openRead()
Definition: Tar.php:839
Archive_Tar\$_ignore_regexp
$_ignore_regexp
Definition: Tar.php:136
Archive_Tar\__construct
__construct($p_tarname, $p_compress=null, $buffer_length=512)
Definition: Tar.php:180
Archive_Tar\$_temp_tarname
$_temp_tarname
Definition: Tar.php:128
Archive_Tar\addString
addString($p_filename, $p_string, $p_datetime=false, $p_params=array())
Definition: Tar.php:531
Archive_Tar\_writeLongHeader
_writeLongHeader($p_filename, $is_link=false)
Definition: Tar.php:1617
Archive_Tar\$error_object
$error_object
Definition: Tar.php:144
Archive_Tar\_writeFooter
_writeFooter()
Definition: Tar.php:1145
Archive_Tar\addModify
addModify($p_filelist, $p_add_dir, $p_remove_dir='')
Definition: Tar.php:478
Archive_Tar\_append
_append($p_filelist, $p_add_dir='', $p_remove_dir='')
Definition: Tar.php:2399
Archive_Tar\$_fmt
$_fmt
Definition: Tar.php:154
Archive_Tar\extract
extract($p_path='', $p_preserve=false, $p_symlinks=true)
Definition: Tar.php:348
Archive_Tar\_close
_close()
Definition: Tar.php:956
Archive_Tar\setIgnoreList
setIgnoreList($list)
Definition: Tar.php:762
Archive_Tar\__destruct
__destruct()
Definition: Tar.php:286
Archive_Tar\_addFile
_addFile($p_filename, &$p_header, $p_add_dir, $p_remove_dir, $v_stored_filename=null)
Definition: Tar.php:1247
Archive_Tar