ManageWP Worker - Version 3.9.4

Version Description

  • Now supporting schedule backups to Amazon S3 and Dropbox
  • Revamped cloning procedure with more features
  • Site colors for your websites
Download this release

Release Info

Developer freediver
Plugin Icon 128x128 ManageWP Worker
Version 3.9.4
Comparing to
See all releases

Code changes from version 3.9.3 to 3.9.4

Files changed (11) hide show
  1. backup.class.php +857 -309
  2. core.class.php +22 -7
  3. helper.class.php +28 -1
  4. init.php +72 -20
  5. installer.class.php +27 -15
  6. lib/dropbox.php +144 -0
  7. lib/s3.php +910 -0
  8. plugins/cleanup/cleanup.php +15 -25
  9. readme.txt +5 -0
  10. stats.class.php +10 -8
  11. version +1 -1
backup.class.php CHANGED
@@ -17,65 +17,132 @@ class MMB_Backup extends MMB_Core
17
  parent::__construct();
18
  }
19
 
20
- function backup($args)
21
- {
22
- @ini_set('memory_limit', '300M');
23
- @set_time_limit(300); //five minutes
24
-
25
- $type = $args['type']; //type like manual, weekly, daily
26
- $what = $args['what']; //what like full or only db
27
-
28
- if (trim($type) == '')
29
- $type = 'manual'; //default
30
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  $sec_string = md5('mmb-worker');
32
  $file = "/$sec_string/mwp_backups";
33
- $file_path = WP_CONTENT_DIR . $file;
34
 
35
- if (!file_exists($file_path)) {
36
- if (!mkdir($file_path, 0755, true))
37
  return array(
38
  'error' => 'Permission denied, make sure you have write permission to wp-content folder.'
39
  );
40
  }
41
 
42
- @file_put_contents($file_path . '/index.php', ''); //safe
43
-
44
- //delete possible breaked previous backups
45
- foreach (glob($file_path."/*.zip") as $filename) {
46
  $short = basename($filename);
47
  preg_match('/^wp\-content(.*)/Ui',$short,$matches);
48
  if($matches)
49
  @unlink($filename);
50
  }
51
-
52
- if (trim($what) == 'full') {
53
- $content_backup = $this->backup_wpcontent($type);
54
- if (array_key_exists('error',$content_backup)) {
55
- @unlink($content_backup['path']);
56
- return array(
57
- 'error' => $content_backup['error']
58
- );
59
- }
60
- }
61
-
62
- if (trim($what) == 'full' || trim($what) == 'db') {
63
- //take database backup
64
- $db_backup = $this->backup_db($type);
65
- if (!$db_backup) {
66
- if (trim($what) == 'full')
67
- @unlink($content_backup['path']);
68
-
69
- @unlink($db_backup['path']);
70
- return array(
71
- 'error' => 'Failed to backup database.'
72
- );
73
- }
74
- }
75
-
76
- include_once ABSPATH . '/wp-admin/includes/class-pclzip.php';
77
- //$worker_options = get_option('mmb-worker');
78
-
79
  //Prepare .zip file name
80
  $site_name = $this->remove_http(get_bloginfo('url'));
81
  $site_name = str_replace(array(
@@ -87,104 +154,190 @@ class MMB_Backup extends MMB_Core
87
  ), $site_name);
88
 
89
  $hash = md5(time());
90
- $backup_file = $file_path . '/' . $site_name . '_' . $type . '_' . $what . '_' . date('Y-m-d') .'_'.$hash. '.zip';
91
-
92
- if ($this->mmb_exec('which zip') == false) {
93
- $archive = new PclZip($backup_file);
94
- }
95
-
96
-
97
- if (trim($what) == 'full') {
98
- $htaccess_path = ABSPATH . ".htaccess";
99
- $wp_config_path = ABSPATH . "wp-config.php";
100
- if ($this->mmb_exec('which zip')) {
101
- $command = "zip $backup_file -j $content_backup[path] -j $db_backup[path] -j $htaccess_path -j $wp_config_path";
102
- ob_start();
103
- $result = $this->mmb_exec($command);
104
- ob_get_clean();
105
- } else {
106
- $files_to_add = array($content_backup['path'],$db_backup['path'],$htaccess_path,$wp_config_path);
107
- $result = $archive->add($files_to_add, PCLZIP_OPT_REMOVE_ALL_PATH);
108
- }
109
 
110
- } elseif (trim($what) == 'db') {
111
- if ($this->mmb_exec('which zip')) {
112
- $command = "zip $backup_file -j $db_backup[path]";
 
 
 
 
 
113
  ob_start();
114
  $result = $this->mmb_exec($command);
115
  ob_get_clean();
116
- } else {
117
-
118
- $result = $archive->add($db_backup['path'], PCLZIP_OPT_REMOVE_ALL_PATH);
119
- }
120
- }
121
-
122
- if (!$result) {
123
- return array(
124
- 'error' => 'Backup failed. Cannot create backup zip file.'
125
- );
 
 
 
126
  }
127
-
128
-
129
- @unlink($content_backup['path']);
130
- @unlink($db_backup['path']);
131
-
132
- $backup_url = WP_CONTENT_URL . $file . '/' . $site_name . '_' . $type . '_' . $what . '_' . date('Y-m-d') .'_'.$hash. '.zip';
133
- $worker_options = get_option('mmb-worker');
134
-
135
- //remove old file
136
- if ($worker_options['backups'][$type]['path'] != $backup_file) {
137
- @unlink($worker_options['backups'][$type]['path']);
138
  }
139
-
140
- $worker_options['backups'][$type]['path'] = $backup_file;
141
- $worker_options['backups'][$type]['url'] = $backup_url;
142
- update_option('mmb-worker', $worker_options);
143
-
144
- //Everything went fine, return backup url to master
145
- return $worker_options['backups'][$type]['url'];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
146
  }
 
 
 
147
 
148
- function backup_wpcontent($type)
149
- {
150
- $sec_string = md5('mmb-worker');
151
- $file = '/' . $sec_string . '/mwp_backups/wp-content_' . date('Y-m-d') . '.zip';
152
- $file_path = WP_CONTENT_DIR . $file;
153
- $content_dir = explode("/",WP_CONTENT_DIR);
154
- $content_dir = $content_dir[(count($content_dir)-1)];
155
 
156
  if ($this->mmb_exec('which zip')) {
157
  chdir(ABSPATH);
158
- $command = "zip -r $file_path './' -x '$content_dir/" . $sec_string . "/*'";
 
 
 
 
 
 
 
 
 
 
 
 
 
159
  ob_start();
160
  $result = $this->mmb_exec($command);
161
  ob_get_clean();
162
- $file_url = WP_CONTENT_URL . $file;
 
163
  if($result){
164
- return array(
165
- 'path' => $file_path,
166
- 'url' => $file_url
167
- );
168
  }
169
  else{
170
- return array('error' => 'Failed to backup site. Try to enable Zip on your server.');
171
  }
172
-
173
-
174
- } else {
175
  require_once ABSPATH . '/wp-admin/includes/class-pclzip.php';
176
- $archive = new PclZip($file_path);
177
  $result = $archive->add(ABSPATH, PCLZIP_OPT_REMOVE_PATH, ABSPATH);
178
- $result = $archive->delete(PCLZIP_OPT_BY_NAME, $content_dir.'/'.$sec_string.'/');
 
 
 
 
 
 
 
 
 
 
 
179
  if ($result) {
180
- $file_url = WP_CONTENT_URL . $file;
181
- return array(
182
- 'path' => $file_path,
183
- 'url' => $file_url
184
- );
185
  }
186
  else {
187
- @unlink($file_path);
188
  if($archive->error_code == '-10'){
189
  return array('error' => 'Failed to zip backup. Try increasing memory limit and/or free space on your server.');
190
  }
@@ -196,35 +349,38 @@ class MMB_Backup extends MMB_Core
196
  }
197
 
198
 
199
- function backup_db($type)
200
- {
201
- $mysqldump_exists = $this->check_mysqldump();
202
- if (is_array($mysqldump_exists)) {
203
- $result = $this->backup_db_dump($type, $mysqldump_exists);
 
 
 
 
 
 
 
 
 
204
 
205
  } else {
206
- $result = $this->backup_db_php($type);
207
-
208
  }
209
  return $result;
210
  }
211
 
212
- function backup_db_dump($type, $paths)
213
  {
214
  global $wpdb;
215
- $sec_string = md5('mmb-worker');
216
  $brace = (substr(PHP_OS, 0, 3) == 'WIN') ? '"' : '';
 
217
 
218
- $file = WP_CONTENT_DIR . '/' . DB_NAME . '.sql';
219
- $file_url = WP_CONTENT_URL . '/' . DB_NAME . '.sql';
220
-
221
- $command = $brace . $paths['mysqldump'] . $brace . ' --host="' . DB_HOST . '" --user="' . DB_USER . '" --password="' . DB_PASSWORD . '" --add-drop-table --skip-lock-tables "' . DB_NAME . '" > ' . $brace . $file . $brace;
222
  ob_start();
223
  $result = $this->mmb_exec($command);
224
  ob_get_clean();
225
-
226
  if (!$result) {
227
- $result = $this->backup_db_php($type);
228
  return $result;
229
  }
230
 
@@ -232,26 +388,16 @@ class MMB_Backup extends MMB_Core
232
  @unlink($file);
233
  return false;
234
  } else {
235
- return array(
236
- 'path' => $file,
237
- 'url' => $file_url
238
- );
239
  }
240
  }
241
 
242
- function backup_db_php($type)
243
  {
244
  global $wpdb;
245
- $tables = $wpdb->get_results('SHOW TABLES', ARRAY_N);
246
- $sec_string = md5('mmb-worker');
247
- $zip_file = '/' . $sec_string . '/mwp_backups/db_' . date('Y-m-d') . '.zip';
248
- $zip_file_path = WP_CONTENT_DIR . $zip_file;
249
-
250
- $file = WP_CONTENT_DIR . '/' . DB_NAME . '.sql';
251
- $file_url = WP_CONTENT_URL . '/' . DB_NAME . '.sql';
252
-
253
  foreach ($tables as $table) {
254
- //drop exixting table
255
  $dump_data = "DROP TABLE IF EXISTS $table[0];";
256
  //create table
257
  $create_table = $wpdb->get_row("SHOW CREATE TABLE $table[0]", ARRAY_N);
@@ -289,46 +435,90 @@ class MMB_Backup extends MMB_Core
289
  file_put_contents($file, $dump_data, FILE_APPEND);
290
  unset($dump_data);
291
  }
 
292
  if (filesize($file) == 0 || !is_file($file)) {
293
  @unlink($file);
294
  return false;
295
  }
296
 
297
- return array(
298
- 'path' => $file,
299
- 'url' => $file_url
300
- );
301
 
302
  }
303
 
304
  function restore($args)
305
- {
306
-
307
- $type = $args['type'];
308
- if (trim($type) == '') {
309
- return false;
310
- }
311
-
312
- // Set paths
313
- $sec_string = md5('mmb-worker');
314
- $file = "/$sec_string/restore";
315
- $file_path = WP_CONTENT_DIR . $file; //restore path - temporary
316
- $backup_path = WP_CONTENT_DIR;
317
- @ini_set('memory_limit', '300M');
318
- @set_time_limit(300);
319
-
320
- // Getting file from worker
321
- $worker_options = get_option('mmb-worker');
322
- $backup_file = $worker_options['backups'][$type]['path'];
323
-
324
- if ($backup_file && file_exists($backup_file)) {
325
- if ($this->mmb_exec('which unzip')) {
326
- if (!mkdir($file_path))
327
- return array(
328
- 'error' => 'Failed to create restore folder.'
329
  );
330
-
331
- chdir($file_path);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
332
  $command = "unzip -o $backup_file";
333
  ob_start();
334
  $result = $this->mmb_exec($command);
@@ -337,8 +527,15 @@ class MMB_Backup extends MMB_Core
337
  } else {
338
  require_once ABSPATH . '/wp-admin/includes/class-pclzip.php';
339
  $archive = new PclZip($backup_file);
340
- $result = $archive->extract(PCLZIP_OPT_PATH, $file_path, PCLZIP_OPT_REMOVE_ALL_PATH);
341
-
 
 
 
 
 
 
 
342
  }
343
 
344
  if (!$result) {
@@ -347,92 +544,89 @@ class MMB_Backup extends MMB_Core
347
  );
348
  }
349
 
350
- list(, $name, $what) = explode('_', basename($backup_file, '.zip'));
351
-
352
- if (trim($what) == 'full' || trim($what) == 'db') {
353
- if (!$this->restore_db($type, $file_path)) {
354
  return array(
355
  'error' => 'Error restoring database.'
356
  );
357
  }
358
- }
359
-
360
- if (trim($what) == 'full') {
361
- if (!$this->restore_wpcontent($type, $file_path)) {
362
- return array(
363
- 'error' => 'Error restoring wp-content.'
364
- );
365
- }
366
- }
367
 
368
- if($del_backup_later)
369
- {
370
- @unlink($backup_file);
371
- }
372
- $this->delete_temp_dir($file_path);
373
  } else {
374
  return array(
375
  'error' => 'Error restoring. Cannot find backup file.'
376
  );
377
  }
378
 
379
- return true;
380
- }
381
-
382
- function restore_wpcontent($type, $file_path)
383
- {
384
- require_once ABSPATH . '/wp-admin/includes/class-pclzip.php';
385
- $content_file = glob($file_path . "/*.zip");
386
- $wp_config_file = glob($file_path . "/wp-config.php");
387
- $htaccess_file = glob($file_path . "/.htaccess");
388
- if ($this->mmb_exec('which unzip')) {
389
- //chdir(WP_CONTENT_DIR);
390
- chdir(ABSPATH);
391
- $con_file = $content_file[0];
392
- $command = "unzip -o $con_file";
393
- ob_start();
394
- $result = $this->mmb_exec($command);
395
- ob_get_clean();
396
- } else {
397
- $archive = new PclZip($content_file[0]);
398
- $result = $archive->extract(PCLZIP_OPT_PATH, ABSPATH, PCLZIP_OPT_REPLACE_NEWER);
399
-
 
 
 
 
 
 
 
 
400
  }
401
 
402
- @rename($wp_config_file[0], ABSPATH . "wp-config.php");
403
- @rename($htaccess_file[0], ABSPATH . ".htaccess");
404
- @unlink($wp_config_file[0]);
405
- @unlink($htaccess_file[0]);
406
-
407
- if ($result)
408
- return true;
409
- else
410
- return false;
411
  }
412
 
413
- function restore_db($type, $file_path)
414
  {
415
  global $wpdb;
416
-
417
  $mysqldump = $this->check_mysqldump();
418
-
419
- if (is_array($mysqldump)) {
 
 
 
420
  $brace = (substr(PHP_OS, 0, 3) == 'WIN') ? '"' : '';
421
-
422
- foreach (glob($file_path . '/*.sql') as $filename) {
423
- $command = $brace . $mysqldump['mysql'] . $brace . ' --host="' . DB_HOST . '" --user="' . DB_USER . '" --password="' . DB_PASSWORD . '" ' . DB_NAME . ' < ' . $brace . $filename . $brace;
424
  ob_start();
425
  $result = $this->mmb_exec($command);
426
  ob_get_clean();
427
- break;
428
- }
 
 
429
 
430
- if (!$result) //try php
431
- {
432
- foreach (glob($file_path . '/*.sql') as $filename) {
433
- $current_query = '';
 
 
 
 
 
 
 
434
  // Read in entire file
435
- $lines = file($filename);
436
  // Loop through each line
437
  foreach ($lines as $line) {
438
  // Skip it if it's a comment
@@ -451,52 +645,43 @@ class MMB_Backup extends MMB_Core
451
  $current_query = '';
452
  }
453
  }
454
- }
455
- return true;
456
- } else {
457
  return true;
458
- }
459
-
460
- } else {
461
- foreach (glob($file_path . '/*.sql') as $filename) {
462
- // Temporary variable, used to store current query
463
- $current_query = '';
464
- // Read in entire file
465
- $lines = file($filename);
466
- // Loop through each line
467
- foreach ($lines as $line) {
468
- // Skip it if it's a comment
469
- if (substr($line, 0, 2) == '--' || $line == '')
470
- continue;
471
-
472
- // Add this line to the current query
473
- $current_query .= $line;
474
- // If it has a semicolon at the end, it's the end of the query
475
- if (substr(trim($line), -1, 1) == ';') {
476
- // Perform the query
477
- $result = $wpdb->query($current_query);
478
- if ($result === false)
479
- return FALSE;
480
- // Reset temp variable to empty
481
- $current_query = '';
482
- }
483
- }
484
- }
485
- return true;
486
- }
487
  }
488
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
489
  function optimize_tables()
