PluginProbe ʕ •ᴥ•ʔ
JetBackup – Backup, Restore & Migrate / 3.1.13.4
JetBackup – Backup, Restore & Migrate v3.1.13.4
3.1.22.3 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.8.1 1.4.9 1.5.0 1.5.1 1.5.1.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.6.0 1.6.10 1.6.11 1.6.12 1.6.13 1.6.15 1.6.5.1 1.6.8.8 1.6.9 1.6.9.1 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7.5 2.0.8.7 2.0.9.11 2.0.9.14 2.0.9.15 2.0.9.6 2.0.9.7 2.0.9.9 3.1.10.7 3.1.11.1 3.1.12.3 3.1.13.4 3.1.14.17 3.1.15.4 3.1.16.1 3.1.17.5 3.1.18.10 3.1.18.8 3.1.18.9 3.1.19.8 3.1.20.3 3.1.21.3 3.1.7.9 3.1.9.2 trunk 1.1.90 1.1.91 1.2.0 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.2
backup / src / JetBackup / Downloader / Downloader.php
backup / src / JetBackup / Downloader Last commit date
.htaccess 9 months ago Downloader.php 9 months ago index.html 9 months ago web.config 9 months ago
Downloader.php
84 lines
1 <?php
2
3 namespace JetBackup\Downloader;
4
5 use JetBackup\Exception\DownloaderException;
6 use JetBackup\Factory;
7
8 if (!defined( '__JETBACKUP__')) die('Direct access is not allowed');
9
10 class Downloader {
11
12 const DEFAULT_CHUNK = 8192; // 8k
13
14 private ?string $_filename;
15 private string $_source;
16
17 /**
18 * @param string $source
19 * @param string|null $filename
20 */
21 public function __construct(string $source, ?string $filename=null) {
22 $this->_source = $source;
23 $this->_filename = $filename;
24 }
25
26 /**
27 * @return \stdClass
28 */
29 private static function _getRange($filesize):object {
30 $output = new \stdClass();
31 $output->start = 0;
32 $output->end = $filesize-1;
33
34 if (
35 !isset($_SERVER['HTTP_RANGE']) ||
36 !preg_match('/bytes=(\d+)-(\d*)/', $_SERVER['HTTP_RANGE'], $matches)
37 ) return $output;
38
39 $output->start = (int) $matches[1];
40 if (!empty($matches[2])) $output->end = (int) $matches[2];
41
42 return $output;
43 }
44
45 /**
46 * @param int $chunk
47 *
48 * @return void
49 * @throws DownloaderException
50 */
51 public function download(int $chunk=self::DEFAULT_CHUNK):void {
52
53 if( !$this->_source || !file_exists($this->_source) || is_dir($this->_source)) throw new DownloaderException('The provided download file does not exists');
54 if (!str_starts_with(trim($this->_source), trim(Factory::getLocations()->getDataDir()))) throw new DownloaderException('Invalid download source path');
55 if(!($fd = fopen($this->_source, 'rb'))) throw new DownloaderException('Unable to open download file');
56 if(!$this->_filename) $this->_filename = basename($this->_source);
57
58 $filesize = filesize($this->_source);
59 if ($filesize === false || $filesize < 0) throw new DownloaderException('Unable to stat download file');
60
61 $range = self::_getRange($filesize);
62
63 // gzip compression may corrupt binary data
64 if (function_exists('apache_setenv')) @apache_setenv('no-gzip', 1);
65 @ini_set('zlib.output_compression', 'Off');
66 while (ob_get_level()) @ob_end_clean();
67
68 header("Content-Type: application/octet-stream");
69 header('Content-Disposition: attachment; filename="' . $this->_filename . '"; filename*=UTF-8\'\'' . rawurlencode($this->_filename));
70 header("Accept-Ranges: bytes");
71 header("Content-Length: " . ($range->end - $range->start + 1));
72 header("Content-Range: bytes $range->start-$range->end/".$filesize);
73
74 if($range->start > 0) fseek($fd, $range->start);
75
76 while (!feof($fd) && ($pos = ftell($fd)) <= $range->end) {
77 echo fread($fd, min($chunk, $range->end - $pos + 1));
78 flush();
79 }
80
81 fclose($fd);
82 exit;
83 }
84 }