annotate vendor/typo3/phar-stream-wrapper/src/Phar/Reader.php @ 19:fa3358dc1485 tip

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