490
  {
491
  global $wpdb;
492
- $tables = $wpdb->get_col("SHOW TABLES");
493
-
494
- foreach ($tables as $table_name) {
495
- $table_string .= $table_name . ",";
 
 
 
 
496
  }
 
497
  $table_string = rtrim($table_string);
498
- $optimize = $wpdb->query("OPTIMIZE TABLE $table_string");
499
- return $optimize ? true : false;
 
500
  }
501
 
502
  ### Function: Auto Detect MYSQL and MYSQL Dump Paths
@@ -537,7 +722,7 @@ class MMB_Backup extends MMB_Core
537
  return $paths;
538
  }
539
 
540
- //Check if exec, system, shell_exec functions exist
541
  function check_sys()
542
  {
543
  if (function_exists('exec'))
@@ -565,44 +750,22 @@ class MMB_Backup extends MMB_Core
565
  if($string) return $log;
566
  return $return ? false : true;
567
  }
568
- if(function_exists('system'))
569
- {
570
  $log = @system($command,$return);
571
 
572
  if($string) return $log;
573
  return $return ? false : true;
574
  }
575
- elseif (function_exists('passthru'))
576
- {
577
  $log = passthru($command,$return);
578
 
579
  return $return ? false : true;
580
  }
581
- else
582
- {
583
  return false;
584
  }
585
  }
586
-
587
- function email_backup($args)
588
- {
589
- $email = $args['email'];
590
- $what = $args['email'];
591
- $type = $args['type'];
592
- $worker_options = get_option('mmb-worker');
593
- $backup_file = $worker_options['backups'][$type]['path'];
594
- if(file_exists($backup_file) && $email)
595
- {
596
- $attachments = array($backup_file);
597
- $headers = 'From: ManageWP <wordpress@managewp.com>' . "\r\n";
598
- $subject = "Backup - " . $type ." - " . date('Y-m-d');
599
- ob_start();
600
- wp_mail($email, $subject, '', $headers, $attachments);
601
- ob_end_clean();
602
- }
603
-
604
- }
605
-
606
  function check_backup_compat()
607
  {
608
  $reqs = array();
@@ -687,8 +850,393 @@ class MMB_Backup extends MMB_Core
687
  }
688
 
689
 
 
690
  return $reqs;
691
  }
692
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
693
  }
 
694
  ?>
17
  parent::__construct();
18
  }
19
 
20
+ function get_backup_settings()
21
+ {
22
+ $backup_settings = get_option('mwp_backup_tasks');
23
+ if(!empty($backup_settings))
24
+ return $backup_settings;
25
+ else
26
+ return false;
27
+ }
28
+
29
+ function set_backup_task($params)
30
+ {
31
+ //$params => [$task_name, $args, $error]
32
+ if(!empty($params)){
33
+ extract($params);
34
+
35
+ $before = $this->get_backup_settings();
36
+ if(!$before || empty($before))
37
+ $before = array();
38
+
39
+ if(isset($args['remove'])){
40
+ unset($before[$task_name]);
41
+ $return = array('removed' => true);
42
+ } else {
43
+ $args['account_info'] = $account_info;
44
+ $before[$task_name]['task_args'] = $args;
45
+
46
+ if(!empty($args['schedule']))
47
+ $before[$task_name]['task_args']['next'] = $this->schedule_next($args['type'],$args['schedule']);
48
+
49
+ $return = $before[$task_name];
50
+ }
51
+
52
+ if($error){
53
+ $before[$task_name]['task_results'][count($before[$task_name]['task_results'])] = array('error' => $error);
54
+ }
55
+ update_option('mwp_backup_tasks',$before);
56
+
57
+ if($task_name == 'Backup Now'){
58
+ $result = $this->backup($args, $task_name);
59
+ $backup_settings = $this->get_backup_settings();
60
+ if(is_array($result) && array_key_exists('error',$result)){
61
+ $return = $result;
62
+ } else {
63
+ $return = $backup_settings[$task_name];
64
+ }
65
+ }
66
+ return $return;
67
+ }
68
+ return false;
69
+ }
70
+
71
+ //Cron check
72
+ function check_backup_tasks()
73
+ {
74
+ $settings = $this->get_backup_settings();
75
+ if(is_array($settings) && !empty($settings)){
76
+ foreach($settings as $task_name => $setting){
77
+ if($setting['task_args']['next'] && $setting['task_args']['next'] < time()){
78
+ $result = $this->backup($setting['task_args'], $task_name);
79
+
80
+ if(is_array($result) && array_key_exists('error', $result)){
81
+ $error = $result['error'];
82
+ } else {
83
+ $error = '';
84
+ }
85
+
86
+ //Update task with next schedule and possible error
87
+ $this->set_backup_task(array('task_name' => $task_name, 'args' => $settings[$task_name]['task_args'], 'error' => $error)); //Update
88
+ break;
89
+ }
90
+ }
91
+ }
92
+
93
+ }
94
+
95
+
96
+
97
+ /*
98
+ * If Task Name not set then it's manual backup
99
+ * Backup args:
100
+ * type -> db, full
101
+ * what -> daily, weekly, monthly
102
+ * account_info -> ftp, amazons3, dropbox
103
+ * exclude-> array of paths to exclude from backup
104
+ */
105
+
106
+ function backup($args, $task_name = false){
107
+ if(!$args || empty($args))
108
+ return false;
109
+
110
+ extract($args); //extract settings
111
+
112
+
113
+ //try increase memory limit
114
+ @ini_set('memory_limit', '300M');
115
+ @set_time_limit(300); //five minutes
116
+
117
+ //Remove old backup(s)
118
+ if($type == 'manual'){
119
+ $old = get_option('mwp_manual_backup');
120
+ if($old['file_path'] && file_exists($old['file_path']))
121
+ @unlink($old['file_path']);
122
+ } else {
123
+ $this->remove_old_backups($task_name);
124
+ }
125
+
126
  $sec_string = md5('mmb-worker');
127
  $file = "/$sec_string/mwp_backups";
128
+ $new_file_path = WP_CONTENT_DIR . $file;
129
 
130
+ if (!file_exists($new_file_path)) {
131
+ if (!mkdir($new_file_path, 0755, true))
132
  return array(
133
  'error' => 'Permission denied, make sure you have write permission to wp-content folder.'
134
  );
135
  }
136
 
137
+ @file_put_contents($new_file_path . '/index.php', ''); //safe
138
+ //Delete possible breaked previous backups - don't need it anymore (works only for previous wrokers)
139
+ foreach (glob($new_file_path."/*.zip") as $filename) {
 
140
  $short = basename($filename);
141
  preg_match('/^wp\-content(.*)/Ui',$short,$matches);
142
  if($matches)
143
  @unlink($filename);
144
  }
145
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
146
  //Prepare .zip file name
147
  $site_name = $this->remove_http(get_bloginfo('url'));
148
  $site_name = str_replace(array(
154
  ), $site_name);
155
 
156
  $hash = md5(time());
157
+ $label = $type ? $type : 'manual';
158
+ $backup_file = $new_file_path . '/' . $site_name . '_' . $label . '_' . $what . '_' . date('Y-m-d') .'_'.$hash. '.zip';
159
+ $backup_url = WP_CONTENT_URL . $file . '/' . $site_name . '_' . $label . '_' . $what . '_' . date('Y-m-d') .'_'.$hash. '.zip';
160
+
161
+
162
+ //What to backup - db or full
163
+ if (trim($what) == 'db') {
164
+ //take database backup
 
 
 
 
 
 
 
 
 
 
 
165
 
166
+ $db_result = $this->backup_db();
167
+ if(!$db_result){
168
+ return array('error' => 'Failed to extract database.');
169
+ }
170
+ else
171
+ {
172
+ if ($this->mmb_exec('which zip')) {
173
+ $command = "zip $backup_file -j $db_result";
174
  ob_start();
175
  $result = $this->mmb_exec($command);
176
  ob_get_clean();
177
+ } else {
178
+ require_once ABSPATH . '/wp-admin/includes/class-pclzip.php';
179
+ $archive = new PclZip($backup_file);
180
+ $result = $archive->add($db_result, PCLZIP_OPT_REMOVE_ALL_PATH);
181
+
182
+ }
183
+
184
+ @unlink($db_result);
185
+ if(!$result)
186
+ return array(
187
+ 'error' => 'Failed to zip database.'
188
+ );
189
+ }
190
  }
191
+ elseif (trim($what) == 'full') {
192
+ $content_backup = $this->backup_full($backup_file,$exclude);
193
+ if (is_array($content_backup) && array_key_exists('error', $content_backup)) {
194
+ return array(
195
+ 'error' => $content_backup['error']
196
+ );
197
+ }
 
 
 
 
198
  }
199
+
200
+ //Update backup info
201
+ if($task_name){
202
+ //backup task (scheduled)
203
+ $backup_settings = $this->get_backup_settings();
204
+ $paths = array();
205
+ $size = ceil(filesize($backup_file) / 1024);
206
+
207
+ if($size > 1000){
208
+ $paths['size'] = ceil($size / 1024).'Mb';
209
+ } else {
210
+ $paths['size'] = $size.'kb';
211
+ }
212
+ $paths['time'] = time();
213
+
214
+ if(!$backup_settings[$task_name]['task_args']['del_host_file']){
215
+ $paths['server'] = array('file_path' => $backup_file, 'file_url' => $backup_url);
216
+ }
217
+
218
+ if(isset($backup_settings[$task_name]['task_args']['account_info']['mwp_ftp'])) {
219
+ $paths['ftp'] = basename($backup_url);
220
+ }
221
+
222
+ if(isset($backup_settings[$task_name]['task_args']['account_info']['mwp_amazon_s3'])) {
223
+ $paths['amazons3'] = basename($backup_url);
224
+ }
225
+
226
+ if(isset($backup_settings[$task_name]['task_args']['account_info']['mwp_dropbox'])) {
227
+ $paths['dropbox'] = basename($backup_url);
228
+ }
229
+
230
+ if($backup_settings[$task_name]['task_args']['email_backup']) {
231
+ $paths['email'] = $backup_settings[$task_name]['task_args']['email_backup'];
232
+ }
233
+
234
+ $temp = $backup_settings[$task_name]['task_results'];
235
+ $temp['temp'] = $paths;
236
+ $backup_settings[$task_name]['task_results'] = array_values($temp);
237
+ update_option ('mwp_backup_tasks',$backup_settings);
238
+ }
239
+ else
240
+ {
241
+ //manual - predefined backup used for cloning
242
+ $manual_backup = $args;
243
+ $manual_backup ['file_path'] = $backup_file;
244
+ $manual_backup ['file_url'] = $backup_url;
245
+ update_option('mwp_manual_backup', $manual_backup);
246
+ }
247
+
248
+ //Additional: Table optimize, email, ftp, amazon_s3, dropbox...
249
+ if(isset($optimize_tables) && !empty($optimize_tables)){
250
+ $this->optimize_tables();
251
+ }
252
+
253
+ if(isset($account_info['mwp_ftp']) && !empty($account_info['mwp_ftp'])){
254
+ $account_info['mwp_ftp']['backup_file'] = $backup_file;
255
+ $this->ftp_backup($account_info['mwp_ftp']);
256
+ }
257
+
258
+ if (isset($account_info['mwp_amazon_s3']) && !empty($account_info['mwp_amazon_s3'])){
259
+ $account_info['mwp_amazon_s3']['backup_file'] = $backup_file;
260
+ $this->amazons3_backup($account_info['mwp_amazon_s3']);
261
+ }
262
+
263
+ if(isset($account_info['mwp_dropbox']) && !empty($account_info['mwp_dropbox'])){
264
+ $account_info['mwp_dropbox']['backup_file'] = $backup_file;
265
+ $this->dropbox_backup($account_info['mwp_dropbox']);
266
+ }
267
+
268
+ if(isset($email_backup) && is_email($email_backup)){
269
+ $mail_args = array(
270
+ 'email' => $email_backup,
271
+ 'task_name' => $task_name,
272
+ 'file_path' => $backup_file
273
+ );
274
+ $this->email_backup($mail_args);
275
+ }
276
+
277
+ if($del_host_file){
278
+ @unlink($backup_file);
279
  }
280
+
281
+ return $backup_url; //Return url to backup file (we need return only for manual backup)
282
+ }
283
 
284
+ function backup_full($path, $exclude = array())
285
+ {
286
+ $db_result = $this->backup_db();
287
+ if(!$db_result)
288
+ return array('error' => 'Failed to backup database.');
289
+ $sec_string = md5('mmb-worker');
290
+ $remove = "wp-content/$sec_string/mwp_backups";
291
 
292
  if ($this->mmb_exec('which zip')) {
293
  chdir(ABSPATH);
294
+
295
+ //exclude paths
296
+ if(empty($exclude)){
297
+ $exclude[0] = $remove;
298
+ } else {
299
+ $exclude[count($exclude)] = $remove;
300
+ }
301
+
302
+ $exclude_data = "-x";
303
+ foreach($exclude as $data){
304
+ $exclude_data .= " '$data/*'";
305
+ }
306
+
307
+ $command = "zip -r $path './' $exclude_data";
308
  ob_start();
309
  $result = $this->mmb_exec($command);
310
  ob_get_clean();
311
+ @unlink($db_result);
312
+
313
  if($result){
314
+ return true;
 
 
 
315
  }
316
  else{
317
+ return array('error' => 'Failed to backup site.');
318
  }
319
+
320
+ }
321
+ else { //php zip
322
  require_once ABSPATH . '/wp-admin/includes/class-pclzip.php';
323
+ $archive = new PclZip($path);
324
  $result = $archive->add(ABSPATH, PCLZIP_OPT_REMOVE_PATH, ABSPATH);
325
+ $exclude_data = array();
326
+ if(!empty($exclude) && $result){
327
+ $exclude_data = array();
328
+ foreach($exclude as $data){
329
+ $exclude_data [] = $data.'/';
330
+ }
331
+
332
+ }
333
+ $exclude_data[] = $remove.'/';
334
+ $result = $archive->delete(PCLZIP_OPT_BY_NAME, $exclude_data);
335
+
336
+ @unlink($db_result);
337
  if ($result) {
338
+ return true;
 
 
 
 
339
  }
340
  else {
 
341
  if($archive->error_code == '-10'){
342
  return array('error' => 'Failed to zip backup. Try increasing memory limit and/or free space on your server.');
343
  }
349
  }
350
 
351
 
352
+ function backup_db()
353
+ {
354
+ $db_folder = ABSPATH.'mwp_db/';
355
+ if (!file_exists($db_folder)) {
356
+ if (!mkdir($db_folder, 0755, true))
357
+ return array(
358
+ 'error' => 'Error creating database backup folder. Make sure you have write permission to your site root folder.'
359
+ );
360
+ }
361
+
362
+ $file = $db_folder . DB_NAME . '.sql';
363
+ $mysqldump = $this->check_mysqldump();
364
+ if (is_array($mysqldump)) {
365
+ $result = $this->backup_db_dump($file,$mysqldump);
366
 
367
  } else {
368
+ $result = $this->backup_db_php($file);
 
369
  }
370
  return $result;
371
  }
372
 
373
+ function backup_db_dump($file,$mysqldump)
374
  {
375
  global $wpdb;
 
376
  $brace = (substr(PHP_OS, 0, 3) == 'WIN') ? '"' : '';
377
+ $command = $brace . $mysqldump['mysqldump'] . $brace . ' --host="' . DB_HOST . '" --user="' . DB_USER . '" --password="' . DB_PASSWORD . '" --add-drop-table --skip-lock-tables "' . DB_NAME . '" > ' . $brace . $file . $brace;
378
 
 
 
 
 
379
  ob_start();
380
  $result = $this->mmb_exec($command);
381
  ob_get_clean();
 
382
  if (!$result) {
383
+ $result = $this->backup_db_php($file);
384
  return $result;
385
  }
386
 
388
  @unlink($file);
389
  return false;
390
  } else {
391
+ return $file;
 
 
 
392
  }
393
  }
394
 
395
+ function backup_db_php($file)
396
  {
397
  global $wpdb;
398
+ $tables = $wpdb->get_results('SHOW TABLES', ARRAY_N);
 
 
 
 
 
 
 
399
  foreach ($tables as $table) {
400
+ //drop existing table
401
  $dump_data = "DROP TABLE IF EXISTS $table[0];";
402
  //create table
403
  $create_table = $wpdb->get_row("SHOW CREATE TABLE $table[0]", ARRAY_N);
435
  file_put_contents($file, $dump_data, FILE_APPEND);
436
  unset($dump_data);
437
  }
438
+
439
  if (filesize($file) == 0 || !is_file($file)) {
440
  @unlink($file);
441
  return false;
442
  }
443
 
444
+ return $file;
 
 
 
445
 
446
  }
447
 
448
  function restore($args)
449
+ {
450
+ global $wpdb;
451
+ if(empty($args)) {return false;}
452
+
453
+ extract($args);
454
+ @ini_set('memory_limit', '300M');
455
+ @set_time_limit(300);
456
+
457
+ $unlink_file = true; //Delete file after restore
458
+
459
+ //Detect source
460
+ if($backup_url){
461
+ //This is for clone (overwrite)
462
+ include_once ABSPATH . 'wp-admin/includes/file.php';
463
+ $backup_file = download_url($backup_url);
464
+ if(is_wp_error($backup_file)){
465
+ return array(
466
+ 'error' => $backup_file->get_error_message()
 
 
 
 
 
 
467
  );
468
+ }
469
+ $what = 'full';
470
+ } else {
471
+ $tasks = $this->get_backup_settings();
472
+ $task = $tasks[$task_name];
473
+ if(isset($task['task_results'][$result_id]['server'])) {
474
+ $backup_file = $task['task_results'][$result_id]['server']['file_path'];
475
+ $unlink_file = false; //Don't delete file if stored on server
476
+ }elseif(isset($task['task_results'][$result_id]['ftp'])){
477
+ $ftp_file = $task['task_results'][$result_id]['ftp'];
478
+ $args = $task['task_args']['account_info']['mwp_ftp'];
479
+ $args['backup_file'] = $ftp_file;
480
+ $backup_file = $this->get_ftp_backup($args);
481
+ if($backup_file == false){
482
+ return array(
483
+ 'error' => 'Failed to download file from FTP'
484
+ );
485
+ }
486
+ }elseif(isset($task['task_results'][$result_id]['amazons3'])){
487
+ $amazons3_file = $task['task_results'][$result_id]['amazons3'];
488
+ $args = $task['task_args']['account_info']['mwp_amazon_s3'];
489
+ $args['backup_file'] = $ftp_file;
490
+ $backup_file = $this->get_amazons3_backup($args);
491
+ if($backup_file == false){
492
+ return array(
493
+ 'error' => 'Failed to download file from Amazon S3'
494
+ );
495
+ }
496
+ }
497
+
498
+ $what = $tasks[$task_name]['task_args']['what'];
499
+ }
500
+
501
+ if ($backup_file && file_exists($backup_file)) {
502
+
503
+ if($overwrite) {
504
+ //Keep old db credentials before overwrite
505
+ if(!rename(ABSPATH.'wp-config.php',ABSPATH.'mwp-temp-wp-config.php')){
506
+ return array('error' => 'Error creating wp-config. Please check your write permisions.');
507
+ }
508
+
509
+ $db_host = DB_HOST;
510
+ $db_user = DB_USER;
511
+ $db_password = DB_PASSWORD;
512
+ $home = get_option('home');
513
+ $site_url = get_option('site_url');
514
+ }
515
+
516
+ if ($this->mmb_exec('which unzip')) {
517
+ if($what == 'db')
518
+ chdir(ABSPATH.'mwp_db/');
519
+ else {
520
+ chdir(ABSPATH);
521
+ }
522
  $command = "unzip -o $backup_file";
523
  ob_start();
524
  $result = $this->mmb_exec($command);
527
  } else {
528
  require_once ABSPATH . '/wp-admin/includes/class-pclzip.php';
529
  $archive = new PclZip($backup_file);
530
+ if($what == 'db'){
531
+ $result = $archive->extract(PCLZIP_OPT_PATH, ABSPATH.'mwp_db/');
532
+ } else {
533
+ $result = $archive->extract(PCLZIP_OPT_PATH, ABSPATH);
534
+ }
535
+ }
536
+
537
+ if($unlink_file){
538
+ @unlink($backup_file);
539
  }
540
 
541
  if (!$result) {
544
  );
545
  }
546
 
547
+ $db_result = $this->restore_db();
548
+
549
+ if (!$db_result) {
 
550
  return array(
551
  'error' => 'Error restoring database.'
552
  );
553
  }
554
+
 
 
 
 
 
 
 
 
555
 
556
+
 
 
 
 
557
  } else {
558
  return array(
559
  'error' => 'Error restoring. Cannot find backup file.'
560
  );
561
  }
562
 
563
+ //Replace options and content urls
564
+ if($overwrite){
565
+ //Get New Table prefix
566
+ $new_table_prefix = trim($this->get_table_prefix());
567
+
568
+ //Retrieve old wp_config
569
+ @unlink(ABSPATH.'wp-config.php');
570
+
571
+ //Replace table prefix
572
+ $lines = file(ABSPATH.'mwp-temp-wp-config.php');
573
+ foreach ($lines as $line) {
574
+ if (strstr($line, '$table_prefix')) {
575
+ $line = '$table_prefix = "'.$new_table_prefix.'";'.PHP_EOL;
576
+ }
577
+ file_put_contents(ABSPATH.'wp-config.php', $line, FILE_APPEND);
578
+ }
579
+
580
+ @unlink(ABSPATH.'mwp-temp-wp-config.php');
581
+
582
+ //Replace options
583
+ $query = "SELECT option_value FROM " . $new_table_prefix . "options WHERE option_name = 'home'";
584
+ $old = $wpdb->get_var($wpdb->prepare($query));
585
+ $query = "UPDATE " . $new_table_prefix . "options SET option_value = '$home' WHERE option_name = 'home'";
586
+ $wpdb->query($wpdb->prepare($query));
587
+ $query = "UPDATE " . $new_table_prefix . "options SET option_value = '$home' WHERE option_name = 'siteurl'";
588
+ $wpdb->query($wpdb->prepare($query));
589
+ //Replace content urls
590
+ $query = "UPDATE " . $new_table_prefix . "posts SET post_content = REPLACE (post_content, '$old','$home') WHERE post_content REGEXP 'src=\"(.*)$old(.*)\"' OR post_content REGEXP 'href=\"(.*)$old(.*)\"'";
591
+ $wpdb->query($wpdb->prepare($query));
592
  }
593
 
594
+ return true;
 
 
 
 
 
 
 
 
595
  }
596
 
597
+ function restore_db()
598
  {
599
  global $wpdb;
 
600
  $mysqldump = $this->check_mysqldump();
601
+ $file_path = ABSPATH.'mwp_db';
602
+ $file_name = glob($file_path . '/*.sql');
603
+ $file_name = $file_name[0];
604
+
605
+ if(is_array($mysqldump)) {
606
  $brace = (substr(PHP_OS, 0, 3) == 'WIN') ? '"' : '';
607
+ $command = $brace . $mysqldump['mysql'] . $brace . ' --host="' . DB_HOST . '" --user="' . DB_USER . '" --password="' . DB_PASSWORD . '" ' . DB_NAME . ' < ' . $brace . $file_name . $brace;
608
+
 
609
  ob_start();
610
  $result = $this->mmb_exec($command);
611
  ob_get_clean();
612
+ if (!$result) {
613
+ //try php
614
+ $this->restore_db_php($file_name);
615
+ }
616
 
617
+ } else {
618
+ $this->restore_db_php($file_name);
619
+ }
620
+
621
+ @unlink($file_name);
622
+ return true;
623
+ }
624
+
625
+ function restore_db_php($file_name)
626
+ {
627
+ $current_query = '';
628
  // Read in entire file
629
+ $lines = file($file_name);
630
  // Loop through each line
631
  foreach ($lines as $line) {
632
  // Skip it if it's a comment
645
  $current_query = '';
646
  }
647
  }
648
+
649
+ @unlink($file_name);
 
650
  return true;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
651
  }
652
 
653
+ function get_table_prefix()
654
+ {
655
+ $lines = file(ABSPATH.'wp-config.php');
656
+ foreach ($lines as $line) {
657
+ if (strstr($line, '$table_prefix')) {
658
+ $pattern = "/(\'|\")[^(\'|\")]*/";
659
+ preg_match($pattern, $line, $matches);
660
+ $prefix = substr($matches[0], 1);
661
+ return $prefix;
662
+ break;
663
+ }
664
+ }
665
+ return 'wp_'; //default
666
+ }
667
+
668
  function optimize_tables()
669
  {
670
  global $wpdb;
671
+ $query = 'SHOW TABLE STATUS FROM '. DB_NAME;
672
+ $tables = $wpdb->get_results($wpdb->prepare($query),ARRAY_A);
673
+ foreach ($tables as $table) {
674
+ if(in_array($table['Engine'], array('MyISAM', 'ISAM', 'HEAP', 'MEMORY', 'ARCHIVE')))
675
+ $table_string .= $table['Name'] . ",";
676
+ elseif($table['Engine'] == 'InnoDB'){
677
+ $optimize = $wpdb->query("ALTER TABLE {$table['Name']} ENGINE=InnoDB");
678
+ }
679
  }
680
+
681
  $table_string = rtrim($table_string);
682
+ $optimize = $wpdb->query("OPTIMIZE TABLE $table_string");
683
+
684
+ return $optimize ? true : false;
685
  }
686
 
687
  ### Function: Auto Detect MYSQL and MYSQL Dump Paths
722
  return $paths;
723
  }
724
 
725
+ //Check if exec, system, passthru functions exist
726
  function check_sys()
727
  {
728
  if (function_exists('exec'))
750
  if($string) return $log;
751
  return $return ? false : true;
752
  }
753
+ elseif(function_exists('system')){
 
754
  $log = @system($command,$return);
755
 
756
  if($string) return $log;
757
  return $return ? false : true;
758
  }
759
+ elseif (function_exists('passthru')){
 
760
  $log = passthru($command,$return);
761
 
762
  return $return ? false : true;
763
  }
764
+ else {
 
765
  return false;
766
  }
767
  }
768
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
769
  function check_backup_compat()
770
  {
771
  $reqs = array();
850
  }
851
 
852
 
853
+
854
  return $reqs;
855
  }
856
 
857
+ function email_backup($args)
858
+ {
859
+ $email = $args['email'];
860
+ $backup_file = $args['file_path'];
861
+ $task_name = isset($args['task_name']) ? $args['task_name'].' on ' : '';
862
+ if(file_exists($backup_file) && $email)
863
+ {
864
+ $attachments = array($backup_file);
865
+ $headers = 'From: ManageWP <no-reply@managewp.com>' . "\r\n";
866
+ $subject = "ManageWP Backup - ".$task_name . date('F jS, y H:s');
867
+ ob_start();
868
+ wp_mail($email, $subject, $subject, $headers, $attachments);
869
+ ob_end_clean();
870
+
871
+ }
872
+
873
+ }
874
+
875
+ function ftp_backup($args){
876
+ extract($args);
877
+ //Args: $ftp_username, $ftp_password, $ftp_hostname, $backup_file, $ftp_remote_folder
878
+
879
+ if($ftp_ssl && function_exists('ftp_ssl_connect')){
880
+ $conn_id = ftp_ssl_connect($ftp_hostname);
881
+ }else if (function_exists('ftp_connect')){
882
+ $conn_id = ftp_connect($ftp_hostname);
883
+ if ($conn_id===false){
884
+ $this->_log("ftp failed to connect");
885
+ }
886
+ }
887
+ else {
888
+ $this->_log("ftp not supported");
889
+ }
890
+
891
+ $login = @ftp_login($conn_id, $ftp_username, $ftp_password);
892
+ if ($login === false ) {
893
+ $this->_log("failed to login");
894
+ } else {
895
+ $this->_log("connected to ftp");
896
+ }
897
+
898
+ @ftp_mkdir($conn_id, $ftp_remote_folder);
899
+
900
+ $upload = @ftp_put($conn_id, $ftp_remote_folder . '/' . basename($backup_file), $backup_file, FTP_BINARY);
901
+ if ($upload === false) {
902
+ $this->_log("not uploaded to ftp");
903
+ } else {
904
+ $this->_log("ftp uploaded successfuly");
905
+ }
906
+ ftp_close($conn_id);
907
+
908
+ }
909
+
910
+ function remove_ftp_backup($args)
911
+ {
912
+ extract($args);
913
+ //Args: $ftp_username, $ftp_password, $ftp_hostname, $backup_file, $ftp_remote_folder
914
+ if($ftp_ssl && function_exists('ftp_ssl_connect')){
915
+ $conn_id = ftp_ssl_connect($ftp_hostname);
916
+ $this->_log("sftp failed to connect");
917
+ }else if (function_exists('ftp_connect')){
918
+ $conn_id = ftp_connect($ftp_hostname);
919
+ if ($conn_id===false){
920
+ $this->_log("ftp failed to connect");
921
+ }
922
+ }
923
+ else {
924
+ $this->_log("ftp not supported");
925
+ }
926
+ $login = @ftp_login($conn_id, $ftp_username, $ftp_password);
927
+ if ($login === false ) {
928
+ $this->_log("failed to connect");
929
+ } else {
930
+ $this->_log("connected");
931
+ }
932
+
933
+ $delete = ftp_delete($conn_id, $ftp_remote_folder . '/' . $backup_file);
934
+ if ($delete === false) {
935
+ $this->_log("not deleted");
936
+ } else {
937
+ $this->_log("deleted successfuly");
938
+ }
939
+ ftp_close($conn_id);
940
+
941
+ }
942
+
943
+ function get_ftp_backup($args){
944
+ extract($args);
945
+ //Args: $ftp_username, $ftp_password, $ftp_hostname, $backup_file, $ftp_remote_folder
946
+ if($ftp_ssl && function_exists('ftp_ssl_connect')){
947
+ $conn_id = ftp_ssl_connect($ftp_hostname);
948
+ $this->_log("sftp failed to connect");
949
+ }else if (function_exists('ftp_connect')){
950
+ $conn_id = ftp_connect($ftp_hostname);
951
+ if ($conn_id===false){
952
+ return false;
953
+ }
954
+ }
955
+ else {
956
+ $this->_log("ftp not supported");
957
+ }
958
+ $login = @ftp_login($conn_id, $ftp_username, $ftp_password);
959
+ if ($login === false ) {
960
+ return false;
961
+ } else {
962
+ $this->_log("connected");
963
+ }
964
+
965
+ $temp = ABSPATH.'mwp_temp_backup.zip';
966
+ $get = ftp_get($conn_id, $temp, $ftp_remote_folder . '/' . $backup_file, FTP_BINARY);
967
+ if ($get === false) {
968
+ return false;
969
+ } else {
970
+ $this->_log("download successfuly");
971
+ }
972
+ ftp_close($conn_id);
973
+
974
+ return $temp;
975
+ }
976
+
977
+ function dropbox_backup($args)
978
+ {
979
+ require_once('lib/dropbox.php');
980
+ extract($args);
981
+
982
+ //$email, $password, $backup_file, $destination
983
+ try{
984
+ $uploader = new DropboxUploader($dropbox_username, $dropbox_password);
985
+ $uploader->upload($backup_file, $dropbox_destination);
986
+ } catch (Exception $e){
987
+ $this->_log($e->getMessage());
988
+ }
989
+ }
990
+
991
+ function amazons3_backup($args)
992
+ {
993
+ require_once('lib/s3.php');
994
+ extract($args);
995
+
996
+ $s3 = new S3( $as3_access_key, str_replace(' ', '+', $as3_secure_key));
997
+
998
+ $s3->putBucket( $as3_bucket, S3::ACL_PUBLIC_READ );
999
+
1000
+ if ( $s3->putObjectFile( $backup_file, $as3_bucket, $as3_directory .'/'. basename($backup_file), S3::ACL_PRIVATE) ) {
1001
+ return array('success' => 'ok');
1002
+ } else {
1003
+ return array('success' => 'error');
1004
+ }
1005
+
1006
+ }
1007
+
1008
+ function remove_amazons3_backup($args)
1009
+ {
1010
+ require_once('lib/s3.php');
1011
+ extract($args);
1012
+ $this->_log("delete");
1013
+ $s3 = new S3( $as3_access_key, str_replace(' ', '+', $as3_secure_key));
1014
+ $s3->deleteObject($as3_bucket,$as3_directory.'/'. $backup_file);
1015
+ }
1016
+
1017
+ function get_amazons3_backup($args)
1018
+ {
1019
+ require_once('lib/s3.php');
1020
+ extract($args);
1021
+ $s3 = new S3( $as3_access_key, str_replace(' ', '+', $as3_secure_key));
1022
+ $s3->deleteObject($as3_bucket,$as3_directory.'/'. $backup_file);
1023
+ $s3->getObject($as3_bucket, $as3_directory.'/'. $backup_file, $temp);
1024
+ $temp = ABSPATH.'mwp_temp_backup.zip';
1025
+ return $temp;
1026
+ }
1027
+
1028
+ function schedule_next($type,$schedule)
1029
+ {
1030
+
1031
+ $schedule = explode("|", $schedule);
1032
+ if(empty($schedule))
1033
+ return false;
1034
+ switch($type){
1035
+
1036
+ case 'daily':
1037
+
1038
+ if($schedule[1]) { $delay_time = $schedule[1] * 60;}
1039
+
1040
+ $current_hour = date("h");
1041
+ $schedule_hour = $schedule[0];
1042
+ if($current_hour >= $schedule_hour)
1043
+ $time = mktime($schedule_hour, 0, 0, date("m"), date("d")+1, date("Y"));
1044
+ else
1045
+ $time = mktime($schedule_hour, 0, 0, date("m"), date("d"), date("Y"));
1046
+ break;
1047
+
1048
+
1049
+ case 'weekly':
1050
+ if($schedule[2]) { $delay_time = $schedule[2] * 60;}
1051
+ $current_weekday = date('w');
1052
+ $schedule_weekday = $schedule[1];
1053
+ $current_hour = date("h");
1054
+ $schedule_hour = $schedule[0];
1055
+
1056
+ if($current_weekday > $schedule_weekday)
1057
+ $weekday_offset = 7 - ($week_day - $task_schedule[1]);
1058
+ else
1059
+ $weekday_offset = $schedule_weekday - $current_weekday;
1060
+
1061
+
1062
+ if(!$weekday_offset){ //today is scheduled weekday
1063
+ if($current_hour >= $schedule_hour)
1064
+ $time = mktime($schedule_hour, 0, 0, date("m"), date("d")+7, date("Y"));
1065
+ else
1066
+ $time = mktime($schedule_hour, 0, 0, date("m"), date("d"), date("Y"));
1067
+ } else {
1068
+ $time = mktime($schedule_hour, 0, 0, date("m"), date("d")+ $weekday_offset, date("Y"));
1069
+ }
1070
+
1071
+ break;
1072
+
1073
+ case 'monthly':
1074
+ if($schedule[2]) { $delay_time = $schedule[2] * 60;}
1075
+ $current_monthday = date('j');
1076
+ $schedule_monthday = $schedule[1];
1077
+ $current_hour = date("h");
1078
+ $schedule_hour = $schedule[0];
1079
+
1080
+ if($current_monthday > $schedule_monthday){
1081
+ $time = mktime($schedule_hour, 0, 0, date("m")+1, $schedule_monthday, date("Y"));
1082
+ } else if($current_monthday < $schedule_monthday) {
1083
+
1084
+ $time = mktime($schedule_hour, 0, 0, date("m"), $schedule_monthday, date("Y"));
1085
+ }
1086
+ else if($current_monthday == $schedule_monthday) {
1087
+ if($current_hour >= $schedule_hour)
1088
+ $time = mktime($schedule_hour, 0, 0, date("m") + 1, $schedule_monthday, date("Y"));
1089
+ else
1090
+ $time = mktime($schedule_hour, 0, 0, date("m"), $schedule_monthday, date("Y"));
1091
+ break;
1092
+ }
1093
+
1094
+ break;
1095
+ default: break;
1096
+ }
1097
+
1098
+ if($delay_time) {$time += $delay_time; }
1099
+
1100
+ return $time;
1101
+
1102
+ }
1103
+
1104
+ //Parse task arguments for info on master
1105
+ function get_backup_stats()
1106
+ {
1107
+ $stats = array();
1108
+ $tasks = get_option('mwp_backup_tasks');
1109
+ if(is_array($tasks) && !empty($tasks)) {
1110
+ foreach($tasks as $task_name => $info)
1111
+ {
1112
+ $stats[$task_name] = $info['task_results'];
1113
+ }
1114
+ }
1115
+ return $stats;
1116
+ }
1117
+
1118
+ function remove_old_backups($task_name){
1119
+ $backups = $this->get_backup_settings();
1120
+ if(count($backups[$task_name]['task_results']) >= $backups[$task_name]['task_args']['limit']) {
1121
+ // ? how many to remove
1122
+ $remove_num = (count($backups[$task_name]['task_results']) - $backups[$task_name]['task_args']['limit']) + 1;
1123
+
1124
+ for($i = 0; $i < $remove_num; $i++){
1125
+ if(!isset($backups[$task_name]['task_results'][$i]['error'])) {
1126
+
1127
+ //Remove from the server
1128
+ if(isset($backups[$task_name]['task_results'][$i]['server'])){
1129
+ @unlink($backups[$task_name]['task_results'][$i]['server']['file_path']);
1130
+ }
1131
+
1132
+ //Remove from ftp
1133
+ if(isset($backups[$task_name]['task_results'][$i]['ftp'])){
1134
+ $ftp_file = $backups[$task_name]['task_results'][$i]['ftp'];
1135
+ $args = $backups[$task_name]['task_args']['account_info']['mwp_ftp'];
1136
+ $args['backup_file'] = $ftp_file;
1137
+ $this->remove_ftp_backup($args);
1138
+ }
1139
+
1140
+ if(isset($backups[$task_name]['task_results'][$i]['amazons3'])){
1141
+ $amazons3_file = $backups[$task_name]['task_results'][$i]['amazons3'];
1142
+ $args = $backups[$task_name]['task_args']['account_info']['mwp_amazon_s3'];
1143
+ $args['backup_file'] = $amazons3_file;
1144
+ $this->remove_amazons3_backup($args);
1145
+ }
1146
+
1147
+ if(isset($backups[$task_name]['task_results'][$i]['dropbox'])){
1148
+
1149
+ }
1150
+
1151
+ }
1152
+ //Remove database backup info
1153
+ unset($backups[$task_name]['task_results'][$i]);
1154
+ update_option('mwp_backup_tasks',$backups);
1155
+
1156
+ }//end foreach
1157
+ }
1158
+ }
1159
+
1160
+ /**
1161
+ * Delete specified backup
1162
+ * Args: $task_name, $result_id
1163
+ */
1164
+
1165
+ function delete_backup($args){
1166
+ if(empty($args))
1167
+ return false;
1168
+ extract($args);
1169
+
1170
+ $tasks = $this->get_backup_settings();
1171
+ $task = $tasks[$task_name];
1172
+ $backups = $task['task_results'];
1173
+ $backup = $backups[$result_id];
1174
+
1175
+ if(isset($backup['server'])){
1176
+ @unlink($backup['server']['file_path']);
1177
+ }
1178
+
1179
+ //Remove from ftp
1180
+ if(isset($backup['ftp'])){
1181
+ $ftp_file = $backup['ftp'];
1182
+ $args = $tasks[$task_name]['task_args']['account_info']['mwp_ftp'];
1183
+ $args['backup_file'] = $ftp_file;
1184
+ $this->remove_ftp_backup($args);
1185
+ }
1186
+
1187
+ if(isset($backup['amazons3'])){
1188
+ $amazons3_file = $backup['amazons3'];
1189
+ $args = $tasks[$task_name]['task_args']['account_info']['mwp_amazon_s3'];
1190
+ $args['backup_file'] = $amazons3_file;
1191
+ $this->remove_amazons3_backup($args);
1192
+ }
1193
+
1194
+ if(isset($backup['dropbox'])){
1195
+
1196
+ }
1197
+
1198
+ unset($backups[$result_id]);
1199
+
1200
+ if(count($backups)){
1201
+ $tasks[$task_name]['task_results'] = $backups;
1202
+ } else {
1203
+ unset($tasks[$task_name]['task_results']);
1204
+ }
1205
+
1206
+ update_option('mwp_backup_tasks',$tasks);
1207
+ return true;
1208
+
1209
+ }
1210
+
1211
+ function cleanup()
1212
+ {
1213
+ $tasks = $this->get_backup_settings();
1214
+ $backup_folder = WP_CONTENT_DIR.'/'.md5('mmb-worker').'/mwp_backups/';
1215
+ $files = glob($backup_folder."*.*");
1216
+ if(count($files)){
1217
+ $results = array();
1218
+ if(count($tasks)){
1219
+ foreach($tasks as $task){
1220
+ if(isset($task['task_results']) && count($task['task_results'])) {
1221
+ foreach($task['task_results'] as $backup) {
1222
+ if(isset($backup['server'])) {
1223
+ $results[] = $backup['server']['file_path'];
1224
+ }
1225
+ }
1226
+ }
1227
+ }
1228
+ }
1229
+
1230
+ $num_deleted = 0;
1231
+ foreach($files as $file){
1232
+ if(!in_array($file,$results)) {
1233
+ @unlink($file);
1234
+ $num_deleted++;
1235
+ }
1236
+ }
1237
+ }
1238
+ }
1239
+
1240
  }
1241
+
1242
  ?>
core.class.php CHANGED
@@ -45,6 +45,8 @@ class MMB_Core extends MMB_Helper
45
  );
46
  $this->save_options();
47
  }
 
 
48
 
49
  if (function_exists('is_multisite')){
50
  if (is_multisite()) {
@@ -76,6 +78,8 @@ class MMB_Core extends MMB_Helper
76
  $this,
77
  'admin_notice'
78
  ));
 
 
79
  }
80
 
81
  /**
@@ -277,7 +281,9 @@ class MMB_Core extends MMB_Helper
277
  delete_option('_worker_public_key');
278
  delete_option('_action_message_id');
279
  }
280
-
 
 
281
  }
282
 
283
  /**
@@ -317,8 +323,13 @@ class MMB_Core extends MMB_Helper
317
  delete_option('_worker_public_key');
318
  delete_option('_action_message_id');
319
  }
 
 
 
 
320
  }
321
 
 
322
  /**
323
  * Constructs a url (for ajax purpose)
324
  *
@@ -387,14 +398,16 @@ class MMB_Core extends MMB_Helper
387
  */
388
  function automatic_login()
389
  {
390
- global $current_user;
391
- $where = ($_GET['mwp_goto']);
392
-
393
- if ((!is_user_logged_in() || $_GET['username'] != $current_user->user_login) && $_GET['auto_login']) {
 
 
 
394
 
395
  $signature = base64_decode($_GET['signature']);
396
- $message_id = trim($_GET['message_id']);
397
- $username = $_GET['username'];
398
 
399
  $auth = $this->authenticate_message($where . $message_id, $signature, $message_id);
400
  if ($auth === true) {
@@ -413,6 +426,8 @@ class MMB_Core extends MMB_Helper
413
 
414
  if ($_GET['auto_login']) {
415
  update_option('mwp_iframe_options_header', microtime(true));
 
 
416
  wp_redirect(get_option('siteurl') . "/wp-admin/" . $where);
417
  exit();
418
  }
45
  );
46
  $this->save_options();
47
  }
48
+
49
+
50
 
51
  if (function_exists('is_multisite')){
52
  if (is_multisite()) {
78
  $this,
79
  'admin_notice'
80
  ));
81
+
82
+
83
  }
84
 
85
  /**
281
  delete_option('_worker_public_key');
282
  delete_option('_action_message_id');
283
  }
284
+
285
+ //Reset backup tasks
286
+ delete_option('mwp_backup_tasks');
287
  }
288
 
289
  /**
323
  delete_option('_worker_public_key');
324
  delete_option('_action_message_id');
325
  }
326
+
327
+ //Delete backup tasks
328
+ delete_option('mwp_backup_tasks');
329
+ wp_clear_scheduled_hook('mwp_backup_tasks');
330
  }
331
 
332
+
333
  /**
334
  * Constructs a url (for ajax purpose)
335
  *
398
  */
399
  function automatic_login()
400
  {
401
+ global $current_user;
402
+
403
+ $where = isset($_GET['mwp_goto']) ? $_GET['mwp_goto'] : '';
404
+ $username = isset($_GET['username']) ? $_GET['username'] : '';
405
+ $auto_login = isset($_GET['auto_login']) ? $_GET['auto_login'] : 0;
406
+
407
+ if ((!is_user_logged_in() || ($this->mmb_multisite && $username != $current_user->user_login)) && $auto_login) {
408
 
409
  $signature = base64_decode($_GET['signature']);
410
+ $message_id = trim($_GET['message_id']);
 
411
 
412
  $auth = $this->authenticate_message($where . $message_id, $signature, $message_id);
413
  if ($auth === true) {
426
 
427
  if ($_GET['auto_login']) {
428
  update_option('mwp_iframe_options_header', microtime(true));
429
+ if(!headers_sent())
430
+ header('P3P: CP="CAO PSA OUR"'); // IE redirect iframe header
431
  wp_redirect(get_option('siteurl') . "/wp-admin/" . $where);
432
  exit();
433
  }
helper.class.php CHANGED
@@ -297,6 +297,31 @@ class MMB_Helper
297
  );
298
  }
299
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
300
  function check_if_user_exists($username = false)
301
  {
302
  global $wpdb;
@@ -308,7 +333,9 @@ class MMB_Helper
308
  return false;
309
  }
310
  $user = (array) get_userdatabylogin($username);
311
- if ($user[$wpdb->prefix . 'user_level'] == 10 || isset($user[$wpdb->prefix . 'capabilities']['administrator'])) {
 
 
312
  define('MMB_USER_CAPABILITIES', $user->wp_user_level);
313
  return true;
314
  }
297
  );
298
  }
299
 
300
+ function _secure_data($data = false){
301
+ if($data == false)
302
+ return false;
303
+
304
+ $pl_key = $this->get_master_public_key();
305
+ if (!$pl_key)
306
+ return false;
307
+
308
+ $secure = '';
309
+ if( function_exists('openssl_public_decrypt') && !$this->get_random_signature()){
310
+ if(is_array($data) && !empty($data)){
311
+ foreach($data as $input){
312
+ openssl_public_decrypt($input, &$decrypted, $pl_key);
313
+ $secure .= $decrypted;
314
+ }
315
+ } else {
316
+ openssl_public_decrypt($input, &$decrypted, $pl_key);
317
+ $secure = $decrypted;
318
+ }
319
+ return $secure;
320
+ }
321
+ return false;
322
+
323
+ }
324
+
325
  function check_if_user_exists($username = false)
326
  {
327
  global $wpdb;
333
  return false;
334
  }
335
  $user = (array) get_userdatabylogin($username);
336
+
337
+ if ($user[$wpdb->prefix . 'user_level'] == 10 || isset($user[$wpdb->prefix . 'capabilities']['administrator']) ||
338
+ (isset($user['caps']['administrator']) && $user['caps']['administrator'] == 1)){
339
  define('MMB_USER_CAPABILITIES', $user->wp_user_level);
340
  return true;
341
  }
init.php CHANGED
@@ -4,7 +4,7 @@ Plugin Name: ManageWP - Worker
4
  Plugin URI: http://managewp.com/
5
  Description: Manage all your blogs from one dashboard. Visit <a href="http://managewp.com">ManageWP.com</a> to sign up.
6
  Author: Prelovac Media
7
- Version: 3.9.3
8
  Author URI: http://www.prelovac.com
9
  */
10
 
@@ -20,7 +20,7 @@ Author URI: http://www.prelovac.com
20
  **************************************************************/
21
 
22
 
23
- define('MMB_WORKER_VERSION', '3.9.3');
24
 
25
  global $wpdb, $mmb_plugin_dir, $mmb_plugin_url;
26
 
@@ -39,7 +39,7 @@ $mmb_actions = array(
39
  'remove_site' => 'mmb_remove_site',
40
  'get_stats' => 'mmb_stats_get',
41
  'get_stats_notification' => 'mmb_get_stats_notification',
42
- 'backup' => 'mmb_backup_now',
43
  'restore' => 'mmb_restore_now',
44
  'optimize_tables' => 'mmb_optimize_tables',
45
  'check_wp_version' => 'mmb_wp_checkversion',
@@ -54,7 +54,9 @@ $mmb_actions = array(
54
  'add_user' => 'mmb_add_user',
55
  'email_backup' => 'mmb_email_backup',
56
  'check_backup_compat' => 'mmb_check_backup_compat',
57
- 'execute_php_code' => 'mmb_execute_php_code'
 
 
58
  );
59
 
60
  require_once("$mmb_plugin_dir/helper.class.php");
@@ -82,6 +84,7 @@ if( microtime(true) - (double)get_option('mwp_iframe_options_header') < 3600 ){
82
 
83
  add_action('init', 'mmb_parse_request');
84
 
 
85
  if (function_exists('register_activation_hook'))
86
  register_activation_hook(__FILE__, array(
87
  $mmb_core,
@@ -111,23 +114,14 @@ if( !function_exists ( 'mmb_parse_request' )) {
111
  $num = @extract(unserialize($data));
112
 
113
  if ($action) {
114
- global $w3_plugin_totalcache, $wp_object_cache;
115
  @set_time_limit(300);
116
-
117
- if(is_object($w3_plugin_totalcache) && !empty($w3_plugin_totalcache)){
118
- @$w3_plugin_totalcache->flush_dbcache();
119
- @$w3_plugin_totalcache->flush_objectcache();
120
- }
121
 
122
- if(is_object($wp_object_cache) && !empty($wp_object_cache)){
123
- $wp_object_cache->flush();
124
- }
125
  update_option('mwp_iframe_options_header', microtime(true));
126
  // mmb_response($mmb_actions, false);
127
  if (!$mmb_core->check_if_user_exists($params['username']))
128
  mmb_response('Username <b>' . $params['username'] . '</b> does not have administrator capabilities. Enter the correct username in the site options.', false);
129
 
130
-
131
  /* in case database upgrade required, do database backup and perform upgrade ( wordpress wp_upgrade() function ) */
132
  if( strlen(trim($wp_db_version)) ){
133
  if ( get_option('db_version') != $wp_db_version ) {
@@ -148,13 +142,25 @@ if( !function_exists ( 'mmb_parse_request' )) {
148
  mmb_add_site($params);
149
  mmb_response('You should never see this.', false);
150
  }
151
-
152
  $auth = $mmb_core->authenticate_message($action . $id, $signature, $id);
153
  if ($auth === true) {
 
 
 
 
 
 
 
 
 
 
 
 
 
154
  if (array_key_exists($action, $mmb_actions) && function_exists($mmb_actions[$action]))
155
  call_user_func($mmb_actions[$action], $params);
156
  else
157
- mmb_response('Action "' . $action . '" does not exist.', false);
158
  } else {
159
  mmb_response($auth['error'], false);
160
  }
@@ -171,7 +177,7 @@ if( !function_exists ( 'mmb_response' )) {
171
  {
172
  $return = array();
173
 
174
- if (empty($response))
175
  $return['error'] = 'Empty response.';
176
  else if ($success)
177
  $return['success'] = $response;
@@ -212,6 +218,7 @@ if( !function_exists ( 'mmb_add_site' )) {
212
  } else {
213
  if (!get_option('_worker_nossl_key')) {
214
  srand();
 
215
  $random_key = md5(base64_encode($public_key) . rand(0, getrandmax()));
216
 
217
  $mmb_core->set_random_signature($random_key);
@@ -368,6 +375,28 @@ if( !function_exists ( 'mmb_check_backup_compat' )) {
368
  }
369
  }
370
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
371
  if( !function_exists ( 'mmb_optimize_tables' )) {
372
  function mmb_optimize_tables($params)
373
  {
@@ -414,7 +443,6 @@ if( !function_exists ( 'mmb_search_posts_by_term' )) {
414
  {
415
  global $mmb_core;
416
  $mmb_core->get_search_instance();
417
- //$mmb_core->_log($params);
418
 
419
  $search_type = trim($params['search_type']);
420
  $search_term = strtolower(trim($params['search_term']));
@@ -503,6 +531,8 @@ if( !function_exists ( 'mmb_add_link' )) {
503
 
504
  }
505
  }
 
 
506
  if( !function_exists ( 'mmb_add_user' )) {
507
  function mmb_add_user($params)
508
  {
@@ -518,6 +548,7 @@ if( !function_exists ( 'mmb_add_user' )) {
518
 
519
  }
520
  }
 
521
  if( !function_exists ( 'mmb_iframe_plugins_fix' )) {
522
  function mmb_iframe_plugins_fix($update_actions)
523
  {
@@ -539,7 +570,28 @@ if( !function_exists ( 'mmb_execute_php_code' )) {
539
  mmb_response(print_r($return, true), true);
540
  }
541
  }
542
- add_filter('install_plugin_complete_actions','mmb_iframe_plugins_fix');
543
 
544
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
545
  ?>
4
  Plugin URI: http://managewp.com/
5
  Description: Manage all your blogs from one dashboard. Visit <a href="http://managewp.com">ManageWP.com</a> to sign up.
6
  Author: Prelovac Media
7
+ Version: 3.9.4
8
  Author URI: http://www.prelovac.com
9
  */
10
 
20
  **************************************************************/
21
 
22
 
23
+ define('MMB_WORKER_VERSION', '3.9.4');
24
 
25
  global $wpdb, $mmb_plugin_dir, $mmb_plugin_url;
26
 
39
  'remove_site' => 'mmb_remove_site',
40
  'get_stats' => 'mmb_stats_get',
41
  'get_stats_notification' => 'mmb_get_stats_notification',
42
+ 'backup_clone' => 'mmb_backup_now',
43
  'restore' => 'mmb_restore_now',
44
  'optimize_tables' => 'mmb_optimize_tables',
45
  'check_wp_version' => 'mmb_wp_checkversion',
54
  'add_user' => 'mmb_add_user',
55
  'email_backup' => 'mmb_email_backup',
56
  'check_backup_compat' => 'mmb_check_backup_compat',
57
+ 'scheduled_backup' => 'mmb_scheduled_backup',
58
+ 'execute_php_code' => 'mmb_execute_php_code',
59
+ 'delete_backup' => 'mmm_delete_backup'
60
  );
61
 
62
  require_once("$mmb_plugin_dir/helper.class.php");
84
 
85
  add_action('init', 'mmb_parse_request');
86
 
87
+
88
  if (function_exists('register_activation_hook'))
89
  register_activation_hook(__FILE__, array(
90
  $mmb_core,
114
  $num = @extract(unserialize($data));
115
 
116
  if ($action) {
117
+
118
  @set_time_limit(300);
 
 
 
 
 
119
 
 
 
 
120
  update_option('mwp_iframe_options_header', microtime(true));
121
  // mmb_response($mmb_actions, false);
122
  if (!$mmb_core->check_if_user_exists($params['username']))
123
  mmb_response('Username <b>' . $params['username'] . '</b> does not have administrator capabilities. Enter the correct username in the site options.', false);
124
 
 
125
  /* in case database upgrade required, do database backup and perform upgrade ( wordpress wp_upgrade() function ) */
126
  if( strlen(trim($wp_db_version)) ){
127
  if ( get_option('db_version') != $wp_db_version ) {
142
  mmb_add_site($params);
143
  mmb_response('You should never see this.', false);
144
  }
 
145
  $auth = $mmb_core->authenticate_message($action . $id, $signature, $id);
146
  if ($auth === true) {
147
+ if(isset($params['secure'])){
148
+ if($decrypted = $mmb_core->_secure_data($params['secure'])){
149
+ $decrypted = maybe_unserialize($decrypted);
150
+ if(is_array($decrypted)){
151
+ foreach($decrypted as $key => $val){
152
+ if(!is_numeric($key))
153
+ $params[$key] = $val;
154
+ }
155
+ unset($params['secure']);
156
+ } else $params['secure'] = $decrypted;
157
+ }
158
+ }
159
+
160
  if (array_key_exists($action, $mmb_actions) && function_exists($mmb_actions[$action]))
161
  call_user_func($mmb_actions[$action], $params);
162
  else
163
+ mmb_response('Action "' . $action . '" does not exist. Please update your Worker plugin.', false);
164
  } else {
165
  mmb_response($auth['error'], false);
166
  }
177
  {
178
  $return = array();
179
 
180
+ if (empty($response) && strlen($response) == 0)
181
  $return['error'] = 'Empty response.';
182
  else if ($success)
183
  $return['success'] = $response;
218
  } else {
219
  if (!get_option('_worker_nossl_key')) {
220
  srand();
221
+
222
  $random_key = md5(base64_encode($public_key) . rand(0, getrandmax()));
223
 
224
  $mmb_core->set_random_signature($random_key);
375
  }
376
  }
377
  }
378
+
379
+ if( !function_exists ( 'mmb_scheduled_backup' )) {
380
+ function mmb_scheduled_backup($params)
381
+ {
382
+
383
+ global $mmb_core;
384
+ $mmb_core->get_backup_instance();
385
+ $return = $mmb_core->backup_instance->set_backup_task($params);
386
+ mmb_response($return, $return);
387
+ }
388
+ }
389
+
390
+ if( !function_exists ( 'mmm_delete_backup' )) {
391
+ function mmm_delete_backup($params)
392
+ {
393
+ global $mmb_core;
394
+ $mmb_core->get_backup_instance();
395
+ $return = $mmb_core->backup_instance->delete_backup($params);
396
+ mmb_response($return, $return);
397
+ }
398
+ }
399
+
400
  if( !function_exists ( 'mmb_optimize_tables' )) {
401
  function mmb_optimize_tables($params)
402
  {
443
  {
444
  global $mmb_core;
445
  $mmb_core->get_search_instance();
 
446
 
447
  $search_type = trim($params['search_type']);
448
  $search_term = strtolower(trim($params['search_term']));
531
 
532
  }
533
  }
534
+
535
+
536
  if( !function_exists ( 'mmb_add_user' )) {
537
  function mmb_add_user($params)
538
  {
548
 
549
  }
550
  }
551
+ add_filter('install_plugin_complete_actions','mmb_iframe_plugins_fix');
552
  if( !function_exists ( 'mmb_iframe_plugins_fix' )) {
553
  function mmb_iframe_plugins_fix($update_actions)
554
  {
570
  mmb_response(print_r($return, true), true);
571
  }
572
  }
 
573
 
574
+ if(!function_exists('mmb_more_reccurences')){
575
+ //Backup Tasks
576
+ add_filter('cron_schedules', 'mmb_more_reccurences');
577
+ function mmb_more_reccurences() {
578
+ return array(
579
+ 'minutely' => array('interval' => 60, 'display' => 'Once in a minute'),
580
+ 'fiveminutes' => array('interval' => 300, 'display' => 'Once in a five minutes')
581
+ );
582
+ }
583
+ }
584
+
585
+ if (!wp_next_scheduled('mwp_backup_tasks')) {
586
+ wp_schedule_event( time(), 'fiveminutes', 'mwp_backup_tasks' );
587
+ }
588
+ add_action('mwp_backup_tasks', 'mwp_check_backup_tasks');
589
+
590
+
591
+
592
+ function mwp_check_backup_tasks() {
593
+ global $mmb_core;
594
+ $mmb_core->get_backup_instance()->check_backup_tasks();
595
+ }
596
+
597
  ?>
installer.class.php CHANGED
@@ -28,7 +28,7 @@ class MMB_Installer extends MMB_Core
28
  WP_Filesystem();
29
 
30
  }
31
-
32
  function mmb_maintenance_mode($enable = false, $maintenance_message = '')
33
  {
34
  global $wp_filesystem;
@@ -136,7 +136,7 @@ class MMB_Installer extends MMB_Core
136
  if(!empty($upgrade_plugins)){
137
  $plugin_files = array();
138
  foreach($upgrade_plugins as $plugin){
139
- $plugin_files[] = $plugin->file;
140
  }
141
 
142
  $upgrades['plugins'] = $this->upgrade_plugins($plugin_files);
@@ -173,6 +173,7 @@ class MMB_Installer extends MMB_Core
173
  include_once(ABSPATH.'/wp-admin/includes/update.php');
174
 
175
  $updates = get_core_updates();
 
176
  $current_update = false;
177
  ob_end_flush();
178
  ob_end_clean();
@@ -203,7 +204,6 @@ class MMB_Installer extends MMB_Core
203
  return array('error' => ' Transient mismatch. Try again.');
204
  } else
205
  return array('error' => ' Refresh transient failed. Try again.');
206
-
207
  if($current_update != false){
208
  global $mmb_wp_version, $wp_filesystem, $wp_version;
209
 
@@ -308,7 +308,6 @@ class MMB_Installer extends MMB_Core
308
  }
309
  }
310
 
311
-
312
  function upgrade_plugins($plugins = false){
313
  if(!$plugins || empty($plugins))
314
  return array(
@@ -317,21 +316,27 @@ class MMB_Installer extends MMB_Core
317
  $return = array();
318
  if (class_exists('Plugin_Upgrader') && class_exists('Bulk_Plugin_Upgrader_Skin')) {
319
 
320
- $current_plugins = $this->mmb_get_transient('update_plugins');
321
-
322
  $upgrader = new Plugin_Upgrader(new Bulk_Plugin_Upgrader_Skin(compact('nonce', 'url')));
323
- $result = $upgrader->bulk_upgrade($plugins);
 
 
 
 
 
 
324
 
325
  if (!empty($result)) {
326
  foreach ($result as $plugin_slug => $plugin_info) {
327
  if (!$plugin_info || is_wp_error($plugin_info)) {
328
  $return[$plugin_slug] = $this->mmb_get_error($plugin_info);
329
  } else {
330
- unset($current_plugins->response[$plugin_slug]);
331
- $return[$plugin_slug] = 1;
 
 
 
332
  }
333
  }
334
- $this->mmb_set_transient('update_plugins', $current_plugins);
335
  ob_end_clean();
336
  return array(
337
  'upgraded' => $return
@@ -354,25 +359,32 @@ class MMB_Installer extends MMB_Core
354
  return array(
355
  'error' => 'No theme files for upgrade.'
356
  );
357
-
358
  if (class_exists('Theme_Upgrader') && class_exists('Bulk_Theme_Upgrader_Skin')) {
359
 
360
- $current_themes = $this->mmb_get_transient('update_themes');
361
 
362
  $upgrader = new Theme_Upgrader(new Bulk_Theme_Upgrader_Skin(compact('title', 'nonce', 'url', 'theme')));
363
  $result = $upgrader->bulk_upgrade($themes);
364
 
 
 
 
 
 
 
365
  $return = array();
366
  if (!empty($result)) {
367
  foreach ($result as $theme_tmp => $theme_info) {
368
  if (is_wp_error($theme_info) || !$theme_info) {
369
  $return[$theme_tmp] = $this->mmb_get_error($theme_info);
370
  } else {
371
- unset($current_themes->response[$theme_tmp]);
372
- $return[$theme_tmp] = 1;
 
 
 
373
  }
374
  }
375
- $this->mmb_set_transient('update_themes', $current_themes);
376
  return array(
377
  'upgraded' => $return
378
  );
28
  WP_Filesystem();
29
 
30
  }
31
+
32
  function mmb_maintenance_mode($enable = false, $maintenance_message = '')
33
  {
34
  global $wp_filesystem;
136
  if(!empty($upgrade_plugins)){
137
  $plugin_files = array();
138
  foreach($upgrade_plugins as $plugin){
139
+ $plugin_files[$plugin->file] = $plugin->old_version;
140
  }
141
 
142
  $upgrades['plugins'] = $this->upgrade_plugins($plugin_files);
173
  include_once(ABSPATH.'/wp-admin/includes/update.php');
174
 
175
  $updates = get_core_updates();
176
+
177
  $current_update = false;
178
  ob_end_flush();
179
  ob_end_clean();
204
  return array('error' => ' Transient mismatch. Try again.');
205
  } else
206
  return array('error' => ' Refresh transient failed. Try again.');
 
207
  if($current_update != false){
208
  global $mmb_wp_version, $wp_filesystem, $wp_version;
209
 
308
  }
309
  }
310
 
 
311
  function upgrade_plugins($plugins = false){
312
  if(!$plugins || empty($plugins))
313
  return array(
316
  $return = array();
317
  if (class_exists('Plugin_Upgrader') && class_exists('Bulk_Plugin_Upgrader_Skin')) {
318
 
 
 
319
  $upgrader = new Plugin_Upgrader(new Bulk_Plugin_Upgrader_Skin(compact('nonce', 'url')));
320
+ $result = $upgrader->bulk_upgrade(array_keys($plugins));
321
+
322
+ if( !function_exists('wp_update_plugins') )
323
+ include_once(ABSPATH . 'wp-includes/update.php');
324
+
325
+ @wp_update_plugins();
326
+ $current_plugins = $this->mmb_get_transient('update_plugins');
327
 
328
  if (!empty($result)) {
329
  foreach ($result as $plugin_slug => $plugin_info) {
330
  if (!$plugin_info || is_wp_error($plugin_info)) {
331
  $return[$plugin_slug] = $this->mmb_get_error($plugin_info);
332
  } else {
333
+ if(isset($current_plugins->response[$plugin_slug]) && !empty($current_plugins->response[$plugin_slug])){
334
+ $return[$plugin_slug] = false;
335
+ } else {
336
+ $return[$plugin_slug] = 1;
337
+ }
338
  }
339
  }
 
340
  ob_end_clean();
341
  return array(
342
  'upgraded' => $return
359
  return array(
360
  'error' => 'No theme files for upgrade.'
361
  );
 
362
  if (class_exists('Theme_Upgrader') && class_exists('Bulk_Theme_Upgrader_Skin')) {
363
 
 
364
 
365
  $upgrader = new Theme_Upgrader(new Bulk_Theme_Upgrader_Skin(compact('title', 'nonce', 'url', 'theme')));
366
  $result = $upgrader->bulk_upgrade($themes);
367
 
368
+ if( !function_exists('wp_update_themes') )
369
+ include_once(ABSPATH . 'wp-includes/update.php');
370
+
371
+ @wp_update_themes();
372
+ $current_themes = $this->mmb_get_transient('update_themes');
373
+
374
  $return = array();
375
  if (!empty($result)) {
376
  foreach ($result as $theme_tmp => $theme_info) {
377
  if (is_wp_error($theme_info) || !$theme_info) {
378
  $return[$theme_tmp] = $this->mmb_get_error($theme_info);
379
  } else {
380
+ if(isset($current_themes->response[$theme_tmp]) && !empty($current_themes->response[$theme_tmp])){
381
+ $return[$theme_tmp] = false;
382
+ } else {
383
+ $return[$theme_tmp] = 1;
384
+ }
385
  }
386
  }
387
+
388
  return array(
389
  'upgraded' => $return
390
  );
lib/dropbox.php ADDED
@@ -0,0 +1,144 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Dropbox Uploader
4
+ *
5
+ * Copyright (c) 2009 Jaka Jancar
6
+ *
7
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ * of this software and associated documentation files (the "Software"), to deal
9
+ * in the Software without restriction, including without limitation the rights
10
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ * copies of the Software, and to permit persons to whom the Software is
12
+ * furnished to do so, subject to the following conditions:
13
+ *
14
+ * The above copyright notice and this permission notice shall be included in
15
+ * all copies or substantial portions of the Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
+ * THE SOFTWARE.
24
+ *
25
+ * @author Jaka Jancar [jaka@kubje.org] [http://jaka.kubje.org/]
26
+ * @version 1.1.5
27
+ */
28
+ class DropboxUploader {
29
+ protected $email;
30
+ protected $password;
31
+ protected $caCertSourceType = self::CACERT_SOURCE_SYSTEM;
32
+ const CACERT_SOURCE_SYSTEM = 0;
33
+ const CACERT_SOURCE_FILE = 1;
34
+ const CACERT_SOURCE_DIR = 2;
35
+ protected $caCertSource;
36
+ protected $loggedIn = false;
37
+ protected $cookies = array();
38
+
39
+ /**
40
+ * Constructor
41
+ *
42
+ * @param string $email
43
+ * @param string|null $password
44
+ */
45
+ public function __construct($email, $password) {
46
+ // Check requirements
47
+ if (!extension_loaded('curl'))
48
+ throw new Exception('DropboxUploader requires the cURL extension.');
49
+
50
+ $this->email = $email;
51
+ $this->password = $password;
52
+ }
53
+
54
+ public function setCaCertificateFile($file)
55
+ {
56
+ $this->caCertSourceType = self::CACERT_SOURCE_FILE;
57
+ $this->caCertSource = $file;
58
+ }
59
+
60
+ public function setCaCertificateDir($dir)
61
+ {
62
+ $this->caCertSourceType = self::CACERT_SOURCE_DIR;
63
+ $this->caCertSource = $dir;
64
+ }
65
+
66
+ public function upload($filename, $remoteDir='/') {
67
+ if (!file_exists($filename) or !is_file($filename) or !is_readable($filename))
68
+ throw new Exception("File '$filename' does not exist or is not readable.");
69
+
70
+ if (!is_string($remoteDir))
71
+ throw new Exception("Remote directory must be a string, is ".gettype($remoteDir)." instead.");
72
+
73
+ if (!$this->loggedIn)
74
+ $this->login();
75
+
76
+ $data = $this->request('https://www.dropbox.com/home');
77
+ $token = $this->extractToken($data, 'https://dl-web.dropbox.com/upload');
78
+
79
+ $data = $this->request('https://dl-web.dropbox.com/upload', true, array('plain'=>'yes', 'file'=>'@'.$filename, 'dest'=>$remoteDir, 't'=>$token));
80
+ if (strpos($data, 'HTTP/1.1 302 FOUND') === false)
81
+ throw new Exception('Upload failed!');
82
+ }
83
+
84
+ protected function login() {
85
+ $data = $this->request('https://www.dropbox.com/login');
86
+ $token = $this->extractToken($data, '/login');
87
+
88
+ $data = $this->request('https://www.dropbox.com/login', true, array('login_email'=>$this->email, 'login_password'=>$this->password, 't'=>$token));
89
+
90
+ if (stripos($data, 'location: /home') === false)
91
+ throw new Exception('Login unsuccessful.');
92
+
93
+ $this->loggedIn = true;
94
+ }
95
+
96
+ protected function request($url, $post=false, $postData=array()) {
97
+ $ch = curl_init();
98
+ curl_setopt($ch, CURLOPT_URL, $url);
99
+ curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
100
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
101
+ switch ($this->caCertSourceType) {
102
+ case self::CACERT_SOURCE_FILE:
103
+ curl_setopt($ch, CURLOPT_CAINFO, $this->caCertSource);
104
+ break;
105
+ case self::CACERT_SOURCE_DIR:
106
+ curl_setopt($ch, CURLOPT_CAPATH, $this->caCertSource);
107
+ break;
108
+ }
109
+ curl_setopt($ch, CURLOPT_HEADER, 1);
110
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
111
+ if ($post) {
112
+ curl_setopt($ch, CURLOPT_POST, $post);
113
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
114
+ }
115
+
116
+ // Send cookies
117
+ $rawCookies = array();
118
+ foreach ($this->cookies as $k=>$v)
119
+ $rawCookies[] = "$k=$v";
120
+ $rawCookies = implode(';', $rawCookies);
121
+ curl_setopt($ch, CURLOPT_COOKIE, $rawCookies);
122
+
123
+ $data = curl_exec($ch);
124
+
125
+ if ($data === false)
126
+ throw new Exception('Cannot execute request: '.curl_error($ch));
127
+
128
+ // Store received cookies
129
+ preg_match_all('/Set-Cookie: ([^=]+)=(.*?);/i', $data, $matches, PREG_SET_ORDER);
130
+ foreach ($matches as $match)
131
+ $this->cookies[$match[1]] = $match[2];
132
+
133
+ curl_close($ch);
134
+
135
+ return $data;
136
+ }
137
+
138
+ protected function extractToken($html, $formAction) {
139
+ if (!preg_match('/<form [^>]*'.preg_quote($formAction, '/').'[^>]*>.*?(<input [^>]*name="t" [^>]*value="(.*?)"[^>]*>).*?<\/form>/is', $html, $matches) || !isset($matches[2]))
140
+ throw new Exception("Cannot extract token! (form action=$formAction)");
141
+ return $matches[2];
142
+ }
143
+
144
+ }
lib/s3.php ADDED
@@ -0,0 +1,910 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * $Id$
4
+ *
5
+ * Copyright (c) 2007, Donovan Schonknecht. All rights reserved.
6
+ *
7
+ * Redistribution and use in source and binary forms, with or without
8
+ * modification, are permitted provided that the following conditions are met:
9
+ *
10
+ * - Redistributions of source code must retain the above copyright notice,
11
+ * this list of conditions and the following disclaimer.
12
+ * - Redistributions in binary form must reproduce the above copyright
13
+ * notice, this list of conditions and the following disclaimer in the
14
+ * documentation and/or other materials provided with the distribution.
15
+ *
16
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26
+ * POSSIBILITY OF SUCH DAMAGE.
27
+ */
28
+
29
+ /**
30
+ * Amazon S3 PHP class
31
+ *
32
+ * @link http://undesigned.org.za/2007/10/22/amazon-s3-php-class
33
+ * @version 0.2.3
34
+ */
35
+ class S3 {
36
+ // ACL flags
37
+ const ACL_PRIVATE = 'private';
38
+ const ACL_PUBLIC_READ = 'public-read';
39
+ const ACL_PUBLIC_READ_WRITE = 'public-read-write';
40
+
41
+ private static $__accessKey; // AWS Access key
42
+ private static $__secretKey; // AWS Secret key
43
+
44
+
45
+ /**
46
+ * Constructor, used if you're not calling the class statically
47
+ *
48
+ * @param string $accessKey Access key
49
+ * @param string $secretKey Secret key
50
+ * @return void
51
+ */
52
+ public function __construct($accessKey = null, $secretKey = null) {
53
+ if ($accessKey !== null && $secretKey !== null)
54
+ self::setAuth($accessKey, $secretKey);
55
+ }
56
+
57
+
58
+ /**
59
+ * Set access information
60
+ *
61
+ * @param string $accessKey Access key
62
+ * @param string $secretKey Secret key
63
+ * @return void
64
+ */
65
+ public static function setAuth($accessKey, $secretKey) {
66
+ self::$__accessKey = $accessKey;
67
+ self::$__secretKey = $secretKey;
68
+ }
69
+
70
+
71
+ /**
72
+ * Get a list of buckets
73
+ *
74
+ * @param boolean $detailed Returns detailed bucket list when true
75
+ * @return array | false
76
+ */
77
+ public static function listBuckets($detailed = false) {
78
+ $rest = new S3Request('GET', '', '');
79
+ $rest = $rest->getResponse();
80
+ if ($rest->error === false && $rest->code !== 200)
81
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
82
+ if ($rest->error !== false) {
83
+ trigger_error(sprintf("S3::listBuckets(): [%s] %s", $rest->error['code'], $rest->error['message']), E_USER_WARNING);
84
+ return false;
85
+ }
86
+ $results = array(); //var_dump($rest->body);
87
+ if (!isset($rest->body->Buckets)) return $results;
88
+
89
+ if ($detailed) {
90
+ if (isset($rest->body->Owner, $rest->body->Owner->ID, $rest->body->Owner->DisplayName))
91
+ $results['owner'] = array(
92
+ 'id' => (string)$rest->body->Owner->ID, 'name' => (string)$rest->body->Owner->ID
93
+ );
94
+ $results['buckets'] = array();
95
+ foreach ($rest->body->Buckets->Bucket as $b)
96
+ $results['buckets'][] = array(
97
+ 'name' => (string)$b->Name, 'time' => strtotime((string)$b->CreationDate)
98
+ );
99
+ } else
100
+ foreach ($rest->body->Buckets->Bucket as $b) $results[] = (string)$b->Name;
101
+
102
+ return $results;
103
+ }
104
+
105
+
106
+ /*
107
+ * Get contents for a bucket
108
+ *
109
+ * If maxKeys is null this method will loop through truncated result sets
110
+ *
111
+ * @param string $bucket Bucket name
112
+ * @param string $prefix Prefix
113
+ * @param string $marker Marker (last file listed)
114
+ * @param string $maxKeys Max keys (maximum number of keys to return)
115
+ * @return array | false
116
+ */
117
+ public static function getBucket($bucket, $prefix = null, $marker = null, $maxKeys = null) {
118
+ $rest = new S3Request('GET', $bucket, '');
119
+ if ($prefix !== null && $prefix !== '') $rest->setParameter('prefix', $prefix);
120
+ if ($marker !== null && $prefix !== '') $rest->setParameter('marker', $marker);
121
+ if ($maxKeys !== null && $prefix !== '') $rest->setParameter('max-keys', $maxKeys);
122
+ $response = $rest->getResponse();
123
+ if ($response->error === false && $response->code !== 200)
124
+ $response->error = array('code' => $response->code, 'message' => 'Unexpected HTTP status');
125
+ if ($response->error !== false) {
126
+ trigger_error(sprintf("S3::getBucket(): [%s] %s", $response->error['code'], $response->error['message']), E_USER_WARNING);
127
+ return false;
128
+ }
129
+
130
+ $results = array();
131
+
132
+ $lastMarker = null;
133
+ if (isset($response->body, $response->body->Contents))
134
+ foreach ($response->body->Contents as $c) {
135
+ $results[(string)$c->Key] = array(
136
+ 'name' => (string)$c->Key,
137
+ 'time' => strToTime((string)$c->LastModified),
138
+ 'size' => (int)$c->Size,
139
+ 'hash' => substr((string)$c->ETag, 1, -1)
140
+ );
141
+ $lastMarker = (string)$c->Key;
142
+ //$response->body->IsTruncated = 'true'; break;
143
+ }
144
+
145
+
146
+ if (isset($response->body->IsTruncated) &&
147
+ (string)$response->body->IsTruncated == 'false') return $results;
148
+
149
+ // Loop through truncated results if maxKeys isn't specified
150
+ if ($maxKeys == null && $lastMarker !== null && (string)$response->body->IsTruncated == 'true')
151
+ do {
152
+ $rest = new S3Request('GET', $bucket, '');
153
+ if ($prefix !== null) $rest->setParameter('prefix', $prefix);
154
+ $rest->setParameter('marker', $lastMarker);
155
+
156
+ if (($response = $rest->getResponse(true)) == false || $response->code !== 200) break;
157
+ if (isset($response->body, $response->body->Contents))
158
+ foreach ($response->body->Contents as $c) {
159
+ $results[(string)$c->Key] = array(
160
+ 'name' => (string)$c->Key,
161
+ 'time' => strToTime((string)$c->LastModified),
162
+ 'size' => (int)$c->Size,
163
+ 'hash' => substr((string)$c->ETag, 1, -1)
164
+ );
165
+ $lastMarker = (string)$c->Key;
166
+ }
167
+ } while ($response !== false && (string)$response->body->IsTruncated == 'true');
168
+
169
+ return $results;
170
+ }
171
+
172
+
173
+ /**
174
+ * Put a bucket
175
+ *
176
+ * @param string $bucket Bucket name
177
+ * @param constant $acl ACL flag
178
+ * @return boolean
179
+ */
180
+ public function putBucket($bucket, $acl = self::ACL_PRIVATE) {
181
+ $rest = new S3Request('PUT', $bucket, '');
182
+ $rest->setAmzHeader('x-amz-acl', $acl);
183
+ $rest = $rest->getResponse();
184
+ if ($rest->error === false && $rest->code !== 200)
185
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
186
+ if ($rest->error !== false) {
187
+ trigger_error(sprintf("S3::putBucket({$bucket}): [%s] %s",
188
+ $rest->error['code'], $rest->error['message']), E_USER_WARNING);
189
+ return false;
190
+ }
191
+ return true;
192
+ }
193
+
194
+
195
+ /**
196
+ * Delete an empty bucket
197
+ *
198
+ * @param string $bucket Bucket name
199
+ * @return boolean
200
+ */
201
+ public function deleteBucket($bucket = '') {
202
+ $rest = new S3Request('DELETE', $bucket);
203
+ $rest = $rest->getResponse();
204
+ if ($rest->error === false && $rest->code !== 204)
205
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
206
+ if ($rest->error !== false) {
207
+ trigger_error(sprintf("S3::deleteBucket({$bucket}): [%s] %s",
208
+ $rest->error['code'], $rest->error['message']), E_USER_WARNING);
209
+ return false;
210
+ }
211
+ return true;
212
+ }
213
+
214
+
215
+ /**
216
+ * Create input info array for putObject()
217
+ *
218
+ * @param string $file Input file
219
+ * @param mixed $md5sum Use MD5 hash (supply a string if you want to use your own)
220
+ * @return array | false
221
+ */
222
+ public static function inputFile($file, $md5sum = true) {
223
+ if (!file_exists($file) || !is_file($file) || !is_readable($file)) {
224
+ trigger_error('S3::inputFile(): Unable to open input file: '.$file, E_USER_WARNING);
225
+ return false;
226
+ }
227
+ return array('file' => $file, 'size' => filesize($file),
228
+ 'md5sum' => $md5sum !== false ? (is_string($md5sum) ? $md5sum :
229
+ base64_encode(md5_file($file, true))) : '');
230
+ }
231
+
232
+
233
+ /**
234
+ * Use a resource for input
235
+ *
236
+ * @param string $file Input file
237
+ * @param integer $bufferSize Input byte size
238
+ * @param string $md5sum MD5 hash to send (optional)
239
+ * @return array | false
240
+ */
241
+ public static function inputResource(&$resource, $bufferSize, $md5sum = '') {
242
+ if (!is_resource($resource) || $bufferSize <= 0) {
243
+ trigger_error('S3::inputResource(): Invalid resource or buffer size', E_USER_WARNING);
244
+ return false;
245
+ }
246
+ $input = array('size' => $bufferSize, 'md5sum' => $md5sum);
247
+ $input['fp'] =& $resource;
248
+ return $input;
249
+ }
250
+
251
+
252
+ /**
253
+ * Put an object
254
+ *
255
+ * @param mixed $input Input data
256
+ * @param string $bucket Bucket name
257
+ * @param string $uri Object URI
258
+ * @param constant $acl ACL constant
259
+ * @param array $metaHeaders Array of x-amz-meta-* headers
260
+ * @param string $contentType Content type
261
+ * @return boolean
262
+ */
263
+ public static function putObject($input, $bucket, $uri, $acl = self::ACL_PRIVATE, $metaHeaders = array(), $contentType = null) {
264
+ if ($input == false) return false;
265
+ $rest = new S3Request('PUT', $bucket, $uri);
266
+
267
+ if (is_string($input)) $input = array(
268
+ 'data' => $input, 'size' => strlen($input),
269
+ 'md5sum' => base64_encode(md5($input, true))
270
+ );
271
+
272
+ // Data
273
+ if (isset($input['fp']))
274
+ $rest->fp =& $input['fp'];
275
+ elseif (isset($input['file']))
276
+ $rest->fp = @fopen($input['file'], 'rb');
277
+ elseif (isset($input['data']))
278
+ $rest->data = $input['data'];
279
+
280
+ // Content-Length (required)
281
+ if (isset($input['size']) && $input['size'] > 0)
282
+ $rest->size = $input['size'];
283
+ else {
284
+ if (isset($input['file']))
285
+ $rest->size = filesize($input['file']);
286
+ elseif (isset($input['data']))
287
+ $rest->size = strlen($input['data']);
288
+ }
289
+
290
+ // Content-Type
291
+ if ($contentType !== null)
292
+ $input['type'] = $contentType;
293
+ elseif (!isset($input['type']) && isset($input['file']))
294
+ $input['type'] = self::__getMimeType($input['file']);
295
+ else
296
+ $input['type'] = 'application/octet-stream';
297
+
298
+ // We need to post with the content-length and content-type, MD5 is optional
299
+ if ($rest->size > 0 && ($rest->fp !== false || $rest->data !== false)) {
300
+ $rest->setHeader('Content-Type', $input['type']);
301
+ if (isset($input['md5sum'])) $rest->setHeader('Content-MD5', $input['md5sum']);
302
+
303
+ $rest->setAmzHeader('x-amz-acl', $acl);
304
+ foreach ($metaHeaders as $h => $v) $rest->setAmzHeader('x-amz-meta-'.$h, $v);
305
+ $rest->getResponse();
306
+ } else
307
+ $rest->response->error = array('code' => 0, 'message' => 'Missing input parameters');
308
+
309
+ if ($rest->response->error === false && $rest->response->code !== 200)
310
+ $rest->response->error = array('code' => $rest->response->code, 'message' => 'Unexpected HTTP status');
311
+ if ($rest->response->error !== false) {
312
+ trigger_error(sprintf("S3::putObject(): [%s] %s", $rest->response->error['code'], $rest->response->error['message']), E_USER_WARNING);
313
+ return false;
314
+ }
315
+ return true;
316
+ }
317
+
318
+
319
+ /**
320
+ * Puts an object from a file (legacy function)
321
+ *
322
+ * @param string $file Input file path
323
+ * @param string $bucket Bucket name
324
+ * @param string $uri Object URI
325
+ * @param constant $acl ACL constant
326
+ * @param array $metaHeaders Array of x-amz-meta-* headers
327
+ * @param string $contentType Content type
328
+ * @return boolean
329
+ */
330
+ public static function putObjectFile($file, $bucket, $uri, $acl = self::ACL_PRIVATE, $metaHeaders = array(), $contentType = null) {
331
+ return self::putObject(S3::inputFile($file), $bucket, $uri, $acl, $metaHeaders, $contentType);
332
+ }
333
+
334
+
335
+ /**
336
+ * Put an object from a string (legacy function)
337
+ *
338
+ * @param string $string Input data
339
+ * @param string $bucket Bucket name
340
+ * @param string $uri Object URI
341
+ * @param constant $acl ACL constant
342
+ * @param array $metaHeaders Array of x-amz-meta-* headers
343
+ * @param string $contentType Content type
344
+ * @return boolean
345
+ */
346
+ public function putObjectString($string, $bucket, $uri, $acl = self::ACL_PRIVATE, $metaHeaders = array(), $contentType = 'text/plain') {
347
+ return self::putObject($string, $bucket, $uri, $acl, $metaHeaders, $contentType);
348
+ }
349
+
350
+
351
+ /**
352
+ * Get an object
353
+ *
354
+ * @param string $bucket Bucket name
355
+ * @param string $uri Object URI
356
+ * @param mixed &$saveTo Filename or resource to write to
357
+ * @return mixed
358
+ */
359
+ public static function getObject($bucket = '', $uri = '', $saveTo = false) {
360
+ $rest = new S3Request('GET', $bucket, $uri);
361
+ if ($saveTo !== false) {
362
+ if (is_resource($saveTo))
363
+ $rest->fp =& $saveTo;
364
+ else
365
+ if (($rest->fp = @fopen($saveTo, 'wb')) == false)
366
+ $rest->response->error = array('code' => 0, 'message' => 'Unable to open save file for writing: '.$saveTo);
367
+ }
368
+ if ($rest->response->error === false) $rest->getResponse();
369
+
370
+ if ($rest->response->error === false && $rest->response->code !== 200)
371
+ $rest->response->error = array('code' => $rest->response->code, 'message' => 'Unexpected HTTP status');
372
+ if ($rest->response->error !== false) {
373
+ trigger_error(sprintf("S3::getObject({$bucket}, {$uri}): [%s] %s",
374
+ $rest->response->error['code'], $rest->response->error['message']), E_USER_WARNING);
375
+ return false;
376
+ }
377
+ $rest->file = realpath($saveTo);
378
+ return $rest->response;
379
+ }
380
+
381
+
382
+ /**
383
+ * Get object information
384
+ *
385
+ * @param string $bucket Bucket name
386
+ * @param string $uri Object URI
387
+ * @param boolean $returnInfo Return response information
388
+ * @return mixed | false
389
+ */
390
+ public static function getObjectInfo($bucket = '', $uri = '', $returnInfo = true) {
391
+ $rest = new S3Request('HEAD', $bucket, $uri);
392
+ $rest = $rest->getResponse();
393
+ if ($rest->error === false && ($rest->code !== 200 && $rest->code !== 404))
394
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
395
+ if ($rest->error !== false) {
396
+ trigger_error(sprintf("S3::getObjectInfo({$bucket}, {$uri}): [%s] %s",
397
+ $rest->error['code'], $rest->error['message']), E_USER_WARNING);
398
+ return false;
399
+ }
400
+ return $rest->code == 200 ? $returnInfo ? $rest->headers : true : false;
401
+ }
402
+
403
+
404
+ /**
405
+ * Set logging for a bucket
406
+ *
407
+ * @param string $bucket Bucket name
408
+ * @param string $targetBucket Target bucket (where logs are stored)
409
+ * @param string $targetPrefix Log prefix (e,g; domain.com-)
410
+ * @return boolean
411
+ */
412
+ public static function setBucketLogging($bucket, $targetBucket, $targetPrefix) {
413
+ $dom = new DOMDocument;
414
+ $bucketLoggingStatus = $dom->createElement('BucketLoggingStatus');
415
+ $bucketLoggingStatus->setAttribute('xmlns', 'http://s3.amazonaws.com/doc/2006-03-01/');
416
+
417
+ $loggingEnabled = $dom->createElement('LoggingEnabled');
418
+
419
+ $loggingEnabled->appendChild($dom->createElement('TargetBucket', $targetBucket));
420
+ $loggingEnabled->appendChild($dom->createElement('TargetPrefix', $targetPrefix));
421
+
422
+ // TODO: Add TargetGrants
423
+
424
+ $bucketLoggingStatus->appendChild($loggingEnabled);
425
+ $dom->appendChild($bucketLoggingStatus);
426
+
427
+ $rest = new S3Request('PUT', $bucket, '');
428
+ $rest->setParameter('logging', null);
429
+ $rest->data = $dom->saveXML();
430
+ $rest->size = strlen($rest->data);
431
+ $rest->setHeader('Content-Type', 'application/xml');
432
+ $rest = $rest->getResponse();
433
+ if ($rest->error === false && $rest->code !== 200)
434
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
435
+ if ($rest->error !== false) {
436
+ trigger_error(sprintf("S3::setBucketLogging({$bucket}, {$uri}): [%s] %s",
437
+ $rest->error['code'], $rest->error['message']), E_USER_WARNING);
438
+ return false;
439
+ }
440
+ return true;
441
+ }
442
+
443
+
444
+ /**
445
+ * Get logging status for a bucket
446
+ *
447
+ * This will return false if logging is not enabled.
448
+ * Note: To enable logging, you also need to grant write access to the log group
449
+ *
450
+ * @param string $bucket Bucket name
451
+ * @return array | false
452
+ */
453
+ public static function getBucketLogging($bucket = '') {
454
+ $rest = new S3Request('GET', $bucket, '');
455
+ $rest->setParameter('logging', null);
456
+ $rest = $rest->getResponse();
457
+ if ($rest->error === false && $rest->code !== 200)
458
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
459
+ if ($rest->error !== false) {
460
+ trigger_error(sprintf("S3::getBucketLogging({$bucket}): [%s] %s",
461
+ $rest->error['code'], $rest->error['message']), E_USER_WARNING);
462
+ return false;
463
+ }
464
+ if (!isset($rest->body->LoggingEnabled)) return false; // No logging
465
+ return array(
466
+ 'targetBucket' => (string)$rest->body->LoggingEnabled->TargetBucket,
467
+ 'targetPrefix' => (string)$rest->body->LoggingEnabled->TargetPrefix,
468
+ );
469
+ }
470
+
471
+
472
+ /**
473
+ * Set object or bucket Access Control Policy
474
+ *
475
+ * @param string $bucket Bucket name
476
+ * @param string $uri Object URI
477
+ * @param array $acp Access Control Policy Data (same as the data returned from getAccessControlPolicy)
478
+ * @return boolean
479
+ */
480
+ public static function setAccessControlPolicy($bucket, $uri = '', $acp = array()) {
481
+ $dom = new DOMDocument;
482
+ $dom->formatOutput = true;
483
+ $accessControlPolicy = $dom->createElement('AccessControlPolicy');
484
+ $accessControlList = $dom->createElement('AccessControlList');
485
+
486
+ // It seems the owner has to be passed along too
487
+ $owner = $dom->createElement('Owner');
488
+ $owner->appendChild($dom->createElement('ID', $acp['owner']['id']));
489
+ $owner->appendChild($dom->createElement('DisplayName', $acp['owner']['name']));
490
+ $accessControlPolicy->appendChild($owner);
491
+
492
+ foreach ($acp['acl'] as $g) {
493
+ $grant = $dom->createElement('Grant');
494
+ $grantee = $dom->createElement('Grantee');
495
+ $grantee->setAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
496
+ if (isset($g['id'])) { // CanonicalUser (DisplayName is omitted)
497
+ $grantee->setAttribute('xsi:type', 'CanonicalUser');
498
+ $grantee->appendChild($dom->createElement('ID', $g['id']));
499
+ } elseif (isset($g['email'])) { // AmazonCustomerByEmail
500
+ $grantee->setAttribute('xsi:type', 'AmazonCustomerByEmail');
501
+ $grantee->appendChild($dom->createElement('EmailAddress', $g['email']));
502
+ } elseif ($g['type'] == 'Group') { // Group
503
+ $grantee->setAttribute('xsi:type', 'Group');
504
+ $grantee->appendChild($dom->createElement('URI', $g['uri']));
505
+ }
506
+ $grant->appendChild($grantee);
507
+ $grant->appendChild($dom->createElement('Permission', $g['permission']));
508
+ $accessControlList->appendChild($grant);
509
+ }
510
+
511
+ $accessControlPolicy->appendChild($accessControlList);
512
+ $dom->appendChild($accessControlPolicy);
513
+
514
+ $rest = new S3Request('PUT', $bucket, '');
515
+ $rest->setParameter('acl', null);
516
+ $rest->data = $dom->saveXML();
517
+ $rest->size = strlen($rest->data);
518
+ $rest->setHeader('Content-Type', 'application/xml');
519
+ $rest = $rest->getResponse();
520
+ if ($rest->error === false && $rest->code !== 200)
521
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
522
+ if ($rest->error !== false) {
523
+ trigger_error(sprintf("S3::setAccessControlPolicy({$bucket}, {$uri}): [%s] %s",
524
+ $rest->error['code'], $rest->error['message']), E_USER_WARNING);
525
+ return false;
526
+ }
527
+ return true;
528
+ }
529
+
530
+
531
+ /**
532
+ * Get object or bucket Access Control Policy
533
+ *
534
+ * Currently this will trigger an error if there is no ACL on an object (will fix soon)
535
+ *
536
+ * @param string $bucket Bucket name
537
+ * @param string $uri Object URI
538
+ * @return mixed | false
539
+ */
540
+ public static function getAccessControlPolicy($bucket, $uri = '') {
541
+ $rest = new S3Request('GET', $bucket, $uri);
542
+ $rest->setParameter('acl', null);
543
+ $rest = $rest->getResponse();
544
+ if ($rest->error === false && $rest->code !== 200)
545
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
546
+ if ($rest->error !== false) {
547
+ trigger_error(sprintf("S3::getAccessControlPolicy({$bucket}, {$uri}): [%s] %s",
548
+ $rest->error['code'], $rest->error['message']), E_USER_WARNING);
549
+ return false;
550
+ }
551
+
552
+ $acp = array();
553
+ if (isset($rest->body->Owner, $rest->body->Owner->ID, $rest->body->Owner->DisplayName)) {
554
+ $acp['owner'] = array(
555
+ 'id' => (string)$rest->body->Owner->ID, 'name' => (string)$rest->body->Owner->DisplayName
556
+ );
557
+ }
558
+ if (isset($rest->body->AccessControlList)) {
559
+ $acp['acl'] = array();
560
+ foreach ($rest->body->AccessControlList->Grant as $grant) {
561
+ foreach ($grant->Grantee as $grantee) {
562
+ if (isset($grantee->ID, $grantee->DisplayName)) // CanonicalUser
563
+ $acp['acl'][] = array(
564
+ 'type' => 'CanonicalUser',
565
+ 'id' => (string)$grantee->ID,
566
+ 'name' => (string)$grantee->DisplayName,
567
+ 'permission' => (string)$grant->Permission
568
+ );
569
+ elseif (isset($grantee->EmailAddress)) // AmazonCustomerByEmail
570
+ $acp['acl'][] = array(
571
+ 'type' => 'AmazonCustomerByEmail',
572
+ 'email' => (string)$grantee->EmailAddress,
573
+ 'permission' => (string)$grant->Permission
574
+ );
575
+ elseif (isset($grantee->URI)) // Group
576
+ $acp['acl'][] = array(
577
+ 'type' => 'Group',
578
+ 'uri' => (string)$grantee->URI,
579
+ 'permission' => (string)$grant->Permission
580
+ );
581
+ else continue;
582
+ }
583
+ }
584
+ }
585
+ return $acp;
586
+ }
587
+
588
+
589
+ /**
590
+ * Delete an object
591
+ *
592
+ * @param string $bucket Bucket name
593
+ * @param string $uri Object URI
594
+ * @return mixed
595
+ */
596
+ public static function deleteObject($bucket = '', $uri = '') {
597
+ $rest = new S3Request('DELETE', $bucket, $uri);
598
+ $rest = $rest->getResponse();
599
+ if ($rest->error === false && $rest->code !== 204)
600
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
601
+ if ($rest->error !== false) {
602
+ trigger_error(sprintf("S3::deleteObject(): [%s] %s", $rest->error['code'], $rest->error['message']), E_USER_WARNING);
603
+ return false;
604
+ }
605
+ return true;
606
+ }
607
+
608
+
609
+ /**
610
+ * Get MIME type for file
611
+ *
612
+ * @internal Used to get mime types
613
+ * @param string &$file File path
614
+ * @return string
615
+ */
616
+ public static function __getMimeType(&$file) {
617
+ $type = false;
618
+ // Fileinfo documentation says fileinfo_open() will use the
619
+ // MAGIC env var for the magic file
620
+ if (extension_loaded('fileinfo') && isset($_ENV['MAGIC']) &&
621
+ ($finfo = finfo_open(FILEINFO_MIME, $_ENV['MAGIC'])) !== false) {
622
+ if (($type = finfo_file($finfo, $file)) !== false) {
623
+ // Remove the charset and grab the last content-type
624
+ $type = explode(' ', str_replace('; charset=', ';charset=', $type));
625
+ $type = array_pop($type);
626
+ $type = explode(';', $type);
627
+ $type = array_shift($type);
628
+ }
629
+ finfo_close($finfo);
630
+
631
+ // If anyone is still using mime_content_type()
632
+ } elseif (function_exists('mime_content_type'))
633
+ $type = mime_content_type($file);
634
+
635
+ if ($type !== false && strlen($type) > 0) return $type;
636
+
637
+ // Otherwise do it the old fashioned way
638
+ static $exts = array(
639
+ 'jpg' => 'image/jpeg', 'gif' => 'image/gif', 'png' => 'image/png',
640
+ 'tif' => 'image/tiff', 'tiff' => 'image/tiff', 'ico' => 'image/x-icon',
641
+ 'swf' => 'application/x-shockwave-flash', 'pdf' => 'application/pdf',
642
+ 'zip' => 'application/zip', 'gz' => 'application/x-gzip',
643
+ 'tar' => 'application/x-tar', 'bz' => 'application/x-bzip',
644
+ 'bz2' => 'application/x-bzip2', 'txt' => 'text/plain',
645
+ 'asc' => 'text/plain', 'htm' => 'text/html', 'html' => 'text/html',
646
+ 'xml' => 'text/xml', 'xsl' => 'application/xsl+xml',
647
+ 'ogg' => 'application/ogg', 'mp3' => 'audio/mpeg', 'wav' => 'audio/x-wav',
648
+ 'avi' => 'video/x-msvideo', 'mpg' => 'video/mpeg', 'mpeg' => 'video/mpeg',
649
+ 'mov' => 'video/quicktime', 'flv' => 'video/x-flv', 'php' => 'text/x-php'
650
+ );
651
+ $ext = strToLower(pathInfo($file, PATHINFO_EXTENSION));
652
+ return isset($exts[$ext]) ? $exts[$ext] : 'application/octet-stream';
653
+ }
654
+
655
+
656
+ /**
657
+ * Generate the auth string: "AWS AccessKey:Signature"
658
+ *
659
+ * This uses the hash extension if loaded
660
+ *
661
+ * @internal Signs the request
662
+ * @param string $string String to sign
663
+ * @return string
664
+ */
665
+ public static function __getSignature($string) {
666
+ return 'AWS '.self::$__accessKey.':'.base64_encode(extension_loaded('hash') ?
667
+ hash_hmac('sha1', $string, self::$__secretKey, true) : pack('H*', sha1(
668
+ (str_pad(self::$__secretKey, 64, chr(0x00)) ^ (str_repeat(chr(0x5c), 64))) .
669
+ pack('H*', sha1((str_pad(self::$__secretKey, 64, chr(0x00)) ^
670
+ (str_repeat(chr(0x36), 64))) . $string)))));
671
+ }
672
+
673
+
674
+ }
675
+
676
+ final class S3Request {
677
+ private $verb, $bucket, $uri, $resource = '', $parameters = array(),
678
+ $amzHeaders = array(), $headers = array(
679
+ 'Host' => '', 'Date' => '', 'Content-MD5' => '', 'Content-Type' => ''
680
+ );
681
+ public $fp = false, $size = 0, $data = false, $response;
682
+
683
+
684
+ /**
685
+ * Constructor
686
+ *
687
+ * @param string $verb Verb
688
+ * @param string $bucket Bucket name
689
+ * @param string $uri Object URI
690
+ * @return mixed
691
+ */
692
+ function __construct($verb, $bucket = '', $uri = '') {
693
+ $this->verb = $verb;
694
+ $this->bucket = strtolower($bucket);
695
+ $this->uri = $uri !== '' ? '/'.$uri : '/';
696
+
697
+ if ($this->bucket !== '') {
698
+ $this->bucket = explode('/', $this->bucket);
699
+ $this->resource = '/'.$this->bucket[0].$this->uri;
700
+ $this->headers['Host'] = $this->bucket[0].'.s3.amazonaws.com';
701
+ $this->bucket = implode('/', $this->bucket);
702
+ } else {
703
+ $this->headers['Host'] = 's3.amazonaws.com';
704
+ if (strlen($this->uri) > 1)
705
+ $this->resource = '/'.$this->bucket.$this->uri;
706
+ else $this->resource = $this->uri;
707
+ }
708
+ $this->headers['Date'] = gmdate('D, d M Y H:i:s T');
709
+
710
+ $this->response = new STDClass;
711
+ $this->response->error = false;
712
+ }
713
+
714
+
715
+ /**
716
+ * Set request parameter
717
+ *
718
+ * @param string $key Key
719
+ * @param string $value Value
720
+ * @return void
721
+ */
722
+ public function setParameter($key, $value) {
723
+ $this->parameters[$key] = $value;
724
+ }
725
+
726
+
727
+ /**
728
+ * Set request header
729
+ *
730
+ * @param string $key Key
731
+ * @param string $value Value
732
+ * @return void
733
+ */
734
+ public function setHeader($key, $value) {
735
+ $this->headers[$key] = $value;
736
+ }
737
+
738
+
739
+ /**
740
+ * Set x-amz-meta-* header
741
+ *
742
+ * @param string $key Key
743
+ * @param string $value Value
744
+ * @return void
745
+ */
746
+ public function setAmzHeader($key, $value) {
747
+ $this->amzHeaders[$key] = $value;
748
+ }
749
+
750
+
751
+ /**
752
+ * Get the S3 response
753
+ *
754
+ * @return object | false
755
+ */
756
+ public function getResponse() {
757
+ $query = '';
758
+ if (sizeof($this->parameters) > 0) {
759
+ $query = substr($this->uri, -1) !== '?' ? '?' : '&';
760
+ foreach ($this->parameters as $var => $value)
761
+ if ($value == null || $value == '') $query .= $var.'&';
762
+ else $query .= $var.'='.$value.'&';
763
+ $query = substr($query, 0, -1);
764
+ $this->uri .= $query;
765
+ if (isset($this->parameters['acl']) || !isset($this->parameters['logging']))
766
+ $this->resource .= $query;
767
+ }
768
+ $url = (extension_loaded('openssl')?'https://':'http://').$this->headers['Host'].$this->uri;
769
+ //var_dump($this->bucket, $this->uri, $this->resource, $url);
770
+
771
+ // Basic setup
772
+ $curl = curl_init();
773
+ curl_setopt($curl, CURLOPT_USERAGENT, 'S3/php');
774
+ curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0);
775
+ curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);
776
+ curl_setopt($curl, CURLOPT_URL, $url);
777
+
778
+ // Headers
779
+ $headers = array(); $amz = array();
780
+ foreach ($this->amzHeaders as $header => $value)
781
+ if (strlen($value) > 0) $headers[] = $header.': '.$value;
782
+ foreach ($this->headers as $header => $value)
783
+ if (strlen($value) > 0) $headers[] = $header.': '.$value;
784
+ foreach ($this->amzHeaders as $header => $value)
785
+ if (strlen($value) > 0) $amz[] = strToLower($header).':'.$value;
786
+ $amz = (sizeof($amz) > 0) ? "\n".implode("\n", $amz) : '';
787
+
788
+ // Authorization string
789
+ $headers[] = 'Authorization: ' . S3::__getSignature(
790
+ $this->verb."\n".
791
+ $this->headers['Content-MD5']."\n".
792
+ $this->headers['Content-Type']."\n".
793
+ $this->headers['Date'].$amz."\n".$this->resource
794
+ );
795
+
796
+ curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
797
+ curl_setopt($curl, CURLOPT_HEADER, false);
798
+ curl_setopt($curl, CURLOPT_RETURNTRANSFER, false);
799
+ curl_setopt($curl, CURLOPT_WRITEFUNCTION, array(&$this, '__responseWriteCallback'));
800
+ curl_setopt($curl, CURLOPT_HEADERFUNCTION, array(&$this, '__responseHeaderCallback'));
801
+
802
+ // Request types
803
+ switch ($this->verb) {
804
+ case 'GET': break;
805
+ case 'PUT':
806
+ if ($this->fp !== false) {
807
+ curl_setopt($curl, CURLOPT_PUT, true);
808
+ curl_setopt($curl, CURLOPT_INFILE, $this->fp);
809
+ if ($this->size > 0)
810
+ curl_setopt($curl, CURLOPT_INFILESIZE, $this->size);
811
+ } elseif ($this->data !== false) {
812
+ curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'PUT');
813
+ curl_setopt($curl, CURLOPT_POSTFIELDS, $this->data);
814
+ if ($this->size > 0)
815
+ curl_setopt($curl, CURLOPT_BUFFERSIZE, $this->size);
816
+ } else
817
+ curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'PUT');
818
+ break;
819
+ case 'HEAD':
820
+ curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'HEAD');
821
+ curl_setopt($curl, CURLOPT_NOBODY, true);
822
+ break;
823
+ case 'DELETE':
824
+ curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'DELETE');
825
+ break;
826
+ default: break;
827
+ }
828
+
829
+ // Execute, grab errors
830
+ if (curl_exec($curl))
831
+ $this->response->code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
832
+ else
833
+ $this->response->error = array(
834
+ 'code' => curl_errno($curl),
835
+ 'message' => curl_error($curl),
836
+ 'resource' => $this->resource
837
+ );
838
+
839
+ @curl_close($curl);
840
+
841
+ // Parse body into XML
842
+ if ($this->response->error === false && isset($this->response->headers['type']) &&
843
+ $this->response->headers['type'] == 'application/xml' && isset($this->response->body)) {
844
+ $this->response->body = simplexml_load_string($this->response->body);
845
+
846
+ // Grab S3 errors
847
+ if (!in_array($this->response->code, array(200, 204)) &&
848
+ isset($this->response->body->Code, $this->response->body->Message)) {
849
+ $this->response->error = array(
850
+ 'code' => (string)$this->response->body->Code,
851
+ 'message' => (string)$this->response->body->Message
852
+ );
853
+ if (isset($this->response->body->Resource))
854
+ $this->response->error['resource'] = (string)$this->response->body->Resource;
855
+ unset($this->response->body);
856
+ }
857
+ }
858
+
859
+ // Clean up file resources
860
+ if ($this->fp !== false && is_resource($this->fp)) fclose($this->fp);
861
+
862
+ return $this->response;
863
+ }
864
+
865
+
866
+ /**
867
+ * CURL write callback
868
+ *
869
+ * @param resource &$curl CURL resource
870
+ * @param string &$data Data
871
+ * @return integer
872
+ */
873
+ private function __responseWriteCallback(&$curl, &$data) {
874
+ if ($this->response->code == 200 && $this->fp !== false)
875
+ return fwrite($this->fp, $data);
876
+ else
877
+ $this->response->body .= $data;
878
+ return strlen($data);
879
+ }
880
+
881
+
882
+ /**
883
+ * CURL header callback
884
+ *
885
+ * @param resource &$curl CURL resource
886
+ * @param string &$data Data
887
+ * @return integer
888
+ */
889
+ private function __responseHeaderCallback(&$curl, &$data) {
890
+ if (($strlen = strlen($data)) <= 2) return $strlen;
891
+ if (substr($data, 0, 4) == 'HTTP')
892
+ $this->response->code = (int)substr($data, 9, 3);
893
+ else {
894
+ list($header, $value) = explode(': ', trim($data));
895
+ if ($header == 'Last-Modified')
896
+ $this->response->headers['time'] = strtotime($value);
897
+ elseif ($header == 'Content-Length')
898
+ $this->response->headers['size'] = (int)$value;
899
+ elseif ($header == 'Content-Type')
900
+ $this->response->headers['type'] = $value;
901
+ elseif ($header == 'ETag')
902
+ $this->response->headers['hash'] = substr($value, 1, -1);
903
+ elseif (preg_match('/^x-amz-meta-.*$/', $header))
904
+ $this->response->headers[$header] = is_numeric($value) ? (int)$value : $value;
905
+ }
906
+ return $strlen;
907
+ }
908
+
909
+ }
910
+ ?>
plugins/cleanup/cleanup.php CHANGED
@@ -10,12 +10,13 @@
10
  * www.prelovac.com
11
  **************************************************************/
12
 
13
- add_filter('mmb_stats_filter', mmb_get_extended_info);
14
 
15
 
16
  function mmb_get_extended_info($stats)
17
  {
18
  $stats['num_revisions'] = mmb_num_revisions();
 
19
  $stats['overhead'] = mmb_get_overhead();
20
  $stats['num_spam_comments'] = mmb_num_spam_comments();
21
  return $stats;
@@ -99,31 +100,20 @@ function mmb_get_overhead()
99
  $tables = $wpdb->get_results($wpdb->prepare($query),ARRAY_A);
100
  foreach($tables as $table)
101
  {
102
- if($wpdb->base_prefix != $wpdb->prefix){
103
- if(preg_match('/^'.$wpdb->prefix.'*/Ui', $table['Name'])){
104
- $tot_data = $table['Data_length'];
105
- $tot_idx = $table['Index_length'];
106
- $total = $tot_data + $tot_idx;
107
- $total = $total / 1024 ;
108
- $total = round ($total,3);
109
- $gain= $table['Data_free'];
110
- $gain = $gain / 1024 ;
111
- $total_gain += $gain;
112
- $gain = round ($gain,3);
113
  }
114
- } else if(preg_match('/^'.$wpdb->prefix.'[0-9]{1,20}_*/Ui', $table['Name'])){
115
- continue;
116
- }
117
- else {
118
- $tot_data = $table['Data_length'];
119
- $tot_idx = $table['Index_length'];
120
- $total = $tot_data + $tot_idx;
121
- $total = $total / 1024 ;
122
- $total = round ($total,3);
123
- $gain= $table['Data_free'];
124
- $gain = $gain / 1024 ;
125
- $total_gain += $gain;
126
- $gain = round ($gain,3);
127
  }
128
  }
129
  return round($total_gain,3);
10
  * www.prelovac.com
11
  **************************************************************/
12
 
13
+ add_filter('mmb_stats_filter', 'mmb_get_extended_info');
14
 
15
 
16
  function mmb_get_extended_info($stats)
17
  {
18
  $stats['num_revisions'] = mmb_num_revisions();
19
+ //$stats['num_revisions'] = 5;
20
  $stats['overhead'] = mmb_get_overhead();
21
  $stats['num_spam_comments'] = mmb_num_spam_comments();
22
  return $stats;
100
  $tables = $wpdb->get_results($wpdb->prepare($query),ARRAY_A);
101
  foreach($tables as $table)
102
  {
103
+ if(in_array($table['Engine'], array('MyISAM', 'ISAM', 'HEAP', 'MEMORY', 'ARCHIVE'))){
104
+
105
+ if($wpdb->base_prefix != $wpdb->prefix){
106
+ if(preg_match('/^'.$wpdb->prefix.'*/Ui', $table['Name'])){
107
+ $total_gain += $table['Data_free'] / 1024;
108
+ }
109
+ } else if(preg_match('/^'.$wpdb->prefix.'[0-9]{1,20}_*/Ui', $table['Name'])){
110
+ continue;
 
 
 
111
  }
112
+ else {
113
+ $total_gain += $table['Data_free'] / 1024;
114
+ }
115
+ } elseif ($table['Engine'] == 'InnoDB'){
116
+ $total_gain += $table['Data_free'] > 100*1024*1024 ? $table['Data_free'] / 1024 : 0;
 
 
 
 
 
 
 
 
117
  }
118
  }
119
  return round($total_gain,3);
readme.txt CHANGED
@@ -30,6 +30,11 @@ API for developers available at [ManageWP.com/API](http://managewp.com/api "Mana
30
 
31
  == Changelog ==
32
 
 
 
 
 
 
33
  = 3.9.3 =
34
  * Included support for WordPress 3.2 partial updates
35
 
30
 
31
  == Changelog ==
32
 
33
+ = 3.9.4 =
34
+ * Now supporting schedule backups to Amazon S3 and Dropbox
35
+ * Revamped cloning procedure with more features
36
+ * Site colors for your websites
37
+
38
  = 3.9.3 =
39
  * Included support for WordPress 3.2 partial updates
40
 
stats.class.php CHANGED
@@ -192,9 +192,17 @@ class MMB_Stats extends MMB_Core
192
 
193
  $stats['writable'] = $this->is_server_writable();
194
 
195
- $stats['backups'] = $this->get_backups();
 
196
 
 
 
 
 
 
 
197
  $stats = apply_filters('mmb_stats_filter', $stats);
 
198
  return $stats;
199
  }
200
 
@@ -411,13 +419,7 @@ class MMB_Stats extends MMB_Core
411
  return false;
412
  }
413
 
414
- function get_backups()
415
- {
416
- $worker_options = get_option('mmb-worker');
417
- //$backup_file = $worker_options['backups'][$type]['path'];
418
- return $worker_options['backups'];
419
- }
420
-
421
  }
422
 
423
  function cmp_posts_worker($a, $b)
192
 
193
  $stats['writable'] = $this->is_server_writable();
194
 
195
+ //Backup Results
196
+ $stats['mwp_backups'] = $this->get_backup_instance()->get_backup_stats();
197
 
198
+ //Backup requirements
199
+ $stats['mwp_backup_req'] = $this->get_backup_instance()->check_backup_compat();
200
+
201
+ $stats['sheduled_backup'] = '12.07.2011 13:00';
202
+ $stats['sheduled_next'] = '12.08.2011 13:00';
203
+
204
  $stats = apply_filters('mmb_stats_filter', $stats);
205
+
206
  return $stats;
207
  }
208
 
419
  return false;
420
  }
421
 
422
+
 
 
 
 
 
 
423
  }
424
 
425
  function cmp_posts_worker($a, $b)
version CHANGED
@@ -1 +1 @@
1
- 3.9.3
1
+ 3.9.4