PluginProbe ʕ •ᴥ•ʔ
JetBackup – Backup, Restore & Migrate / trunk
JetBackup – Backup, Restore & Migrate vtrunk
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 / Cron / Task / Download.php
backup / src / JetBackup / Cron / Task Last commit date
.htaccess 1 year ago Backup.php 1 year ago Download.php 1 year ago DownloadBackupLog.php 1 year ago Export.php 1 year ago Extract.php 1 year ago PreRestore.php 5 months ago Reindex.php 1 month ago Restore.php 5 months ago RetentionCleanup.php 4 months ago System.php 5 months ago Task.php 4 months ago index.html 1 year ago web.config 1 year ago
Download.php
255 lines
1 <?php
2
3 namespace JetBackup\Cron\Task;
4
5 use JetBackup\Archive\Archive;
6 use JetBackup\Archive\Gzip;
7 use JetBackup\BackupJob\BackupJob;
8 use JetBackup\Data\Engine;
9 use JetBackup\Destination\Destination;
10 use JetBackup\DirIterator\DirIterator;
11 use JetBackup\Entities\Util;
12 use JetBackup\Exception\ArchiveException;
13 use JetBackup\Exception\DBException;
14 use JetBackup\Exception\DirIteratorException;
15 use JetBackup\Exception\DirIteratorFileVanishedException;
16 use JetBackup\Exception\DownloaderException;
17 use JetBackup\Exception\SGBExtractorException;
18 use JetBackup\Exception\TaskException;
19 use JetBackup\Factory;
20 use JetBackup\JetBackup;
21 use JetBackup\License\License;
22 use JetBackup\Queue\Queue;
23 use JetBackup\Queue\QueueItem;
24 use JetBackup\Queue\QueueItemDownload;
25 use JetBackup\SGB\Extractor;
26 use JetBackup\Snapshot\Snapshot;
27 use JetBackup\Snapshot\SnapshotDownload;
28 use SleekDB\Exceptions\InvalidArgumentException;
29 use SleekDB\Exceptions\IOException;
30
31 if (!defined( '__JETBACKUP__')) die('Direct access is not allowed');
32
33 class Download extends Task {
34
35 const LOG_FILENAME = 'download';
36
37 private Snapshot $_snapshot;
38 private QueueItemDownload $_queue_item_download;
39 private string $_target;
40
41 public function __construct() {
42 parent::__construct(self::LOG_FILENAME);
43 }
44
45 /**
46 * @return void
47 * @throws IOException
48 * @throws InvalidArgumentException
49 * @throws DBException
50 * @throws TaskException
51 */
52 public function execute():void {
53 parent::execute();
54
55 $this->_queue_item_download = $this->getQueueItem()->getItemData();
56 $this->_snapshot = new Snapshot($this->_queue_item_download->getSnapshotId());
57
58 $destination = new Destination($this->_snapshot->getDestinationId());
59
60 if(!License::isValid() && !in_array($destination->getType(), Destination::LICENSE_EXCLUDED)) {
61 $this->getLogController()->logError("You can't download backups from {$destination->getType()} destination without a license");
62 $this->getQueueItem()->updateStatus(Queue::STATUS_ABORTED);
63 $this->getQueueItem()->updateProgress('Download Aborted!', QueueItem::PROGRESS_LAST_STEP);
64 return;
65 }
66
67 if($this->getQueueItem()->getStatus() == Queue::STATUS_PENDING) {
68 $this->getLogController()->logMessage('Starting Download Task');
69
70 $this->getQueueItem()->getProgress()->setTotalItems(count(Queue::STATUS_DOWNLOAD_NAMES));
71 $this->getQueueItem()->save();
72
73 $this->getQueueItem()->updateProgress('Starting Download Task');
74 } elseif($this->getQueueItem()->getStatus() > Queue::STATUS_PENDING) {
75 $this->getLogController()->logMessage('Resumed Download Task');
76 }
77
78 $this->_target = $this->getQueueItem()->getWorkspace() . JetBackup::SEP . $this->_snapshot->getName() . Archive::ARCHIVE_EXT;
79
80 try {
81 $this->func([$this, '_download']);
82 $this->func([$this, '_extractLegacy']);
83 $this->func([$this, '_archive']);
84 // Not sure if we need this, all backup items are already compressed
85 //$this->func([$this, '_compress']);
86 $this->func([$this, '_moveDownload'], [$this->_target]);
87 if($this->getQueueItem()->getStatus() < Queue::STATUS_DONE && !$this->getQueueItem()->getErrors()) $this->getQueueItem()->updateStatus(Queue::STATUS_DONE);
88 else $this->getQueueItem()->updateStatus(Queue::STATUS_PARTIALLY);
89 $this->getLogController()->logMessage('Completed!');
90 } catch(\Exception $e) {
91 $this->getQueueItem()->updateStatus(Queue::STATUS_FAILED);
92 $this->getLogController()->logError($e->getMessage());
93 $this->getLogController()->logMessage('Failed!');
94 }
95
96 $this->getQueueItem()->updateProgress(
97 $this->getQueueItem()->getStatus() == Queue::STATUS_DONE
98 ? 'Download Completed!'
99 : ($this->getQueueItem()->getStatus() == Queue::STATUS_PARTIALLY
100 ? 'Completed with errors (see logs)'
101 : 'Download Failed!'),
102 QueueItem::PROGRESS_LAST_STEP
103 );
104
105 $this->getLogController()->logMessage('Total time: ' . $this->getExecutionTimeElapsed());
106 }
107
108 /**
109 * @return void
110 * @throws IOException
111 * @throws InvalidArgumentException
112 * @throws \JetBackup\Exception\IOException
113 */
114 public function _download() {
115
116 $queue_item = $this->getQueueItem();
117
118 $this->getLogController()->logMessage('Execution time: ' . $this->getExecutionTimeElapsed());
119 $this->getLogController()->logMessage('TTL time: ' . $this->getExecutionTimeLimit());
120
121 $queue_item->updateStatus(Queue::STATUS_DOWNLOAD_DOWNLOAD);
122 $queue_item->updateProgress('Downloading backup files');
123 $this->getLogController()->logMessage('Downloading backup files');
124
125 $download = new SnapshotDownload($this->_snapshot, $this->getQueueItem()->getWorkspace());
126 $download->setLogController($this->getLogController());
127 $download->setQueueItem($this->getQueueItem());
128 $download->setTask($this);
129 $download->downloadAll();
130
131 // done downloading, reset sub process bar
132 $queue_item->getProgress()->resetSub();
133 $queue_item->save();
134 }
135
136 public function _extractLegacy() {
137 if($this->_snapshot->getEngine() != Engine::ENGINE_SGB) return;
138
139 // SGB snapshot has only 1 item
140 $item = $this->_snapshot->getItems()[0];
141
142 $path = $this->getQueueItem()->getWorkspace() . JetBackup::SEP . $item->getPath();
143
144 try {
145 $extractor = new Extractor($path, $this->getQueueItem()->getWorkspace());
146 $extractor->setLogController($this->getLogController());
147 $extractor->extract(function() {
148 $this->checkExecutionTime();
149 });
150 } catch(SGBExtractorException $e) {
151 throw new DownloaderException($e->getMessage());
152 }
153
154 unlink($path);
155 }
156
157 /**
158 * @return void
159 * @throws ArchiveException
160 * @throws DirIteratorException
161 * @throws \JetBackup\Exception\IOException
162 */
163 public function _archive() {
164
165 $queue_item = $this->getQueueItem();
166
167 $this->getLogController()->logMessage('Execution time: ' . $this->getExecutionTimeElapsed());
168 $this->getLogController()->logMessage('TTL time: ' . $this->getExecutionTimeLimit());
169
170 $queue_item->updateStatus(Queue::STATUS_DOWNLOAD_ARCHIVE);
171 $queue_item->updateProgress('Archiving backup files');
172 $this->getLogController()->logMessage('Archiving backup files');
173
174 $archive = new Archive($this->_target, false, Archive::OPT_SPARSE, 0, $this->getQueueItem()->getWorkspace());
175 $archive->setLogController($this->getLogController());
176
177 $this->scan($this->getQueueItem()->getWorkspace(), function(DirIterator $scan, $data) use ($archive) {
178
179 if (!$data->total_size) throw new ArchiveException('Invalid total tree size');
180
181 $archive->setAppend(!($data->total_size == $data->current_pos));
182
183 if(!$archive->isAppend()) {
184 $this->getLogController()->logMessage('Inside Archive Manager First run');
185 $this->getLogController()->logMessage('Total tree size: ' . $data->total_size);
186 $this->getLogController()->logMessage('Current tree POS: ' . $data->current_pos);
187 }
188
189 try {
190 $fd = $archive->getFileFD();
191 $current_file = $scan->next($fd ? $fd->tell() : 0);
192 } catch (DirIteratorFileVanishedException $e) {
193 $this->getLogController()->logMessage('[ WARNING ] File Vanished : ' . $e->getMessage());
194 return;
195 }
196
197 if($scan->getSource() == $current_file->getName()) return;
198 $this->getLogController()->logMessage("[". ($data->total_size - $data->current_pos)."/$data->total_size] Archiving: {$current_file->getName()}");
199
200 try {
201
202 $file = substr($current_file->getName(), strlen($this->getQueueItem()->getWorkspace())+1);
203 $archive->appendFileChunked($current_file, $file, function() use ($data) {
204
205 $progress = $this->getQueueItem()->getProgress();
206 $progress->setMessage("Archiving");
207 $progress->setTotalSubItems($data->total_size);
208 $progress->setCurrentSubItem($data->total_size - $data->current_pos);
209 $this->getQueueItem()->save();
210
211 // We should return true end exit later, however I want to try to exit here to see if this makes issues
212 $this->checkExecutionTime(function() use ($data) {
213
214 $progress = $this->getQueueItem()->getProgress();
215 $progress->setSubMessage("Waiting for next cron iteration");
216 $progress->setTotalSubItems($data->total_size);
217 $progress->setCurrentSubItem($data->total_size - $data->current_pos);
218 $this->getQueueItem()->save();
219 });
220
221 return false;
222
223 }, Factory::getSettingsPerformance()->getReadChunkSizeBytes());
224 } catch(\Exception|ArchiveException $e) {
225 //this will throw exception if the file has been changed more than 3 times
226 $this->getLogController()->logError('[Download] Error while trying to archive: ' . $e->getMessage());
227 }
228
229 }, ['*.resume', '*.scan']);
230
231 $archive->save();
232 $this->getLogController()->logMessage('[Download] Archive Done');
233 }
234
235 /**
236 * Retrieve the site URL from the snapshot to account for cases where the backup was created on a different domain and later imported.
237 * If the site URL is unavailable, fallback to the current site's domain.
238 * The site URL is included in the downloaded backup file to help users differentiate between backups.
239 *
240 * @throws IOException
241 * @throws InvalidArgumentException
242 */
243 public function _moveDownload($file) {
244
245 $prefix = isset($this->_snapshot->getParams()['site_url']) && $this->_snapshot->getParams()['site_url']
246 ? str_replace('.', '_', parse_url($this->_snapshot->getParams()['site_url'], PHP_URL_HOST))
247 : null;
248
249 $download = \JetBackup\Download\Download::create($file, $prefix);
250 $this->_queue_item_download->setDownloadId($download->getId());
251 $this->getQueueItem()->save();
252
253 $this->getLogController()->logMessage("Download Id: " . $download->getId());
254 }
255 }