[ Index ] |
PHP Cross Reference of Joomla 4.2.2 documentation |
[Summary view] [Print] [Text view]
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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Sep 7 05:41:13 2022 | Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer |