[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/libraries/vendor/typo3/phar-stream-wrapper/src/Phar/ -> Reader.php (source)

   1  <?php
   2  declare(strict_types=1);
   3  namespace TYPO3\PharStreamWrapper\Phar;
   4  
   5  /*
   6   * This file is part of the TYPO3 project.
   7   *
   8   * It is free software; you can redistribute it and/or modify it under the terms
   9   * of the MIT License (MIT). For the full copyright and license information,
  10   * please read the LICENSE file that was distributed with this source code.
  11   *
  12   * The TYPO3 project - inspiring people to share!
  13   */
  14  
  15  class Reader
  16  {
  17      /**
  18       * @var string
  19       */
  20      private $fileName;
  21  
  22      /**
  23       * Mime-type in order to use zlib, bzip2 or no compression.
  24       * In case ext-fileinfo is not present only the relevant types
  25       * 'application/x-gzip' and 'application/x-bzip2' are assigned
  26       * to this class property.
  27       *
  28       * @var string
  29       */
  30      private $fileType;
  31  
  32      /**
  33       * @param string $fileName
  34       */
  35      public function __construct(string $fileName)
  36      {
  37          if (strpos($fileName, '://') !== false) {
  38              throw new ReaderException(
  39                  'File name must not contain stream prefix',
  40                  1539623708
  41              );
  42          }
  43  
  44          $this->fileName = $fileName;
  45          $this->fileType = $this->determineFileType();
  46      }
  47  
  48      /**
  49       * @return Container
  50       */
  51      public function resolveContainer(): Container
  52      {
  53          $data = $this->extractData($this->resolveStream() . $this->fileName);
  54  
  55          if ($data['stubContent'] === null) {
  56              throw new ReaderException(
  57                  'Cannot resolve stub',
  58                  1547807881
  59              );
  60          }
  61          if ($data['manifestContent'] === null || $data['manifestLength'] === null) {
  62              throw new ReaderException(
  63                  'Cannot resolve manifest',
  64                  1547807882
  65              );
  66          }
  67          if (strlen($data['manifestContent']) < $data['manifestLength']) {
  68              throw new ReaderException(
  69                  sprintf(
  70                      'Exected manifest length %d, got %d',
  71                      strlen($data['manifestContent']),
  72                      $data['manifestLength']
  73                  ),
  74                  1547807883
  75              );
  76          }
  77  
  78          return new Container(
  79              Stub::fromContent($data['stubContent']),
  80              Manifest::fromContent($data['manifestContent'])
  81          );
  82      }
  83  
  84      /**
  85       * @param string $fileName e.g. '/path/file.phar' or 'compress.zlib:///path/file.phar'
  86       * @return array
  87       */
  88      private function extractData(string $fileName): array
  89      {
  90          $stubContent = null;
  91          $manifestContent = null;
  92          $manifestLength = null;
  93  
  94          $resource = fopen($fileName, 'r');
  95          if (!is_resource($resource)) {
  96              throw new ReaderException(
  97                  sprintf('Resource %s could not be opened', $fileName),
  98                  1547902055
  99              );
 100          }
 101  
 102          while (!feof($resource)) {
 103              $line = fgets($resource);
 104              // stop processing in case the system fails to read from a stream
 105              if ($line === false) {
 106                  break;
 107              }
 108              // stop reading file when manifest can be extracted
 109              if ($manifestLength !== null && $manifestContent !== null && strlen($manifestContent) >= $manifestLength) {
 110                  break;
 111              }
 112  
 113              $manifestPosition = strpos($line, '__HALT_COMPILER();');
 114  
 115              // first line contains start of manifest
 116              if ($stubContent === null && $manifestContent === null && $manifestPosition !== false) {
 117                  $stubContent = substr($line, 0, $manifestPosition - 1);
 118                  $manifestContent = preg_replace('#^.*__HALT_COMPILER\(\);(?>[ \n]\?>(?>\r\n|\n)?)?#', '', $line);
 119                  $manifestLength = $this->resolveManifestLength($manifestContent);
 120              // line contains start of stub
 121              } elseif ($stubContent === null) {
 122                  $stubContent = $line;
 123              // line contains start of manifest
 124              } elseif ($manifestContent === null && $manifestPosition !== false) {
 125                  $manifestContent = preg_replace('#^.*__HALT_COMPILER\(\);(?>[ \n]\?>(?>\r\n|\n)?)?#', '', $line);
 126                  $manifestLength = $this->resolveManifestLength($manifestContent);
 127              // manifest has been started (thus is cannot be stub anymore), add content
 128              } elseif ($manifestContent !== null) {
 129                  $manifestContent .= $line;
 130                  $manifestLength = $this->resolveManifestLength($manifestContent);
 131              // stub has been started (thus cannot be manifest here, yet), add content
 132              } elseif ($stubContent !== null) {
 133                  $stubContent .= $line;
 134              }
 135          }
 136          fclose($resource);
 137  
 138          return [
 139              'stubContent' => $stubContent,
 140              'manifestContent' => $manifestContent,
 141              'manifestLength' => $manifestLength,
 142          ];
 143      }
 144  
 145      /**
 146       * Resolves stream in order to handle compressed Phar archives.
 147       *
 148       * @return string
 149       */
 150      private function resolveStream(): string
 151      {
 152          if ($this->fileType === 'application/x-gzip' || $this->fileType === 'application/gzip') {
 153              return 'compress.zlib://';
 154          } elseif ($this->fileType === 'application/x-bzip2') {
 155              return 'compress.bzip2://';
 156          }
 157          return '';
 158      }
 159  
 160      /**
 161       * @return string
 162       */
 163      private function determineFileType()
 164      {
 165          if (class_exists('\\finfo')) {
 166              $fileInfo = new \finfo();
 167              return $fileInfo->file($this->fileName, FILEINFO_MIME_TYPE);
 168          }
 169          return $this->determineFileTypeByHeader();
 170      }
 171  
 172      /**
 173       * In case ext-fileinfo is not present only the relevant types
 174       * 'application/x-gzip' and 'application/x-bzip2' are resolved.
 175       *
 176       * @return string
 177       */
 178      private function determineFileTypeByHeader(): string
 179      {
 180          $resource = fopen($this->fileName, 'r');
 181          if (!is_resource($resource)) {
 182              throw new ReaderException(
 183                  sprintf('Resource %s could not be opened', $this->fileName),
 184                  1557753055
 185              );
 186          }
 187          $header = fgets($resource, 4);
 188          fclose($resource);
 189          $mimeType = '';
 190          if (strpos($header, "\x42\x5a\x68") === 0) {
 191              $mimeType = 'application/x-bzip2';
 192          } elseif (strpos($header, "\x1f\x8b") === 0) {
 193              $mimeType = 'application/x-gzip';
 194          }
 195          return $mimeType;
 196      }
 197  
 198      /**
 199       * @param string $content
 200       * @return int|null
 201       */
 202      private function resolveManifestLength(string $content)
 203      {
 204          if (strlen($content) < 4) {
 205              return null;
 206          }
 207          return static::resolveFourByteLittleEndian($content, 0);
 208      }
 209  
 210      /**
 211       * @param string $content
 212       * @param int $start
 213       * @return int
 214       */
 215      public static function resolveFourByteLittleEndian(string $content, int $start): int
 216      {
 217          $payload = substr($content, $start, 4);
 218          if (!is_string($payload)) {
 219              throw new ReaderException(
 220                  sprintf('Cannot resolve value at offset %d', $start),
 221                  1539614260
 222              );
 223          }
 224  
 225          $value = unpack('V', $payload);
 226          if (!isset($value[1])) {
 227              throw new ReaderException(
 228                  sprintf('Cannot resolve value at offset %d', $start),
 229                  1539614261
 230              );
 231          }
 232          return $value[1];
 233      }
 234  
 235      /**
 236       * @param string $content
 237       * @param int $start
 238       * @return int
 239       */
 240      public static function resolveTwoByteBigEndian(string $content, int $start): int
 241      {
 242          $payload = substr($content, $start, 2);
 243          if (!is_string($payload)) {
 244              throw new ReaderException(
 245                  sprintf('Cannot resolve value at offset %d', $start),
 246                  1539614263
 247              );
 248          }
 249  
 250          $value = unpack('n', $payload);
 251          if (!isset($value[1])) {
 252              throw new ReaderException(
 253                  sprintf('Cannot resolve value at offset %d', $start),
 254                  1539614264
 255              );
 256          }
 257          return $value[1];
 258      }
 259  }


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