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