BackWPup – WordPress Backup Plugin - Version 3.2.4

Version Description

= After an upgrade from version 2 =

Please check all settings after the update:

  • Dropbox authentication must be done again
  • SugarSync authentication must be done again
  • S3 Settings
  • Google Storage is now in S3
  • Check all your passwords
Download this release

Release Info

Developer danielhuesken
Plugin Icon 128x128 BackWPup – WordPress Backup Plugin
Version 3.2.4
Comparing to
See all releases

Code changes from version 3.2.3 to 3.2.4

backwpup.php CHANGED
@@ -5,7 +5,7 @@
5
  * Description: WordPress Backup Plugin
6
  * Author: Inpsyde GmbH
7
  * Author URI: http://inpsyde.com
8
- * Version: 3.2.3
9
  * Text Domain: backwpup
10
  * Domain Path: /languages/
11
  * Network: true
5
  * Description: WordPress Backup Plugin
6
  * Author: Inpsyde GmbH
7
  * Author URI: http://inpsyde.com
8
+ * Version: 3.2.4
9
  * Text Domain: backwpup
10
  * Domain Path: /languages/
11
  * Network: true
inc/class-admin.php CHANGED
@@ -393,8 +393,9 @@ final class BackWPup_Admin {
393
 
394
  if ( isset( $_REQUEST[ 'page' ] ) && strstr( $_REQUEST[ 'page' ], 'backwpup' ) ) {
395
  $admin_footer_text = '<a href="' . __( 'http://marketpress.com', 'backwpup' ) . '" class="mp_logo" title="' . __( 'MarketPress', 'backwpup' ) . '">' . __( 'MarketPress', 'backwpup' ) . '</a>';
396
- if ( ! class_exists( 'BackWPup_Pro', FALSE ) )
397
- $admin_footer_text .= sprintf( __( '<a class="backwpup-get-pro" href="%s">Get BackWPup Pro now.</a>', 'backwpup' ), __( 'http://marketpress.com/product/backwpup-pro/', 'backwpup' ) );
 
398
 
399
  return $admin_footer_text . $default_text;
400
  }
393
 
394
  if ( isset( $_REQUEST[ 'page' ] ) && strstr( $_REQUEST[ 'page' ], 'backwpup' ) ) {
395
  $admin_footer_text = '<a href="' . __( 'http://marketpress.com', 'backwpup' ) . '" class="mp_logo" title="' . __( 'MarketPress', 'backwpup' ) . '">' . __( 'MarketPress', 'backwpup' ) . '</a>';
396
+ if ( ! class_exists( 'BackWPup_Pro', FALSE ) ) {
397
+ $admin_footer_text .= sprintf( __( '<a class="backwpup-get-pro" href="%s">Get BackWPup Pro now.</a>', 'backwpup' ), translate( BackWPup::get_plugin_data( 'PluginURI' ), 'backwpup' ) );
398
+ }
399
 
400
  return $admin_footer_text . $default_text;
401
  }
inc/class-create-archive.php CHANGED
@@ -44,13 +44,6 @@ class BackWPup_Create_Archive {
44
  */
45
  private $pclzip_file_list = array();
46
 
47
- /**
48
- * Saved encoding will restored on __destruct
49
- *
50
- * @var string
51
- */
52
- private $previous_encoding = '';
53
-
54
  /**
55
  * File cont off added files to handel somethings that depends on it
56
  *
@@ -121,10 +114,6 @@ class BackWPup_Create_Archive {
121
  }
122
  if( $this->get_method() == 'PclZip' ) {
123
  $this->method = 'PclZip';
124
- if ( ini_get( 'mbstring.func_overload' ) && function_exists( 'mb_internal_encoding' ) ) {
125
- $this->previous_encoding = mb_internal_encoding();
126
- mb_internal_encoding( 'ISO-8859-1' );
127
- }
128
  if ( ! defined('PCLZIP_TEMPORARY_DIR') ) {
129
  define( 'PCLZIP_TEMPORARY_DIR', BackWPup::get_plugin_data( 'TEMP' ) );
130
  }
@@ -162,11 +151,6 @@ class BackWPup_Create_Archive {
162
  */
163
  public function __destruct() {
164
 
165
- //set encoding back
166
- if ( ! empty( $this->previous_encoding ) ) {
167
- mb_internal_encoding( $this->previous_encoding );
168
- }
169
-
170
  //close PclZip Class
171
  if ( is_object( $this->pclzip ) ) {
172
  if ( count( $this->pclzip_file_list ) > 0 ) {
@@ -255,23 +239,6 @@ class BackWPup_Create_Archive {
255
  //remove reserved chars
256
  $name_in_archive = str_replace( array( "?", "<", ">", ":", "%","\"", "*", "|", chr(0) ) , '', $name_in_archive );
257
 
258
- //convert chars in archives
259
- if ( function_exists( 'iconv' ) ) {
260
- $charsets = array( 'UTF-8', 'ASCII',
261
- 'ISO-8859-1', 'ISO-8859-2', 'ISO-8859-3', 'ISO-8859-4', 'ISO-8859-5',
262
- 'ISO-8859-6', 'ISO-8859-7', 'ISO-8859-8', 'ISO-8859-9', 'ISO-8859-10',
263
- 'ISO-8859-13', 'ISO-8859-14', 'ISO-8859-15', 'ISO-8859-16',
264
- 'Windows-1251', 'Windows-1252', 'Windows-1254'
265
- );
266
- foreach ( $charsets as $charset ) {
267
- $test = @iconv( $charset, 'UTF-8', $name_in_archive );
268
- if ( $test ) {
269
- $name_in_archive = $test;
270
- break;
271
- }
272
- }
273
- }
274
-
275
  switch ( $this->get_method() ) {
276
  case 'gz':
277
  if ( $this->file_count > 0 ) {
@@ -308,9 +275,23 @@ class BackWPup_Create_Archive {
308
  case 'Tar':
309
  case 'TarGz':
310
  case 'TarBz2':
 
 
 
 
 
 
 
311
  return $this->tar_file( $file_name, $name_in_archive );
312
  break;
313
  case 'ZipArchive':
 
 
 
 
 
 
 
314
  $file_size = filesize( $file_name );
315
  if ( $file_size === FALSE ) {
316
  return FALSE;
44
  */
45
  private $pclzip_file_list = array();
46
 
 
 
 
 
 
 
 
47
  /**
48
  * File cont off added files to handel somethings that depends on it
49
  *
114
  }
115
  if( $this->get_method() == 'PclZip' ) {
116
  $this->method = 'PclZip';
 
 
 
 
117
  if ( ! defined('PCLZIP_TEMPORARY_DIR') ) {
118
  define( 'PCLZIP_TEMPORARY_DIR', BackWPup::get_plugin_data( 'TEMP' ) );
119
  }
151
  */
152
  public function __destruct() {
153
 
 
 
 
 
 
154
  //close PclZip Class
155
  if ( is_object( $this->pclzip ) ) {
156
  if ( count( $this->pclzip_file_list ) > 0 ) {
239
  //remove reserved chars
240
  $name_in_archive = str_replace( array( "?", "<", ">", ":", "%","\"", "*", "|", chr(0) ) , '', $name_in_archive );
241
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
242
  switch ( $this->get_method() ) {
243
  case 'gz':
244
  if ( $this->file_count > 0 ) {
275
  case 'Tar':
276
  case 'TarGz':
277
  case 'TarBz2':
278
+ //convert chars for archives file names
279
+ if ( function_exists( 'iconv' ) && stristr( PHP_OS, 'win' ) !== false ) {
280
+ $test = @iconv( 'ISO-8859-1', 'UTF-8', $name_in_archive );
281
+ if ( $test ) {
282
+ $name_in_archive = $test;
283
+ }
284
+ }
285
  return $this->tar_file( $file_name, $name_in_archive );
286
  break;
287
  case 'ZipArchive':
288
+ //convert chars for archives file names
289
+ if ( function_exists( 'iconv' ) && stristr( PHP_OS, 'win' ) === false ) {
290
+ $test = @iconv( 'UTF-8', 'CP437', $name_in_archive );
291
+ if ( $test ) {
292
+ $name_in_archive = $test;
293
+ }
294
+ }
295
  $file_size = filesize( $file_name );
296
  if ( $file_size === FALSE ) {
297
  return FALSE;
inc/class-cron.php CHANGED
@@ -138,8 +138,8 @@ class BackWPup_Cron {
138
  nocache_headers();
139
 
140
  //on test die for fast feedback
141
- if ( $_GET[ 'backwpup_run' ] == 'test' ) {
142
- die( 'BackWPup Test' );
143
  }
144
 
145
  // generate normal nonce
138
  nocache_headers();
139
 
140
  //on test die for fast feedback
141
+ if ( $_GET[ 'backwpup_run' ] === 'test' ) {
142
+ die( '' );
143
  }
144
 
145
  // generate normal nonce
inc/class-destination-dropbox.php CHANGED
@@ -1,4 +1,5 @@
1
  <?php
 
2
  /**
3
  * Documentation: https://www.dropbox.com/developers/reference/api
4
  */
@@ -7,14 +8,20 @@ class BackWPup_Destination_Dropbox extends BackWPup_Destinations {
7
  /**
8
  * @var $backwpup_job_object BackWPup_Job
9
  */
10
- public static $backwpup_job_object = NULL;
11
 
12
  /**
13
  * @return array
14
  */
15
  public function option_defaults() {
16
 
17
- return array( 'dropboxtoken' => array(), 'dropboxroot' => 'sandbox', 'dropboxmaxbackups' => 15, 'dropboxsyncnodelete' => TRUE, 'dropboxdir' => trailingslashit( sanitize_file_name( get_bloginfo( 'name' ) ) ) );
 
 
 
 
 
 
18
  }
19
 
20
 
@@ -23,14 +30,18 @@ class BackWPup_Destination_Dropbox extends BackWPup_Destinations {
23
  */
24
  public function edit_tab( $jobid ) {
25
 
26
- if ( ! empty( $_GET[ 'deleteauth' ] ) && $_GET[ 'deleteauth' ] == 1 ) {
27
  //disable token on dropbox
28
  try {
29
  $dropbox = new BackWPup_Destination_Dropbox_API( BackWPup_Option::get( $jobid, 'dropboxroot' ) );
30
- if ( BackWPup_Option::get( $jobid, 'dropboxsecret' ) )
31
- $dropbox->setOAuthTokens( array( 'access_token' => BackWPup_Option::get( $jobid, 'dropboxtoken' ), 'oauth_token_secret' => BackWPup_Encryption::decrypt( BackWPup_Option::get( $jobid, 'dropboxsecret' ) ) ) );
32
- else
 
 
 
33
  $dropbox->setOAuthTokens( BackWPup_Option::get( $jobid, 'dropboxtoken' ) );
 
34
  $dropbox->disable_access_token();
35
  } catch ( Exception $e ) {
36
  echo '<div id="message" class="error"><p>' . sprintf( __( 'Dropbox API: %s', 'backwpup' ), $e->getMessage() ) . '</p></div>';
@@ -40,122 +51,148 @@ class BackWPup_Destination_Dropbox extends BackWPup_Destinations {
40
  BackWPup_Option::delete( $jobid, 'dropboxsecret' );
41
  }
42
 
43
- $dropbox = new BackWPup_Destination_Dropbox_API( 'dropbox' );
44
  $dropbox_auth_url = $dropbox->oAuthAuthorize();
45
- $dropbox = new BackWPup_Destination_Dropbox_API( 'sandbox' );
46
  $sandbox_auth_url = $dropbox->oAuthAuthorize();
47
 
48
  $dropboxtoken = BackWPup_Option::get( $jobid, 'dropboxtoken' );
49
  ?>
50
 
51
- <h3 class="title"><?php _e( 'Login', 'backwpup' ); ?></h3>
52
- <p></p>
53
- <table class="form-table">
54
- <tr>
55
- <th scope="row"><?php _e( 'Authentication', 'backwpup' ); ?></th>
56
- <td><?php if ( empty( $dropboxtoken[ 'access_token' ] ) ) { ?>
57
- <span style="color:red;"><?php _e( 'Not authenticated!', 'backwpup' ); ?></span><br />&nbsp;<br />
58
- <a class="button secondary" href="http://db.tt/8irM1vQ0"><?php _e( 'Create Account', 'backwpup' ); ?></a>
59
- <?php } else { ?>
60
- <span style="color:green;"><?php _e( 'Authenticated!', 'backwpup' ); ?></span><br />&nbsp;<br />
61
- <a class="button secondary" href="<?php echo network_admin_url( 'admin.php' ) . '?page=backwpupeditjob&deleteauth=1&jobid=' . $jobid .'&tab=dest-dropbox&_wpnonce=' . wp_create_nonce( 'edit-job' ); ?>" title="<?php _e( 'Delete Dropbox Authentication', 'backwpup' ); ?>"><?php _e( 'Delete Dropbox Authentication', 'backwpup' ); ?></a>
62
- <?php } ?>
63
- </td>
64
- </tr>
65
-
66
- <?php if ( empty( $dropboxtoken[ 'access_token' ] ) ) { ?>
67
- <tr>
68
- <th scope="row"><label for="id_sandbox_code"><?php _e( 'App Access to Dropbox', 'backwpup' ); ?></label></th>
69
- <td>
70
- <input id="id_sandbox_code" name="sandbox_code" type="text" value="" class="regular-text code help-tip" title="<?php esc_attr_e( 'A dedicated folder named BackWPup will be created inside of the Apps folder in your Dropbox. BackWPup will get read and write access to that folder only. You can specify a subfolder as your backup destination for this job in the destination field below.', 'backwpup' ); ?>" />&nbsp;
71
- <a class="button secondary" href="<?php echo $sandbox_auth_url;?>" target="_blank"><?php _e( 'Get Dropbox App auth code', 'backwpup' ); ?></a>
72
- <p><em><?php _e( 'Allows restricted access to Apps/BackWPup folder only.', 'backwpup' ); ?></em></p>
73
- </td>
74
- </tr>
75
- <tr>
76
- <th></th>
77
- <td><?php _e( '— OR —', 'backwpup' ); ?></td>
78
- </tr>
79
- <tr>
80
- <th scope="row"><label for="id_dropbbox_code"><?php _e( 'Full Access to Dropbox', 'backwpup' ); ?></label></th>
81
- <td>
82
- <input id="id_dropbbox_code" name="dropbbox_code" type="text" value="" class="regular-text code help-tip" title="<?php _e( 'BackWPup will have full read and write access to your entire Dropbox. You can specify your backup destination wherever you want, just be aware that ANY files or folders inside of your Dropbox can be overridden or deleted by BackWPup.', 'backwpup' ); ?>" />&nbsp;
83
- <a class="button secondary" href="<?php echo $dropbox_auth_url;?>" target="_blank"><?php _e( 'Get full Dropbox auth code ', 'backwpup' ); ?></a>
84
- <p><em><?php _e( 'Allows full access to your entire Dropbox.', 'backwpup' ); ?></em></p>
85
- </td>
86
- </tr>
87
- <?php } ?>
88
- </table>
89
-
90
-
91
- <h3 class="title"><?php _e( 'Backup settings', 'backwpup' ); ?></h3>
92
- <p></p>
93
- <table class="form-table">
94
- <tr>
95
- <th scope="row"><label for="iddropboxdir"><?php _e( 'Destination Folder', 'backwpup' ); ?></label></th>
96
- <td>
97
- <input id="iddropboxdir" name="dropboxdir" type="text" value="<?php echo esc_attr( BackWPup_Option::get( $jobid, 'dropboxdir' ) ); ?>" class="regular-text help-tip" title="<?php esc_attr_e( 'Specify a subfolder where your backup archives will be stored. If you use the App option from above, this folder will be created inside of Apps/BackWPup. Otherwise it will be created at the root of your Dropbox. Already exisiting folders with the same name will not be overriden.', 'backwpup' ); ?>" />
98
- <p><em><?php _e( 'Folder inside your Dropbox where your backup archives will be stored.', 'backwpup' );?></em></p>
99
- </td>
100
- </tr>
101
- <tr>
102
- <th scope="row"><?php _e( 'File Deletion', 'backwpup' ); ?></th>
103
- <td>
104
- <?php
105
- if ( BackWPup_Option::get( $jobid, 'backuptype' ) == 'archive' ) {
106
- ?>
107
- <label for="iddropboxmaxbackups"><input id="iddropboxmaxbackups" name="dropboxmaxbackups" title="<?php esc_attr_e( 'Older files will be deleted first. 0 = no files will be deleted.', 'backwpup' ); ?>" type="text" size="3" value="<?php echo esc_attr( BackWPup_Option::get( $jobid, 'dropboxmaxbackups' ) );?>" class="small-text help-tip" />&nbsp;
108
- <em><?php _e( 'Number of files to keep in folder.', 'backwpup' ); ?></em></label>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
  <?php } else { ?>
110
- <label for="iddropboxsyncnodelete" ><input class="checkbox" value="1"
111
- type="checkbox" <?php checked( BackWPup_Option::get( $jobid, 'dropboxsyncnodelete' ), TRUE ); ?>
112
- name="dropboxsyncnodelete" id="iddropboxsyncnodelete" /> <?php _e( 'Do not delete files while syncing to destination!', 'backwpup' ); ?></label>
 
 
113
  <?php } ?>
114
- </td>
115
- </tr>
116
- </table>
117
 
118
- <?php
119
  }
120
 
121
  /**
122
  * @param $jobid
 
123
  * @return string|void
124
  */
125
  public function edit_form_post_save( $jobid ) {
126
 
127
  // get auth
128
- if ( ! empty( $_POST[ 'sandbox_code' ] ) ) {
129
  try {
130
- $dropbox = new BackWPup_Destination_Dropbox_API( 'sandbox' );
131
- $dropboxtoken = $dropbox->oAuthToken( $_POST[ 'sandbox_code' ] );
132
  BackWPup_Option::update( $jobid, 'dropboxtoken', $dropboxtoken );
133
  BackWPup_Option::update( $jobid, 'dropboxroot', 'sandbox' );
134
  } catch ( Exception $e ) {
135
- BackWPup_Admin::message( 'DROPBOX: ' . $e->getMessage(), TRUE );
136
  }
137
  }
138
 
139
- if ( ! empty( $_POST[ 'dropbbox_code' ] ) ) {
140
  try {
141
- $dropbox = new BackWPup_Destination_Dropbox_API( 'dropbox' );
142
- $dropboxtoken = $dropbox->oAuthToken( $_POST[ 'dropbbox_code' ] );
143
  BackWPup_Option::update( $jobid, 'dropboxtoken', $dropboxtoken );
144
  BackWPup_Option::update( $jobid, 'dropboxroot', 'dropbox' );
145
  } catch ( Exception $e ) {
146
- BackWPup_Admin::message( 'DROPBOX: ' . $e->getMessage(), TRUE );
147
  }
148
  }
149
 
150
- BackWPup_Option::update( $jobid, 'dropboxsyncnodelete', ( isset( $_POST[ 'dropboxsyncnodelete' ] ) && $_POST[ 'dropboxsyncnodelete' ] == 1 ) ? TRUE : FALSE );
151
- BackWPup_Option::update( $jobid, 'dropboxmaxbackups', isset( $_POST[ 'dropboxmaxbackups' ] ) ? (int)$_POST[ 'dropboxmaxbackups' ] : 0 );
152
 
153
- $_POST[ 'dropboxdir' ] = trailingslashit( str_replace( '//', '/', str_replace( '\\', '/', trim( stripslashes( $_POST[ 'dropboxdir' ] ) ) ) ) );
154
- if ( substr( $_POST[ 'dropboxdir' ], 0, 1 ) == '/' )
155
- $_POST[ 'dropboxdir' ] = substr( $_POST[ 'dropboxdir' ], 1 );
156
- if ( $_POST[ 'dropboxdir' ] == '/' )
157
- $_POST[ 'dropboxdir' ] = '';
158
- BackWPup_Option::update( $jobid, 'dropboxdir', $_POST[ 'dropboxdir' ] );
 
 
159
 
160
  }
161
 
@@ -174,13 +211,13 @@ class BackWPup_Destination_Dropbox extends BackWPup_Destinations {
174
  $dropbox->fileopsDelete( $backupfile );
175
  //update file list
176
  foreach ( $files as $key => $file ) {
177
- if ( is_array( $file ) && $file[ 'file' ] == $backupfile )
178
  unset( $files[ $key ] );
 
179
  }
180
  unset( $dropbox );
181
- }
182
- catch ( Exception $e ) {
183
- BackWPup_Admin::message( 'DROPBOX: ' . $e->getMessage(), TRUE );
184
  }
185
 
186
  set_site_transient( 'backwpup_' . strtolower( $jobdest ), $files, 3600 * 24 * 7 );
@@ -196,17 +233,18 @@ class BackWPup_Destination_Dropbox extends BackWPup_Destinations {
196
  $dropbox = new BackWPup_Destination_Dropbox_API( BackWPup_Option::get( $jobid, 'dropboxroot' ) );
197
  $dropbox->setOAuthTokens( BackWPup_Option::get( $jobid, 'dropboxtoken' ) );
198
  $media = $dropbox->media( $get_file );
199
- if ( ! empty( $media[ 'url' ] ) )
200
- header( "Location: " . $media[ 'url' ] );
 
201
  die();
202
- }
203
- catch ( Exception $e ) {
204
  die( $e->getMessage() );
205
  }
206
  }
207
 
208
  /**
209
  * @param $jobdest
 
210
  * @return mixed
211
  */
212
  public function file_get_list( $jobdest ) {
@@ -215,44 +253,50 @@ class BackWPup_Destination_Dropbox extends BackWPup_Destinations {
215
 
216
  /**
217
  * @param $job_object
 
218
  * @return bool
219
  */
220
  public function job_run_archive( BackWPup_Job $job_object ) {
221
 
222
  $job_object->substeps_todo = 2 + $job_object->backup_filesize;
223
- if ( $job_object->steps_data[ $job_object->step_working ]['SAVE_STEP_TRY'] != $job_object->steps_data[ $job_object->step_working ][ 'STEP_TRY' ] )
224
- $job_object->log( sprintf( __( '%d. Try to send backup file to Dropbox&#160;&hellip;', 'backwpup' ), $job_object->steps_data[ $job_object->step_working ][ 'STEP_TRY' ] ) );
 
225
 
226
  try {
227
- $dropbox = new BackWPup_Destination_Dropbox_API( $job_object->job[ 'dropboxroot' ] );
228
  // cahnge oauth1 to oauth2 token
229
- if ( ! empty( $job_object->job[ 'dropboxsecret' ] ) && empty( $job_object->job[ 'dropboxtoken' ][ 'access_token' ] ) ) {
230
- $dropbox->setOAuthTokens( array( 'access_token' => $job_object->job[ 'dropboxtoken' ], 'oauth_token_secret' => BackWPup_Encryption::decrypt( $job_object->job[ 'dropboxsecret' ] ) ) );
231
- $job_object->job[ 'dropboxtoken' ] = $dropbox->token_from_oauth1();
232
- BackWPup_Option::update( $job_object->job[ 'jobid' ], 'dropboxtoken', $job_object->job[ 'dropboxtoken' ] );
233
- BackWPup_Option::delete( $job_object->job[ 'jobid' ], 'dropboxsecret' );
 
 
 
234
  }
235
  // set the tokens
236
- $dropbox->setOAuthTokens( $job_object->job[ 'dropboxtoken' ] );
237
 
238
  //get account info
239
- if ( $job_object->steps_data[ $job_object->step_working ]['SAVE_STEP_TRY'] != $job_object->steps_data[ $job_object->step_working ][ 'STEP_TRY' ] ) {
240
  $info = $dropbox->accountInfo();
241
- if ( ! empty( $info[ 'uid' ] ) ) {
242
  if ( $job_object->is_debug() ) {
243
- $user = $info[ 'display_name' ] . ' (' . $info[ 'email' ] . ')';
244
  } else {
245
- $user = $info[ 'display_name' ];
246
  }
247
  $job_object->log( sprintf( __( 'Authenticated with Dropbox of user: %s', 'backwpup' ), $user ) );
248
  //Quota
249
  if ( $job_object->is_debug() ) {
250
- $dropboxfreespase = $info[ 'quota_info' ][ 'quota' ] - $info[ 'quota_info' ][ 'shared' ] - $info[ 'quota_info' ][ 'normal' ];
251
  $job_object->log( sprintf( __( '%s available on your Dropbox', 'backwpup' ), size_format( $dropboxfreespase, 2 ) ) );
252
  }
253
  } else {
254
  $job_object->log( __( 'Not Authenticated with Dropbox!', 'backwpup' ), E_USER_ERROR );
255
- return FALSE;
 
256
  }
257
  $job_object->log( __( 'Uploading to Dropbox&#160;&hellip;', 'backwpup' ) );
258
  }
@@ -261,24 +305,25 @@ class BackWPup_Destination_Dropbox extends BackWPup_Destinations {
261
  self::$backwpup_job_object = &$job_object;
262
 
263
  if ( $job_object->substeps_done < $job_object->backup_filesize ) { //only if upload not complete
264
- $response = $dropbox->upload( $job_object->backup_folder . $job_object->backup_file, $job_object->job[ 'dropboxdir' ] . $job_object->backup_file );
265
- if ( $response[ 'bytes' ] == $job_object->backup_filesize ) {
266
- if ( ! empty( $job_object->job[ 'jobid' ] ) )
267
- BackWPup_Option::update( $job_object->job[ 'jobid' ], 'lastbackupdownloadurl', network_admin_url( 'admin.php' ) . '?page=backwpupbackups&action=downloaddropbox&file=' . ltrim( $response[ 'path' ], '/' ) . '&jobid=' . $job_object->job[ 'jobid' ] );
 
268
  $job_object->substeps_done = 1 + $job_object->backup_filesize;
269
- $job_object->log( sprintf( __( 'Backup transferred to %s', 'backwpup' ), 'https://api-content.dropbox.com/1/files/' . $job_object->job[ 'dropboxroot' ] . $response[ 'path' ] ), E_USER_NOTICE );
270
- }
271
- else {
272
- if ( $response[ 'bytes' ] != $job_object->backup_filesize )
273
  $job_object->log( __( 'Uploaded file size and local file size don\'t match.', 'backwpup' ), E_USER_ERROR );
274
- else
275
  $job_object->log(
276
- sprintf(
277
- __( 'Error transfering backup to %s.', 'backwpup' ) . ' ' . $response[ 'error' ],
278
- __( 'Dropbox', 'backwpup' )
279
- ), E_USER_ERROR );
 
280
 
281
- return FALSE;
282
  }
283
  }
284
 
@@ -286,68 +331,72 @@ class BackWPup_Destination_Dropbox extends BackWPup_Destinations {
286
  $backupfilelist = array();
287
  $filecounter = 0;
288
  $files = array();
289
- $metadata = $dropbox->metadata( $job_object->job[ 'dropboxdir' ] );
290
  if ( is_array( $metadata ) ) {
291
- foreach ( $metadata[ 'contents' ] as $data ) {
292
- if ( $data[ 'is_dir' ] != TRUE ) {
293
- $file = basename( $data[ 'path' ] );
294
  if ( $job_object->is_backup_archive( $file ) ) {
295
- $backupfilelist[ strtotime( $data[ 'modified' ] ) ] = $file;
296
  }
297
- $files[ $filecounter ][ 'folder' ] = "https://api-content.dropbox.com/1/files/" . $job_object->job[ 'dropboxroot' ] . dirname( $data[ 'path' ] ) . "/";
298
- $files[ $filecounter ][ 'file' ] = $data[ 'path' ];
299
- $files[ $filecounter ][ 'filename' ] = basename( $data[ 'path' ] );
300
- $files[ $filecounter ][ 'downloadurl' ] = network_admin_url( 'admin.php' ) . '?page=backwpupbackups&action=downloaddropbox&file=' . $data[ 'path' ] . '&jobid=' . $job_object->job[ 'jobid' ];
301
- $files[ $filecounter ][ 'filesize' ] = $data[ 'bytes' ];
302
- $files[ $filecounter ][ 'time' ] = strtotime( $data[ 'modified' ] ) + ( get_option( 'gmt_offset' ) * 3600 );
303
  $filecounter ++;
304
  }
305
  }
306
  }
307
- if ( $job_object->job[ 'dropboxmaxbackups' ] > 0 && is_object( $dropbox ) ) { //Delete old backups
308
- if ( count( $backupfilelist ) > $job_object->job[ 'dropboxmaxbackups' ] ) {
309
  ksort( $backupfilelist );
310
  $numdeltefiles = 0;
311
  while ( $file = array_shift( $backupfilelist ) ) {
312
- if ( count( $backupfilelist ) < $job_object->job[ 'dropboxmaxbackups' ] )
313
  break;
314
- $response = $dropbox->fileopsDelete( $job_object->job[ 'dropboxdir' ] . $file ); //delete files on Cloud
315
- if ( $response[ 'is_deleted' ] == 'true' ) {
 
316
  foreach ( $files as $key => $filedata ) {
317
- if ( $filedata[ 'file' ] == '/' .$job_object->job[ 'dropboxdir' ] . $file )
318
  unset( $files[ $key ] );
 
319
  }
320
  $numdeltefiles ++;
321
- }
322
- else
323
  $job_object->log( sprintf( __( 'Error while deleting file from Dropbox: %s', 'backwpup' ), $file ), E_USER_ERROR );
 
324
  }
325
- if ( $numdeltefiles > 0 )
326
  $job_object->log( sprintf( _n( 'One file deleted from Dropbox', '%d files deleted on Dropbox', $numdeltefiles, 'backwpup' ), $numdeltefiles ), E_USER_NOTICE );
 
327
  }
328
  }
329
- set_site_transient( 'backwpup_' . $job_object->job[ 'jobid' ] . '_dropbox', $files, 60 * 60 * 24 * 7 );
330
- }
331
- catch ( Exception $e ) {
332
  $job_object->log( E_USER_ERROR, sprintf( __( 'Dropbox API: %s', 'backwpup' ), $e->getMessage() ), $e->getFile(), $e->getLine() );
333
 
334
- return FALSE;
335
  }
336
  $job_object->substeps_done ++;
337
 
338
- return TRUE;
339
  }
340
 
341
  /**
342
  * @param $job_settings
 
343
  * @return bool
344
  */
345
  public function can_run( array $job_settings ) {
346
 
347
- if ( empty( $job_settings[ 'dropboxtoken' ] ) )
348
- return FALSE;
 
349
 
350
- return TRUE;
351
  }
352
 
353
  }
@@ -361,17 +410,17 @@ final class BackWPup_Destination_Dropbox_API {
361
  /**
362
  *
363
  */
364
- const API_URL = 'https://api.dropbox.com/';
365
 
366
  /**
367
  *
368
  */
369
- const API_CONTENT_URL = 'https://api-content.dropbox.com/';
370
 
371
  /**
372
  *
373
  */
374
- const API_WWW_URL = 'https://www.dropbox.com/';
375
 
376
  /**
377
  *
@@ -402,41 +451,43 @@ final class BackWPup_Destination_Dropbox_API {
402
  private $oauth_token = '';
403
 
404
 
405
-
406
  /**
407
  * @param string $boxtype
 
408
  * @throws BackWPup_Destination_Dropbox_API_Exception
409
  */
410
  public function __construct( $boxtype = 'dropbox' ) {
411
 
412
  if ( $boxtype == 'dropbox' ) {
413
- $this->oauth_app_key = get_site_option( 'backwpup_cfg_dropboxappkey', base64_decode( "dHZkcjk1MnRhZnM1NmZ2" ) );
414
  $this->oauth_app_secret = BackWPup_Encryption::decrypt( get_site_option( 'backwpup_cfg_dropboxappsecret', base64_decode( "OWV2bDR5MHJvZ2RlYmx1" ) ) );
415
  $this->root = 'dropbox';
416
- }
417
- else {
418
- $this->oauth_app_key = get_site_option( 'backwpup_cfg_dropboxsandboxappkey', base64_decode( "cHVrZmp1a3JoZHR5OTFk" ) );
419
  $this->oauth_app_secret = BackWPup_Encryption::decrypt( get_site_option( 'backwpup_cfg_dropboxsandboxappsecret', base64_decode( "eGNoYzhxdTk5eHE0eWdq" ) ) );
420
  $this->root = 'sandbox';
421
  }
422
 
423
- if ( empty( $this->oauth_app_key ) || empty( $this->oauth_app_secret ) )
424
  throw new BackWPup_Destination_Dropbox_API_Exception( "No App key or App Secret specified." );
 
425
  }
426
 
427
  /**
428
  * @param $token
 
429
  * @throws BackWPup_Destination_Dropbox_API_Exception
430
  */
431
  public function setOAuthTokens( $token ) {
432
 
433
- if ( empty( $token[ 'access_token' ] ) )
434
  throw new BackWPup_Destination_Dropbox_API_Exception( "No oAuth token specified." );
 
435
 
436
  $this->oauth_token = $token;
437
  }
438
 
439
- public function token_from_oauth1( ) {
440
 
441
  $url = self::API_URL . self::API_VERSION_URL . 'oauth2/token_from_oauth1';
442
 
@@ -463,11 +514,12 @@ final class BackWPup_Destination_Dropbox_API {
463
  /**
464
  * @param $file
465
  * @param string $path
466
- * @param bool $overwrite
 
467
  * @return array|mixed|string
468
  * @throws BackWPup_Destination_Dropbox_API_Exception
469
  */
470
- public function upload( $file, $path = '', $overwrite = TRUE ) {
471
 
472
  $file = str_replace( "\\", "/", $file );
473
 
@@ -476,10 +528,9 @@ final class BackWPup_Destination_Dropbox_API {
476
  }
477
 
478
  if ( filesize( $file ) < 5242880 ) { //chunk transfer on bigger uploads
479
- $url = self::API_CONTENT_URL . self::API_VERSION_URL . 'files_put/' . $this->root . '/' . $this->encode_path( $path );
480
- $output = $this->request( $url, array( 'overwrite' => ( $overwrite ) ? 'true' : 'false' ), 'PUT', file_get_contents( $file ) );
481
- }
482
- else {
483
  $output = $this->chunked_upload( $file, $path, $overwrite );
484
  }
485
 
@@ -489,11 +540,12 @@ final class BackWPup_Destination_Dropbox_API {
489
  /**
490
  * @param $file
491
  * @param string $path
492
- * @param bool $overwrite
 
493
  * @return array|mixed|string
494
  * @throws BackWPup_Destination_Dropbox_API_Exception
495
  */
496
- public function chunked_upload( $file, $path = '', $overwrite = TRUE ) {
497
 
498
  $backwpup_job_object = BackWPup_Destination_Dropbox::$backwpup_job_object;
499
 
@@ -510,33 +562,36 @@ final class BackWPup_Destination_Dropbox_API {
510
  throw new BackWPup_Destination_Dropbox_API_Exception( "Can not open source file for transfer." );
511
  }
512
 
513
- if ( ! isset( $backwpup_job_object->steps_data[ $backwpup_job_object->step_working ][ 'uploadid' ] ) ) {
514
- $backwpup_job_object->steps_data[ $backwpup_job_object->step_working ][ 'uploadid' ] = NULL;
515
  }
516
- if ( ! isset( $backwpup_job_object->steps_data[ $backwpup_job_object->step_working ][ 'offset' ] ) ) {
517
- $backwpup_job_object->steps_data[ $backwpup_job_object->step_working ][ 'offset' ] = 0;
518
  }
519
 
520
  //seek to current position
521
- if ( $backwpup_job_object->steps_data[ $backwpup_job_object->step_working ][ 'offset' ] > 0 ) {
522
- fseek( $file_handel, $backwpup_job_object->steps_data[ $backwpup_job_object->step_working ][ 'offset' ] );
523
  }
524
 
525
  while ( $data = fread( $file_handel, $chunk_size ) ) {
526
- $chunk_upload_start = microtime( TRUE );
527
- $url = self::API_CONTENT_URL . self::API_VERSION_URL . 'chunked_upload';
528
- $output = $this->request( $url, array( 'upload_id' => $backwpup_job_object->steps_data[ $backwpup_job_object->step_working ][ 'uploadid' ], 'offset' => $backwpup_job_object->steps_data[ $backwpup_job_object->step_working ][ 'offset' ] ), 'PUT', $data );
529
- $chunk_upload_time = microtime( TRUE ) - $chunk_upload_start;
 
 
 
530
  //args for next chunk
531
- $backwpup_job_object->steps_data[ $backwpup_job_object->step_working ][ 'offset' ] = $output[ 'offset' ];
532
- $backwpup_job_object->steps_data[ $backwpup_job_object->step_working ][ 'uploadid' ] = $output[ 'upload_id' ];
533
- if ( $backwpup_job_object->job[ 'backuptype' ] == 'archive' ) {
534
- $backwpup_job_object->substeps_done = $backwpup_job_object->steps_data[ $backwpup_job_object->step_working ][ 'offset' ];
535
  if ( strlen( $data ) == $chunk_size ) {
536
  $time_remaining = $backwpup_job_object->do_restart_time();
537
  //calc next chunk
538
  if ( $time_remaining < $chunk_upload_time ) {
539
- $chunk_size = floor ( $chunk_size / $chunk_upload_time * ( $time_remaining - 3 ) );
540
  if ( $chunk_size < 0 ) {
541
  $chunk_size = 1024;
542
  }
@@ -548,52 +603,64 @@ final class BackWPup_Destination_Dropbox_API {
548
  }
549
  $backwpup_job_object->update_working_data();
550
  //correct position
551
- fseek( $file_handel, $backwpup_job_object->steps_data[ $backwpup_job_object->step_working ][ 'offset' ] );
552
  }
553
 
554
  fclose( $file_handel );
555
 
556
  $url = self::API_CONTENT_URL . self::API_VERSION_URL . 'commit_chunked_upload/' . $this->root . '/' . $this->encode_path( $path );
557
 
558
- return $this->request( $url, array( 'overwrite' => ( $overwrite ) ? 'true' : 'false', 'upload_id' => $backwpup_job_object->steps_data[ $backwpup_job_object->step_working ][ 'uploadid' ] ), 'POST' );
 
 
 
 
 
 
 
 
559
  }
560
 
561
  /**
562
  * @param $path
563
  * @param bool $echo
 
564
  * @return string
565
  */
566
- public function download( $path, $echo = FALSE ) {
567
 
568
- $url = self::API_CONTENT_URL . self::API_VERSION_URL . 'files/' . $this->root . '/' . $path;
569
- if ( ! $echo )
570
  return $this->request( $url );
571
- else {
572
- $this->request( $url, NULL, 'GET', '', TRUE );
 
573
  return '';
574
  }
575
  }
576
 
577
  /**
578
  * @param string $path
579
- * @param bool $listContents
580
- * @param int $fileLimit
581
  * @param string $hash
 
582
  * @return array|mixed|string
583
  */
584
- public function metadata( $path = '', $listContents = TRUE, $fileLimit = 10000, $hash = '' ) {
585
 
586
  $url = self::API_URL . self::API_VERSION_URL . 'metadata/' . $this->root . '/' . $this->encode_path( $path );
587
 
588
  return $this->request( $url, array(
589
- 'list' => ( $listContents ) ? 'true' : 'false',
590
- 'hash' => ( $hash ) ? $hash : '',
591
- 'file_limit' => $fileLimit
592
- ) );
593
  }
594
 
595
  /**
596
  * @param string $path
 
597
  * @return array|mixed|string
598
  */
599
  public function media( $path = '' ) {
@@ -605,6 +672,7 @@ final class BackWPup_Destination_Dropbox_API {
605
 
606
  /**
607
  * @param $path
 
608
  * @return array|mixed|string
609
  */
610
  public function fileopsDelete( $path ) {
@@ -612,12 +680,12 @@ final class BackWPup_Destination_Dropbox_API {
612
  $url = self::API_URL . self::API_VERSION_URL . 'fileops/delete';
613
 
614
  return $this->request( $url, array(
615
- 'path' => '/' . $path,
616
- 'root' => $this->root
617
- ) );
618
  }
619
 
620
- public function oAuthAuthorize( ) {
621
 
622
  return self::API_WWW_URL . self::API_VERSION_URL . 'oauth2/authorize?response_type=code&client_id=' . $this->oauth_app_key;
623
  }
@@ -628,113 +696,115 @@ final class BackWPup_Destination_Dropbox_API {
628
  $url = self::API_URL . self::API_VERSION_URL . 'oauth2/token';
629
 
630
  return $this->request( $url, array(
631
- 'code' => trim( $code ),
632
- 'grant_type' => 'authorization_code',
633
- 'client_id' => $this->oauth_app_key,
634
- 'client_secret' => $this->oauth_app_secret
635
- ), 'POST' );
636
 
637
  }
638
 
639
 
640
  /**
641
  * @param $url
642
- * @param array $args
643
  * @param string $method
644
  * @param string $data
645
- * @param bool $echo
646
  *
647
  * @throws BackWPup_Destination_Dropbox_API_Exception
648
  * @internal param null $file
649
  * @return array|mixed|string
650
  */
651
- private function request( $url, $args = array(), $method = 'GET', $data = '', $echo = FALSE ) {
652
 
653
  /* Header*/
654
  // oAuth 2
655
- if ( ! empty( $this->oauth_token[ 'access_token' ] ) && ! empty( $this->oauth_token[ 'token_type' ] ) && strtolower( $this->oauth_token[ 'token_type' ] ) == 'bearer' )
656
- $headers[ ] = 'Authorization: Bearer ' . $this->oauth_token[ 'access_token' ] ;
657
- // oAuth 1
658
- elseif ( ! empty( $this->oauth_token[ 'access_token' ] ) && ! empty( $this->oauth_token[ 'oauth_token_secret' ] ) )
659
- $headers[ ] = 'Authorization: OAuth oauth_version="1.0", oauth_signature_method="PLAINTEXT", oauth_consumer_key="' . $this->oauth_app_key . '", oauth_token="' . $this->oauth_token[ 'access_token' ] . '", oauth_signature="' . $this->oauth_app_secret . '&' . $this->oauth_token[ 'oauth_token_secret' ] . '"';
 
660
 
661
- $headers[ ] = 'Expect:';
662
 
663
  /* Build cURL Request */
664
  $ch = curl_init();
665
  if ( $method == 'POST' ) {
666
- curl_setopt( $ch, CURLOPT_POST, TRUE );
667
  curl_setopt( $ch, CURLOPT_POSTFIELDS, $args );
668
  curl_setopt( $ch, CURLOPT_URL, $url );
669
- }
670
- elseif ( $method == 'PUT' ) {
671
  curl_setopt( $ch, CURLOPT_CUSTOMREQUEST, 'PUT' );
672
  curl_setopt( $ch, CURLOPT_POSTFIELDS, $data );
673
- $headers[ ] = 'Content-Type: application/octet-stream';
674
- $args = ( is_array( $args ) ) ? '?' . http_build_query( $args, '', '&' ) : $args;
675
  curl_setopt( $ch, CURLOPT_URL, $url . $args );
676
- }
677
- else {
678
- curl_setopt( $ch, CURLOPT_BINARYTRANSFER, TRUE );
679
  $args = ( is_array( $args ) ) ? '?' . http_build_query( $args, '', '&' ) : $args;
680
  curl_setopt( $ch, CURLOPT_URL, $url . $args );
681
  }
682
  curl_setopt( $ch, CURLOPT_USERAGENT, BackWPup::get_plugin_data( 'User-Agent' ) );
683
- curl_setopt( $ch, CURLOPT_RETURNTRANSFER, TRUE );
684
  if ( BackWPup::get_plugin_data( 'cacert' ) ) {
685
  curl_setopt( $ch, CURLOPT_SSLVERSION, 1 );
686
- curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, TRUE );
687
  $curl_version = curl_version();
688
- if ( strstr( $curl_version[ 'ssl_version' ], 'NSS/' ) === FALSE ) {
689
  curl_setopt( $ch, CURLOPT_SSL_CIPHER_LIST,
690
- 'ECDHE-RSA-AES256-GCM-SHA384:'.
691
- 'ECDHE-RSA-AES128-GCM-SHA256:'.
692
- 'ECDHE-RSA-AES256-SHA384:'.
693
- 'ECDHE-RSA-AES128-SHA256:'.
694
- 'ECDHE-RSA-AES256-SHA:'.
695
- 'ECDHE-RSA-AES128-SHA:'.
696
- 'ECDHE-RSA-RC4-SHA:'.
697
- 'DHE-RSA-AES256-GCM-SHA384:'.
698
- 'DHE-RSA-AES128-GCM-SHA256:'.
699
- 'DHE-RSA-AES256-SHA256:'.
700
- 'DHE-RSA-AES128-SHA256:'.
701
- 'DHE-RSA-AES256-SHA:'.
702
- 'DHE-RSA-AES128-SHA:'.
703
- 'AES256-GCM-SHA384:'.
704
- 'AES128-GCM-SHA256:'.
705
- 'AES256-SHA256:'.
706
- 'AES128-SHA256:'.
707
- 'AES256-SHA:'.
708
- 'AES128-SHA'
709
  );
710
  }
711
- if ( defined( 'CURLOPT_PROTOCOLS' ) )
712
  curl_setopt( $ch, CURLOPT_PROTOCOLS, CURLPROTO_HTTPS );
713
- if ( defined( 'CURLOPT_REDIR_PROTOCOLS' ) )
 
714
  curl_setopt( $ch, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTPS );
 
715
  curl_setopt( $ch, CURLOPT_CAINFO, BackWPup::get_plugin_data( 'cacert' ) );
716
  curl_setopt( $ch, CURLOPT_CAPATH, dirname( BackWPup::get_plugin_data( 'cacert' ) ) );
717
  } else {
718
- curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, FALSE );
719
  }
720
  curl_setopt( $ch, CURLOPT_HTTPHEADER, $headers );
721
  $output = '';
722
  if ( $echo ) {
723
  echo curl_exec( $ch );
724
- }
725
- else {
726
- curl_setopt( $ch, CURLOPT_HEADER, TRUE );
727
  if ( 0 == curl_errno( $ch ) ) {
728
  $responce = explode( "\r\n\r\n", curl_exec( $ch ), 2 );
729
- if ( ! empty( $responce[ 1 ] ) )
730
- $output = json_decode( $responce[ 1 ], TRUE );
 
731
  }
732
  }
733
  $status = curl_getinfo( $ch );
734
- if ( $status[ 'http_code' ] == 503 ) {
735
  $wait = 0;
736
- if ( preg_match( "/retry-after:(.*?)\r/i", $responce[ 0 ], $matches ) )
737
- $wait = trim( $matches[ 1 ] );
 
738
  //only wait if we get a retry-after header.
739
  if ( ! empty( $wait ) ) {
740
  trigger_error( sprintf( '(503) Your app is making too many requests and is being rate limited. Error 503 can be triggered on a per-app or per-user basis. Wait for %d seconds.', $wait ), E_USER_WARNING );
@@ -742,42 +812,57 @@ final class BackWPup_Destination_Dropbox_API {
742
  } else {
743
  throw new BackWPup_Destination_Dropbox_API_Exception( '(503) This indicates a transient server error.' );
744
  }
 
745
  //redo request
746
  return $this->request( $url, $args, $method, $data, $echo );
747
- }
748
- elseif ( $status[ 'http_code' ] == 400 && $method == 'PUT' ) { //correct offset on chunk uploads
749
- trigger_error( '(' . $status[ 'http_code' ] . ') False offset will corrected', E_USER_NOTICE );
750
- return $output;
751
- }
752
- elseif ( $status[ 'http_code' ] == 404 && ! empty( $output[ 'error' ] )) {
753
- trigger_error( '(' . $status[ 'http_code' ] . ') ' . $output[ 'error' ], E_USER_WARNING );
754
 
755
- return FALSE;
756
- }
757
- elseif ( isset( $output[ 'error' ] ) || $status[ 'http_code' ] >= 300 || $status[ 'http_code' ] < 200 || curl_errno( $ch ) > 0 ) {
758
- if ( isset( $output[ 'error' ] ) && is_string( $output[ 'error' ] ) ) $message = '(' . $status[ 'http_code' ] . ') ' . $output[ 'error' ];
759
- elseif ( isset( $output[ 'error' ][ 'hash' ] ) && $output[ 'error' ][ 'hash' ] != '' ) $message = (string)'(' . $status[ 'http_code' ] . ') ' . $output[ 'error' ][ 'hash' ];
760
- elseif ( 0 != curl_errno( $ch ) ) $message = '(' . curl_errno( $ch ) . ') ' . curl_error( $ch );
761
- elseif ( $status[ 'http_code' ] == 304 ) $message = '(304) Folder contents have not changed (relies on hash parameter).';
762
- elseif ( $status[ 'http_code' ] == 400 ) $message = '(400) Bad input parameter: ' . strip_tags( $responce[ 1 ] );
763
- elseif ( $status[ 'http_code' ] == 401 ) $message = '(401) Bad or expired token. This can happen if the user or Dropbox revoked or expired an access token. To fix, you should re-authenticate the user.';
764
- elseif ( $status[ 'http_code' ] == 403 ) $message = '(403) Bad OAuth request (wrong consumer key, bad nonce, expired timestamp...). Unfortunately, re-authenticating the user won\'t help here.';
765
- elseif ( $status[ 'http_code' ] == 404 ) $message = '(404) File or folder not found at the specified path.';
766
- elseif ( $status[ 'http_code' ] == 405 ) $message = '(405) Request method not expected (generally should be GET or POST).';
767
- elseif ( $status[ 'http_code' ] == 406 ) $message = '(406) There are too many file entries to return.';
768
- elseif ( $status[ 'http_code' ] == 411 ) $message = '(411) Missing Content-Length header (this endpoint doesn\'t support HTTP chunked transfer encoding).';
769
- elseif ( $status[ 'http_code' ] == 415 ) $message = '(415) The image is invalid and cannot be converted to a thumbnail.';
770
- elseif ( $status[ 'http_code' ] == 429 ) $message = '(429) Your app is making too many requests and is being rate limited. 429s can trigger on a per-app or per-user basis.';
771
- elseif ( $status[ 'http_code' ] == 507 ) $message = '(507) User is over Dropbox storage quota.';
772
- else $message = '(' . $status[ 'http_code' ] . ') Invalid response.';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
773
  throw new BackWPup_Destination_Dropbox_API_Exception( $message );
774
- }
775
- else {
776
  curl_close( $ch );
777
- if ( ! is_array( $output ) )
778
- return $responce[ 1 ];
779
- else
780
  return $output;
 
781
  }
782
  }
783
 
1
  <?php
2
+
3
  /**
4
  * Documentation: https://www.dropbox.com/developers/reference/api
5
  */
8
  /**
9
  * @var $backwpup_job_object BackWPup_Job
10
  */
11
+ public static $backwpup_job_object = null;
12
 
13
  /**
14
  * @return array
15
  */
16
  public function option_defaults() {
17
 
18
+ return array(
19
+ 'dropboxtoken' => array(),
20
+ 'dropboxroot' => 'sandbox',
21
+ 'dropboxmaxbackups' => 15,
22
+ 'dropboxsyncnodelete' => true,
23
+ 'dropboxdir' => trailingslashit( sanitize_file_name( get_bloginfo( 'name' ) ) )
24
+ );
25
  }
26
 
27
 
30
  */
31
  public function edit_tab( $jobid ) {
32
 
33
+ if ( ! empty( $_GET['deleteauth'] ) && $_GET['deleteauth'] == 1 ) {
34
  //disable token on dropbox
35
  try {
36
  $dropbox = new BackWPup_Destination_Dropbox_API( BackWPup_Option::get( $jobid, 'dropboxroot' ) );
37
+ if ( BackWPup_Option::get( $jobid, 'dropboxsecret' ) ) {
38
+ $dropbox->setOAuthTokens( array(
39
+ 'access_token' => BackWPup_Option::get( $jobid, 'dropboxtoken' ),
40
+ 'oauth_token_secret' => BackWPup_Encryption::decrypt( BackWPup_Option::get( $jobid, 'dropboxsecret' ) )
41
+ ) );
42
+ } else {
43
  $dropbox->setOAuthTokens( BackWPup_Option::get( $jobid, 'dropboxtoken' ) );
44
+ }
45
  $dropbox->disable_access_token();
46
  } catch ( Exception $e ) {
47
  echo '<div id="message" class="error"><p>' . sprintf( __( 'Dropbox API: %s', 'backwpup' ), $e->getMessage() ) . '</p></div>';
51
  BackWPup_Option::delete( $jobid, 'dropboxsecret' );
52
  }
53
 
54
+ $dropbox = new BackWPup_Destination_Dropbox_API( 'dropbox' );
55
  $dropbox_auth_url = $dropbox->oAuthAuthorize();
56
+ $dropbox = new BackWPup_Destination_Dropbox_API( 'sandbox' );
57
  $sandbox_auth_url = $dropbox->oAuthAuthorize();
58
 
59
  $dropboxtoken = BackWPup_Option::get( $jobid, 'dropboxtoken' );
60
  ?>
61
 
62
+ <h3 class="title"><?php _e( 'Login', 'backwpup' ); ?></h3>
63
+ <p></p>
64
+ <table class="form-table">
65
+ <tr>
66
+ <th scope="row"><?php _e( 'Authentication', 'backwpup' ); ?></th>
67
+ <td><?php if ( empty( $dropboxtoken['access_token'] ) ) { ?>
68
+ <span style="color:red;"><?php _e( 'Not authenticated!', 'backwpup' ); ?></span><br/>&nbsp;<br/>
69
+ <a class="button secondary"
70
+ href="http://db.tt/8irM1vQ0"><?php _e( 'Create Account', 'backwpup' ); ?></a>
71
+ <?php } else { ?>
72
+ <span style="color:green;"><?php _e( 'Authenticated!', 'backwpup' ); ?></span><br/>&nbsp;<br/>
73
+ <a class="button secondary"
74
+ href="<?php echo network_admin_url( 'admin.php' ) . '?page=backwpupeditjob&deleteauth=1&jobid=' . $jobid . '&tab=dest-dropbox&_wpnonce=' . wp_create_nonce( 'edit-job' ); ?>"
75
+ title="<?php _e( 'Delete Dropbox Authentication', 'backwpup' ); ?>"><?php _e( 'Delete Dropbox Authentication', 'backwpup' ); ?></a>
76
+ <?php } ?>
77
+ </td>
78
+ </tr>
79
+
80
+ <?php if ( empty( $dropboxtoken['access_token'] ) ) { ?>
81
+ <tr>
82
+ <th scope="row"><label
83
+ for="id_sandbox_code"><?php _e( 'App Access to Dropbox', 'backwpup' ); ?></label></th>
84
+ <td>
85
+ <input id="id_sandbox_code" name="sandbox_code" type="text" value=""
86
+ class="regular-text code help-tip"
87
+ title="<?php esc_attr_e( 'A dedicated folder named BackWPup will be created inside of the Apps folder in your Dropbox. BackWPup will get read and write access to that folder only. You can specify a subfolder as your backup destination for this job in the destination field below.', 'backwpup' ); ?>"/>&nbsp;
88
+ <a class="button secondary" href="<?php echo $sandbox_auth_url; ?>"
89
+ target="_blank"><?php _e( 'Get Dropbox App auth code', 'backwpup' ); ?></a>
90
+ <p><em><?php _e( 'Allows restricted access to Apps/BackWPup folder only.', 'backwpup' ); ?></em>
91
+ </p>
92
+ </td>
93
+ </tr>
94
+ <tr>
95
+ <th></th>
96
+ <td><?php _e( '— OR —', 'backwpup' ); ?></td>
97
+ </tr>
98
+ <tr>
99
+ <th scope="row"><label
100
+ for="id_dropbbox_code"><?php _e( 'Full Access to Dropbox', 'backwpup' ); ?></label></th>
101
+ <td>
102
+ <input id="id_dropbbox_code" name="dropbbox_code" type="text" value=""
103
+ class="regular-text code help-tip"
104
+ title="<?php _e( 'BackWPup will have full read and write access to your entire Dropbox. You can specify your backup destination wherever you want, just be aware that ANY files or folders inside of your Dropbox can be overridden or deleted by BackWPup.', 'backwpup' ); ?>"/>&nbsp;
105
+ <a class="button secondary" href="<?php echo $dropbox_auth_url; ?>"
106
+ target="_blank"><?php _e( 'Get full Dropbox auth code ', 'backwpup' ); ?></a>
107
+ <p><em><?php _e( 'Allows full access to your entire Dropbox.', 'backwpup' ); ?></em></p>
108
+ </td>
109
+ </tr>
110
+ <?php } ?>
111
+ </table>
112
+
113
+
114
+ <h3 class="title"><?php _e( 'Backup settings', 'backwpup' ); ?></h3>
115
+ <p></p>
116
+ <table class="form-table">
117
+ <tr>
118
+ <th scope="row"><label for="iddropboxdir"><?php _e( 'Destination Folder', 'backwpup' ); ?></label></th>
119
+ <td>
120
+ <input id="iddropboxdir" name="dropboxdir" type="text"
121
+ value="<?php echo esc_attr( BackWPup_Option::get( $jobid, 'dropboxdir' ) ); ?>"
122
+ class="regular-text help-tip"
123
+ title="<?php esc_attr_e( 'Specify a subfolder where your backup archives will be stored. If you use the App option from above, this folder will be created inside of Apps/BackWPup. Otherwise it will be created at the root of your Dropbox. Already exisiting folders with the same name will not be overriden.', 'backwpup' ); ?>"/>
124
+ <p>
125
+ <em><?php _e( 'Folder inside your Dropbox where your backup archives will be stored.', 'backwpup' ); ?></em>
126
+ </p>
127
+ </td>
128
+ </tr>
129
+ <tr>
130
+ <th scope="row"><?php _e( 'File Deletion', 'backwpup' ); ?></th>
131
+ <td>
132
+ <?php
133
+ if ( BackWPup_Option::get( $jobid, 'backuptype' ) == 'archive' ) {
134
+ ?>
135
+ <label for="iddropboxmaxbackups"><input id="iddropboxmaxbackups" name="dropboxmaxbackups"
136
+ title="<?php esc_attr_e( 'Older files will be deleted first. 0 = no files will be deleted.', 'backwpup' ); ?>"
137
+ type="text" size="3"
138
+ value="<?php echo esc_attr( BackWPup_Option::get( $jobid, 'dropboxmaxbackups' ) ); ?>"
139
+ class="small-text help-tip"/>&nbsp;
140
+ <em><?php _e( 'Number of files to keep in folder.', 'backwpup' ); ?></em></label>
141
  <?php } else { ?>
142
+ <label for="iddropboxsyncnodelete"><input class="checkbox" value="1"
143
+ type="checkbox" <?php checked( BackWPup_Option::get( $jobid, 'dropboxsyncnodelete' ), true ); ?>
144
+ name="dropboxsyncnodelete"
145
+ id="iddropboxsyncnodelete"/> <?php _e( 'Do not delete files while syncing to destination!', 'backwpup' ); ?>
146
+ </label>
147
  <?php } ?>
148
+ </td>
149
+ </tr>
150
+ </table>
151
 
152
+ <?php
153
  }
154
 
155
  /**
156
  * @param $jobid
157
+ *
158
  * @return string|void
159
  */
160
  public function edit_form_post_save( $jobid ) {
161
 
162
  // get auth
163
+ if ( ! empty( $_POST['sandbox_code'] ) ) {
164
  try {
165
+ $dropbox = new BackWPup_Destination_Dropbox_API( 'sandbox' );
166
+ $dropboxtoken = $dropbox->oAuthToken( $_POST['sandbox_code'] );
167
  BackWPup_Option::update( $jobid, 'dropboxtoken', $dropboxtoken );
168
  BackWPup_Option::update( $jobid, 'dropboxroot', 'sandbox' );
169
  } catch ( Exception $e ) {
170
+ BackWPup_Admin::message( 'DROPBOX: ' . $e->getMessage(), true );
171
  }
172
  }
173
 
174
+ if ( ! empty( $_POST['dropbbox_code'] ) ) {
175
  try {
176
+ $dropbox = new BackWPup_Destination_Dropbox_API( 'dropbox' );
177
+ $dropboxtoken = $dropbox->oAuthToken( $_POST['dropbbox_code'] );
178
  BackWPup_Option::update( $jobid, 'dropboxtoken', $dropboxtoken );
179
  BackWPup_Option::update( $jobid, 'dropboxroot', 'dropbox' );
180
  } catch ( Exception $e ) {
181
+ BackWPup_Admin::message( 'DROPBOX: ' . $e->getMessage(), true );
182
  }
183
  }
184
 
185
+ BackWPup_Option::update( $jobid, 'dropboxsyncnodelete', ( isset( $_POST['dropboxsyncnodelete'] ) && $_POST['dropboxsyncnodelete'] == 1 ) ? true : false );
186
+ BackWPup_Option::update( $jobid, 'dropboxmaxbackups', isset( $_POST['dropboxmaxbackups'] ) ? (int) $_POST['dropboxmaxbackups'] : 0 );
187
 
188
+ $_POST['dropboxdir'] = trailingslashit( str_replace( '//', '/', str_replace( '\\', '/', trim( stripslashes( $_POST['dropboxdir'] ) ) ) ) );
189
+ if ( substr( $_POST['dropboxdir'], 0, 1 ) == '/' ) {
190
+ $_POST['dropboxdir'] = substr( $_POST['dropboxdir'], 1 );
191
+ }
192
+ if ( $_POST['dropboxdir'] == '/' ) {
193
+ $_POST['dropboxdir'] = '';
194
+ }
195
+ BackWPup_Option::update( $jobid, 'dropboxdir', $_POST['dropboxdir'] );
196
 
197
  }
198
 
211
  $dropbox->fileopsDelete( $backupfile );
212
  //update file list
213
  foreach ( $files as $key => $file ) {
214
+ if ( is_array( $file ) && $file['file'] == $backupfile ) {
215
  unset( $files[ $key ] );
216
+ }
217
  }
218
  unset( $dropbox );
219
+ } catch ( Exception $e ) {
220
+ BackWPup_Admin::message( 'DROPBOX: ' . $e->getMessage(), true );
 
221
  }
222
 
223
  set_site_transient( 'backwpup_' . strtolower( $jobdest ), $files, 3600 * 24 * 7 );
233
  $dropbox = new BackWPup_Destination_Dropbox_API( BackWPup_Option::get( $jobid, 'dropboxroot' ) );
234
  $dropbox->setOAuthTokens( BackWPup_Option::get( $jobid, 'dropboxtoken' ) );
235
  $media = $dropbox->media( $get_file );
236
+ if ( ! empty( $media['url'] ) ) {
237
+ header( "Location: " . $media['url'] );
238
+ }
239
  die();
240
+ } catch ( Exception $e ) {
 
241
  die( $e->getMessage() );
242
  }
243
  }
244
 
245
  /**
246
  * @param $jobdest
247
+ *
248
  * @return mixed
249
  */
250
  public function file_get_list( $jobdest ) {
253
 
254
  /**
255
  * @param $job_object
256
+ *
257
  * @return bool
258
  */
259
  public function job_run_archive( BackWPup_Job $job_object ) {
260
 
261
  $job_object->substeps_todo = 2 + $job_object->backup_filesize;
262
+ if ( $job_object->steps_data[ $job_object->step_working ]['SAVE_STEP_TRY'] != $job_object->steps_data[ $job_object->step_working ]['STEP_TRY'] ) {
263
+ $job_object->log( sprintf( __( '%d. Try to send backup file to Dropbox&#160;&hellip;', 'backwpup' ), $job_object->steps_data[ $job_object->step_working ]['STEP_TRY'] ) );
264
+ }
265
 
266
  try {
267
+ $dropbox = new BackWPup_Destination_Dropbox_API( $job_object->job['dropboxroot'] );
268
  // cahnge oauth1 to oauth2 token
269
+ if ( ! empty( $job_object->job['dropboxsecret'] ) && empty( $job_object->job['dropboxtoken']['access_token'] ) ) {
270
+ $dropbox->setOAuthTokens( array(
271
+ 'access_token' => $job_object->job['dropboxtoken'],
272
+ 'oauth_token_secret' => BackWPup_Encryption::decrypt( $job_object->job['dropboxsecret'] )
273
+ ) );
274
+ $job_object->job['dropboxtoken'] = $dropbox->token_from_oauth1();
275
+ BackWPup_Option::update( $job_object->job['jobid'], 'dropboxtoken', $job_object->job['dropboxtoken'] );
276
+ BackWPup_Option::delete( $job_object->job['jobid'], 'dropboxsecret' );
277
  }
278
  // set the tokens
279
+ $dropbox->setOAuthTokens( $job_object->job['dropboxtoken'] );
280
 
281
  //get account info
282
+ if ( $job_object->steps_data[ $job_object->step_working ]['SAVE_STEP_TRY'] != $job_object->steps_data[ $job_object->step_working ]['STEP_TRY'] ) {
283
  $info = $dropbox->accountInfo();
284
+ if ( ! empty( $info['uid'] ) ) {
285
  if ( $job_object->is_debug() ) {
286
+ $user = $info['display_name'] . ' (' . $info['email'] . ')';
287
  } else {
288
+ $user = $info['display_name'];
289
  }
290
  $job_object->log( sprintf( __( 'Authenticated with Dropbox of user: %s', 'backwpup' ), $user ) );
291
  //Quota
292
  if ( $job_object->is_debug() ) {
293
+ $dropboxfreespase = $info['quota_info']['quota'] - $info['quota_info']['shared'] - $info['quota_info']['normal'];
294
  $job_object->log( sprintf( __( '%s available on your Dropbox', 'backwpup' ), size_format( $dropboxfreespase, 2 ) ) );
295
  }
296
  } else {
297
  $job_object->log( __( 'Not Authenticated with Dropbox!', 'backwpup' ), E_USER_ERROR );
298
+
299
+ return false;
300
  }
301
  $job_object->log( __( 'Uploading to Dropbox&#160;&hellip;', 'backwpup' ) );
302
  }
305
  self::$backwpup_job_object = &$job_object;
306
 
307
  if ( $job_object->substeps_done < $job_object->backup_filesize ) { //only if upload not complete
308
+ $response = $dropbox->upload( $job_object->backup_folder . $job_object->backup_file, $job_object->job['dropboxdir'] . $job_object->backup_file );
309
+ if ( $response['bytes'] == $job_object->backup_filesize ) {
310
+ if ( ! empty( $job_object->job['jobid'] ) ) {
311
+ BackWPup_Option::update( $job_object->job['jobid'], 'lastbackupdownloadurl', network_admin_url( 'admin.php' ) . '?page=backwpupbackups&action=downloaddropbox&file=' . ltrim( $response['path'], '/' ) . '&jobid=' . $job_object->job['jobid'] );
312
+ }
313
  $job_object->substeps_done = 1 + $job_object->backup_filesize;
314
+ $job_object->log( sprintf( __( 'Backup transferred to %s', 'backwpup' ), 'https://content.dropboxapi.com/1/files/' . $job_object->job['dropboxroot'] . $response['path'] ), E_USER_NOTICE );
315
+ } else {
316
+ if ( $response['bytes'] != $job_object->backup_filesize ) {
 
317
  $job_object->log( __( 'Uploaded file size and local file size don\'t match.', 'backwpup' ), E_USER_ERROR );
318
+ } else {
319
  $job_object->log(
320
+ sprintf(
321
+ __( 'Error transfering backup to %s.', 'backwpup' ) . ' ' . $response['error'],
322
+ __( 'Dropbox', 'backwpup' )
323
+ ), E_USER_ERROR );
324
+ }
325
 
326
+ return false;
327
  }
328
  }
329
 
331
  $backupfilelist = array();
332
  $filecounter = 0;
333
  $files = array();
334
+ $metadata = $dropbox->metadata( $job_object->job['dropboxdir'] );
335
  if ( is_array( $metadata ) ) {
336
+ foreach ( $metadata['contents'] as $data ) {
337
+ if ( $data['is_dir'] != true ) {
338
+ $file = basename( $data['path'] );
339
  if ( $job_object->is_backup_archive( $file ) ) {
340
+ $backupfilelist[ strtotime( $data['modified'] ) ] = $file;
341
  }
342
+ $files[ $filecounter ]['folder'] = "https://content.dropboxapi.com/1/files/" . $job_object->job['dropboxroot'] . dirname( $data['path'] ) . "/";
343
+ $files[ $filecounter ]['file'] = $data['path'];
344
+ $files[ $filecounter ]['filename'] = basename( $data['path'] );
345
+ $files[ $filecounter ]['downloadurl'] = network_admin_url( 'admin.php' ) . '?page=backwpupbackups&action=downloaddropbox&file=' . $data['path'] . '&jobid=' . $job_object->job['jobid'];
346
+ $files[ $filecounter ]['filesize'] = $data['bytes'];
347
+ $files[ $filecounter ]['time'] = strtotime( $data['modified'] ) + ( get_option( 'gmt_offset' ) * 3600 );
348
  $filecounter ++;
349
  }
350
  }
351
  }
352
+ if ( $job_object->job['dropboxmaxbackups'] > 0 && is_object( $dropbox ) ) { //Delete old backups
353
+ if ( count( $backupfilelist ) > $job_object->job['dropboxmaxbackups'] ) {
354
  ksort( $backupfilelist );
355
  $numdeltefiles = 0;
356
  while ( $file = array_shift( $backupfilelist ) ) {
357
+ if ( count( $backupfilelist ) < $job_object->job['dropboxmaxbackups'] ) {
358
  break;
359
+ }
360
+ $response = $dropbox->fileopsDelete( $job_object->job['dropboxdir'] . $file ); //delete files on Cloud
361
+ if ( $response['is_deleted'] == 'true' ) {
362
  foreach ( $files as $key => $filedata ) {
363
+ if ( $filedata['file'] == '/' . $job_object->job['dropboxdir'] . $file ) {
364
  unset( $files[ $key ] );
365
+ }
366
  }
367
  $numdeltefiles ++;
368
+ } else {
 
369
  $job_object->log( sprintf( __( 'Error while deleting file from Dropbox: %s', 'backwpup' ), $file ), E_USER_ERROR );
370
+ }
371
  }
372
+ if ( $numdeltefiles > 0 ) {
373
  $job_object->log( sprintf( _n( 'One file deleted from Dropbox', '%d files deleted on Dropbox', $numdeltefiles, 'backwpup' ), $numdeltefiles ), E_USER_NOTICE );
374
+ }
375
  }
376
  }
377
+ set_site_transient( 'backwpup_' . $job_object->job['jobid'] . '_dropbox', $files, 60 * 60 * 24 * 7 );
378
+ } catch ( Exception $e ) {
 
379
  $job_object->log( E_USER_ERROR, sprintf( __( 'Dropbox API: %s', 'backwpup' ), $e->getMessage() ), $e->getFile(), $e->getLine() );
380
 
381
+ return false;
382
  }
383
  $job_object->substeps_done ++;
384
 
385
+ return true;
386
  }
387
 
388
  /**
389
  * @param $job_settings
390
+ *
391
  * @return bool
392
  */
393
  public function can_run( array $job_settings ) {
394
 
395
+ if ( empty( $job_settings['dropboxtoken'] ) ) {
396
+ return false;
397
+ }
398
 
399
+ return true;
400
  }
401
 
402
  }
410
  /**
411
  *
412
  */
413
+ const API_URL = 'https://api.dropboxapi.com/';
414
 
415
  /**
416
  *
417
  */
418
+ const API_CONTENT_URL = 'https://content.dropboxapi.com/';
419
 
420
  /**
421
  *
422
  */
423
+ const API_WWW_URL = 'https://www.dropbox.com/';
424
 
425
  /**
426
  *
451
  private $oauth_token = '';
452
 
453
 
 
454
  /**
455
  * @param string $boxtype
456
+ *
457
  * @throws BackWPup_Destination_Dropbox_API_Exception
458
  */
459
  public function __construct( $boxtype = 'dropbox' ) {
460
 
461
  if ( $boxtype == 'dropbox' ) {
462
+ $this->oauth_app_key = get_site_option( 'backwpup_cfg_dropboxappkey', base64_decode( "dHZkcjk1MnRhZnM1NmZ2" ) );
463
  $this->oauth_app_secret = BackWPup_Encryption::decrypt( get_site_option( 'backwpup_cfg_dropboxappsecret', base64_decode( "OWV2bDR5MHJvZ2RlYmx1" ) ) );
464
  $this->root = 'dropbox';
465
+ } else {
466
+ $this->oauth_app_key = get_site_option( 'backwpup_cfg_dropboxsandboxappkey', base64_decode( "cHVrZmp1a3JoZHR5OTFk" ) );
 
467
  $this->oauth_app_secret = BackWPup_Encryption::decrypt( get_site_option( 'backwpup_cfg_dropboxsandboxappsecret', base64_decode( "eGNoYzhxdTk5eHE0eWdq" ) ) );
468
  $this->root = 'sandbox';
469
  }
470
 
471
+ if ( empty( $this->oauth_app_key ) || empty( $this->oauth_app_secret ) ) {
472
  throw new BackWPup_Destination_Dropbox_API_Exception( "No App key or App Secret specified." );
473
+ }
474
  }
475
 
476
  /**
477
  * @param $token
478
+ *
479
  * @throws BackWPup_Destination_Dropbox_API_Exception
480
  */
481
  public function setOAuthTokens( $token ) {
482
 
483
+ if ( empty( $token['access_token'] ) ) {
484
  throw new BackWPup_Destination_Dropbox_API_Exception( "No oAuth token specified." );
485
+ }
486
 
487
  $this->oauth_token = $token;
488
  }
489
 
490
+ public function token_from_oauth1() {
491
 
492
  $url = self::API_URL . self::API_VERSION_URL . 'oauth2/token_from_oauth1';
493
 
514
  /**
515
  * @param $file
516
  * @param string $path
517
+ * @param bool $overwrite
518
+ *
519
  * @return array|mixed|string
520
  * @throws BackWPup_Destination_Dropbox_API_Exception
521
  */
522
+ public function upload( $file, $path = '', $overwrite = true ) {
523
 
524
  $file = str_replace( "\\", "/", $file );
525
 
528
  }
529
 
530
  if ( filesize( $file ) < 5242880 ) { //chunk transfer on bigger uploads
531
+ $url = self::API_CONTENT_URL . self::API_VERSION_URL . 'files_put/' . $this->root . '/' . $this->encode_path( $path );
532
+ $output = $this->request( $url, array( 'overwrite' => ( $overwrite ) ? 'true' : 'false' ), 'PUT', file_get_contents( $file ) );
533
+ } else {
 
534
  $output = $this->chunked_upload( $file, $path, $overwrite );
535
  }
536
 
540
  /**
541
  * @param $file
542
  * @param string $path
543
+ * @param bool $overwrite
544
+ *
545
  * @return array|mixed|string
546
  * @throws BackWPup_Destination_Dropbox_API_Exception
547
  */
548
+ public function chunked_upload( $file, $path = '', $overwrite = true ) {
549
 
550
  $backwpup_job_object = BackWPup_Destination_Dropbox::$backwpup_job_object;
551
 
562
  throw new BackWPup_Destination_Dropbox_API_Exception( "Can not open source file for transfer." );
563
  }
564
 
565
+ if ( ! isset( $backwpup_job_object->steps_data[ $backwpup_job_object->step_working ]['uploadid'] ) ) {
566
+ $backwpup_job_object->steps_data[ $backwpup_job_object->step_working ]['uploadid'] = null;
567
  }
568
+ if ( ! isset( $backwpup_job_object->steps_data[ $backwpup_job_object->step_working ]['offset'] ) ) {
569
+ $backwpup_job_object->steps_data[ $backwpup_job_object->step_working ]['offset'] = 0;
570
  }
571
 
572
  //seek to current position
573
+ if ( $backwpup_job_object->steps_data[ $backwpup_job_object->step_working ]['offset'] > 0 ) {
574
+ fseek( $file_handel, $backwpup_job_object->steps_data[ $backwpup_job_object->step_working ]['offset'] );
575
  }
576
 
577
  while ( $data = fread( $file_handel, $chunk_size ) ) {
578
+ $chunk_upload_start = microtime( true );
579
+ $url = self::API_CONTENT_URL . self::API_VERSION_URL . 'chunked_upload';
580
+ $output = $this->request( $url, array(
581
+ 'upload_id' => $backwpup_job_object->steps_data[ $backwpup_job_object->step_working ]['uploadid'],
582
+ 'offset' => $backwpup_job_object->steps_data[ $backwpup_job_object->step_working ]['offset']
583
+ ), 'PUT', $data );
584
+ $chunk_upload_time = microtime( true ) - $chunk_upload_start;
585
  //args for next chunk
586
+ $backwpup_job_object->steps_data[ $backwpup_job_object->step_working ]['offset'] = $output['offset'];
587
+ $backwpup_job_object->steps_data[ $backwpup_job_object->step_working ]['uploadid'] = $output['upload_id'];
588
+ if ( $backwpup_job_object->job['backuptype'] === 'archive' ) {
589
+ $backwpup_job_object->substeps_done = $backwpup_job_object->steps_data[ $backwpup_job_object->step_working ]['offset'];
590
  if ( strlen( $data ) == $chunk_size ) {
591
  $time_remaining = $backwpup_job_object->do_restart_time();
592
  //calc next chunk
593
  if ( $time_remaining < $chunk_upload_time ) {
594
+ $chunk_size = floor( $chunk_size / $chunk_upload_time * ( $time_remaining - 3 ) );
595
  if ( $chunk_size < 0 ) {
596
  $chunk_size = 1024;
597
  }
603
  }
604
  $backwpup_job_object->update_working_data();
605
  //correct position
606
+ fseek( $file_handel, $backwpup_job_object->steps_data[ $backwpup_job_object->step_working ]['offset'] );
607
  }
608
 
609
  fclose( $file_handel );
610
 
611
  $url = self::API_CONTENT_URL . self::API_VERSION_URL . 'commit_chunked_upload/' . $this->root . '/' . $this->encode_path( $path );
612
 
613
+ $request = $this->request( $url, array(
614
+ 'overwrite' => ( $overwrite ) ? 'true' : 'false',
615
+ 'upload_id' => $backwpup_job_object->steps_data[ $backwpup_job_object->step_working ]['uploadid']
616
+ ), 'POST' );
617
+
618
+ unset( $backwpup_job_object->steps_data[ $backwpup_job_object->step_working ]['uploadid'] );
619
+ unset( $backwpup_job_object->steps_data[ $backwpup_job_object->step_working ]['offset'] );
620
+
621
+ return $request;
622
  }
623
 
624
  /**
625
  * @param $path
626
  * @param bool $echo
627
+ *
628
  * @return string
629
  */
630
+ public function download( $path, $echo = false ) {
631
 
632
+ $url = self::API_CONTENT_URL . self::API_VERSION_URL . 'files/' . $this->root . '/' . $path;
633
+ if ( ! $echo ) {
634
  return $this->request( $url );
635
+ } else {
636
+ $this->request( $url, null, 'GET', '', true );
637
+
638
  return '';
639
  }
640
  }
641
 
642
  /**
643
  * @param string $path
644
+ * @param bool $listContents
645
+ * @param int $fileLimit
646
  * @param string $hash
647
+ *
648
  * @return array|mixed|string
649
  */
650
+ public function metadata( $path = '', $listContents = true, $fileLimit = 10000, $hash = '' ) {
651
 
652
  $url = self::API_URL . self::API_VERSION_URL . 'metadata/' . $this->root . '/' . $this->encode_path( $path );
653
 
654
  return $this->request( $url, array(
655
+ 'list' => ( $listContents ) ? 'true' : 'false',
656
+ 'hash' => ( $hash ) ? $hash : '',
657
+ 'file_limit' => $fileLimit
658
+ ) );
659
  }
660
 
661
  /**
662
  * @param string $path
663
+ *
664
  * @return array|mixed|string
665
  */
666
  public function media( $path = '' ) {
672
 
673
  /**
674
  * @param $path
675
+ *
676
  * @return array|mixed|string
677
  */
678
  public function fileopsDelete( $path ) {
680
  $url = self::API_URL . self::API_VERSION_URL . 'fileops/delete';
681
 
682
  return $this->request( $url, array(
683
+ 'path' => '/' . $path,
684
+ 'root' => $this->root
685
+ ) );
686
  }
687
 
688
+ public function oAuthAuthorize() {
689
 
690
  return self::API_WWW_URL . self::API_VERSION_URL . 'oauth2/authorize?response_type=code&client_id=' . $this->oauth_app_key;
691
  }
696
  $url = self::API_URL . self::API_VERSION_URL . 'oauth2/token';
697
 
698
  return $this->request( $url, array(
699
+ 'code' => trim( $code ),
700
+ 'grant_type' => 'authorization_code',
701
+ 'client_id' => $this->oauth_app_key,
702
+ 'client_secret' => $this->oauth_app_secret
703
+ ), 'POST' );
704
 
705
  }
706
 
707
 
708
  /**
709
  * @param $url
710
+ * @param array $args
711
  * @param string $method
712
  * @param string $data
713
+ * @param bool $echo
714
  *
715
  * @throws BackWPup_Destination_Dropbox_API_Exception
716
  * @internal param null $file
717
  * @return array|mixed|string
718
  */
719
+ private function request( $url, $args = array(), $method = 'GET', $data = '', $echo = false ) {
720
 
721
  /* Header*/
722
  // oAuth 2
723
+ if ( ! empty( $this->oauth_token['access_token'] ) && ! empty( $this->oauth_token['token_type'] ) && strtolower( $this->oauth_token['token_type'] ) == 'bearer' ) {
724
+ $headers[] = 'Authorization: Bearer ' . $this->oauth_token['access_token'];
725
+ } // oAuth 1
726
+ elseif ( ! empty( $this->oauth_token['access_token'] ) && ! empty( $this->oauth_token['oauth_token_secret'] ) ) {
727
+ $headers[] = 'Authorization: OAuth oauth_version="1.0", oauth_signature_method="PLAINTEXT", oauth_consumer_key="' . $this->oauth_app_key . '", oauth_token="' . $this->oauth_token['access_token'] . '", oauth_signature="' . $this->oauth_app_secret . '&' . $this->oauth_token['oauth_token_secret'] . '"';
728
+ }
729
 
730
+ $headers[] = 'Expect:';
731
 
732
  /* Build cURL Request */
733
  $ch = curl_init();
734
  if ( $method == 'POST' ) {
735
+ curl_setopt( $ch, CURLOPT_POST, true );
736
  curl_setopt( $ch, CURLOPT_POSTFIELDS, $args );
737
  curl_setopt( $ch, CURLOPT_URL, $url );
738
+ } elseif ( $method == 'PUT' ) {
 
739
  curl_setopt( $ch, CURLOPT_CUSTOMREQUEST, 'PUT' );
740
  curl_setopt( $ch, CURLOPT_POSTFIELDS, $data );
741
+ $headers[] = 'Content-Type: application/octet-stream';
742
+ $args = ( is_array( $args ) ) ? '?' . http_build_query( $args, '', '&' ) : $args;
743
  curl_setopt( $ch, CURLOPT_URL, $url . $args );
744
+ } else {
745
+ curl_setopt( $ch, CURLOPT_BINARYTRANSFER, true );
 
746
  $args = ( is_array( $args ) ) ? '?' . http_build_query( $args, '', '&' ) : $args;
747
  curl_setopt( $ch, CURLOPT_URL, $url . $args );
748
  }
749
  curl_setopt( $ch, CURLOPT_USERAGENT, BackWPup::get_plugin_data( 'User-Agent' ) );
750
+ curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
751
  if ( BackWPup::get_plugin_data( 'cacert' ) ) {
752
  curl_setopt( $ch, CURLOPT_SSLVERSION, 1 );
753
+ curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, true );
754
  $curl_version = curl_version();
755
+ if ( strstr( $curl_version['ssl_version'], 'NSS/' ) === false ) {
756
  curl_setopt( $ch, CURLOPT_SSL_CIPHER_LIST,
757
+ 'ECDHE-RSA-AES256-GCM-SHA384:' .
758
+ 'ECDHE-RSA-AES128-GCM-SHA256:' .
759
+ 'ECDHE-RSA-AES256-SHA384:' .
760
+ 'ECDHE-RSA-AES128-SHA256:' .
761
+ 'ECDHE-RSA-AES256-SHA:' .
762
+ 'ECDHE-RSA-AES128-SHA:' .
763
+ 'ECDHE-RSA-RC4-SHA:' .
764
+ 'DHE-RSA-AES256-GCM-SHA384:' .
765
+ 'DHE-RSA-AES128-GCM-SHA256:' .
766
+ 'DHE-RSA-AES256-SHA256:' .
767
+ 'DHE-RSA-AES128-SHA256:' .
768
+ 'DHE-RSA-AES256-SHA:' .
769
+ 'DHE-RSA-AES128-SHA:' .
770
+ 'AES256-GCM-SHA384:' .
771
+ 'AES128-GCM-SHA256:' .
772
+ 'AES256-SHA256:' .
773
+ 'AES128-SHA256:' .
774
+ 'AES256-SHA:' .
775
+ 'AES128-SHA'
776
  );
777
  }
778
+ if ( defined( 'CURLOPT_PROTOCOLS' ) ) {
779
  curl_setopt( $ch, CURLOPT_PROTOCOLS, CURLPROTO_HTTPS );
780
+ }
781
+ if ( defined( 'CURLOPT_REDIR_PROTOCOLS' ) ) {
782
  curl_setopt( $ch, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTPS );
783
+ }
784
  curl_setopt( $ch, CURLOPT_CAINFO, BackWPup::get_plugin_data( 'cacert' ) );
785
  curl_setopt( $ch, CURLOPT_CAPATH, dirname( BackWPup::get_plugin_data( 'cacert' ) ) );
786
  } else {
787
+ curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, false );
788
  }
789
  curl_setopt( $ch, CURLOPT_HTTPHEADER, $headers );
790
  $output = '';
791
  if ( $echo ) {
792
  echo curl_exec( $ch );
793
+ } else {
794
+ curl_setopt( $ch, CURLOPT_HEADER, true );
 
795
  if ( 0 == curl_errno( $ch ) ) {
796
  $responce = explode( "\r\n\r\n", curl_exec( $ch ), 2 );
797
+ if ( ! empty( $responce[1] ) ) {
798
+ $output = json_decode( $responce[1], true );
799
+ }
800
  }
801
  }
802
  $status = curl_getinfo( $ch );
803
+ if ( $status['http_code'] == 503 ) {
804
  $wait = 0;
805
+ if ( preg_match( "/retry-after:(.*?)\r/i", $responce[0], $matches ) ) {
806
+ $wait = trim( $matches[1] );
807
+ }
808
  //only wait if we get a retry-after header.
809
  if ( ! empty( $wait ) ) {
810
  trigger_error( sprintf( '(503) Your app is making too many requests and is being rate limited. Error 503 can be triggered on a per-app or per-user basis. Wait for %d seconds.', $wait ), E_USER_WARNING );
812
  } else {
813
  throw new BackWPup_Destination_Dropbox_API_Exception( '(503) This indicates a transient server error.' );
814
  }
815
+
816
  //redo request
817
  return $this->request( $url, $args, $method, $data, $echo );
818
+ } elseif ( $status['http_code'] === 400 && $method === 'PUT' && strstr( $url, '/chunked_upload' ) ) { //correct offset on chunk uploads
819
+ trigger_error( '(' . $status['http_code'] . ') False offset will corrected', E_USER_NOTICE );
 
 
 
 
 
820
 
821
+ return $output;
822
+ } elseif ( $status['http_code'] === 404 && ! empty( $output['error'] ) ) {
823
+ trigger_error( '(' . $status['http_code'] . ') ' . $output['error'], E_USER_WARNING );
824
+
825
+ return false;
826
+ } elseif ( isset( $output['error'] ) || $status['http_code'] >= 300 || $status['http_code'] < 200 || curl_errno( $ch ) > 0 ) {
827
+ if ( isset( $output['error'] ) && is_string( $output['error'] ) ) {
828
+ $message = '(' . $status['http_code'] . ') ' . $output['error'] . ' ' . $url . $args;
829
+ } elseif ( isset( $output['error']['hash'] ) && $output['error']['hash'] != '' ) {
830
+ $message = (string) '(' . $status['http_code'] . ') ' . $output['error']['hash'] . ' ' . $url . $args;
831
+ } elseif ( 0 != curl_errno( $ch ) ) {
832
+ $message = '(' . curl_errno( $ch ) . ') ' . curl_error( $ch );
833
+ } elseif ( $status['http_code'] == 304 ) {
834
+ $message = '(304) Folder contents have not changed (relies on hash parameter).';
835
+ } elseif ( $status['http_code'] == 400 ) {
836
+ $message = '(400) Bad input parameter: ' . strip_tags( $responce[1] );
837
+ } elseif ( $status['http_code'] == 401 ) {
838
+ $message = '(401) Bad or expired token. This can happen if the user or Dropbox revoked or expired an access token. To fix, you should re-authenticate the user.';
839
+ } elseif ( $status['http_code'] == 403 ) {
840
+ $message = '(403) Bad OAuth request (wrong consumer key, bad nonce, expired timestamp...). Unfortunately, re-authenticating the user won\'t help here.';
841
+ } elseif ( $status['http_code'] == 404 ) {
842
+ $message = '(404) File or folder not found at the specified path.';
843
+ } elseif ( $status['http_code'] == 405 ) {
844
+ $message = '(405) Request method not expected (generally should be GET or POST).';
845
+ } elseif ( $status['http_code'] == 406 ) {
846
+ $message = '(406) There are too many file entries to return.';
847
+ } elseif ( $status['http_code'] == 411 ) {
848
+ $message = '(411) Missing Content-Length header (this endpoint doesn\'t support HTTP chunked transfer encoding).';
849
+ } elseif ( $status['http_code'] == 415 ) {
850
+ $message = '(415) The image is invalid and cannot be converted to a thumbnail.';
851
+ } elseif ( $status['http_code'] == 429 ) {
852
+ $message = '(429) Your app is making too many requests and is being rate limited. 429s can trigger on a per-app or per-user basis.';
853
+ } elseif ( $status['http_code'] == 507 ) {
854
+ $message = '(507) User is over Dropbox storage quota.';
855
+ } else {
856
+ $message = '(' . $status['http_code'] . ') Invalid response.';
857
+ }
858
  throw new BackWPup_Destination_Dropbox_API_Exception( $message );
859
+ } else {
 
860
  curl_close( $ch );
861
+ if ( ! is_array( $output ) ) {
862
+ return $responce[1];
863
+ } else {
864
  return $output;
865
+ }
866
  }
867
  }
868
 
inc/class-destination-folder.php CHANGED
@@ -101,7 +101,6 @@ class BackWPup_Destination_Folder extends BackWPup_Destinations {
101
  $get_file = realpath( trailingslashit( $backup_dir ) . basename( $get_file ) );
102
 
103
  if ( $get_file && is_readable( $get_file ) ) {
104
- while( @ob_end_clean() );
105
  header( "Pragma: public" );
106
  header( "Expires: 0" );
107
  header( "Cache-Control: must-revalidate, post-check=0, pre-check=0" );
101
  $get_file = realpath( trailingslashit( $backup_dir ) . basename( $get_file ) );
102
 
103
  if ( $get_file && is_readable( $get_file ) ) {
 
104
  header( "Pragma: public" );
105
  header( "Expires: 0" );
106
  header( "Cache-Control: must-revalidate, post-check=0, pre-check=0" );
inc/class-job.php CHANGED
@@ -452,7 +452,7 @@ final class BackWPup_Job {
452
 
453
  $authentication = get_site_option( 'backwpup_cfg_authentication', array( 'method' => '', 'basic_user' => '', 'basic_password' => '', 'user_id' => 0, 'query_arg' => '' ) );
454
  $url = site_url( 'wp-cron.php' );
455
- $header = array();
456
  $authurl = '';
457
  $query_args = array( '_nonce' => substr( wp_hash( wp_nonce_tick() . 'backwpup_job_run-' . $starttype, 'nonce' ), - 12, 10 ), 'doing_wp_cron' => sprintf( '%.22F', microtime( true ) ) );
458
 
@@ -548,6 +548,9 @@ final class BackWPup_Job {
548
 
549
  if ( ! in_array( $starttype, array( 'runnowlink', 'runext', 'restartalt' ) ) ) {
550
  delete_transient( 'doing_cron' );
 
 
 
551
  return wp_remote_post( $cron_request[ 'url' ], $cron_request[ 'args' ] );
552
  }
553
 
@@ -858,10 +861,6 @@ final class BackWPup_Job {
858
  }
859
  }
860
  }
861
- //clear output buffer
862
- ob_start();
863
- while( @ob_end_clean() );
864
- @flush();
865
  $job_types = BackWPup::get_job_types();
866
  //go step by step
867
  foreach ( $this->steps_todo as $this->step_working ) {
@@ -2387,7 +2386,7 @@ final class BackWPup_Job {
2387
  public static function clean_temp_folder() {
2388
 
2389
  $temp_dir = BackWPup::get_plugin_data( 'TEMP' );
2390
- $do_not_delete_files = array( '.htaccess', 'index.php', '.', '..', '.donotbackup' );
2391
 
2392
  if ( is_writable( $temp_dir ) && $dir = opendir( $temp_dir ) ) {
2393
  while ( FALSE !== ( $file = readdir( $dir ) ) ) {
452
 
453
  $authentication = get_site_option( 'backwpup_cfg_authentication', array( 'method' => '', 'basic_user' => '', 'basic_password' => '', 'user_id' => 0, 'query_arg' => '' ) );
454
  $url = site_url( 'wp-cron.php' );
455
+ $header = array( 'x-backwpup-version' => BackWPup::get_plugin_data( 'version' ) );
456
  $authurl = '';
457
  $query_args = array( '_nonce' => substr( wp_hash( wp_nonce_tick() . 'backwpup_job_run-' . $starttype, 'nonce' ), - 12, 10 ), 'doing_wp_cron' => sprintf( '%.22F', microtime( true ) ) );
458
 
548
 
549
  if ( ! in_array( $starttype, array( 'runnowlink', 'runext', 'restartalt' ) ) ) {
550
  delete_transient( 'doing_cron' );
551
+ if ( $starttype === 'test' ) {
552
+ return wp_remote_head( $cron_request[ 'url' ], $cron_request[ 'args' ] );
553
+ }
554
  return wp_remote_post( $cron_request[ 'url' ], $cron_request[ 'args' ] );
555
  }
556
 
861
  }
862
  }
863
  }
 
 
 
 
864
  $job_types = BackWPup::get_job_types();
865
  //go step by step
866
  foreach ( $this->steps_todo as $this->step_working ) {
2386
  public static function clean_temp_folder() {
2387
 
2388
  $temp_dir = BackWPup::get_plugin_data( 'TEMP' );
2389
+ $do_not_delete_files = array( '.htaccess', 'nginx.conf', 'index.php', '.', '..', '.donotbackup' );
2390
 
2391
  if ( is_writable( $temp_dir ) && $dir = opendir( $temp_dir ) ) {
2392
  while ( FALSE !== ( $file = readdir( $dir ) ) ) {
inc/class-jobtype-file.php CHANGED
@@ -291,9 +291,9 @@ class BackWPup_JobType_File extends BackWPup_JobTypes {
291
  <tr>
292
  <th scope="row"><?php _e( 'Include special files', 'backwpup' ); ?></th>
293
  <td>
294
- <label for="idbackupspecialfiles"><input class="checkbox help-tip" id="idbackupspecialfiles" title="<?php _e( 'If the WordPress root folder is not included in this backup job, check this option to additionally include wp-config.php, robots.txt, .htaccess, .htpasswd and favicon.ico into the backup. Your wp-config.php will be included even if you placed it in the parent directory of your root folder.', 'backwpup' ); ?>"
295
  type="checkbox"<?php checked( BackWPup_Option::get( $main, 'backupspecialfiles' ), TRUE, TRUE ); ?>
296
- name="backupspecialfiles" value="1" /> <?php _e( 'Backup wp-config.php, robots.txt, .htaccess, .htpasswd and favicon.ico from root.', 'backwpup' ); ?></label>
297
  </td>
298
  </tr>
299
  <tr>
@@ -512,6 +512,10 @@ class BackWPup_JobType_File extends BackWPup_JobTypes {
512
  $job_object->additional_files_to_backup[ ] = $abs_path . '.htaccess';
513
  $job_object->log( sprintf( __( 'Added "%s" to backup file list', 'backwpup' ), '.htaccess' ) );
514
  }
 
 
 
 
515
  if ( is_readable( $abs_path . '.htpasswd' ) && empty( $job_object->job[ 'backuproot' ] ) ) {
516
  $job_object->additional_files_to_backup[ ] = $abs_path . '.htpasswd';
517
  $job_object->log( sprintf( __( 'Added "%s" to backup file list', 'backwpup' ), '.htpasswd' ) );
291
  <tr>
292
  <th scope="row"><?php _e( 'Include special files', 'backwpup' ); ?></th>
293
  <td>
294
+ <label for="idbackupspecialfiles"><input class="checkbox help-tip" id="idbackupspecialfiles" title="<?php _e( 'If the WordPress root folder is not included in this backup job, check this option to additionally include wp-config.php, robots.txt, .htaccess, nginx.conf, .htpasswd and favicon.ico into the backup. Your wp-config.php will be included even if you placed it in the parent directory of your root folder.', 'backwpup' ); ?>"
295
  type="checkbox"<?php checked( BackWPup_Option::get( $main, 'backupspecialfiles' ), TRUE, TRUE ); ?>
296
+ name="backupspecialfiles" value="1" /> <?php _e( 'Backup wp-config.php, robots.txt, nginx.conf, .htaccess, .htpasswd and favicon.ico from root.', 'backwpup' ); ?></label>
297
  </td>
298
  </tr>
299
  <tr>
512
  $job_object->additional_files_to_backup[ ] = $abs_path . '.htaccess';
513
  $job_object->log( sprintf( __( 'Added "%s" to backup file list', 'backwpup' ), '.htaccess' ) );
514
  }
515
+ if ( is_readable( $abs_path . 'nginx.conf' ) && empty( $job_object->job[ 'backuproot' ] ) ) {
516
+ $job_object->additional_files_to_backup[ ] = $abs_path . 'nginx.conf';
517
+ $job_object->log( sprintf( __( 'Added "%s" to backup file list', 'backwpup' ), 'nginx.conf' ) );
518
+ }
519
  if ( is_readable( $abs_path . '.htpasswd' ) && empty( $job_object->job[ 'backuproot' ] ) ) {
520
  $job_object->additional_files_to_backup[ ] = $abs_path . '.htpasswd';
521
  $job_object->log( sprintf( __( 'Added "%s" to backup file list', 'backwpup' ), '.htpasswd' ) );
inc/class-jobtype-wpexp.php CHANGED
@@ -305,7 +305,6 @@ class BackWPup_JobType_WPEXP extends BackWPup_JobTypes {
305
 
306
  // fetch 20 posts at a time rather than loading the entire table into memory
307
  while ( $next_posts = array_splice( $job_object->steps_data[ $job_object->step_working ]['post_ids'], 0, 20 ) ) {
308
- wp_cache_flush();
309
  $where = 'WHERE ID IN (' . join( ',', $next_posts ) . ')';
310
  $posts = $wpdb->get_results( "SELECT * FROM {$wpdb->posts} $where" );
311
  $wxr_post = '';
@@ -394,7 +393,7 @@ class BackWPup_JobType_WPEXP extends BackWPup_JobTypes {
394
  $job_object->do_restart_time();
395
  }
396
 
397
- remove_filter( 'wxr_export_skip_postmeta', array( $this, 'wxr_filter_postmeta' ), 10, 2 );
398
 
399
  if ( $job_object->steps_data[ $job_object->step_working ]['substep'] == 'check' ) {
400
 
@@ -515,8 +514,9 @@ class BackWPup_JobType_WPEXP extends BackWPup_JobTypes {
515
  * @return string
516
  */
517
  private function wxr_cdata( $str ) {
518
- if ( seems_utf8( $str ) == false )
519
  $str = utf8_encode( $str );
 
520
 
521
  // not allowed UTF-8 chars in XML
522
  $str = preg_replace( '/[^\x{0009}\x{000a}\x{000d}\x{0020}-\x{D7FF}\x{E000}-\x{FFFD}]+/u', '', $str );
@@ -637,8 +637,10 @@ class BackWPup_JobType_WPEXP extends BackWPup_JobTypes {
637
  * Output list of authors with posts
638
  *
639
  * @since WordPress 3.1.0
 
 
640
  */
641
- private function wxr_authors_list() {
642
  global $wpdb;
643
 
644
  $authors = array();
@@ -691,7 +693,7 @@ class BackWPup_JobType_WPEXP extends BackWPup_JobTypes {
691
  * @since WordPress 2.3.0
692
  */
693
  private function wxr_post_taxonomy() {
694
- global $post;
695
 
696
  $taxonomies = get_object_taxonomies( $post->post_type );
697
  if ( empty( $taxonomies ) )
305
 
306
  // fetch 20 posts at a time rather than loading the entire table into memory
307
  while ( $next_posts = array_splice( $job_object->steps_data[ $job_object->step_working ]['post_ids'], 0, 20 ) ) {
 
308
  $where = 'WHERE ID IN (' . join( ',', $next_posts ) . ')';
309
  $posts = $wpdb->get_results( "SELECT * FROM {$wpdb->posts} $where" );
310
  $wxr_post = '';
393
  $job_object->do_restart_time();
394
  }
395
 
396
+ remove_filter( 'wxr_export_skip_postmeta', array( $this, 'wxr_filter_postmeta' ), 10 );
397
 
398
  if ( $job_object->steps_data[ $job_object->step_working ]['substep'] == 'check' ) {
399
 
514
  * @return string
515
  */
516
  private function wxr_cdata( $str ) {
517
+ if ( ! seems_utf8( $str ) ) {
518
  $str = utf8_encode( $str );
519
+ }
520
 
521
  // not allowed UTF-8 chars in XML
522
  $str = preg_replace( '/[^\x{0009}\x{000a}\x{000d}\x{0020}-\x{D7FF}\x{E000}-\x{FFFD}]+/u', '', $str );
637
  * Output list of authors with posts
638
  *
639
  * @since WordPress 3.1.0
640
+ *
641
+ * @return string
642
  */
643
+ private function wxr_authors_list( ) {
644
  global $wpdb;
645
 
646
  $authors = array();
693
  * @since WordPress 2.3.0
694
  */
695
  private function wxr_post_taxonomy() {
696
+ $post = get_post();
697
 
698
  $taxonomies = get_object_taxonomies( $post->post_type );
699
  if ( empty( $taxonomies ) )
inc/class-mysqldump.php CHANGED
@@ -102,7 +102,7 @@ class BackWPup_MySQLDump {
102
 
103
 
104
  if ( ! $this->mysqli->options( MYSQLI_OPT_CONNECT_TIMEOUT, 5 ) ) {
105
- throw new BackWPup_MySQLDump_Exception( __( 'Setting of MySQLi connection timeout failed', 'backwpup' ) );
106
  }
107
 
108
  //connect to Database
@@ -114,7 +114,7 @@ class BackWPup_MySQLDump {
114
  if ( ! empty( $args[ 'dbcharset' ] ) && method_exists( $this->mysqli, 'set_charset' ) ) {
115
  $res = $this->mysqli->set_charset( $args[ 'dbcharset' ] );
116
  if ( ! $res ) {
117
- throw new BackWPup_MySQLDump_Exception( sprintf( _x( 'Cannot set DB charset to %s error: %s','Database Charset', 'backwpup' ), $args[ 'dbcharset' ], $this->mysqli->error ) );
118
  }
119
  }
120
 
@@ -306,6 +306,30 @@ class BackWPup_MySQLDump {
306
  $res->close();
307
  }
308
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
309
  //for better import with mysql client
310
  $dbdumpfooter = "\n/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;\n";
311
  $dbdumpfooter .= "/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;\n";
102
 
103
 
104
  if ( ! $this->mysqli->options( MYSQLI_OPT_CONNECT_TIMEOUT, 5 ) ) {
105
+ trigger_error( __( 'Setting of MySQLi connection timeout failed', 'backwpup' ) );
106
  }
107
 
108
  //connect to Database
114
  if ( ! empty( $args[ 'dbcharset' ] ) && method_exists( $this->mysqli, 'set_charset' ) ) {
115
  $res = $this->mysqli->set_charset( $args[ 'dbcharset' ] );
116
  if ( ! $res ) {
117
+ trigger_error( sprintf( _x( 'Cannot set DB charset to %s error: %s','Database Charset', 'backwpup' ), $args[ 'dbcharset' ], $this->mysqli->error ), E_USER_WARNING );
118
  }
119
  }
120
 
306
  $res->close();
307
  }
308
 
309
+ //dump Trigger
310
+ $res = $this->mysqli->query( "SHOW TRIGGERS FROM `" . $this->dbname . "`" );
311
+ $GLOBALS[ 'wpdb' ]->num_queries ++;
312
+ if ( $this->mysqli->error ) {
313
+ trigger_error( sprintf( __( 'Database error %1$s for query %2$s', 'backwpup' ), $this->mysqli->error, "SHOW TRIGGERS" ), E_USER_WARNING );
314
+ } else {
315
+ while ( $triggers = $res->fetch_assoc() ) {
316
+ $create = "\n--\n-- Trigger structure for " . $triggers[ 'Trigger' ] . "\n--\n\n";
317
+ $create .= "DROP TRIGGER IF EXISTS `" . $triggers[ 'Trigger' ] . "`;\n";
318
+ $create .= "DELIMITER //\n";
319
+ $res2 = $this->mysqli->query( "SHOW CREATE TRIGGER `" . $this->dbname . "`.`" . $triggers[ 'Trigger' ] . "`" );
320
+ $GLOBALS[ 'wpdb' ]->num_queries ++;
321
+ if ( $this->mysqli->error ) {
322
+ trigger_error( sprintf( __( 'Database error %1$s for query %2$s', 'backwpup' ), $this->mysqli->error, "SHOW CREATE TRIGGER `" . $this->dbname . "`.`" . $triggers[ 'Trigger' ] . "`" ), E_USER_WARNING );
323
+ }
324
+ $create_trigger = $res2->fetch_assoc();
325
+ $res2->close();
326
+ $create .= $create_trigger[ 'SQL Original Statement' ] . ";\n";
327
+ $create .= "//\nDELIMITER ;\n";
328
+ $this->write( $create );
329
+ }
330
+ $res->close();
331
+ }
332
+
333
  //for better import with mysql client
334
  $dbdumpfooter = "\n/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;\n";
335
  $dbdumpfooter .= "/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;\n";
inc/class-page-editjob.php CHANGED
@@ -422,11 +422,12 @@ class BackWPup_Page_Editjob {
422
  echo '</h2>';
423
  //display messages
424
  BackWPup_Admin::display_messages();
425
- echo '<form name="editjob" id="editjob" method="post" action="' . admin_url( 'admin-post.php?action=backwpup' ) . '">';
426
  echo '<input type="hidden" id="jobid" name="jobid" value="' . $jobid . '" />';
427
  echo '<input type="hidden" name="tab" value="' . $_GET[ 'tab' ] . '" />';
428
  echo '<input type="hidden" name="nexttab" value="' . $_GET[ 'tab' ] . '" />';
429
  echo '<input type="hidden" name="page" value="backwpupeditjob" />';
 
430
  echo '<input type="hidden" name="anchor" value="" />';
431
  wp_nonce_field( 'backwpupeditjob_page' );
432
  wp_nonce_field( 'backwpup_ajax_nonce', 'backwpupajaxnonce', FALSE );
422
  echo '</h2>';
423
  //display messages
424
  BackWPup_Admin::display_messages();
425
+ echo '<form name="editjob" id="editjob" method="post" action="' . admin_url( 'admin-post.php' ) . '">';
426
  echo '<input type="hidden" id="jobid" name="jobid" value="' . $jobid . '" />';
427
  echo '<input type="hidden" name="tab" value="' . $_GET[ 'tab' ] . '" />';
428
  echo '<input type="hidden" name="nexttab" value="' . $_GET[ 'tab' ] . '" />';
429
  echo '<input type="hidden" name="page" value="backwpupeditjob" />';
430
+ echo '<input type="hidden" name="action" value="backwpup" />';
431
  echo '<input type="hidden" name="anchor" value="" />';
432
  wp_nonce_field( 'backwpupeditjob_page' );
433
  wp_nonce_field( 'backwpup_ajax_nonce', 'backwpupajaxnonce', FALSE );
inc/class-page-jobs.php CHANGED
@@ -445,9 +445,15 @@ class BackWPup_Page_Jobs extends WP_List_Table {
445
  if ( $response_code < 200 && $response_code > 204 ) {
446
  $test_result .= sprintf( __( 'The HTTP response test get a false http status (%s)','backwpup' ), wp_remote_retrieve_response_code( $raw_response ) );
447
  } else {
448
- $response_body = wp_remote_retrieve_body( $raw_response );
449
- if ( FALSE === strstr( $response_body, 'BackWPup Test' ) ) {
450
- $test_result .= sprintf( __( 'Not expected HTTP response body: %s','backwpup' ), esc_attr( strip_tags( $response_body ) ) );
 
 
 
 
 
 
451
  }
452
  }
453
  if ( ! empty( $test_result ) ) {
445
  if ( $response_code < 200 && $response_code > 204 ) {
446
  $test_result .= sprintf( __( 'The HTTP response test get a false http status (%s)','backwpup' ), wp_remote_retrieve_response_code( $raw_response ) );
447
  } else {
448
+ $response_header = wp_remote_retrieve_header( $raw_response, 'x-backwpup-version' );
449
+ $version = BackWPup::get_plugin_data( 'version' );
450
+ if ( $response_header !== $version ) {
451
+ $headers = '<br>';
452
+ $response_headers = wp_remote_retrieve_headers( $raw_response );
453
+ foreach( $response_headers as $key => $value ) {
454
+ $headers .= esc_attr( $key ) . ': ' . esc_attr( $value ) . '<br>';
455
+ }
456
+ $test_result .= sprintf( __( '<strong>Missing or not expected HTTP response headers:</strong> %s','backwpup' ), $headers );
457
  }
458
  }
459
  if ( ! empty( $test_result ) ) {
inc/class-page-settings.php CHANGED
@@ -127,9 +127,10 @@ class BackWPup_Page_Settings {
127
  BackWPup_Admin::display_messages();
128
  ?>
129
 
130
- <form id="settingsform" action="<?php echo admin_url( 'admin-post.php?action=backwpup' ); ?>" method="post">
131
  <?php wp_nonce_field( 'backwpupsettings_page' ); ?>
132
  <input type="hidden" name="page" value="backwpupsettings" />
 
133
  <input type="hidden" name="anchor" value="#backwpup-tab-general" />
134
 
135
  <div class="table ui-tabs-hide" id="backwpup-tab-general">
@@ -439,9 +440,15 @@ class BackWPup_Page_Settings {
439
  $test_result .= sprintf( __( 'The HTTP response test get an error "%s"','backwpup' ), $raw_response->get_error_message() );
440
  elseif ( 200 != wp_remote_retrieve_response_code( $raw_response ) && 204 != wp_remote_retrieve_response_code( $raw_response ) )
441
  $test_result .= sprintf( __( 'The HTTP response test get a false http status (%s)','backwpup' ), wp_remote_retrieve_response_code( $raw_response ) );
442
- $headers = wp_remote_retrieve_headers( $raw_response );
443
- if ( isset( $headers['x-backwpup-ver'] ) && $headers['x-backwpup-ver'] != BackWPup::get_plugin_data( 'version' ) )
444
- $test_result .= sprintf( __( 'The BackWPup HTTP response header returns a false value: "%s"','backwpup' ), $headers['x-backwpup-ver'] );
 
 
 
 
 
 
445
 
446
  if ( empty( $test_result ) )
447
  _e( 'Response Test O.K.', 'backwpup' );
127
  BackWPup_Admin::display_messages();
128
  ?>
129
 
130
+ <form id="settingsform" action="<?php echo admin_url( 'admin-post.php' ); ?>" method="post">
131
  <?php wp_nonce_field( 'backwpupsettings_page' ); ?>
132
  <input type="hidden" name="page" value="backwpupsettings" />
133
+ <input type="hidden" name="action" value="backwpup" />
134
  <input type="hidden" name="anchor" value="#backwpup-tab-general" />
135
 
136
  <div class="table ui-tabs-hide" id="backwpup-tab-general">
440
  $test_result .= sprintf( __( 'The HTTP response test get an error "%s"','backwpup' ), $raw_response->get_error_message() );
441
  elseif ( 200 != wp_remote_retrieve_response_code( $raw_response ) && 204 != wp_remote_retrieve_response_code( $raw_response ) )
442
  $test_result .= sprintf( __( 'The HTTP response test get a false http status (%s)','backwpup' ), wp_remote_retrieve_response_code( $raw_response ) );
443
+ $header = wp_remote_retrieve_header( $raw_response, 'x-backwpup-version' );
444
+ if ( $header !== BackWPup::get_plugin_data( 'version' ) ) {
445
+ $headers = '<br>';
446
+ $response_headers = wp_remote_retrieve_headers( $raw_response );
447
+ foreach( $response_headers as $key => $value ) {
448
+ $headers .= esc_attr( $key ) . ': ' . esc_attr( $value ) . '<br>';
449
+ }
450
+ $test_result .= sprintf( __( '<strong>Missing or not expected HTTP response headers:</strong> %s','backwpup' ), $headers );
451
+ }
452
 
453
  if ( empty( $test_result ) )
454
  _e( 'Response Test O.K.', 'backwpup' );
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: inpsyde, danielhuesken, Bueltge, nullbyte
3
  Tags: Amazon, Amazon S3, back up, backup, chinese, cloud, cloud files, database, db backup, dropbox, dump, file, french, ftp, ftps, german, migrate, multisite, russian, schedule, sftp, storage, S3, time, upload, xml
4
  Requires at least: 3.8
5
  Tested up to: 4.4.1
6
- Stable tag: 3.2.3
7
  License: GPLv3
8
  License URI: http://www.gnu.org/licenses/gpl-3.0.html
9
 
@@ -170,6 +170,12 @@ Please check all settings after the update:
170
 
171
 
172
  == Changelog ==
 
 
 
 
 
 
173
  = Version 3.2.3 =
174
  * Added: AWS Region Asien-Pazifik (Seoul)
175
  * Improved: open basedir checking
3
  Tags: Amazon, Amazon S3, back up, backup, chinese, cloud, cloud files, database, db backup, dropbox, dump, file, french, ftp, ftps, german, migrate, multisite, russian, schedule, sftp, storage, S3, time, upload, xml
4
  Requires at least: 3.8
5
  Tested up to: 4.4.1
6
+ Stable tag: 3.2.4
7
  License: GPLv3
8
  License URI: http://www.gnu.org/licenses/gpl-3.0.html
9
 
170
 
171
 
172
  == Changelog ==
173
+ = Version 3.2.4 =
174
+ * Added: Backup database triggers
175
+ * Fixed: Charset issues on file names in archives
176
+ * Improved: checking on response test
177
+ * Changed: Dropbox API URLs
178
+
179
  = Version 3.2.3 =
180
  * Added: AWS Region Asien-Pazifik (Seoul)
181
  * Improved: open basedir checking