[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/libraries/vendor/joomla/archive/src/ -> Tar.php (source)

   1  <?php
   2  /**
   3   * Part of the Joomla Framework Archive Package
   4   *
   5   * @copyright  Copyright (C) 2005 - 2021 Open Source Matters, Inc. All rights reserved.
   6   * @license    GNU General Public License version 2 or later; see LICENSE
   7   */
   8  
   9  namespace Joomla\Archive;
  10  
  11  use Joomla\Filesystem\File;
  12  use Joomla\Filesystem\Folder;
  13  use Joomla\Filesystem\Path;
  14  
  15  /**
  16   * Tar format adapter for the Archive package
  17   *
  18   * This class is inspired from and draws heavily in code and concept from the Compress package of
  19   * The Horde Project <http://www.horde.org>
  20   *
  21   * @contributor  Michael Slusarz <[email protected]>
  22   * @contributor  Michael Cochrane <[email protected]>
  23   *
  24   * @since  1.0
  25   */
  26  class Tar implements ExtractableInterface
  27  {
  28      /**
  29       * Tar file types.
  30       *
  31       * @var    array
  32       * @since  1.0
  33       */
  34      private const TYPES = [
  35          0x0  => 'Unix file',
  36          0x30 => 'File',
  37          0x31 => 'Link',
  38          0x32 => 'Symbolic link',
  39          0x33 => 'Character special file',
  40          0x34 => 'Block special file',
  41          0x35 => 'Directory',
  42          0x36 => 'FIFO special file',
  43          0x37 => 'Contiguous file',
  44      ];
  45  
  46      /**
  47       * Tar file data buffer
  48       *
  49       * @var    string
  50       * @since  1.0
  51       */
  52      private $data;
  53  
  54      /**
  55       * Tar file metadata array
  56       *
  57       * @var    array
  58       * @since  1.0
  59       */
  60      private $metadata;
  61  
  62      /**
  63       * Holds the options array.
  64       *
  65       * @var    array|\ArrayAccess
  66       * @since  1.0
  67       */
  68      protected $options = [];
  69  
  70      /**
  71       * Create a new Archive object.
  72       *
  73       * @param   array|\ArrayAccess  $options  An array of options or an object that implements \ArrayAccess
  74       *
  75       * @since   1.0
  76       * @throws  \InvalidArgumentException
  77       */
  78  	public function __construct($options = [])
  79      {
  80          if (!\is_array($options) && !($options instanceof \ArrayAccess))
  81          {
  82              throw new \InvalidArgumentException(
  83                  'The options param must be an array or implement the ArrayAccess interface.'
  84              );
  85          }
  86  
  87          $this->options = $options;
  88      }
  89  
  90      /**
  91       * Extract a ZIP compressed file to a given path
  92       *
  93       * @param   string  $archive      Path to ZIP archive to extract
  94       * @param   string  $destination  Path to extract archive into
  95       *
  96       * @return  boolean True if successful
  97       *
  98       * @since   1.0
  99       * @throws  \RuntimeException
 100       */
 101  	public function extract($archive, $destination)
 102      {
 103          $this->metadata = null;
 104          $this->data     = file_get_contents($archive);
 105  
 106          if (!$this->data)
 107          {
 108              throw new \RuntimeException('Unable to read archive');
 109          }
 110  
 111          $this->getTarInfo($this->data);
 112  
 113          for ($i = 0, $n = \count($this->metadata); $i < $n; $i++)
 114          {
 115              $type = strtolower($this->metadata[$i]['type']);
 116  
 117              if ($type == 'file' || $type == 'unix file')
 118              {
 119                  $buffer = $this->metadata[$i]['data'];
 120                  $path   = Path::clean($destination . '/' . $this->metadata[$i]['name']);
 121  
 122                  if (!$this->isBelow($destination, $destination . '/' . $this->metadata[$i]['name']))
 123                  {
 124                      throw new \OutOfBoundsException('Unable to write outside of destination path', 100);
 125                  }
 126  
 127                  // Make sure the destination folder exists
 128                  if (!Folder::create(\dirname($path)))
 129                  {
 130                      throw new \RuntimeException('Unable to create destination folder ' . \dirname($path));
 131                  }
 132  
 133                  if (!File::write($path, $buffer))
 134                  {
 135                      throw new \RuntimeException('Unable to write entry to file ' . $path);
 136                  }
 137              }
 138          }
 139  
 140          return true;
 141      }
 142  
 143      /**
 144       * Tests whether this adapter can unpack files on this computer.
 145       *
 146       * @return  boolean  True if supported
 147       *
 148       * @since   1.0
 149       */
 150  	public static function isSupported()
 151      {
 152          return true;
 153      }
 154  
 155      /**
 156       * Get the list of files/data from a Tar archive buffer and builds a metadata array.
 157       *
 158       * Array structure:
 159       * <pre>
 160       * KEY: Position in the array
 161       * VALUES: 'attr'  --  File attributes
 162       * 'data'  --  Raw file contents
 163       * 'date'  --  File modification time
 164       * 'name'  --  Filename
 165       * 'size'  --  Original file size
 166       * 'type'  --  File type
 167       * </pre>
 168       *
 169       * @param   string  $data  The Tar archive buffer.
 170       *
 171       * @return  void
 172       *
 173       * @since   1.0
 174       * @throws  \RuntimeException
 175       */
 176  	protected function getTarInfo(&$data)
 177      {
 178          $position    = 0;
 179          $returnArray = [];
 180  
 181          while ($position < \strlen($data))
 182          {
 183              $info = @unpack(
 184                  'Z100filename/Z8mode/Z8uid/Z8gid/Z12size/Z12mtime/Z8checksum/Ctypeflag/Z100link/Z6magic/Z2version/Z32uname/Z32gname/Z8devmajor/Z8devminor',
 185                  substr($data, $position)
 186              );
 187  
 188              /*
 189               * This variable has been set in the previous loop, meaning that the filename was present in the previous block
 190               * to allow more than 100 characters - see below
 191               */
 192              if (isset($longlinkfilename))
 193              {
 194                  $info['filename'] = $longlinkfilename;
 195                  unset($longlinkfilename);
 196              }
 197  
 198              if (!$info)
 199              {
 200                  throw new \RuntimeException('Unable to decompress data');
 201              }
 202  
 203              $position += 512;
 204              $contents = substr($data, $position, octdec($info['size']));
 205              $position += ceil(octdec($info['size']) / 512) * 512;
 206  
 207              if ($info['filename'])
 208              {
 209                  $file = [
 210                      'attr' => null,
 211                      'data' => null,
 212                      'date' => octdec($info['mtime']),
 213                      'name' => trim($info['filename']),
 214                      'size' => octdec($info['size']),
 215                      'type' => self::TYPES[$info['typeflag']] ?? null,
 216                  ];
 217  
 218                  if (($info['typeflag'] == 0) || ($info['typeflag'] == 0x30) || ($info['typeflag'] == 0x35))
 219                  {
 220                      // File or folder.
 221                      $file['data'] = $contents;
 222  
 223                      $mode         = hexdec(substr($info['mode'], 4, 3));
 224                      $file['attr'] = (($info['typeflag'] == 0x35) ? 'd' : '-')
 225                          . (($mode & 0x400) ? 'r' : '-')
 226                          . (($mode & 0x200) ? 'w' : '-')
 227                          . (($mode & 0x100) ? 'x' : '-')
 228                          . (($mode & 0x040) ? 'r' : '-')
 229                          . (($mode & 0x020) ? 'w' : '-')
 230                          . (($mode & 0x010) ? 'x' : '-')
 231                          . (($mode & 0x004) ? 'r' : '-')
 232                          . (($mode & 0x002) ? 'w' : '-')
 233                          . (($mode & 0x001) ? 'x' : '-');
 234                  }
 235                  elseif (\chr($info['typeflag']) == 'L' && $info['filename'] == '././@LongLink')
 236                  {
 237                      // GNU tar ././@LongLink support - the filename is actually in the contents, set a variable here so we can test in the next loop
 238                      $longlinkfilename = $contents;
 239  
 240                      // And the file contents are in the next block so we'll need to skip this
 241                      continue;
 242                  }
 243  
 244                  $returnArray[] = $file;
 245              }
 246          }
 247  
 248          $this->metadata = $returnArray;
 249      }
 250  
 251      /**
 252       * Check if a path is below a given destination path
 253       *
 254       * @param   string  $destination  The destination path
 255       * @param   string  $path         The path to be checked
 256       *
 257       * @return  boolean
 258       *
 259       * @since   2.0.1
 260       */
 261  	private function isBelow($destination, $path): bool
 262      {
 263          $absoluteRoot = Path::clean(Path::resolve($destination));
 264          $absolutePath = Path::clean(Path::resolve($path));
 265  
 266          return strpos($absolutePath, $absoluteRoot) === 0;
 267      }
 268  }


Generated: Wed Sep 7 05:41:13 2022 Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer