annotate vendor/typo3/phar-stream-wrapper/src/Phar/Reader.php @ 5:12f9dff5fda9 tip

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