PluginProbe ʕ •ᴥ•ʔ
Backup Migration / 2.1.6
Backup Migration v2.1.6
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 / backup-process.php
backup-backup / includes Last commit date
banner 3 weeks ago bodies 3 weeks ago check 3 weeks ago cli 3 weeks ago cron 3 weeks ago dashboard 3 weeks ago database 3 weeks ago external 3 weeks ago extracter 3 weeks ago htaccess 3 weeks ago notices 3 weeks ago progress 3 weeks ago scanner 3 weeks ago services 3 weeks ago staging 3 weeks ago traits 3 weeks ago uploader 3 weeks ago vendor 3 weeks ago zipper 3 weeks ago .htaccess 3 weeks ago activation.php 3 weeks ago ajax.php 3 weeks ago ajax_offline.php 3 weeks ago analyst.php 3 weeks ago backup-process.php 3 weeks ago class-backup-method-mananger.php 3 weeks ago cli-handler.php 3 weeks ago compatibility.php 3 weeks ago config.php 3 weeks ago constants.php 3 weeks ago file-explorer.php 3 weeks ago initializer.php 3 weeks ago logger.php 3 weeks ago offline.php 3 weeks ago
backup-process.php
1393 lines
1 <?php
2
3 // Namespace
4 namespace BMI\Plugin\Heart;
5
6 // Usage
7 use BMI\Plugin\BMI_Logger AS Logger;
8 use BMI\Plugin\Progress\BMI_ZipProgress_Logger AS Output;
9 use BMI\Plugin\Checker\System_Info as SI;
10 use BMI\Plugin\Dashboard as Dashboard;
11 use BMI\Plugin\Database\BMI_Database as Database;
12 use BMI\Plugin\Database\BMI_Database_Exporter as BetterDatabaseExport;
13 use BMI\Plugin\Backup_Migration_Plugin as BMP;
14 use BMI\Plugin\Database\Export\DatabaseExportProcessor;
15 use BMI\Plugin\BMI_Pro_Core as Pro_Core;
16 use BMI\Plugin AS BMI;
17
18 // Exit on direct access
19 if (!defined('ABSPATH')) exit;
20
21 // Fixes for some cases
22 require_once BMI_INCLUDES . '/compatibility.php';
23
24 /**
25 * Main class to handle heartbeat of the backup
26 */
27 class BMI_Backup_Heart {
28
29 public $it;
30 public $dbit;
31 public $abs;
32 public $dir;
33 public $url;
34 public $curl;
35 public $config;
36 public $content;
37 public $backups;
38 public $dblast;
39 public $output;
40 public $useragent;
41 public $remote_settings;
42
43 public $identy;
44 public $manifest;
45 public $backupname;
46 public $safelimit;
47 public $total_files;
48 public $rev;
49 public $backupstart;
50 public $filessofar;
51 public $identyfile;
52 public $browserSide;
53
54 public $identyFolder;
55 public $fileList;
56 public $dbfile;
57 public $db_dir_v2;
58 public $db_v2_engine;
59
60 public $final_made;
61 public $final_batch;
62 public $dbitJustFinished;
63 public $lock_cli;
64 public $startOfBatch;
65 public $errorSent = false;
66 public $statusSent = false;
67 public $backupSize = 0;
68 public $isStreamed = false;
69
70 public $_zip;
71 public $_lib;
72 public $batches_left;
73 public $res = [ 'status' => 'success', 'default' => true ];
74
75 // Prepare the request details
76 function __construct($curlIdenty = false, $config = false, $content = false, $backups = false, $abs = false, $dir = false, $remote_settings = []) {
77
78 if (!defined('BMI_CLI_REQUEST')) {
79 define('BMI_CLI_REQUEST', false);
80 }
81
82 $curl = false;
83 if ($curlIdenty != false) $curl = true;
84
85 $remote_settings = $this->getRemoteSettings($curlIdenty, $curl);
86 $this->remote_settings = $remote_settings;
87 if (sizeof($remote_settings) === 0) return;
88
89 $this->setupConstants();
90
91 $this->it = $remote_settings['it'];
92 $this->dbit = $remote_settings['dbit'];
93 $this->abs = $abs;
94 $this->dir = $dir;
95 $this->curl = $curl;
96 $this->config = $config;
97 $this->content = $content;
98 $this->backups = $backups;
99 $this->dblast = $remote_settings['dblast'];
100 $this->useragent = $remote_settings['useragent'];
101
102 $this->identy = $remote_settings['identy'];
103 $this->manifest = $remote_settings['manifest'];
104 $this->backupname = $remote_settings['backupname'];
105 $this->safelimit = intval($remote_settings['safelimit']);
106 $this->total_files = $remote_settings['total_files'];
107 $this->rev = intval($remote_settings['rev']);
108 $this->backupstart = $remote_settings['start'];
109 $this->filessofar = intval($remote_settings['filessofar']);
110 $this->identyfile = BMI_TMP . DIRECTORY_SEPARATOR . '.' . $this->identy;
111 $this->browserSide = (isset($remote_settings['browser']) && ($remote_settings['browser'] === true || $remote_settings['browser'] === 'true')) ? true : false;
112
113 if ($curl) {
114 // Here we could use nonces, but well, WordPress can't handle nonces in such scenario due to the way its generated
115 // We still use "nonce" here to bypass some security plugins as they may block the URL if the nonce string does not exist in such URL
116 $this->url = get_home_url(null, sprintf('/?backup-migration=CURL_BACKUP&bmi-id=%s&_wpnonce=%s&t=%s&sk=%s', $this->identy, 'Wn19dnWuq', time(), Dashboard\bmi_get_config('REQUEST:SECRET')));
117 } else {
118 $this->url = null;
119 }
120
121 $this->identyFolder = BMI_TMP . DIRECTORY_SEPARATOR . 'bg-' . $this->identy;
122 $this->fileList = BMI_TMP . DIRECTORY_SEPARATOR . 'files_latest.list';
123 $this->dbfile = BMI_TMP . DIRECTORY_SEPARATOR . 'bmi_database_backup.sql';
124 $this->db_dir_v2 = BMI_TMP . DIRECTORY_SEPARATOR . 'db_tables';
125 $this->db_v2_engine = false;
126
127 $this->final_made = $remote_settings['final_made'];
128 $this->final_batch = $remote_settings['final_batch'];
129 $this->dbitJustFinished = $remote_settings['dbitJustFinished'];
130 $this->backupSize = 0;
131 if (isset($remote_settings['backupSize']))
132 $this->backupSize = $remote_settings['backupSize'];
133
134 if (isset($remote_settings['is_streamed']))
135 $this->isStreamed = $remote_settings['is_streamed'];
136
137 $this->startOfBatch = time();
138 if (isset($remote_settings['startOfBatch']))
139 $this->startOfBatch = $remote_settings['startOfBatch'];
140
141 $this->lock_cli = BMI_BACKUPS . '/.backup_cli_lock';
142 if ($this->it > 1) @touch($this->lock_cli);
143
144 if ($this->isFunctionEnabled('ini_set') && $this->isFunctionEnabled('session_status') && session_status() != PHP_SESSION_ACTIVE) {
145 ini_set('display_errors', 1);
146 ini_set('error_reporting', E_ALL);
147 ini_set('log_errors', 1);
148 ini_set('error_log', BMI_CONFIG_DIR . '/background-errors.' . BMI_LOGS_SUFFIX . '.log');
149 }
150
151 }
152
153 // Get "remote_settings" from file created by the server
154 public function getRemoteSettings($curlIdenty, $curl = false) : array {
155 $settings_name = 'currentBackupConfig.' . 'php';
156 $settings_path = BMP::fixSlashes(BMI_TMP . DIRECTORY_SEPARATOR . $settings_name);
157
158 if (!file_exists($settings_path) && $curl) {
159 Logger::error('Settings path does not exist for backup-process.php');
160 return [];
161 }
162
163 if (!file_exists($settings_path)) {
164 Logger::error('Config file does not exist, please try to run the backup process once again.');
165 return $this->send_error('Config file does not exist, please try to run the backup process once again.', true);
166 }
167
168 $remote_settings = file_get_contents($settings_path);
169 $remote_settings = (array) json_decode(substr($remote_settings, 8));
170
171 if (!isset($remote_settings['identy'])) {
172 Logger::error('Identy is not set in the config, which prevents backup-process.php from running.');
173 return [];
174 }
175
176 if ($curl && $curlIdenty != $remote_settings['identy']) {
177 Logger::error('backup-process.php runs via CURL but the identy provided by CURL does not match config.');
178 return [];
179 }
180
181 return $remote_settings;
182 }
183
184 // Save remote setting for next batch
185 public function saveRemoteSettings() {
186 $settings_name = 'currentBackupConfig.' . 'php';
187 $settings_path = BMP::fixSlashes(BMI_TMP . DIRECTORY_SEPARATOR . $settings_name);
188
189 $this->remote_settings['identy'] = $this->identy;
190 $this->remote_settings['manifest'] = $this->manifest;
191 $this->remote_settings['backupname'] = $this->backupname;
192 $this->remote_settings['safelimit'] = $this->safelimit;
193 $this->remote_settings['total_files'] = $this->total_files;
194 $this->remote_settings['rev'] = $this->rev;
195 $this->remote_settings['start'] = $this->backupstart;
196 $this->remote_settings['filessofar'] = $this->filessofar;
197 $this->remote_settings['browser'] = $this->browserSide;
198 $this->remote_settings['it'] = $this->it;
199 $this->remote_settings['dbit'] = $this->dbit;
200 $this->remote_settings['dblast'] = $this->dblast;
201 $this->remote_settings['final_made'] = $this->final_made;
202 $this->remote_settings['final_batch'] = $this->final_batch;
203 $this->remote_settings['dbitJustFinished'] = $this->dbitJustFinished;
204 $this->remote_settings['startOfBatch'] = $this->startOfBatch;
205 $this->remote_settings['backupSize'] = $this->backupSize;
206 $this->remote_settings['is_streamed'] = $this->isStreamed;
207
208 if (file_exists($settings_path)) @unlink($settings_path);
209 file_put_contents($settings_path, '<?php //' . json_encode($this->remote_settings));
210 }
211
212 // Setup constants and handle request
213 public function setupConstants() {
214
215 if (!defined('BMI_CURL_REQUEST')) define('BMI_CURL_REQUEST', true);
216 if (!defined('BMI_CLI_REQUEST')) define('BMI_CLI_REQUEST', false);
217 if (!defined('BMI_SAFELIMIT')) define('BMI_SAFELIMIT', intval($this->remote_settings['safelimit']));
218
219 if ($this->isFunctionEnabled('ignore_user_abort')) @ignore_user_abort(true);
220 if ($this->isFunctionEnabled('set_time_limit')) @set_time_limit(259200);
221 if ($this->isFunctionEnabled('ini_set') && $this->isFunctionEnabled('session_status') && session_status() != PHP_SESSION_ACTIVE) {
222 @ini_set('max_input_time', '259200');
223 @ini_set('max_execution_time', '259200');
224 }
225
226 if (!isset($this->remote_settings['browser'])) $this->remote_settings['browser'] = false;
227
228 // Don't block server handler
229 // if ($this->isFunctionEnabled('session_write_close')) @session_write_close();
230
231 }
232
233 // Make sure it's impossible to unlink some files
234 public function unlinksafe($path) {
235
236 if (substr($path, 0, 7) == 'file://') {
237 $path = substr($path, 7);
238 }
239
240 $path = realpath($path);
241 if ($path === false) return;
242 if (strpos($path, 'wp-config.php') !== false) return;
243 if (substr($path, -8) == '/backups') return;
244
245 @unlink('file://' . $path);
246
247 }
248
249 // Human size from bytes
250 public static function humanSize($bytes) {
251 if (is_int($bytes)) {
252 $label = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
253 for ($i = 0; $bytes >= 1024 && $i < (count($label) - 1); $bytes /= 1024, $i++);
254
255 return (round($bytes, 2) . " " . $label[$i]);
256 } else return $bytes;
257 }
258
259 // Create new process
260 public function send_beat($manual = false, &$logger = null) {
261
262 $globalLockFile = BMI_TMP . DIRECTORY_SEPARATOR . '.beat_lock_' . $this->identy;
263 $maxLockAge = 10;
264
265 if (is_null($logger)) $this->load_logger();
266 else if ($logger instanceof Output) $this->output = $logger;
267
268 if (file_exists($globalLockFile)) {
269 $lockAge = time() - filemtime($globalLockFile);
270 if ($lockAge < $maxLockAge) {
271 sleep($maxLockAge - $lockAge + 1);
272 @unlink($globalLockFile);
273 } else {
274 @unlink($globalLockFile);
275 }
276 }
277
278 $fp = fopen($globalLockFile, 'c');
279 if (!$fp) {
280 $this->output->log('Could not open lock file for writing, skipping this beat.', 'WARN');
281 return;
282 }
283 if (!flock($fp, LOCK_EX | LOCK_NB)) {
284 $this->output->log('Another process is already running, skipping this beat.', 'WARN');
285 fclose($fp);
286 return;
287 }
288
289 try {
290
291 $header = array(
292 'Content-Accept:*/*',
293 'Access-Control-Allow-Origin:*'
294 );
295
296 $this->saveRemoteSettings();
297 $c = curl_init();
298 curl_setopt($c, CURLOPT_POST, 1);
299 curl_setopt($c, CURLOPT_COOKIESESSION, false);
300 curl_setopt($c, CURLOPT_TIMEOUT, 20);
301 curl_setopt($c, CURLOPT_VERBOSE, false);
302 curl_setopt($c, CURLOPT_HEADER, false);
303 curl_setopt($c, CURLOPT_URL, $this->url);
304 curl_setopt($c, CURLOPT_FOLLOWLOCATION, 1);
305 curl_setopt($c, CURLOPT_MAXREDIRS, 10);
306 curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
307 curl_setopt($c, CURLOPT_SSL_VERIFYHOST, 0);
308 curl_setopt($c, CURLOPT_SSL_VERIFYPEER, 0);
309 curl_setopt($c, CURLOPT_HTTPHEADER, $header);
310 curl_setopt($c, CURLOPT_CUSTOMREQUEST, 'POST');
311 curl_setopt($c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
312 curl_setopt($c, CURLOPT_USERAGENT, $this->useragent);
313
314 $r = curl_exec($c);
315
316 $statusCode = curl_getinfo($c, CURLINFO_HTTP_CODE);
317 if ($statusCode > 299) {
318 Logger::error(print_r(curl_getinfo($c), true));
319 $this->output->log('Response: ' . $r, 'ERROR');
320 $this->send_error('There was something wrong with the request, the response code was: ' . $statusCode, true);
321 }
322
323 if ($manual === true && $logger !== null) {
324 if ($r === false) {
325 if (intval(curl_errno($c)) === CURLE_OPERATION_TIMEDOUT || $statusCode === 429) {
326 Logger::error(print_r(curl_getinfo($c), true));
327 Logger::error(curl_errno($c) . ': ' . curl_error($c));
328 $this->output->log('There was something wrong with the request:', 'WARN');
329 $this->output->log(curl_errno($c) . ': ' . curl_error($c), 'WARN');
330 }
331 } else {
332 $this->output->log('Request sent successfully, without error returned.', 'SUCCESS');
333 }
334 }
335
336 if (is_resource($c)) {
337 curl_close($c);
338 }
339 if (isset($this->output)) $this->output->end();
340
341 } catch (\Exception $e) {
342
343 error_log($e->getMessage());
344 $this->output->log($e->getMessage(), 'ERROR');
345 if (isset($this->output)) $this->output->end();
346
347 } catch (\Throwable $e) {
348
349 error_log($e->getMessage());
350 $this->output->log($e->getMessage(), 'ERROR');
351 if (isset($this->output)) $this->output->end();
352
353 } finally {
354 flock($fp, LOCK_UN);
355 fclose($fp);
356 @unlink($globalLockFile);
357 }
358
359 }
360
361 // Load backup logger
362 public function load_logger() {
363
364 if ($this->output instanceof Output) return;
365
366 require_once BMI_INCLUDES . '/logger.php';
367 require_once BMI_INCLUDES . '/progress/logger-only.php';
368
369 $this->output = new Output();
370 $this->output->start();
371
372 }
373
374 // Remove common files
375 public function remove_commons() {
376
377 if (is_null($this->fileList)) return;
378
379 // Remove list if exists
380 $identyfile = $this->identyfile;
381 $logfile = BMI_TMP . DIRECTORY_SEPARATOR . 'bmi_logs_this_backup.log';
382 $clidata = BMI_TMP . DIRECTORY_SEPARATOR . 'bmi_cli_data.json';
383 $settings_path = BMI_TMP . DIRECTORY_SEPARATOR . 'currentBackupConfig.php';
384 if (file_exists($this->fileList)) $this->unlinksafe($this->fileList);
385 if (file_exists($this->dbfile)) $this->unlinksafe($this->dbfile);
386 if (file_exists($this->manifest)) $this->unlinksafe($this->manifest);
387 if (file_exists($logfile)) $this->unlinksafe($logfile);
388 if (file_exists($clidata)) $this->unlinksafe($clidata);
389 if (file_exists($identyfile)) $this->unlinksafe($identyfile);
390 if (file_exists($identyfile . '-running')) $this->unlinksafe($identyfile . '-running');
391 if (file_exists($this->lock_cli)) $this->unlinksafe($this->lock_cli);
392 if (file_exists($settings_path)) $this->unlinksafe($settings_path);
393
394 // Remove backup
395 if (file_exists(BMI_BACKUPS . '/.running')) $this->unlinksafe(BMI_BACKUPS . '/.running');
396 if (file_exists(BMI_BACKUPS . '/.space_check')) $this->unlinksafe(BMI_BACKUPS . '/.space_check');
397 if (file_exists(BMI_BACKUPS . '/.abort')) $this->unlinksafe(BMI_BACKUPS . '/.abort');
398 if (file_exists(BMI_BACKUPS . '/.last_triggered')) $this->unlinksafe(BMI_BACKUPS . '/.last_triggered');
399
400 // Remove group folder
401 if (file_exists($this->identyFolder)) {
402 $files = glob($this->identyFolder . '/*');
403 foreach ($files as $file) if (is_file($file)) $this->unlinksafe($file);
404 @rmdir($this->identyFolder);
405 }
406
407 // Remove tmp database files
408 if (file_exists($this->db_dir_v2) && is_dir($this->db_dir_v2)) {
409 $files = glob($this->db_dir_v2 . '/*');
410 foreach ($files as $file) if (is_file($file)) $this->unlinksafe($file);
411 if (is_dir($this->db_dir_v2)) @rmdir($this->db_dir_v2);
412 }
413
414 }
415
416 // Make success
417 public function send_success() {
418
419 $this->load_logger();
420
421 // Display the success
422 $this->output->log('Backup completed successfully!', 'SUCCESS');
423 $this->output->log('#001', 'END-CODE');
424
425 // Remove common files
426 $this->remove_commons();
427
428 // End logger
429 if (isset($this->output)) @$this->output->end();
430
431 $this->actionsAfterProcess(true);
432 $this->it += 1;
433
434 // Set header for browser
435 if ($this->browserSide) {
436
437 // Content finished
438 $this->sendResponse(true);
439
440 }
441
442 // End the process
443 exit;
444
445 }
446
447 // Make error
448 public function send_error($reason = false, $abort = false, $customEndCode = false) {
449
450 if ($this->errorSent) return;
451 $this->errorSent = true;
452
453 $this->load_logger();
454
455 // Log error
456 $this->output->log('Something went wrong with background process... ' . '(part: ' . $this->it . ')', 'ERROR');
457 if ($reason !== false) $this->output->log('Reason: ' . $reason, 'ERROR');
458 $this->output->log('Removing backup files... ', 'ERROR');
459
460 // Remove common files
461 $this->remove_commons();
462
463 // Remove backup
464 if (file_exists(BMI_BACKUPS . DIRECTORY_SEPARATOR . $this->backupname)) $this->unlinksafe(BMI_BACKUPS . DIRECTORY_SEPARATOR . $this->backupname);
465
466 // Abort step
467 $this->output->log('Aborting backup... ', 'STEP');
468 if ($customEndCode !== false) $this->output->log($customEndCode, 'END-CODE');
469 else if ($abort === false) $this->output->log('#002', 'END-CODE');
470 else $this->output->log('#004', 'END-CODE');
471 if (isset($this->output)) @$this->output->end();
472
473 $this->actionsAfterProcess();
474 $this->it += 1;
475
476 // Set header for browser
477 if ($this->browserSide) {
478
479 // Content finished
480 $this->sendResponse(false, true);
481
482 }
483 exit;
484
485 }
486
487 // Group files for batches
488 public function make_file_groups() {
489
490 if (!(file_exists($this->fileList) && is_readable($this->fileList))) {
491 return $this->send_error('File list is not accessible or does not exist, try to run your backup process once again.', true);
492 }
493
494 $this->output->log('Making batches for each process...', 'STEP');
495 $list_path = $this->fileList;
496
497 $file = fopen($list_path, 'r');
498 $this->output->log('Reading list file...', 'INFO');
499 $first_line = explode('_', fgets($file));
500 $files = intval($first_line[0]);
501 $firstmax = intval($first_line[1]);
502
503 if ($files > 0) {
504 $batches = 100;
505 if ($files <= 200) $batches = 100;
506 if ($files > 200) $batches = 400;
507 if ($files > 1600) $batches = 600;
508 if ($files > 3200) $batches = 1000;
509 if ($files > 6400) $batches = 2000;
510 if ($files > 12800) $batches = 4000;
511 if ($files > 25600) $batches = 5000;
512 if ($files > 30500) $batches = 10000;
513 if ($files > 60500) $batches = 20000;
514 if ($files > 90500) $batches = 40000;
515 if ($files > 100000) $batches = 60000;
516 if ($files > 150000) $batches = 80000;
517
518 $this->output->log('Each batch will contain up to ' . $batches . ' files.', 'INFO');
519 $this->output->log('Large files takes more time, you will be notified about those.', 'INFO');
520
521 $folder = $this->identyFolder;
522 if (!(file_exists($folder) && is_dir($file))) {
523 @mkdir($folder, 0755, true);
524 }
525
526 $limitcrl = 96;
527 if (BMI_CLI_REQUEST === true) {
528 $limitcrl = 512;
529 if ($files > 30000) $limitcrl = 1024;
530 }
531
532 $i = 0; $bigs = 0; $prev = 0; $currsize = 0;
533 while (($line = fgets($file)) !== false) {
534
535 $line = explode(',', $line);
536 $last = sizeof($line) - 1;
537 $size = intval($line[$last]);
538 unset($line[$last]);
539 $line = implode(',', $line);
540
541 $i++;
542 if ($firstmax != -1 && $i > $firstmax) $bigs++;
543 $suffix = intval(ceil(abs($i / $batches))) + $bigs;
544
545 if ($prev == $suffix) {
546 $currsize += $size;
547 } else {
548 $currsize = $size;
549 $prev = $suffix;
550 }
551
552 $skip = false;
553 if ($currsize > ($limitcrl * (1024 * 1024))) $skip = true;
554
555 $groupFile = $folder . DIRECTORY_SEPARATOR . $this->identy . '-' . $suffix . '.files';
556 $group = fopen($groupFile, 'a');
557 fwrite($group, $line . ',' . $size . "\r\n");
558 fclose($group);
559
560 if ($skip === true) $bigs++;
561 unset($line);
562
563 }
564
565 fclose($file);
566 if (file_exists($this->fileList)) $this->unlinksafe($this->fileList);
567
568 } else {
569
570 $this->output->log('No file found to be backed up, omitting files.', 'INFO');
571
572 }
573
574 if (file_exists($this->fileList)) $this->unlinksafe($this->fileList);
575 $this->output->log('Batches completed...', 'SUCCESS');
576
577 }
578
579 // Final batch
580 public function get_final_batch() {
581
582 $db_root_dir = BMI_TMP . DIRECTORY_SEPARATOR;
583 $logs = $db_root_dir . 'bmi_logs_this_backup.log';
584 $_manifest = $this->manifest;
585
586 if (strpos($logs, 'file://') !== false) $logs = substr($logs, 7);
587 if (strpos($_manifest, 'file://') !== false) $_manifest = substr($_manifest, 7);
588
589 $log_file = fopen($logs, 'w');
590 fwrite($log_file, file_get_contents(BMI_BACKUPS . DIRECTORY_SEPARATOR . 'latest.' . BMI_LOGS_SUFFIX . '.log'));
591 fclose($log_file);
592 $files = [$logs, $_manifest];
593
594 return $files;
595
596 }
597
598 // Final logs
599 public function log_final_batch() {
600
601 $this->output->log('Finalizing backup', 'STEP');
602 $this->output->log('Closing files and archives', 'STEP');
603 $this->output->log('Archiving of ' . $this->total_files . ' files took: ' . number_format(microtime(true) - floatval($this->backupstart), 2) . 's', 'INFO');
604
605 if (!BMI_CLI_REQUEST) {
606 if (!$this->browserSide) sleep(1);
607 }
608
609 if (file_exists(BMI_BACKUPS . '/.abort')) {
610 $this->send_error('Backup aborted manually by user.', true, '#003');
611 return;
612 }
613
614 $this->send_success();
615
616 }
617
618 // Load batch
619 public function load_batch() {
620
621 if (!(file_exists($this->identyFolder) && is_dir($this->identyFolder))) {
622 return $this->send_error('Temporary directory does not exist, please start the backup once again.', true);
623 }
624
625 $allFiles = scandir($this->identyFolder);
626 $files = array_slice((array) $allFiles, 2);
627 if (sizeof($files) > 0) {
628
629 $largest = $files[0]; $prev_size = 0;
630 for ($i = 0; $i < sizeof($files); ++$i) {
631 $curr_size = filesize($this->identyFolder . DIRECTORY_SEPARATOR . $files[$i]);
632 if ($curr_size > $prev_size) {
633 $largest = $files[$i];
634 $prev_size = $curr_size;
635 }
636 }
637 $this->batches_left = sizeof($files);
638
639 if (sizeof($files) == 1) {
640 $this->final_batch = true;
641 }
642
643 return $this->identyFolder . DIRECTORY_SEPARATOR . $largest;
644
645 } else {
646
647 $this->log_final_batch();
648 return false;
649
650 }
651
652 }
653
654 // Cut Path for ZIP structure
655 public function cutDir($file) {
656
657 if (substr($file, -4) === '.sql') {
658
659 if ($this->db_v2_engine == true) {
660
661 $path = 'db_tables' . DIRECTORY_SEPARATOR . basename($file);
662
663 } else {
664
665 $path = basename($file);
666
667 }
668
669 } else {
670
671 $path = basename($file);
672
673 }
674
675 $path = str_replace('\\', '/', $path);
676 return $path;
677
678 }
679
680 // Add files to ZIP – The Backup
681 public function add_files($files = [], $file_list = false, $final = false, $dbLog = false) {
682
683 try {
684
685 $zipArchive = false;
686 if (class_exists('\ZipArchive') || class_exists('ZipArchive')) {
687 if (!isset($this->_zip)) {
688 $this->_zip = new \ZipArchive();
689 }
690
691 if ($this->_zip) {
692 $zipArchive = true;
693 } else {
694 $zipArchive = false;
695 }
696 }
697
698 // Check if PclZip exists
699 if ($zipArchive === false) {
700 if (!class_exists('PclZip')) {
701 if (!defined('PCLZIP_TEMPORARY_DIR')) {
702 $bmi_tmp_dir = BMI_TMP;
703 if (!file_exists($bmi_tmp_dir)) {
704 @mkdir($bmi_tmp_dir, 0775, true);
705 }
706
707 define('PCLZIP_TEMPORARY_DIR', $bmi_tmp_dir . DIRECTORY_SEPARATOR . 'bmi-');
708 }
709
710 if (!defined('PCLZIP_READ_BLOCK_SIZE')) {
711 define('PCLZIP_READ_BLOCK_SIZE', 32768);
712 }
713 }
714
715 // Require the LIB and check if it's compatible
716 $alternative = dirname($this->dir) . '/backup-backup-pro/includes/pcl.php';
717 if ($this->rev === 2 || !file_exists($alternative)) {
718 require_once ABSPATH . 'wp-admin/includes/class-pclzip.php';
719 } else {
720 require_once $alternative;
721 if ($this->it === 1) {
722 $this->output->log('Using dedicated PclZIP for Premium Users.', 'INFO');
723 if ($dbLog == true) {
724 $this->output->log('Adding database SQL file(s) to the backup file.', 'STEP');
725 }
726 }
727 }
728
729 // Get/Create the Archive
730 if (!isset($this->_lib)) {
731 $this->_lib = new \PclZip(BMI_BACKUPS . DIRECTORY_SEPARATOR . $this->backupname);
732 }
733
734 if (!$this->_lib) {
735 $this->send_error('PHP-ZIP: Permission Denied or zlib cannot be found');
736 return;
737 }
738
739 } else {
740
741 $backupPath = BMI_BACKUPS . DIRECTORY_SEPARATOR . $this->backupname;
742 if (BMI_CLI_REQUEST) {
743 if (!isset($this->zip_initialized)) {
744 if (file_exists($backupPath)) $this->_zip->open($backupPath);
745 else $this->_zip->open($backupPath, \ZipArchive::CREATE);
746 }
747 } else {
748 if (file_exists($backupPath)) $this->_zip->open($backupPath);
749 else $this->_zip->open($backupPath, \ZipArchive::CREATE);
750 }
751
752 if ($this->it === 1) {
753 $this->output->log('Using ZipArchive extension for this backup process.', 'INFO');
754 if ($dbLog == true) {
755 $this->output->log('Adding database SQL file(s) to the backup file.', 'STEP');
756 }
757 }
758
759 }
760
761 if (sizeof($files) <= 0) {
762 return false;
763 }
764
765 $back = 0;
766 $files = array_filter($files, function ($path) {
767 if (is_readable($path) && file_exists($path) && !is_link($path)) return true;
768 else {
769 $this->output->log("Excluding file that cannot be read: " . $path, 'warn');
770 return false;
771 }
772 });
773
774 $_abspath = ABSPATH;
775 $_bmi_tmp = BMI_TMP;
776 $_wp_content = WP_CONTENT_DIR;
777 if (strpos($_abspath, 'file://') !== false) $_abspath = substr($_abspath, 7);
778 if (strpos($_bmi_tmp, 'file://') !== false) $_bmi_tmp = substr($_bmi_tmp, 7);
779 if (strpos($_wp_content, 'file://') !== false) $_wp_content = substr($_wp_content, 7);
780
781 $needManipulation = false;
782 if ( strpos($_wp_content, $_abspath) === false ) {
783 $needManipulation = true;
784 }
785
786 // Add files
787 if ($final || $dbLog) {
788
789 if ($zipArchive) {
790 for ($i = 0; $i < sizeof($files); ++$i) {
791
792 // Add the file
793 if (is_dir($files[$i])) {
794 $this->_zip->addEmptyDir($this->cutDir($files[$i]));
795 } else {
796 $this->_zip->addFile($files[$i], $this->cutDir($files[$i]));
797 }
798
799 }
800 } else {
801
802 // Final configuration
803 if (sizeof($files) > 0) {
804 $back = $this->_lib->add($files, PCLZIP_OPT_REMOVE_PATH, $_bmi_tmp . DIRECTORY_SEPARATOR, PCLZIP_OPT_ADD_TEMP_FILE_ON, PCLZIP_OPT_TEMP_FILE_THRESHOLD, $this->safelimit);
805 }
806
807 }
808
809 if ($dbLog === false) {
810 $this->final_made = true;
811 }
812
813 } else {
814
815 if ($zipArchive) {
816
817 for ($i = 0; $i < sizeof($files); ++$i) {
818
819 if ($needManipulation) {
820 if (strpos($files[$i], $_wp_content) !== false) {
821 $path = 'wordpress' . DIRECTORY_SEPARATOR . 'wp-content' . DIRECTORY_SEPARATOR . substr($files[$i], strlen($_wp_content));
822 } else {
823 $path = 'wordpress' . DIRECTORY_SEPARATOR . substr($files[$i], strlen($_abspath));
824 }
825 } else {
826 $path = 'wordpress' . DIRECTORY_SEPARATOR . substr($files[$i], strlen($_abspath));
827 }
828
829 $path = BMP::fixSlashes($path);
830
831 // Add the file
832 if (is_dir($files[$i])) {
833 $this->_zip->addEmptyDir($path);
834 } else {
835 $this->_zip->addFile($files[$i], $path);
836 }
837
838 }
839
840 } else {
841
842 if ($needManipulation) {
843 $coreFiles = [];
844 $contentFiles = [];
845 foreach ($files as $file) {
846 if (strpos($file, $_wp_content) !== false) {
847 $contentFiles[] = $file;
848 } else {
849 $coreFiles[] = $file;
850 }
851 }
852
853 $back_1 = $this->_lib->add($coreFiles, PCLZIP_OPT_REMOVE_PATH, $_abspath, PCLZIP_OPT_ADD_PATH, 'wordpress' . DIRECTORY_SEPARATOR, PCLZIP_OPT_ADD_TEMP_FILE_ON, PCLZIP_OPT_TEMP_FILE_THRESHOLD, $this->safelimit);
854 $back_2 = $this->_lib->add($contentFiles, PCLZIP_OPT_REMOVE_PATH, $_wp_content, PCLZIP_OPT_ADD_PATH, 'wordpress' . DIRECTORY_SEPARATOR . 'wp-content' . DIRECTORY_SEPARATOR, PCLZIP_OPT_ADD_TEMP_FILE_ON, PCLZIP_OPT_TEMP_FILE_THRESHOLD, $this->safelimit);
855 $back = $back_1 && $back_2;
856
857 } else {
858 $back = $this->_lib->add($files, PCLZIP_OPT_REMOVE_PATH, $_abspath, PCLZIP_OPT_ADD_PATH, 'wordpress' . DIRECTORY_SEPARATOR, PCLZIP_OPT_ADD_TEMP_FILE_ON, PCLZIP_OPT_TEMP_FILE_THRESHOLD, $this->safelimit);
859 }
860
861 }
862
863 }
864
865 // Check if there was any error
866 touch(BMI_BACKUPS . '/.running');
867 if ($zipArchive) {
868 if (!BMI_CLI_REQUEST || $final) {
869 $result = $this->_zip->close();
870
871 if ($result === true) {
872
873 // Remove batch
874 if ($file_list && file_exists($file_list)) {
875 $this->unlinksafe($file_list);
876 }
877
878 } else {
879 $this->output->log('not_enough_space', 'verbose');
880
881 $this->send_error('Error, there is most likely not enough space for the backup.');
882 return false;
883
884 }
885 } else {
886
887 // Remove batch
888 if ($file_list && file_exists($file_list)) {
889 $this->unlinksafe($file_list);
890 }
891
892 }
893 } else {
894
895 if ($back == 0) {
896
897 $this->send_error($this->_lib->errorInfo(true));
898 return false;
899
900 } else {
901
902 if ($file_list && file_exists($file_list)) {
903 $this->unlinksafe($file_list);
904 }
905
906 }
907
908 }
909
910 } catch (\Exception $e) {
911
912 error_log($e->getMessage());
913 $this->send_error($e->getMessage());
914 return false;
915
916 } catch (\Throwable $e) {
917
918 error_log($e->getMessage());
919 $this->send_error($e->getMessage());
920 return false;
921
922 }
923
924 }
925
926 // ZIP one of the grouped files
927 public function zip_batch() {
928
929 $_dbfile = $this->dbfile;
930 $_db_dir_v2 = $this->db_dir_v2;
931 if (strpos($_dbfile, 'file://') !== false) $_dbfile = substr($_dbfile, 7);
932 if (strpos($_db_dir_v2, 'file://') !== false) $_db_dir_v2 = substr($_db_dir_v2, 7);
933
934 if ($this->it === 1) {
935
936 $files = [];
937 if (file_exists($this->dbfile)) {
938 $files[] = $_dbfile;
939 } elseif (file_exists($this->db_dir_v2) && is_dir($this->db_dir_v2)) {
940 $this->db_v2_engine = true;
941 $db_files = scandir($this->db_dir_v2);
942 foreach ($db_files as $i => $name) {
943 if (!($name == '.' || $name == '..')) {
944 $files[] = $_db_dir_v2 . DIRECTORY_SEPARATOR . $name;
945 }
946 }
947 }
948
949 if (sizeof($files) > 0) {
950 $this->add_files($files, false, false, true);
951 $this->output->log('Database added to the backup file.', 'SUCCESS');
952 $this->output->log('Performing site files backup...', 'STEP');
953 return true;
954 }
955
956 $this->output->log('Performing site files backup...', 'STEP');
957
958 }
959
960 $list_file = $this->load_batch();
961 if ($list_file === false) return true;
962 $files = explode("\r\n", file_get_contents($list_file));
963
964 $total_size = 0;
965 $parsed_files = [];
966
967 $absWo = ABSPATH;
968 $wpcDirWo = WP_CONTENT_DIR;
969
970 if (strpos($absWo, 'file://') !== false) $absWo = substr(ABSPATH, 7);
971 if (strpos($wpcDirWo, 'file://') !== false) $wpcDirWo = substr(WP_CONTENT_DIR, 7);
972
973 for ($i = 0; $i < sizeof($files); ++$i) {
974 if (strlen(trim($files[$i])) <= 1) {
975 $this->total_files--;
976 continue;
977 }
978
979 $files[$i] = explode(',', $files[$i]);
980 $last = sizeof($files[$i]) - 1;
981 $size = intval($files[$i][$last]);
982 unset($files[$i][$last]);
983 $files[$i] = implode(',', $files[$i]);
984
985 $file = null;
986 if ($files[$i][0] . $files[$i][1] . $files[$i][2] === '@1@') {
987 $file = $wpcDirWo . DIRECTORY_SEPARATOR . substr($files[$i], 3);
988 } else if ($files[$i][0] . $files[$i][1] . $files[$i][2] === '@2@') {
989 $file = $absWo . DIRECTORY_SEPARATOR . substr($files[$i], 3);
990 } else {
991 $file = $files[$i];
992 }
993
994 if (!file_exists($file)) {
995 $this->output->log('Removing this file from backup (it does not exist anymore): ' . $file, 'WARN');
996 $this->total_files--;
997 continue;
998 }
999
1000 // if (filesize($file) === 0) {
1001 // $this->output->log('Removing this file from backup (file size is equal to 0 bytes): ' . $file, 'WARN');
1002 // $this->total_files--;
1003 // continue;
1004 // }
1005
1006 $parsed_files[] = $file;
1007 $total_size += $size;
1008 unset($file);
1009 }
1010
1011 unset($files);
1012 if (sizeof($parsed_files) === 1) {
1013 $this->output->log('Adding: ' . sizeof($parsed_files) . ' file...' . ' [Size: ' . $this->humanSize($total_size) . ']', 'INFO');
1014 $this->output->log('Alone-file mode for: ' . $parsed_files[0] . ' file...', 'INFO');
1015 } else $this->output->log('Adding: ' . sizeof($parsed_files) . ' files...' . ' [Size: ' . $this->humanSize($total_size) . ']', 'INFO');
1016
1017 if ((60 * (1024 * 1024)) < $total_size) $this->output->log('Current batch is quite large, it may take some time...', 'WARN');
1018
1019 $this->add_files($parsed_files, $list_file);
1020 $this->filessofar += sizeof($parsed_files);
1021
1022 $currentBackupSize = filesize(BMI_BACKUPS . DIRECTORY_SEPARATOR . $this->backupname);
1023 $this->output->progress($this->filessofar . '/' . $this->total_files);
1024 $this->output->log('Milestone: ' . $this->filessofar . '/' . $this->total_files . ' [' . $this->batches_left . ' batches left]', 'SUCCESS');
1025 $this->output->log('Backup file size: ' . $this->humanSize($currentBackupSize), 'VERBOSE');
1026 $this->output->log('Time since last batch: ' . (time() - $this->startOfBatch) . ' seconds.', 'VERBOSE');
1027 $this->startOfBatch = time();
1028
1029 if ($this->backupSize > $currentBackupSize)
1030 return $this->send_error('Backup size is smaller than it should be, it has been damaged, it may not be restorable, abort recommended.', true);
1031
1032 $this->backupSize = $currentBackupSize;
1033
1034 if ($this->final_batch === true) {
1035 $this->output->log('Adding final files to this batch...', 'STEP');
1036 $this->output->log('Adding manifest as addition...', 'INFO');
1037
1038 $additionalFiles = $this->get_final_batch();
1039 $this->add_files($additionalFiles, false, true);
1040 $this->log_final_batch();
1041 return true;
1042 }
1043
1044 }
1045
1046 // Shutdown callback
1047 public function shutdown() {
1048
1049 // Check if there was any error
1050 $err = error_get_last();
1051 if ($err != null) {
1052 Logger::error('Shuted down');
1053 Logger::error(print_r($err, true));
1054 $this->output->log('Background process had some issues, more details printed to global logs.', 'WARN');
1055 }
1056
1057 // Remove lock
1058 if (BMI_CLI_REQUEST && $this->lock_cli && file_exists($this->lock_cli)) {
1059 $this->unlinksafe($this->lock_cli);
1060 }
1061
1062 // Send next beat to handle next batch
1063 if (BMI_CLI_REQUEST) {
1064 $this->res = [ 'status' => 'success' ];
1065 return true;
1066 }
1067
1068 if (file_exists($this->identyfile)) {
1069
1070 // Set header for browser
1071 if ($this->browserSide) {
1072
1073 $this->saveRemoteSettings();
1074
1075 // Content finished
1076 $this->sendResponse(false);
1077
1078 } else {
1079
1080 $this->send_beat();
1081
1082 }
1083
1084 } else {
1085 if (!$this->statusSent && !isset($GLOBALS['BMI::RESPONSE::SENT'])) {
1086 $this->statusSent = true;
1087 return BMP::res([ 'status' => 'success' ]);
1088 }
1089 }
1090
1091 }
1092
1093 public function sendResponse($finish = false, $error = false) {
1094 $res = [
1095 'status' => 'success',
1096 'backup_completed' => (($finish == true) ? 'true' : 'false'),
1097 'backup_process_error' => (($error == true) ? 'true' : 'false')
1098 ];
1099
1100 if ($error == true)
1101 $res['status'] = 'error';
1102
1103 $this->res = $res;
1104
1105 if (!$this->statusSent && !isset($GLOBALS['BMI::RESPONSE::SENT'])) {
1106 $this->statusSent = true;
1107 BMP::res($res);
1108 }
1109
1110 return $res;
1111 }
1112
1113 // Handle received batch
1114 public function handle_batch() {
1115
1116 // Check if aborted
1117 if (file_exists(BMI_BACKUPS . '/.abort')) {
1118 if (!isset($this->output)) $this->load_logger();
1119 $this->res = [ 'status' => 'error' ];
1120 $this->send_error('Backup aborted manually by user.', true, '#003');
1121 return;
1122 }
1123
1124 // Check if it was triggered by verified user
1125 if (!file_exists($this->identyfile)) {
1126 $this->res = [ 'status' => 'error' ];
1127 return;
1128 }
1129
1130 // Register shutdown
1131 register_shutdown_function([$this, 'shutdown']);
1132
1133 // Load logger
1134 $this->load_logger();
1135
1136 set_error_handler(function ($errno, $errstr, $errfile, $errline) {
1137 Logger::error('Bypasser error:');
1138 Logger::error($errno . ' - ' . $errstr);
1139 Logger::error($errfile . ' - ' . $errline);
1140
1141 $this->load_logger();
1142 $this->output->log('Bypasser error:', 'ERROR');
1143 $this->output->log($errno . ' - ' . $errstr, 'ERROR');
1144 $this->output->log($errfile . ' - ' . $errline, 'ERROR');
1145
1146 $this->res = [ 'status' => 'error' ];
1147 return;
1148 }, E_ERROR);
1149
1150 // Notice parent script
1151 touch($this->identyfile . '-running');
1152 touch(BMI_BACKUPS . '/.running');
1153
1154 // CLI case
1155 if (BMI_CLI_REQUEST) {
1156
1157 $this->output->log('Starting database backup exporter', 'STEP');
1158 $this->output->log('Database exporter started via CLI', 'VERBOSE');
1159 while ($this->dbit !== -1) {
1160 $this->databaseBackupMaker();
1161 }
1162
1163 // Log
1164 $this->output->log("PHP CLI initialized - process ran successfully", 'SUCCESS');
1165 $this->make_file_groups();
1166
1167 // Make ZIP
1168 $this->output->log('Making archive...', 'STEP');
1169 while (!$this->final_made) {
1170 touch($this->identyfile . '-running');
1171 touch(BMI_BACKUPS . '/.running');
1172 $this->it += 1;
1173 if ($this->isStreamed) {
1174 do_action('bmip_streaming_backup_process_batch', $this);
1175 } else {
1176 $this->zip_batch();
1177 }
1178 }
1179
1180 } else {
1181
1182 // Background
1183 if ($this->dbit !== -1) {
1184
1185 if ($this->dbit === 0) {
1186 $this->output->log('Background process initialized', 'SUCCESS');
1187 $this->output->log('Starting database backup exporter', 'STEP');
1188 $this->output->log('Database exporter started via WEB REQUESTS', 'VERBOSE');
1189 }
1190
1191 $this->databaseBackupMaker();
1192 return $this->res;
1193
1194 } else {
1195
1196 if ($this->it === 0) {
1197
1198 $this->make_file_groups();
1199 $this->it += 1;
1200 $this->output->log('Making archive...', 'STEP');
1201
1202 } else {
1203 if ($this->isStreamed) {
1204 do_action('bmip_streaming_backup_process_batch', $this);
1205 } else {
1206 $this->zip_batch();
1207 }
1208 $this->it += 1;
1209
1210 }
1211
1212 }
1213
1214 }
1215
1216 }
1217
1218 public function fixSlashes($str, $slash = false) {
1219 // Old version
1220 // $str = str_replace('\\\\', DIRECTORY_SEPARATOR, $str);
1221 // $str = str_replace('\\', DIRECTORY_SEPARATOR, $str);
1222 // $str = str_replace('\/', DIRECTORY_SEPARATOR, $str);
1223 // $str = str_replace('/', DIRECTORY_SEPARATOR, $str);
1224
1225 // if ($str[strlen($str) - 1] == DIRECTORY_SEPARATOR) {
1226 // $str = substr($str, 0, -1);
1227 // }
1228
1229 // Since 1.3.2
1230 $protocol = '';
1231 if ($slash == false) $slash = DIRECTORY_SEPARATOR;
1232 if (substr($str, 0, 7) == 'http://') $protocol = 'http://';
1233 else if (substr($str, 0, 8) == 'https://') $protocol = 'https://';
1234
1235 $str = substr($str, strlen($protocol));
1236 $str = preg_replace('/[\\\\\/]+/', $slash, $str);
1237 $str = rtrim($str, '/\\' );
1238
1239 return $protocol . $str;
1240 }
1241
1242 public function isFunctionEnabled($func) {
1243 $disabled = explode(',', ini_get('disable_functions'));
1244 $isDisabled = in_array($func, $disabled);
1245 if (!$isDisabled && function_exists($func)) return true;
1246 else return false;
1247 }
1248
1249 // Database batch maker and dumper
1250 // We need WP instance for that to get access to wpdb
1251 public function databaseBackupMaker() {
1252
1253 if ($this->dbit === -1) {
1254 $this->res = [ 'status' => 'error' ];
1255 return;
1256 }
1257
1258 // DB File Name for that type of backup
1259 $dbbackupname = 'bmi_database_backup.sql';
1260 $database_file = $this->fixSlashes(BMI_TMP . DIRECTORY_SEPARATOR . $dbbackupname);
1261 $shouldBackupDB = apply_filters('bmip_database_backup', Dashboard\bmi_get_config('BACKUP:DATABASE') == 'true');
1262 if ( $shouldBackupDB ) {
1263
1264 if (Dashboard\bmi_get_config('OTHER:BACKUP:DB:SINGLE:FILE') == 'true') {
1265
1266 // Require Database Manager
1267 require_once BMI_INCLUDES . DIRECTORY_SEPARATOR . 'database' . DIRECTORY_SEPARATOR . 'manager.php';
1268
1269 // Log what's going on
1270 $this->output->log('Making single-file database backup (using deprecated engine, due to used settings)', 'STEP');
1271
1272 // Get database dump
1273 $databaser = new Database(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
1274 $databaser->exportDatabase($dbbackupname);
1275 $this->output->log("Database size: " . $this->humanSize(filesize($database_file)), 'INFO');
1276 $this->output->log('Database (single-file) backup finished.', 'SUCCESS');
1277
1278 $this->dbitJustFinished = true;
1279 $this->dbit = -1;
1280
1281 $this->res = [ 'status' => 'success' ];
1282 return true;
1283
1284 } else {
1285
1286 // Log what's going on
1287 if ($this->dbit === 0) {
1288 $this->output->log("Making database backup (using v3 engine, requires at least v1.2.2 to restore)", 'STEP');
1289 $this->output->log("Iterating database...", 'INFO');
1290 }
1291
1292
1293 $database_file_dir = $this->fixSlashes((dirname($database_file))) . DIRECTORY_SEPARATOR;
1294 $better_database_files_dir = $database_file_dir . 'db_tables';
1295 $better_database_files_dir = str_replace('file:', 'file://', $better_database_files_dir);
1296
1297 if (!is_dir($better_database_files_dir)) @mkdir($better_database_files_dir, 0755, true);
1298 $dbEngine = 3;
1299 if (Dashboard\bmi_get_config('OTHER::NEW_DATABASE_EXPORT_ENGINE')) {
1300 require_once BMI_INCLUDES . DIRECTORY_SEPARATOR . 'database' . DIRECTORY_SEPARATOR . 'export' . DIRECTORY_SEPARATOR . 'class-database-export-processor.php';
1301 $dbEngine = 4;
1302 $db_exporter = new DatabaseExportProcessor($better_database_files_dir, $this->output, intval($this->backupstart));
1303 } else {
1304 // Require Database Manager
1305 require_once BMI_INCLUDES . DIRECTORY_SEPARATOR . 'database' . DIRECTORY_SEPARATOR . 'better-backup-v3.php';
1306 $db_exporter = new BetterDatabaseExport($better_database_files_dir, $this->output, $this->dbit, intval($this->backupstart));
1307 }
1308
1309 $dbBatchingEnabled = false;
1310 if (Dashboard\bmi_get_config('OTHER:BACKUP:DB:BATCHING') == 'true') {
1311 $dbBatchingEnabled = true;
1312 } else {
1313 if ($this->dbit === 0) {
1314 $this->output->log("Database batching is disabled in options, consider to use this option if your database backup fails.", 'WARN');
1315 }
1316 }
1317
1318 if (BMI_CLI_REQUEST === true || $dbBatchingEnabled === false) {
1319
1320 if ($dbEngine === 4) {
1321 $results = $db_exporter->exportAll();
1322 } else {
1323 $results = $db_exporter->export();
1324 }
1325
1326 $this->output->log("Database backup finished", 'SUCCESS');
1327 $this->dbitJustFinished = true;
1328 $this->dbit = -1;
1329 $this->dblast = 0;
1330
1331 } else {
1332
1333 if ($dbEngine === 4) {
1334 $results = $db_exporter->exportBatch();
1335 // Backward compatibility for v3 engine
1336 $this->dbit += 1;
1337 $results['batchingStep'] = $this->dbit;
1338 $results['finishedQuery'] = $this->dblast;
1339 $results['dumpCompleted'] = $results['status'] === DatabaseExportProcessor::STATUS_COMPLETED;
1340 } else {
1341 $results = $db_exporter->export($this->dbit, $this->dblast);
1342 }
1343
1344 $this->dbit = intval($results['batchingStep']);
1345 $this->dblast = intval($results['finishedQuery']);
1346 $dbFinished = $results['dumpCompleted'];
1347
1348 if ($dbFinished == true) {
1349 $this->output->log("Database backup finished", 'SUCCESS');
1350 $this->dbitJustFinished = true;
1351 $this->dbit = -1;
1352 }
1353
1354 }
1355
1356 $this->res = [ 'status' => 'success' ];
1357 return true;
1358
1359 }
1360
1361 } else {
1362
1363 $this->output->log('Database will not be dumped due to user settings.', 'INFO');
1364 $this->dbitJustFinished = true;
1365 $this->dbit = -1;
1366
1367 $this->res = [ 'status' => 'success' ];
1368 return true;
1369
1370 }
1371
1372 }
1373
1374 public function actionsAfterProcess($success = false) {
1375 if ($success == true) {
1376 Logger::log("Backup file created successfully via backup-process.php");
1377 set_transient('bmi_latest_backup_file', base64_encode($this->backupname), 30);
1378 BMP::handle_after_cron();
1379 } else {
1380 Logger::log("Backup file creation failed via backup-process.php");
1381 }
1382
1383 if (has_action('bmi_premium_after_process') || (defined('BACKUP_TRIGGERED_BY_URL') && BACKUP_TRIGGERED_BY_URL === true)){
1384 do_action('bmi_premium_after_process', $success, 'backup', defined('BACKUP_TRIGGERED_BY_URL') && BACKUP_TRIGGERED_BY_URL === true);
1385 }
1386
1387 return null;
1388
1389 }
1390
1391
1392 }
1393