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