PluginProbe ʕ •ᴥ•ʔ
Backup Migration / 2.1.2
Backup Migration v2.1.2
2.1.6 2.1.5.2 trunk 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.6.1 1.4.7 1.4.8 1.4.9 1.4.9.1 2.0.0 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.5.1
backup-backup / includes / scanner / backups.php
backup-backup / includes / scanner Last commit date
backups.php 3 months ago files.php 3 months ago
backups.php
271 lines
1 <?php
2
3 // Namespace
4 namespace BMI\Plugin\Scanner;
5
6 // Use
7 use BMI\Plugin\BMI_Logger AS Logger;
8 use BMI\Plugin\Zipper\BMI_Zipper AS Zipper;
9 use BMI\Plugin\Zipper\Zip AS Zip;
10 use BMI\Plugin\External\BMI_External_Storage as ExternalStorage;
11
12 // Exit on direct access
13 if (!defined('ABSPATH')) exit;
14
15 /**
16 * Main Backup Scanner Logic
17 */
18 class BMI_BackupsScanner {
19
20 public function scanBackupDir($path) {
21
22 $files = [];
23 $dirs = new \DirectoryIterator($path);
24 foreach ($dirs as $fileInfo) {
25
26 if ($fileInfo->isDot()) continue;
27 if ($fileInfo->isFile()) {
28 if (in_array($fileInfo->getExtension(), ['zip', 'tar', 'tar.gz', 'gz', 'rar', '7zip', '7z'])) {
29
30 $files[] = array(
31 'filename' => $fileInfo->getFilename(),
32 'path' => $path,
33 'size' => $fileInfo->getSize()
34 );
35
36 } else if (strlen($fileInfo->getExtension()) == 6) { // Remove old partial backups e.g. abcdef.zip.g1wdas
37 $extentions = explode('.', $fileInfo->getFilename());
38 if (in_array($extentions[count($extentions) - 2],['zip', 'tar', 'tar.gz', 'gz', 'rar', '7zip', '7z'])) {
39 if (!file_exists(BMI_BACKUPS . DIRECTORY_SEPARATOR . '.running')) {
40 @unlink($path . DIRECTORY_SEPARATOR . $fileInfo->getFilename());
41 }
42 }
43 } else if ($fileInfo->getFilename() == '.space_check') {
44 if (filemtime(BMI_BACKUPS . DIRECTORY_SEPARATOR . '.space_check') < time() - 2 * MINUTE_IN_SECONDS) {
45 @unlink($path . DIRECTORY_SEPARATOR . $fileInfo->getFilename());
46 }
47 }
48 }
49
50 }
51
52 return $files;
53
54 }
55
56 public function removeOldCache() {
57 $md5_file_summary_path = BMI_BACKUPS . DIRECTORY_SEPARATOR. 'md5summary.php';
58
59 $md5summary = [];
60 if (file_exists($md5_file_summary_path)) {
61 $md5summary = file_get_contents($md5_file_summary_path);
62 $md5summary = substr($md5summary, 18, -2);
63 if (is_serialized($md5summary)) {
64 $md5summary = maybe_unserialize($md5summary);
65 }
66 }
67
68 foreach ($md5summary as $backupName => $md5files) {
69 foreach ($md5files as $index => $md5) {
70 if (!file_exists(BMI_BACKUPS . DIRECTORY_SEPARATOR . $backupName)) {
71 if (file_exists(BMI_BACKUPS . DIRECTORY_SEPARATOR . $md5 . '.json')) {
72 @unlink(BMI_BACKUPS . DIRECTORY_SEPARATOR . $md5 . '.json');
73 }
74 unset($md5summary[$backupName][$index]);
75 }
76 }
77
78 if (sizeof($md5summary[$backupName]) == 0) {
79 unset($md5summary[$backupName]);
80 }
81 }
82
83 $cacheMd5String = "<?php exit; \$x = '" . serialize($md5summary) . "';";
84 file_put_contents($md5_file_summary_path, $cacheMd5String);
85 }
86
87 /**
88 * Get Manifest from Zip
89 * @return array|false Array format:
90 * 0 => Backup Name with Zip Name (string)
91 * 1 => Backup Date date in string format (Y-m-d H:i:s)
92 * 2 => Number of Files (int)
93 * 3 => Backup created date in string format (Y-m-d H:i:s)
94 * 4 => Zip Size (int)
95 * 5 => Lock Status (string) 'locked' | 'unlocked'
96 * 6 => Cron Backup (bool)
97 * 7 => MD5 Hash (string)
98 * 8 => Domain (string)
99 */
100 public function getManifestFromZip($zip_path, &$zipper) {
101
102 if (!file_exists($zip_path)) return false;
103
104 // Get manifest content
105 $md5_file_summary_path = BMI_BACKUPS . DIRECTORY_SEPARATOR. 'md5summary.php';
106 $zip_modification_time = filemtime($zip_path);
107 $zip_name = basename($zip_path);
108
109 $md5summary = [];
110 if (file_exists($md5_file_summary_path)) {
111 $md5summary = file_get_contents($md5_file_summary_path);
112 $md5summary = substr($md5summary, 18, -2);
113 if (is_serialized($md5summary)) {
114 $md5summary = maybe_unserialize($md5summary);
115 }
116 }
117
118 if (!is_array($md5summary)) {
119 @unlink($md5_file_summary_path);
120 $md5summary = [];
121 }
122
123 $md5s = [];
124 $cached_md5 = false;
125 if (isset($md5summary[$zip_name])) {
126
127 $md5s = $md5summary[$zip_name];
128 $latest = 0;
129 $latest_md5 = false;
130 for ($i = 0; $i < sizeof($md5s); ++$i) {
131 $md5_file_path = BMI_BACKUPS . DIRECTORY_SEPARATOR . $md5s[$i] . '.json';
132 if (file_exists($md5_file_path)) {
133 $ftime = filemtime($md5_file_path);
134 if ($ftime > $latest) {
135 $latest = $ftime;
136 $latest_md5 = $md5s[$i];
137 }
138 }
139 }
140
141 if ($latest_md5 != false) {
142 $cached_md5 = $latest_md5;
143 }
144
145 } else {
146
147 if ($zip_name) $md5summary[$zip_name] = [];
148 else return false;
149
150 }
151
152 if ($cached_md5 != false) {
153 $zip_md5 = $cached_md5;
154 $md5_file_path = BMI_BACKUPS . DIRECTORY_SEPARATOR. $cached_md5 . '.json';
155 } else {
156 $zip_md5 = md5_file($zip_path);
157 $md5_file_path = BMI_BACKUPS . DIRECTORY_SEPARATOR. $zip_md5 . '.json';
158 if (!in_array($zip_md5, $md5summary[$zip_name])) {
159 $md5summary[$zip_name][] = $zip_md5;
160 }
161 }
162
163 $res = array();
164 if (file_exists($md5_file_path)) {
165 $manifest = json_decode(file_get_contents($md5_file_path));
166 } else {
167 $manifest = $zipper->getZipFileContent($zip_path, 'bmi_backup_manifest.json');
168 }
169
170 if ($manifest) {
171
172 $res[] = $manifest->name . '#%&' . $zip_name;
173 $res[] = $manifest->date;
174 $res[] = $manifest->files;
175 $res[] = $manifest->manifest;
176 $res[] = @filesize($zip_path);
177 if (!isset($manifest->is_locked)) {
178 $manifest->is_locked = $zipper->is_locked_zip($zip_path) ? 'locked' : 'unlocked';
179 $res[] = $manifest->is_locked;
180 } else {
181 $res[] = $manifest->is_locked;
182 }
183 $res[] = $manifest->cron;
184 $res[] = $zip_md5;
185 $res[] = sanitize_text_field($manifest->domain);
186
187 if (!file_exists($md5_file_path)) {
188 $manifest->abspath = $manifest->config->ABSPATH;
189 $manifest->table_prefix = $manifest->config->table_prefix;
190 unset($manifest->config);
191 file_put_contents($md5_file_path, json_encode($manifest));
192 } else touch($md5_file_path);
193
194 $cacheMd5String = "<?php exit; \$x = '" . serialize($md5summary) . "';";
195 file_put_contents($md5_file_summary_path, $cacheMd5String);
196
197 return $res;
198
199 } else return false;
200
201 }
202
203 public function getAvailableBackups($scope = "all") {
204
205 // Require Universal Zip Library
206 require_once BMI_INCLUDES . '/zipper/zipping.php';
207 $zipper = new Zipper();
208
209 // Scan for manifests
210 $manifests = array();
211 $backups = array();
212 $external = array();
213 $ongoing = get_option('bmip_to_be_uploaded', [
214 'current_upload' => [],
215 'queue' => [],
216 'failed' => []
217 ]);
218
219 if (file_exists(BMI_BACKUPS))
220 $backups = $this->scanBackupDir(BMI_BACKUPS);
221
222 // $start = time();
223 // $maxTime = ini_get('max_execution_time');
224 $uploadedBackupStatus = get_option('bmi_uploaded_backups_status', []);
225
226 for ($i = 0; $i < sizeof($backups); ++$i) {
227
228 // $filestart = time();
229
230 $backup = $backups[$i];
231 $path = $backup['path'] . '/' . $backup['filename'];
232 if ( file_exists( BMI_BACKUPS . '/.running' ) && !empty( glob( $path . '.?*' ) ) ) continue;
233 if (!file_exists($backup['path'])) continue;
234
235 $manifest = $this->getManifestFromZip($path, $zipper);
236 if ($manifest) {
237 $md5 = $manifest[7];
238 if (isset($uploadedBackupStatus[$md5])) {
239 $manifest[] = $uploadedBackupStatus[$md5];
240 } else {
241 $manifest[] = [];
242 }
243 $manifests[$backup['filename']] = $manifest;
244 }
245 else{
246 if (!file_exists(BMI_BACKUPS . '/.running')) @unlink($path); // Prevents deletion of running backups
247 }
248
249 // $fileend = $filestart - time();
250 // $totalTime = $start - time();
251
252 // if ($totalTime + $fileend > $maxTime) break;
253
254 }
255
256 if ($scope == "local") {
257 return [ 'local' => $manifests ];
258 }
259
260 require_once BMI_INCLUDES . '/external/controller.php';
261 $externalStorage = new ExternalStorage();
262 $external = $externalStorage->getExternalBackups();
263
264 $this->removeOldCache();
265
266 return [ 'local' => $manifests, 'external' => $external, 'ongoing' => $ongoing ];
267
268 }
269
270 }
271