UpdraftPlus WordPress Backup Plugin - Version 1.2.40

Version Description

Set retention separately for files/db. Complete Dropbox support. FTP over SSL. Less noise, more info. Option to delete all settings.

Download this release

Release Info

Developer DavidAnderson
Plugin Icon 128x128 UpdraftPlus WordPress Backup Plugin
Version 1.2.40
Comparing to
See all releases

Code changes from version 1.2.39 to 1.2.40

Files changed (2) hide show
  1. readme.txt +9 -3
  2. updraftplus.php +80 -53
readme.txt CHANGED
@@ -3,12 +3,12 @@ Contributors: David Anderson
3
  Tags: backup, restore, database, cloud, amazon, s3, dropbox, google drive, gdrive, ftp, cloud, updraft, back up
4
  Requires at least: 3.2
5
  Tested up to: 3.5
6
- Stable tag: 1.2.39
7
  Donate link: http://david.dw-perspective.org.uk/donate
8
  License: GPLv3 or later
9
 
10
  == Upgrade Notice ==
11
- Complete Dropbox support. FTP over SSL. Less noise, more info. Option to delete all settings.
12
 
13
  == Description ==
14
 
@@ -32,6 +32,10 @@ That's according to WordPress big cheese, Vladimir Prelovac. Check out his weekl
32
 
33
  UpdraftPlus is written by professional WordPress developers. If your site needs guaranteed support, then we are available. Get in touch - https://www.simbahosting.co.uk/s3/products-and-services/wordpress-experts/ - to arrange the support contract that your site needs.
34
 
 
 
 
 
35
  == Installation ==
36
 
37
  Standard WordPress plugin installation:
@@ -128,11 +132,13 @@ Thanks for asking - yes, I have. Check out my profile page - http://profiles.wor
128
 
129
  == Changelog ==
130
 
131
- = 1.2.39 - 01/18/2013 =
132
  * Easier Dropbox setup (we are now an official production app)
133
  * New button to delete all existing settings
134
  * Admin console now displays rolling status updates
 
135
  * Fixed bug with checking access token on Google Drive restore
 
136
 
137
  = 1.2.31 - 01/15/2013 =
138
  * Fixed bug with Dropbox deletions
3
  Tags: backup, restore, database, cloud, amazon, s3, dropbox, google drive, gdrive, ftp, cloud, updraft, back up
4
  Requires at least: 3.2
5
  Tested up to: 3.5
6
+ Stable tag: 1.2.41
7
  Donate link: http://david.dw-perspective.org.uk/donate
8
  License: GPLv3 or later
9
 
10
  == Upgrade Notice ==
11
+ Set retention separately for files/db. Complete Dropbox support. FTP over SSL. Less noise, more info. Option to delete all settings.
12
 
13
  == Description ==
14
 
32
 
33
  UpdraftPlus is written by professional WordPress developers. If your site needs guaranteed support, then we are available. Get in touch - https://www.simbahosting.co.uk/s3/products-and-services/wordpress-experts/ - to arrange the support contract that your site needs.
34
 
35
+ = Other support =
36
+
37
+ We hang out in the support forum for this plugin - http://wordpress.org/support/plugin/updraftplus - however, to save our time so that we can spend it on development and not repeating ourselves, please read the plugin's Frequently Asked Questions ((http://wordpress.org/extend/plugins/updraftplus/faq/) before you submit any support requests, and ensure that you have updated to the latest released version of UpdraftPlus.
38
+
39
  == Installation ==
40
 
41
  Standard WordPress plugin installation:
132
 
133
  == Changelog ==
134
 
135
+ = 1.2.41 - 01/19/2013 =
136
  * Easier Dropbox setup (we are now an official production app)
137
  * New button to delete all existing settings
138
  * Admin console now displays rolling status updates
139
+ * Feature: choose how many files and databases to retain separately
140
  * Fixed bug with checking access token on Google Drive restore
141
+ * Fixed bug producing copious warnings in PHP log
142
 
143
  = 1.2.31 - 01/15/2013 =
144
  * Fixed bug with Dropbox deletions
updraftplus.php CHANGED
@@ -4,7 +4,7 @@ Plugin Name: UpdraftPlus - Backup/Restore
4
  Plugin URI: http://wordpress.org/extend/plugins/updraftplus
5
  Description: Backup and restore: your content and database can be automatically backed up to Amazon S3, Dropbox, Google Drive, FTP or email, on separate schedules.
6
  Author: David Anderson.
7
- Version: 1.2.39
8
  Donate link: http://david.dw-perspective.org.uk/donate
9
  License: GPLv3 or later
10
  Author URI: http://wordshell.net
@@ -17,12 +17,12 @@ TODO
17
  //?? On 'backup now', open up a Lightbox, count down 5 seconds, then start examining the log file (if it can be found)
18
  //Should make clear in dashboard what is a non-fatal error (i.e. can be retried) - leads to unnecessary bug reports
19
  //Eventually, when everything can be resumed, we will no longer need the backup() routine; it can be replaced with the resume() routine
20
- // Should we resume if the only errors were upon deletion (i.e. the backup itself was fine?) Presently we do, but it displays errors for the user to confuse them.
21
  // Make jobs *individually* resumable (i.e. all the state info must be keyed on the nonce; then call the resume event *specifying the nonce*)
22
- // Separate 'retain' settings for db + files (since they are on separate schedules)
23
  // Warn the user if their zip-file creation is slooowww...
24
  // Create a "Want Support?" button/console, that leads them through what is needed, and performs some basic tests...
25
  // Resuming partial FTP uploads
 
26
 
27
  Encrypt filesystem, if memory allows (and have option for abort if not); split up into multiple zips when needed
28
  // Does not delete old custom directories upon a restore?
@@ -65,7 +65,7 @@ define('UPDRAFT_DEFAULT_OTHERS_EXCLUDE','upgrade,cache,updraft,index.php');
65
 
66
  class UpdraftPlus {
67
 
68
- var $version = '1.2.39';
69
 
70
  // Choices will be shown in the admin menu in the order used here
71
  var $backup_methods = array (
@@ -424,7 +424,6 @@ class UpdraftPlus {
424
  //cloud operations (S3,Google Drive,FTP,email,nothing)
425
  //this also calls the retain (prune) feature at the end (done in this method to reuse existing cloud connections)
426
  if(is_array($backup_array) && count($backup_array) >0) {
427
- $this->log("Beginning dispatch of backup to remote");
428
  $this->cloud_backup($backup_array);
429
  }
430
 
@@ -445,10 +444,12 @@ class UpdraftPlus {
445
  if (strlen($encryption) > 0) {
446
  $this->log("$file: applying encryption");
447
  $encryption_error = 0;
 
448
  require_once(UPDRAFTPLUS_DIR.'/includes/Rijndael.php');
449
  $rijndael = new Crypt_Rijndael();
450
  $rijndael->setKey($encryption);
451
  $updraft_dir = $this->backups_dir_location();
 
452
  $in_handle = @fopen($updraft_dir.'/'.$file,'r');
453
  $buffer = "";
454
  while (!feof ($in_handle)) {
@@ -459,7 +460,8 @@ class UpdraftPlus {
459
  if (!fwrite($out_handle, $rijndael->encrypt($buffer))) {$encryption_error = 1;}
460
  fclose ($out_handle);
461
  if (0 == $encryption_error) {
462
- $this->log("$file: encryption successful");
 
463
  # Delete unencrypted file
464
  @unlink($updraft_dir.'/'.$file);
465
  return basename($file.'.crypt');
@@ -568,9 +570,9 @@ class UpdraftPlus {
568
  update_option('updraft_file_ids',$ids);
569
  $this->log("Stored file<->id correlation in database ($file <-> $id)");
570
  }
571
- // Delete local files if the option is set
572
- $this->delete_local($file);
573
-
574
  }
575
 
576
  // Dispatch to the relevant function
@@ -582,13 +584,19 @@ class UpdraftPlus {
582
  $method_include = UPDRAFTPLUS_DIR.'/methods/'.$service.'.php';
583
  if (file_exists($method_include)) require_once($method_include);
584
 
 
 
 
 
 
 
585
  $objname = "UpdraftPlus_BackupModule_${service}";
586
  if (method_exists($objname, "backup")) {
587
  // New style - external, allowing more plugability
588
  $remote_obj = new $objname;
589
  $remote_obj->backup($backup_array);
590
- } else {
591
- $this->prune_retained_backups("local", null, null);
592
  }
593
  }
594
 
@@ -608,12 +616,23 @@ class UpdraftPlus {
608
  // Carries out retain behaviour. Pass in a valid S3 or FTP object and path if relevant.
609
  function prune_retained_backups($updraft_service, $backup_method_object = null, $backup_passback = null) {
610
 
 
 
 
 
 
 
611
  $this->log("Retain: beginning examination of existing backup sets");
612
 
613
- // Number of backups to retain
614
  $updraft_retain = get_option('updraft_retain', 1);
615
- $retain = (is_numeric($updraft_retain)) ? $updraft_retain : 1;
616
- $this->log("Retain: user setting: number to retain = $retain");
 
 
 
 
 
617
 
618
  // Returns an array, most recent first, of backup sets
619
  $backup_history = $this->get_backup_history();
@@ -629,8 +648,8 @@ class UpdraftPlus {
629
  if (isset($backup_to_examine['db'])) {
630
  $db_backups_found++;
631
  $this->log("$backup_datestamp: this set includes a database (".$backup_to_examine['db']."); db count is now $db_backups_found");
632
- if ($db_backups_found > $retain) {
633
- $this->log("$backup_datestamp: over retain limit; will delete this database");
634
  $dofile = $backup_to_examine['db'];
635
  if (!empty($dofile)) $this->prune_file($updraft_service, $dofile, $backup_method_object, $backup_passback);
636
  unset($backup_to_examine['db']);
@@ -639,8 +658,8 @@ class UpdraftPlus {
639
  if (isset($backup_to_examine['plugins']) || isset($backup_to_examine['themes']) || isset($backup_to_examine['uploads']) || isset($backup_to_examine['others'])) {
640
  $file_backups_found++;
641
  $this->log("$backup_datestamp: this set includes files; fileset count is now $file_backups_found");
642
- if ($file_backups_found > $retain) {
643
- $this->log("$backup_datestamp: over retain limit; will delete this file set");
644
  $file = isset($backup_to_examine['plugins']) ? $backup_to_examine['plugins'] : "";
645
  $file2 = isset($backup_to_examine['themes']) ? $backup_to_examine['themes'] : "";
646
  $file3 = isset($backup_to_examine['uploads']) ? $backup_to_examine['uploads'] : "";
@@ -794,12 +813,12 @@ class UpdraftPlus {
794
  while (false !== ($entry = readdir($handle))) {
795
  $candidate = WP_CONTENT_DIR.'/'.$entry;
796
  if ($entry == "." || $entry == "..") { ; }
797
- elseif ($candidate == $updraft_dir) { $this->log("$entry: skipping: this is the updraft directory"); }
798
- elseif ($candidate == $wp_themes_dir) { $this->log("$entry: skipping: this is the themes directory"); }
799
- elseif ($candidate == $wp_upload_dir) { $this->log("$entry: skipping: this is the uploads directory"); }
800
- elseif ($candidate == $wp_plugins_dir) { $this->log("$entry: skipping: this is the plugins directory"); }
801
- elseif (isset($others_skip[$entry])) { $this->log("$entry: skipping: excluded by options"); }
802
- else { $this->log("$entry: adding to list"); array_push($other_dirlist, $candidate); }
803
  }
804
  } else {
805
  $this->log('ERROR: Could not read the content directory: '.WP_CONTENT_DIR);
@@ -953,7 +972,7 @@ class UpdraftPlus {
953
  foreach ($stitch_files as $table_file) {
954
  $this->log("{$table_file}.gz: adding to final database dump");
955
  $handle = gzopen($updraft_dir.'/'.$table_file.'.gz', "r");
956
- while (!feof($handle)) { $this->stow(gzread($handle, 65536)); }
957
  gzclose($handle);
958
  @unlink($updraft_dir.'/'.$table_file.'.gz');
959
  }
@@ -1098,7 +1117,7 @@ class UpdraftPlus {
1098
  $this->stow("# --------------------------------------------------------\n");
1099
  $this->stow("\n");
1100
  }
1101
- $this->log("Table $table: Total rows added: $total_rows in ".sprintf("%.02f",microtime(true)-$microtime)." seconds");
1102
 
1103
  } // end backup_table()
1104
 
@@ -1452,6 +1471,7 @@ class UpdraftPlus {
1452
  register_setting( 'updraft-options-group', 'updraft_interval', array($this,'schedule_backup') );
1453
  register_setting( 'updraft-options-group', 'updraft_interval_database', array($this,'schedule_backup_database') );
1454
  register_setting( 'updraft-options-group', 'updraft_retain', array($this,'retain_range') );
 
1455
  register_setting( 'updraft-options-group', 'updraft_encryptionphrase', 'wp_filter_nohtml_kses' );
1456
  register_setting( 'updraft-options-group', 'updraft_service', 'wp_filter_nohtml_kses' );
1457
 
@@ -1612,7 +1632,7 @@ class UpdraftPlus {
1612
  if(isset($_POST['action']) && $_POST['action'] == 'updraft_backup_debug_all') { $this->backup(true,true); }
1613
  elseif (isset($_POST['action']) && $_POST['action'] == 'updraft_backup_debug_db') { $this->backup_db(); }
1614
  elseif (isset($_POST['action']) && $_POST['action'] == 'updraft_wipesettings') {
1615
- $settings = array('updraft_interval', 'updraft_interval_database', 'updraft_retain', 'updraft_encryptionphrase', 'updraft_service', 'updraft_s3_login', 'updraft_s3_pass', 'updraft_s3_remote_path', 'updraft_dropbox_appkey', 'updraft_dropbox_secret', 'updraft_dropbox_folder', 'updraft_googledrive_clientid', 'updraft_googledrive_secret', 'updraft_googledrive_remotepath', 'updraft_ftp_login', 'updraft_ftp_pass', 'updraft_ftp_remote_path', 'updraft_server_address', 'updraft_dir', 'updraft_email', 'updraft_delete_local', 'updraft_debug_mode', 'updraft_include_plugins', 'updraft_include_themes', 'updraft_include_uploads', 'updraft_include_others', 'updraft_include_others_exclude', 'updraft_lastmessage');
1616
  foreach ($settings as $s) {
1617
  delete_option($s);
1618
  }
@@ -1846,7 +1866,12 @@ ENDHERE;
1846
  echo ">$descrip</option>\n";
1847
  }
1848
  ?>
1849
- </select></td>
 
 
 
 
 
1850
  </tr>
1851
  <tr>
1852
  <th>Database backup intervals:</th>
@@ -1858,10 +1883,15 @@ ENDHERE;
1858
  echo ">$descrip</option>\n";
1859
  }
1860
  ?>
1861
- </select></td>
 
 
 
 
 
1862
  </tr>
1863
  <tr class="backup-interval-description">
1864
- <td></td><td>If you would like to automatically schedule backups, choose schedules from the dropdowns above. Backups will occur at the intervals specified starting just after the current time. If you choose manual you must click the &quot;Backup Now!&quot; button whenever you wish a backup to occur. If the two schedules are the same, then the two backups will take place together.</td>
1865
  </tr>
1866
  <?php
1867
  # The true (default value if non-existent) here has the effect of forcing a default of on.
@@ -1872,35 +1902,19 @@ ENDHERE;
1872
  $include_others_exclude = get_option('updraft_include_others_exclude',UPDRAFT_DEFAULT_OTHERS_EXCLUDE);
1873
  ?>
1874
  <tr>
1875
- <th>Include in Files Backup:</th>
1876
  <td>
1877
  <input type="checkbox" name="updraft_include_plugins" value="1" <?php echo $include_plugins; ?> /> Plugins<br>
1878
  <input type="checkbox" name="updraft_include_themes" value="1" <?php echo $include_themes; ?> /> Themes<br>
1879
  <input type="checkbox" name="updraft_include_uploads" value="1" <?php echo $include_uploads; ?> /> Uploads<br>
1880
  <input type="checkbox" name="updraft_include_others" value="1" <?php echo $include_others; ?> /> Any other directories found inside wp-content - but exclude these directories: <input type="text" name="updraft_include_others_exclude" size="32" value="<?php echo htmlspecialchars($include_others_exclude); ?>"/><br>
1881
- Include all of these, unless you are backing them up separately. Note that presently UpdraftPlus backs up these directories only - which is usually everything (except for WordPress core itself which you can download afresh from WordPress.org). But if you have made customised modifications outside of these directories, you need to back them up another way.<br>(<a href="http://wordshell.net">Use WordShell</a> for automatic backup, version control and patching).<br></td>
1882
  </td>
1883
  </tr>
1884
- <tr>
1885
- <th>Retain backups:</th>
1886
- <?php
1887
- $updraft_retain = get_option('updraft_retain');
1888
- $retain = ((int)$updraft_retain > 0)?get_option('updraft_retain'):1;
1889
- ?>
1890
- <td><input type="text" name="updraft_retain" value="<?php echo $retain ?>" style="width:50px" /></td>
1891
- </tr>
1892
- <tr class="backup-retain-description">
1893
- <td></td><td>By default only the most recent backup is retained. If you'd like to preserve more, specify the number here. (This many of <strong>both</strong> files and database backups will be retained.)</td>
1894
- </tr>
1895
  <tr>
1896
  <th>Email:</th>
1897
  <td><input type="text" style="width:260px" name="updraft_email" value="<?php echo get_option('updraft_email'); ?>" /> <br>Enter an address here to have a report sent (and the whole backup, if you choose) to it.</td>
1898
  </tr>
1899
- <tr class="deletelocal">
1900
- <th>Delete local backup:</th>
1901
- <td><input type="checkbox" name="updraft_delete_local" value="1" <?php $delete_local = (get_option('updraft_delete_local')) ? 'checked="checked"' : "";
1902
- echo $delete_local; ?> /> <br>Check this to delete the local backup file (only sensible if you have enabled a remote backup (below), otherwise you will have no backup remaining).</td>
1903
- </tr>
1904
 
1905
  <tr>
1906
  <th>Database encryption phrase:</th>
@@ -1910,7 +1924,7 @@ echo $delete_local; ?> /> <br>Check this to delete the local backup file (only s
1910
  <td><input type="text" name="updraft_encryptionphrase" value="<?php echo $updraft_encryptionphrase ?>" style="width:132px" /></td>
1911
  </tr>
1912
  <tr class="backup-crypt-description">
1913
- <td></td><td>If you enter text here, it is used to encrypt backups (Rijndael). Do not lose it, or all your backups will be useless. Presently, only the database file is encrypted. This is also the key used to decrypt backups from this admin interface (so if you change it, then automatic decryption will not work until you change it back). You can also use the file example-decrypt.php from inside the UpdraftPlus plugin directory to decrypt manually.</td>
1914
  </tr>
1915
  </table>
1916
 
@@ -1984,6 +1998,23 @@ echo $delete_local; ?> /> <br>Check this to delete the local backup file (only s
1984
  <tr>
1985
  <td colspan="2"><h2>Advanced / Debugging Settings</h2></td>
1986
  </tr>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1987
  <tr>
1988
  <th>Backup directory:</th>
1989
  <td><input type="text" name="updraft_dir" style="width:525px" value="<?php echo htmlspecialchars($updraft_dir); ?>" /></td>
@@ -1991,10 +2022,6 @@ echo $delete_local; ?> /> <br>Check this to delete the local backup file (only s
1991
  <tr>
1992
  <td></td><td><?php echo $dir_info ?> This is where Updraft Backup/Restore will write the zip files it creates initially. This directory must be writable by your web server. Typically you'll want to have it inside your wp-content folder (this is the default). <b>Do not</b> place it inside your uploads dir, as that will cause recursion issues (backups of backups of backups of...).</td>
1993
  </tr>
1994
- <tr>
1995
- <th>Debug / Expert mode:</th>
1996
- <td><input type="checkbox" name="updraft_debug_mode" value="1" <?php echo $debug_mode; ?> /> <br>Check this to enable some more options below (that will appear after you save), and potentially receive more information and emails on the backup process - useful if something is going wrong. You <strong>must</strong> send me this log if you are filing a bug report.</td>
1997
- </tr>
1998
  <tr>
1999
  <td></td>
2000
  <td>
4
  Plugin URI: http://wordpress.org/extend/plugins/updraftplus
5
  Description: Backup and restore: your content and database can be automatically backed up to Amazon S3, Dropbox, Google Drive, FTP or email, on separate schedules.
6
  Author: David Anderson.
7
+ Version: 1.2.41
8
  Donate link: http://david.dw-perspective.org.uk/donate
9
  License: GPLv3 or later
10
  Author URI: http://wordshell.net
17
  //?? On 'backup now', open up a Lightbox, count down 5 seconds, then start examining the log file (if it can be found)
18
  //Should make clear in dashboard what is a non-fatal error (i.e. can be retried) - leads to unnecessary bug reports
19
  //Eventually, when everything can be resumed, we will no longer need the backup() routine; it can be replaced with the resume() routine
20
+ // Should we resume if the only errors were upon deletion (i.e. the backup itself was fine?) Presently we do, but it displays errors for the user to confuse them. Perhaps better to make pruning a separate scheuled task??
21
  // Make jobs *individually* resumable (i.e. all the state info must be keyed on the nonce; then call the resume event *specifying the nonce*)
 
22
  // Warn the user if their zip-file creation is slooowww...
23
  // Create a "Want Support?" button/console, that leads them through what is needed, and performs some basic tests...
24
  // Resuming partial FTP uploads
25
+ // Provide backup/restoration for UpdraftPlus's settings, to allow 'bootstrap' on a fresh WP install
26
 
27
  Encrypt filesystem, if memory allows (and have option for abort if not); split up into multiple zips when needed
28
  // Does not delete old custom directories upon a restore?
65
 
66
  class UpdraftPlus {
67
 
68
+ var $version = '1.2.41';
69
 
70
  // Choices will be shown in the admin menu in the order used here
71
  var $backup_methods = array (
424
  //cloud operations (S3,Google Drive,FTP,email,nothing)
425
  //this also calls the retain (prune) feature at the end (done in this method to reuse existing cloud connections)
426
  if(is_array($backup_array) && count($backup_array) >0) {
 
427
  $this->cloud_backup($backup_array);
428
  }
429
 
444
  if (strlen($encryption) > 0) {
445
  $this->log("$file: applying encryption");
446
  $encryption_error = 0;
447
+ $microstart = microtime(true);
448
  require_once(UPDRAFTPLUS_DIR.'/includes/Rijndael.php');
449
  $rijndael = new Crypt_Rijndael();
450
  $rijndael->setKey($encryption);
451
  $updraft_dir = $this->backups_dir_location();
452
+ $file_size = @filesize($updraft_dir.'/'.$file)/1024;
453
  $in_handle = @fopen($updraft_dir.'/'.$file,'r');
454
  $buffer = "";
455
  while (!feof ($in_handle)) {
460
  if (!fwrite($out_handle, $rijndael->encrypt($buffer))) {$encryption_error = 1;}
461
  fclose ($out_handle);
462
  if (0 == $encryption_error) {
463
+ $time_taken = max(0.000001, microtime(true)-$microstart);
464
+ $this->log("$file: encryption successful: ".round($file_size,1)."Kb in ".round($time_taken,1)."s (".round($file_size/$time_taken, 1)."Kb/s)");
465
  # Delete unencrypted file
466
  @unlink($updraft_dir.'/'.$file);
467
  return basename($file.'.crypt');
570
  update_option('updraft_file_ids',$ids);
571
  $this->log("Stored file<->id correlation in database ($file <-> $id)");
572
  }
573
+ // Delete local files immediately if the option is set
574
+ // Where we are only backing up locally, only the "prune" function should do deleting
575
+ if (get_option('updraft_service', 'none') != 'none') $this->delete_local($file);
576
  }
577
 
578
  // Dispatch to the relevant function
584
  $method_include = UPDRAFTPLUS_DIR.'/methods/'.$service.'.php';
585
  if (file_exists($method_include)) require_once($method_include);
586
 
587
+ if ($service == "none") {
588
+ $this->log("No remote despatch: user chose no remote backup service");
589
+ } else {
590
+ $this->log("Beginning dispatch of backup to remote");
591
+ }
592
+
593
  $objname = "UpdraftPlus_BackupModule_${service}";
594
  if (method_exists($objname, "backup")) {
595
  // New style - external, allowing more plugability
596
  $remote_obj = new $objname;
597
  $remote_obj->backup($backup_array);
598
+ } elseif ($service == "none") {
599
+ $this->prune_retained_backups("none", null, null);
600
  }
601
  }
602
 
616
  // Carries out retain behaviour. Pass in a valid S3 or FTP object and path if relevant.
617
  function prune_retained_backups($updraft_service, $backup_method_object = null, $backup_passback = null) {
618
 
619
+ // If they turned off deletion on local backups, then there is nothing to do
620
+ if (get_option('updraft_delete_local') == 0 && $updraft_service == 'none') {
621
+ $this->log("Prune old backups from local store: nothing to do, since the user disabled local deletion and we are using local backups");
622
+ return;
623
+ }
624
+
625
  $this->log("Retain: beginning examination of existing backup sets");
626
 
627
+ // Number of backups to retain - files
628
  $updraft_retain = get_option('updraft_retain', 1);
629
+ $updraft_retain = (is_numeric($updraft_retain)) ? $updraft_retain : 1;
630
+ $this->log("Retain files: user setting: number to retain = $updraft_retain");
631
+
632
+ // Number of backups to retain - db
633
+ $updraft_retain_db = get_option('updraft_retain_db', $updraft_retain);
634
+ $updraft_retain_db = (is_numeric($updraft_retain_db)) ? $updraft_retain_db : 1;
635
+ $this->log("Retain db: user setting: number to retain = $updraft_retain_db");
636
 
637
  // Returns an array, most recent first, of backup sets
638
  $backup_history = $this->get_backup_history();
648
  if (isset($backup_to_examine['db'])) {
649
  $db_backups_found++;
650
  $this->log("$backup_datestamp: this set includes a database (".$backup_to_examine['db']."); db count is now $db_backups_found");
651
+ if ($db_backups_found > $updraft_retain_db) {
652
+ $this->log("$backup_datestamp: over retain limit ($updraft_retain_db); will delete this database");
653
  $dofile = $backup_to_examine['db'];
654
  if (!empty($dofile)) $this->prune_file($updraft_service, $dofile, $backup_method_object, $backup_passback);
655
  unset($backup_to_examine['db']);
658
  if (isset($backup_to_examine['plugins']) || isset($backup_to_examine['themes']) || isset($backup_to_examine['uploads']) || isset($backup_to_examine['others'])) {
659
  $file_backups_found++;
660
  $this->log("$backup_datestamp: this set includes files; fileset count is now $file_backups_found");
661
+ if ($file_backups_found > $updraft_retain) {
662
+ $this->log("$backup_datestamp: over retain limit ($updraft_retain); will delete this file set");
663
  $file = isset($backup_to_examine['plugins']) ? $backup_to_examine['plugins'] : "";
664
  $file2 = isset($backup_to_examine['themes']) ? $backup_to_examine['themes'] : "";
665
  $file3 = isset($backup_to_examine['uploads']) ? $backup_to_examine['uploads'] : "";
813
  while (false !== ($entry = readdir($handle))) {
814
  $candidate = WP_CONTENT_DIR.'/'.$entry;
815
  if ($entry == "." || $entry == "..") { ; }
816
+ elseif ($candidate == $updraft_dir) { $this->log("others: $entry: skipping: this is the updraft directory"); }
817
+ elseif ($candidate == $wp_themes_dir) { $this->log("others: $entry: skipping: this is the themes directory"); }
818
+ elseif ($candidate == $wp_upload_dir) { $this->log("others: $entry: skipping: this is the uploads directory"); }
819
+ elseif ($candidate == $wp_plugins_dir) { $this->log("others: $entry: skipping: this is the plugins directory"); }
820
+ elseif (isset($others_skip[$entry])) { $this->log("others: $entry: skipping: excluded by options"); }
821
+ else { $this->log("others: $entry: adding to list"); array_push($other_dirlist, $candidate); }
822
  }
823
  } else {
824
  $this->log('ERROR: Could not read the content directory: '.WP_CONTENT_DIR);
972
  foreach ($stitch_files as $table_file) {
973
  $this->log("{$table_file}.gz: adding to final database dump");
974
  $handle = gzopen($updraft_dir.'/'.$table_file.'.gz', "r");
975
+ while (!gzeof($handle)) { $this->stow(gzread($handle, 65536)); }
976
  gzclose($handle);
977
  @unlink($updraft_dir.'/'.$table_file.'.gz');
978
  }
1117
  $this->stow("# --------------------------------------------------------\n");
1118
  $this->stow("\n");
1119
  }
1120
+ $this->log("Table $table: Total rows added: $total_rows in ".sprintf("%.02f",max(microtime(true)-$microtime,0.00001))." seconds");
1121
 
1122
  } // end backup_table()
1123
 
1471
  register_setting( 'updraft-options-group', 'updraft_interval', array($this,'schedule_backup') );
1472
  register_setting( 'updraft-options-group', 'updraft_interval_database', array($this,'schedule_backup_database') );
1473
  register_setting( 'updraft-options-group', 'updraft_retain', array($this,'retain_range') );
1474
+ register_setting( 'updraft-options-group', 'updraft_retain_db', array($this,'retain_range') );
1475
  register_setting( 'updraft-options-group', 'updraft_encryptionphrase', 'wp_filter_nohtml_kses' );
1476
  register_setting( 'updraft-options-group', 'updraft_service', 'wp_filter_nohtml_kses' );
1477
 
1632
  if(isset($_POST['action']) && $_POST['action'] == 'updraft_backup_debug_all') { $this->backup(true,true); }
1633
  elseif (isset($_POST['action']) && $_POST['action'] == 'updraft_backup_debug_db') { $this->backup_db(); }
1634
  elseif (isset($_POST['action']) && $_POST['action'] == 'updraft_wipesettings') {
1635
+ $settings = array('updraft_interval', 'updraft_interval_database', 'updraft_retain', 'updraft_retain_db', 'updraft_encryptionphrase', 'updraft_service', 'updraft_s3_login', 'updraft_s3_pass', 'updraft_s3_remote_path', 'updraft_dropbox_appkey', 'updraft_dropbox_secret', 'updraft_dropbox_folder', 'updraft_googledrive_clientid', 'updraft_googledrive_secret', 'updraft_googledrive_remotepath', 'updraft_ftp_login', 'updraft_ftp_pass', 'updraft_ftp_remote_path', 'updraft_server_address', 'updraft_dir', 'updraft_email', 'updraft_delete_local', 'updraft_debug_mode', 'updraft_include_plugins', 'updraft_include_themes', 'updraft_include_uploads', 'updraft_include_others', 'updraft_include_others_exclude', 'updraft_lastmessage');
1636
  foreach ($settings as $s) {
1637
  delete_option($s);
1638
  }
1866
  echo ">$descrip</option>\n";
1867
  }
1868
  ?>
1869
+ </select>
1870
+ and retain this many backups: <?php
1871
+ $updraft_retain = get_option('updraft_retain', 1);
1872
+ $updraft_retain = ((int)$updraft_retain > 0) ? (int)$updraft_retain : 1;
1873
+ ?> <input type="text" name="updraft_retain" value="<?php echo $updraft_retain ?>" style="width:40px;" />
1874
+ </td>
1875
  </tr>
1876
  <tr>
1877
  <th>Database backup intervals:</th>
1883
  echo ">$descrip</option>\n";
1884
  }
1885
  ?>
1886
+ </select>
1887
+ and retain this many backups: <?php
1888
+ $updraft_retain_db = get_option('updraft_retain_db', $updraft_retain);
1889
+ $updraft_retain_db = ((int)$updraft_retain_db > 0) ? (int)$updraft_retain_db : 1;
1890
+ ?> <input type="text" name="updraft_retain_db" value="<?php echo $updraft_retain_db ?>" style="width:40px" />
1891
+ </td>
1892
  </tr>
1893
  <tr class="backup-interval-description">
1894
+ <td></td><td>If you would like to automatically schedule backups, choose schedules from the dropdowns above. Backups will occur at the intervals specified starting just after the current time. If the two schedules are the same, then the two backups will take place together. If you choose &quot;manual&quot; then you must click the &quot;Backup Now!&quot; button whenever you wish a backup to occur. </td>
1895
  </tr>
1896
  <?php
1897
  # The true (default value if non-existent) here has the effect of forcing a default of on.
1902
  $include_others_exclude = get_option('updraft_include_others_exclude',UPDRAFT_DEFAULT_OTHERS_EXCLUDE);
1903
  ?>
1904
  <tr>
1905
+ <th>Include in files backup:</th>
1906
  <td>
1907
  <input type="checkbox" name="updraft_include_plugins" value="1" <?php echo $include_plugins; ?> /> Plugins<br>
1908
  <input type="checkbox" name="updraft_include_themes" value="1" <?php echo $include_themes; ?> /> Themes<br>
1909
  <input type="checkbox" name="updraft_include_uploads" value="1" <?php echo $include_uploads; ?> /> Uploads<br>
1910
  <input type="checkbox" name="updraft_include_others" value="1" <?php echo $include_others; ?> /> Any other directories found inside wp-content - but exclude these directories: <input type="text" name="updraft_include_others_exclude" size="32" value="<?php echo htmlspecialchars($include_others_exclude); ?>"/><br>
1911
+ Include all of these, unless you are backing them up outside of UpdraftPlus. The above directories are usually everything (except for WordPress core itself which you can download afresh from WordPress.org). But if you have made customised modifications outside of these directories, you need to back them up another way. (<a href="http://wordshell.net">Use WordShell</a> for automatic backup, version control and patching).<br></td>
1912
  </td>
1913
  </tr>
 
 
 
 
 
 
 
 
 
 
 
1914
  <tr>
1915
  <th>Email:</th>
1916
  <td><input type="text" style="width:260px" name="updraft_email" value="<?php echo get_option('updraft_email'); ?>" /> <br>Enter an address here to have a report sent (and the whole backup, if you choose) to it.</td>
1917
  </tr>
 
 
 
 
 
1918
 
1919
  <tr>
1920
  <th>Database encryption phrase:</th>
1924
  <td><input type="text" name="updraft_encryptionphrase" value="<?php echo $updraft_encryptionphrase ?>" style="width:132px" /></td>
1925
  </tr>
1926
  <tr class="backup-crypt-description">
1927
+ <td></td><td>If you enter text here, it is used to encrypt backups (Rijndael). <strong>Do make a separate record of it and do not lose it, or all your backups <em>will</em> be useless.</strong> Presently, only the database file is encrypted. This is also the key used to decrypt backups from this admin interface (so if you change it, then automatic decryption will not work until you change it back). You can also use the file example-decrypt.php from inside the UpdraftPlus plugin directory to decrypt manually.</td>
1928
  </tr>
1929
  </table>
1930
 
1998
  <tr>
1999
  <td colspan="2"><h2>Advanced / Debugging Settings</h2></td>
2000
  </tr>
2001
+ <tr>
2002
+ <th>Debug / Expert mode:</th>
2003
+ <td><input type="checkbox" name="updraft_debug_mode" value="1" <?php echo $debug_mode; ?> /> <br>Check this to enable some more options here and below (that will appear after you save), and potentially receive more information and emails on the backup process - useful if something is going wrong. You <strong>must</strong> send me this log if you are filing a bug report.</td>
2004
+ </tr>
2005
+ <?php
2006
+ $delete_local = get_option('updraft_delete_local', 1);
2007
+ if (get_option('updraft_debug_mode')) { ?>
2008
+
2009
+ <tr class="deletelocal">
2010
+ <th>Delete local backup:</th>
2011
+ <td><input type="checkbox" name="updraft_delete_local" value="1" <?php if ($delete_local) echo 'checked="checked"'; ?>> <br>Uncheck this to prevent deletion of any superfluous backup files from your server after the backup run finishes (i.e. any files despatched remotely will also remain locally, and any files being kept locally will not be subject to the retention limits).</td>
2012
+ </tr>
2013
+
2014
+ <?php } else { ?>
2015
+ <input type="hidden" name="updraft_delete_local" value="<?php echo ($delete_local) ? 1 : 0; ?>">
2016
+ <?php } ?>
2017
+
2018
  <tr>
2019
  <th>Backup directory:</th>
2020
  <td><input type="text" name="updraft_dir" style="width:525px" value="<?php echo htmlspecialchars($updraft_dir); ?>" /></td>
2022
  <tr>
2023
  <td></td><td><?php echo $dir_info ?> This is where Updraft Backup/Restore will write the zip files it creates initially. This directory must be writable by your web server. Typically you'll want to have it inside your wp-content folder (this is the default). <b>Do not</b> place it inside your uploads dir, as that will cause recursion issues (backups of backups of backups of...).</td>
2024
  </tr>
 
 
 
 
2025
  <tr>
2026
  <td></td>
2027
  <td>