PluginProbe
ManageWP Worker / 3.9.27
ManageWP Worker v3.9.27
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.27, at backup.class.php

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