PluginProbe
ManageWP Worker / 3.9.28
ManageWP Worker v3.9.28
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.28, at backup.class.php

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