PluginProbe
ManageWP Worker / 3.9.24
ManageWP Worker v3.9.24
4.9.38 4.9.37 4.9.36 4.9.35 4.9.34 3.8.7 3.8.8 3.9.0 3.9.1 3.9.10 3.9.11 3.9.12 3.9.13 3.9.14 3.9.15 3.9.16 3.9.17 3.9.18 3.9.19 3.9.2 3.9.20 3.9.21 3.9.22 3.9.23 3.9.24 All 73 releases
worker / backup.class.php

backup.class.php in ManageWP Worker 3.9.24, at backup.class.php

3,263 lines 127.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*************************************************************
3 *
4 * backup.class.php
5 *
6 * Manage Backups
7 *
8 *
9 * Copyright (c) 2011 Prelovac Media
10 * www.prelovac.com
11 **************************************************************/
12 if(basename($_SERVER['SCRIPT_FILENAME']) == "backup.class.php"):
13 echo "Sorry but you cannot browse this file directly!";
14 exit;
15 endif;
16 define('MWP_BACKUP_DIR', WP_CONTENT_DIR . '/managewp/backups');
17 define('MWP_DB_DIR', MWP_BACKUP_DIR . '/mwp_db');
18
19 $zip_errors = array(
20 'No error',
21 'No error',
22 'Unexpected end of zip file',
23 'A generic error in the zipfile format was detected.',
24 'zip was unable to allocate itself memory',
25 'A severe error in the zipfile format was detected',
26 'Entry too large to be split with zipsplit',
27 'Invalid comment format',
28 'zip -T failed or out of memory',
29 'The user aborted zip prematurely',
30 'zip encountered an error while using a temp file',
31 'Read or seek error',
32 'zip has nothing to do',
33 'Missing or empty zip file',
34 'Error writing to a file',
35 'zip was unable to create a file to write to',
36 'bad command line parameters',
37 'no error',
38 'zip could not open a specified file to read'
39 );
40 $unzip_errors = array(
41 'No error',
42 'One or more warning errors were encountered, but processing completed successfully anyway',
43 'A generic error in the zipfile format was detected',
44 'A severe error in the zipfile format was detected.',
45 'unzip was unable to allocate itself memory.',
46 'unzip was unable to allocate memory, or encountered an encryption error',
47 'unzip was unable to allocate memory during decompression to disk',
48 'unzip was unable allocate memory during in-memory decompression',
49 'unused',
50 'The specified zipfiles were not found',
51 'Bad command line parameters',
52 'No matching files were found',
53 50 => 'The disk is (or was) full during extraction',
54 51 => 'The end of the ZIP archive was encountered prematurely.',
55 80 => 'The user aborted unzip prematurely.',
56 81 => 'Testing or extraction of one or more files failed due to unsupported compression methods or unsupported decryption.',
57 82 => 'No files were found due to bad decryption password(s)'
58 );
59
60 /**
61 * The main class for processing database and full backups on ManageWP worker.
62 *
63 * @copyright 2011-2012 Prelovac Media
64 * @version 3.9.24
65 * @package ManageWP
66 * @subpackage backup
67 *
68 */
69 class MMB_Backup extends MMB_Core {
70 var $site_name;
71 var $statuses;
72 var $tasks;
73 var $s3;
74 var $ftp;
75 var $dropbox;
76 var $google_drive;
77
78 /**
79 * Initializes site_name, statuses, and tasks attributes.
80 *
81 * @return void
82 */
83 function __construct() {
84 parent::__construct();
85 $this->site_name = str_replace(array(
86 "_",
87 "/",
88 "~"
89 ), array(
90 "",
91 "-",
92 "-"
93 ), rtrim($this->remove_http(get_bloginfo('url')), "/"));
94 $this->statuses = array(
95 'db_dump' => 1,
96 'db_zip' => 2,
97 'files_zip' => 3,
98 's3' => 4,
99 'dropbox' => 5,
100 'ftp' => 6,
101 'email' => 7,
102 'google_drive' => 8,
103 'finished' => 100
104 );
105 $this->tasks = get_option('mwp_backup_tasks');
106 }
107
108 /**
109 * Tries to increase memory limit to 384M and execution time to 600s.
110 *
111 * @return array an array with two keys for execution time and memory limit (0 - if not changed, 1 - if succesfully)
112 */
113 function set_memory() {
114 $changed = array('execution_time' => 0, 'memory_limit' => 0);
115
116 $memory_limit = trim(ini_get('memory_limit'));
117 $last = strtolower(substr($memory_limit, -1));
118
119 if($last == 'g')
120 $memory_limit = ((int) $memory_limit)*1024;
121 else if($last == 'm')
122 $memory_limit = (int) $memory_limit;
123 if($last == 'k')
124 $memory_limit = ((int) $memory_limit)/1024;
125
126 if ( $memory_limit < 384 ) {
127 @ini_set('memory_limit', '384M');
128 $changed['memory_limit'] = 1;
129 }
130
131 if ( (int) @ini_get('max_execution_time') < 600 ) {
132 @set_time_limit(600); //ten minutes
133 $changed['execution_time'] = 1;
134 }
135
136 return $changed;
137 }
138
139 /**
140 * Returns backup settings from local database for all tasks
141 *
142 * @return mixed|boolean
143 */
144 function get_backup_settings() {
145 $backup_settings = get_option('mwp_backup_tasks');
146
147 if (!empty($backup_settings))
148 return $backup_settings;
149 else
150 return false;
151 }
152
153 /**
154 * Sets backup task defined from master, if task name is "Backup Now" this function fires processing backup.
155 *
156 * @param mixed $params parameters sent from master
157 * @return mixed|boolean $this->tasks variable if success, array with error message if error has ocurred, false if $params are empty
158 */
159 function set_backup_task($params) {
160 //$params => [$task_name, $args, $error]
161 if (!empty($params)) {
162
163 //Make sure backup cron job is set
164 if (!wp_next_scheduled('mwp_backup_tasks')) {
165 wp_schedule_event( time(), 'tenminutes', 'mwp_backup_tasks' );
166 }
167
168 extract($params);
169
170 //$before = $this->get_backup_settings();
171 $before = $this->tasks;
172 if (!$before || empty($before))
173 $before = array();
174
175 if (isset($args['remove'])) {
176 unset($before[$task_name]);
177 $return = array(
178 'removed' => true
179 );
180 } else {
181 if (isset($params['account_info']) && is_array($params['account_info'])) { //only if sends from master first time(secure data)
182 $args['account_info'] = $account_info;
183 }
184
185 $before[$task_name]['task_args'] = $args;
186 if (strlen($args['schedule']))
187 $before[$task_name]['task_args']['next'] = $this->schedule_next($args['type'], $args['schedule']);
188
189 $return = $before[$task_name];
190 }
191
192 //Update with error
193 if (isset($error)) {
194 if (is_array($error)) {
195 $before[$task_name]['task_results'][count($before[$task_name]['task_results']) - 1]['error'] = $error['error'];
196 } else {
197 $before[$task_name]['task_results'][count($before[$task_name]['task_results'])]['error'] = $error;
198 }
199 }
200
201 if (isset($time) && $time) { //set next result time before backup
202 if (is_array($before[$task_name]['task_results'])) {
203 $before[$task_name]['task_results'] = array_values($before[$task_name]['task_results']);
204 }
205 $before[$task_name]['task_results'][count($before[$task_name]['task_results'])]['time'] = $time;
206 }
207
208 $this->update_tasks($before);
209 //update_option('mwp_backup_tasks', $before);
210
211 if ($task_name == 'Backup Now') {
212 $result = $this->backup($args, $task_name);
213 $backup_settings = $this->tasks;
214
215 if (is_array($result) && array_key_exists('error', $result)) {
216 $return = $result;
217 } else {
218 $return = $backup_settings[$task_name];
219 }
220 }
221 return $return;
222 }
223
224 return false;
225 }
226
227 /**
228 * Checks if scheduled task is ready for execution,
229 * if it is ready master sends google_drive_token, failed_emails, success_emails if are needed.
230 *
231 * @return void
232 */
233 function check_backup_tasks() {
234 $this->check_cron_remove();
235
236 $failed_emails = array();
237 $settings = $this->tasks;
238 if (is_array($settings) && !empty($settings)) {
239 foreach ($settings as $task_name => $setting) {
240 if (isset($setting['task_args']['next']) && $setting['task_args']['next'] < time()) {
241 //if ($setting['task_args']['next'] && $_GET['force_backup']) {
242 if ($setting['task_args']['url'] && $setting['task_args']['task_id'] && $setting['task_args']['site_key']) {
243 //Check orphan task
244 $check_data = array(
245 'task_name' => $task_name,
246 'task_id' => $setting['task_args']['task_id'],
247 'site_key' => $setting['task_args']['site_key'],
248 'worker_version' => MMB_WORKER_VERSION
249 );
250
251 if (isset($setting['task_args']['account_info']['mwp_google_drive']['google_drive_token'])) {
252 $check_data['mwp_google_drive_refresh_token'] = true;
253 }
254
255 $check = $this->validate_task($check_data, $setting['task_args']['url']);
256 if($check == 'paused' || $check == 'deleted'){
257 continue;
258 }
259 $worker_upto_3_9_22 = (MMB_WORKER_VERSION <= '3.9.22'); // worker version is less or equals to 3.9.22
260
261 // This is the patch done in worker 3.9.22 because old worked provided message in the following format:
262 // token - not found or token - {...json...}
263 // The new message is a serialized string with google_drive_token or message.
264 if ($worker_upto_3_9_22) {
265 $potential_token = substr($check, 8);
266 if (substr($check, 0, 8) == 'token - ' && $potential_token != 'not found') {
267 $this->tasks[$task_name]['task_args']['account_info']['mwp_google_drive']['google_drive_token'] = $potential_token;
268 $settings[$task_name]['task_args']['account_info']['mwp_google_drive']['google_drive_token'] = $potential_token;
269 $setting['task_args']['account_info']['mwp_google_drive']['google_drive_token'] = $potential_token;
270 }
271 } else {
272 $potential_token = isset($check['google_drive_token']) ? $check['google_drive_token'] : false;
273 if ($potential_token) {
274 $this->tasks[$task_name]['task_args']['account_info']['mwp_google_drive']['google_drive_token'] = $potential_token;
275 $settings[$task_name]['task_args']['account_info']['mwp_google_drive']['google_drive_token'] = $potential_token;
276 $setting['task_args']['account_info']['mwp_google_drive']['google_drive_token'] = $potential_token;
277 }
278 }
279
280 }
281
282 $update = array(
283 'task_name' => $task_name,
284 'args' => $settings[$task_name]['task_args']
285 );
286
287 if ($check != 'paused') {
288 $update['time'] = time();
289 }
290
291 //Update task with next schedule
292 $this->set_backup_task($update);
293
294 $result = $this->backup($setting['task_args'], $task_name);
295 $error = '';
296
297 if (is_array($result) && array_key_exists('error', $result)) {
298 $error = $result;
299 $this->set_backup_task(array(
300 'task_name' => $task_name,
301 'args' => $settings[$task_name]['task_args'],
302 'error' => $error
303 ));
304 } else {
305 if (@count($setting['task_args']['account_info'])) {
306 // Old way through sheduling.
307 // wp_schedule_single_event(time(), 'mmb_scheduled_remote_upload', array('args' => array('task_name' => $task_name)));
308 $nonce = substr(wp_hash(wp_nonce_tick() . 'mmb-backup-nonce' . 0, 'nonce'), -12, 10);
309 $cron_url = site_url('index.php');
310 $backup_file = $this->tasks[$task_name]['task_results'][count($this->tasks[$task_name]['task_results']) - 1]['server']['file_url'];
311 $del_host_file = $this->tasks[$task_name]['task_args']['del_host_file'];
312 $public_key = get_option('_worker_public_key');
313 $args = array(
314 'body' => array(
315 'backup_cron_action' => 'mmb_remote_upload',
316 'args' => json_encode(array('task_name' => $task_name, 'backup_file' => $backup_file, 'del_host_file' => $del_host_file)),
317 'mmb_backup_nonce' => $nonce,
318 'public_key' => $public_key,
319 ),
320 'timeout' => 0.01,
321 'blocking' => false,
322 'sslverify' => apply_filters('https_local_ssl_verify', true)
323 );
324 wp_remote_post($cron_url, $args);
325 }
326 }
327
328 break; //Only one backup per cron
329 }
330 }
331 }
332
333 }
334
335 /**
336 * Runs backup task invoked from ManageWP master.
337 *
338 * @param string $task_name name of backup task
339 * @param string|bool[optional] $google_drive_token false if backup destination is not Google Drive, json of Google Drive token if it is remote destination (default: false)
340 * @return mixed array with backup statistics if successful, array with error message if not
341 */
342 function task_now($task_name, $google_drive_token = false) {
343 if ($google_drive_token) {
344 $this->tasks[$task_name]['task_args']['account_info']['mwp_google_drive']['google_drive_token'] = $google_drive_token;
345 }
346
347 $settings = $this->tasks;
348 if(!array_key_exists($task_name,$settings)){
349 return array('error' => $task_name." does not exist.");
350 } else {
351 $setting = $settings[$task_name];
352 }
353
354 $this->set_backup_task(array(
355 'task_name' => $task_name,
356 'args' => $settings[$task_name]['task_args'],
357 'time' => time()
358 ));
359
360 //Run backup
361 $result = $this->backup($setting['task_args'], $task_name);
362
363 //Check for error
364 if (is_array($result) && array_key_exists('error', $result)) {
365 $this->set_backup_task(array(
366 'task_name' => $task_name,
367 'args' => $settings[$task_name]['task_args'],
368 'error' => $result
369 ));
370 return $result;
371 } else {
372 return $this->get_backup_stats();
373 }
374 }
375
376 /**
377 * Backup a full wordpress instance, including a database dump, which is placed in mwp_db dir in root folder.
378 * All backups are compressed by zip and placed in wp-content/managewp/backups folder.
379 *
380 * @param string $args arguments passed from master
381 * [type] -> db, full
382 * [what] -> daily, weekly, monthly
383 * [account_info] -> remote destinations ftp, amazons3, dropbox, google_drive, email with their parameters
384 * [include] -> array of folders from site root which are included to backup (wp-admin, wp-content, wp-includes are default)
385 * [exclude] -> array of files of folders to exclude, relative to site's root
386 * @param bool|string[optional] $task_name the name of backup task, which backup is done (default: false)
387 * @return bool|array false if $args are missing, array with error if error has occured, ture if is successful
388 */
389 function backup($args, $task_name = false) {
390 if (!$args || empty($args))
391 return false;
392
393 extract($args); //extract settings
394
395 if (!empty($account_info)) {
396 $found = false;
397 $destinations = array('mwp_ftp', 'mwp_amazon_s3', 'mwp_dropbox', 'mwp_google_drive', 'mwp_email');
398 foreach($destinations as $dest) {
399 $found = $found || (isset($account_info[$dest]));
400 }
401 if (!$found) {
402 $error_message = 'Remote destination is not supported, please update your client plugin.';
403 return array(
404 'error' => $error_message
405 );
406 }
407 }
408
409 //Try increase memory limit and execution time
410 $this->set_memory();
411
412 //Remove old backup(s)
413 $removed = $this->remove_old_backups($task_name);
414 if (is_array($removed) && isset($removed['error'])) {
415 $error_message = $removed['error'];
416 return $removed;
417 }
418
419 $new_file_path = MWP_BACKUP_DIR;
420
421 if (!file_exists($new_file_path)) {
422 if (!mkdir($new_file_path, 0755, true))
423 $error_message = 'Permission denied, make sure you have write permission to wp-content folder.';
424 return array(
425 'error' => $error_message
426 );
427 }
428
429 @file_put_contents($new_file_path . '/index.php', ''); //safe
430
431 //Prepare .zip file name
432 $hash = md5(time());
433 $label = $type ? $type : 'manual';
434 $backup_file = $new_file_path . '/' . $this->site_name . '_' . $label . '_' . $what . '_' . date('Y-m-d') . '_' . $hash . '.zip';
435 $backup_url = WP_CONTENT_URL . '/managewp/backups/' . $this->site_name . '_' . $label . '_' . $what . '_' . date('Y-m-d') . '_' . $hash . '.zip';
436
437 $begin_compress = microtime(true);
438
439 //Optimize tables?
440 if (isset($optimize_tables) && !empty($optimize_tables)) {
441 $this->optimize_tables();
442 }
443
444 //What to backup - db or full?
445 if (trim($what) == 'db') {
446 $db_backup = $this->backup_db_compress($task_name, $backup_file);
447 if (is_array($db_backup) && array_key_exists('error', $db_backup)) {
448 $error_message = $db_backup['error'];
449 return array(
450 'error' => $error_message
451 );
452 }
453 } elseif (trim($what) == 'full') {
454 if (!$exclude) {
455 $exclude = array();
456 }
457 if (!$include) {
458 $include = array();
459 }
460 $content_backup = $this->backup_full($task_name, $backup_file, $exclude, $include);
461 if (is_array($content_backup) && array_key_exists('error', $content_backup)) {
462 $error_message = $content_backup['error'];
463 return array(
464 'error' => $error_message
465 );
466 }
467 }
468
469 $end_compress = microtime(true);
470
471 //Update backup info
472 if ($task_name) {
473 //backup task (scheduled)
474 $backup_settings = $this->tasks;
475 $paths = array();
476 $size = ceil(filesize($backup_file) / 1024);
477 $duration = round($end_compress - $begin_compress, 2);
478
479 if ($size > 1000) {
480 $paths['size'] = ceil($size / 1024) . "mb";
481 } else {
482 $paths['size'] = $size . 'kb';
483 }
484
485 $paths['duration'] = $duration . 's';
486
487 if ($task_name != 'Backup Now') {
488 $paths['server'] = array(
489 'file_path' => $backup_file,
490 'file_url' => $backup_url
491 );
492 } else {
493 $paths['server'] = array(
494 'file_path' => $backup_file,
495 'file_url' => $backup_url
496 );
497 }
498
499 if (isset($backup_settings[$task_name]['task_args']['account_info']['mwp_ftp'])) {
500 $paths['ftp'] = basename($backup_url);
501 }
502
503 if (isset($backup_settings[$task_name]['task_args']['account_info']['mwp_amazon_s3'])) {
504 $paths['amazons3'] = basename($backup_url);
505 }
506
507 if (isset($backup_settings[$task_name]['task_args']['account_info']['mwp_dropbox'])) {
508 $paths['dropbox'] = basename($backup_url);
509 }
510
511 if (isset($backup_settings[$task_name]['task_args']['account_info']['mwp_email'])) {
512 $paths['email'] = basename($backup_url);
513 }
514
515 if (isset($backup_settings[$task_name]['task_args']['account_info']['mwp_google_drive'])) {
516 $paths['google_drive'] = basename($backup_url);
517 }
518
519 $temp = $backup_settings[$task_name]['task_results'];
520 $temp = array_values($temp);
521 $paths['time'] = time();
522
523 if ($task_name != 'Backup Now') {
524 $paths['status'] = $temp[count($temp) - 1]['status'];
525 $temp[count($temp) - 1] = $paths;
526
527 } else {
528 $temp[count($temp)] = $paths;
529 }
530
531 $backup_settings[$task_name]['task_results'] = $temp;
532 $this->update_tasks($backup_settings);
533 //update_option('mwp_backup_tasks', $backup_settings);
534 }
535
536 // If there are not remote destination, set up task status to finished
537 if (@count($backup_settings[$task_name]['task_args']['account_info']) == 0) {
538 $this->update_status($task_name, $this->statuses['finished'], true);
539 }
540
541 return true;
542 }
543
544 /**
545 * Backup a full wordpress instance, including a database dump, which is placed in mwp_db dir in root folder.
546 * All backups are compressed by zip and placed in wp-content/managewp/backups folder.
547 *
548 * @param string $task_name the name of backup task, which backup is done
549 * @param string $backup_file relative path to file which backup is stored
550 * @param array[optional] $exclude the list of files and folders, which are excluded from backup (default: array())
551 * @param array[optional] $include the list of folders in wordpress root which are included to backup, expect wp-admin, wp-content, wp-includes, which are default (default: array())
552 * @return bool|array true if backup is successful, or an array with error message if is failed
553 */
554 function backup_full($task_name, $backup_file, $exclude = array(), $include = array()) {
555 $this->update_status($task_name, $this->statuses['db_dump']);
556 $db_result = $this->backup_db();
557
558 if ($db_result == false) {
559 return array(
560 'error' => 'Failed to backup database.'
561 );
562 } else if (is_array($db_result) && isset($db_result['error'])) {
563 return array(
564 'error' => $db_result['error']
565 );
566 }
567
568 $this->update_status($task_name, $this->statuses['db_dump'], true);
569 $this->update_status($task_name, $this->statuses['db_zip']);
570
571 @file_put_contents(MWP_BACKUP_DIR.'/mwp_db/index.php', '');
572 $zip_db_result = $this->zip_backup_db($task_name, $backup_file);
573
574 if (!$zip_db_result) {
575 $zip_archive_db_result = false;
576 if (class_exists("ZipArchive")) {
577 $this->_log("DB zip, fallback to ZipArchive");
578 $zip_archive_db_result = $this->zip_archive_backup_db($task_name, $db_result, $backup_file);
579 }
580
581 if (!$zip_archive_db_result) {
582 $this->_log("DB zip, fallback to PclZip");
583 $pclzip_db_result = $this->pclzip_backup_db($task_name, $backup_file);
584 if (!$pclzip_db_result) {
585 @unlink(MWP_BACKUP_DIR.'/mwp_db/index.php');
586 @unlink($db_result);
587 @rmdir(MWP_DB_DIR);
588
589 return array(
590 'error' => 'Failed to zip database. pclZip error (' . $archive->error_code . '): .' . $archive->error_string
591 );
592 }
593 }
594 }
595
596 @unlink(MWP_BACKUP_DIR.'/mwp_db/index.php');
597 @unlink($db_result);
598 @rmdir(MWP_DB_DIR);
599
600 $remove = array(
601 trim(basename(WP_CONTENT_DIR)) . "/managewp/backups",
602 trim(basename(WP_CONTENT_DIR)) . "/" . md5('mmb-worker') . "/mwp_backups"
603 );
604 $exclude = array_merge($exclude, $remove);
605
606 $this->update_status($task_name, $this->statuses['db_zip'], true);
607 $this->update_status($task_name, $this->statuses['files_zip']);
608
609 $zip_result = $this->zip_backup($task_name, $backup_file, $exclude, $include);
610
611 if (isset($zip_result['error'])) {
612 return $zip_result;
613 }
614
615 if (!$zip_result) {
616 $zip_archive_result = false;
617 if (class_exists("ZipArchive")) {
618 $this->_log("Files zip fallback to ZipArchive");
619 $zip_archive_result = $this->zip_archive_backup($task_name, $backup_file, $exclude, $include);
620 }
621
622 if (!$zip_archive_result) {
623 $this->_log("Files zip fallback to PclZip");
624 $pclzip_result = $this->pclzip_backup($task_name, $backup_file, $exclude, $include);
625 if (!$pclzip_result) {
626 @unlink(MWP_BACKUP_DIR.'/mwp_db/index.php');
627 @unlink($db_result);
628 @rmdir(MWP_DB_DIR);
629
630 if (!$pclzip_result) {
631 @unlink($backup_file);
632 return array(
633 'error' => 'Failed to zip files. pclZip error (' . $archive->error_code . '): .' . $archive->error_string
634 );
635 }
636 }
637 }
638 }
639
640 //Reconnect
641 $this->wpdb_reconnect();
642
643 $this->update_status($task_name, $this->statuses['files_zip'], true);
644 return true;
645 }
646
647 /**
648 * Zipping database dump and index.php in folder mwp_db by system zip command, requires zip installed on OS.
649 *
650 * @param string $task_name the name of backup task
651 * @param string $backup_file absolute path to zip file
652 * @return bool is compress successful or not
653 */
654 function zip_backup_db($task_name, $backup_file) {
655 $disable_comp = $this->tasks[$task_name]['task_args']['disable_comp'];
656 $comp_level = $disable_comp ? '-0' : '-1';
657 $zip = $this->get_zip();
658 //Add database file
659 chdir(MWP_BACKUP_DIR);
660 $command = "$zip -q -r $comp_level $backup_file 'mwp_db'";
661
662 ob_start();
663 $this->_log("Executing $command");
664 $result = $this->mmb_exec($command);
665 ob_get_clean();
666
667 return $result;
668 }
669
670 /**
671 * Zipping database dump and index.php in folder mwp_db by ZipArchive class, requires php zip extension.
672 *
673 * @param string $task_name the name of backup task
674 * @param string $db_result relative path to database dump file
675 * @param string $backup_file absolute path to zip file
676 * @return bool is compress successful or not
677 */
678 function zip_archive_backup_db($task_name, $db_result, $backup_file) {
679 $disable_comp = $this->tasks[$task_name]['task_args']['disable_comp'];
680 if (!$disable_comp) {
681 $this->_log("Compression is not supported by ZipArchive");
682 }
683 $zip = new ZipArchive();
684 $result = $zip->open($backup_file, ZIPARCHIVE::OVERWRITE); // Tries to open $backup_file for acrhiving
685 if ($result === true) {
686 $result = $result && $zip->addFile(MWP_BACKUP_DIR.'/mwp_db/index.php', "mwp_db/index.php"); // Tries to add mwp_db/index.php to $backup_file
687 $result = $result && $zip->addFile($db_result, "mwp_db/" . basename($db_result)); // Tries to add db dump form mwp_db dir to $backup_file
688 $result = $result && $zip->close(); // Tries to close $backup_file
689 } else {
690 $result = false;
691 }
692
693 return $result; // true if $backup_file iz zipped successfully, false if error is occured in zip process
694 }
695
696 /**
697 * Zipping database dump and index.php in folder mwp_db by PclZip library.
698 *
699 * @param string $task_name the name of backup task
700 * @param string $backup_file absolute path to zip file
701 * @return bool is compress successful or not
702 */
703 function pclzip_backup_db($task_name, $backup_file) {
704 $disable_comp = $this->tasks[$task_name]['task_args']['disable_comp'];
705 define('PCLZIP_TEMPORARY_DIR', MWP_BACKUP_DIR . '/');
706 require_once ABSPATH . '/wp-admin/includes/class-pclzip.php';
707 $zip = new PclZip($backup_file);
708
709 if ($disable_comp) {
710 $result = $zip->add(MWP_BACKUP_DIR, PCLZIP_OPT_REMOVE_PATH, MWP_BACKUP_DIR, PCLZIP_OPT_NO_COMPRESSION) !== 0;
711 } else {
712 $result = $zip->add(MWP_BACKUP_DIR, PCLZIP_OPT_REMOVE_PATH, MWP_BACKUP_DIR) !== 0;
713 }
714
715 return $result;
716 }
717
718 /**
719 * Zipping whole site root folder and append to backup file with database dump
720 * by system zip command, requires zip installed on OS.
721 *
722 * @param string $task_name the name of backup task
723 * @param string $backup_file absolute path to zip file
724 * @param array $exclude array of files of folders to exclude, relative to site's root
725 * @param array $include array of folders from site root which are included to backup (wp-admin, wp-content, wp-includes are default)
726 * @return array|bool true if successful or an array with error message if not
727 */
728 function zip_backup($task_name, $backup_file, $exclude, $include) {
729 global $zip_errors;
730 $sys = substr(PHP_OS, 0, 3);
731
732 //Exclude paths
733 $exclude_data = "-x";
734
735 $exclude_file_data = '';
736
737 // TODO: Prevent to $exclude include blank string '', beacuse zip 12 error will be occured.
738 if (!empty($exclude)) {
739 foreach ($exclude as $data) {
740 if (is_dir(ABSPATH . $data)) {
741 if ($sys == 'WIN')
742 $exclude_data .= " $data/*.*";
743 else
744 $exclude_data .= " '$data/*'";
745 } else {
746 if ($sys == 'WIN'){
747 if(file_exists(ABSPATH . $data)){
748 $exclude_data .= " $data";
749 $exclude_file_data .= " $data";
750 }
751 } else {
752 if(file_exists(ABSPATH . $data)){
753 $exclude_data .= " '$data'";
754 $exclude_file_data .= " '$data'";
755 }
756 }
757 }
758 }
759 }
760
761 if($exclude_file_data){
762 $exclude_file_data = "-x".$exclude_file_data;
763 }
764
765 //Include paths by default
766 $add = array(
767 trim(WPINC),
768 trim(basename(WP_CONTENT_DIR)),
769 "wp-admin"
770 );
771
772 $include_data = ". -i";
773 foreach ($add as $data) {
774 if ($sys == 'WIN')
775 $include_data .= " $data/*.*";
776 else
777 $include_data .= " '$data/*'";
778 }
779
780 //Additional includes?
781 if (!empty($include)) {
782 foreach ($include as $data) {
783 if ($data) {
784 if ($sys == 'WIN')
785 $include_data .= " $data/*.*";
786 else
787 $include_data .= " '$data/*'";
788 }
789 }
790 }
791
792 $disable_comp = $this->tasks[$task_name]['task_args']['disable_comp'];
793 $comp_level = $disable_comp ? '-0' : '-1';
794 $zip = $this->get_zip();
795 chdir(ABSPATH);
796 ob_start();
797 $command = "$zip -q -j $comp_level $backup_file .* * $exclude_file_data";
798 $this->_log("Executing $command");
799 $result_f = $this->mmb_exec($command, false, true);
800 if (!$result_f || $result_f == 18) { // disregard permissions error, file can't be accessed
801 $command = "$zip -q -r $comp_level $backup_file $include_data $exclude_data";
802 $result_d = $this->mmb_exec($command, false, true);
803 $this->_log("Executing $command");
804 if ($result_d && $result_d != 18) {
805 @unlink($backup_file);
806 if ($result_d > 0 && $result_d < 18)
807 return array(
808 'error' => 'Failed to archive files (' . $zip_errors[$result_d] . ') .'
809 );
810 else {
811 if ($result_d === -1) return false;
812 return array(
813 'error' => 'Failed to archive files.'
814 );
815 }
816 }
817 } else {
818 return false;
819 }
820
821 ob_get_clean();
822
823 return true;
824 }
825
826 /**
827 * Zipping whole site root folder and append to backup file with database dump
828 * by ZipArchive class, requires php zip extension.
829 *
830 * @param string $task_name the name of backup task
831 * @param string $backup_file absolute path to zip file
832 * @param array $exclude array of files of folders to exclude, relative to site's root
833 * @param array $include array of folders from site root which are included to backup (wp-admin, wp-content, wp-includes are default)
834 * @return array|bool true if successful or an array with error message if not
835 */
836 function zip_archive_backup($task_name, $backup_file, $exclude, $include, $overwrite = false) {
837 $filelist = $this->get_backup_files($exclude, $include);
838 $disable_comp = $this->tasks[$task_name]['task_args']['disable_comp'];
839 if (!$disable_comp) {
840 $this->_log("Compression is not supported by ZipArchive");
841 }
842
843 $zip = new ZipArchive();
844 if ($overwrite) {
845 $result = $zip->open($backup_file, ZipArchive::OVERWRITE); // Tries to open $backup_file for acrhiving
846 } else {
847 $result = $zip->open($backup_file); // Tries to open $backup_file for acrhiving
848 }
849 if ($result === true) {
850 foreach ($filelist as $file) {
851 $result = $result && $zip->addFile($file, sprintf("%s", str_replace(ABSPATH, '', $file))); // Tries to add a new file to $backup_file
852 }
853 $result = $result && $zip->close(); // Tries to close $backup_file
854 } else {
855 $result = false;
856 }
857
858 return $result; // true if $backup_file iz zipped successfully, false if error is occured in zip process
859 }
860
861 /**
862 * Zipping whole site root folder and append to backup file with database dump
863 * by PclZip library.
864 *
865 * @param string $task_name the name of backup task
866 * @param string $backup_file absolute path to zip file
867 * @param array $exclude array of files of folders to exclude, relative to site's root
868 * @param array $include array of folders from site root which are included to backup (wp-admin, wp-content, wp-includes are default)
869 * @return array|bool true if successful or an array with error message if not
870 */
871 function pclzip_backup($task_name, $backup_file, $exclude, $include) {
872 define('PCLZIP_TEMPORARY_DIR', MWP_BACKUP_DIR . '/');
873 require_once ABSPATH . '/wp-admin/includes/class-pclzip.php';
874 $zip = new PclZip($backup_file);
875 $add = array(
876 trim(WPINC),
877 trim(basename(WP_CONTENT_DIR)),
878 "wp-admin"
879 );
880
881 $include_data = array();
882 if (!empty($include)) {
883 foreach ($include as $data) {
884 if ($data && file_exists(ABSPATH . $data))
885 $include_data[] = ABSPATH . $data . '/';
886 }
887 }
888 $include_data = array_merge($add, $include_data);
889
890 if ($handle = opendir(ABSPATH)) {
891 while (false !== ($file = readdir($handle))) {
892 if ($file != "." && $file != ".." && !is_dir($file) && file_exists(ABSPATH . $file)) {
893 $include_data[] = ABSPATH . $file;
894 }
895 }
896 closedir($handle);
897 }
898
899 $disable_comp = $this->tasks[$task_name]['task_args']['disable_comp'];
900
901 if ($disable_comp) {
902 $result = $zip->add($include_data, PCLZIP_OPT_REMOVE_PATH, ABSPATH, PCLZIP_OPT_NO_COMPRESSION) !== 0;
903 } else {
904 $result = $zip->add($include_data, PCLZIP_OPT_REMOVE_PATH, ABSPATH) !== 0;
905 }
906
907 $exclude_data = array();
908 if (!empty($exclude)) {
909 foreach ($exclude as $data) {
910 if (file_exists(ABSPATH . $data)) {
911 if (is_dir(ABSPATH . $data))
912 $exclude_data[] = $data . '/';
913 else
914 $exclude_data[] = $data;
915 }
916 }
917 }
918 $result = $result && $zip->delete(PCLZIP_OPT_BY_NAME, $exclude_data);
919
920 return $result;
921 }
922
923 /**
924 * Gets an array of relative paths of all files in site root recursively.
925 * By default, there are all files from root folder, all files from folders wp-admin, wp-content, wp-includes recursively.
926 * Parameter $include adds other folders from site root, and excludes any file or folder by relative path to site's root.
927 *
928 * @param array $exclude array of files of folders to exclude, relative to site's root
929 * @param array $include array of folders from site root which are included to backup (wp-admin, wp-content, wp-includes are default)
930 * @return array array with all files in site root dir
931 */
932 function get_backup_files($exclude, $include) {
933 $add = array(
934 trim(WPINC),
935 trim(basename(WP_CONTENT_DIR)),
936 "wp-admin"
937 );
938
939 $include = array_merge($add, $include);
940
941 $filelist = array();
942 if ($handle = opendir(ABSPATH)) {
943 while (false !== ($file = readdir($handle))) {
944 if (is_dir($file) && file_exists(ABSPATH . $file) && !(in_array($file, $include))) {
945 $exclude[] = $file;
946 }
947 }
948 closedir($handle);
949 }
950
951 $filelist = get_all_files_from_dir(ABSPATH, $exclude);
952
953 return $filelist;
954 }
955
956 /**
957 * Backup a database dump of WordPress site.
958 * All backups are compressed by zip and placed in wp-content/managewp/backups folder.
959 *
960 * @param string $task_name the name of backup task, which backup is done
961 * @param string $backup_file relative path to file which backup is stored
962 * @return bool|array true if backup is successful, or an array with error message if is failed
963 */
964 function backup_db_compress($task_name, $backup_file) {
965 $this->update_status($task_name, $this->statuses['db_dump']);
966 $db_result = $this->backup_db();
967
968 if ($db_result == false) {
969 return array(
970 'error' => 'Failed to backup database.'
971 );
972 } else if (is_array($db_result) && isset($db_result['error'])) {
973 return array(
974 'error' => $db_result['error']
975 );
976 }
977
978 $this->update_status($task_name, $this->statuses['db_dump'], true);
979 $this->update_status($task_name, $this->statuses['db_zip']);
980 @file_put_contents(MWP_BACKUP_DIR.'/mwp_db/index.php', '');
981 $zip_db_result = $this->zip_backup_db($task_name, $backup_file);
982
983 if (!$zip_db_result) {
984 $zip_archive_db_result = false;
985 if (class_exists("ZipArchive")) {
986 $this->_log("DB zip, fallback to ZipArchive");
987 $zip_archive_db_result = $this->zip_archive_backup_db($task_name, $db_result, $backup_file);
988 }
989
990 if (!$zip_archive_db_result) {
991 $this->_log("DB zip, fallback to PclZip");
992 $pclzip_db_result = $this->pclzip_backup_db($task_name, $backup_file);
993 if (!$pclzip_db_result) {
994 @unlink(MWP_BACKUP_DIR.'/mwp_db/index.php');
995 @unlink($db_result);
996 @rmdir(MWP_DB_DIR);
997
998 return array(
999 'error' => 'Failed to zip database. pclZip error (' . $archive->error_code . '): .' . $archive->error_string
1000 );
1001 }
1002 }
1003 }
1004
1005 @unlink(MWP_BACKUP_DIR.'/mwp_db/index.php');
1006 @unlink($db_result);
1007 @rmdir(MWP_DB_DIR);
1008
1009 $this->update_status($task_name, $this->statuses['db_zip'], true);
1010
1011 return true;
1012 }
1013
1014 /**
1015 * Creates database dump and places it in mwp_db folder in site's root.
1016 * This function dispatches if OS mysql command does not work calls a php alternative.
1017 *
1018 * @return string|array path to dump file if successful, or an array with error message if is failed
1019 */
1020 function backup_db() {
1021 $db_folder = MWP_DB_DIR . '/';
1022 if (!file_exists($db_folder)) {
1023 if (!mkdir($db_folder, 0755, true))
1024 return array(
1025 'error' => 'Error creating database backup folder (' . $db_folder . '). Make sure you have corrrect write permissions.'
1026 );
1027 }
1028
1029 $file = $db_folder . DB_NAME . '.sql';
1030 $result = $this->backup_db_dump($file); // try mysqldump always then fallback to php dump
1031 return $result;
1032 }
1033
1034 /**
1035 * Creates database dump by system mysql command.
1036 *
1037 * @param string $file absolute path to file in which dump should be placed
1038 * @return string|array path to dump file if successful, or an array with error message if is failed
1039 */
1040 function backup_db_dump($file) {
1041 global $wpdb;
1042 $paths = $this->check_mysql_paths();
1043 $brace = (substr(PHP_OS, 0, 3) == 'WIN') ? '"' : '';
1044 $command = $brace . $paths['mysqldump'] . $brace . ' --force --host="' . DB_HOST . '" --user="' . DB_USER . '" --password="' . DB_PASSWORD . '" --add-drop-table --skip-lock-tables "' . DB_NAME . '" > ' . $brace . $file . $brace;
1045 ob_start();
1046 $result = $this->mmb_exec($command);
1047 ob_get_clean();
1048
1049 if (!$result) { // Fallback to php
1050 $this->_log("DB dump fallback to php");
1051 $result = $this->backup_db_php($file);
1052 return $result;
1053 }
1054
1055 if (filesize($file) == 0 || !is_file($file) || !$result) {
1056 @unlink($file);
1057 return false;
1058 } else {
1059 return $file;
1060 }
1061 }
1062
1063 /**
1064 * Creates database dump by php functions.
1065 *
1066 * @param string $file absolute path to file in which dump should be placed
1067 * @return string|array path to dump file if successful, or an array with error message if is failed
1068 */
1069 function backup_db_php($file) {
1070 global $wpdb;
1071 $tables = $wpdb->get_results('SHOW TABLES', ARRAY_N);
1072 foreach ($tables as $table) {
1073 //drop existing table
1074 $dump_data = "DROP TABLE IF EXISTS $table[0];";
1075 file_put_contents($file, $dump_data, FILE_APPEND);
1076 //create table
1077 $create_table = $wpdb->get_row("SHOW CREATE TABLE $table[0]", ARRAY_N);
1078 $dump_data = "\n\n" . $create_table[1] . ";\n\n";
1079 file_put_contents($file, $dump_data, FILE_APPEND);
1080
1081 $count = $wpdb->get_var("SELECT count(*) FROM $table[0]");
1082 if ($count > 100)
1083 $count = ceil($count / 100);
1084 else if ($count > 0)
1085 $count = 1;
1086
1087 for ($i = 0; $i < $count; $i++) {
1088 $low_limit = $i * 100;
1089 $qry = "SELECT * FROM $table[0] LIMIT $low_limit, 100";
1090 $rows = $wpdb->get_results($qry, ARRAY_A);
1091 if (is_array($rows)) {
1092 foreach ($rows as $row) {
1093 //insert single row
1094 $dump_data = "INSERT INTO $table[0] VALUES(";
1095 $num_values = count($row);
1096 $j = 1;
1097 foreach ($row as $value) {
1098 $value = addslashes($value);
1099 $value = preg_replace("/\n/Ui", "\\n", $value);
1100 $num_values == $j ? $dump_data .= "'" . $value . "'" : $dump_data .= "'" . $value . "', ";
1101 $j++;
1102 unset($value);
1103 }
1104 $dump_data .= ");\n";
1105 file_put_contents($file, $dump_data, FILE_APPEND);
1106 }
1107 }
1108 }
1109 $dump_data = "\n\n\n";
1110 file_put_contents($file, $dump_data, FILE_APPEND);
1111
1112 unset($rows);
1113 unset($dump_data);
1114 }
1115
1116 if (filesize($file) == 0 || !is_file($file)) {
1117 @unlink($file);
1118 return array(
1119 'error' => 'Database backup failed. Try to enable MySQL dump on your server.'
1120 );
1121 }
1122
1123 return $file;
1124 }
1125
1126 /**
1127 * Restores full WordPress site or database only form backup zip file.
1128 *
1129 * @param array array of arguments passed to backup restore
1130 * [task_name] -> name of backup task
1131 * [result_id] -> id of baskup task result, which should be restored
1132 * [google_drive_token] -> json of Google Drive token, if it is remote destination
1133 * @return bool|array true if successful, or an array with error message if is failed
1134 */
1135 function restore($args) {
1136 global $wpdb;
1137 if (empty($args)) {
1138 return false;
1139 }
1140
1141 extract($args);
1142 if (isset($google_drive_token)) {
1143 $this->tasks[$task_name]['task_args']['account_info']['mwp_google_drive']['google_drive_token'] = $google_drive_token;
1144 }
1145 $this->set_memory();
1146
1147 $unlink_file = true; //Delete file after restore
1148
1149 //Detect source
1150 if ($backup_url) {
1151 //This is for clone (overwrite)
1152 include_once ABSPATH . 'wp-admin/includes/file.php';
1153 $backup_file = download_url($backup_url);
1154 if (is_wp_error($backup_file)) {
1155 return array(
1156 'error' => 'Unable to download backup file ('.$backup_file->get_error_message().')'
1157 );
1158 }
1159 $what = 'full';
1160 } else {
1161 $tasks = $this->tasks;
1162 $task = $tasks[$task_name];
1163 if (isset($task['task_results'][$result_id]['server'])) {
1164 $backup_file = $task['task_results'][$result_id]['server']['file_path'];
1165 $unlink_file = false; //Don't delete file if stored on server
1166 } elseif (isset($task['task_results'][$result_id]['ftp'])) {
1167 $ftp_file = $task['task_results'][$result_id]['ftp'];
1168 $args = $task['task_args']['account_info']['mwp_ftp'];
1169 $args['backup_file'] = $ftp_file;
1170 $backup_file = $this->get_ftp_backup($args);
1171
1172 if ($backup_file == false) {
1173 return array(
1174 'error' => 'Failed to download file from FTP.'
1175 );
1176 }
1177 } elseif (isset($task['task_results'][$result_id]['amazons3'])) {
1178 $amazons3_file = $task['task_results'][$result_id]['amazons3'];
1179 $args = $task['task_args']['account_info']['mwp_amazon_s3'];
1180 $args['backup_file'] = $amazons3_file;
1181 $backup_file = $this->get_amazons3_backup($args);
1182
1183 if ($backup_file == false) {
1184 return array(
1185 'error' => 'Failed to download file from Amazon S3.'
1186 );
1187 }
1188 } elseif(isset($task['task_results'][$result_id]['dropbox'])){
1189 $dropbox_file = $task['task_results'][$result_id]['dropbox'];
1190 $args = $task['task_args']['account_info']['mwp_dropbox'];
1191 $args['backup_file'] = $dropbox_file;
1192 $backup_file = $this->get_dropbox_backup($args);
1193
1194 if ($backup_file == false) {
1195 return array(
1196 'error' => 'Failed to download file from Dropbox.'
1197 );
1198 }
1199 } elseif (isset($task['task_results'][$result_id]['google_drive'])) {
1200 $google_drive_file = $task['task_results'][$result_id]['google_drive'];
1201 $args = $task['task_args']['account_info']['mwp_google_drive'];
1202 $args['backup_file'] = $google_drive_file;
1203 $backup_file = $this->get_google_drive_backup($args);
1204
1205 if (is_array($backup_file) && isset($backup_file['error'])) {
1206 return array(
1207 'error' => 'Failed to download file from Google Drive, reason: ' . $backup_file['error']
1208 );
1209 } elseif ($backup_file == false) {
1210 return array(
1211 'error' => 'Failed to download file from Google Drive.'
1212 );
1213 }
1214 }
1215
1216 $what = $tasks[$task_name]['task_args']['what'];
1217 }
1218
1219 $this->wpdb_reconnect();
1220
1221 if ($backup_file && file_exists($backup_file)) {
1222 if ($overwrite) {
1223 //Keep old db credentials before overwrite
1224 if (!copy(ABSPATH . 'wp-config.php', ABSPATH . 'mwp-temp-wp-config.php')) {
1225 @unlink($backup_file);
1226 return array(
1227 'error' => 'Error creating wp-config. Please check your write permissions.'
1228 );
1229 }
1230
1231 $db_host = DB_HOST;
1232 $db_user = DB_USER;
1233 $db_password = DB_PASSWORD;
1234 $home = rtrim(get_option('home'), "/");
1235 $site_url = get_option('site_url');
1236
1237 $clone_options = array();
1238 if (trim($clone_from_url) || trim($mwp_clone)) {
1239 $clone_options['_worker_nossl_key'] = get_option('_worker_nossl_key');
1240 $clone_options['_worker_public_key'] = get_option('_worker_public_key');
1241 $clone_options['_action_message_id'] = get_option('_action_message_id');
1242 }
1243 $clone_options['upload_path'] = get_option('upload_path');
1244 $clone_options['upload_url_path'] = get_option('upload_url_path');
1245
1246 $clone_options['mwp_backup_tasks'] = serialize(get_option('mwp_backup_tasks'));
1247 $clone_options['mwp_notifications'] = serialize(get_option('mwp_notifications'));
1248 $clone_options['mwp_pageview_alerts'] = serialize(get_option('mwp_pageview_alerts'));
1249 } else {
1250 $restore_options = array();
1251 $restore_options['mwp_notifications'] = get_option('mwp_notifications');
1252 $restore_options['mwp_pageview_alerts'] = get_option('mwp_pageview_alerts');
1253 $restore_options['user_hit_count'] = get_option('user_hit_count');
1254 }
1255
1256 chdir(ABSPATH);
1257 $unzip = $this->get_unzip();
1258 $command = "$unzip -o $backup_file";
1259 ob_start();
1260 $result = $this->mmb_exec($command);
1261 ob_get_clean();
1262
1263 if (!$result) { //fallback to pclzip
1264 $this->_log("Files uznip fallback to pclZip");
1265 define('PCLZIP_TEMPORARY_DIR', MWP_BACKUP_DIR . '/');
1266 require_once ABSPATH . '/wp-admin/includes/class-pclzip.php';
1267 $archive = new PclZip($backup_file);
1268 $result = $archive->extract(PCLZIP_OPT_PATH, ABSPATH, PCLZIP_OPT_REPLACE_NEWER);
1269 }
1270
1271 if ($unlink_file) {
1272 @unlink($backup_file);
1273 }
1274
1275 if (!$result) {
1276 return array(
1277 'error' => 'Failed to unzip files. pclZip error (' . $archive->error_code . '): .' . $archive->error_string
1278 );
1279 }
1280
1281 $db_result = $this->restore_db();
1282
1283 if (!$db_result) {
1284 return array(
1285 'error' => 'Error restoring database.'
1286 );
1287 } else if(is_array($db_result) && isset($db_result['error'])){
1288 return array(
1289 'error' => $db_result['error']
1290 );
1291 }
1292
1293 } else {
1294 return array(
1295 'error' => 'Error restoring. Cannot find backup file.'
1296 );
1297 }
1298
1299 $this->wpdb_reconnect();
1300
1301 //Replace options and content urls
1302 if ($overwrite) {
1303 //Get New Table prefix
1304 $new_table_prefix = trim($this->get_table_prefix());
1305 //Retrieve old wp_config
1306 @unlink(ABSPATH . 'wp-config.php');
1307 //Replace table prefix
1308 $lines = file(ABSPATH . 'mwp-temp-wp-config.php');
1309
1310 foreach ($lines as $line) {
1311 if (strstr($line, '$table_prefix')) {
1312 $line = '$table_prefix = "' . $new_table_prefix . '";' . PHP_EOL;
1313 }
1314 file_put_contents(ABSPATH . 'wp-config.php', $line, FILE_APPEND);
1315 }
1316
1317 @unlink(ABSPATH . 'mwp-temp-wp-config.php');
1318
1319 //Replace options
1320 $query = "SELECT option_value FROM " . $new_table_prefix . "options WHERE option_name = 'home'";
1321 $old = $wpdb->get_var($query);
1322 $old = rtrim($old, "/");
1323 $query = "UPDATE " . $new_table_prefix . "options SET option_value = %s WHERE option_name = 'home'";
1324 $wpdb->query($wpdb->prepare($query, $home));
1325 $query = "UPDATE " . $new_table_prefix . "options SET option_value = %s WHERE option_name = 'siteurl'";
1326 $wpdb->query($wpdb->prepare($query, $home));
1327 //Replace content urls
1328 $regexp1 = 'src="(.*)$old(.*)"';
1329 $regexp2 = 'href="(.*)$old(.*)"';
1330 $query = "UPDATE " . $new_table_prefix . "posts SET post_content = REPLACE (post_content, %s,%s) WHERE post_content REGEXP %s OR post_content REGEXP %s";
1331 $wpdb->query($wpdb->prepare($query, array($old, $home, $regexp1, $regexp2)));
1332
1333 if (trim($new_password)) {
1334 $new_password = wp_hash_password($new_password);
1335 }
1336 if (!trim($clone_from_url) && !trim($mwp_clone)) {
1337 if ($new_user && $new_password) {
1338 $query = "UPDATE " . $new_table_prefix . "users SET user_login = %s, user_pass = %s WHERE user_login = %s";
1339 $wpdb->query($wpdb->prepare($query, $new_user, $new_password, $old_user));
1340 }
1341 } else {
1342 if ($clone_from_url) {
1343 if ($new_user && $new_password) {
1344 $query = "UPDATE " . $new_table_prefix . "users SET user_pass = %s WHERE user_login = %s";
1345 $wpdb->query($wpdb->prepare($query, $new_password, $new_user));
1346 }
1347 }
1348
1349 if ($mwp_clone) {
1350 if ($admin_email) {
1351 //Clean Install
1352 $query = "UPDATE " . $new_table_prefix . "options SET option_value = %s WHERE option_name = 'admin_email'";
1353 $wpdb->query($wpdb->prepare($query, $admin_email));
1354 $query = "SELECT * FROM " . $new_table_prefix . "users LIMIT 1";
1355 $temp_user = $wpdb->get_row($query);
1356 if (!empty($temp_user)) {
1357 $query = "UPDATE " . $new_table_prefix . "users SET user_email=%s, user_login = %s, user_pass = %s WHERE user_login = %s";
1358 $wpdb->query($wpdb->prepare($query, $admin_email, $new_user, $new_password, $temp_user->user_login));
1359 }
1360
1361 }
1362 }
1363 }
1364
1365 if (is_array($clone_options) && !empty($clone_options)) {
1366 foreach ($clone_options as $key => $option) {
1367 if (!empty($key)) {
1368 $query = "SELECT option_value FROM " . $new_table_prefix . "options WHERE option_name = %s";
1369 $res = $wpdb->get_var($wpdb->prepare($query, $key));
1370 if ($res == false) {
1371 $query = "INSERT INTO " . $new_table_prefix . "options (option_value,option_name) VALUES(%s,%s)";
1372 $wpdb->query($wpdb->prepare($query, $option, $key));
1373 } else {
1374 $query = "UPDATE " . $new_table_prefix . "options SET option_value = %s WHERE option_name = %s";
1375 $wpdb->query($wpdb->prepare($query, $option, $key));
1376 }
1377 }
1378 }
1379 }
1380
1381 //Remove hit count
1382 $query = "DELETE FROM " . $new_table_prefix . "options WHERE option_name = 'user_hit_count'";
1383 $wpdb->query($query);
1384
1385 //Check for .htaccess permalinks update
1386 $this->replace_htaccess($home);
1387 } else {
1388 //restore worker options
1389 if (is_array($restore_options) && !empty($restore_options)) {
1390 foreach ($restore_options as $key => $option) {
1391 update_option($key, $option);
1392 }
1393 }
1394 }
1395
1396 return true;
1397 }
1398
1399 /**
1400 * This function dispathces database restoring between mysql system command and php functions.
1401 * If system command fails, it calls the php alternative.
1402 *
1403 * @return bool|array true if successful, array with error message if not
1404 */
1405 function restore_db() {
1406 global $wpdb;
1407 $paths = $this->check_mysql_paths();
1408 $file_path = ABSPATH . 'mwp_db';
1409 @chmod($file_path,0755);
1410 $file_name = glob($file_path . '/*.sql');
1411 $file_name = $file_name[0];
1412
1413 if(!$file_name){
1414 return array('error' => 'Cannot access database file.');
1415 }
1416
1417 $brace = (substr(PHP_OS, 0, 3) == 'WIN') ? '"' : '';
1418 $command = $brace . $paths['mysql'] . $brace . ' --host="' . DB_HOST . '" --user="' . DB_USER . '" --password="' . DB_PASSWORD . '" --default-character-set="utf8" ' . DB_NAME . ' < ' . $brace . $file_name . $brace;
1419
1420 ob_start();
1421 $result = $this->mmb_exec($command);
1422 ob_get_clean();
1423 if (!$result) {
1424 $this->_log('DB restore fallback to PHP');
1425 //try php
1426 $this->restore_db_php($file_name);
1427 }
1428
1429 @unlink($file_name);
1430 return true;
1431 }
1432
1433 /**
1434 * Restores database dump by php functions.
1435 *
1436 * @param string $file_name relative path to database dump, which should be restored
1437 * @return bool is successful or not
1438 */
1439 function restore_db_php($file_name) {
1440 global $wpdb;
1441 $current_query = '';
1442 // Read in entire file
1443 $lines = file($file_name);
1444 // Loop through each line
1445 foreach ($lines as $line) {
1446 // Skip it if it's a comment
1447 if (substr($line, 0, 2) == '--' || $line == '')
1448 continue;
1449
1450 // Add this line to the current query
1451 $current_query .= $line;
1452 // If it has a semicolon at the end, it's the end of the query
1453 if (substr(trim($line), -1, 1) == ';') {
1454 // Perform the query
1455 $result = $wpdb->query($current_query);
1456 if ($result === false)
1457 return false;
1458 // Reset temp variable to empty
1459 $current_query = '';
1460 }
1461 }
1462
1463 @unlink($file_name);
1464 return true;
1465 }
1466
1467 /**
1468 * Retruns table_prefix for this WordPress installation.
1469 * It is used by restore.
1470 *
1471 * @return string table prefix from wp-config.php file, (default: wp_)
1472 */
1473 function get_table_prefix() {
1474 $lines = file(ABSPATH . 'wp-config.php');
1475 foreach ($lines as $line) {
1476 if (strstr($line, '$table_prefix')) {
1477 $pattern = "/(\'|\")[^(\'|\")]*/";
1478 preg_match($pattern, $line, $matches);
1479 $prefix = substr($matches[0], 1);
1480 return $prefix;
1481 break;
1482 }
1483 }
1484 return 'wp_'; //default
1485 }
1486
1487 /**
1488 * Change all tables to InnoDB engine, and executes mysql OPTIMIZE TABLE for each table.
1489 *
1490 * @return bool optimized successfully or not
1491 */
1492 function optimize_tables() {
1493 global $wpdb;
1494 $query = 'SHOW TABLES';
1495 $tables = $wpdb->get_results($query, ARRAY_A);
1496 foreach ($tables as $table) {
1497 if (in_array($table['Engine'], array(
1498 'MyISAM',
1499 'ISAM',
1500 'HEAP',
1501 'MEMORY',
1502 'ARCHIVE'
1503 )))
1504 $table_string .= $table['Name'] . ",";
1505 elseif ($table['Engine'] == 'InnoDB') {
1506 $optimize = $wpdb->query("ALTER TABLE {$table['Name']} ENGINE=InnoDB");
1507 }
1508 }
1509
1510 $table_string = rtrim($table_string);
1511 $optimize = $wpdb->query("OPTIMIZE TABLE $table_string");
1512
1513 return $optimize ? true : false;
1514 }
1515
1516 /**
1517 * Returns mysql and mysql dump command path on OS.
1518 *
1519 * @return array array with system mysql and mysqldump command, blank if does not exist
1520 */
1521 function check_mysql_paths() {
1522 global $wpdb;
1523 $paths = array(
1524 'mysql' => '',
1525 'mysqldump' => ''
1526 );
1527 if (substr(PHP_OS, 0, 3) == 'WIN') {
1528 $mysql_install = $wpdb->get_row("SHOW VARIABLES LIKE 'basedir'");
1529 if ($mysql_install) {
1530 $install_path = str_replace('\\', '/', $mysql_install->Value);
1531 $paths['mysql'] = $install_path . 'bin/mysql.exe';
1532 $paths['mysqldump'] = $install_path . 'bin/mysqldump.exe';
1533 } else {
1534 $paths['mysql'] = 'mysql.exe';
1535 $paths['mysqldump'] = 'mysqldump.exe';
1536 }
1537 } else {
1538 $paths['mysql'] = $this->mmb_exec('which mysql', true);
1539 if (empty($paths['mysql']))
1540 $paths['mysql'] = 'mysql'; // try anyway
1541
1542 $paths['mysqldump'] = $this->mmb_exec('which mysqldump', true);
1543 if (empty($paths['mysqldump']))
1544 $paths['mysqldump'] = 'mysqldump'; // try anyway
1545 }
1546
1547 return $paths;
1548 }
1549
1550 /**
1551 * Check if exec, system, passthru functions exist
1552 *
1553 * @return string|bool exec if exists, then system, then passthru, then false if no one exist
1554 */
1555 function check_sys() {
1556 if ($this->mmb_function_exists('exec'))
1557 return 'exec';
1558
1559 if ($this->mmb_function_exists('system'))
1560 return 'system';
1561
1562 if ($this->mmb_function_exists('passhtru'))
1563 return 'passthru';
1564
1565 return false;
1566 }
1567
1568 /**
1569 * Executes an external system command.
1570 *
1571 * @param string $command external command to execute
1572 * @param bool[optional] $string return as a system output string (default: false)
1573 * @param bool[optional] $rawreturn return as a status of executed command
1574 * @return bool|int|string output depends on parameters $string and $rawreturn, -1 if no one execute function is enabled
1575 */
1576 function mmb_exec($command, $string = false, $rawreturn = false) {
1577 if ($command == '')
1578 return false;
1579
1580 if ($this->mmb_function_exists('exec')) {
1581 $log = @exec($command, $output, $return);
1582 $this->_log("Type: exec");
1583 $this->_log("Command: ".$command);
1584 $this->_log("Return: ".$return);
1585 if ($string)
1586 return $log;
1587 if ($rawreturn)
1588 return $return;
1589
1590 return $return ? false : true;
1591 } elseif ($this->mmb_function_exists('system')) {
1592 $log = @system($command, $return);
1593 $this->_log("Type: system");
1594 $this->_log("Command: ".$command);
1595 $this->_log("Return: ".$return);
1596 if ($string)
1597 return $log;
1598
1599 if ($rawreturn)
1600 return $return;
1601
1602 return $return ? false : true;
1603 } elseif ($this->mmb_function_exists('passthru') && !$string) {
1604 $log = passthru($command, $return);
1605 $this->_log("Type: passthru");
1606 $this->_log("Command: ".$command);
1607 $this->_log("Return: ".$return);
1608 if ($rawreturn)
1609 return $return;
1610
1611 return $return ? false : true;
1612 }
1613
1614 if ($rawreturn)
1615 return -1;
1616
1617 return false;
1618 }
1619
1620 /**
1621 * Returns a path to system command for zip execution.
1622 *
1623 * @return string command for zip execution
1624 */
1625 function get_zip() {
1626 $zip = $this->mmb_exec('which zip', true);
1627 if (!$zip)
1628 $zip = "zip";
1629 return $zip;
1630 }
1631
1632 /**
1633 * Returns a path to system command for unzip execution.
1634 *
1635 * @return string command for unzip execution
1636 */
1637 function get_unzip() {
1638 $unzip = $this->mmb_exec('which unzip', true);
1639 if (!$unzip)
1640 $unzip = "unzip";
1641 return $unzip;
1642 }
1643
1644 /**
1645 * Returns all important information of worker's system status to master.
1646 *
1647 * @return mixed associative array with information of server OS, php version, is backup folder writable, execute function, zip and unzip command, execution time, memory limit and path to error log if exists
1648 */
1649 function check_backup_compat() {
1650 $reqs = array();
1651 if (strpos($_SERVER['DOCUMENT_ROOT'], '/') === 0) {
1652 $reqs['Server OS']['status'] = 'Linux (or compatible)';
1653 $reqs['Server OS']['pass'] = true;
1654 } else {
1655 $reqs['Server OS']['status'] = 'Windows';
1656 $reqs['Server OS']['pass'] = true;
1657 $pass = false;
1658 }
1659 $reqs['PHP Version']['status'] = phpversion();
1660 if ((float) phpversion() >= 5.1) {
1661 $reqs['PHP Version']['pass'] = true;
1662 } else {
1663 $reqs['PHP Version']['pass'] = false;
1664 $pass = false;
1665 }
1666
1667 if (is_writable(WP_CONTENT_DIR)) {
1668 $reqs['Backup Folder']['status'] = "writable";
1669 $reqs['Backup Folder']['pass'] = true;
1670 } else {
1671 $reqs['Backup Folder']['status'] = "not writable";
1672 $reqs['Backup Folder']['pass'] = false;
1673 }
1674
1675 $file_path = MWP_BACKUP_DIR;
1676 $reqs['Backup Folder']['status'] .= ' (' . $file_path . ')';
1677
1678 if ($func = $this->check_sys()) {
1679 $reqs['Execute Function']['status'] = $func;
1680 $reqs['Execute Function']['pass'] = true;
1681 } else {
1682 $reqs['Execute Function']['status'] = "not found";
1683 $reqs['Execute Function']['info'] = "(will try PHP replacement)";
1684 $reqs['Execute Function']['pass'] = false;
1685 }
1686
1687 $reqs['Zip']['status'] = $this->get_zip();
1688 $reqs['Zip']['pass'] = true;
1689 $reqs['Unzip']['status'] = $this->get_unzip();
1690 $reqs['Unzip']['pass'] = true;
1691
1692 $paths = $this->check_mysql_paths();
1693
1694 if (!empty($paths['mysqldump'])) {
1695 $reqs['MySQL Dump']['status'] = $paths['mysqldump'];
1696 $reqs['MySQL Dump']['pass'] = true;
1697 } else {
1698 $reqs['MySQL Dump']['status'] = "not found";
1699 $reqs['MySQL Dump']['info'] = "(will try PHP replacement)";
1700 $reqs['MySQL Dump']['pass'] = false;
1701 }
1702
1703 $exec_time = ini_get('max_execution_time');
1704 $reqs['Execution time']['status'] = $exec_time ? $exec_time . "s" : 'unknown';
1705 $reqs['Execution time']['pass'] = true;
1706
1707 $mem_limit = ini_get('memory_limit');
1708 $reqs['Memory limit']['status'] = $mem_limit ? $mem_limit : 'unknown';
1709 $reqs['Memory limit']['pass'] = true;
1710
1711 $changed = $this->set_memory();
1712 if($changed['execution_time']){
1713 $exec_time = ini_get('max_execution_time');
1714 $reqs['Execution time']['status'] .= $exec_time ? ' (will try '.$exec_time . 's)' : ' (unknown)';
1715 }
1716 if($changed['memory_limit']){
1717 $mem_limit = ini_get('memory_limit');
1718 $reqs['Memory limit']['status'] .= $mem_limit ? ' (will try '.$mem_limit.')' : ' (unknown)';
1719 }
1720
1721 if(defined('MWP_SHOW_LOG') && MWP_SHOW_LOG == true){
1722 $md5 = get_option('mwp_log_md5');
1723 if ($md5 !== false) {
1724 global $mmb_plugin_url;
1725 $md5 = "<a href='$mmb_plugin_url/log_$md5' target='_blank'>$md5</a>";
1726 } else {
1727 $md5 = "not created";
1728 }
1729 $reqs['Backup Log']['status'] = $md5;
1730 $reqs['Backup Log']['pass'] = true;
1731 }
1732
1733 return $reqs;
1734 }
1735
1736 /**
1737 * Uploads backup file from server to email.
1738 * A lot of email service have limitation to 10mb.
1739 *
1740 * @param array $args arguments passed to the function
1741 * [email] -> email address which backup should send to
1742 * [task_name] -> name of backup task
1743 * [file_path] -> absolute path of backup file on local server
1744 * @return bool|array true is successful, array with error message if not
1745 */
1746 function email_backup($args) {
1747 $email = $args['email'];
1748
1749 if (!is_email($email)) {
1750 return array(
1751 'error' => 'Your email (' . $email . ') is not correct'
1752 );
1753 }
1754 $backup_file = $args['file_path'];
1755 $task_name = isset($args['task_name']) ? $args['task_name'] : '';
1756 if (file_exists($backup_file) && $email) {
1757 $attachments = array(
1758 $backup_file
1759 );
1760 $headers = 'From: ManageWP <[email protected]>' . "\r\n";
1761 $subject = "ManageWP - " . $task_name . " - " . $this->site_name;
1762 ob_start();
1763 $result = wp_mail($email, $subject, $subject, $headers, $attachments);
1764 ob_end_clean();
1765
1766 }
1767
1768 if (!$result) {
1769 return array(
1770 'error' => 'Email not sent. Maybe your backup is too big for email or email server is not available on your website.'
1771 );
1772 }
1773 return true;
1774 }
1775
1776 /**
1777 * Uploads backup file from server to remote ftp server.
1778 *
1779 * @param array $args arguments passed to the function
1780 * [ftp_username] -> ftp username on remote server
1781 * [ftp_password] -> ftp password on remote server
1782 * [ftp_hostname] -> ftp hostname of remote host
1783 * [ftp_remote_folder] -> folder on remote site which backup file should be upload to
1784 * [ftp_site_folder] -> subfolder with site name in ftp_remote_folder which backup file should be upload to
1785 * [ftp_passive] -> passive mode or not
1786 * [ftp_ssl] -> ssl or not
1787 * [ftp_port] -> number of port for ssl protocol
1788 * [backup_file] -> absolute path of backup file on local server
1789 * @return bool|array true is successful, array with error message if not
1790 */
1791 function ftp_backup($args) {
1792 extract($args);
1793
1794 $port = $ftp_port ? $ftp_port : 21; //default port is 21
1795 if ($ftp_ssl) {
1796 if (function_exists('ftp_ssl_connect')) {
1797 $conn_id = ftp_ssl_connect($ftp_hostname,$port);
1798 if ($conn_id === false) {
1799 return array(
1800 'error' => 'Failed to connect to ' . $ftp_hostname,
1801 'partial' => 1
1802 );
1803 }
1804 } else {
1805 return array(
1806 'error' => 'FTPS disabled: Please enable ftp_ssl_connect in PHP',
1807 'partial' => 1
1808 );
1809 }
1810 } else {
1811 if (function_exists('ftp_connect')) {
1812 $conn_id = ftp_connect($ftp_hostname,$port);
1813 if ($conn_id === false) {
1814 return array(
1815 'error' => 'Failed to connect to ' . $ftp_hostname,
1816 'partial' => 1
1817 );
1818 }
1819 } else {
1820 return array(
1821 'error' => 'FTP disabled: Please enable ftp_connect in PHP',
1822 'partial' => 1
1823 );
1824 }
1825 }
1826 $login = @ftp_login($conn_id, $ftp_username, $ftp_password);
1827 if ($login === false) {
1828 return array(
1829 'error' => 'FTP login failed for ' . $ftp_username . ', ' . $ftp_password,
1830 'partial' => 1
1831 );
1832 }
1833
1834 if($ftp_passive){
1835 @ftp_pasv($conn_id,true);
1836 }
1837
1838 @ftp_mkdir($conn_id, $ftp_remote_folder);
1839 if ($ftp_site_folder) {
1840 $ftp_remote_folder .= '/' . $this->site_name;
1841 }
1842 @ftp_mkdir($conn_id, $ftp_remote_folder);
1843
1844 $upload = @ftp_put($conn_id, $ftp_remote_folder . '/' . basename($backup_file), $backup_file, FTP_BINARY);
1845
1846 if ($upload === false) { //Try ascii
1847 $upload = @ftp_put($conn_id, $ftp_remote_folder . '/' . basename($backup_file), $backup_file, FTP_ASCII);
1848 }
1849 @ftp_close($conn_id);
1850
1851 if ($upload === false) {
1852 return array(
1853 'error' => 'Failed to upload file to FTP. Please check your specified path.',
1854 'partial' => 1
1855 );
1856 }
1857
1858 return true;
1859 }
1860
1861 /**
1862 * Deletes backup file from remote ftp server.
1863 *
1864 * @param array $args arguments passed to the function
1865 * [ftp_username] -> ftp username on remote server
1866 * [ftp_password] -> ftp password on remote server
1867 * [ftp_hostname] -> ftp hostname of remote host
1868 * [ftp_remote_folder] -> folder on remote site which backup file should be deleted from
1869 * [ftp_site_folder] -> subfolder with site name in ftp_remote_folder which backup file should be deleted from
1870 * [backup_file] -> absolute path of backup file on local server
1871 * @return void
1872 */
1873 function remove_ftp_backup($args) {
1874 extract($args);
1875
1876 $port = $ftp_port ? $ftp_port : 21; //default port is 21
1877 if ($ftp_ssl && function_exists('ftp_ssl_connect')) {
1878 $conn_id = ftp_ssl_connect($ftp_hostname,$port);
1879 } else if (function_exists('ftp_connect')) {
1880 $conn_id = ftp_connect($ftp_hostname,$port);
1881 }
1882
1883 if ($conn_id) {
1884 $login = @ftp_login($conn_id, $ftp_username, $ftp_password);
1885 if ($ftp_site_folder)
1886 $ftp_remote_folder .= '/' . $this->site_name;
1887
1888 if($ftp_passive){
1889 @ftp_pasv($conn_id,true);
1890 }
1891
1892 $delete = ftp_delete($conn_id, $ftp_remote_folder . '/' . $backup_file);
1893
1894 ftp_close($conn_id);
1895 }
1896 }
1897
1898 /**
1899 * Downloads backup file from server from remote ftp server to root folder on local server.
1900 *
1901 * @param array $args arguments passed to the function
1902 * [ftp_username] -> ftp username on remote server
1903 * [ftp_password] -> ftp password on remote server
1904 * [ftp_hostname] -> ftp hostname of remote host
1905 * [ftp_remote_folder] -> folder on remote site which backup file should be downloaded from
1906 * [ftp_site_folder] -> subfolder with site name in ftp_remote_folder which backup file should be downloaded from
1907 * [backup_file] -> absolute path of backup file on local server
1908 * @return string|array absolute path to downloaded file is successful, array with error message if not
1909 */
1910 function get_ftp_backup($args) {
1911 extract($args);
1912
1913 $port = $ftp_port ? $ftp_port : 21; //default port is 21
1914 if ($ftp_ssl && function_exists('ftp_ssl_connect')) {
1915 $conn_id = ftp_ssl_connect($ftp_hostname,$port);
1916
1917 } else if (function_exists('ftp_connect')) {
1918 $conn_id = ftp_connect($ftp_hostname,$port);
1919 if ($conn_id === false) {
1920 return false;
1921 }
1922 }
1923 $login = @ftp_login($conn_id, $ftp_username, $ftp_password);
1924 if ($login === false) {
1925 return false;
1926 }
1927
1928 if ($ftp_site_folder)
1929 $ftp_remote_folder .= '/' . $this->site_name;
1930
1931 if($ftp_passive){
1932 @ftp_pasv($conn_id,true);
1933 }
1934
1935 $temp = ABSPATH . 'mwp_temp_backup.zip';
1936 $get = ftp_get($conn_id, $temp, $ftp_remote_folder . '/' . $backup_file, FTP_BINARY);
1937 if ($get === false) {
1938 return false;
1939 }
1940
1941 ftp_close($conn_id);
1942
1943 return $temp;
1944 }
1945
1946 /**
1947 * Uploads backup file from server to Dropbox.
1948 *
1949 * @param array $args arguments passed to the function
1950 * [consumer_key] -> consumer key of ManageWP Dropbox application
1951 * [consumer_secret] -> consumer secret of ManageWP Dropbox application
1952 * [oauth_token] -> oauth token of user on ManageWP Dropbox application
1953 * [oauth_token_secret] -> oauth token secret of user on ManageWP Dropbox application
1954 * [dropbox_destination] -> folder on user's Dropbox account which backup file should be upload to
1955 * [dropbox_site_folder] -> subfolder with site name in dropbox_destination which backup file should be upload to
1956 * [backup_file] -> absolute path of backup file on local server
1957 * @return bool|array true is successful, array with error message if not
1958 */
1959 function dropbox_backup($args) {
1960 extract($args);
1961
1962 global $mmb_plugin_dir;
1963 require_once $mmb_plugin_dir . '/lib/dropbox.php';
1964
1965 $dropbox = new Dropbox($consumer_key, $consumer_secret);
1966 $dropbox->setOAuthTokens($oauth_token, $oauth_token_secret);
1967
1968 if ($dropbox_site_folder == true)
1969 $dropbox_destination .= '/' . $this->site_name . '/' . basename($backup_file);
1970 else
1971 $dropbox_destination .= '/' . basename($backup_file);
1972
1973 try {
1974 $dropbox->upload($backup_file, $dropbox_destination, true);
1975 } catch (Exception $e) {
1976 $this->_log($e->getMessage());
1977 return array(
1978 'error' => $e->getMessage(),
1979 'partial' => 1
1980 );
1981 }
1982
1983 return true;
1984 }
1985
1986 /**
1987 * Deletes backup file from Dropbox to root folder on local server.
1988 *
1989 * @param array $args arguments passed to the function
1990 * [consumer_key] -> consumer key of ManageWP Dropbox application
1991 * [consumer_secret] -> consumer secret of ManageWP Dropbox application
1992 * [oauth_token] -> oauth token of user on ManageWP Dropbox application
1993 * [oauth_token_secret] -> oauth token secret of user on ManageWP Dropbox application
1994 * [dropbox_destination] -> folder on user's Dropbox account which backup file should be downloaded from
1995 * [dropbox_site_folder] -> subfolder with site name in dropbox_destination which backup file should be downloaded from
1996 * [backup_file] -> absolute path of backup file on local server
1997 * @return void
1998 */
1999 function remove_dropbox_backup($args) {
2000 extract($args);
2001
2002 global $mmb_plugin_dir;
2003 require_once $mmb_plugin_dir . '/lib/dropbox.php';
2004
2005 $dropbox = new Dropbox($consumer_key, $consumer_secret);
2006 $dropbox->setOAuthTokens($oauth_token, $oauth_token_secret);
2007
2008 if ($dropbox_site_folder == true)
2009 $dropbox_destination .= '/' . $this->site_name;
2010
2011 try {
2012 $dropbox->fileopsDelete($dropbox_destination . '/' . $backup_file);
2013 } catch (Exception $e) {
2014 $this->_log($e->getMessage());
2015 /*return array(
2016 'error' => $e->getMessage(),
2017 'partial' => 1
2018 );*/
2019 }
2020
2021 //return true;
2022 }
2023
2024 /**
2025 * Downloads backup file from Dropbox to root folder on local server.
2026 *
2027 * @param array $args arguments passed to the function
2028 * [consumer_key] -> consumer key of ManageWP Dropbox application
2029 * [consumer_secret] -> consumer secret of ManageWP Dropbox application
2030 * [oauth_token] -> oauth token of user on ManageWP Dropbox application
2031 * [oauth_token_secret] -> oauth token secret of user on ManageWP Dropbox application
2032 * [dropbox_destination] -> folder on user's Dropbox account which backup file should be deleted from
2033 * [dropbox_site_folder] -> subfolder with site name in dropbox_destination which backup file should be deleted from
2034 * [backup_file] -> absolute path of backup file on local server
2035 * @return bool|array absolute path to downloaded file is successful, array with error message if not
2036 */
2037 function get_dropbox_backup($args) {
2038 extract($args);
2039
2040 global $mmb_plugin_dir;
2041 require_once $mmb_plugin_dir . '/lib/dropbox.php';
2042
2043 $dropbox = new Dropbox($consumer_key, $consumer_secret);
2044 $dropbox->setOAuthTokens($oauth_token, $oauth_token_secret);
2045
2046 if ($dropbox_site_folder == true)
2047 $dropbox_destination .= '/' . $this->site_name;
2048
2049 $temp = ABSPATH . 'mwp_temp_backup.zip';
2050
2051 try {
2052 $file = $dropbox->download($dropbox_destination.'/'.$backup_file);
2053 $handle = @fopen($temp, 'w');
2054 $result = fwrite($handle,$file);
2055 fclose($handle);
2056
2057 if($result)
2058 return $temp;
2059 else
2060 return false;
2061 } catch (Exception $e) {
2062 $this->_log($e->getMessage());
2063 return array(
2064 'error' => $e->getMessage(),
2065 'partial' => 1
2066 );
2067 }
2068 }
2069
2070 /**
2071 * Uploads backup file from server to Amazon S3.
2072 *
2073 * @param array $args arguments passed to the function
2074 * [as3_bucket_region] -> Amazon S3 bucket region
2075 * [as3_bucket] -> Amazon S3 bucket
2076 * [as3_access_key] -> Amazon S3 access key
2077 * [as3_secure_key] -> Amazon S3 secure key
2078 * [as3_directory] -> folder on user's Amazon S3 account which backup file should be upload to
2079 * [as3_site_folder] -> subfolder with site name in as3_directory which backup file should be upload to
2080 * [backup_file] -> absolute path of backup file on local server
2081 * @return bool|array true is successful, array with error message if not
2082 */
2083 function amazons3_backup($args) {
2084 if ($this->mmb_function_exists('curl_init')) {
2085 require_once('lib/s3.php');
2086 extract($args);
2087
2088 if ($as3_site_folder == true)
2089 $as3_directory .= '/' . $this->site_name;
2090
2091 $endpoint = isset($as3_bucket_region) ? $as3_bucket_region : 's3.amazonaws.com';
2092 try{
2093 $s3 = new mwpS3(trim($as3_access_key), trim(str_replace(' ', '+', $as3_secure_key)), false, $endpoint);
2094 if ($s3->putObjectFile($backup_file, $as3_bucket, $as3_directory . '/' . basename($backup_file), mwpS3::ACL_PRIVATE)) {
2095 return true;
2096 } else {
2097 return array(
2098 'error' => 'Failed to upload to Amazon S3. Please check your details and set upload/delete permissions on your bucket.',
2099 'partial' => 1
2100 );
2101 }
2102 } catch (Exception $e) {
2103 $err = $e->getMessage();
2104 if($err){
2105 return array(
2106 'error' => 'Failed to upload to AmazonS3 ('.$err.').'
2107 );
2108 } else {
2109 return array(
2110 'error' => 'Failed to upload to Amazon S3.'
2111 );
2112 }
2113 }
2114
2115 } else {
2116 return array(
2117 'error' => 'You cannot use Amazon S3 on your server. Please enable curl extension first.',
2118 'partial' => 1
2119 );
2120 }
2121 }
2122
2123 /**
2124 * Deletes backup file from Amazon S3.
2125 *
2126 * @param array $args arguments passed to the function
2127 * [as3_bucket_region] -> Amazon S3 bucket region
2128 * [as3_bucket] -> Amazon S3 bucket
2129 * [as3_access_key] -> Amazon S3 access key
2130 * [as3_secure_key] -> Amazon S3 secure key
2131 * [as3_directory] -> folder on user's Amazon S3 account which backup file should be deleted from
2132 * [as3_site_folder] -> subfolder with site name in as3_directory which backup file should be deleted from
2133 * [backup_file] -> absolute path of backup file on local server
2134 * @return void
2135 */
2136 function remove_amazons3_backup($args) {
2137 if ($this->mmb_function_exists('curl_init')) {
2138 require_once('lib/s3.php');
2139 extract($args);
2140 if ($as3_site_folder == true)
2141 $as3_directory .= '/' . $this->site_name;
2142 $endpoint = isset($as3_bucket_region) ? $as3_bucket_region : 's3.amazonaws.com';
2143 try {
2144 $s3 = new mwpS3(trim($as3_access_key), trim(str_replace(' ', '+', $as3_secure_key)), false, $endpoint);
2145 $s3->deleteObject($as3_bucket, $as3_directory . '/' . $backup_file);
2146 } catch (Exception $e){
2147
2148 }
2149 }
2150 }
2151
2152 /**
2153 * Downloads backup file from Amazon S3 to root folder on local server.
2154 *
2155 * @param array $args arguments passed to the function
2156 * [as3_bucket_region] -> Amazon S3 bucket region
2157 * [as3_bucket] -> Amazon S3 bucket
2158 * [as3_access_key] -> Amazon S3 access key
2159 * [as3_secure_key] -> Amazon S3 secure key
2160 * [as3_directory] -> folder on user's Amazon S3 account which backup file should be downloaded from
2161 * [as3_site_folder] -> subfolder with site name in as3_directory which backup file should be downloaded from
2162 * [backup_file] -> absolute path of backup file on local server
2163 * @return bool|array absolute path to downloaded file is successful, array with error message if not
2164 */
2165 function get_amazons3_backup($args) {
2166 require_once('lib/s3.php');
2167 extract($args);
2168 $endpoint = isset($as3_bucket_region) ? $as3_bucket_region : 's3.amazonaws.com';
2169 $temp = '';
2170 try {
2171 $s3 = new mwpS3($as3_access_key, str_replace(' ', '+', $as3_secure_key), false, $endpoint);
2172 if ($as3_site_folder == true)
2173 $as3_directory .= '/' . $this->site_name;
2174
2175 $temp = ABSPATH . 'mwp_temp_backup.zip';
2176 $s3->getObject($as3_bucket, $as3_directory . '/' . $backup_file, $temp);
2177 } catch (Exception $e) {
2178 return $temp;
2179 }
2180 return $temp;
2181 }
2182
2183 /**
2184 * Uploads backup file from server to Google Drive.
2185 *
2186 * @param array $args arguments passed to the function
2187 * [google_drive_token] -> user's Google drive token in json form
2188 * [google_drive_directory] -> folder on user's Google Drive account which backup file should be upload to
2189 * [google_drive_site_folder] -> subfolder with site name in google_drive_directory which backup file should be upload to
2190 * [backup_file] -> absolute path of backup file on local server
2191 * @return bool|array true is successful, array with error message if not
2192 */
2193 function google_drive_backup($args) {
2194 extract($args);
2195
2196 global $mmb_plugin_dir;
2197 require_once("$mmb_plugin_dir/lib/google-api-client/Google_Client.php");
2198 require_once("$mmb_plugin_dir/lib/google-api-client/contrib/Google_DriveService.php");
2199
2200 $gdrive_client = new Google_Client();
2201 $gdrive_client->setUseObjects(true);
2202 $gdrive_client->setAccessToken($google_drive_token);
2203
2204 $gdrive_service = new Google_DriveService($gdrive_client);
2205
2206 try {
2207 $about = $gdrive_service->about->get();
2208 $root_folder_id = $about->getRootFolderId();
2209 } catch (Exception $e) {
2210 return array(
2211 'error' => $e->getMessage(),
2212 );
2213 }
2214
2215 try {
2216 $list_files = $gdrive_service->files->listFiles(array("q"=>"title='$google_drive_directory' and '$root_folder_id' in parents and trashed = false"));
2217 $files = $list_files->getItems();
2218 } catch (Exception $e) {
2219 return array(
2220 'error' => $e->getMessage(),
2221 );
2222 }
2223 if (isset($files[0])) {
2224 $managewp_folder = $files[0];
2225 }
2226
2227 if (!isset($managewp_folder)) {
2228 try {
2229 $_managewp_folder = new Google_DriveFile();
2230 $_managewp_folder->setTitle($google_drive_directory);
2231 $_managewp_folder->setMimeType('application/vnd.google-apps.folder');
2232
2233 if ($root_folder_id != null) {
2234 $parent = new Google_ParentReference();
2235 $parent->setId($root_folder_id);
2236 $_managewp_folder->setParents(array($parent));
2237 }
2238
2239 $managewp_folder = $gdrive_service->files->insert($_managewp_folder, array());
2240 } catch (Exception $e) {
2241 return array(
2242 'error' => $e->getMessage(),
2243 );
2244 }
2245 }
2246
2247 if ($google_drive_site_folder) {
2248 try {
2249 $subfolder_title = $this->site_name;
2250 $managewp_folder_id = $managewp_folder->getId();
2251 $list_files = $gdrive_service->files->listFiles(array("q"=>"title='$subfolder_title' and '$managewp_folder_id' in parents and trashed = false"));
2252 $files = $list_files->getItems();
2253 } catch (Exception $e) {
2254 return array(
2255 'error' => $e->getMessage(),
2256 );
2257 }
2258 if (isset($files[0])) {
2259 $backup_folder = $files[0];
2260 } else {
2261 try {
2262 $_backup_folder = new Google_DriveFile();
2263 $_backup_folder->setTitle($subfolder_title);
2264 $_backup_folder->setMimeType('application/vnd.google-apps.folder');
2265
2266 if (isset($managewp_folder)) {
2267 $_backup_folder->setParents(array($managewp_folder));
2268 }
2269
2270 $backup_folder = $gdrive_service->files->insert($_backup_folder, array());
2271 } catch (Exception $e) {
2272 return array(
2273 'error' => $e->getMessage(),
2274 );
2275 }
2276 }
2277 } else {
2278 $backup_folder = $managewp_folder;
2279 }
2280
2281 $file_path = explode('/', $backup_file);
2282 $new_file = new Google_DriveFile();
2283 $new_file->setTitle(end($file_path));
2284 $new_file->setDescription('Backup file of site: ' . $this->site_name . '.');
2285
2286 if ($backup_folder != null) {
2287 $new_file->setParents(array($backup_folder));
2288 }
2289
2290 $tries = 1;
2291
2292 while($tries <= 2) {
2293 try {
2294 $data = file_get_contents($backup_file);
2295
2296 $createdFile = $gdrive_service->files->insert($new_file, array(
2297 'data' => $data,
2298 ));
2299
2300 break;
2301 } catch (Exception $e) {
2302 if ($e->getCode() >= 500 && $e->getCode() <= 504 && $mmb_gdrive_upload_tries <= 2) {
2303 sleep(2);
2304 $tries++;
2305 } else {
2306 return array(
2307 'error' => $e->getMessage(),
2308 );
2309 }
2310 }
2311 }
2312
2313 return true;
2314 }
2315
2316 /**
2317 * Deletes backup file from Google Drive.
2318 *
2319 * @param array $args arguments passed to the function
2320 * [google_drive_token] -> user's Google drive token in json form
2321 * [google_drive_directory] -> folder on user's Google Drive account which backup file should be deleted from
2322 * [google_drive_site_folder] -> subfolder with site name in google_drive_directory which backup file should be deleted from
2323 * [backup_file] -> absolute path of backup file on local server
2324 * @return void
2325 */
2326 function remove_google_drive_backup($args) {
2327 extract($args);
2328
2329 global $mmb_plugin_dir;
2330 require_once("$mmb_plugin_dir/lib/google-api-client/Google_Client.php");
2331 require_once("$mmb_plugin_dir/lib/google-api-client/contrib/Google_DriveService.php");
2332
2333 try {
2334 $gdrive_client = new Google_Client();
2335 $gdrive_client->setUseObjects(true);
2336 $gdrive_client->setAccessToken($google_drive_token);
2337 } catch (Exception $e) {
2338 $this->_log($e->getMessage());
2339 /*eturn array(
2340 'error' => $e->getMessage(),
2341 );*/
2342 }
2343
2344 $gdrive_service = new Google_DriveService($gdrive_client);
2345
2346 try {
2347 $about = $gdrive_service->about->get();
2348 $root_folder_id = $about->getRootFolderId();
2349 } catch (Exception $e) {
2350 $this->_log($e->getMessage());
2351 /*return array(
2352 'error' => $e->getMessage(),
2353 );*/
2354 }
2355
2356 try {
2357 $list_files = $gdrive_service->files->listFiles(array("q"=>"title='$google_drive_directory' and '$root_folder_id' in parents and trashed = false"));
2358 $files = $list_files->getItems();
2359 } catch (Exception $e) {
2360 $this->_log($e->getMessage());
2361 /*return array(
2362 'error' => $e->getMessage(),
2363 );*/
2364 }
2365 if (isset($files[0])) {
2366 $managewp_folder = $files[0];
2367 } else {
2368 $this->_log("This file does not exist.");
2369 /*return array(
2370 'error' => "This file does not exist.",
2371 );*/
2372 }
2373
2374 if ($google_drive_site_folder) {
2375 try {
2376 $subfolder_title = $this->site_name;
2377 $managewp_folder_id = $managewp_folder->getId();
2378 $list_files = $gdrive_service->files->listFiles(array("q"=>"title='$subfolder_title' and '$managewp_folder_id' in parents and trashed = false"));
2379 $files = $list_files->getItems();
2380 } catch (Exception $e) {
2381 $this->_log($e->getMessage());
2382 /*return array(
2383 'error' => $e->getMessage(),
2384 );*/
2385 }
2386 if (isset($files[0])) {
2387 $backup_folder = $files[0];
2388 }
2389 } else {
2390 $backup_folder = $managewp_folder;
2391 }
2392
2393 if (isset($backup_folder)) {
2394 try {
2395 $backup_folder_id = $backup_folder->getId();
2396 $list_files = $gdrive_service->files->listFiles(array("q"=>"title='$backup_file' and '$backup_folder_id' in parents and trashed = false"));
2397 $files = $list_files->getItems();;
2398 } catch (Exception $e) {
2399 $this->_log($e->getMessage());
2400 /*return array(
2401 'error' => $e->getMessage(),
2402 );*/
2403 }
2404 if (isset($files[0])) {
2405 try {
2406 $gdrive_service->files->delete($files[0]->getId());
2407 } catch (Exception $e) {
2408 $this->_log($e->getMessage());
2409 /*return array(
2410 'error' => $e->getMessage(),
2411 );*/
2412 }
2413 } else {
2414 $this->_log("This file does not exist.");
2415 /*return array(
2416 'error' => "This file does not exist.",
2417 );*/
2418 }
2419 } else {
2420 $this->_log("This file does not exist.");
2421 /*return array(
2422 'error' => "This file does not exist.",
2423 );*/
2424 }
2425
2426 //return true;
2427 }
2428
2429 /**
2430 * Downloads backup file from Google Drive to root folder on local server.
2431 *
2432 * @param array $args arguments passed to the function
2433 * [google_drive_token] -> user's Google drive token in json form
2434 * [google_drive_directory] -> folder on user's Google Drive account which backup file should be downloaded from
2435 * [google_drive_site_folder] -> subfolder with site name in google_drive_directory which backup file should be downloaded from
2436 * [backup_file] -> absolute path of backup file on local server
2437 * @return bool|array absolute path to downloaded file is successful, array with error message if not
2438 */
2439 function get_google_drive_backup($args) {
2440 extract($args);
2441
2442 global $mmb_plugin_dir;
2443 require_once("$mmb_plugin_dir/lib/google-api-client/Google_Client.php");
2444 require_once("$mmb_plugin_dir/lib/google-api-client/contrib/Google_DriveService.php");
2445
2446 try {
2447 $gdrive_client = new Google_Client();
2448 $gdrive_client->setUseObjects(true);
2449 $gdrive_client->setAccessToken($google_drive_token);
2450 } catch (Exception $e) {
2451 return array(
2452 'error' => $e->getMessage(),
2453 );
2454 }
2455
2456 $gdrive_service = new Google_DriveService($gdrive_client);
2457
2458 try {
2459 $about = $gdrive_service->about->get();
2460 $root_folder_id = $about->getRootFolderId();
2461 } catch (Exception $e) {
2462 return array(
2463 'error' => $e->getMessage(),
2464 );
2465 }
2466
2467 try {
2468 $list_files = $gdrive_service->files->listFiles(array("q"=>"title='$google_drive_directory' and '$root_folder_id' in parents and trashed = false"));
2469 $files = $list_files->getItems();
2470 } catch (Exception $e) {
2471 return array(
2472 'error' => $e->getMessage(),
2473 );
2474 }
2475 if (isset($files[0])) {
2476 $managewp_folder = $files[0];
2477 } else {
2478 return array(
2479 'error' => "This file does not exist.",
2480 );
2481 }
2482
2483 if ($google_drive_site_folder) {
2484 try {
2485 $subfolder_title = $this->site_name;
2486 $managewp_folder_id = $managewp_folder->getId();
2487 $list_files = $gdrive_service->files->listFiles(array("q"=>"title='$subfolder_title' and '$managewp_folder_id' in parents and trashed = false"));
2488 $files = $list_files->getItems();
2489 } catch (Exception $e) {
2490 return array(
2491 'error' => $e->getMessage(),
2492 );
2493 }
2494 if (isset($files[0])) {
2495 $backup_folder = $files[0];
2496 }
2497 } else {
2498 $backup_folder = $managewp_folder;
2499 }
2500
2501 if (isset($backup_folder)) {
2502 try {
2503 $backup_folder_id = $backup_folder->getId();
2504 $list_files = $gdrive_service->files->listFiles(array("q"=>"title='$backup_file' and '$backup_folder_id' in parents and trashed = false"));
2505 $files = $list_files->getItems();
2506 } catch (Exception $e) {
2507 return array(
2508 'error' => $e->getMessage(),
2509 );
2510 }
2511 if (isset($files[0])) {
2512 try {
2513 $download_url = $files[0]->getDownloadUrl();
2514 if ($download_url) {
2515 $request = new Google_HttpRequest($download_url, 'GET', null, null);
2516 $http_request = Google_Client::$io->authenticatedRequest($request);
2517 if ($http_request->getResponseHttpCode() == 200) {
2518 $stream = $http_request->getResponseBody();
2519 $local_destination = ABSPATH . 'mwp_temp_backup.zip';
2520 $handle = @fopen($local_destination, 'w+');
2521 $result = fwrite($handle, $stream);
2522 fclose($handle);
2523 if($result)
2524 return $local_destination;
2525 else
2526 return array(
2527 'error' => "Write permission error.",
2528 );
2529 } else {
2530 return array(
2531 'error' => "This file does not exist.",
2532 );
2533 }
2534 } else {
2535 return array(
2536 'error' => "This file does not exist.",
2537 );
2538 }
2539 } catch (Exception $e) {
2540 return array(
2541 'error' => $e->getMessage(),
2542 );
2543 }
2544 } else {
2545 return array(
2546 'error' => "This file does not exist.",
2547 );
2548 }
2549 } else {
2550 return array(
2551 'error' => "This file does not exist.",
2552 );
2553 }
2554
2555 return false;
2556 }
2557
2558 /**
2559 * Schedules the next execution of some backup task.
2560 *
2561 * @param string $type daily, weekly or monthly
2562 * @param string $schedule format: task_time (if daily), task_time|task_day (if weekly), task_time|task_date (if monthly)
2563 * @return bool|int timestamp if sucessful, false if not
2564 */
2565 function schedule_next($type, $schedule) {
2566 $schedule = explode("|", $schedule);
2567
2568 if (empty($schedule))
2569 return false;
2570 switch ($type) {
2571 case 'daily':
2572 if (isset($schedule[1]) && $schedule[1]) {
2573 $delay_time = $schedule[1] * 60;
2574 }
2575
2576 $current_hour = date("H");
2577 $schedule_hour = $schedule[0];
2578 if ($current_hour >= $schedule_hour)
2579 $time = mktime($schedule_hour, 0, 0, date("m"), date("d") + 1, date("Y"));
2580 else
2581 $time = mktime($schedule_hour, 0, 0, date("m"), date("d"), date("Y"));
2582 break;
2583
2584 case 'weekly':
2585 if (isset($schedule[2]) && $schedule[2]) {
2586 $delay_time = $schedule[2] * 60;
2587 }
2588 $current_weekday = date('w');
2589 $schedule_weekday = $schedule[1];
2590 $current_hour = date("H");
2591 $schedule_hour = $schedule[0];
2592
2593 if ($current_weekday > $schedule_weekday)
2594 $weekday_offset = 7 - ($week_day - $task_schedule[1]);
2595 else
2596 $weekday_offset = $schedule_weekday - $current_weekday;
2597
2598 if (!$weekday_offset) { //today is scheduled weekday
2599 if ($current_hour >= $schedule_hour)
2600 $time = mktime($schedule_hour, 0, 0, date("m"), date("d") + 7, date("Y"));
2601 else
2602 $time = mktime($schedule_hour, 0, 0, date("m"), date("d"), date("Y"));
2603 } else {
2604 $time = mktime($schedule_hour, 0, 0, date("m"), date("d") + $weekday_offset, date("Y"));
2605 }
2606 break;
2607
2608 case 'monthly':
2609 if (isset($schedule[2]) && $schedule[2]) {
2610 $delay_time = $schedule[2] * 60;
2611 }
2612 $current_monthday = date('j');
2613 $schedule_monthday = $schedule[1];
2614 $current_hour = date("H");
2615 $schedule_hour = $schedule[0];
2616
2617 if ($current_monthday > $schedule_monthday) {
2618 $time = mktime($schedule_hour, 0, 0, date("m") + 1, $schedule_monthday, date("Y"));
2619 } else if ($current_monthday < $schedule_monthday) {
2620 $time = mktime($schedule_hour, 0, 0, date("m"), $schedule_monthday, date("Y"));
2621 } else if ($current_monthday == $schedule_monthday) {
2622 if ($current_hour >= $schedule_hour)
2623 $time = mktime($schedule_hour, 0, 0, date("m") + 1, $schedule_monthday, date("Y"));
2624 else
2625 $time = mktime($schedule_hour, 0, 0, date("m"), $schedule_monthday, date("Y"));
2626 break;
2627 }
2628
2629 break;
2630
2631 default:
2632 break;
2633 }
2634
2635 if (isset($delay_time) && $delay_time) {
2636 $time += $delay_time;
2637 }
2638
2639 return $time;
2640 }
2641
2642 /**
2643 * Parse task arguments for info on master.
2644 *
2645 * @return mixed associative array with stats for every backup task or error if backup is manually deleted on server
2646 */
2647 function get_backup_stats() {
2648 $stats = array();
2649 $tasks = $this->tasks;
2650 if (is_array($tasks) && !empty($tasks)) {
2651 foreach ($tasks as $task_name => $info) {
2652 if (is_array($info['task_results']) && !empty($info['task_results'])) {
2653 foreach ($info['task_results'] as $key => $result) {
2654 if (isset($result['server']) && !isset($result['error'])) {
2655 if (isset($result['server']['file_path']) && !$info['task_args']['del_host_file']) {
2656 if (!file_exists($result['server']['file_path'])) {
2657 $info['task_results'][$key]['error'] = 'Backup created but manually removed from server.';
2658 }
2659 }
2660 }
2661 }
2662 }
2663 if (is_array($info['task_results']))
2664 $stats[$task_name] = array_values($info['task_results']);
2665 }
2666 }
2667 return $stats;
2668 }
2669
2670 /**
2671 * Returns all backup tasks with information when the next schedule will be.
2672 *
2673 * @return mixed associative array with timestamp with next schedule for every backup task
2674 */
2675 function get_next_schedules() {
2676 $stats = array();
2677 $tasks = $this->tasks;
2678 if (is_array($tasks) && !empty($tasks)) {
2679 foreach ($tasks as $task_name => $info) {
2680 $stats[$task_name] = isset($info['task_args']['next']) ? $info['task_args']['next'] : array();
2681 }
2682 }
2683 return $stats;
2684 }
2685
2686 /**
2687 * Deletes all old backups from local server.
2688 * It depends on configuration on master (Number of backups to keep).
2689 *
2690 * @param string $task_name name of backup task
2691 * @return bool|void true if there are backups for deletion, void if not
2692 */
2693 function remove_old_backups($task_name) {
2694 //Check for previous failed backups first
2695 $this->cleanup();
2696
2697 //Remove by limit
2698 $backups = $this->tasks;
2699 if ($task_name == 'Backup Now') {
2700 $num = 0;
2701 } else {
2702 $num = 1;
2703 }
2704
2705 if ((count($backups[$task_name]['task_results']) - $num) >= $backups[$task_name]['task_args']['limit']) {
2706 //how many to remove ?
2707 $remove_num = (count($backups[$task_name]['task_results']) - $num - $backups[$task_name]['task_args']['limit']) + 1;
2708 for ($i = 0; $i < $remove_num; $i++) {
2709 //Remove from the server
2710 if (isset($backups[$task_name]['task_results'][$i]['server'])) {
2711 @unlink($backups[$task_name]['task_results'][$i]['server']['file_path']);
2712 }
2713
2714 //Remove from ftp
2715 if (isset($backups[$task_name]['task_results'][$i]['ftp']) && isset($backups[$task_name]['task_args']['account_info']['mwp_ftp'])) {
2716 $ftp_file = $backups[$task_name]['task_results'][$i]['ftp'];
2717 $args = $backups[$task_name]['task_args']['account_info']['mwp_ftp'];
2718 $args['backup_file'] = $ftp_file;
2719 $this->remove_ftp_backup($args);
2720 }
2721
2722 if (isset($backups[$task_name]['task_results'][$i]['amazons3']) && isset($backups[$task_name]['task_args']['account_info']['mwp_amazon_s3'])) {
2723 $amazons3_file = $backups[$task_name]['task_results'][$i]['amazons3'];
2724 $args = $backups[$task_name]['task_args']['account_info']['mwp_amazon_s3'];
2725 $args['backup_file'] = $amazons3_file;
2726 $this->remove_amazons3_backup($args);
2727 }
2728
2729 if (isset($backups[$task_name]['task_results'][$i]['dropbox']) && isset($backups[$task_name]['task_args']['account_info']['mwp_dropbox'])) {
2730 //To do: dropbox remove
2731 $dropbox_file = $backups[$task_name]['task_results'][$i]['dropbox'];
2732 $args = $backups[$task_name]['task_args']['account_info']['mwp_dropbox'];
2733 $args['backup_file'] = $dropbox_file;
2734 $this->remove_dropbox_backup($args);
2735 }
2736
2737 if (isset($backups[$task_name]['task_results'][$i]['google_drive']) && isset($backups[$task_name]['task_args']['account_info']['mwp_google_drive'])) {
2738 $google_drive_file = $backups[$task_name]['task_results'][$i]['google_drive'];
2739 $args = $backups[$task_name]['task_args']['account_info']['mwp_google_drive'];
2740 $args['backup_file'] = $google_drive_file;
2741 $this->remove_google_drive_backup($args);
2742 }
2743
2744 //Remove database backup info
2745 unset($backups[$task_name]['task_results'][$i]);
2746 } //end foreach
2747
2748 if (is_array($backups[$task_name]['task_results']))
2749 $backups[$task_name]['task_results'] = array_values($backups[$task_name]['task_results']);
2750 else
2751 $backups[$task_name]['task_results']=array();
2752
2753 $this->update_tasks($backups);
2754
2755 return true;
2756 }
2757 }
2758
2759 /**
2760 * Deletes specified backup.
2761 *
2762 * @param array $args arguments passed to function
2763 * [task_name] -> name of backup task
2764 * [result_id] -> id of baskup task result, which should be restored
2765 * [google_drive_token] -> json of Google Drive token, if it is remote destination
2766 * @return bool true if successful, false if not
2767 */
2768 function delete_backup($args) {
2769 if (empty($args))
2770 return false;
2771 extract($args);
2772 if (isset($google_drive_token)) {
2773 $this->tasks[$task_name]['task_args']['account_info']['mwp_google_drive']['google_drive_token'] = $google_drive_token;
2774 }
2775
2776 $tasks = $this->tasks;
2777 $task = $tasks[$task_name];
2778 $backups = $task['task_results'];
2779 $backup = $backups[$result_id];
2780
2781 if (isset($backup['server'])) {
2782 @unlink($backup['server']['file_path']);
2783 }
2784
2785 //Remove from ftp
2786 if (isset($backup['ftp'])) {
2787 $ftp_file = $backup['ftp'];
2788 $args = $tasks[$task_name]['task_args']['account_info']['mwp_ftp'];
2789 $args['backup_file'] = $ftp_file;
2790 $this->remove_ftp_backup($args);
2791 }
2792
2793 if (isset($backup['amazons3'])) {
2794 $amazons3_file = $backup['amazons3'];
2795 $args = $tasks[$task_name]['task_args']['account_info']['mwp_amazon_s3'];
2796 $args['backup_file'] = $amazons3_file;
2797 $this->remove_amazons3_backup($args);
2798 }
2799
2800 if (isset($backup['dropbox'])) {
2801 $dropbox_file = $backup['dropbox'];
2802 $args = $tasks[$task_name]['task_args']['account_info']['mwp_dropbox'];
2803 $args['backup_file'] = $dropbox_file;
2804 $this->remove_dropbox_backup($args);
2805 }
2806
2807 if (isset($backup['google_drive'])) {
2808 $google_drive_file = $backup['google_drive'];
2809 $args = $tasks[$task_name]['task_args']['account_info']['mwp_google_drive'];
2810 $args['backup_file'] = $google_drive_file;
2811 $this->remove_google_drive_backup($args);
2812 }
2813
2814 unset($backups[$result_id]);
2815
2816 if (count($backups)) {
2817 $tasks[$task_name]['task_results'] = $backups;
2818 } else {
2819 unset($tasks[$task_name]['task_results']);
2820 }
2821
2822 $this->update_tasks($tasks);
2823 //update_option('mwp_backup_tasks', $tasks);
2824 return true;
2825 }
2826
2827 /**
2828 * Deletes all unneeded files produced by backup process.
2829 *
2830 * @return array array of deleted files
2831 */
2832 function cleanup() {
2833 $tasks = $this->tasks;
2834 $backup_folder = WP_CONTENT_DIR . '/' . md5('mmb-worker') . '/mwp_backups/';
2835 $backup_folder_new = MWP_BACKUP_DIR . '/';
2836 $files = glob($backup_folder . "*");
2837 $new = glob($backup_folder_new . "*");
2838
2839 //Failed db files first
2840 $db_folder = MWP_DB_DIR . '/';
2841 $db_files = glob($db_folder . "*");
2842 if (is_array($db_files) && !empty($db_files)) {
2843 foreach ($db_files as $file) {
2844 @unlink($file);
2845 }
2846 @unlink(MWP_BACKUP_DIR.'/mwp_db/index.php');
2847 @rmdir(MWP_DB_DIR);
2848 }
2849
2850 //clean_old folder?
2851 if ((isset($files[0]) && basename($files[0]) == 'index.php' && count($files) == 1) || (empty($files))) {
2852 if (!empty($files)) {
2853 foreach ($files as $file) {
2854 @unlink($file);
2855 }
2856 }
2857 @rmdir(WP_CONTENT_DIR . '/' . md5('mmb-worker') . '/mwp_backups');
2858 @rmdir(WP_CONTENT_DIR . '/' . md5('mmb-worker'));
2859 }
2860
2861 if (!empty($new)) {
2862 foreach ($new as $b) {
2863 $files[] = $b;
2864 }
2865 }
2866 $deleted = array();
2867
2868 if (is_array($files) && count($files)) {
2869 $results = array();
2870 if (!empty($tasks)) {
2871 foreach ((array) $tasks as $task) {
2872 if (isset($task['task_results']) && count($task['task_results'])) {
2873 foreach ($task['task_results'] as $backup) {
2874 if (isset($backup['server'])) {
2875 $results[] = $backup['server']['file_path'];
2876 }
2877 }
2878 }
2879 }
2880 }
2881
2882 $num_deleted = 0;
2883 foreach ($files as $file) {
2884 if (!in_array($file, $results) && basename($file) != 'index.php') {
2885 @unlink($file);
2886 $deleted[] = basename($file);
2887 $num_deleted++;
2888 }
2889 }
2890 }
2891
2892 return $deleted;
2893 }
2894
2895 /**
2896 * Uploads to remote destination in the second step, invoked from master.
2897 *
2898 * @param array $args arguments passed to function
2899 * [task_name] -> name of backup task
2900 * @return array|void void if success, array with error message if not
2901 */
2902 function remote_backup_now($args) {
2903 $this->set_memory();
2904 if (!empty($args))
2905 extract($args);
2906
2907 $tasks = $this->tasks;
2908 $task = $tasks[$task_name];
2909
2910 if (!empty($task)) {
2911 extract($task['task_args']);
2912 }
2913
2914 $results = $task['task_results'];
2915
2916 if (is_array($results) && count($results)) {
2917 $backup_file = $results[count($results) - 1]['server']['file_path'];
2918 }
2919
2920 if ($backup_file && file_exists($backup_file)) {
2921 //FTP, Amazon S3, Dropbox or Google Drive
2922 if (isset($account_info['mwp_ftp']) && !empty($account_info['mwp_ftp'])) {
2923 $this->update_status($task_name, $this->statuses['ftp']);
2924 $account_info['mwp_ftp']['backup_file'] = $backup_file;
2925 $return = $this->ftp_backup($account_info['mwp_ftp']);
2926 $this->wpdb_reconnect();
2927
2928 if (!(is_array($return) && isset($return['error']))) {
2929 $this->update_status($task_name, $this->statuses['ftp'], true);
2930 $this->update_status($task_name, $this->statuses['finished'], true);
2931 }
2932 }
2933
2934 if (isset($account_info['mwp_amazon_s3']) && !empty($account_info['mwp_amazon_s3'])) {
2935 $this->update_status($task_name, $this->statuses['s3']);
2936 $account_info['mwp_amazon_s3']['backup_file'] = $backup_file;
2937 $return = $this->amazons3_backup($account_info['mwp_amazon_s3']);
2938 $this->wpdb_reconnect();
2939
2940 if (!(is_array($return) && isset($return['error']))) {
2941 $this->update_status($task_name, $this->statuses['s3'], true);
2942 $this->update_status($task_name, $this->statuses['finished'], true);
2943 }
2944 }
2945
2946 if (isset($account_info['mwp_dropbox']) && !empty($account_info['mwp_dropbox'])) {
2947 $this->update_status($task_name, $this->statuses['dropbox']);
2948 $account_info['mwp_dropbox']['backup_file'] = $backup_file;
2949 $return = $this->dropbox_backup($account_info['mwp_dropbox']);
2950 $this->wpdb_reconnect();
2951
2952 if (!(is_array($return) && isset($return['error']))) {
2953 $this->update_status($task_name, $this->statuses['dropbox'], true);
2954 $this->update_status($task_name, $this->statuses['finished'], true);
2955 }
2956 }
2957
2958 if (isset($account_info['mwp_email']) && !empty($account_info['mwp_email'])) {
2959 $this->update_status($task_name, $this->statuses['email']);
2960 $account_info['mwp_email']['task_name'] = $task_name;
2961 $account_info['mwp_email']['file_path'] = $backup_file;
2962 $return = $this->email_backup($account_info['mwp_email']);
2963 $this->wpdb_reconnect();
2964
2965 if (!(is_array($return) && isset($return['error']))) {
2966 $this->update_status($task_name, $this->statuses['email'], true);
2967 $this->update_status($task_name, $this->statuses['finished'], true);
2968 }
2969 }
2970
2971 if (isset($account_info['mwp_google_drive']) && !empty($account_info['mwp_google_drive'])) {
2972 $this->update_status($task_name, $this->statuses['google_drive']);
2973 $account_info['mwp_google_drive']['backup_file'] = $backup_file;
2974 $return = $this->google_drive_backup($account_info['mwp_google_drive']);
2975 $this->wpdb_reconnect();
2976
2977 if (!(is_array($return) && isset($return['error']))) {
2978 $this->update_status($task_name, $this->statuses['google_drive'], true);
2979 $this->update_status($task_name, $this->statuses['finished'], true);
2980 }
2981 }
2982
2983 $tasks = $this->tasks;
2984 @file_put_contents(MWP_BACKUP_DIR.'/mwp_db/index.php', '');
2985 if ($return == true && $del_host_file) {
2986 @unlink($backup_file);
2987 unset($tasks[$task_name]['task_results'][count($tasks[$task_name]['task_results']) - 1]['server']);
2988 }
2989 $this->update_tasks($tasks);
2990 } else {
2991 $return = array(
2992 'error' => 'Backup file not found on your server. Please try again.'
2993 );
2994 }
2995
2996 return $return;
2997 }
2998
2999 /**
3000 * Checks if scheduled backup tasks should be executed.
3001 *
3002 * @param array $args arguments passed to function
3003 * [task_name] -> name of backup task
3004 * [task_id] -> id of backup task
3005 * [$site_key] -> hash key of backup task
3006 * [worker_version] -> version of worker
3007 * [mwp_google_drive_refresh_token] -> should be Google Drive token be refreshed, true if it is remote destination of task
3008 * @param string $url url on master where worker validate task
3009 * @return string|array|boolean
3010 */
3011 function validate_task($args, $url) {
3012 if (!class_exists('WP_Http')) {
3013 include_once(ABSPATH . WPINC . '/class-http.php');
3014 }
3015
3016 $worker_upto_3_9_22 = (MMB_WORKER_VERSION <= '3.9.22'); // worker version is less or equals to 3.9.22
3017 $params = array('timeout'=>100);
3018 $params['body'] = $args;
3019 $result = wp_remote_post($url, $params);
3020
3021 if ($worker_upto_3_9_22) {
3022 if (is_array($result) && $result['body'] == 'mwp_delete_task') {
3023 //$tasks = $this->get_backup_settings();
3024 $tasks = $this->tasks;
3025 unset($tasks[$args['task_name']]);
3026 $this->update_tasks($tasks);
3027 $this->cleanup();
3028 return 'deleted';
3029 } elseif(is_array($result) && $result['body'] == 'mwp_pause_task'){
3030 return 'paused';
3031 } elseif(is_array($result) && substr($result['body'], 0, 8) == 'token - '){
3032 return $result['body'];
3033 }
3034 } else {
3035 if (is_array($result) && $result['body']) {
3036 $response = unserialize($result['body']);
3037 if ($response['message'] == 'mwp_delete_task') {
3038 $tasks = $this->tasks;
3039 unset($tasks[$args['task_name']]);
3040 $this->update_tasks($tasks);
3041 $this->cleanup();
3042 return 'deleted';
3043 } elseif ($response['message'] == 'mwp_pause_task') {
3044 return 'paused';
3045 } elseif ($response['message'] == 'mwp_do_task') {
3046 return $response;
3047 }
3048 }
3049 }
3050
3051 return false;
3052 }
3053
3054 /**
3055 * Updates status of backup task.
3056 * Positive number if completed, negative if not.
3057 *
3058 * @param string $task_name name of backup task
3059 * @param int $status status which tasks should be updated to
3060 * (
3061 * 0 - Backup started,
3062 * 1 - DB dump,
3063 * 2 - DB ZIP,
3064 * 3 - Files ZIP,
3065 * 4 - Amazon S3,
3066 * 5 - Dropbox,
3067 * 6 - FTP,
3068 * 7 - Email,
3069 * 8 - Google Drive,
3070 * 100 - Finished
3071 * )
3072 * @param bool $completed completed or not
3073 * @return void
3074 */
3075 function update_status($task_name, $status, $completed = false) {
3076 if ($task_name != 'Backup Now') {
3077 $tasks = $this->tasks;
3078 $index = count($tasks[$task_name]['task_results']) - 1;
3079 if (!is_array($tasks[$task_name]['task_results'][$index]['status'])) {
3080 $tasks[$task_name]['task_results'][$index]['status'] = array();
3081 }
3082 if (!$completed) {
3083 $tasks[$task_name]['task_results'][$index]['status'][] = (int) $status * (-1);
3084 } else {
3085 $status_index = count($tasks[$task_name]['task_results'][$index]['status']) - 1;
3086 $tasks[$task_name]['task_results'][$index]['status'][$status_index] = abs($tasks[$task_name]['task_results'][$index]['status'][$status_index]);
3087 }
3088
3089 $this->update_tasks($tasks);
3090 //update_option('mwp_backup_tasks',$tasks);
3091 }
3092 }
3093
3094 /**
3095 * Update $this->tasks attribute and save it to wp_options with key mwp_backup_tasks.
3096 *
3097 * @param mixed $tasks associative array with all tasks data
3098 * @return void
3099 */
3100 function update_tasks($tasks) {
3101 $this->tasks = $tasks;
3102 update_option('mwp_backup_tasks', $tasks);
3103 }
3104
3105 /**
3106 * Reconnects to database to avoid timeout problem after ZIP files.
3107 *
3108 * @return void
3109 */
3110 function wpdb_reconnect() {
3111 global $wpdb;
3112
3113 if(class_exists('wpdb') && function_exists('wp_set_wpdb_vars')){
3114 @mysql_close($wpdb->dbh);
3115 $wpdb = new wpdb( DB_USER, DB_PASSWORD, DB_NAME, DB_HOST );
3116 wp_set_wpdb_vars();
3117 }
3118 }
3119
3120 /**
3121 * Replaces .htaccess file in process of restoring WordPress site.
3122 *
3123 * @param string $url url of current site
3124 * @return void
3125 */
3126 function replace_htaccess($url) {
3127 $file = @file_get_contents(ABSPATH.'.htaccess');
3128 if ($file && strlen($file)) {
3129 $args = parse_url($url);
3130 $string = rtrim($args['path'], "/");
3131 $regex = "/BEGIN WordPress(.*?)RewriteBase(.*?)\n(.*?)RewriteRule \.(.*?)index\.php(.*?)END WordPress/sm";
3132 $replace = "BEGIN WordPress$1RewriteBase " . $string . "/ \n$3RewriteRule . " . $string . "/index.php$5END WordPress";
3133 $file = preg_replace($regex, $replace, $file);
3134 @file_put_contents(ABSPATH.'.htaccess', $file);
3135 }
3136 }
3137
3138 /**
3139 * Removes cron for checking scheduled tasks, if there are not any scheduled task.
3140 *
3141 * @return void
3142 */
3143 function check_cron_remove() {
3144 if(empty($this->tasks) || (count($this->tasks) == 1 && isset($this->tasks['Backup Now'])) ){
3145 wp_clear_scheduled_hook('mwp_backup_tasks');
3146 exit;
3147 }
3148 }
3149
3150 /**
3151 * Re-add tasks on website re-add.
3152 *
3153 * @param array $params arguments passed to function
3154 * @return array $params without backups
3155 */
3156 public function readd_tasks($params = array()) {
3157 global $mmb_core;
3158
3159 if( empty($params) || !isset($params['backups']) )
3160 return $params;
3161
3162 $before = array();
3163 $tasks = $params['backups'];
3164 if( !empty($tasks) ){
3165 $mmb_backup = new MMB_Backup();
3166
3167 if( function_exists( 'wp_next_scheduled' ) ){
3168 if ( !wp_next_scheduled('mwp_backup_tasks') ) {
3169 wp_schedule_event( time(), 'tenminutes', 'mwp_backup_tasks' );
3170 }
3171 }
3172
3173 foreach( $tasks as $task ){
3174 $before[$task['task_name']] = array();
3175
3176 if(isset($task['secure'])){
3177 if($decrypted = $mmb_core->_secure_data($task['secure'])){
3178 $decrypted = maybe_unserialize($decrypted);
3179 if(is_array($decrypted)){
3180 foreach($decrypted as $key => $val){
3181 if(!is_numeric($key))
3182 $task[$key] = $val;
3183 }
3184 unset($task['secure']);
3185 } else
3186 $task['secure'] = $decrypted;
3187 }
3188
3189 }
3190 if (isset($task['account_info']) && is_array($task['account_info'])) { //only if sends from master first time(secure data)
3191 $task['args']['account_info'] = $task['account_info'];
3192 }
3193
3194 $before[$task['task_name']]['task_args'] = $task['args'];
3195 $before[$task['task_name']]['task_args']['next'] = $mmb_backup->schedule_next($task['args']['type'], $task['args']['schedule']);
3196 }
3197 }
3198 update_option('mwp_backup_tasks', $before);
3199
3200 unset($params['backups']);
3201 return $params;
3202 }
3203
3204 }
3205
3206 /*if( function_exists('add_filter') ) {
3207 add_filter( 'mwp_website_add', 'MMB_Backup::readd_tasks' );
3208 }*/
3209
3210 if(!function_exists('get_all_files_from_dir')) {
3211 /**
3212 * Get all files in directory
3213 *
3214 * @param string $path Relative or absolute path to folder
3215 * @param array $exclude List of excluded files or folders, relative to $path
3216 * @return array List of all files in folder $path, exclude all files in $exclude array
3217 */
3218 function get_all_files_from_dir($path, $exclude = array()) {
3219 if ($path[strlen($path) - 1] === "/") $path = substr($path, 0, -1);
3220 global $directory_tree, $ignore_array;
3221 $directory_tree = array();
3222 foreach ($exclude as $file) {
3223 if (!in_array($file, array('.', '..'))) {
3224 if ($file[0] === "/") $path = substr($file, 1);
3225 $ignore_array[] = "$path/$file";
3226 }
3227 }
3228 get_all_files_from_dir_recursive($path);
3229 return $directory_tree;
3230 }
3231 }
3232
3233 if (!function_exists('get_all_files_from_dir_recursive')) {
3234 /**
3235 * Get all files in directory,
3236 * wrapped function which writes in global variable
3237 * and exclued files or folders are read from global variable
3238 *
3239 * @param string $path Relative or absolute path to folder
3240 * @return void
3241 */
3242 function get_all_files_from_dir_recursive($path) {
3243 if ($path[strlen($path) - 1] === "/") $path = substr($path, 0, -1);
3244 global $directory_tree, $ignore_array;
3245 $directory_tree_temp = array();
3246 $dh = @opendir($path);
3247
3248 while (false !== ($file = @readdir($dh))) {
3249 if (!in_array($file, array('.', '..'))) {
3250 if (!in_array("$path/$file", $ignore_array)) {
3251 if (!is_dir("$path/$file")) {
3252 $directory_tree[] = "$path/$file";
3253 } else {
3254 get_all_files_from_dir_recursive("$path/$file");
3255 }
3256 }
3257 }
3258 }
3259 @closedir($dh);
3260 }
3261 }
3262
3263 ?>