PluginProbe
User Access Manager / 2.1.11
User Access Manager v2.1.11
2.3.20 2.3.19 2.3.18 2.3.17 2.3.16 2.3.15 2.3.14 2.3.13 trunk 0.6 0.6.1 0.6.2 0.7 0.7 Beta 0.7.0.1 0.8 0.8.0.1 0.8.0.2 0.9 0.9.1 0.9.1.1 0.9.1.2 0.9.1.3 0.9.1.4 1.0 All 136 releases
← All changes | src/File/FileHandler.php +225 -76 2.3.16 → 2.1.11 View file →
@@ -1,42 +1,105 @@
1 1 <?php
2 -
3 -declare(strict_types=1);
4 -
2 +/**
3 + * FileHandler.php
4 + *
5 + * The FileHandler class file.
6 + *
7 + * PHP versions 5
8 + *
9 + * @author Alexander Schneider <[email protected]>
10 + * @copyright 2008-2017 Alexander Schneider
11 + * @license http://www.gnu.org/licenses/gpl-2.0.html GNU General Public License, version 2
12 + * @version SVN: $id$
13 + * @link http://wordpress.org/extend/plugins/user-access-manager/
14 + */
5 15 namespace UserAccessManager\File;
6 16
7 -use JetBrains\PhpStorm\NoReturn;
8 17 use UserAccessManager\Config\MainConfig;
9 18 use UserAccessManager\Config\WordpressConfig;
10 19 use UserAccessManager\Wrapper\Php;
11 20 use UserAccessManager\Wrapper\Wordpress;
12 21
22 +/**
23 + * Class FileHandler
24 + *
25 + * @package UserAccessManager\FileHandler
26 + */
13 27 class FileHandler
14 28 {
15 - public const X_SEND_FILE_TEST_FILE = 'xSendFileTestFile';
29 + const X_SEND_FILE_TEST_FILE = 'xSendFileTestFile';
16 30
31 + /**
32 + * @var Php
33 + */
34 + private $php;
35 +
36 + /**
37 + * @var Wordpress
38 + */
39 + private $wordpress;
40 +
41 + /**
42 + * @var WordpressConfig
43 + */
44 + private $wordpressConfig;
45 +
46 + /**
47 + * @var MainConfig
48 + */
49 + private $mainConfig;
50 +
51 + /**
52 + * @var FileProtectionFactory
53 + */
54 + private $fileProtectionFactory;
55 +
56 + /**
57 + * FileHandler constructor.
58 + *
59 + * @param Php $php
60 + * @param Wordpress $wordpress
61 + * @param WordpressConfig $wordpressConfig
62 + * @param MainConfig $mainConfig
63 + * @param FileProtectionFactory $fileProtectionFactory
64 + */
17 65 public function __construct(
18 - private Php $php,
19 - private Wordpress $wordpress,
20 - private WordpressConfig $wordpressConfig,
21 - private MainConfig $mainConfig,
22 - private FileProtectionFactory $fileProtectionFactory
66 + Php $php,
67 + Wordpress $wordpress,
68 + WordpressConfig $wordpressConfig,
69 + MainConfig $mainConfig,
70 + FileProtectionFactory $fileProtectionFactory
23 71 ) {
72 + $this->php = $php;
73 + $this->wordpress = $wordpress;
74 + $this->wordpressConfig = $wordpressConfig;
75 + $this->mainConfig = $mainConfig;
76 + $this->fileProtectionFactory = $fileProtectionFactory;
24 77 }
25 78
26 - private function clearBuffer(): void
79 + /**
80 + * Clears the buffer.
81 + */
82 + private function clearBuffer()
27 83 {
28 84 //prevent '\n' / '0A'
29 - if ((int) $this->php->iniGet('output_buffering') === 0
85 + if ((int)$this->php->iniGet('output_buffering') === 0
30 86 && is_numeric(ob_get_length()) === true
31 87 ) {
32 88 ob_clean();
33 89 }
34 90
35 - $this->php->flush();
91 + flush();
36 92 }
37 93
38 - private function getFileMineType(string $file): string
94 + /**
95 + * Returns the file mine type.
96 + *
97 + * @param string $file
98 + *
99 + * @return string
100 + */
101 + private function getFileMineType($file)
39 102 {
40 103 $fileName = basename($file);
41 104
42 105 /*
@@ -52,9 +115,9 @@
52 115
53 116 if ($this->php->functionExists('finfo_open') === true) {
54 117 $fileInfo = finfo_open(FILEINFO_MIME);
55 118 $fileMimeType = finfo_file($fileInfo, $file);
56 - $this->php->fInfoClose($fileInfo);
119 + finfo_close($fileInfo);
57 120 } elseif ($this->php->functionExists('mime_content_type')) {
58 121 $fileMimeType = mime_content_type($file);
59 122 } elseif (isset($mimeTypes[$fileExt]) === true) {
60 123 $fileMimeType = $mimeTypes[$fileExt];
@@ -61,23 +124,34 @@
61 124 } else {
62 125 $fileMimeType = 'application/octet-stream';
63 126 }
64 127
65 - return (string) $fileMimeType;
128 + return (string)$fileMimeType;
66 129 }
67 130
68 - private function addDefaultHeader(string $file, bool $isInline): void
131 + /**
132 + * Adds the default header.
133 + *
134 + * @param string $file
135 + * @param bool $isInline
136 + */
137 + private function addDefaultHeader($file, $isInline)
69 138 {
70 139 $fileMimeType = $this->getFileMineType($file);
71 140 $contentDisposition = ($isInline === true) ? 'inline' : 'attachment';
72 141 $baseName = str_replace(' ', '_', basename($file));
73 142
74 - $this->php->header('Content-Description: File Transfer');
75 - $this->php->header('Content-Type: ' . $fileMimeType);
76 - $this->php->header("Content-Disposition: $contentDisposition; filename=\"$baseName\"");
143 + header('Content-Description: File Transfer');
144 + header('Content-Type: '.$fileMimeType);
145 + header("Content-Disposition: {$contentDisposition}; filename=\"{$baseName}\"");
77 146 }
78 147
79 - private function deliverFileViaFopen(string $file): void
148 + /**
149 + * Delivers the file via fopen.
150 + *
151 + * @param string $file
152 + */
153 + private function deliverFileViaFopen($file)
80 154 {
81 155 $handler = fopen($file, 'r');
82 156
83 157 while (feof($handler) === false) {
@@ -88,33 +162,27 @@
88 162 echo $this->php->fread($handler, 1024);
89 163 }
90 164 }
91 165
92 - private function deliverFile(string $file, bool $isInline): void
166 + /**
167 + * Delivers the file.
168 + *
169 + * @param string $file
170 + * @param bool $isInline
171 + */
172 + private function deliverFile($file, $isInline)
93 173 {
94 - $this->php->header("HTTP/1.1 200 OK");
95 174 $downloadType = $this->mainConfig->getDownloadType();
96 175
97 176 if ($downloadType === 'xsendfile') {
98 - if ($this->wordpress->isNginx()) {
99 - // Use /uam-files/ prefix so the internal redirect goes to a dedicated
100 - // internal location that bypasses UAM's rewrite rules, avoiding a loop.
101 - $uri = '/uam-files' . str_replace(rtrim(ABSPATH, '/'), '', $file);
102 - $this->php->header("X-Accel-Redirect: $uri");
103 - } elseif ($this->wordpress->isApacheModuleLoaded('mod_xsendfile')) {
104 - $this->php->header("X-Sendfile: $file");
105 - } else {
106 - // mod_xsendfile is not available — fall back to fopen so the file
107 - // is still delivered rather than sending an empty response.
108 - $downloadType = 'fopen';
109 - }
177 + header("X-Sendfile: {$file}");
110 178 }
111 179
112 180 $this->addDefaultHeader($file, $isInline);
113 181
114 182 if ($downloadType !== 'xsendfile') {
115 - $this->php->header('Content-Transfer-Encoding: binary');
116 - $this->php->header('Content-Length: ' . filesize($file));
183 + header('Content-Transfer-Encoding: binary');
184 + header('Content-Length: '.filesize($file));
117 185 $this->clearBuffer();
118 186
119 187 if ($downloadType === 'fopen') {
120 188 $this->deliverFileViaFopen($file);
@@ -123,14 +191,24 @@
123 191 }
124 192 }
125 193 }
126 194
127 - private function getSeekStartEnd(string $range, int $fileSize, ?int &$seekStart, ?int &$seekEnd): bool
195 + /**
196 + * Sets the seek start and end.
197 + *
198 + * @param string $range
199 + * @param int $fileSize
200 + * @param int $seekStart
201 + * @param int $seekEnd
202 + *
203 + * @return bool
204 + */
205 + private function getSeekStartEnd($range, $fileSize, &$seekStart, &$seekEnd)
128 206 {
129 207 //Figure out download piece from range (if set)
130 208 $seek = explode('-', $range);
131 - $seekStart = ($seek[0] !== '') ? abs((int) $seek[0]) : null;
132 - $seekEnd = (isset($seek[1]) === true && $seek[1] !== '') ? abs((int) $seek[1]) : null;
209 + $seekStart = ($seek[0] !== '') ? abs((int)$seek[0]) : null;
210 + $seekEnd = (isset($seek[1]) === true && $seek[1] !== '') ? abs((int)$seek[1]) : null;
133 211 $maxSize = $fileSize - 1;
134 212
135 213 if ($seekStart === null) {
136 214 $seekStart = $fileSize - $seekEnd;
@@ -144,9 +222,15 @@
144 222
145 223 return $seekStart < $seekEnd;
146 224 }
147 225
148 - private function readFilePartly($fileHandler, int $bytes): void
226 + /**
227 + * Reads the file partly.
228 + *
229 + * @param resource $fileHandler
230 + * @param int $bytes
231 + */
232 + private function readFilePartly($fileHandler, $bytes)
149 233 {
150 234 $bytesLeft = $bytes;
151 235 $bufferSize = 1024;
152 236
@@ -162,9 +246,16 @@
162 246 }
163 247 }
164 248 }
165 249
166 - private function getRanges(int $fileSize): array
250 + /**
251 + * Returns the http ranges.
252 + *
253 + * @param int $fileSize
254 + *
255 + * @return array
256 + */
257 + private function getRanges($fileSize)
167 258 {
168 259 $httpRange = explode('=', $_SERVER['HTTP_RANGE']);
169 260 $originRanges = isset($httpRange[1]) === true ? $httpRange[1] : '';
170 261 $originRanges = explode(',', $originRanges);
@@ -184,9 +275,19 @@
184 275
185 276 return $ranges;
186 277 }
187 278
188 - private function getExtraContents(string $file, array $ranges, ?int &$contentLength, ?string &$boundary): array
279 + /**
280 + * Returns the extra contents.
281 + *
282 + * @param string $file
283 + * @param array $ranges
284 + * @param int $contentLength
285 + * @param string $boundary
286 + *
287 + * @return array
288 + */
289 + private function getExtraContents($file, array $ranges, &$contentLength, &$boundary)
189 290 {
190 291 $contentLength = 0;
191 292 $extraContents = [];
192 293
@@ -192,17 +293,17 @@
192 293
193 294 //More than one range is requested?
194 295 if (count($ranges) > 1) {
195 296 $boundary = 'g45d64df96bmdf4sdgh45hf5';
196 - $fullBoundary = "\r\n--$boundary--\r\n";
297 + $fullBoundary = "\r\n--{$boundary}--\r\n";
197 298 $fileSize = filesize($file);
198 299 $mineType = $this->getFileMineType($file);
199 300
200 301 //compute content length
201 302 foreach ($ranges as $index => $range) {
202 - [$seekStart, $seekEnd] = $range;
303 + list($seekStart, $seekEnd) = $range;
203 304 $extraContent = $fullBoundary;
204 - $extraContent .= "Content-Type: $mineType\r\n";
305 + $extraContent .= "Content-Type: {$mineType}\r\n";
205 306 $extraContent .= "Content-Range: bytes $seekStart-$seekEnd/$fileSize\r\n\r\n";
206 307 $extraContents[$index] = $extraContent;
207 308 $contentLength += strlen($extraContent) + ($seekEnd - $seekStart + 1);
208 309 }
@@ -213,9 +314,15 @@
213 314
214 315 return $extraContents;
215 316 }
216 317
217 - private function deliverFilePartial(string $file, bool $isInline): void
318 + /**
319 + * Delivers the file partial.
320 + *
321 + * @param string $file
322 + * @param bool $isInline
323 + */
324 + private function deliverFilePartial($file, $isInline)
218 325 {
219 326 $fileSize = filesize($file);
220 327 $ranges = $this->getRanges($fileSize);
221 328
@@ -221,22 +328,22 @@
221 328
222 329 if ($ranges !== []) {
223 330 $extraContents = $this->getExtraContents($file, $ranges, $contentLength, $boundary);
224 331
225 - $this->php->header('HTTP/1.1 206 Partial Content');
226 - $this->php->header('Content-Transfer-Encoding: binary');
227 - $this->php->header('Accept-Ranges: bytes');
332 + header('HTTP/1.1 206 Partial Content');
333 + header('Content-Transfer-Encoding: binary');
334 + header('Accept-Ranges: bytes');
228 335
229 336 if ($extraContents === []) {
230 337 $this->addDefaultHeader($file, $isInline);
231 - [$seekStart, $seekEnd] = $ranges[0];
338 + list($seekStart, $seekEnd) = $ranges[0];
232 339 $contentLength = ($seekEnd - $seekStart + 1);
233 - $this->php->header("Content-Range: bytes $seekStart-$seekEnd/$fileSize");
340 + header("Content-Range: bytes {$seekStart}-{$seekEnd}/{$fileSize}");
234 341 } else {
235 - $this->php->header("Content-Type: multipart/x-byteranges; boundary=$boundary");
342 + header("Content-Type: multipart/x-byteranges; boundary={$boundary}");
236 343 }
237 344
238 - $this->php->header("Content-Length: $contentLength");
345 + header("Content-Length: {$contentLength}");
239 346 $fileHandler = fopen($file, 'r');
240 347
241 348 foreach ($ranges as $index => $range) {
242 349 if (isset($extraContents[$index]) === true) {
@@ -242,10 +349,10 @@
242 349 if (isset($extraContents[$index]) === true) {
243 350 echo $extraContents[$index];
244 351 }
245 352
246 - [$seekStart, $seekEnd] = $ranges[0];
247 - $this->php->fseek($fileHandler, $seekStart);
353 + list($seekStart, $seekEnd) = $ranges[0];
354 + fseek($fileHandler, $seekStart);
248 355 $this->readFilePartly($fileHandler, $seekEnd - $seekStart + 1);
249 356 }
250 357
251 358 if ($extraContents !== []) {
@@ -252,16 +359,23 @@
252 359 echo end($extraContents);
253 360 $this->clearBuffer();
254 361 }
255 362 } else {
256 - $this->php->header('HTTP/1.1 416 Requested Range Not Satisfiable');
257 - $this->php->header("Content-Range: */$fileSize");
363 + header('HTTP/1.1 416 Requested Range Not Satisfiable');
364 + header("Content-Range: */$fileSize");
258 365 }
259 366 }
260 367
261 - private function isInlineFile(string $file): bool
368 + /**
369 + * Checks if the file is an inline file
370 + *
371 + * @param string $file
372 + *
373 + * @return bool
374 + */
375 + private function isInlineFile($file)
262 376 {
263 - $inlineFiles = array_map('trim', explode(',', (string) $this->mainConfig->getInlineFiles()));
377 + $inlineFiles = array_map('trim', explode(',', $this->mainConfig->getInlineFiles()));
264 378 $map = array_flip($inlineFiles);
265 379 $extension = pathinfo($file, PATHINFO_EXTENSION);
266 380
267 381 return isset($map[$extension]);
@@ -266,10 +380,15 @@
266 380
267 381 return isset($map[$extension]);
268 382 }
269 383
270 - #[NoReturn]
271 - public function getFile(string $file, bool $isImage): void
384 + /**
385 + * Delivers the content of the requested file.
386 + *
387 + * @param string $file
388 + * @param bool $isImage
389 + */
390 + public function getFile($file, $isImage)
272 391 {
273 392 //Deliver content
274 393 if (file_exists($file) === true) {
275 394 $isInline = $isImage === true || $this->isInlineFile($file) === true;
@@ -292,9 +411,14 @@
292 411 );
293 412 }
294 413 }
295 414
296 - private function getCurrentFileProtectionHandler(): FileProtectionInterface
415 + /**
416 + * Returns the current file protection handler.
417 + *
418 + * @return FileProtectionInterface
419 + */
420 + private function getCurrentFileProtectionHandler()
297 421 {
298 422 if ($this->wordpress->isNginx() === true) {
299 423 return $this->fileProtectionFactory->createNginxFileProtection();
300 424 }
@@ -301,9 +425,14 @@
301 425
302 426 return $this->fileProtectionFactory->createApacheFileProtection();
303 427 }
304 428
305 - public function getFileProtectionFileName(): string
429 + /**
430 + * Returns the file protection file.
431 + *
432 + * @return string
433 + */
434 + public function getFileProtectionFileName()
306 435 {
307 436 return $this->getCurrentFileProtectionHandler()->getFileNameWithPath(
308 437 $this->wordpressConfig->getUploadDirectory()
309 438 );
@@ -308,9 +437,17 @@
308 437 $this->wordpressConfig->getUploadDirectory()
309 438 );
310 439 }
311 440
312 - public function createFileProtection(?string $dir = null, ?string $objectType = null): bool
441 + /**
442 + * Creates a protection file.
443 + *
444 + * @param string $dir The destination directory.
445 + * @param string $objectType The object type.
446 + *
447 + * @return false
448 + */
449 + public function createFileProtection($dir = null, $objectType = null)
313 450 {
314 451 $dir = ($dir === null) ? $this->wordpressConfig->getUploadDirectory() : $dir;
315 452
316 453 if ($dir !== null) {
@@ -319,9 +456,16 @@
319 456
320 457 return false;
321 458 }
322 459
323 - public function deleteFileProtection(?string $dir = null): bool
460 + /**
461 + * Deletes the protection files.
462 + *
463 + * @param string $dir The destination directory.
464 + *
465 + * @return false
466 + */
467 + public function deleteFileProtection($dir = null)
324 468 {
325 469 $dir = ($dir === null) ? $this->wordpressConfig->getUploadDirectory() : $dir;
326 470
327 471 if ($dir !== null) {
@@ -330,25 +474,30 @@
330 474
331 475 return false;
332 476 }
333 477
334 - #[NoReturn]
335 - public function deliverXSendFileTestFile(): void
478 + /**
479 + * Delivers a xsendfile test file.
480 + */
481 + public function deliverXSendFileTestFile()
336 482 {
337 - $file = $this->wordpressConfig->getUploadDirectory() . DIRECTORY_SEPARATOR . self::X_SEND_FILE_TEST_FILE;
483 + $file = $this->wordpressConfig->getUploadDirectory().DIRECTORY_SEPARATOR.self::X_SEND_FILE_TEST_FILE;
338 484 file_put_contents($file, 'success');
339 485
340 - $this->php->header("X-Sendfile: $file");
341 - $this->php->header('Content-Type: application/octet-stream');
342 - $this->php->header('Content-Disposition: attachment; filename="' . basename($file) . '"');
486 + header("X-Sendfile: {$file}");
487 + header('Content-Type: application/octet-stream');
488 + header('Content-Disposition: attachment; filename="'.basename($file).'"');
343 489 $this->php->callExit();
344 490 }
345 491
346 - public function removeXSendFileTestFile(): void
492 + /**
493 + * Removes the xsendfile test file if exists.
494 + */
495 + public function removeXSendFileTestFile()
347 496 {
348 - $file = $this->wordpressConfig->getUploadDirectory() . DIRECTORY_SEPARATOR . self::X_SEND_FILE_TEST_FILE;
497 + $file = $this->wordpressConfig->getUploadDirectory().DIRECTORY_SEPARATOR.self::X_SEND_FILE_TEST_FILE;
349 498
350 - if ($this->php->isFile($file) === true) {
351 - $this->php->unlink($file);
499 + if (file_exists($file) === true) {
500 + unlink($file);
352 501 }
353 502 }
354 503 }