root / drupal7 / misc / typo3 / phar-stream-wrapper / src / Phar / Reader.php @ fbb66ca6
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 |
} |