XCloner – Backup and Restore - Version 4.0.9

Version Description

  • remote storage password encryption addon for database
  • vendor cleanup packages
  • database silent fail fix
  • copyright changes
  • jstree fix database display
  • microtime float div fix
  • manage backups data order fix
Download this release

Release Info

Developer xcloner
Plugin Icon 128x128 XCloner – Backup and Restore
Version 4.0.9
Comparing to
See all releases

Code changes from version 4.0.8 to 4.0.9

Files changed (94) hide show
  1. README.txt +10 -1
  2. admin/class-xcloner-admin.php +164 -163
  3. admin/css/xcloner-admin.css +184 -184
  4. admin/js/xcloner-admin.js +100 -107
  5. admin/js/xcloner-backup-class.js +403 -440
  6. admin/js/xcloner-manage-backups-class.js +1 -1
  7. admin/partials/xcloner_console_page.php +31 -28
  8. admin/partials/xcloner_generate_backups_page.php +552 -504
  9. admin/partials/xcloner_init_page.php +240 -209
  10. admin/partials/xcloner_manage_backups_page.php +240 -201
  11. admin/partials/xcloner_remote_storage_page.php +1027 -847
  12. admin/partials/xcloner_restore_page.php +451 -383
  13. admin/partials/xcloner_scheduled_backups_page.php +185 -167
  14. composer.json +2 -1
  15. composer.lock +102 -37
  16. includes/class-xcloner-activator.php +105 -66
  17. includes/class-xcloner-api.php +1117 -1055
  18. includes/class-xcloner-archive.php +738 -624
  19. includes/class-xcloner-deactivator.php +31 -15
  20. includes/class-xcloner-file-system.php +1060 -980
  21. includes/class-xcloner-file-transfer.php +157 -95
  22. includes/class-xcloner-i18n.php +40 -26
  23. includes/class-xcloner-loader.php +176 -134
  24. includes/class-xcloner-logger.php +71 -82
  25. includes/class-xcloner-remote-storage.php +624 -570
  26. includes/class-xcloner-requirements.php +110 -113
  27. includes/class-xcloner-sanitization.php +40 -45
  28. includes/class-xcloner-scheduler.php +276 -300
  29. includes/class-xcloner-settings.php +740 -628
  30. includes/class-xcloner.php +137 -121
  31. public/class-xcloner-public.php +7 -6
  32. vendor/composer/ClassLoader.php +8 -4
  33. vendor/composer/LICENSE +1 -1
  34. vendor/composer/autoload_files.php +4 -3
  35. vendor/composer/autoload_psr4.php +1 -1
  36. vendor/composer/autoload_static.php +8 -7
  37. vendor/composer/installed.json +854 -787
  38. vendor/defuse/php-encryption/.gitignore +11 -0
  39. vendor/defuse/php-encryption/.php_cs +60 -0
  40. vendor/defuse/php-encryption/LICENSE +21 -0
  41. vendor/defuse/php-encryption/README.md +102 -0
  42. vendor/defuse/php-encryption/bin/generate-defuse-key +14 -0
  43. vendor/defuse/php-encryption/composer.json +35 -0
  44. vendor/defuse/php-encryption/dist/Makefile +37 -0
  45. vendor/defuse/php-encryption/dist/box.json +25 -0
  46. vendor/defuse/php-encryption/dist/signingkey.asc +52 -0
  47. vendor/defuse/php-encryption/docs/CryptoDetails.md +64 -0
  48. vendor/defuse/php-encryption/docs/FAQ.md +51 -0
  49. vendor/defuse/php-encryption/docs/InstallingAndVerifying.md +53 -0
  50. vendor/defuse/php-encryption/docs/InternalDeveloperDocs.md +166 -0
  51. vendor/defuse/php-encryption/docs/Tutorial.md +314 -0
  52. vendor/defuse/php-encryption/docs/UpgradingFromV1.2.md +51 -0
  53. vendor/defuse/php-encryption/docs/classes/Crypto.md +280 -0
  54. vendor/defuse/php-encryption/docs/classes/File.md +486 -0
  55. vendor/defuse/php-encryption/docs/classes/Key.md +117 -0
  56. vendor/defuse/php-encryption/docs/classes/KeyProtectedByPassword.md +259 -0
  57. vendor/defuse/php-encryption/psalm.xml +12 -0
  58. vendor/defuse/php-encryption/src/Core.php +448 -0
  59. vendor/defuse/php-encryption/src/Crypto.php +445 -0
  60. vendor/defuse/php-encryption/src/DerivedKeys.php +50 -0
  61. vendor/defuse/php-encryption/src/Encoding.php +268 -0
  62. vendor/defuse/php-encryption/src/Exception/BadFormatException.php +7 -0
  63. vendor/defuse/php-encryption/src/Exception/CryptoException.php +7 -0
  64. vendor/defuse/php-encryption/src/Exception/EnvironmentIsBrokenException.php +7 -0
  65. vendor/defuse/php-encryption/src/Exception/IOException.php +7 -0
  66. vendor/defuse/php-encryption/src/Exception/WrongKeyOrModifiedCiphertextException.php +7 -0
  67. vendor/defuse/php-encryption/src/File.php +762 -0
  68. vendor/defuse/php-encryption/src/Key.php +94 -0
  69. vendor/defuse/php-encryption/src/KeyOrPassword.php +149 -0
  70. vendor/defuse/php-encryption/src/KeyProtectedByPassword.php +145 -0
  71. vendor/defuse/php-encryption/src/RuntimeTests.php +228 -0
  72. vendor/gliterd/backblaze-b2/CHANGELOG.md +22 -0
  73. vendor/gliterd/backblaze-b2/CONDUCT.md +74 -0
  74. vendor/gliterd/backblaze-b2/CONTRIBUTING.md +32 -0
  75. vendor/gliterd/backblaze-b2/LICENSE +21 -0
  76. vendor/gliterd/backblaze-b2/README.md +141 -0
  77. vendor/gliterd/backblaze-b2/composer.json +42 -0
  78. vendor/gliterd/backblaze-b2/phpunit.hhvm.xml +24 -0
  79. vendor/gliterd/backblaze-b2/phpunit.php +3 -0
  80. vendor/gliterd/backblaze-b2/phpunit.xml +29 -0
  81. vendor/gliterd/backblaze-b2/src/Bucket.php +42 -0
  82. vendor/gliterd/backblaze-b2/src/Client.php +479 -0
  83. vendor/gliterd/backblaze-b2/src/ErrorHandler.php +38 -0
  84. vendor/gliterd/backblaze-b2/src/Exceptions/B2Exception.php +7 -0
  85. vendor/gliterd/backblaze-b2/src/Exceptions/BadJsonException.php +7 -0
  86. vendor/gliterd/backblaze-b2/src/Exceptions/BadValueException.php +7 -0
  87. vendor/gliterd/backblaze-b2/src/Exceptions/BucketAlreadyExistsException.php +7 -0
  88. vendor/gliterd/backblaze-b2/src/Exceptions/BucketNotEmptyException.php +7 -0
  89. vendor/gliterd/backblaze-b2/src/Exceptions/FileNotPresentException.php +7 -0
  90. vendor/gliterd/backblaze-b2/src/Exceptions/NotFoundException.php +7 -0
  91. vendor/gliterd/backblaze-b2/src/Exceptions/ValidationException.php +7 -0
  92. vendor/gliterd/backblaze-b2/src/File.php +114 -0
  93. vendor/gliterd/backblaze-b2/src/Http/Client.php +37 -0
  94. vendor/gliterd/backblaze-b2/tests/ClientTest.php +113 -0
README.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: xcloner
3
  Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=AAPE8PLAE554S
4
  Tags: backup plugin, restore plugin, database backup, duplicate, full site backup, website cloner, wordpress backup, database restore, webdav, azure, ftp, sftp, amazon s3, dropbox, google drive, differential backup
5
  Requires at least: 3.0.1
6
- Tested up to: 4.9
7
  Stable tag: 4.0.8
8
 
9
  Backup your site, restore to any web location, send your backups to Dropbox, Amazon S3, Azure, FTP, SFTP, WebDAV, Google Drive with XCloner plugin.
@@ -112,6 +112,15 @@ Immigration Attorney Montana <a href="https://www.immigrationlawofmt.com" target
112
 
113
  == Changelog ==
114
 
 
 
 
 
 
 
 
 
 
115
  = 4.0.8 =
116
  * updated vendor library dependencies, AWS, phpseclib
117
  * TAR compression fix
3
  Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=AAPE8PLAE554S
4
  Tags: backup plugin, restore plugin, database backup, duplicate, full site backup, website cloner, wordpress backup, database restore, webdav, azure, ftp, sftp, amazon s3, dropbox, google drive, differential backup
5
  Requires at least: 3.0.1
6
+ Tested up to: 5.0
7
  Stable tag: 4.0.8
8
 
9
  Backup your site, restore to any web location, send your backups to Dropbox, Amazon S3, Azure, FTP, SFTP, WebDAV, Google Drive with XCloner plugin.
112
 
113
  == Changelog ==
114
 
115
+ = 4.0.9 =
116
+ * remote storage password encryption addon for database
117
+ * vendor cleanup packages
118
+ * database silent fail fix
119
+ * copyright changes
120
+ * jstree fix database display
121
+ * microtime float div fix
122
+ * manage backups data order fix
123
+
124
  = 4.0.8 =
125
  * updated vendor library dependencies, AWS, phpseclib
126
  * TAR compression fix
admin/class-xcloner-admin.php CHANGED
@@ -27,7 +27,7 @@ class Xcloner_Admin {
27
  *
28
  * @since 1.0.0
29
  * @access private
30
- * @var string $plugin_name The ID of this plugin.
31
  */
32
  private $plugin_name;
33
 
@@ -36,27 +36,28 @@ class Xcloner_Admin {
36
  *
37
  * @since 1.0.0
38
  * @access private
39
- * @var string $version The current version of this plugin.
40
  */
41
  private $version;
42
-
43
  private $xcloner_container;
 
44
  /**
45
  * Initialize the class and set its properties.
46
  *
47
  * @since 1.0.0
48
- * @param string $plugin_name The name of this plugin.
49
- * @param string $version The version of this plugin.
 
50
  */
51
- public function __construct( Xcloner $xcloner_container) {
52
 
53
- $this->plugin_name = $xcloner_container->get_plugin_name();
54
- $this->version = $xcloner_container->get_version();
55
- $this->xcloner_container = $xcloner_container;
56
  }
57
-
58
- public function get_xcloner_container()
59
- {
60
  return $this->xcloner_container;
61
  }
62
 
@@ -65,10 +66,11 @@ class Xcloner_Admin {
65
  *
66
  * @since 1.0.0
67
  */
68
- public function enqueue_styles($hook) {
69
-
70
- if(!stristr($hook, "page_".$this->plugin_name) || (isset($_GET['option']) and $_GET['option']=="com_cloner"))
71
  return;
 
72
 
73
  /**
74
  * This function is provided for demonstration purposes only.
@@ -82,12 +84,12 @@ class Xcloner_Admin {
82
  * class.
83
  */
84
 
85
- wp_enqueue_style( $this->plugin_name."_materialize", plugin_dir_url( __FILE__ ) . 'css/materialize.min.css', array(), $this->version, 'all' );
86
- wp_enqueue_style( $this->plugin_name."_materialize.clockpicker", plugin_dir_url( __FILE__ ) . 'css/materialize.clockpicker.css', array(), $this->version, 'all' );
87
- wp_enqueue_style( $this->plugin_name."_materialize.icons", '//fonts.googleapis.com/icon?family=Material+Icons', array(), $this->version, 'all' );
88
- wp_enqueue_style( $this->plugin_name."_jquery.datatables", plugin_dir_url( __FILE__ ) . 'css/jquery.dataTables.min.css', array(), $this->version, 'all' );
89
- wp_enqueue_style( $this->plugin_name."_jquery.datatables.responsive", plugin_dir_url( __FILE__ ) . 'css/responsive.dataTables.css', array(), $this->version, 'all' );
90
- wp_enqueue_style( $this->plugin_name."_jstree", dirname(plugin_dir_url( __FILE__ )) . '/vendor/vakata/jstree/dist/themes/default/style.min.css', array(), '3.3', 'all' );
91
  wp_enqueue_style( $this->plugin_name, plugin_dir_url( __FILE__ ) . 'css/xcloner-admin.css', array(), $this->version, 'all' );
92
 
93
  }
@@ -97,11 +99,12 @@ class Xcloner_Admin {
97
  *
98
  * @since 1.0.0
99
  */
100
- public function enqueue_scripts($hook) {
101
 
102
- if(!stristr($hook, "page_".$this->plugin_name))
103
  return;
104
-
 
105
  /**
106
  * This function is provided for demonstration purposes only.
107
  *
@@ -113,177 +116,175 @@ class Xcloner_Admin {
113
  * between the defined hooks and the functions defined in this
114
  * class.
115
  */
116
-
117
  add_thickbox();
118
- wp_enqueue_script('plugin-install');
119
- wp_enqueue_script('updates');
120
- wp_enqueue_script( $this->plugin_name."_materialize", plugin_dir_url( __FILE__ ) . 'js/materialize.min.js', array( 'jquery' ), $this->version, false );
121
- wp_enqueue_script( $this->plugin_name."_materialize.clockpicker", plugin_dir_url( __FILE__ ) . 'js/materialize.clockpicker.js', array( 'jquery' ), $this->version, false );
122
- wp_enqueue_script( $this->plugin_name."_jquery.datatables", plugin_dir_url( __FILE__ ) . 'js/jquery.dataTables.min.js', array( 'jquery' ), $this->version, false );
123
- wp_enqueue_script( $this->plugin_name."_jquery.datatables.respnsive", plugin_dir_url( __FILE__ ) . 'js/dataTables.responsive.js', array( 'jquery' ), $this->version, false );
124
- wp_enqueue_script( $this->plugin_name."_vakata", dirname(plugin_dir_url( __FILE__ )) . '/vendor/vakata/jstree/dist/jstree.min.js', array( 'jquery' ), '3.3', false );
125
- wp_enqueue_script( $this->plugin_name."_xcloner-backup-class", plugin_dir_url( __FILE__ ) . 'js/xcloner-backup-class.js', array( 'jquery' ), $this->version, false );
126
- wp_enqueue_script( $this->plugin_name."_xcloner-scheduler-class", plugin_dir_url( __FILE__ ) . 'js/xcloner-scheduler-class.js', array( 'jquery' ), $this->version, false );
127
- wp_enqueue_script( $this->plugin_name."_xcloner-restore-class", plugin_dir_url( __FILE__ ) . 'js/xcloner-restore-class.js', array( 'jquery' ), $this->version, false );
128
- wp_enqueue_script( $this->plugin_name."_xcloner-manage-backups-class", plugin_dir_url( __FILE__ ) . 'js/xcloner-manage-backups-class.js', array( 'jquery' ), $this->version, false );
129
- wp_enqueue_script( $this->plugin_name."_xcloner-remote-storage-class", plugin_dir_url( __FILE__ ) . 'js/xcloner-remote-storage-class.js', array( 'jquery' ), $this->version, false );
130
  wp_enqueue_script( $this->plugin_name, plugin_dir_url( __FILE__ ) . 'js/xcloner-admin.js', array( 'jquery' ), $this->version, false );
131
-
132
 
133
  }
134
-
135
- public function xcloner_init_page()
136
- {
137
- require_once("partials/xcloner_init_page.php");
138
-
139
  }
140
-
141
- public function xcloner_remote_storage_page()
142
- {
143
  $xcloner_sanitization = $this->get_xcloner_container()->get_xcloner_sanitization();
144
- $remote_storage = $this->get_xcloner_container()->get_xcloner_remote_storage();
145
-
146
-
147
- if(isset($_POST['action']))
148
- {
149
- $_POST['action'] = $xcloner_sanitization->sanitize_input_as_string($_POST['action']);
150
- $remote_storage->save($_POST['action']);
151
  }
152
-
153
- if(isset($_POST['authentification_code']) && $_POST['authentification_code'] != "")
154
- {
155
- $_POST['authentification_code'] = $xcloner_sanitization->sanitize_input_as_string($_POST['authentification_code']);
156
-
157
- $remote_storage->set_access_token($_POST['authentification_code']);
158
  }
159
-
160
- if(isset($_POST['connection_check']) && $_POST['connection_check'])
161
- {
162
- $remote_storage->check($_POST['action']);
163
  }
164
-
165
- require_once("partials/xcloner_remote_storage_page.php");
166
-
167
  }
168
-
169
- public function xcloner_scheduled_backups_page()
170
- {
171
  $requirements = $this->xcloner_container->get_xcloner_requirements();
172
-
173
- if(!$requirements->check_backup_ready_status())
174
- {
175
- require_once("partials/xcloner_init_page.php");
176
  return false;
177
  }
178
-
179
- require_once("partials/xcloner_scheduled_backups_page.php");
180
-
181
  }
182
-
183
- public function xcloner_manage_backups_page()
184
- {
185
- require_once("partials/xcloner_manage_backups_page.php");
186
-
187
  }
188
-
189
- public function xcloner_debugger_page()
190
- {
191
- require_once("partials/xcloner_console_page.php");
192
-
193
  }
194
-
195
- public function xcloner_restore_page()
196
- {
197
- require_once("partials/xcloner_restore_page.php");
198
-
199
  }
200
-
201
- public function xcloner_generate_backups_page()
202
- {
203
  $requirements = $this->xcloner_container->get_xcloner_requirements();
204
-
205
- if(!$requirements->check_backup_ready_status())
206
- {
207
- require_once("partials/xcloner_init_page.php");
208
  return false;
209
  }
210
-
211
- require_once("partials/xcloner_generate_backups_page.php");
 
212
  return;
213
  }
214
-
215
- public function xcloner_settings_page()
216
- {
217
  // check user capabilities
218
- if (!current_user_can('manage_options')) {
219
  return;
220
  }
221
-
222
  // add error/update messages
223
-
224
- // check if the user have submitted the settings
225
- // wordpress will add the "settings-updated" $_GET parameter to the url
226
- if (isset($_GET['settings-updated'])) {
227
- // add settings saved message with the class of "updated"
228
- add_settings_error('wporg_messages', 'wporg_message', __('Settings Saved', 'wporg'), 'updated');
229
- }
230
-
231
- // show error/update messages
232
- settings_errors('wporg_messages');
233
- ?>
234
-
235
- <?php
236
- $xcloner_sanitization = $this->get_xcloner_container()->get_xcloner_sanitization();
237
-
238
- if( isset( $_GET[ 'tab' ] ) ) {
239
- $active_tab = $xcloner_sanitization->sanitize_input_as_string($_GET[ 'tab' ]);
240
- } // end if
241
- else{
242
- $active_tab = "general_options";
243
- }
244
-
245
- ?>
246
- <h1><?= esc_html(get_admin_page_title()); ?></h1>
247
-
248
  <ul class="nav-tab-wrapper row">
249
- <li><a href="?page=xcloner_settings_page&tab=general_options" class="nav-tab col s12 m3 l2 <?php echo $active_tab == 'general_options' ? 'nav-tab-active' : ''; ?>"><?php echo __('General Options', 'xcloner-backup-and-restore')?></a></li>
250
- <li><a href="?page=xcloner_settings_page&tab=mysql_options" class="nav-tab col s12 m3 l2 <?php echo $active_tab == 'mysql_options' ? 'nav-tab-active' : ''; ?>"><?php echo __('Mysql Options', 'xcloner-backup-and-restore')?></a></li>
251
- <li><a href="?page=xcloner_settings_page&tab=system_options" class="nav-tab col s12 m3 l2 <?php echo $active_tab == 'system_options' ? 'nav-tab-active' : ''; ?>"><?php echo __('System Options', 'xcloner-backup-and-restore')?></a></li>
252
- <li><a href="?page=xcloner_settings_page&tab=cleanup_options" class="nav-tab col s12 m3 l2 <?php echo $active_tab == 'cleanup_options' ? 'nav-tab-active' : ''; ?>"><?php echo __('Cleanup Options', 'xcloner-backup-and-restore')?></a></li>
 
 
 
 
 
 
 
 
253
  </ul>
254
 
255
- <div class="wrap">
256
-
257
- <form action="options.php" method="post">
258
- <?php
259
-
260
- if( $active_tab == 'general_options' ) {
261
-
262
- settings_fields('xcloner_general_settings_group');
263
- do_settings_sections('xcloner_settings_page');
264
-
265
- }elseif( $active_tab == 'mysql_options' ) {
266
-
267
- settings_fields('xcloner_mysql_settings_group');
268
- do_settings_sections('xcloner_mysql_settings_page');
269
- }elseif( $active_tab == 'system_options' ) {
270
-
271
- settings_fields('xcloner_system_settings_group');
272
- do_settings_sections('xcloner_system_settings_page');
273
- }elseif( $active_tab == 'cleanup_options' ) {
274
-
275
- settings_fields('xcloner_cleanup_settings_group');
276
- do_settings_sections('xcloner_cleanup_settings_page');
277
  }
278
 
279
- // output save settings button
280
- submit_button('Save Settings');
281
- ?>
282
- </form>
 
 
 
283
 
284
- </div>
285
- <?php
286
-
287
  }
288
 
289
  }
27
  *
28
  * @since 1.0.0
29
  * @access private
30
+ * @var string $plugin_name The ID of this plugin.
31
  */
32
  private $plugin_name;
33
 
36
  *
37
  * @since 1.0.0
38
  * @access private
39
+ * @var string $version The current version of this plugin.
40
  */
41
  private $version;
42
+
43
  private $xcloner_container;
44
+
45
  /**
46
  * Initialize the class and set its properties.
47
  *
48
  * @since 1.0.0
49
+ *
50
+ * @param string $plugin_name The name of this plugin.
51
+ * @param string $version The version of this plugin.
52
  */
53
+ public function __construct( Xcloner $xcloner_container ) {
54
 
55
+ $this->plugin_name = $xcloner_container->get_plugin_name();
56
+ $this->version = $xcloner_container->get_version();
57
+ $this->xcloner_container = $xcloner_container;
58
  }
59
+
60
+ public function get_xcloner_container() {
 
61
  return $this->xcloner_container;
62
  }
63
 
66
  *
67
  * @since 1.0.0
68
  */
69
+ public function enqueue_styles( $hook ) {
70
+
71
+ if ( ! stristr( $hook, "page_" . $this->plugin_name ) || ( isset( $_GET['option'] ) and $_GET['option'] == "com_cloner" ) ) {
72
  return;
73
+ }
74
 
75
  /**
76
  * This function is provided for demonstration purposes only.
84
  * class.
85
  */
86
 
87
+ wp_enqueue_style( $this->plugin_name . "_materialize", plugin_dir_url( __FILE__ ) . 'css/materialize.min.css', array(), $this->version, 'all' );
88
+ wp_enqueue_style( $this->plugin_name . "_materialize.clockpicker", plugin_dir_url( __FILE__ ) . 'css/materialize.clockpicker.css', array(), $this->version, 'all' );
89
+ wp_enqueue_style( $this->plugin_name . "_materialize.icons", '//fonts.googleapis.com/icon?family=Material+Icons', array(), $this->version, 'all' );
90
+ wp_enqueue_style( $this->plugin_name . "_jquery.datatables", plugin_dir_url( __FILE__ ) . 'css/jquery.dataTables.min.css', array(), $this->version, 'all' );
91
+ wp_enqueue_style( $this->plugin_name . "_jquery.datatables.responsive", plugin_dir_url( __FILE__ ) . 'css/responsive.dataTables.css', array(), $this->version, 'all' );
92
+ wp_enqueue_style( $this->plugin_name . "_jstree", dirname( plugin_dir_url( __FILE__ ) ) . '/vendor/vakata/jstree/dist/themes/default/style.min.css', array(), '3.3', 'all' );
93
  wp_enqueue_style( $this->plugin_name, plugin_dir_url( __FILE__ ) . 'css/xcloner-admin.css', array(), $this->version, 'all' );
94
 
95
  }
99
  *
100
  * @since 1.0.0
101
  */
102
+ public function enqueue_scripts( $hook ) {
103
 
104
+ if ( ! stristr( $hook, "page_" . $this->plugin_name ) ) {
105
  return;
106
+ }
107
+
108
  /**
109
  * This function is provided for demonstration purposes only.
110
  *
116
  * between the defined hooks and the functions defined in this
117
  * class.
118
  */
119
+
120
  add_thickbox();
121
+ wp_enqueue_script( 'plugin-install' );
122
+ wp_enqueue_script( 'updates' );
123
+ wp_enqueue_script( $this->plugin_name . "_materialize", plugin_dir_url( __FILE__ ) . 'js/materialize.min.js', array( 'jquery' ), $this->version, false );
124
+ wp_enqueue_script( $this->plugin_name . "_materialize.clockpicker", plugin_dir_url( __FILE__ ) . 'js/materialize.clockpicker.js', array( 'jquery' ), $this->version, false );
125
+ wp_enqueue_script( $this->plugin_name . "_jquery.datatables", plugin_dir_url( __FILE__ ) . 'js/jquery.dataTables.min.js', array( 'jquery' ), $this->version, false );
126
+ wp_enqueue_script( $this->plugin_name . "_jquery.datatables.respnsive", plugin_dir_url( __FILE__ ) . 'js/dataTables.responsive.js', array( 'jquery' ), $this->version, false );
127
+ wp_enqueue_script( $this->plugin_name . "_vakata", dirname( plugin_dir_url( __FILE__ ) ) . '/vendor/vakata/jstree/dist/jstree.min.js', array( 'jquery' ), '3.3', false );
128
+ wp_enqueue_script( $this->plugin_name . "_xcloner-backup-class", plugin_dir_url( __FILE__ ) . 'js/xcloner-backup-class.js', array( 'jquery' ), $this->version, false );
129
+ wp_enqueue_script( $this->plugin_name . "_xcloner-scheduler-class", plugin_dir_url( __FILE__ ) . 'js/xcloner-scheduler-class.js', array( 'jquery' ), $this->version, false );
130
+ wp_enqueue_script( $this->plugin_name . "_xcloner-restore-class", plugin_dir_url( __FILE__ ) . 'js/xcloner-restore-class.js', array( 'jquery' ), $this->version, false );
131
+ wp_enqueue_script( $this->plugin_name . "_xcloner-manage-backups-class", plugin_dir_url( __FILE__ ) . 'js/xcloner-manage-backups-class.js', array( 'jquery' ), $this->version, false );
132
+ wp_enqueue_script( $this->plugin_name . "_xcloner-remote-storage-class", plugin_dir_url( __FILE__ ) . 'js/xcloner-remote-storage-class.js', array( 'jquery' ), $this->version, false );
133
  wp_enqueue_script( $this->plugin_name, plugin_dir_url( __FILE__ ) . 'js/xcloner-admin.js', array( 'jquery' ), $this->version, false );
134
+
135
 
136
  }
137
+
138
+ public function xcloner_init_page() {
139
+ require_once( "partials/xcloner_init_page.php" );
140
+
 
141
  }
142
+
143
+ public function xcloner_remote_storage_page() {
 
144
  $xcloner_sanitization = $this->get_xcloner_container()->get_xcloner_sanitization();
145
+ $remote_storage = $this->get_xcloner_container()->get_xcloner_remote_storage();
146
+
147
+
148
+ if ( isset( $_POST['action'] ) ) {
149
+ $_POST['action'] = $xcloner_sanitization->sanitize_input_as_string( $_POST['action'] );
150
+ $remote_storage->save( $_POST['action'] );
 
151
  }
152
+
153
+ if ( isset( $_POST['authentification_code'] ) && $_POST['authentification_code'] != "" ) {
154
+ $_POST['authentification_code'] = $xcloner_sanitization->sanitize_input_as_string( $_POST['authentification_code'] );
155
+
156
+ $remote_storage->set_access_token( $_POST['authentification_code'] );
 
157
  }
158
+
159
+ if ( isset( $_POST['connection_check'] ) && $_POST['connection_check'] ) {
160
+ $remote_storage->check( $_POST['action'] );
 
161
  }
162
+
163
+ require_once( "partials/xcloner_remote_storage_page.php" );
164
+
165
  }
166
+
167
+ public function xcloner_scheduled_backups_page() {
 
168
  $requirements = $this->xcloner_container->get_xcloner_requirements();
169
+
170
+ if ( ! $requirements->check_backup_ready_status() ) {
171
+ require_once( "partials/xcloner_init_page.php" );
172
+
173
  return false;
174
  }
175
+
176
+ require_once( "partials/xcloner_scheduled_backups_page.php" );
177
+
178
  }
179
+
180
+ public function xcloner_manage_backups_page() {
181
+ require_once( "partials/xcloner_manage_backups_page.php" );
182
+
 
183
  }
184
+
185
+ public function xcloner_debugger_page() {
186
+ require_once( "partials/xcloner_console_page.php" );
187
+
 
188
  }
189
+
190
+ public function xcloner_restore_page() {
191
+ require_once( "partials/xcloner_restore_page.php" );
192
+
 
193
  }
194
+
195
+ public function xcloner_generate_backups_page() {
 
196
  $requirements = $this->xcloner_container->get_xcloner_requirements();
197
+
198
+ if ( ! $requirements->check_backup_ready_status() ) {
199
+ require_once( "partials/xcloner_init_page.php" );
200
+
201
  return false;
202
  }
203
+
204
+ require_once( "partials/xcloner_generate_backups_page.php" );
205
+
206
  return;
207
  }
208
+
209
+ public function xcloner_settings_page() {
 
210
  // check user capabilities
211
+ if ( ! current_user_can( 'manage_options' ) ) {
212
  return;
213
  }
214
+
215
  // add error/update messages
216
+
217
+ // check if the user have submitted the settings
218
+ // wordpress will add the "settings-updated" $_GET parameter to the url
219
+ if ( isset( $_GET['settings-updated'] ) ) {
220
+ // add settings saved message with the class of "updated"
221
+ add_settings_error( 'wporg_messages', 'wporg_message', __( 'Settings Saved', 'wporg' ), 'updated' );
222
+ }
223
+
224
+ // show error/update messages
225
+ settings_errors( 'wporg_messages' );
226
+ ?>
227
+
228
+ <?php
229
+ $xcloner_sanitization = $this->get_xcloner_container()->get_xcloner_sanitization();
230
+
231
+ if ( isset( $_GET['tab'] ) ) {
232
+ $active_tab = $xcloner_sanitization->sanitize_input_as_string( $_GET['tab'] );
233
+ } // end if
234
+ else {
235
+ $active_tab = "general_options";
236
+ }
237
+
238
+ ?>
239
+ <h1><?= esc_html( get_admin_page_title() ); ?></h1>
240
+
241
  <ul class="nav-tab-wrapper row">
242
+ <li><a href="?page=xcloner_settings_page&tab=general_options"
243
+ class="nav-tab col s12 m3 l2 <?php echo $active_tab == 'general_options' ? 'nav-tab-active' : ''; ?>"><?php echo __( 'General Options', 'xcloner-backup-and-restore' ) ?></a>
244
+ </li>
245
+ <li><a href="?page=xcloner_settings_page&tab=mysql_options"
246
+ class="nav-tab col s12 m3 l2 <?php echo $active_tab == 'mysql_options' ? 'nav-tab-active' : ''; ?>"><?php echo __( 'Mysql Options', 'xcloner-backup-and-restore' ) ?></a>
247
+ </li>
248
+ <li><a href="?page=xcloner_settings_page&tab=system_options"
249
+ class="nav-tab col s12 m3 l2 <?php echo $active_tab == 'system_options' ? 'nav-tab-active' : ''; ?>"><?php echo __( 'System Options', 'xcloner-backup-and-restore' ) ?></a>
250
+ </li>
251
+ <li><a href="?page=xcloner_settings_page&tab=cleanup_options"
252
+ class="nav-tab col s12 m3 l2 <?php echo $active_tab == 'cleanup_options' ? 'nav-tab-active' : ''; ?>"><?php echo __( 'Cleanup Options', 'xcloner-backup-and-restore' ) ?></a>
253
+ </li>
254
  </ul>
255
 
256
+ <div class="wrap">
257
+
258
+ <form action="options.php" method="post">
259
+ <?php
260
+
261
+ if ( $active_tab == 'general_options' ) {
262
+
263
+ settings_fields( 'xcloner_general_settings_group' );
264
+ do_settings_sections( 'xcloner_settings_page' );
265
+
266
+ } elseif ( $active_tab == 'mysql_options' ) {
267
+
268
+ settings_fields( 'xcloner_mysql_settings_group' );
269
+ do_settings_sections( 'xcloner_mysql_settings_page' );
270
+ } elseif ( $active_tab == 'system_options' ) {
271
+
272
+ settings_fields( 'xcloner_system_settings_group' );
273
+ do_settings_sections( 'xcloner_system_settings_page' );
274
+ } elseif ( $active_tab == 'cleanup_options' ) {
275
+
276
+ settings_fields( 'xcloner_cleanup_settings_group' );
277
+ do_settings_sections( 'xcloner_cleanup_settings_page' );
278
  }
279
 
280
+ // output save settings button
281
+ submit_button( 'Save Settings' );
282
+ ?>
283
+ </form>
284
+
285
+ </div>
286
+ <?php
287
 
 
 
 
288
  }
289
 
290
  }
admin/css/xcloner-admin.css CHANGED
@@ -6,8 +6,9 @@
6
 
7
  html {
8
  font-family: GillSans, Calibri, Trebuchet, sans-serif;
9
- }
10
- /*
 
11
  @font-face {
12
  font-family: 'Material Icons';
13
  font-style: normal;
@@ -20,139 +21,135 @@ html {
20
  url(../fontsMaterialIcons-Regular.ttf) format('truetype');
21
  }*/
22
 
23
-
24
-
25
- h1{
26
- font-size: 23px;
27
  }
28
 
29
- h2{
30
- font-size: 18px;
31
  }
32
 
33
- .input-field{
34
- margin-top: 0px;
35
  }
36
 
37
  td, th {
38
- padding-top: 0px !important;
39
  }
40
 
41
  .form-table th {
42
- padding-top: 10px !important;
43
  }
44
 
45
  a.nav-tab.col {
46
  padding: 10px;
47
  }
48
 
49
-
50
- span.shorten_string{
51
- cursor: pointer;
52
  }
53
 
54
- .card-panel{
55
- min-height: 60px;
56
  }
57
 
58
-
59
- .dashboard .additional_system_info{
60
- display: none;
61
  }
62
 
63
- .nav-tab-wrapper li{
64
- margin-bottom: 0px;
65
  }
66
 
67
- .nav-tab-wrapper-content .tab-content{
68
- display: none;
69
  }
70
 
71
- .nav-tab-wrapper-content .tab-content.active{
72
- display: block;
73
  }
74
 
75
  .input-field label.active {
76
- font-size: 1rem;
77
  }
78
 
79
- .xcloner-debugger .console{
80
- height: 450px;
81
- min-height: 300px;
82
- overflow: auto;
83
  }
84
 
85
- #error_modal textarea{
86
- height: 150px;
87
  }
88
 
89
- #error_modal .msg{
90
- font-size: 14px;
91
  }
92
 
93
- #generate_backup .backup-status, #generate_backup ul.backup-status > li{
94
- display: none;
95
  }
96
 
97
- ul.backup-name{
98
- margin-top: 1.78rem;
99
  }
100
 
101
- #generate_backup .status-body ul.backup-name li, #generate_backup ul.logged-databases li{
102
- font-weight: bold;
103
  }
104
 
105
  #generate_backup .backup-done .collapsible-body {
106
- margin-top: 1.83rem;
107
  }
108
 
109
- #generate_backup .status-body > ul, #generate_backup .status-body ul.logged-tables{
110
- margin: 5px 10px;
111
- max-height: 200px;
112
  overflow-y: auto;
113
- margin-top: 1.78rem;
114
  }
115
 
116
- #generate_backup .action-buttons .cancel,
117
- #generate_backup .action-buttons .restart{
118
- display: none;
119
- }
120
 
121
- .modal-footer .modal-close.btn-flat{
122
- color: #fff;
123
  }
124
 
125
- .collapsible-body{
126
- padding: 0px 10px;
127
  }
128
 
129
- .select-wrapper+label {
130
  font-size: 1rem;
131
  }
132
 
133
- #schedule_backup .server-time h2{
134
- color: #fff;
135
  }
136
 
137
- #schedule_backup_success{
138
- display: none;
139
  }
140
 
141
- #scheduled_backups_wrapper .dataTables_length,
142
- #manage_backups_wrapper .dataTables_length{
143
- display: none;
144
  }
145
 
146
- table#scheduled_backups{
147
- font-size: 16px;
148
  }
149
 
150
- #scheduled_backups td, #scheduled_backups th{
151
- padding-top: 8px !important;
152
  }
153
 
154
- #scheduled_backups i.status{
155
- color: #fff;
156
  }
157
 
158
  .site-backup_page_xcloner_scheduled_backups_page #server_time h2 {
@@ -161,236 +158,239 @@ table#scheduled_backups{
161
  padding: 10px 10px 5px 10px;
162
  }
163
 
164
- textarea.materialize-textarea{
165
- overflow: auto;
166
- resize: auto;
167
  }
168
 
169
  #scheduled_backups .edit, #scheduled_backups .status.active, #scheduled_backups .delete,
170
  #manage_backups .download, #manage_backups .cloud-upload, #manage_backups .delete, #manage_backups .list-backup-content,
171
- .backup-done .download, .backup-done .cloud-upload, .backup-done .delete, .backup-done .list-backup-content,
172
- #manage_backups .copy-remote-to-local,#manage_backups .expand-multipart{
173
- color: #4db6ac;
174
  }
175
 
176
- #scheduled_backups .status.inactive{
177
- color: #d32f2f ;
178
  }
179
 
180
- table.dataTable thead th, table.dataTable tfoot th{
181
- padding-left: 10px;
182
  }
183
 
184
- table.dataTable tr.odd { background-color: #fff; }
185
- table.dataTable tr.even { background-color: #f3f3f3; }
 
186
 
187
- #manage_backups ul.multipart{
188
- margin-left: 20px;
189
- display: none;
190
  }
191
 
192
- #manage_backups ul.multipart li{
193
- padding: 5px;
194
- list-style-type: square;
195
  }
196
-
197
- a.expand-multipart.remove{
198
- display: none;
 
199
  }
200
 
201
- .remote-storage .label label{
202
- font-size:16px;
203
  }
204
- .remote-storage .label{
205
- padding-top: 25px;
 
206
  }
207
 
208
- .remote-storage .collapsible-header{
209
- padding: 2px 5px;
210
  }
211
 
 
 
 
212
 
213
- #manage_backups td.checkbox{
214
- vertical-align: top;
215
  }
216
 
217
- #remote_storage_modal{
218
- min-height: 350px;
219
  }
220
 
221
- #remote_storage_modal .label label{
222
- font-size: 16px;
223
  }
224
 
225
- #remote_storage_modal .label{
226
- padding-top: 25px;
227
  }
228
 
229
- #remote_storage_modal .status{
230
- display: none;
231
  }
232
 
233
- #remote_storage_modal .status-text.error{
234
- color: red;
235
  }
236
 
237
- #remote_storage_modal .status-text{
238
- font-weight: bold;
239
  }
240
 
241
- #backup-status h5{
242
  font-size: 18px;
243
  }
244
 
245
- #backup-status .row .item .title{
246
  width: 100px;
247
  display: inline-block;
248
  font-weight: bold;
249
  }
250
 
251
- .xcloner-restore li.steps{
252
- display: none;
253
  }
254
 
255
- .xcloner-restore .steps.show{
256
- display: block;
257
  }
258
 
259
- .xcloner-restore li .collapsible-body{
260
- padding: 25px 10px 15px 10px;
261
  }
262
 
263
- .xcloner-restore select.browser-default{
264
- height: 36px;
265
- font-size: 18px;
266
  }
267
 
268
- .xcloner-restore .steps .progress{
269
- display: none;
270
  }
271
 
272
- .xcloner-restore .status > div{
273
- margin: 10px 0px 0px 0px;
274
  }
275
 
276
- .xcloner-restore .toggler{
277
- display: inline-block;
278
  }
279
 
280
- .xcloner-restore .toggler .normal{
281
- display: block;
282
  }
283
 
284
- .xcloner-restore .toggler .cancel{
285
- display: none;
286
  }
287
 
288
- .xcloner-restore .toggler.cancel .normal{
289
- display: none;
290
  }
291
 
292
- .xcloner-restore .toggler.cancel .cancel{
293
- display: block;
294
  }
295
 
296
- .xcloner-restore ul.text-steps li{
297
- list-style-type: decimal;
298
  }
299
 
300
- .xcloner-restore ul.text-steps li.warning{
301
- color: red;
302
  }
303
 
304
- .xcloner-restore ul.text-steps ul li{
305
- list-style-type: disc;
306
  }
307
 
308
- .xcloner-restore ul.text-steps ul{
309
- margin: 10px;
310
  }
311
 
312
- .xcloner-restore ul.text-steps{
313
- margin-left: 20px;
314
  }
315
 
316
- .xcloner-restore .restore-remote-backup-step .files-list{
317
- max-height: 250px;
318
  overflow: auto;
319
  margin: 10px 5px;
320
  }
321
 
322
- #backup_cotent_modal .modal-content .files-list span{
323
- cursor: pointer;
324
  }
325
 
326
- .xcloner-restore .query-box{
327
- display: none;
328
  }
329
 
330
- .xcloner-restore .query-box .query-list{
331
- height: 10rem;
332
  }
333
 
334
- .xcloner-restore .restore-remote-database-step h5{
335
- margin-top: -10px;
336
  margin-bottom: 25px;
337
  }
338
 
339
-
340
- .regex_pattern{
341
- cursor: pointer;
342
- font-weight: bold;
343
  }
344
 
345
- .jstree-icon.jstree-checkbox.jstree-checkbox-disabled{
346
- opacity: 0.3;
347
  }
348
 
349
- #xcloner_regex_exclude{
350
- height: 5rem;
351
  }
352
 
353
  ul.xcloner_regex_exclude_limit li:nth-of-type(n+2) {
354
- display:none;
355
  }
356
 
357
- .xcloner-restore .btn.waves-effect.waves-light.grey{
358
- margin-top: -2px;
359
  }
360
 
361
- .xcloner-restore #xcloner_restore_finish{
362
- display: none;
363
  }
364
 
365
- ul.files-list li{
366
- padding: 0px;
367
- white-space: pre;
368
  }
369
 
370
- #manage_backups_wrapper #manage_backups_filter{
371
- min-width: 250px;
372
  }
373
 
374
- #generate_backup_form .progress, .xcloner-restore .progress{
375
- width: 100% !important;
376
  height: 4px !important;
377
  }
378
 
379
- i.backup_warning{
380
- color: red;
381
  }
382
 
383
- .col.remote-storage-selection{
384
- padding-top: 20px;
385
  }
386
 
387
  .remote-storage #authentification_code {
388
- display: none;
389
  }
390
 
391
-
392
- @media only screen and (min-width: 993px){
393
- .dashboard .backup-ready{
394
- float: right;
395
- }
396
  }
6
 
7
  html {
8
  font-family: GillSans, Calibri, Trebuchet, sans-serif;
9
+ }
10
+
11
+ /*
12
  @font-face {
13
  font-family: 'Material Icons';
14
  font-style: normal;
21
  url(../fontsMaterialIcons-Regular.ttf) format('truetype');
22
  }*/
23
 
24
+ h1 {
25
+ font-size: 23px;
 
 
26
  }
27
 
28
+ h2 {
29
+ font-size: 18px;
30
  }
31
 
32
+ .input-field {
33
+ margin-top: 0px;
34
  }
35
 
36
  td, th {
37
+ padding-top: 0px !important;
38
  }
39
 
40
  .form-table th {
41
+ padding-top: 10px !important;
42
  }
43
 
44
  a.nav-tab.col {
45
  padding: 10px;
46
  }
47
 
48
+ span.shorten_string {
49
+ cursor: pointer;
 
50
  }
51
 
52
+ .card-panel {
53
+ min-height: 60px;
54
  }
55
 
56
+ .dashboard .additional_system_info {
57
+ display: none;
 
58
  }
59
 
60
+ .nav-tab-wrapper li {
61
+ margin-bottom: 0px;
62
  }
63
 
64
+ .nav-tab-wrapper-content .tab-content {
65
+ display: none;
66
  }
67
 
68
+ .nav-tab-wrapper-content .tab-content.active {
69
+ display: block;
70
  }
71
 
72
  .input-field label.active {
73
+ font-size: 1rem;
74
  }
75
 
76
+ .xcloner-debugger .console {
77
+ height: 450px;
78
+ min-height: 300px;
79
+ overflow: auto;
80
  }
81
 
82
+ #error_modal textarea {
83
+ height: 150px;
84
  }
85
 
86
+ #error_modal .msg {
87
+ font-size: 14px;
88
  }
89
 
90
+ #generate_backup .backup-status, #generate_backup ul.backup-status > li {
91
+ display: none;
92
  }
93
 
94
+ ul.backup-name {
95
+ margin-top: 1.78rem;
96
  }
97
 
98
+ #generate_backup .status-body ul.backup-name li, #generate_backup ul.logged-databases li {
99
+ font-weight: bold;
100
  }
101
 
102
  #generate_backup .backup-done .collapsible-body {
103
+ margin-top: 1.83rem;
104
  }
105
 
106
+ #generate_backup .status-body > ul, #generate_backup .status-body ul.logged-tables {
107
+ margin: 5px 10px;
108
+ max-height: 200px;
109
  overflow-y: auto;
110
+ margin-top: 1.78rem;
111
  }
112
 
113
+ #generate_backup .action-buttons .cancel,
114
+ #generate_backup .action-buttons .restart {
115
+ display: none;
116
+ }
117
 
118
+ .modal-footer .modal-close.btn-flat {
119
+ color: #fff;
120
  }
121
 
122
+ .collapsible-body {
123
+ padding: 0px 10px;
124
  }
125
 
126
+ .select-wrapper + label {
127
  font-size: 1rem;
128
  }
129
 
130
+ #schedule_backup .server-time h2 {
131
+ color: #fff;
132
  }
133
 
134
+ #schedule_backup_success {
135
+ display: none;
136
  }
137
 
138
+ #scheduled_backups_wrapper .dataTables_length,
139
+ #manage_backups_wrapper .dataTables_length {
140
+ display: none;
141
  }
142
 
143
+ table#scheduled_backups {
144
+ font-size: 16px;
145
  }
146
 
147
+ #scheduled_backups td, #scheduled_backups th {
148
+ padding-top: 8px !important;
149
  }
150
 
151
+ #scheduled_backups i.status {
152
+ color: #fff;
153
  }
154
 
155
  .site-backup_page_xcloner_scheduled_backups_page #server_time h2 {
158
  padding: 10px 10px 5px 10px;
159
  }
160
 
161
+ textarea.materialize-textarea {
162
+ overflow: auto;
163
+ resize: auto;
164
  }
165
 
166
  #scheduled_backups .edit, #scheduled_backups .status.active, #scheduled_backups .delete,
167
  #manage_backups .download, #manage_backups .cloud-upload, #manage_backups .delete, #manage_backups .list-backup-content,
168
+ .backup-done .download, .backup-done .cloud-upload, .backup-done .delete, .backup-done .list-backup-content,
169
+ #manage_backups .copy-remote-to-local, #manage_backups .expand-multipart {
170
+ color: #4db6ac;
171
  }
172
 
173
+ #scheduled_backups .status.inactive {
174
+ color: #d32f2f;
175
  }
176
 
177
+ table.dataTable thead th, table.dataTable tfoot th {
178
+ padding-left: 10px;
179
  }
180
 
181
+ table.dataTable tr.odd {
182
+ background-color: #fff;
183
+ }
184
 
185
+ table.dataTable tr.even {
186
+ background-color: #f3f3f3;
 
187
  }
188
 
189
+ #manage_backups ul.multipart {
190
+ margin-left: 20px;
191
+ display: none;
192
  }
193
+
194
+ #manage_backups ul.multipart li {
195
+ padding: 5px;
196
+ list-style-type: square;
197
  }
198
 
199
+ a.expand-multipart.remove {
200
+ display: none;
201
  }
202
+
203
+ .remote-storage .label label {
204
+ font-size: 16px;
205
  }
206
 
207
+ .remote-storage .label {
208
+ padding-top: 25px;
209
  }
210
 
211
+ .remote-storage .collapsible-header {
212
+ padding: 2px 5px;
213
+ }
214
 
215
+ #manage_backups td.checkbox {
216
+ vertical-align: top;
217
  }
218
 
219
+ #remote_storage_modal {
220
+ min-height: 350px;
221
  }
222
 
223
+ #remote_storage_modal .label label {
224
+ font-size: 16px;
225
  }
226
 
227
+ #remote_storage_modal .label {
228
+ padding-top: 25px;
229
  }
230
 
231
+ #remote_storage_modal .status {
232
+ display: none;
233
  }
234
 
235
+ #remote_storage_modal .status-text.error {
236
+ color: red;
237
  }
238
 
239
+ #remote_storage_modal .status-text {
240
+ font-weight: bold;
241
  }
242
 
243
+ #backup-status h5 {
244
  font-size: 18px;
245
  }
246
 
247
+ #backup-status .row .item .title {
248
  width: 100px;
249
  display: inline-block;
250
  font-weight: bold;
251
  }
252
 
253
+ .xcloner-restore li.steps {
254
+ display: none;
255
  }
256
 
257
+ .xcloner-restore .steps.show {
258
+ display: block;
259
  }
260
 
261
+ .xcloner-restore li .collapsible-body {
262
+ padding: 25px 10px 15px 10px;
263
  }
264
 
265
+ .xcloner-restore select.browser-default {
266
+ height: 36px;
267
+ font-size: 18px;
268
  }
269
 
270
+ .xcloner-restore .steps .progress {
271
+ display: none;
272
  }
273
 
274
+ .xcloner-restore .status > div {
275
+ margin: 10px 0px 0px 0px;
276
  }
277
 
278
+ .xcloner-restore .toggler {
279
+ display: inline-block;
280
  }
281
 
282
+ .xcloner-restore .toggler .normal {
283
+ display: block;
284
  }
285
 
286
+ .xcloner-restore .toggler .cancel {
287
+ display: none;
288
  }
289
 
290
+ .xcloner-restore .toggler.cancel .normal {
291
+ display: none;
292
  }
293
 
294
+ .xcloner-restore .toggler.cancel .cancel {
295
+ display: block;
296
  }
297
 
298
+ .xcloner-restore ul.text-steps li {
299
+ list-style-type: decimal;
300
  }
301
 
302
+ .xcloner-restore ul.text-steps li.warning {
303
+ color: red;
304
  }
305
 
306
+ .xcloner-restore ul.text-steps ul li {
307
+ list-style-type: disc;
308
  }
309
 
310
+ .xcloner-restore ul.text-steps ul {
311
+ margin: 10px;
312
  }
313
 
314
+ .xcloner-restore ul.text-steps {
315
+ margin-left: 20px;
316
  }
317
 
318
+ .xcloner-restore .restore-remote-backup-step .files-list {
319
+ max-height: 250px;
320
  overflow: auto;
321
  margin: 10px 5px;
322
  }
323
 
324
+ #backup_cotent_modal .modal-content .files-list span {
325
+ cursor: pointer;
326
  }
327
 
328
+ .xcloner-restore .query-box {
329
+ display: none;
330
  }
331
 
332
+ .xcloner-restore .query-box .query-list {
333
+ height: 10rem;
334
  }
335
 
336
+ .xcloner-restore .restore-remote-database-step h5 {
337
+ margin-top: -10px;
338
  margin-bottom: 25px;
339
  }
340
 
341
+ .regex_pattern {
342
+ cursor: pointer;
343
+ font-weight: bold;
 
344
  }
345
 
346
+ .jstree-icon.jstree-checkbox.jstree-checkbox-disabled {
347
+ opacity: 0.3;
348
  }
349
 
350
+ #xcloner_regex_exclude {
351
+ height: 5rem;
352
  }
353
 
354
  ul.xcloner_regex_exclude_limit li:nth-of-type(n+2) {
355
+ display: none;
356
  }
357
 
358
+ .xcloner-restore .btn.waves-effect.waves-light.grey {
359
+ margin-top: -2px;
360
  }
361
 
362
+ .xcloner-restore #xcloner_restore_finish {
363
+ display: none;
364
  }
365
 
366
+ ul.files-list li {
367
+ padding: 0px;
368
+ white-space: pre;
369
  }
370
 
371
+ #manage_backups_wrapper #manage_backups_filter {
372
+ min-width: 250px;
373
  }
374
 
375
+ #generate_backup_form .progress, .xcloner-restore .progress {
376
+ width: 100% !important;
377
  height: 4px !important;
378
  }
379
 
380
+ i.backup_warning {
381
+ color: red;
382
  }
383
 
384
+ .col.remote-storage-selection {
385
+ padding-top: 20px;
386
  }
387
 
388
  .remote-storage #authentification_code {
389
+ display: none;
390
  }
391
 
392
+ @media only screen and (min-width: 993px) {
393
+ .dashboard .backup-ready {
394
+ float: right;
395
+ }
 
396
  }
admin/js/xcloner-admin.js CHANGED
@@ -1,126 +1,119 @@
1
- (function( $ ) {
2
- 'use strict';
3
-
4
- jQuery(document).ready(function(){
5
-
6
- jQuery("span.shorten_string").click(function(){
7
- jQuery(this).toggleClass("full");
8
- doShortText(jQuery(this));
9
- })
10
-
11
- jQuery("span.shorten_string").each(function(){
12
- doShortText(jQuery(this));
13
- })
14
-
15
- jQuery("#xcloner_regex_exclude").on("focus", function(){
16
- jQuery("ul.xcloner_regex_exclude_limit li").fadeIn();
17
- })
18
-
19
- jQuery(".regex_pattern").on("click", function(){
20
- jQuery(this).select();
21
- })
22
-
23
- jQuery(".btn.system_info_toggle").on("click", function(){
24
- jQuery(".additional_system_info").toggle();
25
- })
26
-
27
- jQuery("a.download-logger").on("click", function(e){
28
- var xcloner_manage_backups = new Xcloner_Manage_Backups();
29
-
30
- var hash = jQuery(this).attr('href');
31
- var id = hash.substr(1)
32
-
33
- if(id)
34
- {
35
- xcloner_manage_backups.download_backup_by_name(id);
36
- }
37
-
38
- e.preventDefault();
39
- })
40
-
41
- jQuery(".nav-tab-wrapper.content li").on("click", function(e){
42
- jQuery(".nav-tab-wrapper li a").removeClass("nav-tab-active");
43
- jQuery(this).find('a').addClass("nav-tab-active");
44
- jQuery(".nav-tab-wrapper-content .tab-content").removeClass('active');
45
- jQuery(".nav-tab-wrapper-content "+jQuery(this).find('a').attr('href')).addClass('active');
46
-
47
- e.preventDefault();
48
-
49
- location.hash = jQuery(this).find('a').attr('href')+"_hash";
50
-
51
- })
52
-
53
- var hash = window.location.hash;
54
- if(hash){
55
- next_tab(hash.replace("_hash",""));
56
- }
57
- })
58
-
59
- })( jQuery );
60
 
 
61
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
 
63
 
64
  //jQuery( document ).ajaxError(function(err, request) {
65
- //show_ajax_error("dd", "dd12", request)
66
  //});
67
 
68
- function next_tab(hash){
69
- jQuery(".nav-tab-wrapper").find("li a[href='"+hash+"']").trigger('click');
70
- location.hash = hash;
71
- }
72
-
73
- function doShortText(elem)
74
- {
75
- if(elem.hasClass("full")){
76
- elem.text(elem.attr("data-text"));
77
- return;
78
- }
79
- var text = elem.text()
80
- var text_lenght = text.length;
81
- var first = text.substr(0, 10);
82
- var last = text.substr(text_lenght-20, text_lenght);
83
-
84
- elem.attr("data-text", text).text(first+"..."+last);
85
  }
86
 
87
  /** global: xcloner_backup */
88
- function show_ajax_error(title, msg, json){
89
-
90
- //var json = jQuery.parseJSON( body )
91
-
92
- if(typeof xcloner_backup !== 'undefined')
93
- {
94
- xcloner_backup.cancel_backup();
95
- }
96
-
97
- if(json.responseText)
98
- {
99
- msg = msg+": "+json.responseText;
100
- }
101
-
102
- jQuery("#error_modal .title").text(title);
103
- jQuery("#error_modal .msg").text(msg);
104
-
105
- if(json.status)
106
- {
107
- jQuery("#error_modal .status").text(json.status+" "+json.statusText);
108
- }
109
-
110
- jQuery("#error_modal .body").text(JSON.stringify(json));
111
- var error_modal = jQuery("#error_modal").modal();
112
- error_modal.modal('open');
113
  }
114
 
115
  var ID = function () {
116
- // Math.random should be unique because of its seeding algorithm.
117
- // Convert it to base 36 (numbers + letters), and grab the first 9 characters
118
- // after the decimal.
119
- return '_' + Math.random().toString(36).substr(2, 9);
120
  };
121
 
122
 
123
- var getUrlParam = function(name) {
124
  return (location.search.split(name + '=')[1] || '').split('&')[0];
125
  }
126
 
1
+ (function ($) {
2
+ 'use strict';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
 
4
+ jQuery(document).ready(function () {
5
 
6
+ jQuery("span.shorten_string").click(function () {
7
+ jQuery(this).toggleClass("full");
8
+ doShortText(jQuery(this));
9
+ })
10
+
11
+ jQuery("span.shorten_string").each(function () {
12
+ doShortText(jQuery(this));
13
+ })
14
+
15
+ jQuery("#xcloner_regex_exclude").on("focus", function () {
16
+ jQuery("ul.xcloner_regex_exclude_limit li").fadeIn();
17
+ })
18
+
19
+ jQuery(".regex_pattern").on("click", function () {
20
+ jQuery(this).select();
21
+ })
22
+
23
+ jQuery(".btn.system_info_toggle").on("click", function () {
24
+ jQuery(".additional_system_info").toggle();
25
+ })
26
+
27
+ jQuery("a.download-logger").on("click", function (e) {
28
+ var xcloner_manage_backups = new Xcloner_Manage_Backups();
29
+
30
+ var hash = jQuery(this).attr('href');
31
+ var id = hash.substr(1)
32
+
33
+ if (id) {
34
+ xcloner_manage_backups.download_backup_by_name(id);
35
+ }
36
+
37
+ e.preventDefault();
38
+ })
39
+
40
+ jQuery(".nav-tab-wrapper.content li").on("click", function (e) {
41
+ jQuery(".nav-tab-wrapper li a").removeClass("nav-tab-active");
42
+ jQuery(this).find('a').addClass("nav-tab-active");
43
+ jQuery(".nav-tab-wrapper-content .tab-content").removeClass('active');
44
+ jQuery(".nav-tab-wrapper-content " + jQuery(this).find('a').attr('href')).addClass('active');
45
+
46
+ e.preventDefault();
47
+
48
+ location.hash = jQuery(this).find('a').attr('href') + "_hash";
49
+
50
+ })
51
+
52
+ var hash = window.location.hash;
53
+ if (hash) {
54
+ next_tab(hash.replace("_hash", ""));
55
+ }
56
+ })
57
+
58
+ })(jQuery);
59
 
60
 
61
  //jQuery( document ).ajaxError(function(err, request) {
62
+ //show_ajax_error("dd", "dd12", request)
63
  //});
64
 
65
+ function next_tab(hash) {
66
+ jQuery(".nav-tab-wrapper").find("li a[href='" + hash + "']").trigger('click');
67
+ location.hash = hash;
68
+ }
69
+
70
+ function doShortText(elem) {
71
+ if (elem.hasClass("full")) {
72
+ elem.text(elem.attr("data-text"));
73
+ return;
74
+ }
75
+ var text = elem.text()
76
+ var text_lenght = text.length;
77
+ var first = text.substr(0, 10);
78
+ var last = text.substr(text_lenght - 20, text_lenght);
79
+
80
+ elem.attr("data-text", text).text(first + "..." + last);
 
81
  }
82
 
83
  /** global: xcloner_backup */
84
+ function show_ajax_error(title, msg, json) {
85
+
86
+ //var json = jQuery.parseJSON( body )
87
+
88
+ if (typeof xcloner_backup !== 'undefined') {
89
+ xcloner_backup.cancel_backup();
90
+ }
91
+
92
+ if (json.responseText) {
93
+ msg = msg + ": " + json.responseText;
94
+ }
95
+
96
+ jQuery("#error_modal .title").text(title);
97
+ jQuery("#error_modal .msg").text(msg);
98
+
99
+ if (json.status) {
100
+ jQuery("#error_modal .status").text(json.status + " " + json.statusText);
101
+ }
102
+
103
+ jQuery("#error_modal .body").text(JSON.stringify(json));
104
+ var error_modal = jQuery("#error_modal").modal();
105
+ error_modal.modal('open');
 
 
 
106
  }
107
 
108
  var ID = function () {
109
+ // Math.random should be unique because of its seeding algorithm.
110
+ // Convert it to base 36 (numbers + letters), and grab the first 9 characters
111
+ // after the decimal.
112
+ return '_' + Math.random().toString(36).substr(2, 9);
113
  };
114
 
115
 
116
+ var getUrlParam = function (name) {
117
  return (location.search.split(name + '=')[1] || '').split('&')[0];
118
  }
119
 
admin/js/xcloner-backup-class.js CHANGED
@@ -1,441 +1,404 @@
1
- class Xcloner_Backup{
2
-
3
- constructor()
4
- {
5
- this.cancel = 0;
6
- this.params;
7
- this.generate_hash = false;
8
- this.last_dumpfile = "";
9
- this.last_backup_file = ""
10
- this.backup_part = 0
11
- this.backup_size_total = 0;
12
- this.resume = new Object();
13
- }
14
-
15
- get_form_params()
16
- {
17
- var table_params = []
18
- var files_params = []
19
- var extra = []
20
-
21
- jQuery.each(jQuery("#jstree_database_container").jstree("get_checked",true),function(){
22
-
23
- var object = new Object();
24
- object.id = this.id
25
- object.parent = this.parent
26
-
27
- var index = table_params.length;
28
- table_params[index] = object
29
- });
30
-
31
- jQuery.each(jQuery("#jstree_files_container").jstree("get_checked",true),function(){
32
- //console.log(this.id+"-"+this.parent);
33
-
34
- var object = new Object();
35
- object.id = this.id
36
- object.parent = this.parent
37
-
38
- var index = files_params.length;
39
- files_params[index] = object
40
- });
41
-
42
- var $return = new Object();
43
- $return.table_params = table_params;
44
- $return.files_params = files_params;
45
- $return.backup_params = jQuery('#generate_backup_form').serializeArray();
46
-
47
- return $return;
48
- }
49
-
50
- do_backup_database_callback(elem, action, json )
51
- {
52
- if(json.extra)
53
- this.params.extra = json.extra;
54
-
55
- if(json.extra.stats)
56
- {
57
- if(json.extra.stats.tables_count !== undefined)
58
- {
59
- jQuery(elem).find(".table-counter").text(parseInt(json.extra.stats.tables_count));
60
- }
61
-
62
- if(json.extra.stats.database_count !== undefined)
63
- {
64
- jQuery(elem).find(".database-counter").text(parseInt(json.extra.stats.database_count));
65
- }
66
-
67
- if(json.extra.stats.total_records !== undefined)
68
- {
69
- jQuery(elem).find(".total-records").text(parseInt(json.extra.stats.total_records));
70
- }
71
- }
72
-
73
- if(json.extra.tableName)
74
- {
75
- jQuery(elem).find(".last-logged-table").text(json.extra.databaseName+"."+json.extra.tableName+" ("+json.extra.processedRecords+" records)");
76
- }
77
-
78
- if(json.extra.processedRecords !== undefined && !json.extra.startAtRecord && !json.extra.endDump)
79
- {
80
- var records = parseInt(jQuery(elem).find(".total-records").attr('data-processed')) + parseInt(json.extra.processedRecords);
81
-
82
- var percent = 100*parseInt(records)/parseInt(jQuery(elem).find(".total-records").text());
83
- jQuery(elem).find('.progress .determinate').css('width', percent+'%');
84
-
85
- jQuery(elem).find(".total-records").attr('data-processed', records);
86
- jQuery(elem).find(".status-body ul.logged-tables").prepend(jQuery("<li>").text(json.extra.databaseName+"."+json.extra.tableName+" ("+json.extra.processedRecords+" records)"));
87
- }
88
-
89
- if(json.extra.dumpfile !== undefined){
90
- var db_text = (json.extra.dumpfile+" ("+this.getSize(json.extra.dumpsize, 1024)+" KB)");
91
-
92
- if(!jQuery(this.last_dumpfile).hasClass(json.extra.dumpfile)){
93
- this.last_dumpfile = (jQuery("<li>").addClass(json.extra.dumpfile).html(db_text)).prependTo("ul.logged-databases");
94
- }
95
- else{
96
- jQuery(this.last_dumpfile).html(db_text)
97
- }
98
-
99
- }
100
-
101
- if(!json.finished /*&& !this.cancel*/){
102
-
103
- this.do_ajax(elem, action);
104
- return false;
105
- }
106
-
107
-
108
-
109
- jQuery(elem).find(".last-logged-table").text('done');
110
- jQuery(elem).find('.progress .determinate').css('width', '100%');
111
-
112
- this.do_backup_files();
113
-
114
- }
115
-
116
- do_backup_database()
117
- {
118
- if(!jQuery('#jstree_database_container').length){
119
- this.do_backup_files();
120
- return;
121
- }
122
-
123
- /*if(this.cancel)
124
- return false;*/
125
-
126
- var elem = "#generate_backup ul.backup-status li.database-backup";
127
- jQuery(elem).show();
128
- jQuery(elem+' .status-body').show();
129
-
130
- jQuery(elem).find(".total-records").text(0);
131
- jQuery(elem).find(".total-records").attr('data-processed', 0);
132
- jQuery(elem).find(".table-counter").text(0);
133
- jQuery(elem).find(".database-counter").text(0);
134
- jQuery(elem).find(".logged-databases").html("");
135
- jQuery(elem).find(".logged-tables").html("");
136
-
137
- this.last_dumpfile = 0;
138
-
139
- jQuery(elem).find('.progress .determinate').css('width', '0%');
140
-
141
- this.do_ajax(elem, 'backup_database', 1);
142
- }
143
-
144
- do_scan_filesystem_callback(elem, action, json )
145
- {
146
-
147
- if(json.total_files_num)
148
- {
149
- jQuery(".file-system .file-counter").text(parseInt(json.total_files_num) + parseInt(jQuery(".file-system .file-counter").text()));
150
- }
151
-
152
- if(json.total_files_size) {
153
- var size = parseFloat(json.total_files_size) + parseFloat(jQuery(".file-system .file-size-total").text())
154
- jQuery(".file-system .file-size-total").text(size.toFixed(2));
155
- }
156
-
157
- if(json.last_logged_file)
158
- {
159
- jQuery(".file-system .last-logged-file").text(json.last_logged_file);
160
- }
161
-
162
- if(!json.finished /*&& !this.cancel*/){
163
-
164
- this.do_ajax(elem, action);
165
- return false;
166
- }
167
-
168
- //finished
169
- jQuery(elem).find('.progress .indeterminate').removeClass('indeterminate').addClass('determinate').css('width', '100%');
170
- jQuery(".file-system .last-logged-file").text('done');
171
-
172
- //this.do_backup_database();
173
- this.do_backup_database();
174
-
175
- }
176
- do_scan_filesystem()
177
- {
178
- /*if(this.cancel)
179
- return false;*/
180
-
181
- var elem = "#generate_backup ul.backup-status li.file-system";
182
- jQuery(elem).show();
183
- jQuery(elem+' .status-body').show();
184
- jQuery(elem).find('.collapsible-header').trigger('click');
185
-
186
- jQuery(".file-system .file-counter").text(0);
187
- jQuery(".file-system .last-logged-file").text("");
188
- jQuery(".file-system .file-size-total").text(0);
189
- jQuery('.file-system .progress div').removeClass('determinate').addClass('indeterminate').css('width', '0%');
190
-
191
-
192
- this.do_ajax(elem, 'scan_filesystem', 1);
193
-
194
- }
195
-
196
- do_backup_files_callback(elem, action, json)
197
- {
198
- /*if(this.cancel)
199
- return false;*/
200
-
201
- if(json.extra)
202
- {
203
- this.params.extra = json.extra;
204
- }
205
-
206
- if(json.extra)
207
- {
208
- if(json.extra.start_at_line !== undefined)
209
- {
210
- jQuery(elem).find(".file-counter").text(parseInt(json.extra.start_at_line));
211
- }
212
-
213
- if(json.extra.start_at_line !== undefined){
214
- //var prev_backup_size = parseInt(jQuery(elem).find(".file-size-total").attr('data-processed'));
215
- jQuery(elem).find(".file-size-total").text( this.getSize(this.backup_size_total+parseInt(json.extra.backup_size)));
216
- //var backup_size = parseInt(json.extra.backup_size);
217
- }
218
-
219
- }
220
-
221
- if(json.extra.processed_file)
222
- {
223
- if(json.extra.start_at_byte !== undefined && json.extra.start_at_byte)
224
- {
225
- var processed_size = json.extra.start_at_byte;
226
- }
227
- else
228
- {
229
- var processed_size = json.extra.processed_file_size;
230
- }
231
-
232
- jQuery(elem).find(".last-logged-file").text(json.extra.processed_file+" ("+this.getSize(processed_size, 1024)+" KB)");
233
- }
234
-
235
- if(json.extra.processed_file !== undefined){
236
-
237
- var backup_text = json.extra.backup_archive_name_full+" ("+this.getSize(json.extra.backup_size)+") MB";
238
-
239
- if(this.backup_part != json.extra.backup_part)
240
- {
241
- this.backup_part = json.extra.backup_part;
242
- this.backup_size_total = this.backup_size_total+json.extra.backup_size;
243
- }
244
-
245
- if(!jQuery(this.last_backup_file).hasClass(json.extra.backup_archive_name)){
246
- this.last_backup_file = (jQuery("<li>").addClass(json.extra.backup_archive_name).html(backup_text)).prependTo(jQuery(elem).find(".status-body .backup-name"));
247
- }
248
-
249
- jQuery(this.last_backup_file).html(backup_text)
250
-
251
- }
252
-
253
-
254
- if(json.extra.lines_total)
255
- {
256
- var percent = 100*parseInt(json.extra.start_at_line)/parseInt(json.extra.lines_total);
257
- jQuery(elem).find('.progress .determinate').css('width', percent+'%');
258
- }
259
-
260
- if(!json.finished /*&& !this.cancel*/){
261
-
262
- this.do_ajax(elem, action);
263
- return false;
264
- }
265
-
266
- jQuery(elem).find(".last-logged-file").text('done');
267
- jQuery(".backup-done .cloud-upload").attr("href", "#"+json.extra.backup_parent);
268
- jQuery(".backup-done .download").attr("href", "#"+json.extra.backup_parent);
269
- jQuery(".backup-done .list-backup-content").attr("href", "#"+json.extra.backup_parent);
270
-
271
- //this.restart_backup();
272
- this.do_backup_done()
273
- }
274
-
275
- do_backup_files()
276
- {
277
- if(this.cancel)
278
- return false;
279
-
280
- var elem = "#generate_backup ul.backup-status li.files-backup";
281
- jQuery(elem).show();
282
- jQuery(elem+' .status-body').show();
283
- jQuery(elem).find('.collapsible-header').trigger('click');
284
-
285
- jQuery(elem).find(".file-size-total").text(0);
286
- jQuery(elem).find(".file-size-total").attr('data-processed', 0);
287
- jQuery(elem).find(".file-counter").text(0);
288
- jQuery(elem).find(".last-logged-file").text("");
289
-
290
- jQuery(elem).find('.progress .determinate').css('width', '0%');
291
-
292
- this.do_ajax(elem, 'backup_files', 1);
293
- }
294
-
295
- do_backup_done()
296
- {
297
- var elem = "#generate_backup ul.backup-status li.backup-done";
298
- jQuery(elem).show();
299
- jQuery(elem+' .status-body').show();
300
- jQuery(elem).find('.collapsible-header').trigger('click');
301
-
302
- this.set_cancel(false)
303
- jQuery('#generate_backup .action-buttons a').hide();
304
- jQuery('#generate_backup .action-buttons .start').css('display', 'inline-block');
305
-
306
- }
307
-
308
- do_save_schedule_callback(elem, action, json)
309
- {
310
- jQuery("#schedule_backup_success").show();
311
- }
312
-
313
- cancel_backup()
314
- {
315
- this.set_cancel(true)
316
- jQuery('#generate_backup .action-buttons a').hide();
317
- jQuery('#generate_backup .action-buttons .start').css('display', 'inline-block');
318
- jQuery('#generate_backup .action-buttons .restart').css('display', 'inline-block');
319
-
320
- //this.restart_backup();
321
- }
322
-
323
- restart_backup()
324
- { this.set_cancel(false);
325
-
326
- jQuery('#generate_backup .action-buttons a').hide();
327
- jQuery('#generate_backup .action-buttons .cancel').css('display', 'inline-block');
328
-
329
- if(this.resume.action)
330
- {
331
- //console.log(this.resume.action)
332
- this.do_ajax(this.resume.elem, this.resume.action, this.resume.params);
333
- this.resume = new Object();
334
- return;
335
- }
336
-
337
- this.start_backup()
338
- }
339
-
340
- start_backup()
341
- {
342
-
343
- this.resume = new Object()
344
- this.set_cancel(false);
345
- jQuery('#generate_backup .action-buttons a').hide();
346
- jQuery('#generate_backup .action-buttons .cancel').css('display', 'inline-block');
347
-
348
-
349
- this.generate_hash = true;
350
- //this.cancel = false;
351
- this.backup_size_total = 0;
352
- this.last_backup_file = "";
353
- this.backup_part = 0;
354
- jQuery('#generate_backup ul.backup-name li').remove();
355
-
356
- jQuery('#generate_backup ul.backup-status > li').hide();
357
- jQuery('#generate_backup .backup-status').show();
358
-
359
- this.params = this.get_form_params();
360
-
361
-
362
-
363
- this.do_scan_filesystem();
364
-
365
- }
366
-
367
- set_cancel(status)
368
- {
369
- if(status)
370
- {
371
- //document.dispatchEvent(new CustomEvent("xcloner_restore_update_progress", {detail: {percent: 0, class: 'determinate' }}));
372
- //jQuery("#generate_backup .collapsible-header.active .progress > div").add
373
- }
374
- this.cancel = status
375
- }
376
-
377
- get_cancel(status)
378
- {
379
- return this.cancel
380
- }
381
-
382
- init_resume(elem, action, init)
383
- {
384
- this.resume.elem = elem
385
- this.resume.action = action
386
- this.resume.init = init
387
- }
388
-
389
- /** global: ajaxurl */
390
- do_ajax(elem, action, init = 0)
391
- {
392
- var hash = '';
393
- if(this.params.hash !==undefined)
394
- hash = this.params.hash;
395
- else if(this.generate_hash)
396
- hash = 'generate_hash';
397
-
398
-
399
- if(this.cancel == true)
400
- {
401
- this.init_resume(elem, action, init);
402
- return;
403
- }
404
-
405
- var callback = 'do_'+action+'_callback';
406
- var data = JSON.stringify(this.params);
407
- var $this = this;
408
-
409
- jQuery.ajax({
410
- url: ajaxurl,
411
- dataType: 'json',
412
- type: 'POST',
413
- data: {'action': action, 'data': data, 'init': init, 'hash': hash, 'API_ID': ID()},
414
- error: function(err) {
415
- show_ajax_error("Communication Error", "", err)
416
- $this.init_resume(elem, action, init);
417
- //console.log(err);
418
- }
419
- }).done(function(json) {
420
- if(json.hash){
421
- $this.params.hash = json.hash;
422
- //console.log(json.hash);
423
- }
424
- if(json.error !== undefined){
425
- show_ajax_error("Communication Error", "", json.error_message);
426
- $this.init_resume(elem, action, init);
427
- return;
428
- }
429
-
430
- $this.resume = new Object();
431
-
432
- $this[callback](elem, action, json)
433
-
434
- });
435
- }
436
-
437
- getSize(bytes, conv = 1024*1024)
438
- {
439
- return (bytes/conv).toFixed(2);
440
- }
441
  }
1
+ class Xcloner_Backup {
2
+
3
+ constructor() {
4
+ this.cancel = 0;
5
+ this.params;
6
+ this.generate_hash = false;
7
+ this.last_dumpfile = "";
8
+ this.last_backup_file = ""
9
+ this.backup_part = 0
10
+ this.backup_size_total = 0;
11
+ this.resume = new Object();
12
+ }
13
+
14
+ get_form_params() {
15
+ var table_params = []
16
+ var files_params = []
17
+ var extra = []
18
+
19
+ jQuery.each(jQuery("#jstree_database_container").jstree("get_checked", true), function () {
20
+
21
+ var object = new Object();
22
+ object.id = this.id
23
+ object.parent = this.parent
24
+
25
+ var index = table_params.length;
26
+ table_params[index] = object
27
+ });
28
+
29
+ jQuery.each(jQuery("#jstree_files_container").jstree("get_checked", true), function () {
30
+ //console.log(this.id+"-"+this.parent);
31
+
32
+ var object = new Object();
33
+ object.id = this.id
34
+ object.parent = this.parent
35
+
36
+ var index = files_params.length;
37
+ files_params[index] = object
38
+ });
39
+
40
+ var $return = new Object();
41
+ $return.table_params = table_params;
42
+ $return.files_params = files_params;
43
+ $return.backup_params = jQuery('#generate_backup_form').serializeArray();
44
+
45
+ return $return;
46
+ }
47
+
48
+ do_backup_database_callback(elem, action, json) {
49
+ if (json.extra)
50
+ this.params.extra = json.extra;
51
+
52
+ if (json.extra.stats) {
53
+ if (json.extra.stats.tables_count !== undefined) {
54
+ jQuery(elem).find(".table-counter").text(parseInt(json.extra.stats.tables_count));
55
+ }
56
+
57
+ if (json.extra.stats.database_count !== undefined) {
58
+ jQuery(elem).find(".database-counter").text(parseInt(json.extra.stats.database_count));
59
+ }
60
+
61
+ if (json.extra.stats.total_records !== undefined) {
62
+ jQuery(elem).find(".total-records").text(parseInt(json.extra.stats.total_records));
63
+ }
64
+ }
65
+
66
+ if (json.extra.tableName) {
67
+ jQuery(elem).find(".last-logged-table").text(json.extra.databaseName + "." + json.extra.tableName + " (" + json.extra.processedRecords + " records)");
68
+ }
69
+
70
+ if (json.extra.processedRecords !== undefined && !json.extra.startAtRecord && !json.extra.endDump) {
71
+ var records = parseInt(jQuery(elem).find(".total-records").attr('data-processed')) + parseInt(json.extra.processedRecords);
72
+
73
+ var percent = 100 * parseInt(records) / parseInt(jQuery(elem).find(".total-records").text());
74
+ jQuery(elem).find('.progress .determinate').css('width', percent + '%');
75
+
76
+ jQuery(elem).find(".total-records").attr('data-processed', records);
77
+ jQuery(elem).find(".status-body ul.logged-tables").prepend(jQuery("<li>").text(json.extra.databaseName + "." + json.extra.tableName + " (" + json.extra.processedRecords + " records)"));
78
+ }
79
+
80
+ if (json.extra.dumpfile !== undefined) {
81
+ var db_text = (json.extra.dumpfile + " (" + this.getSize(json.extra.dumpsize, 1024) + " KB)");
82
+
83
+ if (!jQuery(this.last_dumpfile).hasClass(json.extra.dumpfile)) {
84
+ this.last_dumpfile = (jQuery("<li>").addClass(json.extra.dumpfile).html(db_text)).prependTo("ul.logged-databases");
85
+ }
86
+ else {
87
+ jQuery(this.last_dumpfile).html(db_text)
88
+ }
89
+
90
+ }
91
+
92
+ if (!json.finished /*&& !this.cancel*/) {
93
+
94
+ this.do_ajax(elem, action);
95
+ return false;
96
+ }
97
+
98
+
99
+ jQuery(elem).find(".last-logged-table").text('done');
100
+ jQuery(elem).find('.progress .determinate').css('width', '100%');
101
+
102
+ this.do_backup_files();
103
+
104
+ }
105
+
106
+ do_backup_database() {
107
+ if (!jQuery('#jstree_database_container').length) {
108
+ this.do_backup_files();
109
+ return;
110
+ }
111
+
112
+ /*if(this.cancel)
113
+ return false;*/
114
+
115
+ var elem = "#generate_backup ul.backup-status li.database-backup";
116
+ jQuery(elem).show();
117
+ jQuery(elem + ' .status-body').show();
118
+
119
+ jQuery(elem).find(".total-records").text(0);
120
+ jQuery(elem).find(".total-records").attr('data-processed', 0);
121
+ jQuery(elem).find(".table-counter").text(0);
122
+ jQuery(elem).find(".database-counter").text(0);
123
+ jQuery(elem).find(".logged-databases").html("");
124
+ jQuery(elem).find(".logged-tables").html("");
125
+
126
+ this.last_dumpfile = 0;
127
+
128
+ jQuery(elem).find('.progress .determinate').css('width', '0%');
129
+
130
+ this.do_ajax(elem, 'backup_database', 1);
131
+ }
132
+
133
+ do_scan_filesystem_callback(elem, action, json) {
134
+
135
+ if (json.total_files_num) {
136
+ jQuery(".file-system .file-counter").text(parseInt(json.total_files_num) + parseInt(jQuery(".file-system .file-counter").text()));
137
+ }
138
+
139
+ if (json.total_files_size) {
140
+ var size = parseFloat(json.total_files_size) + parseFloat(jQuery(".file-system .file-size-total").text())
141
+ jQuery(".file-system .file-size-total").text(size.toFixed(2));
142
+ }
143
+
144
+ if (json.last_logged_file) {
145
+ jQuery(".file-system .last-logged-file").text(json.last_logged_file);
146
+ }
147
+
148
+ if (!json.finished /*&& !this.cancel*/) {
149
+
150
+ this.do_ajax(elem, action);
151
+ return false;
152
+ }
153
+
154
+ //finished
155
+ jQuery(elem).find('.progress .indeterminate').removeClass('indeterminate').addClass('determinate').css('width', '100%');
156
+ jQuery(".file-system .last-logged-file").text('done');
157
+
158
+ //this.do_backup_database();
159
+ this.do_backup_database();
160
+
161
+ }
162
+
163
+ do_scan_filesystem() {
164
+ /*if(this.cancel)
165
+ return false;*/
166
+
167
+ var elem = "#generate_backup ul.backup-status li.file-system";
168
+ jQuery(elem).show();
169
+ jQuery(elem + ' .status-body').show();
170
+ jQuery(elem).find('.collapsible-header').trigger('click');
171
+
172
+ jQuery(".file-system .file-counter").text(0);
173
+ jQuery(".file-system .last-logged-file").text("");
174
+ jQuery(".file-system .file-size-total").text(0);
175
+ jQuery('.file-system .progress div').removeClass('determinate').addClass('indeterminate').css('width', '0%');
176
+
177
+
178
+ this.do_ajax(elem, 'scan_filesystem', 1);
179
+
180
+ }
181
+
182
+ do_backup_files_callback(elem, action, json) {
183
+ /*if(this.cancel)
184
+ return false;*/
185
+
186
+ if (json.extra) {
187
+ this.params.extra = json.extra;
188
+ }
189
+
190
+ if (json.extra) {
191
+ if (json.extra.start_at_line !== undefined) {
192
+ jQuery(elem).find(".file-counter").text(parseInt(json.extra.start_at_line));
193
+ }
194
+
195
+ if (json.extra.start_at_line !== undefined) {
196
+ //var prev_backup_size = parseInt(jQuery(elem).find(".file-size-total").attr('data-processed'));
197
+ jQuery(elem).find(".file-size-total").text(this.getSize(this.backup_size_total + parseInt(json.extra.backup_size)));
198
+ //var backup_size = parseInt(json.extra.backup_size);
199
+ }
200
+
201
+ }
202
+
203
+ if (json.extra.processed_file) {
204
+ if (json.extra.start_at_byte !== undefined && json.extra.start_at_byte) {
205
+ var processed_size = json.extra.start_at_byte;
206
+ }
207
+ else {
208
+ var processed_size = json.extra.processed_file_size;
209
+ }
210
+
211
+ jQuery(elem).find(".last-logged-file").text(json.extra.processed_file + " (" + this.getSize(processed_size, 1024) + " KB)");
212
+ }
213
+
214
+ if (json.extra.processed_file !== undefined) {
215
+
216
+ var backup_text = json.extra.backup_archive_name_full + " (" + this.getSize(json.extra.backup_size) + ") MB";
217
+
218
+ if (this.backup_part != json.extra.backup_part) {
219
+ this.backup_part = json.extra.backup_part;
220
+ this.backup_size_total = this.backup_size_total + json.extra.backup_size;
221
+ }
222
+
223
+ if (!jQuery(this.last_backup_file).hasClass(json.extra.backup_archive_name)) {
224
+ this.last_backup_file = (jQuery("<li>").addClass(json.extra.backup_archive_name).html(backup_text)).prependTo(jQuery(elem).find(".status-body .backup-name"));
225
+ }
226
+
227
+ jQuery(this.last_backup_file).html(backup_text)
228
+
229
+ }
230
+
231
+
232
+ if (json.extra.lines_total) {
233
+ var percent = 100 * parseInt(json.extra.start_at_line) / parseInt(json.extra.lines_total);
234
+ jQuery(elem).find('.progress .determinate').css('width', percent + '%');
235
+ }
236
+
237
+ if (!json.finished /*&& !this.cancel*/) {
238
+
239
+ this.do_ajax(elem, action);
240
+ return false;
241
+ }
242
+
243
+ jQuery(elem).find(".last-logged-file").text('done');
244
+ jQuery(".backup-done .cloud-upload").attr("href", "#" + json.extra.backup_parent);
245
+ jQuery(".backup-done .download").attr("href", "#" + json.extra.backup_parent);
246
+ jQuery(".backup-done .list-backup-content").attr("href", "#" + json.extra.backup_parent);
247
+
248
+ //this.restart_backup();
249
+ this.do_backup_done()
250
+ }
251
+
252
+ do_backup_files() {
253
+ if (this.cancel)
254
+ return false;
255
+
256
+ var elem = "#generate_backup ul.backup-status li.files-backup";
257
+ jQuery(elem).show();
258
+ jQuery(elem + ' .status-body').show();
259
+ jQuery(elem).find('.collapsible-header').trigger('click');
260
+
261
+ jQuery(elem).find(".file-size-total").text(0);
262
+ jQuery(elem).find(".file-size-total").attr('data-processed', 0);
263
+ jQuery(elem).find(".file-counter").text(0);
264
+ jQuery(elem).find(".last-logged-file").text("");
265
+
266
+ jQuery(elem).find('.progress .determinate').css('width', '0%');
267
+
268
+ this.do_ajax(elem, 'backup_files', 1);
269
+ }
270
+
271
+ do_backup_done() {
272
+ var elem = "#generate_backup ul.backup-status li.backup-done";
273
+ jQuery(elem).show();
274
+ jQuery(elem + ' .status-body').show();
275
+ jQuery(elem).find('.collapsible-header').trigger('click');
276
+
277
+ this.set_cancel(false)
278
+ jQuery('#generate_backup .action-buttons a').hide();
279
+ jQuery('#generate_backup .action-buttons .start').css('display', 'inline-block');
280
+
281
+ }
282
+
283
+ do_save_schedule_callback(elem, action, json) {
284
+ jQuery("#schedule_backup_success").show();
285
+ }
286
+
287
+ cancel_backup() {
288
+ this.set_cancel(true)
289
+ jQuery('#generate_backup .action-buttons a').hide();
290
+ jQuery('#generate_backup .action-buttons .start').css('display', 'inline-block');
291
+ jQuery('#generate_backup .action-buttons .restart').css('display', 'inline-block');
292
+
293
+ //this.restart_backup();
294
+ }
295
+
296
+ restart_backup() {
297
+ this.set_cancel(false);
298
+
299
+ jQuery('#generate_backup .action-buttons a').hide();
300
+ jQuery('#generate_backup .action-buttons .cancel').css('display', 'inline-block');
301
+
302
+ if (this.resume.action) {
303
+ //console.log(this.resume.action)
304
+ this.do_ajax(this.resume.elem, this.resume.action, this.resume.params);
305
+ this.resume = new Object();
306
+ return;
307
+ }
308
+
309
+ this.start_backup()
310
+ }
311
+
312
+ start_backup() {
313
+
314
+ this.resume = new Object()
315
+ this.set_cancel(false);
316
+ jQuery('#generate_backup .action-buttons a').hide();
317
+ jQuery('#generate_backup .action-buttons .cancel').css('display', 'inline-block');
318
+
319
+
320
+ this.generate_hash = true;
321
+ //this.cancel = false;
322
+ this.backup_size_total = 0;
323
+ this.last_backup_file = "";
324
+ this.backup_part = 0;
325
+ jQuery('#generate_backup ul.backup-name li').remove();
326
+
327
+ jQuery('#generate_backup ul.backup-status > li').hide();
328
+ jQuery('#generate_backup .backup-status').show();
329
+
330
+ this.params = this.get_form_params();
331
+
332
+
333
+ this.do_scan_filesystem();
334
+
335
+ }
336
+
337
+ set_cancel(status) {
338
+ if (status) {
339
+ //document.dispatchEvent(new CustomEvent("xcloner_restore_update_progress", {detail: {percent: 0, class: 'determinate' }}));
340
+ //jQuery("#generate_backup .collapsible-header.active .progress > div").add
341
+ }
342
+ this.cancel = status
343
+ }
344
+
345
+ get_cancel(status) {
346
+ return this.cancel
347
+ }
348
+
349
+ init_resume(elem, action, init) {
350
+ this.resume.elem = elem
351
+ this.resume.action = action
352
+ this.resume.init = init
353
+ }
354
+
355
+ /** global: ajaxurl */
356
+ do_ajax(elem, action, init = 0) {
357
+ var hash = '';
358
+ if (this.params.hash !== undefined)
359
+ hash = this.params.hash;
360
+ else if (this.generate_hash)
361
+ hash = 'generate_hash';
362
+
363
+
364
+ if (this.cancel == true) {
365
+ this.init_resume(elem, action, init);
366
+ return;
367
+ }
368
+
369
+ var callback = 'do_' + action + '_callback';
370
+ var data = JSON.stringify(this.params);
371
+ var $this = this;
372
+
373
+ jQuery.ajax({
374
+ url: ajaxurl,
375
+ dataType: 'json',
376
+ type: 'POST',
377
+ data: {'action': action, 'data': data, 'init': init, 'hash': hash, 'API_ID': ID()},
378
+ error: function (err) {
379
+ show_ajax_error("Communication Error", "", err)
380
+ $this.init_resume(elem, action, init);
381
+ //console.log(err);
382
+ }
383
+ }).done(function (json) {
384
+ if (json.hash) {
385
+ $this.params.hash = json.hash;
386
+ //console.log(json.hash);
387
+ }
388
+ if (json.error !== undefined) {
389
+ show_ajax_error("Communication Error", "", json.error_message);
390
+ $this.init_resume(elem, action, init);
391
+ return;
392
+ }
393
+
394
+ $this.resume = new Object();
395
+
396
+ $this[callback](elem, action, json)
397
+
398
+ });
399
+ }
400
+
401
+ getSize(bytes, conv = 1024 * 1024) {
402
+ return (bytes / conv).toFixed(2);
403
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
404
  }
admin/js/xcloner-manage-backups-class.js CHANGED
@@ -203,7 +203,7 @@ jQuery(document).ready(function(){
203
  var dataTable = jQuery('#manage_backups').DataTable( {
204
  'responsive': true,
205
  'bFilter': true,
206
- "order": [[ 1, "desc" ]],
207
  buttons: [
208
  'selectAll',
209
  'selectNone'
203
  var dataTable = jQuery('#manage_backups').DataTable( {
204
  'responsive': true,
205
  'bFilter': true,
206
+ "order": [[ 2, "desc" ]],
207
  buttons: [
208
  'selectAll',
209
  'selectNone'
admin/partials/xcloner_console_page.php CHANGED
@@ -1,33 +1,36 @@
1
  <?php
2
 
3
- $xcloner_settings = $this->get_xcloner_container()->get_xcloner_settings();
4
- $logger = $this->get_xcloner_container()->get_xcloner_logger();
5
- $logger_content = $logger->getLastDebugLines();
6
  ?>
7
  <div class="col s12 ">
8
- <div>
9
- <h5 class="left-align">
10
- <?php echo __('XCloner Debugger Dashboard', 'xcloner-backup-and-restore') ?>
11
- </h5>
12
-
13
- <?php if($xcloner_settings->get_xcloner_option('xcloner_enable_log')) :?>
14
- <ul class="collapsible xcloner-debugger" data-collapsible="accordion">
15
- <li class="active">
16
- <div class="collapsible-header active"><i class="material-icons">bug_report</i>XCloner Debugger</div>
17
- <div class="collapsible-body">
18
- <div class="console" id="xcloner-console"><?php if(isset($logger_content)) echo implode("<br />\n", $logger_content); ?></div>
19
- </div>
20
- </li>
21
- </ul>
22
- <script>
23
- jQuery(document).ready(function(){
24
- var objDiv = document.getElementById("xcloner-console");
25
- objDiv.scrollTop = objDiv.scrollHeight;
26
- /*setInterval(function(){
27
- getXclonerLog();
28
- }, 2000);*/
29
- })
30
- </script>
31
- <?php endif;?>
32
- </div>
 
 
 
33
  </div>
1
  <?php
2
 
3
+ $xcloner_settings = $this->get_xcloner_container()->get_xcloner_settings();
4
+ $logger = $this->get_xcloner_container()->get_xcloner_logger();
5
+ $logger_content = $logger->getLastDebugLines();
6
  ?>
7
  <div class="col s12 ">
8
+ <div>
9
+ <h5 class="left-align">
10
+ <?php echo __( 'XCloner Debugger Dashboard', 'xcloner-backup-and-restore' ) ?>
11
+ </h5>
12
+
13
+ <?php if ( $xcloner_settings->get_xcloner_option( 'xcloner_enable_log' ) ) : ?>
14
+ <ul class="collapsible xcloner-debugger" data-collapsible="accordion">
15
+ <li class="active">
16
+ <div class="collapsible-header active"><i class="material-icons">bug_report</i>XCloner Debugger
17
+ </div>
18
+ <div class="collapsible-body">
19
+ <div class="console" id="xcloner-console"><?php if ( isset( $logger_content ) ) {
20
+ echo implode( "<br />\n", $logger_content );
21
+ } ?></div>
22
+ </div>
23
+ </li>
24
+ </ul>
25
+ <script>
26
+ jQuery(document).ready(function () {
27
+ var objDiv = document.getElementById("xcloner-console");
28
+ objDiv.scrollTop = objDiv.scrollHeight;
29
+ /*setInterval(function(){
30
+ getXclonerLog();
31
+ }, 2000);*/
32
+ })
33
+ </script>
34
+ <?php endif; ?>
35
+ </div>
36
  </div>
admin/partials/xcloner_generate_backups_page.php CHANGED
@@ -1,545 +1,593 @@
1
- <?php
2
- $xcloner_settings = $this->get_xcloner_container()->get_xcloner_settings();
3
  $xcloner_remote_storage = $this->get_xcloner_container()->get_xcloner_remote_storage();
4
- $available_storages = $xcloner_remote_storage->get_available_storages();
5
- $xcloner_scheduler = $this->get_xcloner_container()->get_xcloner_scheduler();
6
- $tab = 1;
7
  ?>
8
 
9
  <script>var xcloner_backup = new Xcloner_Backup();</script>
10
 
11
- <h1><?= esc_html(get_admin_page_title()); ?></h1>
12
-
13
  <ul class="nav-tab-wrapper content row">
14
- <li><a href="#backup_options" class="nav-tab col s12 m3 l2 nav-tab-active"><?php echo $tab.". ".__('Backup Options','xcloner-backup-and-restore')?></a></li>
15
- <?php if($xcloner_settings->get_enable_mysql_backup()):?>
16
- <li><a href="#database_options" class="nav-tab col s12 m3 l2 "><?php echo ++$tab.". ".__('Database Options','xcloner-backup-and-restore')?></a></li>
17
- <?php endif?>
18
- <li><a href="#files_options" class="nav-tab col s12 m3 l2 "><?php echo ++$tab.". ".__('Files Options','xcloner-backup-and-restore')?></a></li>
19
- <li><a href="#generate_backup" class="nav-tab col s12 m3 l2 "><?php echo ++$tab.". ".__('Generate Backup','xcloner-backup-and-restore')?></a></li>
20
- <li><a href="#schedule_backup" class="nav-tab col s12 m3 l2 "><?php echo ++$tab.". ".__('Schedule Backup','xcloner-backup-and-restore')?></a></li>
 
 
 
 
 
 
 
 
 
 
21
  </ul>
22
 
23
  <form action="" method="POST" id="generate_backup_form">
24
- <div class="nav-tab-wrapper-content">
25
- <!-- Backup Options Content Tab-->
26
- <div id="backup_options" class="tab-content active">
27
- <div class="row">
28
- <div class="input-field inline col s12 m10 l6">
29
- <i class="material-icons prefix">input</i>
30
- <input name="backup_name" id="backup_name" type="text" value=<?php echo $xcloner_settings->get_default_backup_name() ?> >
31
- <label for="backup_name"><?php echo __('Backup Name','xcloner-backup-and-restore')?></label>
32
- </div>
33
- <div class="hide-on-small-only m2">
34
- <a class="btn-floating tooltipped btn-small" data-position="right" data-delay="50" data-tooltip="<?php echo __('The default backup name, supported tags [time], [hostname], [domain]','xcloner-backup-and-restore')?>" data-tooltip-id=""><i class="material-icons">help_outline</i></a>
35
- </div>
36
- </div>
37
-
38
- <div class="row">
39
- <div class="input-field inline col s12 m10 l6">
40
- <i class="material-icons prefix">email</i>
41
- <input name="email_notification" id="email_notification" type="text" value="<?php echo get_option('admin_email');?>" >
42
- <label for="email_notification"><?php echo __('Send Email Notification To','xcloner-backup-and-restore')?></label>
43
- </div>
44
- <div class="hide-on-small-only m2">
45
- <a class="btn-floating tooltipped btn-small" data-position="right" data-delay="50" data-tooltip="<?php echo __('If left blank, no notification will be sent','xcloner-backup-and-restore')?>" data-tooltip-id=""><i class="material-icons">help_outline</i></a>
46
- </div>
47
- </div>
48
-
49
- <div class="row">
50
- <div class="input-field inline col s10 m10 l6">
51
- <i class="material-icons prefix">access_time</i>
52
- <input type="datetime-local" id="diff_start_date" class="datepicker_max_today" name="diff_start_date" >
53
- <label for="diff_start_date"><?php echo __('Backup Only Files Modified/Created After','xcloner-backup-and-restore')?></label>
54
- </div>
55
- <div class="hide-on-small-only m2">
56
- <a class="btn-floating tooltipped btn-small" data-html="true" data-position="center" data-delay="50" data-tooltip="<?php echo __("This option allows you to create a differential backup that will include only <br> changed files since the set date, leave blank to include all files", "xcloner-backup-and-restore")?>"><i class="material-icons">help_outline</i></a>
57
- </div>
58
- </div>
59
-
60
- <div class="row">
61
- <div class="input-field col s12 m10 l6">
62
- <i class="material-icons prefix">input</i>
63
- <textarea name="backup_comments" id="backup_comments" class="materialize-textarea"></textarea>
64
- <label for="backup_comments"><?php echo __('Backup Comments','xcloner-backup-and-restore')?></label>
65
- </div>
66
- <div class="hide-on-small-only m2">
67
- <a class="btn-floating tooltipped btn-small" data-position="right" data-delay="50" data-tooltip="<?php echo __('Some default backup comments that will be stored inside the backup archive','xcloner-backup-and-restore')?>" data-tooltip-id=""><i class="material-icons">help_outline</i></a>
68
- </div>
69
- </div>
70
-
71
- <div class="row">
72
- <div class="input-field col s12 m10 l6 right-align">
73
- <a class="waves-effect waves-light btn" onclick="next_tab('#database_options');"><i class="material-icons right">skip_next</i>Next</a>
74
- </div>
75
- </div>
76
- </div>
77
-
78
- <?php if($xcloner_settings->get_enable_mysql_backup()):?>
79
- <div id="database_options" class="tab-content">
80
- <h2><?php echo __('Select database data to include in the backup', 'xcloner-backup-and-restore')?>:
81
- <a class="btn-floating tooltipped btn-small" data-position="right" data-delay="50" data-tooltip="<?php echo __('Enable the \'Backup only WP tables\' setting if you don\'t want to show all other databases and tables not related to this Wordpress install','xcloner-backup-and-restore');?>" data-tooltip-id=""><i class="material-icons">help_outline</i></a>
82
- </h2>
83
-
84
- <!-- database/tables tree -->
85
- <div class="row">
86
- <div class="col s12 l6">
87
- <div id="jstree_database_container"></div>
88
- </div>
89
- </div>
90
-
91
- <div class="row">
92
- <div class="input-field col s12 m10 l6 right-align">
93
- <a class="waves-effect waves-light btn" onclick="next_tab('#files_options');"><i class="material-icons right">skip_next</i>Next</a>
94
- </div>
95
- </div>
96
-
97
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
  <?php endif ?>
99
-
100
- <div id="files_options" class="tab-content">
101
- <h2><?php echo __('Select from below the files/folders you want to exclude from your Backup Archive','xcloner-backup-and-restore')?>:
102
- <a class="btn-floating tooltipped btn-small" data-position="bottom" data-delay="50" data-html="true" data-tooltip="<?php echo __('You can navigate below through all your site structure(Backup Start Location) to exclude any file/folder you need by clicking the checkbox near it. <br />If the checkobx is disabled, then it matches a Regex Exclude File option and it can\'t be unchecked','xcloner-backup-and-restore');?>" data-tooltip-id=""><i class="material-icons">help_outline</i></a>
103
- </h2>
104
-
105
- <!-- Files System Container -->
106
- <div class="row">
107
- <div class="col s12 l6">
108
- <div id="jstree_files_container"></div>
109
- </div>
110
- </div>
111
-
112
- <div class="row">
113
- <div class="input-field col s12 m10 l6 right-align">
114
- <a class="waves-effect waves-light btn" onclick="next_tab('#generate_backup');"><i class="material-icons right">skip_next</i>Next</a>
115
- </div>
116
- </div>
117
-
118
- </div>
119
- <div id="generate_backup" class="tab-content">
120
- <div class="row ">
121
- <div class="col s12 l10 center action-buttons">
122
- <a class="waves-effect waves-light btn-large teal darken-1 start" onclick="xcloner_backup.start_backup()">Start Backup<i class="material-icons left">forward</i></a>
123
- <a class="waves-effect waves-light btn-large teal darken-1 restart" onclick="xcloner_backup.restart_backup()">Restart Backup<i class="material-icons left">cached</i></a>
124
- <a class="waves-effect waves-light btn-large red darken-1 cancel" onclick="xcloner_backup.cancel_backup()">Cancel Backup<i class="material-icons left">cancel</i></a>
125
- </div>
126
- <div class="col l10 s12">
127
- <ul class="backup-status collapsible" data-collapsible="accordion">
128
- <li class="file-system">
129
- <div class="collapsible-header">
130
- <i class="material-icons">folder</i><?php echo __('Scanning The File System...','xcloner-backup-and-restore')?>
131
-
132
- <p class="right"><?php echo sprintf(__('Found %s files (%s)', 'xcloner-backup-and-restore'), '<span class="file-counter">0</span>', '<span class="file-size-total">0</span>MB')?></p>
133
-
134
- <div>
135
- <p class="right"><span class="last-logged-file"></span></p>
136
- </div>
137
-
138
- <div class="progress">
139
- <div class="indeterminate"></div>
140
- </div>
141
- </div>
142
- <div class="collapsible-body status-body"></div>
143
- </li>
144
- <?php if($xcloner_settings->get_enable_mysql_backup()):?>
145
- <li class="database-backup">
146
- <div class="collapsible-header">
147
- <i class="material-icons">storage</i><?php echo __('Generating the Mysql Backup...','xcloner-backup-and-restore')?>
148
-
149
- <p class="right"><?php echo sprintf(__('Found %s tables in %s databases (%s)', 'xcloner-backup-and-restore'), '<span class="table-counter">0</span>', '<span class="database-counter">0</span>', '<span data-processed="0" class="total-records">0</span> records','xcloner-backup-and-restore')?></p>
150
-
151
- <div>
152
- <p class="right"><span class="last-logged-table"></span></p>
153
- </div>
154
-
155
- <div class="progress">
156
- <div class="determinate" style="width:0%"></div>
157
- </div>
158
- </div>
159
- <div class="collapsible-body status-body">
160
- <div class="row">
161
- <div class="col l7 s12">
162
- <ul class="logged-tables"></ul>
163
- </div>
164
- <div class="col l5 s12">
165
- <ul class="logged-databases right"></ul>
166
- </div>
167
- </div>
168
- </div>
169
- </li>
170
- <?php endif?>
171
- <li class="files-backup">
172
- <div class="collapsible-header">
173
- <i class="material-icons">archive</i><?php echo __('Adding Files to Archive...','xcloner-backup-and-restore')?>
174
-
175
- <p class="right"><?php echo sprintf(__('Adding %s files (%s)','xcloner-backup-and-restore'), '<span class="file-counter">0</span>', '<span data-processed="0" class="file-size-total">0</span>MB')?></p>
176
-
177
- <div>
178
- <p class="right"><span class="last-logged-file"></span></p>
179
- </div>
180
-
181
- <div class="progress">
182
- <div class="determinate" style="width:0%"></div>
183
- </div>
184
- </div>
185
- <div class="collapsible-body status-body">
186
- <div class="row">
187
- <div class="col l3 s12">
188
- <h2><?php echo __("Backup Parts",'xcloner-backup-and-restore')?>: </h2>
189
- </div>
190
- <div class="col l9 s12">
191
- <ul class="backup-name"></ul>
192
- </div>
193
- </div>
194
- </div>
195
- </li>
196
- <li class="backup-done">
197
- <div class="collapsible-header">
198
- <i class="material-icons">done</i><?php echo __('Backup Done','xcloner-backup-and-restore')?>
199
-
200
- <p class="right">
201
- <?php if(sizeof($available_storages)):?>
202
- <a href="#" class="cloud-upload" title="<?php echo __("Send Backup To Remote Storage",'xcloner-backup-and-restore')?>"><i class="material-icons">cloud_upload</i></a>
203
- <?php endif?>
204
- <a href="#" class="download" title="<?php echo __("Download Backup",'xcloner-backup-and-restore')?>"><i class="material-icons">file_download</i></a>
205
- <a href="#" class="list-backup-content" title="<?php echo __("List Backup Content",'xcloner-backup-and-restore')?>"><i class="material-icons">folder_open</i></a>
206
- </p>
207
-
208
- <div class="progress">
209
- <div class="determinate" style="width:100%"></div>
210
- </div>
211
-
212
- </div>
213
- <div class="collapsible-body center-align">
214
- <div class="row">
215
- <h5><?php echo __("Thank you for using XCloner.",'xcloner-backup-and-restore')?></h5>
216
- <h6><?php echo sprintf(__("We would love to hear about your experience in the %s.", 'xcloner-backup-and-restore'),'<a href="https://wordpress.org/support/plugin/xcloner-backup-and-restore/reviews/" target="_blank">Wordpress XCloner Reviews Section</a>') ?></h6>
217
- <a class="twitter-follow-button" href="https://twitter.com/thinkovi" data-show-count="false">Follow @thinkovi</a>
218
- <script src="//platform.twitter.com/widgets.js" async="" charset="utf-8"></script>
219
-
220
- <br />
221
- <!-- XCLONER SPONSORS AREA-->
222
- <!-- END XCLONER SPONSORS AREA-->
223
- </div>
224
- </div>
225
- </li>
226
- </ul>
227
- </div>
228
-
229
- </div>
230
- </div>
231
-
232
- <div id="schedule_backup" class="tab-content">
233
-
234
- <div class="row">
235
- <div id="schedule_backup_success" class="col s12 l6 updated settings-error notice is-dismissible">
236
- <p><strong><?php echo __('Schedule Saved', 'xcloner-backup-and-restore')?></strong></p>
237
- <button type="button" class="notice-dismiss"><span class="screen-reader-text"><?php echo __('(Dismiss this notice.','xcloner-backup-and-restore')?></span></button>
238
- </div>
239
- </div>
240
-
241
- <div class="row">
242
- <div class="input-field inline col s12 l7">
243
- <input type="text" id="schedule_name" class="" name="schedule_name" required>
244
- <label for="schedule_name"><?php echo __('Schedule Name', 'xcloner-backup-and-restore') ?></label>
245
- </div>
246
- </div>
247
-
248
- <div class="row">
249
- <div class="input-field inline col s12 m8 l4">
250
- <input type="datetime-local" id="datepicker" class="datepicker" name="schedule_start_date" >
251
- <label for="datepicker"><?php echo __('Schedule Backup To Start On:','xcloner-backup-and-restore')?></label>
252
- </div>
253
- <div class="input-field inline col s12 m4 l3">
254
- <input id="timepicker_ampm_dark" class="timepicker" type="time" name="schedule_start_time">
255
- <label for="timepicker_ampm_dark"><?php echo __('At:','xcloner-backup-and-restore')?></label>
256
- </div>
257
- </div>
258
-
259
- <!--
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
260
  <div class="row">
261
  <div class="input-field inline col s10 m11 l7">
262
  <select id="backup_type" class="" name="backup_type">
263
- <option value=""><?php echo __("Full Backup","xcloner-backup-and-restore");?></option>
264
- <option value="diff"><?php echo __("Differential Backups","xcloner-backup-and-restore");?></option>
265
- <option value="full_diff"><?php echo __("Full Backup + Differential Backups","xcloner-backup-and-restore");?></option>
266
  </select>
267
- <label for="backup_type"><?php echo __('Scheduled Backup Type','xcloner-backup-and-restore')?></label>
268
  </div>
269
  <div class="col s2 m1">
270
  <a class="btn-floating tooltipped btn-small" data-html="true" data-position="center" data-delay="50" data-tooltip="<ul style='max-width:760px; text-align:left;'>
271
- <li><?php echo __("Full Backup = it will generate a full backup of all included files each time schedule runs","xcloner-backup-and-restore");?></li>
272
- <li><?php echo __("Differentials Backups = backups will include only changed files since the schedule started to run","xcloner-backup-and-restore");?></li>
273
- <li><?php echo __("Full Backup + Differential Backups = the first time schedule runs, it will create a full backup and all next scheduled backups will include only files created/modified since that last full backup; a full backup is recreated when the number of changed files is bigger than the 'Differetial Backups Max Days' XCloner option.","xcloner-backup-and-restore");?></li>
274
  </ul>"><i class="material-icons">help_outline</i></a>
275
  </div>
276
  </div>
277
  -->
278
- <div class="row">
279
- <div class="input-field col s12 l7">
280
- <select name="schedule_frequency" id="schedule_frequency" class="validate" required>
281
- <option value="" disabled selected><?php echo __('please select', 'xcloner-backup-and-restore') ?></option>
 
282
  <?php
283
  $schedules = $xcloner_scheduler->get_available_intervals();
284
-
285
- foreach($schedules as $key=>$schedule)
286
- {
287
- ?>
288
- <option value="<?php echo $key?>"><?php echo $schedule['display']?></option>
289
- <?php
290
  }
291
- ?>
292
- </select>
293
- <label><?php echo __('Schedule Frequency', 'xcloner-backup-and-restore') ?></label>
294
- </div>
295
- </div>
296
-
297
- <?php if(sizeof($available_storages)):?>
298
- <div class="row">
299
- <div class="input-field col s12 m12 l7">
300
- <select name="schedule_storage" id="schedule_storage" class="validate">
301
- <option value="" selected><?php echo __('none', 'xcloner-backup-and-restore') ?></option>
302
- <?php foreach($available_storages as $storage=>$text):?>
303
- <option value="<?php echo $storage?>"><?php echo $text?></option>
304
- <?php endforeach?>
305
- </select>
306
- <label><?php echo __('Send To Remote Storage', 'xcloner-backup-and-restore') ?></label>
307
- </div>
308
- </div>
309
- <?php endif?>
310
- <div class="row">
311
- <div class="col s12 l7">
312
- <button class="right btn waves-effect waves-light submit_schedule" type="submit" name="action"><?php echo __("Submit" ,'xcloner-backup-and-restore')?>
313
- <i class="material-icons right">send</i>
314
- </button>
315
- </div>
316
- </div>
317
- </div>
318
- </div>
 
319
  </form>
320
 
321
  <!-- Error Modal Structure -->
322
  <div id="error_modal" class="modal">
323
- <a title="Online Help" href="https://wordpress.org/support/plugin/xcloner-backup-and-restore" target="_blank"><i class="material-icons medium right">help</i></a>
324
- <div class="modal-content">
325
- <h4 class="title_line"><span class="title"></span></h4>
326
- <!--<h5 class="title_line"><?php echo __('Message')?>: <span class="msg.old"></span></h5>-->
327
- <h5><?php echo __('Response Code', 'xcloner-backup-and-restore')?>: <span class="status"></span></h5>
328
- <textarea class="body" rows="5"></textarea>
329
- </div>
330
- <div class="modal-footer">
331
- <a class=" modal-action modal-close waves-effect waves-green btn-flat red darken-2"><?php echo __('Close','xcloner-backup-and-restore')?></a>
332
- </div>
 
333
  </div>
334
 
335
  <!-- List Backup Content Modal-->
336
  <div id="backup_cotent_modal" class="modal">
337
- <div class="modal-content">
338
- <h4><?php echo sprintf(__("Listing Backup Content ",'xcloner-backup-and-restore'), "")?></h4>
339
- <h5 class="backup-name"></h5>
340
-
341
- <div class="progress">
342
- <div class="indeterminate"></div>
343
- </div>
344
- <ul class="files-list"></ul>
345
- </div>
346
  </div>
347
 
348
  <!-- Remote Storage Modal Structure -->
349
  <div id="remote_storage_modal" class="modal">
350
- <form method="POST" class="remote-storage-form">
351
- <input type="hidden" name="file" class="backup_name">
352
- <div class="modal-content">
353
- <h4><?php echo __("Remote Storage Transfer",'xcloner-backup-and-restore')?></h4>
354
- <p>
355
- <?php if(sizeof($available_storages)):?>
356
- <div class="row">
357
- <div class="col s12 label">
358
- <label><?php echo __(sprintf('Send %s to remote storage', "<span class='backup_name'></span>"), 'xcloner-backup-and-restore') ?></label>
359
- </div>
360
- <div class="input-field col s8 m10">
361
- <select name="transfer_storage" id="transfer_storage" class="validate" required >
362
- <option value="" selected><?php echo __('please select...', 'xcloner-backup-and-restore') ?></option>
363
- <?php foreach($available_storages as $storage=>$text):?>
364
- <option value="<?php echo $storage?>"><?php echo $text?></option>
365
- <?php endforeach?>
366
- </select>
367
-
368
- </div>
369
- <div class="s4 m2 right">
370
- <button type="submit" class="upload-submit btn-floating btn-large waves-effect waves-light teal"><i class="material-icons">file_upload</i></submit>
371
- </div>
372
- </div>
373
- <div class="row status">
374
- <?php echo __("Uploading backup to the selected remote storage...",'xcloner-backup-and-restore')?> <span class="status-text"></span>
375
- <div class="progress">
376
- <div class="indeterminate"></div>
377
- </div>
378
- </div>
379
- <?php endif?>
380
- </p>
381
- </div>
382
- </form>
 
 
 
383
  </div>
384
-
385
  <script>
386
- jQuery(function () {
387
-
388
- jQuery('.col select').material_select();
389
- jQuery("select[required]").css({display: "block", height: 0, padding: 0, width: 0, position: 'absolute'});
390
- jQuery(".backup-done .cloud-upload").on("click", function(e){
391
- var xcloner_manage_backups = new Xcloner_Manage_Backups();
392
- var hash = jQuery(this).attr('href');
393
- var id = hash.substr(1)
394
-
395
- e.preventDefault();
396
- xcloner_manage_backups.cloud_upload(id)
397
- })
398
-
399
- jQuery("#generate_backup_form").on("submit", function(){
400
-
401
- xcloner_backup.params = xcloner_backup.get_form_params();
402
- var data = JSON.stringify(xcloner_backup.params);
403
-
404
- xcloner_backup.set_cancel(false);
405
-
406
- xcloner_backup.do_ajax(data, "save_schedule")
407
- return false;
408
- })
409
-
410
- jQuery(".backup-done .download").on("click", function(e){
411
- var xcloner_manage_backups = new Xcloner_Manage_Backups();
412
- var hash = jQuery(this).attr('href');
413
- var id = hash.substr(1)
414
-
415
- e.preventDefault();
416
- xcloner_manage_backups.download_backup_by_name(id)
417
- })
418
-
419
- jQuery(".backup-done .list-backup-content").on("click", function(e){
420
- var xcloner_manage_backups = new Xcloner_Manage_Backups();
421
- var hash = jQuery(this).attr('href');
422
- var id = hash.substr(1)
423
-
424
- e.preventDefault();
425
- xcloner_manage_backups.list_backup_content(id)
426
- })
427
-
428
- jQuery('.timepicker').pickatime({
429
- default: 'now',
430
- min: [7,30],
431
- twelvehour: false, // change to 12 hour AM/PM clock from 24 hour
432
- donetext: 'OK',
433
- autoclose: false,
434
- vibrate: true // vibrate the device when dragging clock hand
435
- });
436
-
437
- var date_picker = jQuery('.datepicker').pickadate({
438
- format: 'd mmmm yyyy',
439
- selectMonths: true, // Creates a dropdown to control month
440
- selectYears: 15, // Creates a dropdown of 15 years to control year
441
- min: +0.1,
442
- onSet: function() {
443
- //this.close();
444
- }
445
- });
446
-
447
- var date_picker_allowed = jQuery('.datepicker_max_today').pickadate({
448
- format: 'd mmmm yyyy',
449
- selectMonths: true, // Creates a dropdown to control month
450
- selectYears: 15, // Creates a dropdown of 15 years to control year
451
- max: +0.1,
452
- onSet: function() {
453
- //this.close();
454
- }
455
- });
456
-
457
- <?php if($xcloner_settings->get_enable_mysql_backup()):?>
458
- jQuery('#jstree_database_container').jstree({
459
- 'core' : {
460
- 'check_callback' : true,
461
- 'data' : {
462
- 'method': 'POST',
463
- 'dataType': 'json',
464
- 'url' : ajaxurl,
465
- 'data' : function (node) {
466
- var data = {
467
- 'action': 'get_database_tables_action',
468
- 'id' : node.id
469
- }
470
- return data;
471
- }
472
- },
473
-
474
- 'error' : function (err) {
475
- //alert("We have encountered a communication error with the server, please review the javascript console.");
476
- var json = jQuery.parseJSON( err.data )
477
- show_ajax_error("Error Loading Database Structure ", err.reason, json.xhr);
478
- },
479
-
480
- 'strings' : { 'Loading ...' : 'Loading the database structure...' },
481
- 'themes' : {
482
- "variant" : "default"
483
- },
484
- },
485
- 'checkbox': {
486
- three_state: true
487
- },
488
- 'plugins' : [
489
- "checkbox",
490
- "massload",
491
- "search",
492
- //"sort",
493
- //"state",
494
- "types",
495
- "unique",
496
- "wholerow"
497
- ]
498
- });
499
- <?php endif ?>
500
-
501
- jQuery('#jstree_files_container').jstree({
502
- 'core' : {
503
- 'check_callback' : true,
504
- 'data' : {
505
- 'method': 'POST',
506
- 'dataType': 'json',
507
- 'url' : ajaxurl,
508
- 'data' : function (node) {
509
- var data = {
510
- 'action': 'get_file_system_action',
511
- 'id' : node.id
512
- }
513
- return data;
514
- }
515
- },
516
-
517
- 'error' : function (err) {
518
- //alert("We have encountered a communication error with the server, please review the javascript console.");
519
- var json = jQuery.parseJSON( err.data )
520
- show_ajax_error("Error Loading Files Structure ", err.reason, json.xhr);
521
- },
522
-
523
- 'strings' : { 'Loading ...' : 'Loading the database structure...' },
524
- 'themes' : {
525
- "variant" : "default"
526
- },
527
- },
528
- 'checkbox': {
529
- three_state: true
530
- },
531
- 'plugins' : [
532
- "checkbox",
533
- "massload",
534
- "search",
535
- //"sort",
536
- //"state",
537
- "types",
538
- "unique",
539
- "wholerow"
540
- ]
541
- });
542
- });
543
 
544
 
545
  </script>
1
+ <?php
2
+ $xcloner_settings = $this->get_xcloner_container()->get_xcloner_settings();
3
  $xcloner_remote_storage = $this->get_xcloner_container()->get_xcloner_remote_storage();
4
+ $available_storages = $xcloner_remote_storage->get_available_storages();
5
+ $xcloner_scheduler = $this->get_xcloner_container()->get_xcloner_scheduler();
6
+ $tab = 1;
7
  ?>
8
 
9
  <script>var xcloner_backup = new Xcloner_Backup();</script>
10
 
11
+ <h1><?= esc_html( get_admin_page_title() ); ?></h1>
12
+
13
  <ul class="nav-tab-wrapper content row">
14
+ <li><a href="#backup_options"
15
+ class="nav-tab col s12 m3 l2 nav-tab-active"><?php echo $tab . ". " . __( 'Backup Options', 'xcloner-backup-and-restore' ) ?></a>
16
+ </li>
17
+ <?php if ( $xcloner_settings->get_enable_mysql_backup() ): ?>
18
+ <li><a href="#database_options"
19
+ class="nav-tab col s12 m3 l2 "><?php echo ++ $tab . ". " . __( 'Database Options', 'xcloner-backup-and-restore' ) ?></a>
20
+ </li>
21
+ <?php endif ?>
22
+ <li><a href="#files_options"
23
+ class="nav-tab col s12 m3 l2 "><?php echo ++ $tab . ". " . __( 'Files Options', 'xcloner-backup-and-restore' ) ?></a>
24
+ </li>
25
+ <li><a href="#generate_backup"
26
+ class="nav-tab col s12 m3 l2 "><?php echo ++ $tab . ". " . __( 'Generate Backup', 'xcloner-backup-and-restore' ) ?></a>
27
+ </li>
28
+ <li><a href="#schedule_backup"
29
+ class="nav-tab col s12 m3 l2 "><?php echo ++ $tab . ". " . __( 'Schedule Backup', 'xcloner-backup-and-restore' ) ?></a>
30
+ </li>
31
  </ul>
32
 
33
  <form action="" method="POST" id="generate_backup_form">
34
+ <div class="nav-tab-wrapper-content">
35
+ <!-- Backup Options Content Tab-->
36
+ <div id="backup_options" class="tab-content active">
37
+ <div class="row">
38
+ <div class="input-field inline col s12 m10 l6">
39
+ <i class="material-icons prefix">input</i>
40
+ <input name="backup_name" id="backup_name" type="text"
41
+ value=<?php echo $xcloner_settings->get_default_backup_name() ?>>
42
+ <label for="backup_name"><?php echo __( 'Backup Name', 'xcloner-backup-and-restore' ) ?></label>
43
+ </div>
44
+ <div class="hide-on-small-only m2">
45
+ <a class="btn-floating tooltipped btn-small" data-position="right" data-delay="50"
46
+ data-tooltip="<?php echo __( 'The default backup name, supported tags [time], [hostname], [domain]', 'xcloner-backup-and-restore' ) ?>"
47
+ data-tooltip-id=""><i class="material-icons">help_outline</i></a>
48
+ </div>
49
+ </div>
50
+
51
+ <div class="row">
52
+ <div class="input-field inline col s12 m10 l6">
53
+ <i class="material-icons prefix">email</i>
54
+ <input name="email_notification" id="email_notification" type="text"
55
+ value="<?php echo get_option( 'admin_email' ); ?>">
56
+ <label for="email_notification"><?php echo __( 'Send Email Notification To', 'xcloner-backup-and-restore' ) ?></label>
57
+ </div>
58
+ <div class="hide-on-small-only m2">
59
+ <a class="btn-floating tooltipped btn-small" data-position="right" data-delay="50"
60
+ data-tooltip="<?php echo __( 'If left blank, no notification will be sent', 'xcloner-backup-and-restore' ) ?>"
61
+ data-tooltip-id=""><i class="material-icons">help_outline</i></a>
62
+ </div>
63
+ </div>
64
+
65
+ <div class="row">
66
+ <div class="input-field inline col s10 m10 l6">
67
+ <i class="material-icons prefix">access_time</i>
68
+ <input type="datetime-local" id="diff_start_date" class="datepicker_max_today"
69
+ name="diff_start_date">
70
+ <label for="diff_start_date"><?php echo __( 'Backup Only Files Modified/Created After', 'xcloner-backup-and-restore' ) ?></label>
71
+ </div>
72
+ <div class="hide-on-small-only m2">
73
+ <a class="btn-floating tooltipped btn-small" data-html="true" data-position="center" data-delay="50"
74
+ data-tooltip="<?php echo __( "This option allows you to create a differential backup that will include only <br> changed files since the set date, leave blank to include all files", "xcloner-backup-and-restore" ) ?>"><i
75
+ class="material-icons">help_outline</i></a>
76
+ </div>
77
+ </div>
78
+
79
+ <div class="row">
80
+ <div class="input-field col s12 m10 l6">
81
+ <i class="material-icons prefix">input</i>
82
+ <textarea name="backup_comments" id="backup_comments" class="materialize-textarea"></textarea>
83
+ <label for="backup_comments"><?php echo __( 'Backup Comments', 'xcloner-backup-and-restore' ) ?></label>
84
+ </div>
85
+ <div class="hide-on-small-only m2">
86
+ <a class="btn-floating tooltipped btn-small" data-position="right" data-delay="50"
87
+ data-tooltip="<?php echo __( 'Some default backup comments that will be stored inside the backup archive', 'xcloner-backup-and-restore' ) ?>"
88
+ data-tooltip-id=""><i class="material-icons">help_outline</i></a>
89
+ </div>
90
+ </div>
91
+
92
+ <div class="row">
93
+ <div class="input-field col s12 m10 l6 right-align">
94
+ <a class="waves-effect waves-light btn" onclick="next_tab('#database_options');"><i
95
+ class="material-icons right">skip_next</i>Next</a>
96
+ </div>
97
+ </div>
98
+ </div>
99
+
100
+ <?php if ( $xcloner_settings->get_enable_mysql_backup() ): ?>
101
+ <div id="database_options" class="tab-content">
102
+ <h2><?php echo __( 'Select database data to include in the backup', 'xcloner-backup-and-restore' ) ?>:
103
+ <a class="btn-floating tooltipped btn-small" data-position="right" data-delay="50"
104
+ data-tooltip="<?php echo __( 'Enable the \'Backup only WP tables\' setting if you don\'t want to show all other databases and tables not related to this Wordpress install', 'xcloner-backup-and-restore' ); ?>"
105
+ data-tooltip-id=""><i class="material-icons">help_outline</i></a>
106
+ </h2>
107
+
108
+ <!-- database/tables tree -->
109
+ <div class="row">
110
+ <div class="col s12 l6">
111
+ <div id="jstree_database_container"></div>
112
+ </div>
113
+ </div>
114
+
115
+ <div class="row">
116
+ <div class="input-field col s12 m10 l6 right-align">
117
+ <a class="waves-effect waves-light btn" onclick="next_tab('#files_options');"><i
118
+ class="material-icons right">skip_next</i>Next</a>
119
+ </div>
120
+ </div>
121
+
122
+ </div>
123
  <?php endif ?>
124
+
125
+ <div id="files_options" class="tab-content">
126
+ <h2><?php echo __( 'Select from below the files/folders you want to exclude from your Backup Archive', 'xcloner-backup-and-restore' ) ?>
127
+ :
128
+ <a class="btn-floating tooltipped btn-small" data-position="bottom" data-delay="50" data-html="true"
129
+ data-tooltip="<?php echo __( 'You can navigate below through all your site structure(Backup Start Location) to exclude any file/folder you need by clicking the checkbox near it. <br />If the checkobx is disabled, then it matches a Regex Exclude File option and it can\'t be unchecked', 'xcloner-backup-and-restore' ); ?>"
130
+ data-tooltip-id=""><i class="material-icons">help_outline</i></a>
131
+ </h2>
132
+
133
+ <!-- Files System Container -->
134
+ <div class="row">
135
+ <div class="col s12 l6">
136
+ <div id="jstree_files_container"></div>
137
+ </div>
138
+ </div>
139
+
140
+ <div class="row">
141
+ <div class="input-field col s12 m10 l6 right-align">
142
+ <a class="waves-effect waves-light btn" onclick="next_tab('#generate_backup');"><i
143
+ class="material-icons right">skip_next</i>Next</a>
144
+ </div>
145
+ </div>
146
+
147
+ </div>
148
+ <div id="generate_backup" class="tab-content">
149
+ <div class="row ">
150
+ <div class="col s12 l10 center action-buttons">
151
+ <a class="waves-effect waves-light btn-large teal darken-1 start"
152
+ onclick="xcloner_backup.start_backup()">Start Backup<i
153
+ class="material-icons left">forward</i></a>
154
+ <a class="waves-effect waves-light btn-large teal darken-1 restart"
155
+ onclick="xcloner_backup.restart_backup()">Restart Backup<i class="material-icons left">cached</i></a>
156
+ <a class="waves-effect waves-light btn-large red darken-1 cancel"
157
+ onclick="xcloner_backup.cancel_backup()">Cancel Backup<i
158
+ class="material-icons left">cancel</i></a>
159
+ </div>
160
+ <div class="col l10 s12">
161
+ <ul class="backup-status collapsible" data-collapsible="accordion">
162
+ <li class="file-system">
163
+ <div class="collapsible-header">
164
+ <i class="material-icons">folder</i><?php echo __( 'Scanning The File System...', 'xcloner-backup-and-restore' ) ?>
165
+
166
+ <p class="right"><?php echo sprintf( __( 'Found %s files (%s)', 'xcloner-backup-and-restore' ), '<span class="file-counter">0</span>', '<span class="file-size-total">0</span>MB' ) ?></p>
167
+
168
+ <div>
169
+ <p class="right"><span class="last-logged-file"></span></p>
170
+ </div>
171
+
172
+ <div class="progress">
173
+ <div class="indeterminate"></div>
174
+ </div>
175
+ </div>
176
+ <div class="collapsible-body status-body"></div>
177
+ </li>
178
+ <?php if ( $xcloner_settings->get_enable_mysql_backup() ): ?>
179
+ <li class="database-backup">
180
+ <div class="collapsible-header">
181
+ <i class="material-icons">storage</i><?php echo __( 'Generating the Mysql Backup...', 'xcloner-backup-and-restore' ) ?>
182
+
183
+ <p class="right"><?php echo sprintf( __( 'Found %s tables in %s databases (%s)', 'xcloner-backup-and-restore' ), '<span class="table-counter">0</span>', '<span class="database-counter">0</span>', '<span data-processed="0" class="total-records">0</span> records', 'xcloner-backup-and-restore' ) ?></p>
184
+
185
+ <div>
186
+ <p class="right"><span class="last-logged-table"></span></p>
187
+ </div>
188
+
189
+ <div class="progress">
190
+ <div class="determinate" style="width:0%"></div>
191
+ </div>
192
+ </div>
193
+ <div class="collapsible-body status-body">
194
+ <div class="row">
195
+ <div class="col l7 s12">
196
+ <ul class="logged-tables"></ul>
197
+ </div>
198
+ <div class="col l5 s12">
199
+ <ul class="logged-databases right"></ul>
200
+ </div>
201
+ </div>
202
+ </div>
203
+ </li>
204
+ <?php endif ?>
205
+ <li class="files-backup">
206
+ <div class="collapsible-header">
207
+ <i class="material-icons">archive</i><?php echo __( 'Adding Files to Archive...', 'xcloner-backup-and-restore' ) ?>
208
+
209
+ <p class="right"><?php echo sprintf( __( 'Adding %s files (%s)', 'xcloner-backup-and-restore' ), '<span class="file-counter">0</span>', '<span data-processed="0" class="file-size-total">0</span>MB' ) ?></p>
210
+
211
+ <div>
212
+ <p class="right"><span class="last-logged-file"></span></p>
213
+ </div>
214
+
215
+ <div class="progress">
216
+ <div class="determinate" style="width:0%"></div>
217
+ </div>
218
+ </div>
219
+ <div class="collapsible-body status-body">
220
+ <div class="row">
221
+ <div class="col l3 s12">
222
+ <h2><?php echo __( "Backup Parts", 'xcloner-backup-and-restore' ) ?>: </h2>
223
+ </div>
224
+ <div class="col l9 s12">
225
+ <ul class="backup-name"></ul>
226
+ </div>
227
+ </div>
228
+ </div>
229
+ </li>
230
+ <li class="backup-done">
231
+ <div class="collapsible-header">
232
+ <i class="material-icons">done</i><?php echo __( 'Backup Done', 'xcloner-backup-and-restore' ) ?>
233
+
234
+ <p class="right">
235
+ <?php if ( sizeof( $available_storages ) ): ?>
236
+ <a href="#" class="cloud-upload"
237
+ title="<?php echo __( "Send Backup To Remote Storage", 'xcloner-backup-and-restore' ) ?>"><i
238
+ class="material-icons">cloud_upload</i></a>
239
+ <?php endif ?>
240
+ <a href="#" class="download"
241
+ title="<?php echo __( "Download Backup", 'xcloner-backup-and-restore' ) ?>"><i
242
+ class="material-icons">file_download</i></a>
243
+ <a href="#" class="list-backup-content"
244
+ title="<?php echo __( "List Backup Content", 'xcloner-backup-and-restore' ) ?>"><i
245
+ class="material-icons">folder_open</i></a>
246
+ </p>
247
+
248
+ <div class="progress">
249
+ <div class="determinate" style="width:100%"></div>
250
+ </div>
251
+
252
+ </div>
253
+ <div class="collapsible-body center-align">
254
+ <div class="row">
255
+ <h5><?php echo __( "Thank you for using XCloner.", 'xcloner-backup-and-restore' ) ?></h5>
256
+ <h6><?php echo sprintf( __( "We would love to hear about your experience in the %s.", 'xcloner-backup-and-restore' ), '<a href="https://wordpress.org/support/plugin/xcloner-backup-and-restore/reviews/" target="_blank">Wordpress XCloner Reviews Section</a>' ) ?></h6>
257
+ <a class="twitter-follow-button" href="https://twitter.com/thinkovi"
258
+ data-show-count="false">Follow @thinkovi</a>
259
+ <script src="//platform.twitter.com/widgets.js" async="" charset="utf-8"></script>
260
+
261
+ <br/>
262
+ <!-- XCLONER SPONSORS AREA-->
263
+ <!-- END XCLONER SPONSORS AREA-->
264
+ </div>
265
+ </div>
266
+ </li>
267
+ </ul>
268
+ </div>
269
+
270
+ </div>
271
+ </div>
272
+
273
+ <div id="schedule_backup" class="tab-content">
274
+
275
+ <div class="row">
276
+ <div id="schedule_backup_success" class="col s12 l6 updated settings-error notice is-dismissible">
277
+ <p><strong><?php echo __( 'Schedule Saved', 'xcloner-backup-and-restore' ) ?></strong></p>
278
+ <button type="button" class="notice-dismiss"><span
279
+ class="screen-reader-text"><?php echo __( '(Dismiss this notice.', 'xcloner-backup-and-restore' ) ?></span>
280
+ </button>
281
+ </div>
282
+ </div>
283
+
284
+ <div class="row">
285
+ <div class="input-field inline col s12 l7">
286
+ <input type="text" id="schedule_name" class="" name="schedule_name" required>
287
+ <label for="schedule_name"><?php echo __( 'Schedule Name', 'xcloner-backup-and-restore' ) ?></label>
288
+ </div>
289
+ </div>
290
+
291
+ <div class="row">
292
+ <div class="input-field inline col s12 m8 l4">
293
+ <input type="datetime-local" id="datepicker" class="datepicker" name="schedule_start_date">
294
+ <label for="datepicker"><?php echo __( 'Schedule Backup To Start On:', 'xcloner-backup-and-restore' ) ?></label>
295
+ </div>
296
+ <div class="input-field inline col s12 m4 l3">
297
+ <input id="timepicker_ampm_dark" class="timepicker" type="time" name="schedule_start_time">
298
+ <label for="timepicker_ampm_dark"><?php echo __( 'At:', 'xcloner-backup-and-restore' ) ?></label>
299
+ </div>
300
+ </div>
301
+
302
+ <!--
303
  <div class="row">
304
  <div class="input-field inline col s10 m11 l7">
305
  <select id="backup_type" class="" name="backup_type">
306
+ <option value=""><?php echo __( "Full Backup", "xcloner-backup-and-restore" ); ?></option>
307
+ <option value="diff"><?php echo __( "Differential Backups", "xcloner-backup-and-restore" ); ?></option>
308
+ <option value="full_diff"><?php echo __( "Full Backup + Differential Backups", "xcloner-backup-and-restore" ); ?></option>
309
  </select>
310
+ <label for="backup_type"><?php echo __( 'Scheduled Backup Type', 'xcloner-backup-and-restore' ) ?></label>
311
  </div>
312
  <div class="col s2 m1">
313
  <a class="btn-floating tooltipped btn-small" data-html="true" data-position="center" data-delay="50" data-tooltip="<ul style='max-width:760px; text-align:left;'>
314
+ <li><?php echo __( "Full Backup = it will generate a full backup of all included files each time schedule runs", "xcloner-backup-and-restore" ); ?></li>
315
+ <li><?php echo __( "Differentials Backups = backups will include only changed files since the schedule started to run", "xcloner-backup-and-restore" ); ?></li>
316
+ <li><?php echo __( "Full Backup + Differential Backups = the first time schedule runs, it will create a full backup and all next scheduled backups will include only files created/modified since that last full backup; a full backup is recreated when the number of changed files is bigger than the 'Differetial Backups Max Days' XCloner option.", "xcloner-backup-and-restore" ); ?></li>
317
  </ul>"><i class="material-icons">help_outline</i></a>
318
  </div>
319
  </div>
320
  -->
321
+ <div class="row">
322
+ <div class="input-field col s12 l7">
323
+ <select name="schedule_frequency" id="schedule_frequency" class="validate" required>
324
+ <option value="" disabled
325
+ selected><?php echo __( 'please select', 'xcloner-backup-and-restore' ) ?></option>
326
  <?php
327
  $schedules = $xcloner_scheduler->get_available_intervals();
328
+
329
+ foreach ( $schedules as $key => $schedule ) {
330
+ ?>
331
+ <option value="<?php echo $key ?>"><?php echo $schedule['display'] ?></option>
332
+ <?php
 
333
  }
334
+ ?>
335
+ </select>
336
+ <label><?php echo __( 'Schedule Frequency', 'xcloner-backup-and-restore' ) ?></label>
337
+ </div>
338
+ </div>
339
+
340
+ <?php if ( sizeof( $available_storages ) ): ?>
341
+ <div class="row">
342
+ <div class="input-field col s12 m12 l7">
343
+ <select name="schedule_storage" id="schedule_storage" class="validate">
344
+ <option value="" selected><?php echo __( 'none', 'xcloner-backup-and-restore' ) ?></option>
345
+ <?php foreach ( $available_storages as $storage => $text ): ?>
346
+ <option value="<?php echo $storage ?>"><?php echo $text ?></option>
347
+ <?php endforeach ?>
348
+ </select>
349
+ <label><?php echo __( 'Send To Remote Storage', 'xcloner-backup-and-restore' ) ?></label>
350
+ </div>
351
+ </div>
352
+ <?php endif ?>
353
+ <div class="row">
354
+ <div class="col s12 l7">
355
+ <button class="right btn waves-effect waves-light submit_schedule" type="submit"
356
+ name="action"><?php echo __( "Submit", 'xcloner-backup-and-restore' ) ?>
357
+ <i class="material-icons right">send</i>
358
+ </button>
359
+ </div>
360
+ </div>
361
+ </div>
362
+ </div>
363
  </form>
364
 
365
  <!-- Error Modal Structure -->
366
  <div id="error_modal" class="modal">
367
+ <a title="Online Help" href="https://wordpress.org/support/plugin/xcloner-backup-and-restore" target="_blank"><i
368
+ class="material-icons medium right">help</i></a>
369
+ <div class="modal-content">
370
+ <h4 class="title_line"><span class="title"></span></h4>
371
+ <!--<h5 class="title_line"><?php echo __( 'Message' ) ?>: <span class="msg.old"></span></h5>-->
372
+ <h5><?php echo __( 'Response Code', 'xcloner-backup-and-restore' ) ?>: <span class="status"></span></h5>
373
+ <textarea class="body" rows="5"></textarea>
374
+ </div>
375
+ <div class="modal-footer">
376
+ <a class=" modal-action modal-close waves-effect waves-green btn-flat red darken-2"><?php echo __( 'Close', 'xcloner-backup-and-restore' ) ?></a>
377
+ </div>
378
  </div>
379
 
380
  <!-- List Backup Content Modal-->
381
  <div id="backup_cotent_modal" class="modal">
382
+ <div class="modal-content">
383
+ <h4><?php echo sprintf( __( "Listing Backup Content ", 'xcloner-backup-and-restore' ), "" ) ?></h4>
384
+ <h5 class="backup-name"></h5>
385
+
386
+ <div class="progress">
387
+ <div class="indeterminate"></div>
388
+ </div>
389
+ <ul class="files-list"></ul>
390
+ </div>
391
  </div>
392
 
393
  <!-- Remote Storage Modal Structure -->
394
  <div id="remote_storage_modal" class="modal">
395
+ <form method="POST" class="remote-storage-form">
396
+ <input type="hidden" name="file" class="backup_name">
397
+ <div class="modal-content">
398
+ <h4><?php echo __( "Remote Storage Transfer", 'xcloner-backup-and-restore' ) ?></h4>
399
+ <p>
400
+ <?php if ( sizeof( $available_storages ) ): ?>
401
+ <div class="row">
402
+ <div class="col s12 label">
403
+ <label><?php echo __( sprintf( 'Send %s to remote storage', "<span class='backup_name'></span>" ), 'xcloner-backup-and-restore' ) ?></label>
404
+ </div>
405
+ <div class="input-field col s8 m10">
406
+ <select name="transfer_storage" id="transfer_storage" class="validate" required>
407
+ <option value=""
408
+ selected><?php echo __( 'please select...', 'xcloner-backup-and-restore' ) ?></option>
409
+ <?php foreach ( $available_storages as $storage => $text ): ?>
410
+ <option value="<?php echo $storage ?>"><?php echo $text ?></option>
411
+ <?php endforeach ?>
412
+ </select>
413
+
414
+ </div>
415
+ <div class="s4 m2 right">
416
+ <button type="submit" class="upload-submit btn-floating btn-large waves-effect waves-light teal"><i
417
+ class="material-icons">file_upload</i></submit>
418
+ </div>
419
+ </div>
420
+ <div class="row status">
421
+ <?php echo __( "Uploading backup to the selected remote storage...", 'xcloner-backup-and-restore' ) ?>
422
+ <span class="status-text"></span>
423
+ <div class="progress">
424
+ <div class="indeterminate"></div>
425
+ </div>
426
+ </div>
427
+ <?php endif ?>
428
+ </p>
429
+ </div>
430
+ </form>
431
  </div>
432
+
433
  <script>
434
+ jQuery(function () {
435
+
436
+ jQuery('.col select').material_select();
437
+ jQuery("select[required]").css({display: "block", height: 0, padding: 0, width: 0, position: 'absolute'});
438
+ jQuery(".backup-done .cloud-upload").on("click", function (e) {
439
+ var xcloner_manage_backups = new Xcloner_Manage_Backups();
440
+ var hash = jQuery(this).attr('href');
441
+ var id = hash.substr(1)
442
+
443
+ e.preventDefault();
444
+ xcloner_manage_backups.cloud_upload(id)
445
+ })
446
+
447
+ jQuery("#generate_backup_form").on("submit", function () {
448
+
449
+ xcloner_backup.params = xcloner_backup.get_form_params();
450
+ var data = JSON.stringify(xcloner_backup.params);
451
+
452
+ xcloner_backup.set_cancel(false);
453
+
454
+ xcloner_backup.do_ajax(data, "save_schedule")
455
+ return false;
456
+ })
457
+
458
+ jQuery(".backup-done .download").on("click", function (e) {
459
+ var xcloner_manage_backups = new Xcloner_Manage_Backups();
460
+ var hash = jQuery(this).attr('href');
461
+ var id = hash.substr(1)
462
+
463
+ e.preventDefault();
464
+ xcloner_manage_backups.download_backup_by_name(id)
465
+ })
466
+
467
+ jQuery(".backup-done .list-backup-content").on("click", function (e) {
468
+ var xcloner_manage_backups = new Xcloner_Manage_Backups();
469
+ var hash = jQuery(this).attr('href');
470
+ var id = hash.substr(1)
471
+
472
+ e.preventDefault();
473
+ xcloner_manage_backups.list_backup_content(id)
474
+ })
475
+
476
+ jQuery('.timepicker').pickatime({
477
+ default: 'now',
478
+ min: [7, 30],
479
+ twelvehour: false, // change to 12 hour AM/PM clock from 24 hour
480
+ donetext: 'OK',
481
+ autoclose: false,
482
+ vibrate: true // vibrate the device when dragging clock hand
483
+ });
484
+
485
+ var date_picker = jQuery('.datepicker').pickadate({
486
+ format: 'd mmmm yyyy',
487
+ selectMonths: true, // Creates a dropdown to control month
488
+ selectYears: 15, // Creates a dropdown of 15 years to control year
489
+ min: +0.1,
490
+ onSet: function () {
491
+ //this.close();
492
+ }
493
+ });
494
+
495
+ var date_picker_allowed = jQuery('.datepicker_max_today').pickadate({
496
+ format: 'd mmmm yyyy',
497
+ selectMonths: true, // Creates a dropdown to control month
498
+ selectYears: 15, // Creates a dropdown of 15 years to control year
499
+ max: +0.1,
500
+ onSet: function () {
501
+ //this.close();
502
+ }
503
+ });
504
+
505
+ <?php if($xcloner_settings->get_enable_mysql_backup()):?>
506
+ jQuery('#jstree_database_container').jstree({
507
+ 'core': {
508
+ 'check_callback': true,
509
+ 'data': {
510
+ 'method': 'POST',
511
+ 'dataType': 'json',
512
+ 'url': ajaxurl,
513
+ 'data': function (node) {
514
+ var data = {
515
+ 'action': 'get_database_tables_action',
516
+ 'id': node.id
517
+ }
518
+ return data;
519
+ }
520
+ },
521
+
522
+ 'error': function (err) {
523
+ //alert("We have encountered a communication error with the server, please review the javascript console.");
524
+ var json = jQuery.parseJSON(err.data)
525
+ show_ajax_error("Error Loading Database Structure ", err.reason, json.xhr);
526
+ },
527
+
528
+ 'strings': {'Loading ...': 'Loading the database structure...'},
529
+ 'themes': {
530
+ "variant": "default"
531
+ },
532
+ },
533
+ 'checkbox': {
534
+ three_state: true
535
+ },
536
+ 'plugins': [
537
+ "checkbox",
538
+ "massload",
539
+ "search",
540
+ //"sort",
541
+ //"state",
542
+ "types",
543
+ "unique",
544
+ "wholerow"
545
+ ]
546
+ });
547
+ <?php endif ?>
548
+
549
+ jQuery('#jstree_files_container').jstree({
550
+ 'core': {
551
+ 'check_callback': true,
552
+ 'data': {
553
+ 'method': 'POST',
554
+ 'dataType': 'json',
555
+ 'url': ajaxurl,
556
+ 'data': function (node) {
557
+ var data = {
558
+ 'action': 'get_file_system_action',
559
+ 'id': node.id
560
+ }
561
+ return data;
562
+ }
563
+ },
564
+
565
+ 'error': function (err) {
566
+ //alert("We have encountered a communication error with the server, please review the javascript console.");
567
+ var json = jQuery.parseJSON(err.data)
568
+ show_ajax_error("Error Loading Files Structure ", err.reason, json.xhr);
569
+ },
570
+
571
+ 'strings': {'Loading ...': 'Loading the database structure...'},
572
+ 'themes': {
573
+ "variant": "default"
574
+ },
575
+ },
576
+ 'checkbox': {
577
+ three_state: true
578
+ },
579
+ 'plugins': [
580
+ "checkbox",
581
+ "massload",
582
+ "search",
583
+ //"sort",
584
+ //"state",
585
+ "types",
586
+ "unique",
587
+ "wholerow"
588
+ ]
589
+ });
590
+ });
591
 
592
 
593
  </script>
admin/partials/xcloner_init_page.php CHANGED
@@ -12,11 +12,11 @@
12
  * @subpackage Xcloner/admin/partials
13
  */
14
 
15
- $requirements = $this->get_xcloner_container()->get_xcloner_requirements();
16
- $xcloner_settings = $this->get_xcloner_container()->get_xcloner_settings();
17
- $xcloner_file_system = $this->get_xcloner_container()->get_xcloner_filesystem();
18
- $logger = $this->get_xcloner_container()->get_xcloner_logger();
19
- $xcloner_scheduler = $this->get_xcloner_container()->get_xcloner_scheduler();
20
 
21
  $logger_content = $logger->getLastDebugLines();
22
 
@@ -25,219 +25,250 @@ $time_format = get_option( 'time_format' );
25
 
26
  //$xcloner_file_system->cleanup_tmp_directories();
27
 
28
- if($requirements->check_backup_ready_status())
29
- {
30
- $latest_backup = $xcloner_file_system->get_latest_backup();
31
  $xcloner_file_system->backup_storage_cleanup();
32
  }
33
  ?>
34
 
35
  <div class="row">
36
- <div class="col s12">
37
- <h5 class="left-align">
38
- <?php echo __('Backup Dashboard', 'xcloner-backup-and-restore') ?>
39
- </h5>
40
- </div>
41
  </div>
42
 
43
- <?php if(isset($latest_backup['timestamp']) and $latest_backup['timestamp'] < strtotime("-1 day")): ?>
44
- <div id="setting-error-" class="error settings-error notice is-dismissible">
45
- <p><strong>
46
- <?php echo __('Your latest backup is older than 24 hours, please create a new backup to keep your site protected.', 'xcloner-backup-and-restore') ?>
47
- </strong>
48
- </p><button type="button" class="notice-dismiss"><span class="screen-reader-text">Dismiss this notice.</span></button>
49
- </div>
50
- <?php endif?>
51
-
52
- <?php if(!isset($latest_backup['timestamp']) ): ?>
53
- <div id="setting-error-" class="error settings-error notice is-dismissible">
54
- <p><strong>
55
- <?php echo __('You have no backup that I could find, please generate a new backup to keep your site protected.', 'xcloner-backup-and-restore') ?>
56
- </strong>
57
- </p><button type="button" class="notice-dismiss"><span class="screen-reader-text">Dismiss this notice.</span></button>
58
- </div>
59
- <?php endif?>
60
-
61
- <?php if(!$requirements->check_backup_ready_status()):?>
62
- <div id="setting-error-" class="error settings-error notice is-dismissible">
63
- <p><strong>
64
- <?php echo __('Backup system not ready, please check and fix the issues marked in red', 'xcloner-backup-and-restore') ?>
65
- </strong>
66
- </p><button type="button" class="notice-dismiss"><span class="screen-reader-text">Dismiss this notice.</span></button>
67
- </div>
68
-
 
 
 
 
 
 
69
  <?php endif ?>
70
 
71
 
72
-
73
  <!-- This file should primarily consist of HTML with a little bit of PHP. -->
74
  <div class="row dashboard">
75
- <div class="col s12 m12 l7">
76
-
77
- <div class="row">
78
-
79
- <ul class="collapsible xcloner-debugger" data-collapsible="accordion">
80
-
81
- <li class="active">
82
- <div class="collapsible-header active"><i class="material-icons">info</i>Backup Status</div>
83
- <div class="collapsible-body">
84
- <div class="" id="backup-status">
85
- <div class="row">
86
- <h5><?php echo __("Latest Backup", 'xcloner-backup-and-restore')?></h5>
87
- <blockquote>
88
- <?php if($latest_backup):?>
89
- <div class="item">
90
- <div class="title"><?php echo __("Backup Name", 'xcloner-backup-and-restore')?>:</div>
91
- <?php echo $latest_backup['basename']?>
92
- </div>
93
- <div class="item">
94
- <div class="title">
95
- <?php echo __("Backup Size", 'xcloner-backup-and-restore')?>:
96
- </div>
97
- <?php echo size_format($latest_backup['size'])?>
98
- </div>
99
- <div class="item">
100
- <div class="title"><?php echo __("Backup Date", 'xcloner-backup-and-restore')?>:</div>
101
- <?php
102
- echo date($date_format." ".$time_format, $latest_backup['timestamp']+(get_option( 'gmt_offset' ) * HOUR_IN_SECONDS))
103
- ?>
104
- </div>
105
- <?php else:?>
106
- <div class="item">
107
- <div class="title"><?php echo __("No Backup Yet", 'xcloner-backup-and-restore')?></div>
108
- </div>
109
- <?php endif?>
110
- </blockquote>
111
- <div>
112
- <h5><?php echo __("Backup Storage Usage", 'xcloner-backup-and-restore')?></h5>
113
- <blockquote>
114
- <div class="item">
115
- <div class="title"><?php echo __("Total Size", 'xcloner-backup-and-restore')?>:</div>
116
- <?php echo size_format($xcloner_file_system->get_storage_usage());?>
117
- </div>
118
- </blockquote>
119
- <h5><?php echo __("Next Scheduled Backup", 'xcloner-backup-and-restore')?></h5>
120
- <blockquote>
121
- <div class="item">
122
- <?php
123
- $list = ($xcloner_scheduler->get_next_run_schedule());
124
-
125
- if(is_array($list))
126
- {
127
- $xcloner_file_system->sort_by($list, "next_run_time","asc");
128
- }
129
-
130
- if(isset($list[0]))
131
- $latest_schedule = $list[0];
132
- ?>
133
- <?php if(isset($latest_schedule->name)):?>
134
- <div class="title"><?php echo __("Schedule Name", 'xcloner-backup-and-restore')?>:</div>
135
- <?php echo $latest_schedule->name;?>
136
- <?php endif;?>
137
- </div>
138
- <div class="item">
139
- <div class="title"><?php echo __("Next Call", 'xcloner-backup-and-restore')?>:</div>
140
- <?php if(isset($latest_schedule->next_run_time))
141
- echo date($date_format." ".$time_format, $latest_schedule->next_run_time);
142
- else
143
- echo __("Unscheduled",'xcloner-backup-and-restore');
144
- ?>
145
- </div>
146
- </blockquote>
147
- </div>
148
- </div>
149
- </li>
150
-
151
- <?php if($xcloner_settings->get_xcloner_option('xcloner_enable_log')) :?>
152
- <li class="active">
153
- <div class="collapsible-header active">
154
- <i class="material-icons">bug_report</i><?php echo __('XCloner Debugger', 'xcloner-backup-and-restore')?>
155
- <div class="right">
156
- <a href="#<?php echo $logger_basename = basename($logger->get_main_logger_url())?>" class="download-logger" title="<?php echo $logger_basename?>">
157
- <span class="shorten_string"><?php echo $logger_basename?>&nbsp;&nbsp;&nbsp;</span>
158
- </a>
159
- </div>
160
- </div>
161
- <div class="collapsible-body">
162
- <div class="console" id="xcloner-console"><?php if($logger_content) echo implode("<br />\n", array_reverse($logger_content)); ?></div>
163
- </div>
164
- </li>
165
- <script>
166
- jQuery(document).ready(function(){
167
- var objDiv = document.getElementById("xcloner-console");
168
- objDiv.scrollTop = objDiv.scrollHeight;
169
- /*setInterval(function(){
170
- getXclonerLog();
171
- }, 2000);*/
172
- })
173
- </script>
174
- <?php endif;?>
175
-
176
- </ul>
177
-
178
- </div>
179
-
180
-
181
- </div>
182
- <div class="col s12 m12 l5">
183
-
184
- <div class="card blue-grey darken-1 z-depth-4 backup-ready">
185
- <div class="card-content white-text">
186
- <span class="card-title"><?php echo __("System Check",'xcloner-backup-and-restore')?></span>
187
- <ul>
188
- <li class="card-panel <?php echo ($requirements->check_xcloner_start_path(1)?"teal":"red")?> lighten-2" >
189
- <?php echo __('Backup Start Location','xcloner-backup-and-restore')?>: <span class="shorten_string "><?php echo $requirements->check_xcloner_start_path();?></span>
190
- </li>
191
- <li class="card-panel <?php echo ($requirements->check_xcloner_store_path(1)?"teal":"red")?> lighten-2" >
192
- <?php echo __('Backup Storage Location','xcloner-backup-and-restore')?>: <span class="shorten_string"><?php echo $requirements->check_xcloner_store_path();?></span>
193
- </li>
194
- <li class="card-panel <?php echo ($requirements->check_xcloner_tmp_path(1)?"teal":"red")?> lighten-2" >
195
- <?php echo __('Temporary Location','xcloner-backup-and-restore')?>: <span class="shorten_string"><?php echo $requirements->check_xcloner_tmp_path();?></span>
196
- </li>
197
-
198
- <li class="card-panel <?php echo ($requirements->check_min_php_version(1)?"teal":"red")?> lighten-2" >
199
- <?php echo __('PHP Version Check','xcloner-backup-and-restore')?>: <?php echo $requirements->check_min_php_version();?>
200
- ( >= <?php echo $requirements->get_constant('min_php_version')?>)
201
- </li>
202
- <li class="card-panel <?php echo ($requirements->check_safe_mode(1)?"teal":"orange")?> lighten-2" >
203
- <?php echo __('PHP Safe Mode','xcloner-backup-and-restore')?>: <?php echo $requirements->check_safe_mode();?>
204
- ( <?php echo $requirements->get_constant('safe_mode')?>)
205
- </li>
206
- <li class="card-panel <?php echo ($requirements->check_backup_ready_status()?"teal":"red")?> lighten-2">
207
- <?php echo ($requirements->check_backup_ready_status()?__('BACKUP READY','xcloner-backup-and-restore'):__('Backup not ready, please check above requirements','xcloner-backup-and-restore'))?>
208
- <i class="material-icons right tiny"><?php echo ($requirements->check_backup_ready_status()?'thumb_up':'thumb_down')?></i>
209
- </li>
210
- </ul>
211
- <ul class="additional_system_info">
212
- <li class="card-panel grey darken-1" >
213
- <?php echo __('PHP max_execution_time','xcloner-backup-and-restore')?>: <?php echo $requirements->get_max_execution_time();?>
214
- </li>
215
- <li class="card-panel grey darken-1" >
216
- <?php echo __('PHP memory_limit','xcloner-backup-and-restore')?>: <?php echo $requirements->get_memory_limit();?>
217
- </li>
218
- <li class="card-panel grey darken-1" >
219
- <?php echo __('PHP open_basedir','xcloner-backup-and-restore')?>: <?php echo $requirements->get_open_basedir();?>
220
- </li>
221
- <?php
222
- $data = array();
223
- if($requirements->check_backup_ready_status())
224
- $data = $xcloner_file_system->estimate_read_write_time();
225
- ?>
226
- <li class="card-panel grey darken-1" >
227
- <?php echo __('Reading Time 1MB Block','xcloner-backup-and-restore')?>: <?php echo (isset($data['reading_time'])?$data['reading_time']:__("unknown"));?>
228
- </li>
229
- <li class="card-panel grey darken-1" >
230
- <?php echo __('Writing Time 1MB Block','xcloner-backup-and-restore')?>: <?php echo (isset($data['writing_time'])?$data['writing_time']:__("unknown"));?>
231
- </li>
232
- <li class="card-panel grey darken-1" >
233
- <?php echo __('Free Disk Space','xcloner-backup-and-restore')?>: <?php echo $requirements->get_free_disk_space();;?>
234
- </li>
235
- </ul>
236
- </div>
237
- <div class="card-action">
238
- <a class="waves-effect waves-light btn system_info_toggle blue darken-1"><i class="material-icons left">list</i><?php echo __('Toggle Additional System Info','xcloner-backup-and-restore')?></a>
239
- </div>
240
- </div>
241
-
242
- </div>
243
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  * @subpackage Xcloner/admin/partials
13
  */
14
 
15
+ $requirements = $this->get_xcloner_container()->get_xcloner_requirements();
16
+ $xcloner_settings = $this->get_xcloner_container()->get_xcloner_settings();
17
+ $xcloner_file_system = $this->get_xcloner_container()->get_xcloner_filesystem();
18
+ $logger = $this->get_xcloner_container()->get_xcloner_logger();
19
+ $xcloner_scheduler = $this->get_xcloner_container()->get_xcloner_scheduler();
20
 
21
  $logger_content = $logger->getLastDebugLines();
22
 
25
 
26
  //$xcloner_file_system->cleanup_tmp_directories();
27
 
28
+ if ( $requirements->check_backup_ready_status() ) {
29
+ $latest_backup = $xcloner_file_system->get_latest_backup();
 
30
  $xcloner_file_system->backup_storage_cleanup();
31
  }
32
  ?>
33
 
34
  <div class="row">
35
+ <div class="col s12">
36
+ <h5 class="left-align">
37
+ <?php echo __( 'Backup Dashboard', 'xcloner-backup-and-restore' ) ?>
38
+ </h5>
39
+ </div>
40
  </div>
41
 
42
+ <?php if ( isset( $latest_backup['timestamp'] ) and $latest_backup['timestamp'] < strtotime( "-1 day" ) ): ?>
43
+ <div id="setting-error-" class="error settings-error notice is-dismissible">
44
+ <p><strong>
45
+ <?php echo __( 'Your latest backup is older than 24 hours, please create a new backup to keep your site protected.', 'xcloner-backup-and-restore' ) ?>
46
+ </strong>
47
+ </p>
48
+ <button type="button" class="notice-dismiss"><span class="screen-reader-text">Dismiss this notice.</span>
49
+ </button>
50
+ </div>
51
+ <?php endif ?>
52
+
53
+ <?php if ( ! isset( $latest_backup['timestamp'] ) ): ?>
54
+ <div id="setting-error-" class="error settings-error notice is-dismissible">
55
+ <p><strong>
56
+ <?php echo __( 'You have no backup that I could find, please generate a new backup to keep your site protected.', 'xcloner-backup-and-restore' ) ?>
57
+ </strong>
58
+ </p>
59
+ <button type="button" class="notice-dismiss"><span class="screen-reader-text">Dismiss this notice.</span>
60
+ </button>
61
+ </div>
62
+ <?php endif ?>
63
+
64
+ <?php if ( ! $requirements->check_backup_ready_status() ): ?>
65
+ <div id="setting-error-" class="error settings-error notice is-dismissible">
66
+ <p><strong>
67
+ <?php echo __( 'Backup system not ready, please check and fix the issues marked in red', 'xcloner-backup-and-restore' ) ?>
68
+ </strong>
69
+ </p>
70
+ <button type="button" class="notice-dismiss"><span class="screen-reader-text">Dismiss this notice.</span>
71
+ </button>
72
+ </div>
73
+
74
  <?php endif ?>
75
 
76
 
 
77
  <!-- This file should primarily consist of HTML with a little bit of PHP. -->
78
  <div class="row dashboard">
79
+ <div class="col s12 m12 l7">
80
+
81
+ <div class="row">
82
+
83
+ <ul class="collapsible xcloner-debugger" data-collapsible="accordion">
84
+
85
+ <li class="active">
86
+ <div class="collapsible-header active"><i class="material-icons">info</i>Backup Status</div>
87
+ <div class="collapsible-body">
88
+ <div class="" id="backup-status">
89
+ <div class="row">
90
+ <h5><?php echo __( "Latest Backup", 'xcloner-backup-and-restore' ) ?></h5>
91
+ <blockquote>
92
+ <?php if ( $latest_backup ): ?>
93
+ <div class="item">
94
+ <div class="title"><?php echo __( "Backup Name", 'xcloner-backup-and-restore' ) ?>
95
+ :
96
+ </div>
97
+ <?php echo $latest_backup['basename'] ?>
98
+ </div>
99
+ <div class="item">
100
+ <div class="title">
101
+ <?php echo __( "Backup Size", 'xcloner-backup-and-restore' ) ?>:
102
+ </div>
103
+ <?php echo size_format( $latest_backup['size'] ) ?>
104
+ </div>
105
+ <div class="item">
106
+ <div class="title"><?php echo __( "Backup Date", 'xcloner-backup-and-restore' ) ?>
107
+ :
108
+ </div>
109
+ <?php
110
+ echo date( $date_format . " " . $time_format, $latest_backup['timestamp'] + ( get_option( 'gmt_offset' ) * HOUR_IN_SECONDS ) )
111
+ ?>
112
+ </div>
113
+ <?php else: ?>
114
+ <div class="item">
115
+ <div class="title"><?php echo __( "No Backup Yet", 'xcloner-backup-and-restore' ) ?></div>
116
+ </div>
117
+ <?php endif ?>
118
+ </blockquote>
119
+ <div>
120
+ <h5><?php echo __( "Backup Storage Usage", 'xcloner-backup-and-restore' ) ?></h5>
121
+ <blockquote>
122
+ <div class="item">
123
+ <div class="title"><?php echo __( "Total Size", 'xcloner-backup-and-restore' ) ?>
124
+ :
125
+ </div>
126
+ <?php echo size_format( $xcloner_file_system->get_storage_usage() ); ?>
127
+ </div>
128
+ </blockquote>
129
+ <h5><?php echo __( "Next Scheduled Backup", 'xcloner-backup-and-restore' ) ?></h5>
130
+ <blockquote>
131
+ <div class="item">
132
+ <?php
133
+ $list = ( $xcloner_scheduler->get_next_run_schedule() );
134
+
135
+ if ( is_array( $list ) ) {
136
+ $xcloner_file_system->sort_by( $list, "next_run_time", "asc" );
137
+ }
138
+
139
+ if ( isset( $list[0] ) ) {
140
+ $latest_schedule = $list[0];
141
+ }
142
+ ?>
143
+ <?php if ( isset( $latest_schedule->name ) ): ?>
144
+ <div class="title"><?php echo __( "Schedule Name", 'xcloner-backup-and-restore' ) ?>
145
+ :
146
+ </div>
147
+ <?php echo $latest_schedule->name; ?>
148
+ <?php endif; ?>
149
+ </div>
150
+ <div class="item">
151
+ <div class="title"><?php echo __( "Next Call", 'xcloner-backup-and-restore' ) ?>
152
+ :
153
+ </div>
154
+ <?php if ( isset( $latest_schedule->next_run_time ) ) {
155
+ echo date( $date_format . " " . $time_format, $latest_schedule->next_run_time );
156
+ } else {
157
+ echo __( "Unscheduled", 'xcloner-backup-and-restore' );
158
+ }
159
+ ?>
160
+ </div>
161
+ </blockquote>
162
+ </div>
163
+ </div>
164
+ </li>
165
+
166
+ <?php if ( $xcloner_settings->get_xcloner_option( 'xcloner_enable_log' ) ) : ?>
167
+ <li class="active">
168
+ <div class="collapsible-header active">
169
+ <i class="material-icons">bug_report</i><?php echo __( 'XCloner Debugger', 'xcloner-backup-and-restore' ) ?>
170
+ <div class="right">
171
+ <a href="#<?php echo $logger_basename = basename( $logger->get_main_logger_url() ) ?>"
172
+ class="download-logger" title="<?php echo $logger_basename ?>">
173
+ <span class="shorten_string"><?php echo $logger_basename ?>&nbsp;&nbsp;&nbsp;</span>
174
+ </a>
175
+ </div>
176
+ </div>
177
+ <div class="collapsible-body">
178
+ <div class="console" id="xcloner-console"><?php if ( $logger_content ) {
179
+ echo implode( "<br />\n", array_reverse( $logger_content ) );
180
+ } ?></div>
181
+ </div>
182
+ </li>
183
+ <script>
184
+ jQuery(document).ready(function () {
185
+ var objDiv = document.getElementById("xcloner-console");
186
+ objDiv.scrollTop = objDiv.scrollHeight;
187
+ /*setInterval(function(){
188
+ getXclonerLog();
189
+ }, 2000);*/
190
+ })
191
+ </script>
192
+ <?php endif; ?>
193
+
194
+ </ul>
195
+
196
+ </div>
197
+
198
+
199
+ </div>
200
+ <div class="col s12 m12 l5">
201
+
202
+ <div class="card blue-grey darken-1 z-depth-4 backup-ready">
203
+ <div class="card-content white-text">
204
+ <span class="card-title"><?php echo __( "System Check", 'xcloner-backup-and-restore' ) ?></span>
205
+ <ul>
206
+ <li class="card-panel <?php echo( $requirements->check_xcloner_start_path( 1 ) ? "teal" : "red" ) ?> lighten-2">
207
+ <?php echo __( 'Backup Start Location', 'xcloner-backup-and-restore' ) ?>: <span
208
+ class="shorten_string "><?php echo $requirements->check_xcloner_start_path(); ?></span>
209
+ </li>
210
+ <li class="card-panel <?php echo( $requirements->check_xcloner_store_path( 1 ) ? "teal" : "red" ) ?> lighten-2">
211
+ <?php echo __( 'Backup Storage Location', 'xcloner-backup-and-restore' ) ?>: <span
212
+ class="shorten_string"><?php echo $requirements->check_xcloner_store_path(); ?></span>
213
+ </li>
214
+ <li class="card-panel <?php echo( $requirements->check_xcloner_tmp_path( 1 ) ? "teal" : "red" ) ?> lighten-2">
215
+ <?php echo __( 'Temporary Location', 'xcloner-backup-and-restore' ) ?>: <span
216
+ class="shorten_string"><?php echo $requirements->check_xcloner_tmp_path(); ?></span>
217
+ </li>
218
+
219
+ <li class="card-panel <?php echo( $requirements->check_min_php_version( 1 ) ? "teal" : "red" ) ?> lighten-2">
220
+ <?php echo __( 'PHP Version Check', 'xcloner-backup-and-restore' ) ?>
221
+ : <?php echo $requirements->check_min_php_version(); ?>
222
+ ( >= <?php echo $requirements->get_constant( 'min_php_version' ) ?>)
223
+ </li>
224
+ <li class="card-panel <?php echo( $requirements->check_safe_mode( 1 ) ? "teal" : "orange" ) ?> lighten-2">
225
+ <?php echo __( 'PHP Safe Mode', 'xcloner-backup-and-restore' ) ?>
226
+ : <?php echo $requirements->check_safe_mode(); ?>
227
+ ( <?php echo $requirements->get_constant( 'safe_mode' ) ?>)
228
+ </li>
229
+ <li class="card-panel <?php echo( $requirements->check_backup_ready_status() ? "teal" : "red" ) ?> lighten-2">
230
+ <?php echo( $requirements->check_backup_ready_status() ? __( 'BACKUP READY', 'xcloner-backup-and-restore' ) : __( 'Backup not ready, please check above requirements', 'xcloner-backup-and-restore' ) ) ?>
231
+ <i class="material-icons right tiny"><?php echo( $requirements->check_backup_ready_status() ? 'thumb_up' : 'thumb_down' ) ?></i>
232
+ </li>
233
+ </ul>
234
+ <ul class="additional_system_info">
235
+ <li class="card-panel grey darken-1">
236
+ <?php echo __( 'PHP max_execution_time', 'xcloner-backup-and-restore' ) ?>
237
+ : <?php echo $requirements->get_max_execution_time(); ?>
238
+ </li>
239
+ <li class="card-panel grey darken-1">
240
+ <?php echo __( 'PHP memory_limit', 'xcloner-backup-and-restore' ) ?>
241
+ : <?php echo $requirements->get_memory_limit(); ?>
242
+ </li>
243
+ <li class="card-panel grey darken-1">
244
+ <?php echo __( 'PHP open_basedir', 'xcloner-backup-and-restore' ) ?>
245
+ : <?php echo $requirements->get_open_basedir(); ?>
246
+ </li>
247
+ <?php
248
+ $data = array();
249
+ if ( $requirements->check_backup_ready_status() ) {
250
+ $data = $xcloner_file_system->estimate_read_write_time();
251
+ }
252
+ ?>
253
+ <li class="card-panel grey darken-1">
254
+ <?php echo __( 'Reading Time 1MB Block', 'xcloner-backup-and-restore' ) ?>
255
+ : <?php echo( isset( $data['reading_time'] ) ? $data['reading_time'] : __( "unknown" ) ); ?>
256
+ </li>
257
+ <li class="card-panel grey darken-1">
258
+ <?php echo __( 'Writing Time 1MB Block', 'xcloner-backup-and-restore' ) ?>
259
+ : <?php echo( isset( $data['writing_time'] ) ? $data['writing_time'] : __( "unknown" ) ); ?>
260
+ </li>
261
+ <li class="card-panel grey darken-1">
262
+ <?php echo __( 'Free Disk Space', 'xcloner-backup-and-restore' ) ?>
263
+ : <?php echo $requirements->get_free_disk_space();; ?>
264
+ </li>
265
+ </ul>
266
+ </div>
267
+ <div class="card-action">
268
+ <a class="waves-effect waves-light btn system_info_toggle blue darken-1"><i class="material-icons left">list</i><?php echo __( 'Toggle Additional System Info', 'xcloner-backup-and-restore' ) ?>
269
+ </a>
270
+ </div>
271
+ </div>
272
+
273
+ </div>
274
+ </div>
admin/partials/xcloner_manage_backups_page.php CHANGED
@@ -1,13 +1,12 @@
1
  <?php
2
 
3
- $xcloner_file_system = $this->get_xcloner_container()->get_xcloner_filesystem();
4
- $xcloner_sanitization = $this->get_xcloner_container()->get_xcloner_sanitization();
5
- $xcloner_remote_storage = $this->get_xcloner_container()->get_xcloner_remote_storage();
6
- $storage_selection = "";
7
-
8
- if(isset($_GET['storage_selection']) and $_GET['storage_selection'])
9
- {
10
- $storage_selection = $xcloner_sanitization->sanitize_input_as_string($_GET['storage_selection']);
11
  }
12
 
13
  $backup_list = $xcloner_file_system->get_backup_archives_list($storage_selection);
@@ -18,197 +17,237 @@ $available_storages = $xcloner_remote_storage->get_available_storages();
18
  ?>
19
 
20
  <div class="row">
21
- <div class="col s12 m6 l9">
22
- <h1><?= esc_html(get_admin_page_title()); ?></h1>
23
- </div>
24
- <?php if(sizeof($available_storages)):?>
25
- <div class="col s12 m6 l3 remote-storage-selection">
26
- <select name="storage_selection" id="storage_selection" class="validate" required >
27
-
28
- <?php if($storage_selection):?>
29
- <option value="" selected><?php echo __('Change To Local Storage...', 'xcloner-backup-and-restore') ?></option>
30
- <?php else: ?>
31
- <option value="" selected><?php echo __('Change To Remote Storage...', 'xcloner-backup-and-restore') ?></option>
32
- <?php endif;?>
33
-
34
- <?php foreach($available_storages as $storage=>$text):?>
35
- <option value="<?php echo $storage?>"<?php if($storage == $storage_selection) echo "selected"?>><?php echo $text?></option>
36
- <?php endforeach?>
37
- </select>
38
- <?php endif?>
39
- </div>
40
-
41
- <table id="manage_backups">
42
- <thead>
43
- <tr class="grey lighten-2">
44
- <th class="no-sort">
45
- <p>
46
- <input name="select_all" class="" id="select_all" value="1" type="checkbox">
47
- <label for="select_all">&nbsp;</label>
48
- </p>
49
- </th>
50
- <th data-field="id"><?php echo __("Backup Name",'xcloner-backup-and-restore')?></th>
51
- <th data-field="name"><?php echo __("Created Time",'xcloner-backup-and-restore')?></th>
52
- <th data-field="name"><?php echo __("Size",'xcloner-backup-and-restore')?></th>
53
- <th class="no-sort" data-field="price"><?php echo __("Action",'xcloner-backup-and-restore')?></th>
54
-
55
- </tr>
56
- </thead>
57
-
58
- <tbody>
59
-
60
-
61
- <?php
62
- $i = 0;
63
- foreach($backup_list as $file_info):?>
64
- <?php
65
- if($storage_selection == "gdrive")
66
- $file_info['path'] = $file_info['filename'].".".$file_info['extension'];
67
- $file_exists_on_local_storage = true;
68
-
69
- if($storage_selection)
70
- {
71
- if(!$xcloner_file_system->get_storage_filesystem()->has($file_info['path']))
72
- $file_exists_on_local_storage = false;
73
- }
74
-
75
- ?>
76
- <?php if(!isset($file_info['parent'])):?>
77
-
78
- <tr>
79
- <td class="checkbox">
80
- <p>
81
- <input name="backup[]" value="<?php echo $file_info['basename']?>" type="checkbox" id="checkbox_<?php echo ++$i?>">
82
- <label for="checkbox_<?php echo $i?>">&nbsp;</label>
83
- </p>
84
- </td>
85
- <td>
86
- <span class=""><?php echo $file_info['path']?></span>
87
- <?php if(!$file_exists_on_local_storage): ?>
88
- <a href="#" title="<?php echo __("File does not exists on local storage","xcloner-backup-and-restore")?>"><i class="material-icons backup_warning">warning</i></a>
89
- <?php endif?>
90
- <?php
91
- if(isset($file_info['childs']) and is_array($file_info['childs'])):
92
- ?>
93
- <a href="#" title="expand" class="expand-multipart add"><i class="material-icons">add</i></a>
94
- <a href="#" title="collapse" class="expand-multipart remove"><i class="material-icons">remove</i></a>
95
- <ul class="multipart">
96
- <?php foreach($file_info['childs'] as $child):?>
97
- <li>
98
- <?php echo $child[0]?> (<?php echo size_format($child[2])?>)
99
- <?php
100
- $child_exists_on_local_storage = true;
101
- if($storage_selection)
102
- {
103
- if(!$xcloner_file_system->get_storage_filesystem()->has($child[0]))
104
- $child_exists_on_local_storage = false;
105
- }
106
- ?>
107
- <?php if(!$child_exists_on_local_storage): ?>
108
- <a href="#" title="<?php echo __("File does not exists on local storage","xcloner-backup-and-restore")?>"><i class="material-icons backup_warning">warning</i></a>
109
- <?php endif?>
110
- <?php if(!$storage_selection) :?>
111
- <a href="#<?php echo $child[0];?>" class="download" title="Download Backup"><i class="material-icons">file_download</i></a>
112
- <a href="#<?php echo $child[0]?>" class="list-backup-content" title="<?php echo __('List Backup Content','xcloner-backup-and-restore')?>"><i class="material-icons">folder_open</i></a>
113
- <?php elseif($storage_selection != "gdrive" && !$xcloner_file_system->get_storage_filesystem()->has($child[0])): ?>
114
- <a href="#<?php echo $child[0]?>" class="copy-remote-to-local" title="<?php echo __('Push Backup To Local Storage','xcloner-backup-and-restore')?>"><i class="material-icons">file_upload</i></a>
115
- <?php endif?>
116
- </li>
117
- <?php endforeach;?>
118
- </ul>
119
- <?php endif;?>
120
- </td>
121
- <td><?php if(isset($file_info['timestamp'])) echo date("d M, Y H:i", $file_info['timestamp'])?></td>
122
- <td><?php echo size_format($file_info['size'])?></td>
123
- <td>
124
- <?php if(!$storage_selection):?>
125
- <a href="#<?php echo $file_info['basename'];?>" class="download" title="<?php echo __('Download Backup','xcloner-backup-and-restore')?>"><i class="material-icons">file_download</i></a>
126
-
127
- <?php if(sizeof($available_storages)):?>
128
- <a href="#<?php echo $file_info['basename']?>" class="cloud-upload" title="<?php echo __('Send Backup To Remote Storage','xcloner-backup-and-restore')?>"><i class="material-icons">cloud_upload</i></a>
129
- <?php endif?>
130
- <a href="#<?php echo $file_info['basename']?>" class="list-backup-content" title="<?php echo __('List Backup Content','xcloner-backup-and-restore')?>"><i class="material-icons">folder_open</i></a>
131
- <?php endif;?>
132
-
133
- <a href="#<?php echo $file_info['basename']?>" class="delete" title="<?php echo __('Delete Backup','xcloner-backup-and-restore')?>"><i class="material-icons">delete</i></a>
134
- <?php if($storage_selection and !$file_exists_on_local_storage):?>
135
- <a href="#<?php echo $file_info['basename'];?>" class="copy-remote-to-local" title="<?php echo __('Push Backup To Local Storage','xcloner-backup-and-restore')?>"><i class="material-icons">file_upload</i></a>
136
- <?php endif?>
137
-
138
- </td>
139
-
140
- </tr>
141
-
142
- <?php endif?>
143
- <?php endforeach?>
144
-
145
- </tbody>
146
- </table>
147
-
148
- <a class="waves-effect waves-light btn delete-all"><i class="material-icons left">delete</i><?php echo __("Delete",'xcloner-backup-and-restore')?></a>
149
-
150
- <!-- List Backup Content Modal-->
151
- <div id="backup_cotent_modal" class="modal">
152
- <div class="modal-content">
153
- <h4><?php echo sprintf(__("Listing Backup Content ",'xcloner-backup-and-restore'), "")?></h4>
154
- <h5 class="backup-name"></h5>
155
-
156
- <div class="progress">
157
- <div class="indeterminate"></div>
158
- </div>
159
- <ul class="files-list"></ul>
160
- </div>
161
- </div>
162
-
163
- <!-- Local Transfer Modal-->
164
- <div id="local_storage_upload_modal" class="modal">
165
- <div class="modal-content">
166
- <h4><?php echo sprintf(__("Transfer Remote Backup To Local Storage",'xcloner-backup-and-restore'), "")?></h4>
167
- <h5 class="backup-name"></h5>
168
-
169
- <div class="row status">
170
- <div class="progress">
171
- <div class="indeterminate"></div>
172
- </div>
173
- <?php echo __("Uploading backup to the local storage filesystem...",'xcloner-backup-and-restore')?> <span class="status-text"></span>
174
- </div>
175
- </div>
176
- </div>
177
-
178
- <!-- Remote Storage Modal Structure -->
179
- <div id="remote_storage_modal" class="modal">
180
- <form method="POST" class="remote-storage-form">
181
- <input type="hidden" name="file" class="backup_name">
182
- <div class="modal-content">
183
- <h4><?php echo __("Remote Storage Transfer",'xcloner-backup-and-restore')?></h4>
184
- <p>
185
- <?php if(sizeof($available_storages)):?>
186
- <div class="row">
187
- <div class="col s12 label">
188
- <label><?php echo sprintf(__('Send %s to remote storage','xcloner-backup-and-restore'), "<span class='backup_name'></span>") ?></label>
189
- </div>
190
- <div class="input-field col s8 m10">
191
- <select name="transfer_storage" id="transfer_storage" class="validate" required >
192
- <option value="" selected><?php echo __('please select...', 'xcloner-backup-and-restore') ?></option>
193
- <?php foreach($available_storages as $storage=>$text):?>
194
- <option value="<?php echo $storage?>"><?php echo $text?></option>
195
- <?php endforeach?>
196
- </select>
197
-
198
- </div>
199
- <div class="s4 m2 right">
200
- <button type="submit" class="upload-submit btn-floating btn-large waves-effect waves-light teal"><i class="material-icons">file_upload</i></submit>
201
- </div>
202
- </div>
203
- <div class="row status">
204
- <?php echo __("Uploading backup to the selected remote storage...",'xcloner-backup-and-restore')?> <span class="status-text"></span>
205
- <div class="progress">
206
- <div class="indeterminate"></div>
207
- </div>
208
- </div>
209
- <?php endif?>
210
- </p>
211
- </div>
212
- </form>
213
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
214
 
1
  <?php
2
 
3
+ $xcloner_file_system = $this->get_xcloner_container()->get_xcloner_filesystem();
4
+ $xcloner_sanitization = $this->get_xcloner_container()->get_xcloner_sanitization();
5
+ $xcloner_remote_storage = $this->get_xcloner_container()->get_xcloner_remote_storage();
6
+ $storage_selection = "";
7
+
8
+ if (isset($_GET['storage_selection']) and $_GET['storage_selection']) {
9
+ $storage_selection = $xcloner_sanitization->sanitize_input_as_string($_GET['storage_selection']);
 
10
  }
11
 
12
  $backup_list = $xcloner_file_system->get_backup_archives_list($storage_selection);
17
  ?>
18
 
19
  <div class="row">
20
+ <div class="col s12 m6 l9">
21
+ <h1><?= esc_html(get_admin_page_title()); ?></h1>
22
+ </div>
23
+ <?php if (sizeof($available_storages)): ?>
24
+ <div class="col s12 m6 l3 remote-storage-selection">
25
+ <select name="storage_selection" id="storage_selection" class="validate" required>
26
+
27
+ <?php if ($storage_selection): ?>
28
+ <option value=""
29
+ selected><?php echo __('Change To Local Storage...', 'xcloner-backup-and-restore') ?></option>
30
+ <?php else: ?>
31
+ <option value=""
32
+ selected><?php echo __('Change To Remote Storage...', 'xcloner-backup-and-restore') ?></option>
33
+ <?php endif; ?>
34
+
35
+ <?php foreach ($available_storages as $storage => $text): ?>
36
+ <option value="<?php echo $storage ?>"<?php if ($storage == $storage_selection)
37
+ echo "selected" ?>><?php echo $text ?></option>
38
+ <?php endforeach ?>
39
+ </select>
40
+ <?php endif ?>
41
+ </div>
42
+
43
+ <table id="manage_backups">
44
+ <thead>
45
+ <tr class="grey lighten-2">
46
+ <th class="no-sort">
47
+ <p>
48
+ <input name="select_all" class="" id="select_all" value="1" type="checkbox">
49
+ <label for="select_all">&nbsp;</label>
50
+ </p>
51
+ </th>
52
+ <th data-field="id"><?php echo __("Backup Name", 'xcloner-backup-and-restore') ?></th>
53
+ <th data-field="name"><?php echo __("Created Time", 'xcloner-backup-and-restore') ?></th>
54
+ <th data-field="name"><?php echo __("Size", 'xcloner-backup-and-restore') ?></th>
55
+ <th class="no-sort" data-field="price"><?php echo __("Action", 'xcloner-backup-and-restore') ?></th>
56
+
57
+ </tr>
58
+ </thead>
59
+
60
+ <tbody>
61
+
62
+
63
+ <?php
64
+ $i = 0;
65
+ foreach ($backup_list as $file_info):?>
66
+ <?php
67
+ if ($storage_selection == "gdrive") {
68
+ $file_info['path'] = $file_info['filename'] . "." . $file_info['extension'];
69
+ }
70
+ $file_exists_on_local_storage = true;
71
+
72
+ if ($storage_selection) {
73
+ if (!$xcloner_file_system->get_storage_filesystem()->has($file_info['path'])) {
74
+ $file_exists_on_local_storage = false;
75
+ }
76
+ }
77
+
78
+ ?>
79
+ <?php if (!isset($file_info['parent'])): ?>
80
+
81
+ <tr>
82
+ <td class="checkbox">
83
+ <p>
84
+ <input name="backup[]" value="<?php echo $file_info['basename'] ?>" type="checkbox"
85
+ id="checkbox_<?php echo ++$i ?>">
86
+ <label for="checkbox_<?php echo $i ?>">&nbsp;</label>
87
+ </p>
88
+ </td>
89
+ <td>
90
+ <span class=""><?php echo $file_info['path'] ?></span>
91
+ <?php if (!$file_exists_on_local_storage): ?>
92
+ <a href="#"
93
+ title="<?php echo __("File does not exists on local storage",
94
+ "xcloner-backup-and-restore") ?>"><i
95
+ class="material-icons backup_warning">warning</i></a>
96
+ <?php endif ?>
97
+ <?php
98
+ if (isset($file_info['childs']) and is_array($file_info['childs'])):
99
+ ?>
100
+ <a href="#" title="expand" class="expand-multipart add"><i
101
+ class="material-icons">add</i></a>
102
+ <a href="#" title="collapse" class="expand-multipart remove"><i class="material-icons">remove</i></a>
103
+ <ul class="multipart">
104
+ <?php foreach ($file_info['childs'] as $child): ?>
105
+ <li>
106
+ <?php echo $child[0] ?> (<?php echo size_format($child[2]) ?>)
107
+ <?php
108
+ $child_exists_on_local_storage = true;
109
+ if ($storage_selection) {
110
+ if (!$xcloner_file_system->get_storage_filesystem()->has($child[0])) {
111
+ $child_exists_on_local_storage = false;
112
+ }
113
+ }
114
+ ?>
115
+ <?php if (!$child_exists_on_local_storage): ?>
116
+ <a href="#"
117
+ title="<?php echo __("File does not exists on local storage",
118
+ "xcloner-backup-and-restore") ?>"><i
119
+ class="material-icons backup_warning">warning</i></a>
120
+ <?php endif ?>
121
+ <?php if (!$storage_selection) : ?>
122
+ <a href="#<?php echo $child[0]; ?>" class="download"
123
+ title="Download Backup"><i class="material-icons">file_download</i></a>
124
+ <a href="#<?php echo $child[0] ?>" class="list-backup-content"
125
+ title="<?php echo __('List Backup Content',
126
+ 'xcloner-backup-and-restore') ?>"><i
127
+ class="material-icons">folder_open</i></a>
128
+ <?php elseif ($storage_selection != "gdrive" && !$xcloner_file_system->get_storage_filesystem()->has($child[0])): ?>
129
+ <a href="#<?php echo $child[0] ?>" class="copy-remote-to-local"
130
+ title="<?php echo __('Push Backup To Local Storage',
131
+ 'xcloner-backup-and-restore') ?>"><i
132
+ class="material-icons">file_upload</i></a>
133
+ <?php endif ?>
134
+ </li>
135
+ <?php endforeach; ?>
136
+ </ul>
137
+ <?php endif; ?>
138
+ </td>
139
+ <td><?php if (isset($file_info['timestamp']))
140
+ echo date("Y-m-d H:i", $file_info['timestamp']) ?></td>
141
+ <td><?php echo size_format($file_info['size']) ?></td>
142
+ <td>
143
+ <?php if (!$storage_selection): ?>
144
+ <a href="#<?php echo $file_info['basename']; ?>" class="download"
145
+ title="<?php echo __('Download Backup', 'xcloner-backup-and-restore') ?>"><i
146
+ class="material-icons">file_download</i></a>
147
+
148
+ <?php if (sizeof($available_storages)): ?>
149
+ <a href="#<?php echo $file_info['basename'] ?>" class="cloud-upload"
150
+ title="<?php echo __('Send Backup To Remote Storage',
151
+ 'xcloner-backup-and-restore') ?>"><i
152
+ class="material-icons">cloud_upload</i></a>
153
+ <?php endif ?>
154
+ <a href="#<?php echo $file_info['basename'] ?>" class="list-backup-content"
155
+ title="<?php echo __('List Backup Content', 'xcloner-backup-and-restore') ?>"><i
156
+ class="material-icons">folder_open</i></a>
157
+ <?php endif; ?>
158
+
159
+ <a href="#<?php echo $file_info['basename'] ?>" class="delete"
160
+ title="<?php echo __('Delete Backup', 'xcloner-backup-and-restore') ?>"><i
161
+ class="material-icons">delete</i></a>
162
+ <?php if ($storage_selection and !$file_exists_on_local_storage): ?>
163
+ <a href="#<?php echo $file_info['basename']; ?>" class="copy-remote-to-local"
164
+ title="<?php echo __('Push Backup To Local Storage', 'xcloner-backup-and-restore') ?>"><i
165
+ class="material-icons">file_upload</i></a>
166
+ <?php endif ?>
167
+
168
+ </td>
169
+
170
+ </tr>
171
+
172
+ <?php endif ?>
173
+ <?php endforeach ?>
174
+
175
+ </tbody>
176
+ </table>
177
+
178
+ <a class="waves-effect waves-light btn delete-all"><i
179
+ class="material-icons left">delete</i><?php echo __("Delete", 'xcloner-backup-and-restore') ?></a>
180
+
181
+ <!-- List Backup Content Modal-->
182
+ <div id="backup_cotent_modal" class="modal">
183
+ <div class="modal-content">
184
+ <h4><?php echo sprintf(__("Listing Backup Content ", 'xcloner-backup-and-restore'), "") ?></h4>
185
+ <h5 class="backup-name"></h5>
186
+
187
+ <div class="progress">
188
+ <div class="indeterminate"></div>
189
+ </div>
190
+ <ul class="files-list"></ul>
191
+ </div>
192
+ </div>
193
+
194
+ <!-- Local Transfer Modal-->
195
+ <div id="local_storage_upload_modal" class="modal">
196
+ <div class="modal-content">
197
+ <h4>
198
+ <?php echo sprintf(__("Transfer Remote Backup To Local Storage", 'xcloner-backup-and-restore'), "") ?>
199
+ </h4>
200
+ <h5 class="backup-name"></h5>
201
+
202
+ <div class="row status">
203
+ <div class="progress">
204
+ <div class="indeterminate"></div>
205
+ </div>
206
+ <?php echo __("Uploading backup to the local storage filesystem...", 'xcloner-backup-and-restore') ?>
207
+ <span class="status-text"></span>
208
+ </div>
209
+ </div>
210
+ </div>
211
+
212
+ <!-- Remote Storage Modal Structure -->
213
+ <div id="remote_storage_modal" class="modal">
214
+ <form method="POST" class="remote-storage-form">
215
+ <input type="hidden" name="file" class="backup_name">
216
+ <div class="modal-content">
217
+ <h4><?php echo __("Remote Storage Transfer", 'xcloner-backup-and-restore') ?></h4>
218
+ <p>
219
+ <?php if (sizeof($available_storages)): ?>
220
+ <div class="row">
221
+ <div class="col s12 label">
222
+ <label><?php echo sprintf(__('Send %s to remote storage', 'xcloner-backup-and-restore'),
223
+ "<span class='backup_name'></span>") ?></label>
224
+ </div>
225
+ <div class="input-field col s8 m10">
226
+ <select name="transfer_storage" id="transfer_storage" class="validate" required>
227
+ <option value=""
228
+ selected><?php echo __('please select...', 'xcloner-backup-and-restore') ?></option>
229
+ <?php foreach ($available_storages as $storage => $text): ?>
230
+ <option value="<?php echo $storage ?>"><?php echo $text ?></option>
231
+ <?php endforeach ?>
232
+ </select>
233
+
234
+ </div>
235
+ <div class="s4 m2 right">
236
+ <button type="submit"
237
+ class="upload-submit btn-floating btn-large waves-effect waves-light teal"><i
238
+ class="material-icons">file_upload</i></submit>
239
+ </div>
240
+ </div>
241
+ <div class="row status">
242
+ <?php echo __("Uploading backup to the selected remote storage...", 'xcloner-backup-and-restore') ?>
243
+ <span class="status-text"></span>
244
+ <div class="progress">
245
+ <div class="indeterminate"></div>
246
+ </div>
247
+ </div>
248
+ <?php endif ?>
249
+ </p>
250
+ </div>
251
+ </form>
252
+ </div>
253
 
admin/partials/xcloner_remote_storage_page.php CHANGED
@@ -1,865 +1,1045 @@
1
- <?php
2
  $remote_storage = $this->get_xcloner_container()->get_xcloner_remote_storage();
3
 
4
  $gdrive_auth_url = "";
5
 
6
- if(method_exists($remote_storage, "get_gdrive_auth_url"))
7
  $gdrive_auth_url = $remote_storage->get_gdrive_auth_url();
 
8
 
9
  $gdrive_construct = $remote_storage->gdrive_construct();
10
  ?>
11
- <h1><?= esc_html(get_admin_page_title()); ?></h1>
12
 
13
  <form class="remote-storage-form" method="POST">
14
 
15
- <input type="hidden" id="connection_check" name="connection_check" value="">
16
-
17
- <div class="row remote-storage">
18
- <div class="col s12 m12 l10">
19
- <ul class="collapsible popout" data-collapsible="accordion">
20
- <!-- FTP STORAGE-->
21
- <li id="ftp">
22
- <div class="collapsible-header">
23
- <i class="material-icons">computer</i><?php echo __("FTP Storage",'xcloner-backup-and-restore')?>
24
- <div class="switch right">
25
- <label>
26
- Off
27
- <input type="checkbox" name="xcloner_ftp_enable" class="status" value="1" <?php if(get_option("xcloner_ftp_enable")) echo "checked"?> \>
28
- <span class="lever"></span>
29
- On
30
- </label>
31
- </div>
32
- </div>
33
- <div class="collapsible-body">
34
- <div class="row">
35
- <div class="col s12 m3 label">
36
- <label for="ftp_host"><?php echo __("Ftp Hostname",'xcloner-backup-and-restore')?></label>
37
- </div>
38
- <div class="col s12 m6">
39
- <input placeholder="<?php echo __("Ftp Hostname",'xcloner-backup-and-restore')?>" id="ftp_host" type="text" name="xcloner_ftp_hostname" class="validate" value="<?php echo get_option("xcloner_ftp_hostname")?>">
40
- </div>
41
- <div class=" col s12 m2">
42
- <input placeholder="<?php echo __("Ftp Port",'xcloner-backup-and-restore')?>" id="ftp_port" type="text" name="xcloner_ftp_port" class="validate" value="<?php echo get_option("xcloner_ftp_port", 21)?>">
43
- </div>
44
- </div>
45
-
46
- <div class="row">
47
- <div class="col s12 m3 label">
48
- <label for="ftp_username"><?php echo __("Ftp Username",'xcloner-backup-and-restore')?></label>
49
- </div>
50
- <div class=" col s12 m6">
51
- <input placeholder="<?php echo __("Ftp Username",'xcloner-backup-and-restore')?>" id="ftp_username" type="text" name="xcloner_ftp_username" class="validate" value="<?php echo get_option("xcloner_ftp_username")?>" autocomplete="off" >
52
- </div>
53
- </div>
54
-
55
-
56
- <div class="row">
57
- <div class="col s12 m3 label">
58
- <label for="ftp_password"><?php echo __("Ftp Password",'xcloner-backup-and-restore')?></label>
59
- </div>
60
- <div class=" col s12 m6">
61
- <input placeholder="<?php echo __("Ftp Password",'xcloner-backup-and-restore')?>" id="ftp_password" type="password" name="xcloner_ftp_password" class="validate" value="<?php echo get_option("xcloner_ftp_password")?>" autocomplete="off" >
62
- </div>
63
- </div>
64
-
65
- <div class="row">
66
- <div class="col s12 m3 label">
67
- <label for="ftp_root"><?php echo __("Ftp Storage Folder",'xcloner-backup-and-restore')?></label>
68
- </div>
69
- <div class=" col s12 m6">
70
- <input placeholder="<?php echo __("Ftp Storage Folder",'xcloner-backup-and-restore')?>" id="ftp_root" type="text" name="xcloner_ftp_path" class="validate" value="<?php echo get_option("xcloner_ftp_path")?>">
71
- </div>
72
- </div>
73
-
74
- <div class="row">
75
- <div class="col s12 m3 label">
76
- <label for="ftp_root"><?php echo __("Ftp Transfer Mode",'xcloner-backup-and-restore')?></label>
77
- </div>
78
- <div class=" col s12 m6 input-field inline">
79
- <input name="xcloner_ftp_transfer_mode" type="radio" id="passive" value="1" <?php if(get_option("xcloner_ftp_transfer_mode", 1)) echo "checked"?> />
80
- <label for="passive"><?php echo __("Passive",'xcloner-backup-and-restore')?></label>
81
-
82
- <input name="xcloner_ftp_transfer_mode" type="radio" id="active" value="0" <?php if(!get_option("xcloner_ftp_transfer_mode", 1)) echo "checked"?> />
83
- <label for="active"><?php echo __("Active",'xcloner-backup-and-restore')?></label>
84
- </div>
85
- </div>
86
-
87
- <div class="row">
88
- <div class="col s12 m3 label">
89
- <label for="ftp_ssl_mode"><?php echo __("Ftp Secure Connection",'xcloner-backup-and-restore')?></label>
90
- </div>
91
- <div class=" col s12 m6 input-field inline">
92
- <input name="xcloner_ftp_ssl_mode" type="radio" id="ftp_ssl_mode_inactive" value="0" <?php if(!get_option("xcloner_ftp_ssl_mode")) echo "checked"?> />
93
- <label for="ftp_ssl_mode_inactive"><?php echo __("Disable",'xcloner-backup-and-restore')?></label>
94
-
95
- <input name="xcloner_ftp_ssl_mode" type="radio" id="ftp_ssl_mode_active" value="1" <?php if(get_option("xcloner_ftp_ssl_mode")) echo "checked"?> />
96
- <label for="ftp_ssl_mode_active"><?php echo __("Enable",'xcloner-backup-and-restore')?></label>
97
- </div>
98
- </div>
99
-
100
- <div class="row">
101
- <div class="col s12 m3 label">
102
- <label for="ftp_timeout"><?php echo __("Ftp Timeout",'xcloner-backup-and-restore')?></label>
103
- </div>
104
- <div class=" col s12 m2">
105
- <input placeholder="<?php echo __("Ftp Timeout",'xcloner-backup-and-restore')?>" id="ftp_timeout" type="text" name="xcloner_ftp_timeout" class="validate" value="<?php echo get_option("xcloner_ftp_timeout", 30)?>">
106
- </div>
107
- </div>
108
-
109
- <div class="row">
110
- <div class="col s12 m3 label">
111
- <label for="ftp_cleanup_days"><?php echo __("Ftp Cleanup (days)",'xcloner-backup-and-restore')?></label>
112
- </div>
113
- <div class=" col s12 m6">
114
- <input placeholder="<?php echo __("how many days to keep the backups for",'xcloner-backup-and-restore')?>" id="ftp_cleanup_days" type="text" name="xcloner_ftp_cleanup_days" class="validate" value="<?php echo get_option("xcloner_ftp_cleanup_days")?>">
115
- </div>
116
- </div>
117
-
118
- <div class="row">
119
- <div class="col s6 m4">
120
- <button class="btn waves-effect waves-light" type="submit" name="action" id="action" value="ftp"><?php echo __("Save Settings",'xcloner-backup-and-restore')?>
121
- <i class="material-icons right">save</i>
122
- </button>
123
- </div>
124
- <div class="col s6 m4">
125
- <button class="btn waves-effect waves-light orange" type="submit" name="action" id="action" value="ftp" onclick="jQuery('#connection_check').val('1')"><?php echo __("Verify",'xcloner-backup-and-restore')?>
126
- <i class="material-icons right">import_export</i>
127
- </button>
128
- </div>
129
- </div>
130
-
131
- </div>
132
- </li>
133
- <!-- SFTP STORAGE-->
134
- <li id="sftp">
135
- <div class="collapsible-header">
136
- <i class="material-icons">computer</i><?php echo __("SFTP Storage",'xcloner-backup-and-restore')?>
137
- <div class="switch right">
138
- <label>
139
- Off
140
- <input type="checkbox" name="xcloner_sftp_enable" class="status" value="1" <?php if(get_option("xcloner_sftp_enable")) echo "checked"?> \>
141
- <span class="lever"></span>
142
- On
143
- </label>
144
- </div>
145
- </div>
146
- <div class="collapsible-body">
147
- <div class="row">
148
- <div class="col s12 m3 label">
149
- <label for="sftp_host"><?php echo __("SFTP Hostname",'xcloner-backup-and-restore')?></label>
150
- </div>
151
- <div class="col s12 m6">
152
- <input placeholder="<?php echo __("SFTP Hostname",'xcloner-backup-and-restore')?>" id="sftp_host" type="text" name="xcloner_sftp_hostname" class="validate" value="<?php echo get_option("xcloner_sftp_hostname")?>">
153
- </div>
154
- <div class=" col s12 m2">
155
- <input placeholder="<?php echo __("SFTP Port",'xcloner-backup-and-restore')?>" id="sftp_port" type="text" name="xcloner_sftp_port" class="validate" value="<?php echo get_option("xcloner_sftp_port", 22)?>">
156
- </div>
157
- </div>
158
-
159
- <div class="row">
160
- <div class="col s12 m3 label">
161
- <label for="sftp_username"><?php echo __("SFTP Username",'xcloner-backup-and-restore')?></label>
162
- </div>
163
- <div class=" col s12 m6">
164
- <input placeholder="<?php echo __("SFTP Username",'xcloner-backup-and-restore')?>" id="sftp_username" type="text" name="xcloner_sftp_username" class="validate" value="<?php echo get_option("xcloner_sftp_username")?>" autocomplete="off" >
165
- </div>
166
- </div>
167
-
168
-
169
- <div class="row">
170
- <div class="col s12 m3 label">
171
- <label for="sftp_password"><?php echo __("SFTP or Private Key Password",'xcloner-backup-and-restore')?></label>
172
- </div>
173
- <div class=" col s12 m6">
174
- <input placeholder="<?php echo __("SFTP or Private Key Password",'xcloner-backup-and-restore')?>" id="ftp_spassword" type="password" name="xcloner_sftp_password" class="validate" value="<?php echo get_option("xcloner_sftp_password")?>" autocomplete="off" >
175
- </div>
176
- </div>
177
-
178
- <div class="row">
179
- <div class="col s12 m3 label">
180
- <label for="sftp_private_key"><?php echo __("SFTP Private Key(RSA)",'xcloner-backup-and-restore')?></label>
181
- </div>
182
- <div class=" col s12 m6">
183
- <textarea rows="5" placeholder="<?php echo __("Local Server Path or Contents of the SFTP Private Key RSA File",'xcloner-backup-and-restore')?>" id="sftp_private_key" type="text" name="xcloner_sftp_private_key" class="validate" value=""><?php echo get_option("xcloner_sftp_private_key")?></textarea>
184
- </div>
185
- </div>
186
-
187
- <div class="row">
188
- <div class="col s12 m3 label">
189
- <label for="sftp_root"><?php echo __("SFTP Storage Folder",'xcloner-backup-and-restore')?></label>
190
- </div>
191
- <div class=" col s12 m6">
192
- <input placeholder="<?php echo __("SFTP Storage Folder",'xcloner-backup-and-restore')?>" id="sftp_root" type="text" name="xcloner_sftp_path" class="validate" value="<?php echo get_option("xcloner_sftp_path")?>">
193
- </div>
194
- </div>
195
-
196
- <div class="row">
197
- <div class="col s12 m3 label">
198
- <label for="sftp_timeout"><?php echo __("SFTP Timeout",'xcloner-backup-and-restore')?></label>
199
- </div>
200
- <div class=" col s12 m2">
201
- <input placeholder="<?php echo __("SFTP Timeout",'xcloner-backup-and-restore')?>" id="sftp_timeout" type="text" name="xcloner_sftp_timeout" class="validate" value="<?php echo get_option("xcloner_sftp_timeout", 30)?>">
202
- </div>
203
- </div>
204
-
205
- <div class="row">
206
- <div class="col s12 m3 label">
207
- <label for="sftp_cleanup_days"><?php echo __("SFTP Cleanup (days)",'xcloner-backup-and-restore')?></label>
208
- </div>
209
- <div class=" col s12 m6">
210
- <input placeholder="<?php echo __("how many days to keep the backups for",'xcloner-backup-and-restore')?>" id="sftp_cleanup_days" type="text" name="xcloner_sftp_cleanup_days" class="validate" value="<?php echo get_option("xcloner_sftp_cleanup_days")?>">
211
- </div>
212
- </div>
213
-
214
- <div class="row">
215
- <div class="col s6 m4">
216
- <button class="btn waves-effect waves-light" type="submit" name="action" id="action" value="sftp"><?php echo __("Save Settings",'xcloner-backup-and-restore')?>
217
- <i class="material-icons right">save</i>
218
- </button>
219
- </div>
220
- <div class="col s6 m4">
221
- <button class="btn waves-effect waves-light orange" type="submit" name="action" id="action" value="sftp" onclick="jQuery('#connection_check').val('1')"><?php echo __("Verify",'xcloner-backup-and-restore')?>
222
- <i class="material-icons right">import_export</i>
223
- </button>
224
- </div>
225
- </div>
226
-
227
- </div>
228
- </li>
229
-
230
- <!-- AWS STORAGE-->
231
- <li id="aws">
232
- <div class="collapsible-header">
233
- <i class="material-icons">computer</i><?php echo __("S3 Storage",'xcloner-backup-and-restore')?>
234
- <div class="switch right">
235
- <label>
236
- Off
237
- <input type="checkbox" name="xcloner_aws_enable" class="status" value="1" <?php if(get_option("xcloner_aws_enable")) echo "checked"?> \>
238
- <span class="lever"></span>
239
- On
240
- </label>
241
- </div>
242
- </div>
243
- <div class="collapsible-body">
244
-
245
- <div class="row">
246
- <div class="col s12 m3 label">
247
- &nbsp;
248
- </div>
249
- <div class=" col s12 m6">
250
- <p>
251
- <?php echo sprintf(__('Visit %s and get your "Key" and "Secret <br />Visit %s to install your own S3 like service.'), "<a href='https://aws.amazon.com/s3/' target='_blank'>https://aws.amazon.com/s3/</a>", "<a href='https://minio.io/' target='_blank'>https://minio.io/</a>")?>
252
- </p>
253
- </div>
254
- </div>
255
-
256
- <div class="row">
257
- <div class="col s12 m3 label">
258
- <label for="aws_key"><?php echo __("S3 Key",'xcloner-backup-and-restore')?></label>
259
- </div>
260
- <div class=" col s12 m6">
261
- <input placeholder="<?php echo __("S3 Key",'xcloner-backup-and-restore')?>" id="aws_key" type="text" name="xcloner_aws_key" class="validate" value="<?php echo get_option("xcloner_aws_key")?>" autocomplete="off" >
262
- </div>
263
- </div>
264
-
265
- <div class="row">
266
- <div class="col s12 m3 label">
267
- <label for="aws_secret"><?php echo __("S3 Secret",'xcloner-backup-and-restore')?></label>
268
- </div>
269
- <div class=" col s12 m6">
270
- <input placeholder="<?php echo __("S3 Secret",'xcloner-backup-and-restore')?>" id="aws_secret" type="text" name="xcloner_aws_secret" class="validate" value="<?php echo get_option("xcloner_aws_secret")?>" autocomplete="off" >
271
- </div>
272
- </div>
273
-
274
- <div class="row">
275
- <div class="col s12 m3 label">
276
- <label for="aws_region"><?php echo __("S3 Region",'xcloner-backup-and-restore')?></label>
277
- </div>
278
- <div class=" col s12 m6">
279
- <select placeholder="<?php echo __("example: us-east-1",'xcloner-backup-and-restore')?>" id="aws_region" type="text" name="xcloner_aws_region" class="validate" value="<?php echo get_option("xcloner_aws_region")?>" autocomplete="off" >
280
- <option readonly value=""><?php echo __("Please Select AWS S3 Region or Leave Unselected for Custom Endpoint")?></option>
281
- <?php
282
- $aws_regions = $remote_storage->get_aws_regions();
283
-
284
- foreach($aws_regions as $key=>$region){
285
- ?>
286
- <option value="<?php echo $key?>" <?php echo ($key == get_option('xcloner_aws_region')?"selected":"")?>><?php echo $region?> = <?php echo $key?></option>
287
- <?php
288
- }
289
- ?>
290
- </select>
291
- </div>
292
- </div>
293
-
294
- <div class="row">
295
- <div class="col s12 m3 label">
296
- <label for="aws_endpoint"><?php echo __("S3 EndPoint",'xcloner-backup-and-restore')?></label>
297
- </div>
298
- <div class=" col s12 m6">
299
- <input placeholder="<?php echo __("S3 EndPoint, leave blank if you want to use the default Amazon AWS Service",'xcloner-backup-and-restore')?>" id="aws_endpoint" type="text" name="xcloner_aws_endpoint" class="validate" value="<?php echo get_option("xcloner_aws_endpoint")?>" autocomplete="off" >
300
- </div>
301
- </div>
302
-
303
- <div class="row">
304
- <div class="col s12 m3 label">
305
- <label for="aws_bucket_name"><?php echo __("S3 Bucket Name",'xcloner-backup-and-restore')?></label>
306
- </div>
307
- <div class=" col s12 m6">
308
- <input placeholder="<?php echo __("S3 Bucket Name",'xcloner-backup-and-restore')?>" id="aws_bucket_name" type="text" name="xcloner_aws_bucket_name" class="validate" value="<?php echo get_option("xcloner_aws_bucket_name")?>" autocomplete="off" >
309
- </div>
310
- </div>
311
-
312
- <div class="row">
313
- <div class="col s12 m3 label">
314
- <label for="aws_prefix"><?php echo __("S3 Prefix",'xcloner-backup-and-restore')?></label>
315
- </div>
316
- <div class=" col s12 m6">
317
- <input placeholder="<?php echo __("S3 Prefix, use / ending to define a folder",'xcloner-backup-and-restore')?>" id="aws_prefix" type="text" name="xcloner_aws_prefix" class="validate" value="<?php echo get_option("xcloner_aws_prefix")?>" autocomplete="off" >
318
- </div>
319
- </div>
320
-
321
- <div class="row">
322
- <div class="col s12 m3 label">
323
- <label for="aws_cleanup_days"><?php echo __("S3 Cleanup (days)",'xcloner-backup-and-restore')?></label>
324
- </div>
325
- <div class=" col s12 m6">
326
- <input placeholder="<?php echo __("how many days to keep the backups for",'xcloner-backup-and-restore')?>" id="aws_cleanup_days" type="text" name="xcloner_aws_cleanup_days" class="validate" value="<?php echo get_option("xcloner_aws_cleanup_days")?>">
327
- </div>
328
- </div>
329
-
330
- <div class="row">
331
- <div class="col s6 m4">
332
- <button class="btn waves-effect waves-light" type="submit" name="action" id="action" value="aws"><?php echo __("Save Settings",'xcloner-backup-and-restore')?>
333
- <i class="material-icons right">save</i>
334
- </button>
335
- </div>
336
- <div class="col s6 m4">
337
- <button class="btn waves-effect waves-light orange" type="submit" name="action" id="action" value="aws" onclick="jQuery('#connection_check').val('1')"><?php echo __("Verify",'xcloner-backup-and-restore')?>
338
- <i class="material-icons right">import_export</i>
339
- </button>
340
- </div>
341
- </div>
342
-
343
- </div>
344
- </li>
345
-
346
- <!-- DROPBOX STORAGE-->
347
- <li id="dropbox">
348
- <div class="collapsible-header">
349
- <i class="material-icons">computer</i><?php echo __("Dropbox Storage",'xcloner-backup-and-restore')?>
350
- <div class="switch right">
351
- <label>
352
- Off
353
- <input type="checkbox" name="xcloner_dropbox_enable" class="status" value="1" <?php if(get_option("xcloner_dropbox_enable")) echo "checked"?> \>
354
- <span class="lever"></span>
355
- On
356
- </label>
357
- </div>
358
- </div>
359
- <div class="collapsible-body">
360
-
361
- <div class="row">
362
- <div class="col s12 m3 label">
363
- &nbsp;
364
- </div>
365
- <div class=" col s12 m6">
366
- <p>
367
- <?php echo sprintf(__('Visit %s and get your "App secret".'), "<a href='https://www.dropbox.com/developers/apps' target='_blank'>https://www.dropbox.com/developers/apps</a>")?>
368
- </p>
369
- </div>
370
- </div>
371
-
372
- <div class="row">
373
- <div class="col s12 m3 label">
374
- <label for="dropbox_access_token"><?php echo __("Dropbox Access Token",'xcloner-backup-and-restore')?></label>
375
- </div>
376
- <div class=" col s12 m6">
377
- <input placeholder="<?php echo __("Dropbox Access Token",'xcloner-backup-and-restore')?>" id="dropbox_access_token" type="text" name="xcloner_dropbox_access_token" class="validate" value="<?php echo get_option("xcloner_dropbox_access_token")?>" autocomplete="off" >
378
- </div>
379
- </div>
380
-
381
-
382
- <div class="row">
383
- <div class="col s12 m3 label">
384
- <label for="dropbox_app_secret"><?php echo __("Dropbox App Secret",'xcloner-backup-and-restore')?></label>
385
- </div>
386
- <div class=" col s12 m6">
387
- <input placeholder="<?php echo __("Dropbox App Secret",'xcloner-backup-and-restore')?>" id="dropbox_app_secret" type="text" name="xcloner_dropbox_app_secret" class="validate" value="<?php echo get_option("xcloner_dropbox_app_secret")?>" autocomplete="off" >
388
- </div>
389
- </div>
390
-
391
- <div class="row">
392
- <div class="col s12 m3 label">
393
- <label for="dropbox_prefix"><?php echo __("Dropbox Prefix",'xcloner-backup-and-restore')?></label>
394
- </div>
395
- <div class=" col s12 m6">
396
- <input placeholder="<?php echo __("Dropbox Prefix",'xcloner-backup-and-restore')?>" id="dropbox_prefix" type="text" name="xcloner_dropbox_prefix" class="validate" value="<?php echo get_option("xcloner_dropbox_prefix")?>">
397
- </div>
398
- </div>
399
-
400
- <div class="row">
401
- <div class="col s12 m3 label">
402
- <label for="dropbox_cleanup_days"><?php echo __("Dropbox Cleanup (days)",'xcloner-backup-and-restore')?></label>
403
- </div>
404
- <div class=" col s12 m6">
405
- <input placeholder="<?php echo __("how many days to keep the backups for",'xcloner-backup-and-restore')?>" id="dropbox_cleanup_days" type="text" name="xcloner_dropbox_cleanup_days" class="validate" value="<?php echo get_option("xcloner_dropbox_cleanup_days")?>">
406
- </div>
407
- </div>
408
-
409
- <div class="row">
410
- <div class="col s6 m4">
411
- <button class="btn waves-effect waves-light" type="submit" name="action" id="action" value="dropbox"><?php echo __("Save Settings",'xcloner-backup-and-restore')?>
412
- <i class="material-icons right">save</i>
413
- </button>
414
- </div>
415
- <div class="col s6 m4">
416
- <button class="btn waves-effect waves-light orange" type="submit" name="action" id="action" value="dropbox" onclick="jQuery('#connection_check').val('1')"><?php echo __("Verify",'xcloner-backup-and-restore')?>
417
- <i class="material-icons right">import_export</i>
418
- </button>
419
- </div>
420
- </div>
421
-
422
- </div>
423
- </li>
424
-
425
- <!-- AZURE STORAGE-->
426
- <li id="azure">
427
- <div class="collapsible-header">
428
- <i class="material-icons">computer</i><?php echo __("Azure Blob Storage",'xcloner-backup-and-restore')?>
429
- <div class="switch right">
430
- <label>
431
- Off
432
- <input type="checkbox" name="xcloner_azure_enable" class="status" value="1" <?php if(get_option("xcloner_azure_enable")) echo "checked"?> \>
433
- <span class="lever"></span>
434
- On
435
- </label>
436
- </div>
437
- </div>
438
- <div class="collapsible-body">
439
-
440
- <div class="row">
441
- <div class="col s12 m3 label">
442
- &nbsp;
443
- </div>
444
- <div class=" col s12 m6">
445
- <p>
446
- <?php echo sprintf(__('Visit %s and get your "Api Key".','xcloner-backup-and-restore'), '<a href="https://azure.microsoft.com/en-us/services/storage/blobs/" target="_blank">https://azure.microsoft.com/en-us/services/storage/blobs/</a>')?>
447
- </p>
448
- </div>
449
- </div>
450
-
451
- <div class="row">
452
- <div class="col s12 m3 label">
453
- <label for="azure_account_name"><?php echo __("Azure Account Name",'xcloner-backup-and-restore')?></label>
454
- </div>
455
- <div class=" col s12 m6">
456
- <input placeholder="<?php echo __("Azure Account Name",'xcloner-backup-and-restore')?>" id="azure_account_name" type="text" name="xcloner_azure_account_name" class="validate" value="<?php echo get_option("xcloner_azure_account_name")?>" autocomplete="off" >
457
- </div>
458
- </div>
459
-
460
-
461
- <div class="row">
462
- <div class="col s12 m3 label">
463
- <label for="azure_api_key"><?php echo __("Azure Api Key",'xcloner-backup-and-restore')?></label>
464
- </div>
465
- <div class=" col s12 m6">
466
- <input placeholder="<?php echo __("Azure Api Key",'xcloner-backup-and-restore')?>" id="azure_api_key" type="text" name="xcloner_azure_api_key" class="validate" value="<?php echo get_option("xcloner_azure_api_key")?>" autocomplete="off" >
467
- </div>
468
- </div>
469
-
470
- <div class="row">
471
- <div class="col s12 m3 label">
472
- <label for="azure_container"><?php echo __("Azure Container",'xcloner-backup-and-restore')?></label>
473
- </div>
474
- <div class=" col s12 m6">
475
- <input placeholder="<?php echo __("Azure Container",'xcloner-backup-and-restore')?>" id="azure_container" type="text" name="xcloner_azure_container" class="validate" value="<?php echo get_option("xcloner_azure_container")?>">
476
- </div>
477
- </div>
478
-
479
- <div class="row">
480
- <div class="col s12 m3 label">
481
- <label for="azure_cleanup_days"><?php echo __("Azure Cleanup (days)",'xcloner-backup-and-restore')?></label>
482
- </div>
483
- <div class=" col s12 m6">
484
- <input placeholder="<?php echo __("how many days to keep the backups for",'xcloner-backup-and-restore')?>" id="azure_cleanup_days" type="text" name="xcloner_azure_cleanup_days" class="validate" value="<?php echo get_option("xcloner_azure_cleanup_days")?>">
485
- </div>
486
- </div>
487
-
488
- <div class="row">
489
- <div class="col s6 m4">
490
- <button class="btn waves-effect waves-light" type="submit" name="action" id="action" value="azure"><?php echo __("Save Settings",'xcloner-backup-and-restore')?>
491
- <i class="material-icons right">save</i>
492
- </button>
493
- </div>
494
- <div class="col s6 m4">
495
- <button class="btn waves-effect waves-light orange" type="submit" name="action" id="action" value="azure" onclick="jQuery('#connection_check').val('1')"><?php echo __("Verify",'xcloner-backup-and-restore')?>
496
- <i class="material-icons right">import_export</i>
497
- </button>
498
- </div>
499
- </div>
500
-
501
- </div>
502
- </li>
503
-
504
- <!-- BACKBLAZE STORAGE-->
505
- <li id="backblaze">
506
- <div class="collapsible-header">
507
- <i class="material-icons">computer</i><?php echo __("Backblaze Storage",'xcloner-backup-and-restore')?>
508
- <div class="switch right">
509
- <label>
510
- Off
511
- <input type="checkbox" name="xcloner_backblaze_enable" class="status" value="1" <?php if(get_option("xcloner_backblaze_enable")) echo "checked"?> \>
512
- <span class="lever"></span>
513
- On
514
- </label>
515
- </div>
516
- </div>
517
- <div class="collapsible-body">
518
-
519
- <div class="row">
520
- <div class="col s12 m3 label">
521
- &nbsp;
522
- </div>
523
- <div class=" col s12 m6">
524
- <p>
525
- <?php echo sprintf(__('Visit %s and get your Account Id and Application Key.','xcloner-backup-and-restore'), '<a href="https://secure.backblaze.com/b2_buckets.htm" target="_blank">https://secure.backblaze.com/b2_buckets.htm</a>')?>
526
- </p>
527
- </div>
528
- </div>
529
-
530
- <div class="row">
531
- <div class="col s12 m3 label">
532
- <label for="backblaze_account_id"><?php echo __("Backblaze Account Id",'xcloner-backup-and-restore')?></label>
533
- </div>
534
- <div class=" col s12 m6">
535
- <input placeholder="<?php echo __("Backblaze Account Id",'xcloner-backup-and-restore')?>" id="backblaze_account_id" type="text" name="xcloner_backblaze_account_id" class="validate" value="<?php echo get_option("xcloner_backblaze_account_id")?>" autocomplete="off" >
536
- </div>
537
- </div>
538
-
539
-
540
- <div class="row">
541
- <div class="col s12 m3 label">
542
- <label for="backblaze_application_key"><?php echo __("Backblaze Application Key",'xcloner-backup-and-restore')?></label>
543
- </div>
544
- <div class=" col s12 m6">
545
- <input placeholder="<?php echo __("Backblaze Application Key",'xcloner-backup-and-restore')?>" id="backblaze_application_key" type="text" name="xcloner_backblaze_application_key" class="validate" value="<?php echo get_option("xcloner_backblaze_application_key")?>" autocomplete="off" >
546
- </div>
547
- </div>
548
-
549
- <div class="row">
550
- <div class="col s12 m3 label">
551
- <label for="backblaze_bucket_name"><?php echo __("Backblaze Bucket Name",'xcloner-backup-and-restore')?></label>
552
- </div>
553
- <div class=" col s12 m6">
554
- <input placeholder="<?php echo __("Backblaze Bucket Name",'xcloner-backup-and-restore')?>" id="backblaze_bucket_name" type="text" name="xcloner_backblaze_bucket_name" class="validate" value="<?php echo get_option("xcloner_backblaze_bucket_name")?>" autocomplete="off" >
555
- </div>
556
- </div>
557
-
558
- <div class="row">
559
- <div class="col s12 m3 label">
560
- <label for="backblaze_cleanup_days"><?php echo __("Backblaze Cleanup (days)",'xcloner-backup-and-restore')?></label>
561
- </div>
562
- <div class=" col s12 m6">
563
- <input placeholder="<?php echo __("how many days to keep the backups for",'xcloner-backup-and-restore')?>" id="backblaze_cleanup_days" type="text" name="xcloner_backblaze_cleanup_days" class="validate" value="<?php echo get_option("xcloner_backblaze_cleanup_days")?>">
564
- </div>
565
- </div>
566
-
567
- <div class="row">
568
- <div class="col s6 m4">
569
- <button class="btn waves-effect waves-light" type="submit" name="action" id="action" value="backblaze"><?php echo __("Save Settings",'xcloner-backup-and-restore')?>
570
- <i class="material-icons right">save</i>
571
- </button>
572
- </div>
573
- <div class="col s6 m4">
574
- <button class="btn waves-effect waves-light orange" type="submit" name="action" id="action" value="backblaze" onclick="jQuery('#connection_check').val('1')"><?php echo __("Verify",'xcloner-backup-and-restore')?>
575
- <i class="material-icons right">import_export</i>
576
- </button>
577
- </div>
578
- </div>
579
-
580
- </div>
581
- </li>
582
-
583
- <!-- WEBDAV STORAGE-->
584
- <li id="webdav">
585
- <div class="collapsible-header">
586
- <i class="material-icons">computer</i><?php echo __("WebDAV Storage",'xcloner-backup-and-restore')?>
587
- <div class="switch right">
588
- <label>
589
- Off
590
- <input type="checkbox" name="xcloner_webdav_enable" class="status" value="1" <?php if(get_option("xcloner_webdav_enable")) echo "checked"?> \>
591
- <span class="lever"></span>
592
- On
593
- </label>
594
- </div>
595
- </div>
596
- <div class="collapsible-body">
597
-
598
- <div class="row">
599
- <div class="col s12 m3 label">
600
- &nbsp;
601
- </div>
602
- <div class=" col s12 m6">
603
- <p>
604
- <?php //echo sprintf(__('Visit %s and get your Account Id and Application Key.','xcloner-backup-and-restore'), '<a href="https://secure.backblaze.com/b2_buckets.htm" target="_blank">https://secure.backblaze.com/b2_buckets.htm</a>')?>
605
- </p>
606
- </div>
607
- </div>
608
-
609
- <div class="row">
610
- <div class="col s12 m3 label">
611
- <label for="webdav_url"><?php echo __("WebDAV Base Url",'xcloner-backup-and-restore')?></label>
612
- </div>
613
- <div class=" col s12 m6">
614
- <input placeholder="<?php echo __("WebDAV Base Url",'xcloner-backup-and-restore')?>" id="webdav_url" type="text" name="xcloner_webdav_url" class="validate" value="<?php echo get_option("xcloner_webdav_url")?>" autocomplete="off" >
615
- </div>
616
- </div>
617
-
618
- <div class="row">
619
- <div class="col s12 m3 label">
620
- <label for="webdav_username"><?php echo __("WebDAV Username",'xcloner-backup-and-restore')?></label>
621
- </div>
622
- <div class=" col s12 m6">
623
- <input placeholder="<?php echo __("WebDAV Username",'xcloner-backup-and-restore')?>" id="webdav_username" type="text" name="xcloner_webdav_username" class="validate" value="<?php echo get_option("xcloner_webdav_username")?>" autocomplete="off" >
624
- </div>
625
- </div>
626
-
627
- <div class="row">
628
- <div class="col s12 m3 label">
629
- <label for="webdav_password"><?php echo __("WebDAV Password",'xcloner-backup-and-restore')?></label>
630
- </div>
631
- <div class=" col s12 m6">
632
- <input placeholder="<?php echo __("WebDAV Password",'xcloner-backup-and-restore')?>" id="webdav_password" type="password" name="xcloner_webdav_password" class="validate" value="<?php echo get_option("xcloner_webdav_password")?>" autocomplete="off" >
633
- </div>
634
- </div>
635
-
636
- <div class="row">
637
- <div class="col s12 m3 label">
638
- <label for="webdav_target_folder"><?php echo __("WebDAV Target Folder",'xcloner-backup-and-restore')?></label>
639
- </div>
640
- <div class=" col s12 m6">
641
- <input placeholder="<?php echo __("WebDAV Target Folder",'xcloner-backup-and-restore')?>" id="webdav_target_folder" type="text" name="xcloner_webdav_target_folder" class="validate" value="<?php echo get_option("xcloner_webdav_target_folder")?>" autocomplete="off" >
642
- </div>
643
- </div>
644
-
645
- <div class="row">
646
- <div class="col s12 m3 label">
647
- <label for="webdav_cleanup_days"><?php echo __("WebDAV Cleanup (days)",'xcloner-backup-and-restore')?></label>
648
- </div>
649
- <div class=" col s12 m6">
650
- <input placeholder="<?php echo __("how many days to keep the backups for",'xcloner-backup-and-restore')?>" id="webdav_cleanup_days" type="text" name="xcloner_webdav_cleanup_days" class="validate" value="<?php echo get_option("xcloner_webdav_cleanup_days")?>">
651
- </div>
652
- </div>
653
-
654
- <div class="row">
655
- <div class="col s6 m4">
656
- <button class="btn waves-effect waves-light" type="submit" name="action" id="action" value="webdav"><?php echo __("Save Settings",'xcloner-backup-and-restore')?>
657
- <i class="material-icons right">save</i>
658
- </button>
659
- </div>
660
- <div class="col s6 m4">
661
- <button class="btn waves-effect waves-light orange" type="submit" name="action" id="action" value="webdav" onclick="jQuery('#connection_check').val('1')"><?php echo __("Verify",'xcloner-backup-and-restore')?>
662
- <i class="material-icons right">import_export</i>
663
- </button>
664
- </div>
665
- </div>
666
-
667
- </div>
668
- </li>
669
-
670
- <!-- Google DRIVE STORAGE-->
671
- <li id="gdrive">
672
- <div class="collapsible-header">
673
- <i class="material-icons">computer</i><?php echo __("Google Drive Storage",'xcloner-backup-and-restore')?>
674
- <?php if($gdrive_construct):?>
675
- <div class="switch right">
676
- <label>
677
- Off
678
- <input type="checkbox" name="xcloner_gdrive_enable" class="status" value="1" <?php if(get_option("xcloner_gdrive_enable")) echo "checked"?> \>
679
- <span class="lever"></span>
680
- On
681
- </label>
682
- </div>
683
- <?php endif?>
684
- </div>
685
- <div class="collapsible-body">
686
-
687
- <?php if($gdrive_construct) : ?>
688
-
689
- <div class="row">
690
- <div class="col s12 m3 label">
691
- &nbsp;
692
- </div>
693
- <div class=" col s12 m9">
694
- <p>
695
- <?php echo sprintf(__('Visit %s to create a new application and get your Client ID and Client Secret.','xcloner-backup-and-restore'), '<a href="https://console.developers.google.com" target="_blank">https://console.developers.google.com</a>')?>
696
- <a href="https://youtu.be/YXUVPUVgG8k" target="_blank" class="btn-floating tooltipped btn-small" data-position="right" data-delay="50" data-html="true"
697
- data-tooltip="<?php echo sprintf(__('Click here to view a short video explaining how to create the Client ID and Client Secret as well as connecting XCloner with the Google Drive API %s','xcloner-backup-and-restore'),"<br />https://youtu.be/YXUVPUVgG8k")?>" data-tooltip-id="92c95730-94e9-7b59-bd52-14adc30d5e3e"><i class="material-icons">help_outline</i></a>
698
- </p>
699
- </div>
700
- </div>
701
-
702
- <div class="row">
703
- <div class="col s12 m3 label">
704
- <label for="gdrive_client_id"><?php echo __("Client ID",'xcloner-backup-and-restore')?></label>
705
- </div>
706
- <div class=" col s12 m6">
707
- <input placeholder="<?php echo __("Google Client ID",'xcloner-backup-and-restore')?>" id="gdrive_client_id" type="text" name="xcloner_gdrive_client_id" class="validate" value="<?php echo get_option("xcloner_gdrive_client_id")?>">
708
- </div>
709
- </div>
710
-
711
- <div class="row">
712
- <div class="col s12 m3 label">
713
- <label for="gdrive_client_secret"><?php echo __("Client Secret",'xcloner-backup-and-restore')?></label>
714
- </div>
715
- <div class=" col s12 m6">
716
- <input placeholder="<?php echo __("Google Client Secret",'xcloner-backup-and-restore')?>" id="gdrive_client_secret" type="text" name="xcloner_gdrive_client_secret" class="validate" value="<?php echo get_option("xcloner_gdrive_client_secret")?>">
717
- </div>
718
- </div>
719
-
720
-
721
- <div class="row">
722
- <div class="col s12 m3 label">
723
- &nbsp;
724
- </div>
725
- <div class=" col s12 m6">
726
- <a class="btn" target="_blank" id="gdrive_authorization_click" onclick="jQuery('#authentification_code').show()" href="<?php echo $gdrive_auth_url?>"><?php echo sprintf(__('Authorize Google Drive','xcloner-backup-and-restore'))?></a>
727
- <input type="text" name="authentification_code" id="authentification_code" placeholder="<?php echo __("Paste Authorization Code Here","xcloner-backup-and-restore")?>">
728
- </div>
729
- </div>
730
-
731
- <div class="row">
732
- <div class="col s12 m3 label">
733
- <label for="gdrive_target_folder"><?php echo __("Folder ID or Root Path",'xcloner-backup-and-restore')?>
734
- <a class="btn-floating tooltipped btn-small" data-position="right" data-delay="50" data-html="true" \
735
- data-tooltip="<?php echo __('Folder ID can be found by right clicking on the folder name and selecting \'Get shareable link\' menu, format https://drive.google.com/open?id={FOLDER_ID}<br />
736
- If you supply a folder name, it has to exists in the drive root and start with / , example /backups.xcloner.com/','xcloner-backup-and-restore')?>" data-tooltip-id="92c95730-94e9-7b59-bd52-14adc30d5e3e"><i class="material-icons">help_outline</i></a>
737
- </label>
738
- </div>
739
- <div class=" col s12 m6">
740
- <input placeholder="<?php echo __("Target Folder ID or Root Path",'xcloner-backup-and-restore')?>" id="gdrive_target_folder" type="text" name="xcloner_gdrive_target_folder" class="validate" value="<?php echo get_option("xcloner_gdrive_target_folder")?>" autocomplete="off" >
741
- </div>
742
- </div>
743
-
744
- <div class="row">
745
- <div class="col s12 m3 label">
746
- <label for="gdrive_cleanup_days"><?php echo __("Google Drive Cleanup (days)",'xcloner-backup-and-restore')?></label>
747
- </div>
748
- <div class=" col s12 m6">
749
- <input placeholder="<?php echo __("how many days to keep the backups for",'xcloner-backup-and-restore')?>" id="gdrive_cleanup_days" type="text" name="xcloner_gdrive_cleanup_days" class="validate" value="<?php echo get_option("xcloner_gdrive_cleanup_days")?>">
750
- </div>
751
- </div>
752
-
753
- <div class="row">
754
- <div class="col s12 m3 label">
755
- <label for="gdrive_empty_trash"><?php echo __("Keeps Deleted Backups in Trash",'xcloner-backup-and-restore')?></label>
756
- </div>
757
- <div class=" col s12 m6 input-field inline">
758
- <input name="xcloner_gdrive_empty_trash" type="radio" value="0" id="gdrive_empty_trash_off" <?php if(!get_option("xcloner_gdrive_empty_trash",0)) echo "checked"?> />
759
- <label for="gdrive_empty_trash_off"><?php echo __("Enabled",'xcloner-backup-and-restore')?></label>
760
-
761
- <input name="xcloner_gdrive_empty_trash" type="radio" value="1" id="gdrive_empty_trash_on" <?php if(get_option("xcloner_gdrive_empty_trash",0)) echo "checked"?> />
762
- <label for="gdrive_empty_trash_on"><?php echo __("Disabled",'xcloner-backup-and-restore')?></label>
763
- </div>
764
- </div>
765
-
766
- <div class="row">
767
- <div class="col s6 m4">
768
- <button class="btn waves-effect waves-light" type="submit" name="action" id="action" value="gdrive"><?php echo __("Save Settings",'xcloner-backup-and-restore')?>
769
- <i class="material-icons right">save</i>
770
- </button>
771
- </div>
772
- <div class="col s6 m4">
773
- <button class="btn waves-effect waves-light orange" type="submit" name="action" id="action" value="gdrive" onclick="jQuery('#connection_check').val('1')"><?php echo __("Verify",'xcloner-backup-and-restore')?>
774
- <i class="material-icons right">import_export</i>
775
- </button>
776
- </div>
777
- </div>
778
- <?php else:?>
779
-
780
- <div class="row">
781
- <div class=" col s12">
782
- <div class="center">
783
- <?php
784
- $url = wp_nonce_url(self_admin_url('update.php?action=install-plugin&plugin=xcloner-google-drive'), 'install-plugin_xcloner-google-drive');
785
  ?>
786
- <h6><?php echo __("This storage option requires the XCloner-Google-Drive Wordpress Plugin to be installed and activated.")?></h6>
787
- <h6><?php echo __("PHP 5.5 minimum version is required.")?></h6>
788
- <br />
789
- <a class="install-now btn" data-slug="xcloner-google-drive" href="<?php echo $url;?>" aria-label="Install XCloner Google Drive 1.0.0 now" data-name="XCloner Google Drive 1.0.0">
790
- <?php echo sprintf(__('Install Now','xcloner-backup-and-restore'))?>
791
- </a>
792
-
793
- <a href="<?php echo admin_url("plugin-install.php")?>?tab=plugin-information&amp;plugin=xcloner-google-drive&amp;TB_iframe=true&amp;width=772&amp;height=499" class="btn thickbox open-plugin-details-modal" aria-label="More information about Theme Check 20160523.1" data-title="Theme Check 20160523.1">
794
- <!--
795
- <a class="btn" href="https://github.com/ovidiul/XCloner-Google-Drive/archive/master.zip">
796
- -->
797
- <?php echo sprintf(__('More Details','xcloner-backup-and-restore'))?>
798
- </a>
799
- </div>
800
- </div>
801
- </div>
802
-
803
- <?php endif; ?>
804
-
805
- </div>
806
- </li>
807
-
808
-
809
-
810
- </ul>
811
- </div>
812
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
813
 
814
  </form>
815
 
816
  <script>
817
-
818
- function checkEndpoint(){
819
- if(jQuery("#aws_region").val() != ""){
820
- jQuery('#aws_endpoint').parent().parent().hide();
821
- }else{
822
- jQuery('#aws_endpoint').parent().parent().show();
823
- }
824
- }
825
 
826
- jQuery(document).ready(function(){
827
-
828
- var remote_storage = new Xcloner_Remote_Storage();
829
-
830
- checkEndpoint()
831
- jQuery("#aws_region").on("change", function(){
832
- checkEndpoint();
833
-
834
- })
835
-
836
- jQuery(".remote-storage .status").on("change", function(){
837
- remote_storage.toggle_status(this);
838
- })
839
-
840
- jQuery(".remote-storage-form #action").on("click", function(){
841
- var tag = jQuery(this).val()
842
- window.location.hash = "#"+tag;
843
- })
844
-
845
- jQuery("#gdrive_authorization_click").on("click", function(e){
846
-
847
- var href = (jQuery(this).attr("href"))
848
-
849
- var new_href= href.replace(/(client_id=).*?(&)/,'$1' + jQuery("#gdrive_client_id").val() + '$2');
850
-
851
- jQuery(this).attr("href", new_href)
852
-
853
- });
854
-
855
- if(location.hash)
856
- jQuery(location.hash+" div.collapsible-header").addClass("active");
857
-
858
- jQuery('.collapsible').collapsible();
859
-
860
- Materialize.updateTextFields();
861
-
862
-
863
- });
864
-
 
 
 
 
 
 
 
 
865
  </script>
1
+ <?php
2
  $remote_storage = $this->get_xcloner_container()->get_xcloner_remote_storage();
3
 
4
  $gdrive_auth_url = "";
5
 
6
+ if ( method_exists( $remote_storage, "get_gdrive_auth_url" ) ) {
7
  $gdrive_auth_url = $remote_storage->get_gdrive_auth_url();
8
+ }
9
 
10
  $gdrive_construct = $remote_storage->gdrive_construct();
11
  ?>
12
+ <h1><?= esc_html( get_admin_page_title() ); ?></h1>
13
 
14
  <form class="remote-storage-form" method="POST">
15
 
16
+ <input type="hidden" id="connection_check" name="connection_check" value="">
17
+
18
+ <div class="row remote-storage">
19
+ <div class="col s12 m12 l10">
20
+ <ul class="collapsible popout" data-collapsible="accordion">
21
+ <!-- FTP STORAGE-->
22
+ <li id="ftp">
23
+ <div class="collapsible-header">
24
+ <i class="material-icons">computer</i><?php echo __( "FTP Storage", 'xcloner-backup-and-restore' ) ?>
25
+ <div class="switch right">
26
+ <label>
27
+ Off
28
+ <input type="checkbox" name="xcloner_ftp_enable" class="status"
29
+ value="1" <?php if ( get_option( "xcloner_ftp_enable" ) )
30
+ echo "checked" ?> \>
31
+ <span class="lever"></span>
32
+ On
33
+ </label>
34
+ </div>
35
+ </div>
36
+ <div class="collapsible-body">
37
+ <div class="row">
38
+ <div class="col s12 m3 label">
39
+ <label for="ftp_host"><?php echo __( "Ftp Hostname", 'xcloner-backup-and-restore' ) ?></label>
40
+ </div>
41
+ <div class="col s12 m6">
42
+ <input placeholder="<?php echo __( "Ftp Hostname", 'xcloner-backup-and-restore' ) ?>"
43
+ id="ftp_host" type="text" name="xcloner_ftp_hostname" class="validate"
44
+ value="<?php echo get_option( "xcloner_ftp_hostname" ) ?>">
45
+ </div>
46
+ <div class=" col s12 m2">
47
+ <input placeholder="<?php echo __( "Ftp Port", 'xcloner-backup-and-restore' ) ?>"
48
+ id="ftp_port" type="text" name="xcloner_ftp_port" class="validate"
49
+ value="<?php echo get_option( "xcloner_ftp_port", 21 ) ?>">
50
+ </div>
51
+ </div>
52
+
53
+ <div class="row">
54
+ <div class="col s12 m3 label">
55
+ <label for="ftp_username"><?php echo __( "Ftp Username", 'xcloner-backup-and-restore' ) ?></label>
56
+ </div>
57
+ <div class=" col s12 m6">
58
+ <input placeholder="<?php echo __( "Ftp Username", 'xcloner-backup-and-restore' ) ?>"
59
+ id="ftp_username" type="text" name="xcloner_ftp_username" class="validate"
60
+ value="<?php echo get_option( "xcloner_ftp_username" ) ?>" autocomplete="off">
61
+ </div>
62
+ </div>
63
+
64
+
65
+ <div class="row">
66
+ <div class="col s12 m3 label">
67
+ <label for="ftp_password"><?php echo __( "Ftp Password", 'xcloner-backup-and-restore' ) ?></label>
68
+ </div>
69
+ <div class=" col s12 m6">
70
+ <input placeholder="<?php echo __( "Ftp Password", 'xcloner-backup-and-restore' ) ?>"
71
+ id="ftp_password" type="password" name="xcloner_ftp_password" class="validate"
72
+ value="<?php echo get_option( "xcloner_ftp_password" ) ?>" autocomplete="off">
73
+ </div>
74
+ </div>
75
+
76
+ <div class="row">
77
+ <div class="col s12 m3 label">
78
+ <label for="ftp_root"><?php echo __( "Ftp Storage Folder", 'xcloner-backup-and-restore' ) ?></label>
79
+ </div>
80
+ <div class=" col s12 m6">
81
+ <input placeholder="<?php echo __( "Ftp Storage Folder", 'xcloner-backup-and-restore' ) ?>"
82
+ id="ftp_root" type="text" name="xcloner_ftp_path" class="validate"
83
+ value="<?php echo get_option( "xcloner_ftp_path" ) ?>">
84
+ </div>
85
+ </div>
86
+
87
+ <div class="row">
88
+ <div class="col s12 m3 label">
89
+ <label for="ftp_root"><?php echo __( "Ftp Transfer Mode", 'xcloner-backup-and-restore' ) ?></label>
90
+ </div>
91
+ <div class=" col s12 m6 input-field inline">
92
+ <input name="xcloner_ftp_transfer_mode" type="radio" id="passive"
93
+ value="1" <?php if ( get_option( "xcloner_ftp_transfer_mode", 1 ) )
94
+ echo "checked" ?> />
95
+ <label for="passive"><?php echo __( "Passive", 'xcloner-backup-and-restore' ) ?></label>
96
+
97
+ <input name="xcloner_ftp_transfer_mode" type="radio" id="active"
98
+ value="0" <?php if ( ! get_option( "xcloner_ftp_transfer_mode", 1 ) )
99
+ echo "checked" ?> />
100
+ <label for="active"><?php echo __( "Active", 'xcloner-backup-and-restore' ) ?></label>
101
+ </div>
102
+ </div>
103
+
104
+ <div class="row">
105
+ <div class="col s12 m3 label">
106
+ <label for="ftp_ssl_mode"><?php echo __( "Ftp Secure Connection", 'xcloner-backup-and-restore' ) ?></label>
107
+ </div>
108
+ <div class=" col s12 m6 input-field inline">
109
+ <input name="xcloner_ftp_ssl_mode" type="radio" id="ftp_ssl_mode_inactive"
110
+ value="0" <?php if ( ! get_option( "xcloner_ftp_ssl_mode" ) )
111
+ echo "checked" ?> />
112
+ <label for="ftp_ssl_mode_inactive"><?php echo __( "Disable", 'xcloner-backup-and-restore' ) ?></label>
113
+
114
+ <input name="xcloner_ftp_ssl_mode" type="radio" id="ftp_ssl_mode_active"
115
+ value="1" <?php if ( get_option( "xcloner_ftp_ssl_mode" ) )
116
+ echo "checked" ?> />
117
+ <label for="ftp_ssl_mode_active"><?php echo __( "Enable", 'xcloner-backup-and-restore' ) ?></label>
118
+ </div>
119
+ </div>
120
+
121
+ <div class="row">
122
+ <div class="col s12 m3 label">
123
+ <label for="ftp_timeout"><?php echo __( "Ftp Timeout", 'xcloner-backup-and-restore' ) ?></label>
124
+ </div>
125
+ <div class=" col s12 m2">
126
+ <input placeholder="<?php echo __( "Ftp Timeout", 'xcloner-backup-and-restore' ) ?>"
127
+ id="ftp_timeout" type="text" name="xcloner_ftp_timeout" class="validate"
128
+ value="<?php echo get_option( "xcloner_ftp_timeout", 30 ) ?>">
129
+ </div>
130
+ </div>
131
+
132
+ <div class="row">
133
+ <div class="col s12 m3 label">
134
+ <label for="ftp_cleanup_days"><?php echo __( "Ftp Cleanup (days)", 'xcloner-backup-and-restore' ) ?></label>
135
+ </div>
136
+ <div class=" col s12 m6">
137
+ <input placeholder="<?php echo __( "how many days to keep the backups for", 'xcloner-backup-and-restore' ) ?>"
138
+ id="ftp_cleanup_days" type="text" name="xcloner_ftp_cleanup_days"
139
+ class="validate" value="<?php echo get_option( "xcloner_ftp_cleanup_days" ) ?>">
140
+ </div>
141
+ </div>
142
+
143
+ <div class="row">
144
+ <div class="col s6 m4">
145
+ <button class="btn waves-effect waves-light" type="submit" name="action" id="action"
146
+ value="ftp"><?php echo __( "Save Settings", 'xcloner-backup-and-restore' ) ?>
147
+ <i class="material-icons right">save</i>
148
+ </button>
149
+ </div>
150
+ <div class="col s6 m4">
151
+ <button class="btn waves-effect waves-light orange" type="submit" name="action"
152
+ id="action" value="ftp"
153
+ onclick="jQuery('#connection_check').val('1')"><?php echo __( "Verify", 'xcloner-backup-and-restore' ) ?>
154
+ <i class="material-icons right">import_export</i>
155
+ </button>
156
+ </div>
157
+ </div>
158
+
159
+ </div>
160
+ </li>
161
+ <!-- SFTP STORAGE-->
162
+ <li id="sftp">
163
+ <div class="collapsible-header">
164
+ <i class="material-icons">computer</i><?php echo __( "SFTP Storage", 'xcloner-backup-and-restore' ) ?>
165
+ <div class="switch right">
166
+ <label>
167
+ Off
168
+ <input type="checkbox" name="xcloner_sftp_enable" class="status"
169
+ value="1" <?php if ( get_option( "xcloner_sftp_enable" ) )
170
+ echo "checked" ?> \>
171
+ <span class="lever"></span>
172
+ On
173
+ </label>
174
+ </div>
175
+ </div>
176
+ <div class="collapsible-body">
177
+ <div class="row">
178
+ <div class="col s12 m3 label">
179
+ <label for="sftp_host"><?php echo __( "SFTP Hostname", 'xcloner-backup-and-restore' ) ?></label>
180
+ </div>
181
+ <div class="col s12 m6">
182
+ <input placeholder="<?php echo __( "SFTP Hostname", 'xcloner-backup-and-restore' ) ?>"
183
+ id="sftp_host" type="text" name="xcloner_sftp_hostname" class="validate"
184
+ value="<?php echo get_option( "xcloner_sftp_hostname" ) ?>">
185
+ </div>
186
+ <div class=" col s12 m2">
187
+ <input placeholder="<?php echo __( "SFTP Port", 'xcloner-backup-and-restore' ) ?>"
188
+ id="sftp_port" type="text" name="xcloner_sftp_port" class="validate"
189
+ value="<?php echo get_option( "xcloner_sftp_port", 22 ) ?>">
190
+ </div>
191
+ </div>
192
+
193
+ <div class="row">
194
+ <div class="col s12 m3 label">
195
+ <label for="sftp_username"><?php echo __( "SFTP Username", 'xcloner-backup-and-restore' ) ?></label>
196
+ </div>
197
+ <div class=" col s12 m6">
198
+ <input placeholder="<?php echo __( "SFTP Username", 'xcloner-backup-and-restore' ) ?>"
199
+ id="sftp_username" type="text" name="xcloner_sftp_username" class="validate"
200
+ value="<?php echo get_option( "xcloner_sftp_username" ) ?>" autocomplete="off">
201
+ </div>
202
+ </div>
203
+
204
+
205
+ <div class="row">
206
+ <div class="col s12 m3 label">
207
+ <label for="sftp_password"><?php echo __( "SFTP or Private Key Password", 'xcloner-backup-and-restore' ) ?></label>
208
+ </div>
209
+ <div class=" col s12 m6">
210
+ <input placeholder="<?php echo __( "SFTP or Private Key Password", 'xcloner-backup-and-restore' ) ?>"
211
+ id="ftp_spassword" type="password" name="xcloner_sftp_password" class="validate"
212
+ value="<?php echo get_option( "xcloner_sftp_password" ) ?>" autocomplete="off">
213
+ </div>
214
+ </div>
215
+
216
+ <div class="row">
217
+ <div class="col s12 m3 label">
218
+ <label for="sftp_private_key"><?php echo __( "SFTP Private Key(RSA)", 'xcloner-backup-and-restore' ) ?></label>
219
+ </div>
220
+ <div class=" col s12 m6">
221
+ <textarea rows="5"
222
+ placeholder="<?php echo __( "Local Server Path or Contents of the SFTP Private Key RSA File", 'xcloner-backup-and-restore' ) ?>"
223
+ id="sftp_private_key" type="text" name="xcloner_sftp_private_key"
224
+ class="validate"
225
+ value=""><?php echo get_option( "xcloner_sftp_private_key" ) ?></textarea>
226
+ </div>
227
+ </div>
228
+
229
+ <div class="row">
230
+ <div class="col s12 m3 label">
231
+ <label for="sftp_root"><?php echo __( "SFTP Storage Folder", 'xcloner-backup-and-restore' ) ?></label>
232
+ </div>
233
+ <div class=" col s12 m6">
234
+ <input placeholder="<?php echo __( "SFTP Storage Folder", 'xcloner-backup-and-restore' ) ?>"
235
+ id="sftp_root" type="text" name="xcloner_sftp_path" class="validate"
236
+ value="<?php echo get_option( "xcloner_sftp_path" ) ?>">
237
+ </div>
238
+ </div>
239
+
240
+ <div class="row">
241
+ <div class="col s12 m3 label">
242
+ <label for="sftp_timeout"><?php echo __( "SFTP Timeout", 'xcloner-backup-and-restore' ) ?></label>
243
+ </div>
244
+ <div class=" col s12 m2">
245
+ <input placeholder="<?php echo __( "SFTP Timeout", 'xcloner-backup-and-restore' ) ?>"
246
+ id="sftp_timeout" type="text" name="xcloner_sftp_timeout" class="validate"
247
+ value="<?php echo get_option( "xcloner_sftp_timeout", 30 ) ?>">
248
+ </div>
249
+ </div>
250
+
251
+ <div class="row">
252
+ <div class="col s12 m3 label">
253
+ <label for="sftp_cleanup_days"><?php echo __( "SFTP Cleanup (days)", 'xcloner-backup-and-restore' ) ?></label>
254
+ </div>
255
+ <div class=" col s12 m6">
256
+ <input placeholder="<?php echo __( "how many days to keep the backups for", 'xcloner-backup-and-restore' ) ?>"
257
+ id="sftp_cleanup_days" type="text" name="xcloner_sftp_cleanup_days"
258
+ class="validate" value="<?php echo get_option( "xcloner_sftp_cleanup_days" ) ?>">
259
+ </div>
260
+ </div>
261
+
262
+ <div class="row">
263
+ <div class="col s6 m4">
264
+ <button class="btn waves-effect waves-light" type="submit" name="action" id="action"
265
+ value="sftp"><?php echo __( "Save Settings", 'xcloner-backup-and-restore' ) ?>
266
+ <i class="material-icons right">save</i>
267
+ </button>
268
+ </div>
269
+ <div class="col s6 m4">
270
+ <button class="btn waves-effect waves-light orange" type="submit" name="action"
271
+ id="action" value="sftp"
272
+ onclick="jQuery('#connection_check').val('1')"><?php echo __( "Verify", 'xcloner-backup-and-restore' ) ?>
273
+ <i class="material-icons right">import_export</i>
274
+ </button>
275
+ </div>
276
+ </div>
277
+
278
+ </div>
279
+ </li>
280
+
281
+ <!-- AWS STORAGE-->
282
+ <li id="aws">
283
+ <div class="collapsible-header">
284
+ <i class="material-icons">computer</i><?php echo __( "S3 Storage", 'xcloner-backup-and-restore' ) ?>
285
+ <div class="switch right">
286
+ <label>
287
+ Off
288
+ <input type="checkbox" name="xcloner_aws_enable" class="status"
289
+ value="1" <?php if ( get_option( "xcloner_aws_enable" ) )
290
+ echo "checked" ?> \>
291
+ <span class="lever"></span>
292
+ On
293
+ </label>
294
+ </div>
295
+ </div>
296
+ <div class="collapsible-body">
297
+
298
+ <div class="row">
299
+ <div class="col s12 m3 label">
300
+ &nbsp;
301
+ </div>
302
+ <div class=" col s12 m6">
303
+ <p>
304
+ <?php echo sprintf( __( 'Visit %s and get your "Key" and "Secret <br />Visit %s to install your own S3 like service.' ), "<a href='https://aws.amazon.com/s3/' target='_blank'>https://aws.amazon.com/s3/</a>", "<a href='https://minio.io/' target='_blank'>https://minio.io/</a>" ) ?>
305
+ </p>
306
+ </div>
307
+ </div>
308
+
309
+ <div class="row">
310
+ <div class="col s12 m3 label">
311
+ <label for="aws_key"><?php echo __( "S3 Key", 'xcloner-backup-and-restore' ) ?></label>
312
+ </div>
313
+ <div class=" col s12 m6">
314
+ <input placeholder="<?php echo __( "S3 Key", 'xcloner-backup-and-restore' ) ?>"
315
+ id="aws_key" type="text" name="xcloner_aws_key" class="validate"
316
+ value="<?php echo get_option( "xcloner_aws_key" ) ?>" autocomplete="off">
317
+ </div>
318
+ </div>
319
+
320
+ <div class="row">
321
+ <div class="col s12 m3 label">
322
+ <label for="aws_secret"><?php echo __( "S3 Secret", 'xcloner-backup-and-restore' ) ?></label>
323
+ </div>
324
+ <div class=" col s12 m6">
325
+ <input placeholder="<?php echo __( "S3 Secret", 'xcloner-backup-and-restore' ) ?>"
326
+ id="aws_secret" type="text" name="xcloner_aws_secret" class="validate"
327
+ value="<?php echo get_option( "xcloner_aws_secret" ) ?>" autocomplete="off">
328
+ </div>
329
+ </div>
330
+
331
+ <div class="row">
332
+ <div class="col s12 m3 label">
333
+ <label for="aws_region"><?php echo __( "S3 Region", 'xcloner-backup-and-restore' ) ?></label>
334
+ </div>
335
+ <div class=" col s12 m6">
336
+ <select placeholder="<?php echo __( "example: us-east-1", 'xcloner-backup-and-restore' ) ?>"
337
+ id="aws_region" type="text" name="xcloner_aws_region" class="validate"
338
+ value="<?php echo get_option( "xcloner_aws_region" ) ?>" autocomplete="off">
339
+ <option readonly
340
+ value=""><?php echo __( "Please Select AWS S3 Region or Leave Unselected for Custom Endpoint" ) ?></option>
341
+ <?php
342
+ $aws_regions = $remote_storage->get_aws_regions();
343
+
344
+ foreach ( $aws_regions as $key => $region ) {
345
+ ?>
346
+ <option value="<?php echo $key ?>" <?php echo( $key == get_option( 'xcloner_aws_region' ) ? "selected" : "" ) ?>><?php echo $region ?>
347
+ = <?php echo $key ?></option>
348
+ <?php
349
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
350
  ?>
351
+ </select>
352
+ </div>
353
+ </div>
354
+
355
+ <div class="row">
356
+ <div class="col s12 m3 label">
357
+ <label for="aws_endpoint"><?php echo __( "S3 EndPoint", 'xcloner-backup-and-restore' ) ?></label>
358
+ </div>
359
+ <div class=" col s12 m6">
360
+ <input placeholder="<?php echo __( "S3 EndPoint, leave blank if you want to use the default Amazon AWS Service", 'xcloner-backup-and-restore' ) ?>"
361
+ id="aws_endpoint" type="text" name="xcloner_aws_endpoint" class="validate"
362
+ value="<?php echo get_option( "xcloner_aws_endpoint" ) ?>" autocomplete="off">
363
+ </div>
364
+ </div>
365
+
366
+ <div class="row">
367
+ <div class="col s12 m3 label">
368
+ <label for="aws_bucket_name"><?php echo __( "S3 Bucket Name", 'xcloner-backup-and-restore' ) ?></label>
369
+ </div>
370
+ <div class=" col s12 m6">
371
+ <input placeholder="<?php echo __( "S3 Bucket Name", 'xcloner-backup-and-restore' ) ?>"
372
+ id="aws_bucket_name" type="text" name="xcloner_aws_bucket_name" class="validate"
373
+ value="<?php echo get_option( "xcloner_aws_bucket_name" ) ?>" autocomplete="off">
374
+ </div>
375
+ </div>
376
+
377
+ <div class="row">
378
+ <div class="col s12 m3 label">
379
+ <label for="aws_prefix"><?php echo __( "S3 Prefix", 'xcloner-backup-and-restore' ) ?></label>
380
+ </div>
381
+ <div class=" col s12 m6">
382
+ <input placeholder="<?php echo __( "S3 Prefix, use / ending to define a folder", 'xcloner-backup-and-restore' ) ?>"
383
+ id="aws_prefix" type="text" name="xcloner_aws_prefix" class="validate"
384
+ value="<?php echo get_option( "xcloner_aws_prefix" ) ?>" autocomplete="off">
385
+ </div>
386
+ </div>
387
+
388
+ <div class="row">
389
+ <div class="col s12 m3 label">
390
+ <label for="aws_cleanup_days"><?php echo __( "S3 Cleanup (days)", 'xcloner-backup-and-restore' ) ?></label>
391
+ </div>
392
+ <div class=" col s12 m6">
393
+ <input placeholder="<?php echo __( "how many days to keep the backups for", 'xcloner-backup-and-restore' ) ?>"
394
+ id="aws_cleanup_days" type="text" name="xcloner_aws_cleanup_days"
395
+ class="validate" value="<?php echo get_option( "xcloner_aws_cleanup_days" ) ?>">
396
+ </div>
397
+ </div>
398
+
399
+ <div class="row">
400
+ <div class="col s6 m4">
401
+ <button class="btn waves-effect waves-light" type="submit" name="action" id="action"
402
+ value="aws"><?php echo __( "Save Settings", 'xcloner-backup-and-restore' ) ?>
403
+ <i class="material-icons right">save</i>
404
+ </button>
405
+ </div>
406
+ <div class="col s6 m4">
407
+ <button class="btn waves-effect waves-light orange" type="submit" name="action"
408
+ id="action" value="aws"
409
+ onclick="jQuery('#connection_check').val('1')"><?php echo __( "Verify", 'xcloner-backup-and-restore' ) ?>
410
+ <i class="material-icons right">import_export</i>
411
+ </button>
412
+ </div>
413
+ </div>
414
+
415
+ </div>
416
+ </li>
417
+
418
+ <!-- DROPBOX STORAGE-->
419
+ <li id="dropbox">
420
+ <div class="collapsible-header">
421
+ <i class="material-icons">computer</i><?php echo __( "Dropbox Storage", 'xcloner-backup-and-restore' ) ?>
422
+ <div class="switch right">
423
+ <label>
424
+ Off
425
+ <input type="checkbox" name="xcloner_dropbox_enable" class="status"
426
+ value="1" <?php if ( get_option( "xcloner_dropbox_enable" ) )
427
+ echo "checked" ?> \>
428
+ <span class="lever"></span>
429
+ On
430
+ </label>
431
+ </div>
432
+ </div>
433
+ <div class="collapsible-body">
434
+
435
+ <div class="row">
436
+ <div class="col s12 m3 label">
437
+ &nbsp;
438
+ </div>
439
+ <div class=" col s12 m6">
440
+ <p>
441
+ <?php echo sprintf( __( 'Visit %s and get your "App secret".' ), "<a href='https://www.dropbox.com/developers/apps' target='_blank'>https://www.dropbox.com/developers/apps</a>" ) ?>
442
+ </p>
443
+ </div>
444
+ </div>
445
+
446
+ <div class="row">
447
+ <div class="col s12 m3 label">
448
+ <label for="dropbox_access_token"><?php echo __( "Dropbox Access Token", 'xcloner-backup-and-restore' ) ?></label>
449
+ </div>
450
+ <div class=" col s12 m6">
451
+ <input placeholder="<?php echo __( "Dropbox Access Token", 'xcloner-backup-and-restore' ) ?>"
452
+ id="dropbox_access_token" type="text" name="xcloner_dropbox_access_token"
453
+ class="validate"
454
+ value="<?php echo get_option( "xcloner_dropbox_access_token" ) ?>"
455
+ autocomplete="off">
456
+ </div>
457
+ </div>
458
+
459
+
460
+ <div class="row">
461
+ <div class="col s12 m3 label">
462
+ <label for="dropbox_app_secret"><?php echo __( "Dropbox App Secret", 'xcloner-backup-and-restore' ) ?></label>
463
+ </div>
464
+ <div class=" col s12 m6">
465
+ <input placeholder="<?php echo __( "Dropbox App Secret", 'xcloner-backup-and-restore' ) ?>"
466
+ id="dropbox_app_secret" type="text" name="xcloner_dropbox_app_secret"
467
+ class="validate" value="<?php echo get_option( "xcloner_dropbox_app_secret" ) ?>"
468
+ autocomplete="off">
469
+ </div>
470
+ </div>
471
+
472
+ <div class="row">
473
+ <div class="col s12 m3 label">
474
+ <label for="dropbox_prefix"><?php echo __( "Dropbox Prefix", 'xcloner-backup-and-restore' ) ?></label>
475
+ </div>
476
+ <div class=" col s12 m6">
477
+ <input placeholder="<?php echo __( "Dropbox Prefix", 'xcloner-backup-and-restore' ) ?>"
478
+ id="dropbox_prefix" type="text" name="xcloner_dropbox_prefix" class="validate"
479
+ value="<?php echo get_option( "xcloner_dropbox_prefix" ) ?>">
480
+ </div>
481
+ </div>
482
+
483
+ <div class="row">
484
+ <div class="col s12 m3 label">
485
+ <label for="dropbox_cleanup_days"><?php echo __( "Dropbox Cleanup (days)", 'xcloner-backup-and-restore' ) ?></label>
486
+ </div>
487
+ <div class=" col s12 m6">
488
+ <input placeholder="<?php echo __( "how many days to keep the backups for", 'xcloner-backup-and-restore' ) ?>"
489
+ id="dropbox_cleanup_days" type="text" name="xcloner_dropbox_cleanup_days"
490
+ class="validate"
491
+ value="<?php echo get_option( "xcloner_dropbox_cleanup_days" ) ?>">
492
+ </div>
493
+ </div>
494
+
495
+ <div class="row">
496
+ <div class="col s6 m4">
497
+ <button class="btn waves-effect waves-light" type="submit" name="action" id="action"
498
+ value="dropbox"><?php echo __( "Save Settings", 'xcloner-backup-and-restore' ) ?>
499
+ <i class="material-icons right">save</i>
500
+ </button>
501
+ </div>
502
+ <div class="col s6 m4">
503
+ <button class="btn waves-effect waves-light orange" type="submit" name="action"
504
+ id="action" value="dropbox"
505
+ onclick="jQuery('#connection_check').val('1')"><?php echo __( "Verify", 'xcloner-backup-and-restore' ) ?>
506
+ <i class="material-icons right">import_export</i>
507
+ </button>
508
+ </div>
509
+ </div>
510
+
511
+ </div>
512
+ </li>
513
+
514
+ <!-- AZURE STORAGE-->
515
+ <li id="azure">
516
+ <div class="collapsible-header">
517
+ <i class="material-icons">computer</i><?php echo __( "Azure Blob Storage", 'xcloner-backup-and-restore' ) ?>
518
+ <div class="switch right">
519
+ <label>
520
+ Off
521
+ <input type="checkbox" name="xcloner_azure_enable" class="status"
522
+ value="1" <?php if ( get_option( "xcloner_azure_enable" ) )
523
+ echo "checked" ?> \>
524
+ <span class="lever"></span>
525
+ On
526
+ </label>
527
+ </div>
528
+ </div>
529
+ <div class="collapsible-body">
530
+
531
+ <div class="row">
532
+ <div class="col s12 m3 label">
533
+ &nbsp;
534
+ </div>
535
+ <div class=" col s12 m6">
536
+ <p>
537
+ <?php echo sprintf( __( 'Visit %s and get your "Api Key".', 'xcloner-backup-and-restore' ), '<a href="https://azure.microsoft.com/en-us/services/storage/blobs/" target="_blank">https://azure.microsoft.com/en-us/services/storage/blobs/</a>' ) ?>
538
+ </p>
539
+ </div>
540
+ </div>
541
+
542
+ <div class="row">
543
+ <div class="col s12 m3 label">
544
+ <label for="azure_account_name"><?php echo __( "Azure Account Name", 'xcloner-backup-and-restore' ) ?></label>
545
+ </div>
546
+ <div class=" col s12 m6">
547
+ <input placeholder="<?php echo __( "Azure Account Name", 'xcloner-backup-and-restore' ) ?>"
548
+ id="azure_account_name" type="text" name="xcloner_azure_account_name"
549
+ class="validate" value="<?php echo get_option( "xcloner_azure_account_name" ) ?>"
550
+ autocomplete="off">
551
+ </div>
552
+ </div>
553
+
554
+
555
+ <div class="row">
556
+ <div class="col s12 m3 label">
557
+ <label for="azure_api_key"><?php echo __( "Azure Api Key", 'xcloner-backup-and-restore' ) ?></label>
558
+ </div>
559
+ <div class=" col s12 m6">
560
+ <input placeholder="<?php echo __( "Azure Api Key", 'xcloner-backup-and-restore' ) ?>"
561
+ id="azure_api_key" type="text" name="xcloner_azure_api_key" class="validate"
562
+ value="<?php echo get_option( "xcloner_azure_api_key" ) ?>" autocomplete="off">
563
+ </div>
564
+ </div>
565
+
566
+ <div class="row">
567
+ <div class="col s12 m3 label">
568
+ <label for="azure_container"><?php echo __( "Azure Container", 'xcloner-backup-and-restore' ) ?></label>
569
+ </div>
570
+ <div class=" col s12 m6">
571
+ <input placeholder="<?php echo __( "Azure Container", 'xcloner-backup-and-restore' ) ?>"
572
+ id="azure_container" type="text" name="xcloner_azure_container" class="validate"
573
+ value="<?php echo get_option( "xcloner_azure_container" ) ?>">
574
+ </div>
575
+ </div>
576
+
577
+ <div class="row">
578
+ <div class="col s12 m3 label">
579
+ <label for="azure_cleanup_days"><?php echo __( "Azure Cleanup (days)", 'xcloner-backup-and-restore' ) ?></label>
580
+ </div>
581
+ <div class=" col s12 m6">
582
+ <input placeholder="<?php echo __( "how many days to keep the backups for", 'xcloner-backup-and-restore' ) ?>"
583
+ id="azure_cleanup_days" type="text" name="xcloner_azure_cleanup_days"
584
+ class="validate"
585
+ value="<?php echo get_option( "xcloner_azure_cleanup_days" ) ?>">
586
+ </div>
587
+ </div>
588
+
589
+ <div class="row">
590
+ <div class="col s6 m4">
591
+ <button class="btn waves-effect waves-light" type="submit" name="action" id="action"
592
+ value="azure"><?php echo __( "Save Settings", 'xcloner-backup-and-restore' ) ?>
593
+ <i class="material-icons right">save</i>
594
+ </button>
595
+ </div>
596
+ <div class="col s6 m4">
597
+ <button class="btn waves-effect waves-light orange" type="submit" name="action"
598
+ id="action" value="azure"
599
+ onclick="jQuery('#connection_check').val('1')"><?php echo __( "Verify", 'xcloner-backup-and-restore' ) ?>
600
+ <i class="material-icons right">import_export</i>
601
+ </button>
602
+ </div>
603
+ </div>
604
+
605
+ </div>
606
+ </li>
607
+
608
+ <!-- BACKBLAZE STORAGE-->
609
+ <li id="backblaze">
610
+ <div class="collapsible-header">
611
+ <i class="material-icons">computer</i><?php echo __( "Backblaze Storage", 'xcloner-backup-and-restore' ) ?>
612
+ <div class="switch right">
613
+ <label>
614
+ Off
615
+ <input type="checkbox" name="xcloner_backblaze_enable" class="status"
616
+ value="1" <?php if ( get_option( "xcloner_backblaze_enable" ) )
617
+ echo "checked" ?> \>
618
+ <span class="lever"></span>
619
+ On
620
+ </label>
621
+ </div>
622
+ </div>
623
+ <div class="collapsible-body">
624
+
625
+ <div class="row">
626
+ <div class="col s12 m3 label">
627
+ &nbsp;
628
+ </div>
629
+ <div class=" col s12 m6">
630
+ <p>
631
+ <?php echo sprintf( __( 'Visit %s and get your Account Id and Application Key.', 'xcloner-backup-and-restore' ), '<a href="https://secure.backblaze.com/b2_buckets.htm" target="_blank">https://secure.backblaze.com/b2_buckets.htm</a>' ) ?>
632
+ </p>
633
+ </div>
634
+ </div>
635
+
636
+ <div class="row">
637
+ <div class="col s12 m3 label">
638
+ <label for="backblaze_account_id"><?php echo __( "Backblaze Account Id", 'xcloner-backup-and-restore' ) ?></label>
639
+ </div>
640
+ <div class=" col s12 m6">
641
+ <input placeholder="<?php echo __( "Backblaze Account Id", 'xcloner-backup-and-restore' ) ?>"
642
+ id="backblaze_account_id" type="text" name="xcloner_backblaze_account_id"
643
+ class="validate"
644
+ value="<?php echo get_option( "xcloner_backblaze_account_id" ) ?>"
645
+ autocomplete="off">
646
+ </div>
647
+ </div>
648
+
649
+
650
+ <div class="row">
651
+ <div class="col s12 m3 label">
652
+ <label for="backblaze_application_key"><?php echo __( "Backblaze Application Key", 'xcloner-backup-and-restore' ) ?></label>
653
+ </div>
654
+ <div class=" col s12 m6">
655
+ <input placeholder="<?php echo __( "Backblaze Application Key", 'xcloner-backup-and-restore' ) ?>"
656
+ id="backblaze_application_key" type="text"
657
+ name="xcloner_backblaze_application_key" class="validate"
658
+ value="<?php echo get_option( "xcloner_backblaze_application_key" ) ?>"
659
+ autocomplete="off">
660
+ </div>
661
+ </div>
662
+
663
+ <div class="row">
664
+ <div class="col s12 m3 label">
665
+ <label for="backblaze_bucket_name"><?php echo __( "Backblaze Bucket Name", 'xcloner-backup-and-restore' ) ?></label>
666
+ </div>
667
+ <div class=" col s12 m6">
668
+ <input placeholder="<?php echo __( "Backblaze Bucket Name", 'xcloner-backup-and-restore' ) ?>"
669
+ id="backblaze_bucket_name" type="text" name="xcloner_backblaze_bucket_name"
670
+ class="validate"
671
+ value="<?php echo get_option( "xcloner_backblaze_bucket_name" ) ?>"
672
+ autocomplete="off">
673
+ </div>
674
+ </div>
675
+
676
+ <div class="row">
677
+ <div class="col s12 m3 label">
678
+ <label for="backblaze_cleanup_days"><?php echo __( "Backblaze Cleanup (days)", 'xcloner-backup-and-restore' ) ?></label>
679
+ </div>
680
+ <div class=" col s12 m6">
681
+ <input placeholder="<?php echo __( "how many days to keep the backups for", 'xcloner-backup-and-restore' ) ?>"
682
+ id="backblaze_cleanup_days" type="text" name="xcloner_backblaze_cleanup_days"
683
+ class="validate"
684
+ value="<?php echo get_option( "xcloner_backblaze_cleanup_days" ) ?>">
685
+ </div>
686
+ </div>
687
+
688
+ <div class="row">
689
+ <div class="col s6 m4">
690
+ <button class="btn waves-effect waves-light" type="submit" name="action" id="action"
691
+ value="backblaze"><?php echo __( "Save Settings", 'xcloner-backup-and-restore' ) ?>
692
+ <i class="material-icons right">save</i>
693
+ </button>
694
+ </div>
695
+ <div class="col s6 m4">
696
+ <button class="btn waves-effect waves-light orange" type="submit" name="action"
697
+ id="action" value="backblaze"
698
+ onclick="jQuery('#connection_check').val('1')"><?php echo __( "Verify", 'xcloner-backup-and-restore' ) ?>
699
+ <i class="material-icons right">import_export</i>
700
+ </button>
701
+ </div>
702
+ </div>
703
+
704
+ </div>
705
+ </li>
706
+
707
+ <!-- WEBDAV STORAGE-->
708
+ <li id="webdav">
709
+ <div class="collapsible-header">
710
+ <i class="material-icons">computer</i><?php echo __( "WebDAV Storage", 'xcloner-backup-and-restore' ) ?>
711
+ <div class="switch right">
712
+ <label>
713
+ Off
714
+ <input type="checkbox" name="xcloner_webdav_enable" class="status"
715
+ value="1" <?php if ( get_option( "xcloner_webdav_enable" ) )
716
+ echo "checked" ?> \>
717
+ <span class="lever"></span>
718
+ On
719
+ </label>
720
+ </div>
721
+ </div>
722
+ <div class="collapsible-body">
723
+
724
+ <div class="row">
725
+ <div class="col s12 m3 label">
726
+ &nbsp;
727
+ </div>
728
+ <div class=" col s12 m6">
729
+ <p>
730
+ <?php //echo sprintf(__('Visit %s and get your Account Id and Application Key.','xcloner-backup-and-restore'), '<a href="https://secure.backblaze.com/b2_buckets.htm" target="_blank">https://secure.backblaze.com/b2_buckets.htm</a>')?>
731
+ </p>
732
+ </div>
733
+ </div>
734
+
735
+ <div class="row">
736
+ <div class="col s12 m3 label">
737
+ <label for="webdav_url"><?php echo __( "WebDAV Base Url", 'xcloner-backup-and-restore' ) ?></label>
738
+ </div>
739
+ <div class=" col s12 m6">
740
+ <input placeholder="<?php echo __( "WebDAV Base Url", 'xcloner-backup-and-restore' ) ?>"
741
+ id="webdav_url" type="text" name="xcloner_webdav_url" class="validate"
742
+ value="<?php echo get_option( "xcloner_webdav_url" ) ?>" autocomplete="off">
743
+ </div>
744
+ </div>
745
+
746
+ <div class="row">
747
+ <div class="col s12 m3 label">
748
+ <label for="webdav_username"><?php echo __( "WebDAV Username", 'xcloner-backup-and-restore' ) ?></label>
749
+ </div>
750
+ <div class=" col s12 m6">
751
+ <input placeholder="<?php echo __( "WebDAV Username", 'xcloner-backup-and-restore' ) ?>"
752
+ id="webdav_username" type="text" name="xcloner_webdav_username" class="validate"
753
+ value="<?php echo get_option( "xcloner_webdav_username" ) ?>" autocomplete="off">
754
+ </div>
755
+ </div>
756
+
757
+ <div class="row">
758
+ <div class="col s12 m3 label">
759
+ <label for="webdav_password"><?php echo __( "WebDAV Password", 'xcloner-backup-and-restore' ) ?></label>
760
+ </div>
761
+ <div class=" col s12 m6">
762
+ <input placeholder="<?php echo __( "WebDAV Password", 'xcloner-backup-and-restore' ) ?>"
763
+ id="webdav_password" type="password" name="xcloner_webdav_password"
764
+ class="validate" value="<?php echo get_option( "xcloner_webdav_password" ) ?>"
765
+ autocomplete="off">
766
+ </div>
767
+ </div>
768
+
769
+ <div class="row">
770
+ <div class="col s12 m3 label">
771
+ <label for="webdav_target_folder"><?php echo __( "WebDAV Target Folder", 'xcloner-backup-and-restore' ) ?></label>
772
+ </div>
773
+ <div class=" col s12 m6">
774
+ <input placeholder="<?php echo __( "WebDAV Target Folder", 'xcloner-backup-and-restore' ) ?>"
775
+ id="webdav_target_folder" type="text" name="xcloner_webdav_target_folder"
776
+ class="validate"
777
+ value="<?php echo get_option( "xcloner_webdav_target_folder" ) ?>"
778
+ autocomplete="off">
779
+ </div>
780
+ </div>
781
+
782
+ <div class="row">
783
+ <div class="col s12 m3 label">
784
+ <label for="webdav_cleanup_days"><?php echo __( "WebDAV Cleanup (days)", 'xcloner-backup-and-restore' ) ?></label>
785
+ </div>
786
+ <div class=" col s12 m6">
787
+ <input placeholder="<?php echo __( "how many days to keep the backups for", 'xcloner-backup-and-restore' ) ?>"
788
+ id="webdav_cleanup_days" type="text" name="xcloner_webdav_cleanup_days"
789
+ class="validate"
790
+ value="<?php echo get_option( "xcloner_webdav_cleanup_days" ) ?>">
791
+ </div>
792
+ </div>
793
+
794
+ <div class="row">
795
+ <div class="col s6 m4">
796
+ <button class="btn waves-effect waves-light" type="submit" name="action" id="action"
797
+ value="webdav"><?php echo __( "Save Settings", 'xcloner-backup-and-restore' ) ?>
798
+ <i class="material-icons right">save</i>
799
+ </button>
800
+ </div>
801
+ <div class="col s6 m4">
802
+ <button class="btn waves-effect waves-light orange" type="submit" name="action"
803
+ id="action" value="webdav"
804
+ onclick="jQuery('#connection_check').val('1')"><?php echo __( "Verify", 'xcloner-backup-and-restore' ) ?>
805
+ <i class="material-icons right">import_export</i>
806
+ </button>
807
+ </div>
808
+ </div>
809
+
810
+ </div>
811
+ </li>
812
+
813
+ <!-- Google DRIVE STORAGE-->
814
+ <li id="gdrive">
815
+ <div class="collapsible-header">
816
+ <i class="material-icons">computer</i><?php echo __( "Google Drive Storage", 'xcloner-backup-and-restore' ) ?>
817
+ <?php if ( $gdrive_construct ): ?>
818
+ <div class="switch right">
819
+ <label>
820
+ Off
821
+ <input type="checkbox" name="xcloner_gdrive_enable" class="status"
822
+ value="1" <?php if ( get_option( "xcloner_gdrive_enable" ) )
823
+ echo "checked" ?> \>
824
+ <span class="lever"></span>
825
+ On
826
+ </label>
827
+ </div>
828
+ <?php endif ?>
829
+ </div>
830
+ <div class="collapsible-body">
831
+
832
+ <?php if ( $gdrive_construct ) : ?>
833
+
834
+ <div class="row">
835
+ <div class="col s12 m3 label">
836
+ &nbsp;
837
+ </div>
838
+ <div class=" col s12 m9">
839
+ <p>
840
+ <?php echo sprintf( __( 'Visit %s to create a new application and get your Client ID and Client Secret.', 'xcloner-backup-and-restore' ), '<a href="https://console.developers.google.com" target="_blank">https://console.developers.google.com</a>' ) ?>
841
+ <a href="https://youtu.be/YXUVPUVgG8k" target="_blank"
842
+ class="btn-floating tooltipped btn-small" data-position="right"
843
+ data-delay="50" data-html="true"
844
+ data-tooltip="<?php echo sprintf( __( 'Click here to view a short video explaining how to create the Client ID and Client Secret as well as connecting XCloner with the Google Drive API %s', 'xcloner-backup-and-restore' ), "<br />https://youtu.be/YXUVPUVgG8k" ) ?>"
845
+ data-tooltip-id="92c95730-94e9-7b59-bd52-14adc30d5e3e"><i
846
+ class="material-icons">help_outline</i></a>
847
+ </p>
848
+ </div>
849
+ </div>
850
+
851
+ <div class="row">
852
+ <div class="col s12 m3 label">
853
+ <label for="gdrive_client_id"><?php echo __( "Client ID", 'xcloner-backup-and-restore' ) ?></label>
854
+ </div>
855
+ <div class=" col s12 m6">
856
+ <input placeholder="<?php echo __( "Google Client ID", 'xcloner-backup-and-restore' ) ?>"
857
+ id="gdrive_client_id" type="text" name="xcloner_gdrive_client_id"
858
+ class="validate"
859
+ value="<?php echo get_option( "xcloner_gdrive_client_id" ) ?>">
860
+ </div>
861
+ </div>
862
+
863
+ <div class="row">
864
+ <div class="col s12 m3 label">
865
+ <label for="gdrive_client_secret"><?php echo __( "Client Secret", 'xcloner-backup-and-restore' ) ?></label>
866
+ </div>
867
+ <div class=" col s12 m6">
868
+ <input placeholder="<?php echo __( "Google Client Secret", 'xcloner-backup-and-restore' ) ?>"
869
+ id="gdrive_client_secret" type="text" name="xcloner_gdrive_client_secret"
870
+ class="validate"
871
+ value="<?php echo get_option( "xcloner_gdrive_client_secret" ) ?>">
872
+ </div>
873
+ </div>
874
+
875
+
876
+ <div class="row">
877
+ <div class="col s12 m3 label">
878
+ &nbsp;
879
+ </div>
880
+ <div class=" col s12 m6">
881
+ <a class="btn" target="_blank" id="gdrive_authorization_click"
882
+ onclick="jQuery('#authentification_code').show()"
883
+ href="<?php echo $gdrive_auth_url ?>"><?php echo sprintf( __( 'Authorize Google Drive', 'xcloner-backup-and-restore' ) ) ?></a>
884
+ <input type="text" name="authentification_code" id="authentification_code"
885
+ placeholder="<?php echo __( "Paste Authorization Code Here", "xcloner-backup-and-restore" ) ?>">
886
+ </div>
887
+ </div>
888
+
889
+ <div class="row">
890
+ <div class="col s12 m3 label">
891
+ <label for="gdrive_target_folder"><?php echo __( "Folder ID or Root Path", 'xcloner-backup-and-restore' ) ?>
892
+ <a class="btn-floating tooltipped btn-small" data-position="right"
893
+ data-delay="50" data-html="true" \
894
+ data-tooltip="<?php echo __( 'Folder ID can be found by right clicking on the folder name and selecting \'Get shareable link\' menu, format https://drive.google.com/open?id={FOLDER_ID}<br />
895
+ If you supply a folder name, it has to exists in the drive root and start with / , example /backups.xcloner.com/', 'xcloner-backup-and-restore' ) ?>"
896
+ data-tooltip-id="92c95730-94e9-7b59-bd52-14adc30d5e3e"><i
897
+ class="material-icons">help_outline</i></a>
898
+ </label>
899
+ </div>
900
+ <div class=" col s12 m6">
901
+ <input placeholder="<?php echo __( "Target Folder ID or Root Path", 'xcloner-backup-and-restore' ) ?>"
902
+ id="gdrive_target_folder" type="text" name="xcloner_gdrive_target_folder"
903
+ class="validate"
904
+ value="<?php echo get_option( "xcloner_gdrive_target_folder" ) ?>"
905
+ autocomplete="off">
906
+ </div>
907
+ </div>
908
+
909
+ <div class="row">
910
+ <div class="col s12 m3 label">
911
+ <label for="gdrive_cleanup_days"><?php echo __( "Google Drive Cleanup (days)", 'xcloner-backup-and-restore' ) ?></label>
912
+ </div>
913
+ <div class=" col s12 m6">
914
+ <input placeholder="<?php echo __( "how many days to keep the backups for", 'xcloner-backup-and-restore' ) ?>"
915
+ id="gdrive_cleanup_days" type="text" name="xcloner_gdrive_cleanup_days"
916
+ class="validate"
917
+ value="<?php echo get_option( "xcloner_gdrive_cleanup_days" ) ?>">
918
+ </div>
919
+ </div>
920
+
921
+ <div class="row">
922
+ <div class="col s12 m3 label">
923
+ <label for="gdrive_empty_trash"><?php echo __( "Keeps Deleted Backups in Trash", 'xcloner-backup-and-restore' ) ?></label>
924
+ </div>
925
+ <div class=" col s12 m6 input-field inline">
926
+ <input name="xcloner_gdrive_empty_trash" type="radio" value="0"
927
+ id="gdrive_empty_trash_off" <?php if ( ! get_option( "xcloner_gdrive_empty_trash", 0 ) )
928
+ echo "checked" ?> />
929
+ <label for="gdrive_empty_trash_off"><?php echo __( "Enabled", 'xcloner-backup-and-restore' ) ?></label>
930
+
931
+ <input name="xcloner_gdrive_empty_trash" type="radio" value="1"
932
+ id="gdrive_empty_trash_on" <?php if ( get_option( "xcloner_gdrive_empty_trash", 0 ) )
933
+ echo "checked" ?> />
934
+ <label for="gdrive_empty_trash_on"><?php echo __( "Disabled", 'xcloner-backup-and-restore' ) ?></label>
935
+ </div>
936
+ </div>
937
+
938
+ <div class="row">
939
+ <div class="col s6 m4">
940
+ <button class="btn waves-effect waves-light" type="submit" name="action" id="action"
941
+ value="gdrive"><?php echo __( "Save Settings", 'xcloner-backup-and-restore' ) ?>
942
+ <i class="material-icons right">save</i>
943
+ </button>
944
+ </div>
945
+ <div class="col s6 m4">
946
+ <button class="btn waves-effect waves-light orange" type="submit" name="action"
947
+ id="action" value="gdrive"
948
+ onclick="jQuery('#connection_check').val('1')"><?php echo __( "Verify", 'xcloner-backup-and-restore' ) ?>
949
+ <i class="material-icons right">import_export</i>
950
+ </button>
951
+ </div>
952
+ </div>
953
+ <?php else: ?>
954
+
955
+ <div class="row">
956
+ <div class=" col s12">
957
+ <div class="center">
958
+ <?php
959
+ $url = wp_nonce_url( self_admin_url( 'update.php?action=install-plugin&plugin=xcloner-google-drive' ), 'install-plugin_xcloner-google-drive' );
960
+ ?>
961
+ <h6><?php echo __( "This storage option requires the XCloner-Google-Drive Wordpress Plugin to be installed and activated." ) ?></h6>
962
+ <h6><?php echo __( "PHP 5.5 minimum version is required." ) ?></h6>
963
+ <br/>
964
+ <a class="install-now btn" data-slug="xcloner-google-drive"
965
+ href="<?php echo $url; ?>"
966
+ aria-label="Install XCloner Google Drive 1.0.0 now"
967
+ data-name="XCloner Google Drive 1.0.0">
968
+ <?php echo sprintf( __( 'Install Now', 'xcloner-backup-and-restore' ) ) ?>
969
+ </a>
970
+
971
+ <a href="<?php echo admin_url( "plugin-install.php" ) ?>?tab=plugin-information&amp;plugin=xcloner-google-drive&amp;TB_iframe=true&amp;width=772&amp;height=499"
972
+ class="btn thickbox open-plugin-details-modal"
973
+ aria-label="More information about Theme Check 20160523.1"
974
+ data-title="Theme Check 20160523.1">
975
+ <!--
976
+ <a class="btn" href="https://github.com/ovidiul/XCloner-Google-Drive/archive/master.zip">
977
+ -->
978
+ <?php echo sprintf( __( 'More Details', 'xcloner-backup-and-restore' ) ) ?>
979
+ </a>
980
+ </div>
981
+ </div>
982
+ </div>
983
+
984
+ <?php endif; ?>
985
+
986
+ </div>
987
+ </li>
988
+
989
+
990
+ </ul>
991
+ </div>
992
+ </div>
993
 
994
  </form>
995
 
996
  <script>
 
 
 
 
 
 
 
 
997
 
998
+ function checkEndpoint() {
999
+ if (jQuery("#aws_region").val() != "") {
1000
+ jQuery('#aws_endpoint').parent().parent().hide();
1001
+ } else {
1002
+ jQuery('#aws_endpoint').parent().parent().show();
1003
+ }
1004
+ }
1005
+
1006
+ jQuery(document).ready(function () {
1007
+
1008
+ var remote_storage = new Xcloner_Remote_Storage();
1009
+
1010
+ checkEndpoint()
1011
+ jQuery("#aws_region").on("change", function () {
1012
+ checkEndpoint();
1013
+
1014
+ })
1015
+
1016
+ jQuery(".remote-storage .status").on("change", function () {
1017
+ remote_storage.toggle_status(this);
1018
+ })
1019
+
1020
+ jQuery(".remote-storage-form #action").on("click", function () {
1021
+ var tag = jQuery(this).val()
1022
+ window.location.hash = "#" + tag;
1023
+ })
1024
+
1025
+ jQuery("#gdrive_authorization_click").on("click", function (e) {
1026
+
1027
+ var href = (jQuery(this).attr("href"))
1028
+
1029
+ var new_href = href.replace(/(client_id=).*?(&)/, '$1' + jQuery("#gdrive_client_id").val() + '$2');
1030
+
1031
+ jQuery(this).attr("href", new_href)
1032
+
1033
+ });
1034
+
1035
+ if (location.hash)
1036
+ jQuery(location.hash + " div.collapsible-header").addClass("active");
1037
+
1038
+ jQuery('.collapsible').collapsible();
1039
+
1040
+ Materialize.updateTextFields();
1041
+
1042
+
1043
+ });
1044
+
1045
  </script>
admin/partials/xcloner_restore_page.php CHANGED
@@ -1,402 +1,470 @@
1
  <?php
2
 
3
- $xcloner_settings = $this->get_xcloner_container()->get_xcloner_settings();
4
- $logger = $this->get_xcloner_container()->get_xcloner_logger();
5
- $xcloner_file_system = $this->get_xcloner_container()->get_xcloner_filesystem();
6
- $xcloner_file_transfer = $this->get_xcloner_container()->get_xcloner_file_transfer();
7
 
8
- $start = 0 ;
9
 
10
  $backup_list = $xcloner_file_system->get_latest_backups();
11
 
12
  ?>
13
 
14
- <h1><?= esc_html(get_admin_page_title()); ?></h1>
15
 
16
- <script>
17
- var xcloner_auth_key = '<?php echo md5(AUTH_KEY)?>';
18
  </script>
19
 
20
  <div class="row xcloner-restore">
21
- <div class="col s12">
22
- <ul class="collapsible xcloner-restore " data-collapsible="accordion">
23
- <li data-step="1" class="restore-script-upload-step steps active show">
24
- <div class="collapsible-header active"><i class="material-icons">settings_remote</i><?php echo __("Restore Script Upload",'xcloner-backup-and-restore')?></div>
25
- <div class="collapsible-body row">
26
-
27
- <ul class="text-steps">
28
- <li><?php echo __("If you want to do a <strong>Local Target System Restore</strong>, leave Url field below empty and click 'Check Connection', you can skip the next steps.",'xcloner-backup-and-restore')?>
29
- </li>
30
- <li><?php echo __("If you want to do a <strong>Remote Target System Restore</strong>, please download the restore script from",'xcloner-backup-and-restore')?> <a href='#' onclick="window.location=ajaxurl+'?action=download_restore_script&phar=true'"><strong><?php echo __("here",'xcloner-backup-and-restore')?></strong></a>
31
- </li>
32
- <li>
33
- <?php echo __("Extract the restore script archive files on your new host",'xcloner-backup-and-restore')?>
34
- </li>
35
- <li>
36
- <?php echo __("Provide url below to the <u>xcloner_restore.php</u> restore script, like http://my_restore_site.com/xcloner_restore.php",'xcloner-backup-and-restore')?>
37
- </li>
38
- <li>
39
- <?php echo __("If your server is not web accessible, like a localhost computer, you can use a DynDNS service or install a blank copy of Wordpress with XCloner in the same environment and start the restore from there.",'xcloner-backup-and-restore')?>
40
- </li>
41
- <?php if(is_ssl()):?>
42
- <li class="warning">
43
- <?php echo __("We have detected your connection to the site as being secure, so your restore script address must start with https://.")?>
44
- </li>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  <?php endif ?>
46
-
47
- </ul>
48
-
49
- <div class="input-field col l9 s12">
50
- <input value="<?php echo (is_ssl())?"https://":""?>" id="restore_script_url" type="text" class="validate" placeholder="Url to XCloner Restore Script, example http://myddns.com/xcloner/xcloner_restore.php" >
51
- <label for="restore_script_url"></label>
52
- <div id="url_validation_status" class="status"></div>
53
- </div>
54
- <div class="col l3 s12 right-align">
55
- <button class="btn waves-effect waves-light" type="submit" id="validate_url" name="action"><?php echo __("Check Connection",'xcloner-backup-and-restore')?>
56
- <i class="material-icons right">send</i>
57
- </button>
58
- </div>
59
- </div>
60
- </li>
61
-
62
- <li data-step="2" class="backup-upload-step steps">
63
- <div class="collapsible-header active"><i class="material-icons">file_upload</i><?php echo __("Upload Local Backup Archive To Target Host",'xcloner-backup-and-restore')?>
64
- </div>
65
- <div class="collapsible-body row">
66
- <p><?php echo __("You can skip this step if you want to transfer the archive in some other way, make sure you upload it in the same directory as the restore script from the previous step.",'xcloner-backup-and-restore')?></p>
67
- <div class="input-field col s12 l7">
68
- <select id="backup_file" name="backup_file" class="browser-default">
69
- <option value="" disabled selected><?php echo __("Please select a local backup archive to upload to target host",'xcloner-backup-and-restore')?></option>
70
- <?php if(is_array($backup_list)):?>
71
- <?php foreach($backup_list as $file):?>
72
- <option value="<?php echo $file['basename']?>">
73
- <?php echo $file['basename']?> (<?php echo size_format($file['size'])?>)
74
- </option>
75
- <?php endforeach?>
76
- <?php endif ?>
77
- </select>
78
-
79
- <label> </label>
80
- <div class="progress">
81
- <div class="determinate" style="width: 0%"></div>
82
- </div>
83
- <div class="status"></div>
84
- </div>
85
- <div class="col s12 l5 right-align">
86
- <div class="toggler">
87
- <button class="btn waves-effect waves-light upload-backup normal" type="submit" id="" name="action"><?php echo __("Upload",'xcloner-backup-and-restore')?>
88
- <i class="material-icons left">navigate_before</i>
89
- </button>
90
- <button class="btn waves-effect waves-light red upload-backup cancel" type="submit" id="" name="action"><?php echo __("Cancel",'xcloner-backup-and-restore')?>
91
- <i class="material-icons right">close</i>
92
- </button>
93
- </div>
94
- <button class="btn waves-effect waves-light grey" type="submit" title="<?php echo __("Skip Next",'xcloner-backup-and-restore')?>" id="skip_upload_backup" name="action"><?php echo __("Skip Next",'xcloner-backup-and-restore')?>
95
- <i class="material-icons right">navigate_next</i>
96
- </button>
97
- </div>
98
- </div>
99
- </li>
100
-
101
- <li data-step="3" class="restore-remote-backup-step steps active">
102
- <div class="collapsible-header"><i class="material-icons">folder_open</i><?php echo __("Restore Files Backup Available On Target Location",'xcloner-backup-and-restore')?>
103
- <i class="material-icons right" title="Refresh Target Backup Files List" id="refresh_remote_backup_file">cached</i>
104
-
105
- <div class="switch right">
106
- <label>
107
- <?php echo __('Verbose Output', 'xcloner-backup-and-restore')?>
108
- <input type="checkbox" id="toggle_file_restore_display" name="toggle_file_restore_display" class="" checked value="1">
109
- <span class="lever"></span>
110
-
111
- </label>
112
- </div>
113
- </div>
114
- <div class="collapsible-body row">
115
-
116
- <div class=" col s12 l7">
117
- <div class="input-field row">
118
- <div class="col s12">
119
- <a class="btn-floating tooltipped btn-small right" data-html="true" data-position="left" data-delay="50"
120
- data-tooltip="<?php echo __("This is the directory where you would like to restore the backup archive files.<br />
121
- Please use this with caution when restoring to a live site.",'xcloner-backup-and-restore')?>"><i class="material-icons">help_outline</i>
122
- </a>
123
- <h5><?php echo __("Restore Target Path:",'xcloner-backup-and-restore')?></h5>
124
- <input type="text" name="remote_restore_path" id="remote_restore_path" class="validate" placeholder="Restore Target Path">
125
- <label></label>
126
- </div>
127
-
128
- </div>
129
-
130
- <div class="input-field row">
131
- <div class="col s12">
132
- <a href="#backup_localhost-2017-04-03_10-58-sql-diff2017-03-22_00-00-5b6c4.tgz"
133
- class="list-backup-content btn-floating tooltipped btn-small right" data-tooltip="<?php echo __('Click To List The Selected Backup Content', 'xcloner-backup-and-restore') ?>">
134
- <i class="material-icons">folder_open</i>
135
- </a>
136
- <h5><?php echo __("Restore Backup Archive:",'xcloner-backup-and-restore')?></h5>
137
- <select id="remote_backup_file" name="remote_backup_file" class="browser-default">
138
- <option value="" disabled selected><?php echo __("Please select the target backup file to restore",'xcloner-backup-and-restore')?></option>
139
- </select>
140
- <label></label>
141
- </div>
142
-
143
- <div class="col s12">
144
- <input class="with-gap" name="filter_files" type="radio" id="filter_files_all" checked value="" disabled />
145
- <label for="filter_files_all" class="tooltipped" data-position="right" data-tooltip="<?php echo __("Restore all backup files. Available only when doing a Remote Target System Restore", 'xcloner-backup-and-restore')?>"><?php echo __("Restore All Files","xcloner-backup-and-restore")?></label>
146
-
147
- <input class="with-gap" name="filter_files" type="radio" id="filter_files_wp_content" value="/^wp-content\/(.*)/" />
148
- <label for="filter_files_wp_content" class="tooltipped" data-tooltip="<?php echo __('Restore the files only of the wp-content/ folder', 'xcloner-backup-and-restore')?>">
149
- <?php echo __("Only wp-content","xcloner-backup-and-restore")?>
150
- </label>
151
-
152
- <input class="with-gap" name="filter_files" type="radio" id="filter_files_plugins" value="/^wp-content\/plugins(.*)/" />
153
- <label for="filter_files_plugins" class="tooltipped" data-tooltip="<?php echo __('Restore the files only of the wp-content/plugins/ folder', 'xcloner-backup-and-restore')?>">
154
- <?php echo __("Only Plugins","xcloner-backup-and-restore")?>
155
- </label>
156
-
157
- <input class="with-gap" name="filter_files" type="radio" id="filter_files_uploads" value="/^wp-content\/uploads(.*)/" />
158
- <label for="filter_files_uploads" class="tooltipped" data-tooltip="<?php echo __('Restore the files only of the wp-content/uploads/ folder only', 'xcloner-backup-and-restore')?>">
159
- <?php echo __("Only Uploads","xcloner-backup-and-restore")?>
160
- </label>
161
-
162
- <input class="with-gap" name="filter_files" type="radio" id="filter_files_themes" value="/^wp-content\/themes(.*)/" />
163
- <label for="filter_files_themes" class="tooltipped" data-tooltip="<?php echo __('Restore the files only of the wp-content/themes/ folder', 'xcloner-backup-and-restore')?>">
164
- <?php echo __("Only Themes","xcloner-backup-and-restore")?>
165
- </label>
166
-
167
- <input class="with-gap" name="filter_files" type="radio" id="filter_files_database" value="/^xcloner-(.*)\/(.*)\.sql/"/>
168
- <label for="filter_files_database" class="tooltipped" data-tooltip="<?php echo __('Restore the database-sql.sql mysql backup from the xcloner-xxxxx/ folder', 'xcloner-backup-and-restore')?>">
169
- <?php echo __("Only Database Backup","xcloner-backup-and-restore")?>
170
- </label>
171
- </div>
172
- </div>
173
-
174
- <div class="progress">
175
- <div class="indeterminate" style="width: 0%"></div>
176
- </div>
177
-
178
- <div class="status"></div>
179
- <ul class="files-list"></ul>
180
- </div>
181
-
182
- <div class="col s12 l5 right-align">
183
- <div class="toggler">
184
- <button class="btn waves-effect waves-light restore_remote_backup normal " type="submit" id="" name="action"><?php echo __("Restore",'xcloner-backup-and-restore')?>
185
- <i class="material-icons left">navigate_before</i>
186
- </button>
187
- <button class="btn waves-effect waves-light red restore_remote_backup cancel" type="submit" id="" name="action"><?php echo __("Cancel",'xcloner-backup-and-restore')?>
188
- <i class="material-icons right">close</i>
189
- </button>
190
- </div>
191
- <button class="btn waves-effect waves-light grey" type="submit" title="<?php echo __("Skip Next",'xcloner-backup-and-restore')?>" id="skip_remote_backup_step" name="action"><?php echo __("Skip Next",'xcloner-backup-and-restore')?>
192
- <i class="material-icons right">navigate_next</i>
193
- </button>
194
- </div>
195
- </div>
196
- </li>
197
-
198
- <li data-step="4" class="restore-remote-database-step steps active">
199
- <div class="collapsible-header"><i class="material-icons">list</i><?php echo __("Restore Target Database - Search and Replace",'xcloner-backup-and-restore')?>
200
- <i class="material-icons right" title="Refresh Database Backup Files List" id="refresh_database_file">cached</i>
201
- </div>
202
- <div class="collapsible-body row">
203
-
204
- <div id="remote-restore-options">
205
- <div class="col s12">
206
- <a class="btn-floating tooltipped btn-small right" data-position="left" data-delay="50" data-html="true" data-tooltip="<?php echo __('Please provide below the mysql connection details for the target host database.<br />For live sites we recommend using a new separate database.','xcloner-backup-and-restore')?>" data-tooltip-id="92c95730-94e9-7b59-bd52-14adc30d5e3e"><i class="material-icons">help_outline</i></a>
207
- <h5><?php echo __('Target Mysql Details','xcloner-backup-and-restore')?></h5>
208
- </div>
209
- <div class=" col s12">
210
- <div class="input-field col s12 m6">
211
- <input type="text" name="remote_mysql_host" id="remote_mysql_host" class="validate" placeholder="Target Mysql Hostname">
212
- <label><?php echo __("Target Mysql Hostname",'xcloner-backup-and-restore')?></label>
213
- </div>
214
-
215
- <div class="input-field col s12 m6">
216
- <input type="text" name="remote_mysql_db" id="remote_mysql_db" class="validate" placeholder="Target Mysql Database">
217
- <label><?php echo __("Target Mysql Database",'xcloner-backup-and-restore')?></label>
218
- </div>
219
-
220
- <div class="input-field col s12 m6">
221
- <input type="text" name="remote_mysql_user" id="remote_mysql_user" class="validate" placeholder="Target Mysql Username">
222
- <label><?php echo __("Target Mysql Username",'xcloner-backup-and-restore')?></label>
223
- </div>
224
-
225
-
226
- <div class="input-field col s12 m6">
227
- <input type="text" name="remote_mysql_pass" id="remote_mysql_pass" class="validate" placeholder="Target Mysql Password">
228
- <label><?php echo __("Target Mysql Password",'xcloner-backup-and-restore')?></label>
229
- </div>
230
-
231
- </div>
232
- <div class="col s12">
233
- <a class="btn-floating tooltipped btn-small right" data-position="left" data-delay="50" data-html="true" data-tooltip="<?php echo __('I will attempt to replace all mysql backup records matching the provided Source Url with the provided Target Url. <br />Leave blank the Target Url if you would like to skip this option. <br />As a bonus, I will also replace all matching serialized data and fix it\'s parsing.','xcloner-backup-and-restore')?>" data-tooltip-id="92c95730-94e9-7b59-bd52-14adc30d5e3e"><i class="material-icons">help_outline</i></a>
234
- <h5><?php echo __('Target Mysql Search and Replace','xcloner-backup-and-restore')?></h5>
235
- </div>
236
- <div class="col s12">
237
- <div class="input-field col s12 m6 ">
238
- <input type="text" name="wp_home_url" id="wp_home_url" class="validate" placeholder="WP Home Url" value="<?php echo home_url();?>">
239
- <label><?php echo __("Source Home Url",'xcloner-backup-and-restore')?></label>
240
- </div>
241
-
242
- <div class="input-field col s12 m6 ">
243
- <input type="text" name="remote_restore_url" id="remote_restore_url" class="validate" placeholder="Restore Target Url">
244
- <label><?php echo __("With Target Home Url",'xcloner-backup-and-restore')?></label>
245
- </div>
246
-
247
- <?php if( site_url() != home_url()) : ?>
248
- <div class="input-field col s12 m6 ">
249
- <input type="text" name="wp_site_url" id="wp_site_url" class="validate" placeholder="WP Site Url" value="<?php echo site_url();?>">
250
- <label><?php echo __("Source Site Url",'xcloner-backup-and-restore')?></label>
251
- </div>
252
-
253
- <div class="input-field col s12 m6 ">
254
- <input type="text" name="remote_restore_site_url" id="remote_restore_site_url" class="validate" placeholder="Restore Target Url">
255
- <label><?php echo __("With Target Site Url",'xcloner-backup-and-restore')?></label>
256
- </div>
257
-
258
- <?php endif;?>
259
- </div>
260
-
261
- </div>
262
-
263
- <div class=" col s12 l7">
264
- <div class="input-field row">
265
- <select id="remote_database_file" name="remote_database_file" class="browser-default">
266
- <option value="" disabled selected><?php echo __("Please select the target database backup file to restore",'xcloner-backup-and-restore')?></option>
267
- </select>
268
-
269
- <label></label>
270
- </div>
271
-
272
- <div class="progress">
273
- <div class="determinate" style="width: 0%"></div>
274
- </div>
275
-
276
- <div class="status"></div>
277
- <div class="query-box">
278
- <h6><?php echo __('Use the field below to fix your mysql query and Retry again the Restore, or replace with # to Skip next', 'xcloner-backup-and-restore')?></h6>
279
- <textarea class="query-list" cols="5"></textarea>
280
- </div>
281
- </div>
282
-
283
- <div class="col s12 l5 right-align">
284
- <div class="toggler">
285
- <button class="btn waves-effect waves-light restore_remote_mysqldump normal " type="submit" id="" name="action"><?php echo __("Restore",'xcloner-backup-and-restore')?>
286
- <i class="material-icons left">navigate_before</i>
287
- </button>
288
- <button class="btn waves-effect waves-light red restore_remote_mysqldump cancel" type="submit" id="" name="action"><?php echo __("Cancel",'xcloner-backup-and-restore')?>
289
- <i class="material-icons right">close</i>
290
- </button>
291
- </div>
292
-
293
- <button class="btn waves-effect waves-light grey" type="submit" title="<?php echo __("Skip Next",'xcloner-backup-and-restore')?>" id="skip_restore_remote_database_step" name="action"><?php echo __("Skip Next",'xcloner-backup-and-restore')?>
294
- <i class="material-icons right">navigate_next</i>
295
- </button>
296
-
297
- </div>
298
-
299
- </div>
300
- </li>
301
-
302
- <li data-step="5" class="restore-finish-step steps active">
303
- <div class="collapsible-header"><i class="material-icons">folder_open</i><?php echo __("Finishing up...",'xcloner-backup-and-restore')?>
304
- </div>
305
- <div class="collapsible-body row">
306
-
307
- <div class="row">
308
- <div class="col s4">
309
- <label><?php echo __("Update wp-config.php mysql details and update the Target Site Url",'xcloner-backup-and-restore')?></label>
310
- </div>
311
-
312
- <div class="col s8">
313
- <div class="switch">
314
- <label>
315
- Off
316
- <input type="checkbox" id="update_remote_site_url" name="update_remote_site_url" checked value="1">
317
- <span class="lever"></span>
318
- On
319
- </label>
320
- </div>
321
- </div>
322
- </div>
323
-
324
- <div class="row">
325
- <div class="col s4">
326
- <label><?php echo __("Delete Restored Backup Temporary Folder",'xcloner-backup-and-restore')?></label>
327
- </div>
328
- <div class="col s8">
329
- <div class="switch">
330
- <label>
331
- Off
332
- <input type="checkbox" id="delete_backup_temporary_folder" name="delete_backup_temporary_folder" checked value="1">
333
- <span class="lever"></span>
334
- On
335
- </label>
336
- </div>
337
- </div>
338
- </div>
339
-
340
- <div class="row">
341
- <div class="col s4">
342
- <label><?php echo __("Delete Restore Script",'xcloner-backup-and-restore')?></label>
343
- </div>
344
- <div class="col s8">
345
- <div class="switch">
346
- <label>
347
- Off
348
- <input type="checkbox" id="delete_restore_script" name="delete_restore_script" checked value="1">
349
- <span class="lever"></span>
350
- On
351
- </label>
352
- </div>
353
- </div>
354
- </div>
355
-
356
- <div class=" row col s12">
357
- <div class="status"></div>
358
- </div>
359
-
360
- <div class=" row col s12 center-align" id="xcloner_restore_finish">
361
- <h5><?php echo __("Thank you for using XCloner.",'xcloner-backup-and-restore')?></h5>
362
- <h6><?php echo sprintf(__("We would love to hear about your experience in the %s.", 'xcloner-backup-and-restore'),'<a href="https://wordpress.org/support/plugin/xcloner-backup-and-restore" target="_blank">Wordpress XCloner forums</a>') ?></h6>
363
- <a class="twitter-follow-button" href="https://twitter.com/thinkovi" data-show-count="false">Follow @thinkovi</a>
364
- <script src="//platform.twitter.com/widgets.js" async="" charset="utf-8"></script>
365
- </div>
366
-
367
- <div class="col s12 center-align">
368
- <div class="row">
369
- <div class="col s6 right-align">
370
- <button class="btn waves-effect waves-light teal" type="submit" id="restore_finish" name="action"><?php echo __("Finish",'xcloner-backup-and-restore')?>
371
- <i class="material-icons right">navigate_next</i>
372
- </button>
373
- </div>
374
-
375
- <div id="open_target_site" class="col s6 left-align">
376
- <a disabled="disabled" href="#" class="btn waves-effect waves-light teal" type="button" target="_blank"><?php echo __("Open Target Site",'xcloner-backup-and-restore')?>
377
- <i class="material-icons right">navigate_next</i>
378
- </a>
379
- </div>
380
- </div>
381
- </div>
382
- </div>
383
- </li>
384
-
385
- </ul>
386
- </div>
387
- </div>
388
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
389
 
390
 
391
  <!-- List Backup Content Modal-->
392
  <div id="backup_cotent_modal" class="modal">
393
- <div class="modal-content">
394
- <h4><?php echo sprintf(__("Listing Backup Content ",'xcloner-backup-and-restore'), "")?></h4>
395
- <h5 class="backup-name"></h5>
396
-
397
- <div class="progress">
398
- <div class="indeterminate"></div>
399
- </div>
400
- <ul class="files-list"></ul>
401
- </div>
402
  </div>
1
  <?php
2
 
3
+ $xcloner_settings = $this->get_xcloner_container()->get_xcloner_settings();
4
+ $logger = $this->get_xcloner_container()->get_xcloner_logger();
5
+ $xcloner_file_system = $this->get_xcloner_container()->get_xcloner_filesystem();
6
+ $xcloner_file_transfer = $this->get_xcloner_container()->get_xcloner_file_transfer();
7
 
8
+ $start = 0;
9
 
10
  $backup_list = $xcloner_file_system->get_latest_backups();
11
 
12
  ?>
13
 
14
+ <h1><?= esc_html( get_admin_page_title() ); ?></h1>
15
 
16
+ <script>
17
+ var xcloner_auth_key = '<?php echo md5( AUTH_KEY )?>';
18
  </script>
19
 
20
  <div class="row xcloner-restore">
21
+ <div class="col s12">
22
+ <ul class="collapsible xcloner-restore " data-collapsible="accordion">
23
+ <li data-step="1" class="restore-script-upload-step steps active show">
24
+ <div class="collapsible-header active"><i
25
+ class="material-icons">settings_remote</i><?php echo __( "Restore Script Upload", 'xcloner-backup-and-restore' ) ?>
26
+ </div>
27
+ <div class="collapsible-body row">
28
+
29
+ <ul class="text-steps">
30
+ <li><?php echo __( "If you want to do a <strong>Local Target System Restore</strong>, leave Url field below empty and click 'Check Connection', you can skip the next steps.", 'xcloner-backup-and-restore' ) ?>
31
+ </li>
32
+ <li><?php echo __( "If you want to do a <strong>Remote Target System Restore</strong>, please download the restore script from", 'xcloner-backup-and-restore' ) ?>
33
+ <a href='#'
34
+ onclick="window.location=ajaxurl+'?action=download_restore_script&phar=true'"><strong><?php echo __( "here", 'xcloner-backup-and-restore' ) ?></strong></a>
35
+ </li>
36
+ <li>
37
+ <?php echo __( "Extract the restore script archive files on your new host", 'xcloner-backup-and-restore' ) ?>
38
+ </li>
39
+ <li>
40
+ <?php echo __( "Provide url below to the <u>xcloner_restore.php</u> restore script, like http://my_restore_site.com/xcloner_restore.php", 'xcloner-backup-and-restore' ) ?>
41
+ </li>
42
+ <li>
43
+ <?php echo __( "If your server is not web accessible, like a localhost computer, you can use a DynDNS service or install a blank copy of Wordpress with XCloner in the same environment and start the restore from there.", 'xcloner-backup-and-restore' ) ?>
44
+ </li>
45
+ <?php if ( is_ssl() ): ?>
46
+ <li class="warning">
47
+ <?php echo __( "We have detected your connection to the site as being secure, so your restore script address must start with https://." ) ?>
48
+ </li>
49
+ <?php endif ?>
50
+
51
+ </ul>
52
+
53
+ <div class="input-field col l9 s12">
54
+ <input value="<?php echo ( is_ssl() ) ? "https://" : "" ?>" id="restore_script_url" type="text"
55
+ class="validate"
56
+ placeholder="Url to XCloner Restore Script, example http://myddns.com/xcloner/xcloner_restore.php">
57
+ <label for="restore_script_url"></label>
58
+ <div id="url_validation_status" class="status"></div>
59
+ </div>
60
+ <div class="col l3 s12 right-align">
61
+ <button class="btn waves-effect waves-light" type="submit" id="validate_url"
62
+ name="action"><?php echo __( "Check Connection", 'xcloner-backup-and-restore' ) ?>
63
+ <i class="material-icons right">send</i>
64
+ </button>
65
+ </div>
66
+ </div>
67
+ </li>
68
+
69
+ <li data-step="2" class="backup-upload-step steps">
70
+ <div class="collapsible-header active"><i
71
+ class="material-icons">file_upload</i><?php echo __( "Upload Local Backup Archive To Target Host", 'xcloner-backup-and-restore' ) ?>
72
+ </div>
73
+ <div class="collapsible-body row">
74
+ <p><?php echo __( "You can skip this step if you want to transfer the archive in some other way, make sure you upload it in the same directory as the restore script from the previous step.", 'xcloner-backup-and-restore' ) ?></p>
75
+ <div class="input-field col s12 l7">
76
+ <select id="backup_file" name="backup_file" class="browser-default">
77
+ <option value="" disabled
78
+ selected><?php echo __( "Please select a local backup archive to upload to target host", 'xcloner-backup-and-restore' ) ?></option>
79
+ <?php if ( is_array( $backup_list ) ): ?>
80
+ <?php foreach ( $backup_list as $file ): ?>
81
+ <option value="<?php echo $file['basename'] ?>">
82
+ <?php echo $file['basename'] ?> (<?php echo size_format( $file['size'] ) ?>)
83
+ </option>
84
+ <?php endforeach ?>
85
  <?php endif ?>
86
+ </select>
87
+
88
+ <label> </label>
89
+ <div class="progress">
90
+ <div class="determinate" style="width: 0%"></div>
91
+ </div>
92
+ <div class="status"></div>
93
+ </div>
94
+ <div class="col s12 l5 right-align">
95
+ <div class="toggler">
96
+ <button class="btn waves-effect waves-light upload-backup normal" type="submit" id=""
97
+ name="action"><?php echo __( "Upload", 'xcloner-backup-and-restore' ) ?>
98
+ <i class="material-icons left">navigate_before</i>
99
+ </button>
100
+ <button class="btn waves-effect waves-light red upload-backup cancel" type="submit" id=""
101
+ name="action"><?php echo __( "Cancel", 'xcloner-backup-and-restore' ) ?>
102
+ <i class="material-icons right">close</i>
103
+ </button>
104
+ </div>
105
+ <button class="btn waves-effect waves-light grey" type="submit"
106
+ title="<?php echo __( "Skip Next", 'xcloner-backup-and-restore' ) ?>"
107
+ id="skip_upload_backup"
108
+ name="action"><?php echo __( "Skip Next", 'xcloner-backup-and-restore' ) ?>
109
+ <i class="material-icons right">navigate_next</i>
110
+ </button>
111
+ </div>
112
+ </div>
113
+ </li>
114
+
115
+ <li data-step="3" class="restore-remote-backup-step steps active">
116
+ <div class="collapsible-header"><i
117
+ class="material-icons">folder_open</i><?php echo __( "Restore Files Backup Available On Target Location", 'xcloner-backup-and-restore' ) ?>
118
+ <i class="material-icons right" title="Refresh Target Backup Files List"
119
+ id="refresh_remote_backup_file">cached</i>
120
+
121
+ <div class="switch right">
122
+ <label>
123
+ <?php echo __( 'Verbose Output', 'xcloner-backup-and-restore' ) ?>
124
+ <input type="checkbox" id="toggle_file_restore_display" name="toggle_file_restore_display"
125
+ class="" checked value="1">
126
+ <span class="lever"></span>
127
+
128
+ </label>
129
+ </div>
130
+ </div>
131
+ <div class="collapsible-body row">
132
+
133
+ <div class=" col s12 l7">
134
+ <div class="input-field row">
135
+ <div class="col s12">
136
+ <a class="btn-floating tooltipped btn-small right" data-html="true" data-position="left"
137
+ data-delay="50"
138
+ data-tooltip="<?php echo __( "This is the directory where you would like to restore the backup archive files.<br />
139
+ Please use this with caution when restoring to a live site.", 'xcloner-backup-and-restore' ) ?>"><i
140
+ class="material-icons">help_outline</i>
141
+ </a>
142
+ <h5><?php echo __( "Restore Target Path:", 'xcloner-backup-and-restore' ) ?></h5>
143
+ <input type="text" name="remote_restore_path" id="remote_restore_path" class="validate"
144
+ placeholder="Restore Target Path">
145
+ <label></label>
146
+ </div>
147
+
148
+ </div>
149
+
150
+ <div class="input-field row">
151
+ <div class="col s12">
152
+ <a href="#backup_localhost-2017-04-03_10-58-sql-diff2017-03-22_00-00-5b6c4.tgz"
153
+ class="list-backup-content btn-floating tooltipped btn-small right"
154
+ data-tooltip="<?php echo __( 'Click To List The Selected Backup Content', 'xcloner-backup-and-restore' ) ?>">
155
+ <i class="material-icons">folder_open</i>
156
+ </a>
157
+ <h5><?php echo __( "Restore Backup Archive:", 'xcloner-backup-and-restore' ) ?></h5>
158
+ <select id="remote_backup_file" name="remote_backup_file" class="browser-default">
159
+ <option value="" disabled
160
+ selected><?php echo __( "Please select the target backup file to restore", 'xcloner-backup-and-restore' ) ?></option>
161
+ </select>
162
+ <label></label>
163
+ </div>
164
+
165
+ <div class="col s12">
166
+ <input class="with-gap" name="filter_files" type="radio" id="filter_files_all" checked
167
+ value="" disabled/>
168
+ <label for="filter_files_all" class="tooltipped" data-position="right"
169
+ data-tooltip="<?php echo __( "Restore all backup files. Available only when doing a Remote Target System Restore", 'xcloner-backup-and-restore' ) ?>"><?php echo __( "Restore All Files", "xcloner-backup-and-restore" ) ?></label>
170
+
171
+ <input class="with-gap" name="filter_files" type="radio" id="filter_files_wp_content"
172
+ value="/^wp-content\/(.*)/"/>
173
+ <label for="filter_files_wp_content" class="tooltipped"
174
+ data-tooltip="<?php echo __( 'Restore the files only of the wp-content/ folder', 'xcloner-backup-and-restore' ) ?>">
175
+ <?php echo __( "Only wp-content", "xcloner-backup-and-restore" ) ?>
176
+ </label>
177
+
178
+ <input class="with-gap" name="filter_files" type="radio" id="filter_files_plugins"
179
+ value="/^wp-content\/plugins(.*)/"/>
180
+ <label for="filter_files_plugins" class="tooltipped"
181
+ data-tooltip="<?php echo __( 'Restore the files only of the wp-content/plugins/ folder', 'xcloner-backup-and-restore' ) ?>">
182
+ <?php echo __( "Only Plugins", "xcloner-backup-and-restore" ) ?>
183
+ </label>
184
+
185
+ <input class="with-gap" name="filter_files" type="radio" id="filter_files_uploads"
186
+ value="/^wp-content\/uploads(.*)/"/>
187
+ <label for="filter_files_uploads" class="tooltipped"
188
+ data-tooltip="<?php echo __( 'Restore the files only of the wp-content/uploads/ folder only', 'xcloner-backup-and-restore' ) ?>">
189
+ <?php echo __( "Only Uploads", "xcloner-backup-and-restore" ) ?>
190
+ </label>
191
+
192
+ <input class="with-gap" name="filter_files" type="radio" id="filter_files_themes"
193
+ value="/^wp-content\/themes(.*)/"/>
194
+ <label for="filter_files_themes" class="tooltipped"
195
+ data-tooltip="<?php echo __( 'Restore the files only of the wp-content/themes/ folder', 'xcloner-backup-and-restore' ) ?>">
196
+ <?php echo __( "Only Themes", "xcloner-backup-and-restore" ) ?>
197
+ </label>
198
+
199
+ <input class="with-gap" name="filter_files" type="radio" id="filter_files_database"
200
+ value="/^xcloner-(.*)\/(.*)\.sql/"/>
201
+ <label for="filter_files_database" class="tooltipped"
202
+ data-tooltip="<?php echo __( 'Restore the database-sql.sql mysql backup from the xcloner-xxxxx/ folder', 'xcloner-backup-and-restore' ) ?>">
203
+ <?php echo __( "Only Database Backup", "xcloner-backup-and-restore" ) ?>
204
+ </label>
205
+ </div>
206
+ </div>
207
+
208
+ <div class="progress">
209
+ <div class="indeterminate" style="width: 0%"></div>
210
+ </div>
211
+
212
+ <div class="status"></div>
213
+ <ul class="files-list"></ul>
214
+ </div>
215
+
216
+ <div class="col s12 l5 right-align">
217
+ <div class="toggler">
218
+ <button class="btn waves-effect waves-light restore_remote_backup normal " type="submit"
219
+ id="" name="action"><?php echo __( "Restore", 'xcloner-backup-and-restore' ) ?>
220
+ <i class="material-icons left">navigate_before</i>
221
+ </button>
222
+ <button class="btn waves-effect waves-light red restore_remote_backup cancel" type="submit"
223
+ id="" name="action"><?php echo __( "Cancel", 'xcloner-backup-and-restore' ) ?>
224
+ <i class="material-icons right">close</i>
225
+ </button>
226
+ </div>
227
+ <button class="btn waves-effect waves-light grey" type="submit"
228
+ title="<?php echo __( "Skip Next", 'xcloner-backup-and-restore' ) ?>"
229
+ id="skip_remote_backup_step"
230
+ name="action"><?php echo __( "Skip Next", 'xcloner-backup-and-restore' ) ?>
231
+ <i class="material-icons right">navigate_next</i>
232
+ </button>
233
+ </div>
234
+ </div>
235
+ </li>
236
+
237
+ <li data-step="4" class="restore-remote-database-step steps active">
238
+ <div class="collapsible-header"><i
239
+ class="material-icons">list</i><?php echo __( "Restore Target Database - Search and Replace", 'xcloner-backup-and-restore' ) ?>
240
+ <i class="material-icons right" title="Refresh Database Backup Files List"
241
+ id="refresh_database_file">cached</i>
242
+ </div>
243
+ <div class="collapsible-body row">
244
+
245
+ <div id="remote-restore-options">
246
+ <div class="col s12">
247
+ <a class="btn-floating tooltipped btn-small right" data-position="left" data-delay="50"
248
+ data-html="true"
249
+ data-tooltip="<?php echo __( 'Please provide below the mysql connection details for the target host database.<br />For live sites we recommend using a new separate database.', 'xcloner-backup-and-restore' ) ?>"
250
+ data-tooltip-id="92c95730-94e9-7b59-bd52-14adc30d5e3e"><i class="material-icons">help_outline</i></a>
251
+ <h5><?php echo __( 'Target Mysql Details', 'xcloner-backup-and-restore' ) ?></h5>
252
+ </div>
253
+ <div class=" col s12">
254
+ <div class="input-field col s12 m6">
255
+ <input type="text" name="remote_mysql_host" id="remote_mysql_host" class="validate"
256
+ placeholder="Target Mysql Hostname">
257
+ <label><?php echo __( "Target Mysql Hostname", 'xcloner-backup-and-restore' ) ?></label>
258
+ </div>
259
+
260
+ <div class="input-field col s12 m6">
261
+ <input type="text" name="remote_mysql_db" id="remote_mysql_db" class="validate"
262
+ placeholder="Target Mysql Database">
263
+ <label><?php echo __( "Target Mysql Database", 'xcloner-backup-and-restore' ) ?></label>
264
+ </div>
265
+
266
+ <div class="input-field col s12 m6">
267
+ <input type="text" name="remote_mysql_user" id="remote_mysql_user" class="validate"
268
+ placeholder="Target Mysql Username">
269
+ <label><?php echo __( "Target Mysql Username", 'xcloner-backup-and-restore' ) ?></label>
270
+ </div>
271
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
272
 
273
+ <div class="input-field col s12 m6">
274
+ <input type="text" name="remote_mysql_pass" id="remote_mysql_pass" class="validate"
275
+ placeholder="Target Mysql Password">
276
+ <label><?php echo __( "Target Mysql Password", 'xcloner-backup-and-restore' ) ?></label>
277
+ </div>
278
+
279
+ </div>
280
+ <div class="col s12">
281
+ <a class="btn-floating tooltipped btn-small right" data-position="left" data-delay="50"
282
+ data-html="true"
283
+ data-tooltip="<?php echo __( 'I will attempt to replace all mysql backup records matching the provided Source Url with the provided Target Url. <br />Leave blank the Target Url if you would like to skip this option. <br />As a bonus, I will also replace all matching serialized data and fix it\'s parsing.', 'xcloner-backup-and-restore' ) ?>"
284
+ data-tooltip-id="92c95730-94e9-7b59-bd52-14adc30d5e3e"><i class="material-icons">help_outline</i></a>
285
+ <h5><?php echo __( 'Target Mysql Search and Replace', 'xcloner-backup-and-restore' ) ?></h5>
286
+ </div>
287
+ <div class="col s12">
288
+ <div class="input-field col s12 m6 ">
289
+ <input type="text" name="wp_home_url" id="wp_home_url" class="validate"
290
+ placeholder="WP Home Url" value="<?php echo home_url(); ?>">
291
+ <label><?php echo __( "Source Home Url", 'xcloner-backup-and-restore' ) ?></label>
292
+ </div>
293
+
294
+ <div class="input-field col s12 m6 ">
295
+ <input type="text" name="remote_restore_url" id="remote_restore_url" class="validate"
296
+ placeholder="Restore Target Url">
297
+ <label><?php echo __( "With Target Home Url", 'xcloner-backup-and-restore' ) ?></label>
298
+ </div>
299
+
300
+ <?php if ( site_url() != home_url() ) : ?>
301
+ <div class="input-field col s12 m6 ">
302
+ <input type="text" name="wp_site_url" id="wp_site_url" class="validate"
303
+ placeholder="WP Site Url" value="<?php echo site_url(); ?>">
304
+ <label><?php echo __( "Source Site Url", 'xcloner-backup-and-restore' ) ?></label>
305
+ </div>
306
+
307
+ <div class="input-field col s12 m6 ">
308
+ <input type="text" name="remote_restore_site_url" id="remote_restore_site_url"
309
+ class="validate" placeholder="Restore Target Url">
310
+ <label><?php echo __( "With Target Site Url", 'xcloner-backup-and-restore' ) ?></label>
311
+ </div>
312
+
313
+ <?php endif; ?>
314
+ </div>
315
+
316
+ </div>
317
+
318
+ <div class=" col s12 l7">
319
+ <div class="input-field row">
320
+ <select id="remote_database_file" name="remote_database_file" class="browser-default">
321
+ <option value="" disabled
322
+ selected><?php echo __( "Please select the target database backup file to restore", 'xcloner-backup-and-restore' ) ?></option>
323
+ </select>
324
+
325
+ <label></label>
326
+ </div>
327
+
328
+ <div class="progress">
329
+ <div class="determinate" style="width: 0%"></div>
330
+ </div>
331
+
332
+ <div class="status"></div>
333
+ <div class="query-box">
334
+ <h6><?php echo __( 'Use the field below to fix your mysql query and Retry again the Restore, or replace with # to Skip next', 'xcloner-backup-and-restore' ) ?></h6>
335
+ <textarea class="query-list" cols="5"></textarea>
336
+ </div>
337
+ </div>
338
+
339
+ <div class="col s12 l5 right-align">
340
+ <div class="toggler">
341
+ <button class="btn waves-effect waves-light restore_remote_mysqldump normal " type="submit"
342
+ id="" name="action"><?php echo __( "Restore", 'xcloner-backup-and-restore' ) ?>
343
+ <i class="material-icons left">navigate_before</i>
344
+ </button>
345
+ <button class="btn waves-effect waves-light red restore_remote_mysqldump cancel"
346
+ type="submit" id=""
347
+ name="action"><?php echo __( "Cancel", 'xcloner-backup-and-restore' ) ?>
348
+ <i class="material-icons right">close</i>
349
+ </button>
350
+ </div>
351
+
352
+ <button class="btn waves-effect waves-light grey" type="submit"
353
+ title="<?php echo __( "Skip Next", 'xcloner-backup-and-restore' ) ?>"
354
+ id="skip_restore_remote_database_step"
355
+ name="action"><?php echo __( "Skip Next", 'xcloner-backup-and-restore' ) ?>
356
+ <i class="material-icons right">navigate_next</i>
357
+ </button>
358
+
359
+ </div>
360
+
361
+ </div>
362
+ </li>
363
+
364
+ <li data-step="5" class="restore-finish-step steps active">
365
+ <div class="collapsible-header"><i
366
+ class="material-icons">folder_open</i><?php echo __( "Finishing up...", 'xcloner-backup-and-restore' ) ?>
367
+ </div>
368
+ <div class="collapsible-body row">
369
+
370
+ <div class="row">
371
+ <div class="col s4">
372
+ <label><?php echo __( "Update wp-config.php mysql details and update the Target Site Url", 'xcloner-backup-and-restore' ) ?></label>
373
+ </div>
374
+
375
+ <div class="col s8">
376
+ <div class="switch">
377
+ <label>
378
+ Off
379
+ <input type="checkbox" id="update_remote_site_url" name="update_remote_site_url"
380
+ checked value="1">
381
+ <span class="lever"></span>
382
+ On
383
+ </label>
384
+ </div>
385
+ </div>
386
+ </div>
387
+
388
+ <div class="row">
389
+ <div class="col s4">
390
+ <label><?php echo __( "Delete Restored Backup Temporary Folder", 'xcloner-backup-and-restore' ) ?></label>
391
+ </div>
392
+ <div class="col s8">
393
+ <div class="switch">
394
+ <label>
395
+ Off
396
+ <input type="checkbox" id="delete_backup_temporary_folder"
397
+ name="delete_backup_temporary_folder" checked value="1">
398
+ <span class="lever"></span>
399
+ On
400
+ </label>
401
+ </div>
402
+ </div>
403
+ </div>
404
+
405
+ <div class="row">
406
+ <div class="col s4">
407
+ <label><?php echo __( "Delete Restore Script", 'xcloner-backup-and-restore' ) ?></label>
408
+ </div>
409
+ <div class="col s8">
410
+ <div class="switch">
411
+ <label>
412
+ Off
413
+ <input type="checkbox" id="delete_restore_script" name="delete_restore_script"
414
+ checked value="1">
415
+ <span class="lever"></span>
416
+ On
417
+ </label>
418
+ </div>
419
+ </div>
420
+ </div>
421
+
422
+ <div class=" row col s12">
423
+ <div class="status"></div>
424
+ </div>
425
+
426
+ <div class=" row col s12 center-align" id="xcloner_restore_finish">
427
+ <h5><?php echo __( "Thank you for using XCloner.", 'xcloner-backup-and-restore' ) ?></h5>
428
+ <h6><?php echo sprintf( __( "We would love to hear about your experience in the %s.", 'xcloner-backup-and-restore' ), '<a href="https://wordpress.org/support/plugin/xcloner-backup-and-restore" target="_blank">Wordpress XCloner forums</a>' ) ?></h6>
429
+ <a class="twitter-follow-button" href="https://twitter.com/thinkovi" data-show-count="false">Follow
430
+ @thinkovi</a>
431
+ <script src="//platform.twitter.com/widgets.js" async="" charset="utf-8"></script>
432
+ </div>
433
+
434
+ <div class="col s12 center-align">
435
+ <div class="row">
436
+ <div class="col s6 right-align">
437
+ <button class="btn waves-effect waves-light teal" type="submit" id="restore_finish"
438
+ name="action"><?php echo __( "Finish", 'xcloner-backup-and-restore' ) ?>
439
+ <i class="material-icons right">navigate_next</i>
440
+ </button>
441
+ </div>
442
+
443
+ <div id="open_target_site" class="col s6 left-align">
444
+ <a disabled="disabled" href="#" class="btn waves-effect waves-light teal" type="button"
445
+ target="_blank"><?php echo __( "Open Target Site", 'xcloner-backup-and-restore' ) ?>
446
+ <i class="material-icons right">navigate_next</i>
447
+ </a>
448
+ </div>
449
+ </div>
450
+ </div>
451
+ </div>
452
+ </li>
453
+
454
+ </ul>
455
+ </div>
456
+ </div>
457
 
458
 
459
  <!-- List Backup Content Modal-->
460
  <div id="backup_cotent_modal" class="modal">
461
+ <div class="modal-content">
462
+ <h4><?php echo sprintf( __( "Listing Backup Content ", 'xcloner-backup-and-restore' ), "" ) ?></h4>
463
+ <h5 class="backup-name"></h5>
464
+
465
+ <div class="progress">
466
+ <div class="indeterminate"></div>
467
+ </div>
468
+ <ul class="files-list"></ul>
469
+ </div>
470
  </div>
admin/partials/xcloner_scheduled_backups_page.php CHANGED
@@ -2,192 +2,210 @@
2
  $xcloner_scheduler = $this->get_xcloner_container()->get_xcloner_scheduler();
3
 
4
  $xcloner_remote_storage = $this->get_xcloner_container()->get_xcloner_remote_storage();
5
- $available_storages = $xcloner_remote_storage->get_available_storages();
6
  ?>
7
- <?php if(!defined("DISABLE_WP_CRON") || !DISABLE_WP_CRON): ?>
8
- <div id="setting-error-" class="error settings-error notice is-dismissible">
9
- <p><strong>
10
- <?php echo sprintf(__('We have noticed that DISABLE_WP_CRON is disabled, we recommend enabling that and setting up wp-cron.php to run manually through your hosting account scheduler as explained <a href="%s" target="_blank">here</a>', 'xcloner-backup-and-restore'), "http://www.inmotionhosting.com/support/website/wordpress/disabling-the-wp-cronphp-in-wordpress") ?>
11
- </strong>
12
- </p><button type="button" class="notice-dismiss"><span class="screen-reader-text">Dismiss this notice.</span></button>
13
- </div>
14
- <?php endif?>
 
 
15
 
16
- <h1><?= esc_html(get_admin_page_title()); ?></h1>
17
 
18
  <div class="row">
19
- <table id="scheduled_backups" class="col s12" cellspacing="0" width="100%">
20
  <thead>
21
- <tr class="grey lighten-2">
22
- <th><?php echo __('ID', 'xcloner-backup-and-restore')?></th>
23
- <th><?php echo __('Schedule Name', 'xcloner-backup-and-restore')?></th>
24
- <th><?php echo __('Recurrence', 'xcloner-backup-and-restore')?></th>
25
- <th class="hide-on-med-and-down"><?php echo __('Next Execution', 'xcloner-backup-and-restore')?></th>
26
- <th><?php echo __('Remote Storage', 'xcloner-backup-and-restore')?></th>
27
- <th class="hide-on-med-and-down"><?php echo __('Last Backup', 'xcloner-backup-and-restore')?></th>
28
- <th><?php echo __('Status', 'xcloner-backup-and-restore')?></th>
29
- <th class="no-sort"><?php echo __('Action', 'xcloner-backup-and-restore')?></th>
30
- </tr>
31
  </thead>
32
  <tfoot>
33
- <tr>
34
- <th><?php echo __('ID', 'xcloner-backup-and-restore')?></th>
35
- <th><?php echo __('Schedule Name', 'xcloner-backup-and-restore')?></th>
36
- <th><?php echo __('Recurrence', 'xcloner-backup-and-restore')?></th>
37
- <th class="hide-on-med-and-down"><?php echo __('Next Execution', 'xcloner-backup-and-restore')?></th>
38
- <th><?php echo __('Remote Storage', 'xcloner-backup-and-restore')?></th>
39
- <th class="hide-on-med-and-down"><?php echo __('Last Backup', 'xcloner-backup-and-restore')?></th>
40
- <th><?php echo __('Status', 'xcloner-backup-and-restore')?></th>
41
- <th><?php echo __('Action', 'xcloner-backup-and-restore')?></th>
42
- </tr>
43
  </tfoot>
44
  <tbody>
45
- </tbody>
46
- </table>
47
  </div>
48
 
49
  <div class="row">
50
- <div class="col s12 m6 offset-m6 teal lighten-1" id="server_time">
51
- <h2><?php echo __('Current Server Time', 'xcloner-backup-and-restore')?>: <span class="right"><?php echo current_time('mysql');?></span></h2>
52
- </div>
 
53
  </div>
54
 
55
 
56
  <!-- Modal Structure -->
57
- <div id="edit_schedule" class="modal">
58
- <form method="POST" action="" id="save_schedule">
59
- <input type="hidden" name="id" id="schedule_id_hidden">
60
- <input type="hidden" name="action" value="save_schedule">
61
- <div class="modal-content">
62
-
63
- <div class="row">
64
- <div class="col s12 m6">
65
- <h4><?php echo __('Edit Schedule', 'xcloner-backup-and-restore') ?> #<span id="schedule_id"></span></h4>
66
- </div>
67
-
68
- <div class="col s12 m6 right-align">
69
- <div class="switch">
70
- <label>
71
- <?php echo __('Off', 'xcloner-backup-and-restore') ?>
72
- <input type="checkbox" id="status" name="status" value="1">
73
- <span class="lever"></span>
74
- <?php echo __('On', 'xcloner-backup-and-restore') ?>
75
- </label>
76
- </div>
77
- </div>
78
- </div>
79
-
80
- <p>
81
-
82
- <ul class="nav-tab-wrapper content row">
83
- <li> <a href="#scheduler_settings" class="nav-tab col s12 m6 nav-tab-active"><?php echo __('Scheduler Settings', 'xcloner-backup-and-restore') ?></a></li>
84
- <li> <a href="#advanced_scheduler_settings" class="nav-tab col s12 m6"><?php echo __('Advanced', 'xcloner-backup-and-restore') ?></a></li>
85
- </ul>
86
-
87
- <div class="nav-tab-wrapper-content">
88
- <div id="scheduler_settings" class="tab-content active">
89
-
90
- <div class="row">
91
- <div class="input-field col s12">
92
- <input placeholder="" name="schedule_name" id="schedule_name" type="text" required value="">
93
- <label for="schedule_name"><?php echo __('Schedule Name', 'xcloner-backup-and-restore') ?></label>
94
- </div>
95
- <!--<div class="input-field inline col s12 l6">
 
 
 
 
96
  <select id="backup_type" class="" name="backup_type" id="backup_type">
97
- <option value=""><?php echo __("Full Backup","xcloner-backup-and-restore");?></option>
98
- <option value="diff"><?php echo __("Differential Backups","xcloner-backup-and-restore");?></option>
99
- <option value="full_diff"><?php echo __("Full Backup + Differential Backups","xcloner-backup-and-restore");?></option>
100
  </select>
101
- <label for="backup_type"><?php echo __('Scheduled Backup Type','xcloner-backup-and-restore')?></label>
102
  </div>-->
103
- </div>
104
-
105
- <div class="row">
106
- <div class="input-field col s12 l6">
107
- <input placeholder="" name="schedule_start_date" id="schedule_start_date" type="datetime" value="">
108
- <label for="schedule_start_date" class="active"><?php echo __('Schedule Start At', 'xcloner-backup-and-restore') ?>:</label>
109
- </div>
110
-
111
- <div class="input-field col s12 l6">
112
- <select name="schedule_frequency" id="schedule_frequency" class="validate" required>
113
- <option value="" disabled selected><?php echo __('Schedule Recurrence', 'xcloner-backup-and-restore') ?></option>
114
- <?php
115
- $schedules = $xcloner_scheduler->get_available_intervals();
116
-
117
- foreach($schedules as $key=>$schedule)
118
- {
119
- ?>
120
- <option value="<?php echo $key?>"><?php echo $schedule['display']?></option>
121
- <?php
122
- }
123
- ?>
124
- </select>
125
- </div>
126
- </div>
127
-
128
- <?php if(sizeof($available_storages)):?>
129
- <div class="row">
130
- <div class="input-field col s12 l12">
131
- <select name="schedule_storage" id="schedule_storage" class="validate" >
132
- <option value="" selected><?php echo __('none', 'xcloner-backup-and-restore') ?></option>
133
- <?php foreach($available_storages as $storage=>$text):?>
134
- <option value="<?php echo $storage?>"><?php echo $text?></option>
135
- <?php endforeach?>
136
- </select>
137
- <label><?php echo __('Send To Remote Storage ', 'xcloner-backup-and-restore') ?></label>
138
- </div>
139
- </div>
140
- <?php endif?>
141
-
142
- <div class="row">
143
- <div class="input-field col s12 l12">
144
- <input placeholder="" name="email_notification" id="email_notification" type="text" value="">
145
- <label for="email_notification"><?php echo __('Email Notification Address', 'xcloner-backup-and-restore') ?></label>
146
- </div>
147
- </div>
148
-
149
- <div class="row">
150
- <div class="input-field col s12 l12">
151
- <input placeholder="" name="diff_start_date" id="diff_start_date" type="text" class="datepicker_max_today" value="">
152
- <label for="diff_start_date"><?php echo __('Backup Only Files Modified/Created After', 'xcloner-backup-and-restore') ?></label>
153
- </div>
154
- </div>
155
- </div>
156
-
157
- <div id="advanced_scheduler_settings" class="tab-content">
158
- <div class="row">
159
- <div class="input-field col s12 l12">
160
- <input placeholder="" name="backup_name" id="backup_name" type="text" required value="">
161
- <label for="backup_name"><?php echo __('Backup Name', 'xcloner-backup-and-restore') ?></label>
162
- </div>
163
- </div>
164
-
165
- <div class="row">
166
- <div class="input-field col s12 l12">
167
- <textarea id="table_params" name="table_params" class="materialize-textarea" rows="15"></textarea>
168
- <label for="table_params" class="active"><?php echo __('Included Database Data', 'xcloner-backup-and-restore') ?></label>
169
- </div>
170
- </div>
171
-
172
- <div class="row">
173
- <div class="input-field col s12 l12">
174
- <textarea id="excluded_files" name="excluded_files" class="materialize-textarea" rows="15"></textarea>
175
- <label for="excluded_files" class="active"><?php echo __('Excluded Files', 'xcloner-backup-and-restore') ?></label>
176
- </div>
177
- </div>
178
- </div>
179
- </div>
180
-
181
- <div class="row">
182
-
183
- <div class="input-field col s12 ">
184
- <button class="right btn waves-effect waves-light" type="submit" name="action"><?php echo __('Save', 'xcloner-backup-and-restore') ?>
185
- <i class="material-icons right">send</i>
186
- </button>
187
- </div>
188
- </div>
189
- </p>
190
- </div>
 
 
 
 
 
 
 
 
 
 
 
191
  </form>
192
  </div>
193
 
2
  $xcloner_scheduler = $this->get_xcloner_container()->get_xcloner_scheduler();
3
 
4
  $xcloner_remote_storage = $this->get_xcloner_container()->get_xcloner_remote_storage();
5
+ $available_storages = $xcloner_remote_storage->get_available_storages();
6
  ?>
7
+ <?php if ( ! defined( "DISABLE_WP_CRON" ) || ! DISABLE_WP_CRON ): ?>
8
+ <div id="setting-error-" class="error settings-error notice is-dismissible">
9
+ <p><strong>
10
+ <?php echo sprintf( __( 'We have noticed that DISABLE_WP_CRON is disabled, we recommend enabling that and setting up wp-cron.php to run manually through your hosting account scheduler as explained <a href="%s" target="_blank">here</a>', 'xcloner-backup-and-restore' ), "http://www.inmotionhosting.com/support/website/wordpress/disabling-the-wp-cronphp-in-wordpress" ) ?>
11
+ </strong>
12
+ </p>
13
+ <button type="button" class="notice-dismiss"><span class="screen-reader-text">Dismiss this notice.</span>
14
+ </button>
15
+ </div>
16
+ <?php endif ?>
17
 
18
+ <h1><?= esc_html( get_admin_page_title() ); ?></h1>
19
 
20
  <div class="row">
21
+ <table id="scheduled_backups" class="col s12" cellspacing="0" width="100%">
22
  <thead>
23
+ <tr class="grey lighten-2">
24
+ <th><?php echo __( 'ID', 'xcloner-backup-and-restore' ) ?></th>
25
+ <th><?php echo __( 'Schedule Name', 'xcloner-backup-and-restore' ) ?></th>
26
+ <th><?php echo __( 'Recurrence', 'xcloner-backup-and-restore' ) ?></th>
27
+ <th class="hide-on-med-and-down"><?php echo __( 'Next Execution', 'xcloner-backup-and-restore' ) ?></th>
28
+ <th><?php echo __( 'Remote Storage', 'xcloner-backup-and-restore' ) ?></th>
29
+ <th class="hide-on-med-and-down"><?php echo __( 'Last Backup', 'xcloner-backup-and-restore' ) ?></th>
30
+ <th><?php echo __( 'Status', 'xcloner-backup-and-restore' ) ?></th>
31
+ <th class="no-sort"><?php echo __( 'Action', 'xcloner-backup-and-restore' ) ?></th>
32
+ </tr>
33
  </thead>
34
  <tfoot>
35
+ <tr>
36
+ <th><?php echo __( 'ID', 'xcloner-backup-and-restore' ) ?></th>
37
+ <th><?php echo __( 'Schedule Name', 'xcloner-backup-and-restore' ) ?></th>
38
+ <th><?php echo __( 'Recurrence', 'xcloner-backup-and-restore' ) ?></th>
39
+ <th class="hide-on-med-and-down"><?php echo __( 'Next Execution', 'xcloner-backup-and-restore' ) ?></th>
40
+ <th><?php echo __( 'Remote Storage', 'xcloner-backup-and-restore' ) ?></th>
41
+ <th class="hide-on-med-and-down"><?php echo __( 'Last Backup', 'xcloner-backup-and-restore' ) ?></th>
42
+ <th><?php echo __( 'Status', 'xcloner-backup-and-restore' ) ?></th>
43
+ <th><?php echo __( 'Action', 'xcloner-backup-and-restore' ) ?></th>
44
+ </tr>
45
  </tfoot>
46
  <tbody>
47
+ </tbody>
48
+ </table>
49
  </div>
50
 
51
  <div class="row">
52
+ <div class="col s12 m6 offset-m6 teal lighten-1" id="server_time">
53
+ <h2><?php echo __( 'Current Server Time', 'xcloner-backup-and-restore' ) ?>: <span
54
+ class="right"><?php echo current_time( 'mysql' ); ?></span></h2>
55
+ </div>
56
  </div>
57
 
58
 
59
  <!-- Modal Structure -->
60
+ <div id="edit_schedule" class="modal">
61
+ <form method="POST" action="" id="save_schedule">
62
+ <input type="hidden" name="id" id="schedule_id_hidden">
63
+ <input type="hidden" name="action" value="save_schedule">
64
+ <div class="modal-content">
65
+
66
+ <div class="row">
67
+ <div class="col s12 m6">
68
+ <h4><?php echo __( 'Edit Schedule', 'xcloner-backup-and-restore' ) ?> #<span
69
+ id="schedule_id"></span></h4>
70
+ </div>
71
+
72
+ <div class="col s12 m6 right-align">
73
+ <div class="switch">
74
+ <label>
75
+ <?php echo __( 'Off', 'xcloner-backup-and-restore' ) ?>
76
+ <input type="checkbox" id="status" name="status" value="1">
77
+ <span class="lever"></span>
78
+ <?php echo __( 'On', 'xcloner-backup-and-restore' ) ?>
79
+ </label>
80
+ </div>
81
+ </div>
82
+ </div>
83
+
84
+ <p>
85
+
86
+ <ul class="nav-tab-wrapper content row">
87
+ <li><a href="#scheduler_settings"
88
+ class="nav-tab col s12 m6 nav-tab-active"><?php echo __( 'Scheduler Settings', 'xcloner-backup-and-restore' ) ?></a>
89
+ </li>
90
+ <li><a href="#advanced_scheduler_settings"
91
+ class="nav-tab col s12 m6"><?php echo __( 'Advanced', 'xcloner-backup-and-restore' ) ?></a></li>
92
+ </ul>
93
+
94
+ <div class="nav-tab-wrapper-content">
95
+ <div id="scheduler_settings" class="tab-content active">
96
+
97
+ <div class="row">
98
+ <div class="input-field col s12">
99
+ <input placeholder="" name="schedule_name" id="schedule_name" type="text" required value="">
100
+ <label for="schedule_name"><?php echo __( 'Schedule Name', 'xcloner-backup-and-restore' ) ?></label>
101
+ </div>
102
+ <!--<div class="input-field inline col s12 l6">
103
  <select id="backup_type" class="" name="backup_type" id="backup_type">
104
+ <option value=""><?php echo __( "Full Backup", "xcloner-backup-and-restore" ); ?></option>
105
+ <option value="diff"><?php echo __( "Differential Backups", "xcloner-backup-and-restore" ); ?></option>
106
+ <option value="full_diff"><?php echo __( "Full Backup + Differential Backups", "xcloner-backup-and-restore" ); ?></option>
107
  </select>
108
+ <label for="backup_type"><?php echo __( 'Scheduled Backup Type', 'xcloner-backup-and-restore' ) ?></label>
109
  </div>-->
110
+ </div>
111
+
112
+ <div class="row">
113
+ <div class="input-field col s12 l6">
114
+ <input placeholder="" name="schedule_start_date" id="schedule_start_date" type="datetime"
115
+ value="">
116
+ <label for="schedule_start_date"
117
+ class="active"><?php echo __( 'Schedule Start At', 'xcloner-backup-and-restore' ) ?>
118
+ :</label>
119
+ </div>
120
+
121
+ <div class="input-field col s12 l6">
122
+ <select name="schedule_frequency" id="schedule_frequency" class="validate" required>
123
+ <option value="" disabled
124
+ selected><?php echo __( 'Schedule Recurrence', 'xcloner-backup-and-restore' ) ?></option>
125
+ <?php
126
+ $schedules = $xcloner_scheduler->get_available_intervals();
127
+
128
+ foreach ( $schedules as $key => $schedule ) {
129
+ ?>
130
+ <option value="<?php echo $key ?>"><?php echo $schedule['display'] ?></option>
131
+ <?php
132
+ }
133
+ ?>
134
+ </select>
135
+ </div>
136
+ </div>
137
+
138
+ <?php if ( sizeof( $available_storages ) ): ?>
139
+ <div class="row">
140
+ <div class="input-field col s12 l12">
141
+ <select name="schedule_storage" id="schedule_storage" class="validate">
142
+ <option value=""
143
+ selected><?php echo __( 'none', 'xcloner-backup-and-restore' ) ?></option>
144
+ <?php foreach ( $available_storages as $storage => $text ): ?>
145
+ <option value="<?php echo $storage ?>"><?php echo $text ?></option>
146
+ <?php endforeach ?>
147
+ </select>
148
+ <label><?php echo __( 'Send To Remote Storage ', 'xcloner-backup-and-restore' ) ?></label>
149
+ </div>
150
+ </div>
151
+ <?php endif ?>
152
+
153
+ <div class="row">
154
+ <div class="input-field col s12 l12">
155
+ <input placeholder="" name="email_notification" id="email_notification" type="text"
156
+ value="">
157
+ <label for="email_notification"><?php echo __( 'Email Notification Address', 'xcloner-backup-and-restore' ) ?></label>
158
+ </div>
159
+ </div>
160
+
161
+ <div class="row">
162
+ <div class="input-field col s12 l12">
163
+ <input placeholder="" name="diff_start_date" id="diff_start_date" type="text"
164
+ class="datepicker_max_today" value="">
165
+ <label for="diff_start_date"><?php echo __( 'Backup Only Files Modified/Created After', 'xcloner-backup-and-restore' ) ?></label>
166
+ </div>
167
+ </div>
168
+ </div>
169
+
170
+ <div id="advanced_scheduler_settings" class="tab-content">
171
+ <div class="row">
172
+ <div class="input-field col s12 l12">
173
+ <input placeholder="" name="backup_name" id="backup_name" type="text" required value="">
174
+ <label for="backup_name"><?php echo __( 'Backup Name', 'xcloner-backup-and-restore' ) ?></label>
175
+ </div>
176
+ </div>
177
+
178
+ <div class="row">
179
+ <div class="input-field col s12 l12">
180
+ <textarea id="table_params" name="table_params" class="materialize-textarea"
181
+ rows="15"></textarea>
182
+ <label for="table_params"
183
+ class="active"><?php echo __( 'Included Database Data', 'xcloner-backup-and-restore' ) ?></label>
184
+ </div>
185
+ </div>
186
+
187
+ <div class="row">
188
+ <div class="input-field col s12 l12">
189
+ <textarea id="excluded_files" name="excluded_files" class="materialize-textarea"
190
+ rows="15"></textarea>
191
+ <label for="excluded_files"
192
+ class="active"><?php echo __( 'Excluded Files', 'xcloner-backup-and-restore' ) ?></label>
193
+ </div>
194
+ </div>
195
+ </div>
196
+ </div>
197
+
198
+ <div class="row">
199
+
200
+ <div class="input-field col s12 ">
201
+ <button class="right btn waves-effect waves-light" type="submit"
202
+ name="action"><?php echo __( 'Save', 'xcloner-backup-and-restore' ) ?>
203
+ <i class="material-icons right">send</i>
204
+ </button>
205
+ </div>
206
+ </div>
207
+ </p>
208
+ </div>
209
  </form>
210
  </div>
211
 
composer.json CHANGED
@@ -9,7 +9,8 @@
9
  "league/flysystem-aws-s3-v3": "^1.0",
10
  "mhetreramesh/flysystem-backblaze": "^1.0",
11
  "league/flysystem-webdav": "^1.0",
12
- "srmklive/flysystem-dropbox-v2": "^1.0"
 
13
  },
14
  "prefer-stable": true
15
  }
9
  "league/flysystem-aws-s3-v3": "^1.0",
10
  "mhetreramesh/flysystem-backblaze": "^1.0",
11
  "league/flysystem-webdav": "^1.0",
12
+ "srmklive/flysystem-dropbox-v2": "^1.0",
13
+ "defuse/php-encryption": "^2.2"
14
  },
15
  "prefer-stable": true
16
  }
composer.lock CHANGED
@@ -1,10 +1,10 @@
1
  {
2
  "_readme": [
3
  "This file locks the dependencies of your project to a known state",
4
- "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
5
  "This file is @generated automatically"
6
  ],
7
- "content-hash": "34877d7a256d21b0272185812cd42e48",
8
  "packages": [
9
  {
10
  "name": "aws/aws-sdk-php",
@@ -129,30 +129,35 @@
129
  "time": "2018-03-04T13:23:48+00:00"
130
  },
131
  {
132
- "name": "cwhite92/b2-sdk-php",
133
- "version": "v1.3.0",
134
  "source": {
135
  "type": "git",
136
- "url": "https://github.com/cwhite92/b2-sdk-php.git",
137
- "reference": "68c054af3c857f08506e9ee9f3c017972cb6bee8"
138
  },
139
  "dist": {
140
  "type": "zip",
141
- "url": "https://api.github.com/repos/cwhite92/b2-sdk-php/zipball/68c054af3c857f08506e9ee9f3c017972cb6bee8",
142
- "reference": "68c054af3c857f08506e9ee9f3c017972cb6bee8",
143
  "shasum": ""
144
  },
145
  "require": {
146
- "guzzlehttp/guzzle": "^6.1",
147
- "php": ">=5.5.0"
 
148
  },
149
  "require-dev": {
150
- "phpunit/phpunit": "4.8.*"
 
151
  },
 
 
 
152
  "type": "library",
153
  "autoload": {
154
  "psr-4": {
155
- "ChrisWhite\\B2\\": "src/"
156
  }
157
  },
158
  "notification-url": "https://packagist.org/downloads/",
@@ -161,35 +166,43 @@
161
  ],
162
  "authors": [
163
  {
164
- "name": "Chris White",
165
- "email": "chris@cwhite.me",
166
- "homepage": "https://cwhite.me"
 
 
 
 
 
167
  }
168
  ],
169
- "description": "A SDK for working with B2 cloud storage.",
170
- "homepage": "https://github.com/cwhite92/b2-sdk-php",
171
  "keywords": [
172
- "b2",
173
- "backblaze",
174
- "backup",
175
- "cloud",
176
- "filesystem",
177
- "storage"
 
 
 
 
178
  ],
179
- "time": "2016-08-24T13:31:19+00:00"
180
  },
181
  {
182
  "name": "gliterd/backblaze-b2",
183
- "version": "0.0.3",
184
  "source": {
185
  "type": "git",
186
  "url": "https://github.com/gliterd/backblaze-b2.git",
187
- "reference": "eeaedb198fe10e0fb7d94ffaa9aa6ab207d7e9c6"
188
  },
189
  "dist": {
190
  "type": "zip",
191
- "url": "https://api.github.com/repos/gliterd/backblaze-b2/zipball/eeaedb198fe10e0fb7d94ffaa9aa6ab207d7e9c6",
192
- "reference": "eeaedb198fe10e0fb7d94ffaa9aa6ab207d7e9c6",
193
  "shasum": ""
194
  },
195
  "require": {
@@ -197,7 +210,9 @@
197
  "php": ">=5.5.0"
198
  },
199
  "require-dev": {
200
- "phpunit/phpunit": "4.8.*"
 
 
201
  },
202
  "type": "library",
203
  "autoload": {
@@ -228,7 +243,7 @@
228
  "filesystem",
229
  "storage"
230
  ],
231
- "time": "2017-08-09T13:57:57+00:00"
232
  },
233
  {
234
  "name": "guzzlehttp/guzzle",
@@ -587,6 +602,7 @@
587
  }
588
  ],
589
  "description": "Flysystem adapter for Windows Azure",
 
590
  "time": "2016-07-10T19:08:39+00:00"
591
  },
592
  {
@@ -685,24 +701,24 @@
685
  },
686
  {
687
  "name": "mhetreramesh/flysystem-backblaze",
688
- "version": "1.0.10",
689
  "source": {
690
  "type": "git",
691
  "url": "https://github.com/gliterd/flysystem-backblaze.git",
692
- "reference": "3f753cbce283edc9774a62c10690699533a7b86e"
693
  },
694
  "dist": {
695
  "type": "zip",
696
- "url": "https://api.github.com/repos/gliterd/flysystem-backblaze/zipball/3f753cbce283edc9774a62c10690699533a7b86e",
697
- "reference": "3f753cbce283edc9774a62c10690699533a7b86e",
698
  "shasum": ""
699
  },
700
  "require": {
701
- "cwhite92/b2-sdk-php": "^1.2",
702
  "gliterd/backblaze-b2": "*",
703
  "league/flysystem": "~1.0",
704
  "mikey179/vfsstream": "*",
705
- "php": ">=5.5.0"
 
706
  },
707
  "require-dev": {
708
  "phpunit/phpunit": "~4.0||~5.0",
@@ -736,7 +752,7 @@
736
  "client",
737
  "filesystem"
738
  ],
739
- "time": "2017-12-20T16:10:51+00:00"
740
  },
741
  {
742
  "name": "microsoft/azure-storage",
@@ -976,6 +992,55 @@
976
  ],
977
  "time": "2016-12-03T22:08:25+00:00"
978
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
979
  {
980
  "name": "phpseclib/phpseclib",
981
  "version": "2.0.11",
1
  {
2
  "_readme": [
3
  "This file locks the dependencies of your project to a known state",
4
+ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
5
  "This file is @generated automatically"
6
  ],
7
+ "content-hash": "920a4f6a39e43da5eab4ff35b172d146",
8
  "packages": [
9
  {
10
  "name": "aws/aws-sdk-php",
129
  "time": "2018-03-04T13:23:48+00:00"
130
  },
131
  {
132
+ "name": "defuse/php-encryption",
133
+ "version": "v2.2.0",
134
  "source": {
135
  "type": "git",
136
+ "url": "https://github.com/defuse/php-encryption.git",
137
+ "reference": "0d4d27c368ca6798bc162469e43248c363c73495"
138
  },
139
  "dist": {
140
  "type": "zip",
141
+ "url": "https://api.github.com/repos/defuse/php-encryption/zipball/0d4d27c368ca6798bc162469e43248c363c73495",
142
+ "reference": "0d4d27c368ca6798bc162469e43248c363c73495",
143
  "shasum": ""
144
  },
145
  "require": {
146
+ "ext-openssl": "*",
147
+ "paragonie/random_compat": "~2.0",
148
+ "php": ">=5.4.0"
149
  },
150
  "require-dev": {
151
+ "nikic/php-parser": "^2.0|^3.0|^4.0",
152
+ "phpunit/phpunit": "^4|^5"
153
  },
154
+ "bin": [
155
+ "bin/generate-defuse-key"
156
+ ],
157
  "type": "library",
158
  "autoload": {
159
  "psr-4": {
160
+ "Defuse\\Crypto\\": "src"
161
  }
162
  },
163
  "notification-url": "https://packagist.org/downloads/",
166
  ],
167
  "authors": [
168
  {
169
+ "name": "Taylor Hornby",
170
+ "email": "taylor@defuse.ca",
171
+ "homepage": "https://defuse.ca/"
172
+ },
173
+ {
174
+ "name": "Scott Arciszewski",
175
+ "email": "info@paragonie.com",
176
+ "homepage": "https://paragonie.com"
177
  }
178
  ],
179
+ "description": "Secure PHP Encryption Library",
 
180
  "keywords": [
181
+ "aes",
182
+ "authenticated encryption",
183
+ "cipher",
184
+ "crypto",
185
+ "cryptography",
186
+ "encrypt",
187
+ "encryption",
188
+ "openssl",
189
+ "security",
190
+ "symmetric key cryptography"
191
  ],
192
+ "time": "2018-04-23T19:33:40+00:00"
193
  },
194
  {
195
  "name": "gliterd/backblaze-b2",
196
+ "version": "1.0.4",
197
  "source": {
198
  "type": "git",
199
  "url": "https://github.com/gliterd/backblaze-b2.git",
200
+ "reference": "5427b10b93b0ba24f06f80623b502c7d1d7fcd72"
201
  },
202
  "dist": {
203
  "type": "zip",
204
+ "url": "https://api.github.com/repos/gliterd/backblaze-b2/zipball/5427b10b93b0ba24f06f80623b502c7d1d7fcd72",
205
+ "reference": "5427b10b93b0ba24f06f80623b502c7d1d7fcd72",
206
  "shasum": ""
207
  },
208
  "require": {
210
  "php": ">=5.5.0"
211
  },
212
  "require-dev": {
213
+ "phpunit/phpunit": "4.8.*",
214
+ "scrutinizer/ocular": "~1.1",
215
+ "squizlabs/php_codesniffer": "~2.3"
216
  },
217
  "type": "library",
218
  "autoload": {
243
  "filesystem",
244
  "storage"
245
  ],
246
+ "time": "2018-07-03T11:52:32+00:00"
247
  },
248
  {
249
  "name": "guzzlehttp/guzzle",
602
  }
603
  ],
604
  "description": "Flysystem adapter for Windows Azure",
605
+ "abandoned": "league/flysystem-azure-blob-storage",
606
  "time": "2016-07-10T19:08:39+00:00"
607
  },
608
  {
701
  },
702
  {
703
  "name": "mhetreramesh/flysystem-backblaze",
704
+ "version": "1.1.4",
705
  "source": {
706
  "type": "git",
707
  "url": "https://github.com/gliterd/flysystem-backblaze.git",
708
+ "reference": "bce0372dfe40baa1e16b54e93c3400a568059070"
709
  },
710
  "dist": {
711
  "type": "zip",
712
+ "url": "https://api.github.com/repos/gliterd/flysystem-backblaze/zipball/bce0372dfe40baa1e16b54e93c3400a568059070",
713
+ "reference": "bce0372dfe40baa1e16b54e93c3400a568059070",
714
  "shasum": ""
715
  },
716
  "require": {
 
717
  "gliterd/backblaze-b2": "*",
718
  "league/flysystem": "~1.0",
719
  "mikey179/vfsstream": "*",
720
+ "php": ">=5.6.0",
721
+ "psr/http-message-implementation": "*"
722
  },
723
  "require-dev": {
724
  "phpunit/phpunit": "~4.0||~5.0",
752
  "client",
753
  "filesystem"
754
  ],
755
+ "time": "2018-06-29T12:06:41+00:00"
756
  },
757
  {
758
  "name": "microsoft/azure-storage",
992
  ],
993
  "time": "2016-12-03T22:08:25+00:00"
994
  },
995
+ {
996
+ "name": "paragonie/random_compat",
997
+ "version": "v2.0.15",
998
+ "source": {
999
+ "type": "git",
1000
+ "url": "https://github.com/paragonie/random_compat.git",
1001
+ "reference": "10bcb46e8f3d365170f6de9d05245aa066b81f09"
1002
+ },
1003
+ "dist": {
1004
+ "type": "zip",
1005
+ "url": "https://api.github.com/repos/paragonie/random_compat/zipball/10bcb46e8f3d365170f6de9d05245aa066b81f09",
1006
+ "reference": "10bcb46e8f3d365170f6de9d05245aa066b81f09",
1007
+ "shasum": ""
1008
+ },
1009
+ "require": {
1010
+ "php": ">=5.2.0"
1011
+ },
1012
+ "require-dev": {
1013
+ "phpunit/phpunit": "4.*|5.*"
1014
+ },
1015
+ "suggest": {
1016
+ "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
1017
+ },
1018
+ "type": "library",
1019
+ "autoload": {
1020
+ "files": [
1021
+ "lib/random.php"
1022
+ ]
1023
+ },
1024
+ "notification-url": "https://packagist.org/downloads/",
1025
+ "license": [
1026
+ "MIT"
1027
+ ],
1028
+ "authors": [
1029
+ {
1030
+ "name": "Paragon Initiative Enterprises",
1031
+ "email": "security@paragonie.com",
1032
+ "homepage": "https://paragonie.com"
1033
+ }
1034
+ ],
1035
+ "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
1036
+ "keywords": [
1037
+ "csprng",
1038
+ "polyfill",
1039
+ "pseudorandom",
1040
+ "random"
1041
+ ],
1042
+ "time": "2018-06-08T15:26:40+00:00"
1043
+ },
1044
  {
1045
  "name": "phpseclib/phpseclib",
1046
  "version": "2.0.11",
includes/class-xcloner-activator.php CHANGED
@@ -1,13 +1,29 @@
1
  <?php
2
-
3
  /**
4
- * Fired during plugin activation
5
  *
6
- * @link http://www.thinkovi.com
7
- * @since 1.0.0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  *
9
- * @package Xcloner
10
- * @subpackage Xcloner/includes
11
  */
12
 
13
  /**
@@ -19,38 +35,48 @@
19
  * @package Xcloner
20
  * @subpackage Xcloner/includes
21
  * @author Liuta Ovidiu <info@thinkovi.com>
 
22
  */
23
  class Xcloner_Activator {
24
 
 
 
 
 
25
  const xcloner_db_version = '1.1.7';
 
 
 
 
26
  const xcloner_minimum_version = '5.6.0';
 
27
  /**
28
- * Short Description. (use period)
29
  *
30
- * Long Description.
31
  *
32
  * @since 1.0.0
33
  */
34
  public static function activate() {
35
-
36
  global $wpdb;
37
-
38
- if(version_compare(phpversion(), Xcloner_Activator::xcloner_minimum_version, '<'))
39
- {
40
- wp_die('<p>'.sprintf(__("XCloner requires minimum PHP version %s in order to run correctly. We have detected your version as %s"),Xcloner_Activator::xcloner_minimum_version, phpversion()).'</p>', __("XCloner Activation Error"), array( 'response'=>500, 'back_link'=>TRUE ) );
 
41
  }
42
-
43
- $charset_collate = $wpdb->get_charset_collate();
44
-
45
  $installed_ver = get_option( "xcloner_db_version" );
46
-
47
  $xcloner_db_version = Xcloner_Activator::xcloner_db_version;
48
-
49
  $xcloner_scheduler_table = $wpdb->prefix . "xcloner_scheduler";
50
-
51
- if($installed_ver != $xcloner_db_version)
52
- {
53
- $xcloner_schedule_sql="CREATE TABLE `".$xcloner_scheduler_table."` (
54
  `id` int(11) NOT NULL AUTO_INCREMENT,
55
  `name` varchar(255) NOT NULL,
56
  `recurrence` varchar(25) NOT NULL,
@@ -61,58 +87,71 @@ class Xcloner_Activator {
61
  `status` int(1) NOT NULL,
62
  `last_backup` varchar(100) DEFAULT NULL,
63
  PRIMARY KEY (`id`)
64
- ) ".$charset_collate.";
65
  ";
66
-
67
  require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
68
  dbDelta( $xcloner_schedule_sql );
69
-
70
  update_option( "xcloner_db_version", $xcloner_db_version );
71
  }
72
-
73
- if(get_option('xcloner_backup_compression_level') === false)
74
- update_option('xcloner_backup_compression_level', 0);
75
-
76
- if(get_option('xcloner_enable_log') === false)
77
- update_option('xcloner_enable_log', 1);
78
-
79
- if(get_option('xcloner_enable_mysql_backup') === false)
80
- update_option('xcloner_enable_mysql_backup', 1);
81
-
82
- if(get_option('xcloner_system_settings_page') === false)
83
- update_option('xcloner_system_settings_page', 100);
84
-
85
- if(get_option('xcloner_files_to_process_per_request') === false)
86
- update_option('xcloner_files_to_process_per_request', 250);
87
-
88
- if(get_option('xcloner_database_records_per_request') === false)
89
- update_option('xcloner_database_records_per_request', 10000);
90
-
91
- if(get_option('xcloner_exclude_files_larger_than_mb') === false)
92
- update_option('xcloner_exclude_files_larger_than_mb', 0);
93
-
94
- if(get_option('xcloner_split_backup_limit') === false)
95
- update_option('xcloner_split_backup_limit', 2048);
96
-
97
- if(get_option('xcloner_size_limit_per_request') === false)
98
- update_option('xcloner_size_limit_per_request', 50);
99
-
100
- if(get_option('xcloner_cleanup_retention_limit_days') === false)
101
- update_option('xcloner_cleanup_retention_limit_days', 60);
102
-
103
- if(get_option('xcloner_cleanup_retention_limit_archives') === false)
104
- update_option('xcloner_cleanup_retention_limit_archives', 100);
105
-
106
- if(get_option('xcloner_directories_to_scan_per_request') === false)
107
- update_option('xcloner_directories_to_scan_per_request', 25);
108
-
 
 
 
 
 
 
 
 
 
 
 
 
109
  /*if(!get_option('xcloner_diff_backup_recreate_period'))
110
  update_option('xcloner_diff_backup_recreate_period', 10);
111
  * */
112
-
113
- if(!get_option('xcloner_regex_exclude'))
114
- update_option('xcloner_regex_exclude', "(wp-content\/updraft|wp-content\/uploads\/wp_all_backup)(.*)$".PHP_EOL."(.*)\.(svn|git)(.*)$".PHP_EOL."wp-content\/cache(.*)$".PHP_EOL."(.*)error_log$");
 
115
 
116
  }
117
-
118
  }
1
  <?php
 
2
  /**
3
+ * XCloner - Backup and Restore backup plugin for Wordpress
4
  *
5
+ * class-xcloner-activator.php
6
+ * @author Liuta Ovidiu <info@thinkovi.com>
7
+ *
8
+ * This program is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation; either version 2 of the License, or
11
+ * (at your option) any later version.
12
+ *
13
+ * This program is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ * GNU General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU General Public License
19
+ * along with this program; if not, write to the Free Software
20
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21
+ * MA 02110-1301, USA.
22
+ *
23
+ * @link https://github.com/ovidiul/XCloner-Wordpress
24
+ *
25
+ * @modified 7/31/18 3:28 PM
26
  *
 
 
27
  */
28
 
29
  /**
35
  * @package Xcloner
36
  * @subpackage Xcloner/includes
37
  * @author Liuta Ovidiu <info@thinkovi.com>
38
+ * @link http://www.thinkovi.com
39
  */
40
  class Xcloner_Activator {
41
 
42
+ /**
43
+ * XCloner Database Version
44
+ * @var string
45
+ */
46
  const xcloner_db_version = '1.1.7';
47
+ /**
48
+ * Minimum required PHP version to run this plugin.
49
+ * @var string
50
+ */
51
  const xcloner_minimum_version = '5.6.0';
52
+
53
  /**
54
+ * Triggered when XCloner is activated.
55
  *
56
+ * This method will get trigger once XCloner plugin is activated.
57
  *
58
  * @since 1.0.0
59
  */
60
  public static function activate() {
61
+
62
  global $wpdb;
63
+
64
+ if ( version_compare( phpversion(), Xcloner_Activator::xcloner_minimum_version, '<' ) ) {
65
+ wp_die( '<p>' . sprintf( __( "XCloner requires minimum PHP version %s in order to run correctly. We have detected your version as %s" ), Xcloner_Activator::xcloner_minimum_version, phpversion() ) . '</p>', __( "XCloner Activation Error" ), array( 'response' => 500,
66
+ 'back_link' => true
67
+ ) );
68
  }
69
+
70
+ $charset_collate = $wpdb->get_charset_collate();
71
+
72
  $installed_ver = get_option( "xcloner_db_version" );
73
+
74
  $xcloner_db_version = Xcloner_Activator::xcloner_db_version;
75
+
76
  $xcloner_scheduler_table = $wpdb->prefix . "xcloner_scheduler";
77
+
78
+ if ( $installed_ver != $xcloner_db_version ) {
79
+ $xcloner_schedule_sql = "CREATE TABLE `" . $xcloner_scheduler_table . "` (
 
80
  `id` int(11) NOT NULL AUTO_INCREMENT,
81
  `name` varchar(255) NOT NULL,
82
  `recurrence` varchar(25) NOT NULL,
87
  `status` int(1) NOT NULL,
88
  `last_backup` varchar(100) DEFAULT NULL,
89
  PRIMARY KEY (`id`)
90
+ ) " . $charset_collate . ";
91
  ";
92
+
93
  require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
94
  dbDelta( $xcloner_schedule_sql );
95
+
96
  update_option( "xcloner_db_version", $xcloner_db_version );
97
  }
98
+
99
+ if ( get_option( 'xcloner_backup_compression_level' ) === false ) {
100
+ update_option( 'xcloner_backup_compression_level', 0 );
101
+ }
102
+
103
+ if ( get_option( 'xcloner_enable_log' ) === false ) {
104
+ update_option( 'xcloner_enable_log', 1 );
105
+ }
106
+
107
+ if ( get_option( 'xcloner_enable_mysql_backup' ) === false ) {
108
+ update_option( 'xcloner_enable_mysql_backup', 1 );
109
+ }
110
+
111
+ if ( get_option( 'xcloner_system_settings_page' ) === false ) {
112
+ update_option( 'xcloner_system_settings_page', 100 );
113
+ }
114
+
115
+ if ( get_option( 'xcloner_files_to_process_per_request' ) === false ) {
116
+ update_option( 'xcloner_files_to_process_per_request', 250 );
117
+ }
118
+
119
+ if ( get_option( 'xcloner_database_records_per_request' ) === false ) {
120
+ update_option( 'xcloner_database_records_per_request', 10000 );
121
+ }
122
+
123
+ if ( get_option( 'xcloner_exclude_files_larger_than_mb' ) === false ) {
124
+ update_option( 'xcloner_exclude_files_larger_than_mb', 0 );
125
+ }
126
+
127
+ if ( get_option( 'xcloner_split_backup_limit' ) === false ) {
128
+ update_option( 'xcloner_split_backup_limit', 2048 );
129
+ }
130
+
131
+ if ( get_option( 'xcloner_size_limit_per_request' ) === false ) {
132
+ update_option( 'xcloner_size_limit_per_request', 50 );
133
+ }
134
+
135
+ if ( get_option( 'xcloner_cleanup_retention_limit_days' ) === false ) {
136
+ update_option( 'xcloner_cleanup_retention_limit_days', 60 );
137
+ }
138
+
139
+ if ( get_option( 'xcloner_cleanup_retention_limit_archives' ) === false ) {
140
+ update_option( 'xcloner_cleanup_retention_limit_archives', 100 );
141
+ }
142
+
143
+ if ( get_option( 'xcloner_directories_to_scan_per_request' ) === false ) {
144
+ update_option( 'xcloner_directories_to_scan_per_request', 25 );
145
+ }
146
+
147
  /*if(!get_option('xcloner_diff_backup_recreate_period'))
148
  update_option('xcloner_diff_backup_recreate_period', 10);
149
  * */
150
+
151
+ if ( ! get_option( 'xcloner_regex_exclude' ) ) {
152
+ update_option( 'xcloner_regex_exclude', "(wp-content\/updraft|wp-content\/uploads\/wp_all_backup)(.*)$" . PHP_EOL . "(.*)\.(svn|git)(.*)$" . PHP_EOL . "wp-content\/cache(.*)$" . PHP_EOL . "(.*)error_log$" );
153
+ }
154
 
155
  }
156
+
157
  }
includes/class-xcloner-api.php CHANGED
@@ -1,4 +1,30 @@
1
  <?php
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
 
3
  use League\Flysystem\Config;
4
  use League\Flysystem\Filesystem;
@@ -11,1062 +37,1098 @@ use splitbrain\PHPArchive\Archive;
11
  use splitbrain\PHPArchive\FileInfo;
12
 
13
 
14
- class Xcloner_Api{
15
-
16
- private $xcloner_database;
17
- private $xcloner_settings;
18
- private $xcloner_file_system;
19
- private $xcloner_requirements;
20
- private $xcloner_sanitization;
21
- private $archive_system;
22
- private $form_params;
23
- private $logger;
24
- private $xcloner_container;
25
-
26
- public function __construct(Xcloner $xcloner_container)
27
- {
28
- global $wpdb;
29
-
30
- if(WP_DEBUG)
31
- {
32
- error_reporting(0);
33
- }
34
-
35
- if( ob_get_length() )
36
- ob_end_clean();
37
- ob_start();
38
-
39
- $wpdb->show_errors = false;
40
-
41
- $this->xcloner_container = $xcloner_container;
42
-
43
- $this->xcloner_settings = $xcloner_container->get_xcloner_settings();
44
- $this->logger = $xcloner_container->get_xcloner_logger()->withName("xcloner_api");
45
- $this->xcloner_file_system = $xcloner_container->get_xcloner_filesystem();
46
- $this->xcloner_sanitization = $xcloner_container->get_xcloner_sanitization();
47
- $this->xcloner_requirements = $xcloner_container->get_xcloner_requirements();
48
- $this->archive_system = $xcloner_container->get_archive_system();
49
- $this->xcloner_database = $xcloner_container->get_xcloner_database();
50
- $this->xcloner_scheduler = $xcloner_container->get_xcloner_scheduler();
51
-
52
- if(isset($_POST['API_ID'])){
53
- $this->logger->info("Processing ajax request ID ".substr($this->xcloner_sanitization->sanitize_input_as_string($_POST['API_ID']), 0 , 15));
54
- }
55
-
56
- }
57
-
58
- public function get_xcloner_container()
59
- {
60
- return $this->xcloner_container;
61
- }
62
-
63
- private function check_access()
64
- {
65
- if (function_exists('current_user_can') && !current_user_can('manage_options')) {
66
- die("Not allowed access here!");
67
- }
68
- }
69
-
70
- public function init_db()
71
- {
72
- return;
73
-
74
-
75
- $data['dbHostname'] = $this->xcloner_settings->get_db_hostname();
76
- $data['dbUsername'] = $this->xcloner_settings->get_db_username();
77
- $data['dbPassword'] = $this->xcloner_settings->get_db_password();
78
- $data['dbDatabase'] = $this->xcloner_settings->get_db_database();
79
-
80
-
81
- $data['recordsPerSession'] = $this->xcloner_settings->get_xcloner_option('xcloner_database_records_per_request');
82
- $data['TEMP_DBPROCESS_FILE'] = $this->xcloner_settings->get_xcloner_tmp_path().DS.".database";
83
- $data['TEMP_DUMP_FILE'] = $this->xcloner_settings->get_xcloner_tmp_path().DS."database-sql.sql";
84
-
85
- try
86
- {
87
- $this->xcloner_database->init($data);
88
-
89
- }catch(Exception $e){
90
-
91
- $this->send_response($e->getMessage());
92
- $this->logger->error($e->getMessage());
93
-
94
- }
95
-
96
- return $this->xcloner_database;
97
-
98
-
99
- }
100
-
101
- /*
102
- *
103
- * Save Schedule API
104
- */
105
- public function save_schedule()
106
- {
107
- global $wpdb;
108
-
109
- $this->check_access();
110
-
111
- $scheduler = $this->xcloner_scheduler;
112
- $params = array();
113
- $schedule = array();
114
- $response = array();
115
-
116
- if(isset($_POST['data']))
117
- $params = json_decode(stripslashes($_POST['data']));
118
-
119
- $this->process_params($params);
120
-
121
- if(isset($_POST['id']))
122
- {
123
-
124
- $this->form_params['backup_params']['backup_name'] = $this->xcloner_sanitization->sanitize_input_as_string($_POST['backup_name']);
125
- $this->form_params['backup_params']['email_notification'] = $this->xcloner_sanitization->sanitize_input_as_string($_POST['email_notification']);
126
- if($_POST['diff_start_date']){
127
- $this->form_params['backup_params']['diff_start_date'] = strtotime($this->xcloner_sanitization->sanitize_input_as_string($_POST['diff_start_date']));
128
- }else{
129
- $this->form_params['backup_params']['diff_start_date'] = "";
130
- }
131
- $this->form_params['backup_params']['schedule_name'] = $this->xcloner_sanitization->sanitize_input_as_string($_POST['schedule_name']);
132
- $this->form_params['backup_params']['start_at'] = strtotime($_POST['schedule_start_date']);
133
- $this->form_params['backup_params']['schedule_frequency'] = $this->xcloner_sanitization->sanitize_input_as_string($_POST['schedule_frequency']);
134
- $this->form_params['backup_params']['schedule_storage'] = $this->xcloner_sanitization->sanitize_input_as_string($_POST['schedule_storage']);
135
- $this->form_params['database'] = (stripslashes($this->xcloner_sanitization->sanitize_input_as_raw($_POST['table_params'])));
136
- $this->form_params['excluded_files'] = (stripslashes($this->xcloner_sanitization->sanitize_input_as_raw($_POST['excluded_files'])));
137
-
138
- //$this->form_params['backup_params']['backup_type'] = $this->xcloner_sanitization->sanitize_input_as_string($_POST['backup_type']);
139
-
140
- $tables = explode(PHP_EOL, $this->form_params['database']);
141
- $return = array();
142
-
143
- foreach($tables as $table)
144
- {
145
- $table = str_replace("\r","", $table);
146
- $data = explode(".", $table);
147
- if(isset($data[1]))
148
- $return[$data[0]][] = $data[1];
149
- }
150
-
151
- $this->form_params['database'] = ($return);
152
-
153
- $excluded_files = explode(PHP_EOL, $this->form_params['excluded_files']);
154
- $return = array();
155
-
156
- foreach($excluded_files as $file)
157
- {
158
- $file = str_replace("\r","", $file);
159
- if($file)
160
- $return[] = $file;
161
- }
162
-
163
- $this->form_params['excluded_files'] = ($return);
164
-
165
- $schedule['start_at'] = $this->form_params['backup_params']['start_at'];
166
-
167
- if(!isset($_POST['status']))
168
- $schedule['status'] = 0;
169
- else
170
- $schedule['status'] = $this->xcloner_sanitization->sanitize_input_as_int($_POST['status']);
171
- }else{
172
-
173
- $schedule['status'] = 1;
174
- $schedule['start_at'] = strtotime($this->form_params['backup_params']['schedule_start_date'] .
175
- " ".$this->form_params['backup_params']['schedule_start_time']);
176
-
177
- if($schedule['start_at'] <= time())
178
- {
179
- $schedule['start_at'] = "";
180
- }
181
- }
182
-
183
- if(!$schedule['start_at'])
184
- {
185
- $schedule['start_at'] = date('Y-m-d H:i:s', time());
186
- }else{
187
- $schedule['start_at'] = date('Y-m-d H:i:s', $schedule['start_at'] - (get_option( 'gmt_offset' ) * HOUR_IN_SECONDS) );
188
- }
189
-
190
- $schedule['name'] = $this->form_params['backup_params']['schedule_name'];
191
- $schedule['recurrence'] = $this->form_params['backup_params']['schedule_frequency'];
192
- if(!isset($this->form_params['backup_params']['schedule_storage']))
193
- {
194
- $this->form_params['backup_params']['schedule_storage'] = "";
195
- }
196
- $schedule['remote_storage'] = $this->form_params['backup_params']['schedule_storage'];
197
- //$schedule['backup_type'] = $this->form_params['backup_params']['backup_type'];
198
- $schedule['params'] = json_encode($this->form_params);
199
-
200
- if(!isset($_POST['id']))
201
- {
202
- $wpdb->insert(
203
- $wpdb->prefix.'xcloner_scheduler',
204
- $schedule,
205
- array(
206
- '%s',
207
- '%s'
208
- )
209
- );
210
- }else {
211
- $wpdb->update(
212
- $wpdb->prefix.'xcloner_scheduler',
213
- $schedule,
214
- array( 'id' => $_POST['id'] ),
215
- array(
216
- '%s',
217
- '%s'
218
- )
219
- );
220
- }
221
- if(isset($_POST['id']))
222
- {
223
- $scheduler->update_cron_hook($_POST['id']);
224
- }
225
-
226
- if( $wpdb->last_error ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
227
  $response['error'] = 1;
228
- $response['error_message'] = $wpdb->last_error/*."--".$wpdb->last_query*/;
229
-
 
230
  }
231
-
232
  $scheduler->update_wp_cron_hooks();
233
- $response['finished'] = 1;
234
-
235
- $this->send_response($response);
236
- }
237
-
238
- /*
239
- *
240
- * Backup Files API
241
- *
242
- */
243
- public function backup_files()
244
- {
245
- $this->check_access();
246
-
247
- $params = json_decode(stripslashes($_POST['data']));
248
-
249
- $init = (int)$_POST['init'];
250
-
251
- if($params === NULL)
252
- die( '{"status":false,"msg":"The post_data parameter must be valid JSON"}' );
253
-
254
- $this->process_params($params);
255
-
256
- $return['finished'] = 1;
257
-
258
- //$return = $this->archive_system->start_incremental_backup($this->form_params['backup_params'], $this->form_params['extra'], $init);
259
- try{
260
- $return = $this->archive_system->start_incremental_backup($this->form_params['backup_params'], $this->form_params['extra'], $init);
261
- }catch(Exception $e)
262
- {
263
- $return = array();
264
- $return['error'] = true;
265
- $return['status'] = 500;
266
- $return['error_message'] = $e->getMessage();
267
- return $this->send_response($return, $hash = 1);
268
- }
269
-
270
- if($return['finished'])
271
- {
272
- $return['extra']['backup_parent'] = $this->archive_system->get_archive_name_with_extension();
273
- if($this->xcloner_file_system->is_part($this->archive_system->get_archive_name_with_extension()))
274
- $return['extra']['backup_parent'] = $this->archive_system->get_archive_name_multipart();
275
- }
276
-
277
- $data = $return;
278
-
279
- //check if backup is finished
280
- if($return['finished'] )
281
- {
282
- if(isset($this->form_params['backup_params']['email_notification']) and $to=$this->form_params['backup_params']['email_notification'])
283
- {
284
- try{
285
- $from = "";
286
- $subject = "";
287
- $additional['lines_total'] = $return['extra']['lines_total'];
288
- $this->archive_system->send_notification($to, $from, $subject, $return['extra']['backup_parent'], $this->form_params,"", $additional);
289
- }catch(Exception $e)
290
- {
291
- $this->logger->error($e->getMessage());
292
- }
293
- }
294
- $this->xcloner_file_system->remove_tmp_filesystem();
295
- }
296
-
297
- return $this->send_response($data, $hash = 1);
298
- }
299
-
300
- /*
301
- *
302
- * Backup Database API
303
- *
304
- */
305
- public function backup_database()
306
- {
307
- $this->check_access();
308
-
309
- $params = json_decode(stripslashes($_POST['data']));
310
-
311
- $init = (int)$_POST['init'];
312
-
313
- if($params === NULL)
314
- die( '{"status":false,"msg":"The post_data parameter must be valid JSON"}' );
315
-
316
- $this->process_params($params);
317
-
318
- //$xcloner_database = $this->init_db();
319
- $return = $this->xcloner_database->start_database_recursion($this->form_params['database'], $this->form_params['extra'], $init);
320
-
321
- if(isset($return['error']) and $return['error'])
322
- $data['finished'] = 1;
323
- else
324
- $data['finished'] = $return['finished'];
325
-
326
- $data['extra'] = $return;
327
-
328
- return $this->send_response($data, $hash = 1);
329
- }
330
-
331
- /*
332
- *
333
- * Scan Filesystem API
334
- *
335
- */
336
- public function scan_filesystem()
337
- {
338
- $this->check_access();
339
-
340
- $params = json_decode(stripslashes($_POST['data']));
341
- $init = (int)$_POST['init'];
342
-
343
- if($params === NULL)
344
- die( '{"status":false,"msg":"The post_data parameter must be valid JSON"}' );
345
-
346
- $hash = $this->process_params($params);
347
-
348
- $this->xcloner_file_system->set_excluded_files($this->form_params['excluded_files']);
349
-
350
- $return = $this->xcloner_file_system->start_file_recursion($init);
351
-
352
- $data["finished"] = !$return;
353
- $data["total_files_num"] = $this->xcloner_file_system->get_scanned_files_num();
354
- $data["last_logged_file"] = $this->xcloner_file_system->last_logged_file();
355
- $data["total_files_size"] = sprintf("%.2f",$this->xcloner_file_system->get_scanned_files_total_size()/(1024*1024));
356
-
357
- return $this->send_response($data, $hash = 1);
358
- }
359
-
360
- /*
361
- *
362
- * Process params sent by the user
363
- *
364
- */
365
- private function process_params($params)
366
- {
367
- if(isset($params->hash))
368
- $this->xcloner_settings->set_hash($params->hash);
369
-
370
- $this->form_params['extra'] = array();
371
- $this->form_params['backup_params'] = array();
372
-
373
- $this->form_params['database'] = array();
374
-
375
- if(isset($params->backup_params))
376
- {
377
- foreach($params->backup_params as $param)
378
- {
379
- $this->form_params['backup_params'][$param->name] = $this->xcloner_sanitization->sanitize_input_as_string($param->value);
380
- $this->logger->debug("Adding form parameter ".$param->name.".".$param->value."\n", array('POST', 'fields filter'));
381
- }
382
- }
383
-
384
- $this->form_params['database'] = array();
385
-
386
- if(isset($params->table_params))
387
- {
388
- foreach($params->table_params as $param)
389
- {
390
- $this->form_params['database'][$param->parent][] = $this->xcloner_sanitization->sanitize_input_as_raw($param->id);
391
- $this->logger->debug("Adding database filter ".$param->parent.".".$param->id."\n", array('POST', 'database filter'));
392
- }
393
- }
394
-
395
- $this->form_params['excluded_files'] = array();
396
- if(isset($params->files_params))
397
- {
398
- foreach($params->files_params as $param)
399
- {
400
- $this->form_params['excluded_files'][] = $this->xcloner_sanitization->sanitize_input_as_relative_path($param->id);
401
- }
402
-
403
- $unique_exclude_files = array();
404
-
405
- foreach($params->files_params as $key=>$param)
406
- {
407
- if(!in_array($param->parent, $this->form_params['excluded_files'])){
408
- //$this->form_params['excluded_files'][] = $this->xcloner_sanitization->sanitize_input_as_relative_path($param->id);
409
- $unique_exclude_files[] = $param->id;
410
- $this->logger->debug("Adding file filter ".$param->id."\n", array('POST', 'exclude files filter'));
411
- }
412
- }
413
- $this->form_params['excluded_files'] = (array)$unique_exclude_files;
414
-
415
- }
416
-
417
- //$this->form_params['excluded_files'] = array_merge($this->form_params['excluded_files'], $this->exclude_files_by_default);
418
-
419
- if(isset($params->extra))
420
- {
421
- foreach($params->extra as $key=>$value)
422
- $this->form_params['extra'][$key] = $this->xcloner_sanitization->sanitize_input_as_raw($value);
423
- }
424
-
425
- if(isset($this->form_params['backup_params']['diff_start_date']) and $this->form_params['backup_params']['diff_start_date'])
426
- {
427
- $this->form_params['backup_params']['diff_start_date'] = strtotime($this->form_params['backup_params']['diff_start_date']);
428
- $this->xcloner_file_system->set_diff_timestamp_start($this->form_params['backup_params']['diff_start_date']);
429
- }
430
-
431
- return $this->xcloner_settings->get_hash();
432
- }
433
-
434
- /*
435
- *
436
- * Get file list for tree view API
437
- *
438
- */
439
- public function get_file_system_action()
440
- {
441
- $this->check_access();
442
-
443
- $folder = $this->xcloner_sanitization->sanitize_input_as_relative_path($_POST['id']);
444
-
445
- $data = array();
446
-
447
- if($folder == "#"){
448
-
449
- $folder = "/";
450
- $data[] = array(
451
- 'id' => $folder,
452
- 'parent' => '#',
453
- 'text' => $this->xcloner_settings->get_xcloner_start_path(),
454
- //'children' => true,
455
- 'state' => array('selected' => false, 'opened' => true),
456
- 'icon' => plugin_dir_url(dirname(__FILE__))."/admin/assets/file-icon-root.png"
457
- );
458
- }
459
-
460
- try{
461
- $files = $this->xcloner_file_system->list_directory($folder);
462
- }catch(Exception $e){
463
-
464
- print $e->getMessage();
465
- $this->logger->error($e->getMessage());
466
-
467
- return;
468
- }
469
-
470
- $type = array();
471
- foreach ($files as $key => $row)
472
- {
473
- $type[$key] = $row['type'];
474
- }
475
- array_multisort($type, SORT_ASC, $files);
476
-
477
- foreach($files as $file)
478
- {
479
- $children = false;
480
- $text = $file['basename'];
481
-
482
- if($file['type'] == "dir")
483
- $children = true;
484
- else
485
- $text .= " (". $this->xcloner_requirements->file_format_size($file['size']).")";
486
-
487
- if($this->xcloner_file_system->is_excluded($file))
488
- $selected = true;
489
- else
490
- $selected = false;
491
-
492
- $data[] = array(
493
- 'id' => $file['path'],
494
- 'parent' => $folder,
495
- 'text' => $text,
496
- //'title' => "test",
497
- 'children' => $children,
498
- 'state' => array('selected' => $selected, 'opened' => false, "checkbox_disabled" => $selected),
499
- 'icon' => plugin_dir_url(dirname(__FILE__))."/admin/assets/file-icon-".strtolower(substr($file['type'], 0, 1)).".png"
500
- );
501
- }
502
-
503
-
504
- return $this->send_response($data, 0);
505
- }
506
-
507
- /*
508
- *
509
- * Get databases/tables list for frontend tree display API
510
- *
511
- */
512
- public function get_database_tables_action()
513
- {
514
- $this->check_access();
515
-
516
- $database = $this->xcloner_sanitization->sanitize_input_as_raw($_POST['id']);
517
-
518
- $data = array();
519
-
520
- $xcloner_backup_only_wp_tables = $this->xcloner_settings->get_xcloner_option('xcloner_backup_only_wp_tables');
521
-
522
- if($database == "#")
523
- {
524
- try{
525
- $return = $this->xcloner_database->get_all_databases();
526
- }catch(Exception $e){
527
- $this->logger->error($e->getMessage());
528
- }
529
-
530
- foreach($return as $database)
531
- {
532
- if($xcloner_backup_only_wp_tables and $database['name'] != $this->xcloner_settings->get_db_database())
533
- continue;
534
-
535
- $state = array();
536
-
537
- if($database['name'] == $this->xcloner_settings->get_db_database())
538
- {
539
- $state['selected'] = true;
540
- if($database['num_tables'] < 25)
541
- $state['opened'] = false;
542
- }
543
-
544
- $data[] = array(
545
- 'id' => $database['name'],
546
- 'parent' => '#',
547
- 'text' => $database['name']." (".(int)$database['num_tables'].")",
548
- 'children' => true,
549
- 'state' => $state,
550
- 'icon' => plugin_dir_url(dirname(__FILE__))."/admin/assets/database-icon.png"
551
- );
552
- }
553
-
554
- }
555
-
556
- else{
557
-
558
- try{
559
- $return = $this->xcloner_database->list_tables($database, "", 1);
560
- }catch(Exception $e){
561
- $this->logger->error($e->getMessage());
562
- }
563
-
564
- foreach($return as $table)
565
- {
566
- $state = array();
567
-
568
- if($xcloner_backup_only_wp_tables and !stristr($table['name'], $this->xcloner_settings->get_table_prefix()))
569
- continue;
570
-
571
- if(isset($database['name']) and $database['name'] == $this->xcloner_settings->get_db_database())
572
- $state = array('selected' => true);
573
-
574
- $data[] = array(
575
- 'id' => $table['name'],
576
- 'parent' => $database,
577
- 'text' => $table['name']." (".(int)$table['records'].")",
578
- 'children' => false,
579
- 'state' => $state,
580
- 'icon' => plugin_dir_url(dirname(__FILE__))."/admin/assets/table-icon.png"
581
- );
582
- }
583
- }
584
-
585
- return $this->send_response($data, 0);
586
- }
587
-
588
- /*
589
- *
590
- * Get schedule by id API
591
- *
592
- */
593
- public function get_schedule_by_id()
594
- {
595
- $this->check_access();
596
-
597
- $schedule_id = $this->xcloner_sanitization->sanitize_input_as_int($_GET['id']);
598
- $scheduler = $this->xcloner_scheduler;
599
- $data = $scheduler->get_schedule_by_id($schedule_id);
600
-
601
- $data['start_at'] = date("Y-m-d H:i", strtotime($data['start_at']) + (get_option( 'gmt_offset' ) * HOUR_IN_SECONDS));
602
- if(isset($data['backup_params']->diff_start_date) && $data['backup_params']->diff_start_date != "")
603
- {
604
- $data['backup_params']->diff_start_date = date("Y-m-d", ($data['backup_params']->diff_start_date) );
605
- }
606
-
607
- return $this->send_response($data);
608
- }
609
-
610
- /*
611
- *
612
- * Get Schedule list API
613
- *
614
- */
615
- public function get_scheduler_list()
616
- {
617
- $this->check_access();
618
-
619
- $scheduler = $this->xcloner_scheduler;
620
- $data = $scheduler->get_scheduler_list();
621
- $return['data'] = array();
622
-
623
- foreach($data as $res)
624
- {
625
- $action = "<a href=\"#".$res->id."\" class=\"edit\" title='Edit'> <i class=\"material-icons \">edit</i></a>
626
- <a href=\"#".$res->id."\" class=\"delete\" title='Delete'><i class=\"material-icons \">delete</i></a>";
627
- if($res->status)
628
- $status = '<i class="material-icons active status">timer</i>';
629
- else
630
- $status = '<i class="material-icons status inactive">timer_off</i>';
631
-
632
- $next_run_time = wp_next_scheduled('xcloner_scheduler_'.$res->id, array($res->id));
633
-
634
- $next_run = date(get_option('date_format')." ".get_option('time_format'), $next_run_time);
635
-
636
- $remote_storage = $res->remote_storage;
637
-
638
- if(!$next_run_time >= time())
639
- $next_run = " ";
640
-
641
- if(trim($next_run))
642
- {
643
- $date_text = date(get_option('date_format')." ".get_option('time_format'), $next_run_time + (get_option( 'gmt_offset' ) * HOUR_IN_SECONDS));
644
-
645
- if($next_run_time >= time())
646
- $next_run = "in ".human_time_diff($next_run_time, time());
647
- else
648
- $next_run = __("executed", 'xcloner-backup-and-restore');
649
-
650
- $next_run = "<a href='#' title='".$date_text."'>".$next_run."</a>";
651
- //$next_run .=" ($date_text)";
652
- }
653
-
654
- $backup_text = "";
655
- $backup_size = "";
656
- $backup_time = "";
657
-
658
- if($res->last_backup)
659
- {
660
- if( $this->xcloner_file_system->get_storage_filesystem()->has($res->last_backup))
661
- {
662
- $metadata = $this->xcloner_file_system->get_storage_filesystem()->getMetadata($res->last_backup);
663
- $backup_size = size_format($this->xcloner_file_system->get_backup_size($res->last_backup));
664
- $backup_time = date(get_option('date_format')." ".get_option('time_format'), $metadata['timestamp']+(get_option( 'gmt_offset' ) * HOUR_IN_SECONDS));
665
- }
666
-
667
- $backup_text = "<span title='".$backup_time."' class='shorten_string'>".$res->last_backup." (".$backup_size.")</span>";
668
- }
669
-
670
- $schedules = wp_get_schedules();
671
-
672
- if(isset($schedules[$res->recurrence]))
673
- {
674
- $res->recurrence = $schedules[$res->recurrence]['display'];
675
- }
676
-
677
- $return['data'][] = array($res->id, $res->name, $res->recurrence,/*$res->start_at,*/ $next_run, $remote_storage, $backup_text, $status, $action);
678
- }
679
-
680
- return $this->send_response($return, 0);
681
- }
682
-
683
- /*
684
- *
685
- * Delete Schedule by ID API
686
- *
687
- */
688
- public function delete_schedule_by_id()
689
- {
690
- $this->check_access();
691
-
692
- $schedule_id = $this->xcloner_sanitization->sanitize_input_as_int($_GET['id']);
693
- $scheduler = $this->xcloner_scheduler;
694
- $data['finished'] = $scheduler->delete_schedule_by_id($schedule_id);
695
-
696
- return $this->send_response($data);
697
- }
698
-
699
- /*
700
- *
701
- * Delete backup by name from the storage path
702
- *
703
- */
704
- public function delete_backup_by_name()
705
- {
706
- $this->check_access();
707
-
708
- $backup_name = $this->xcloner_sanitization->sanitize_input_as_string($_POST['name']);
709
- $storage_selection = $this->xcloner_sanitization->sanitize_input_as_string($_POST['storage_selection']);
710
-
711
- $data['finished'] = $this->xcloner_file_system->delete_backup_by_name($backup_name, $storage_selection);
712
-
713
- return $this->send_response($data);
714
- }
715
-
716
- public function list_backup_files()
717
- {
718
- $this->check_access();
719
-
720
- $backup_parts = array();
721
-
722
- $source_backup_file = $this->xcloner_sanitization->sanitize_input_as_string($_POST['file']);
723
- $start = $this->xcloner_sanitization->sanitize_input_as_int($_POST['start']);
724
- $return['part'] = $this->xcloner_sanitization->sanitize_input_as_int($_POST['part']);
725
-
726
- $backup_file = $source_backup_file;
727
-
728
- if($this->xcloner_file_system->is_multipart($backup_file))
729
- {
730
- $backup_parts = $this->xcloner_file_system->get_multipart_files($backup_file);
731
- $backup_file = $backup_parts[$return['part']];
732
- }
733
-
734
- try{
735
- $tar = new Tar();
736
- $tar->open($this->xcloner_settings->get_xcloner_store_path().DS.$backup_file, $start);
737
-
738
- $data = $tar->contents(get_option('xcloner_files_to_process_per_request'));
739
- }catch(Exception $e)
740
- {
741
- $return['error'] = true;
742
- $return['message'] = $e->getMessage();
743
- $this->send_response($return, 0);
744
- }
745
-
746
- $return['files'] = array();
747
- $return['finished'] = 1;
748
- $return['total_size'] = filesize($this->xcloner_settings->get_xcloner_store_path().DS.$backup_file);
749
- $i = 0;
750
-
751
- if(isset($data['extracted_files']) and is_array($data['extracted_files']))
752
- {
753
- foreach($data['extracted_files'] as $file)
754
- {
755
- $return['files'][$i]['path'] = $file->getPath();
756
- $return['files'][$i]['size'] = $file->getSize();
757
- $return['files'][$i]['mtime'] = date(get_option('date_format')." ".get_option('time_format'), $file->getMtime());
758
-
759
- $i++;
760
- }
761
- }
762
-
763
- if(isset($data['start']))
764
- {
765
- $return['start'] = $data['start'];
766
- $return['finished'] = 0;
767
- }else{
768
- if($this->xcloner_file_system->is_multipart($source_backup_file))
769
- {
770
- $return['start'] = 0;
771
-
772
- ++$return['part'];
773
-
774
- if($return['part'] < sizeof($backup_parts))
775
- $return['finished'] = 0;
776
-
777
- }
778
- }
779
-
780
- $this->send_response($return, 0);
781
- }
782
-
783
- public function copy_backup_remote_to_local()
784
- {
785
-
786
- $this->check_access();
787
-
788
- $backup_file = $this->xcloner_sanitization->sanitize_input_as_string($_POST['file']);
789
- $storage_type = $this->xcloner_sanitization->sanitize_input_as_string($_POST['storage_type']);
790
-
791
- $xcloner_remote_storage = $this->get_xcloner_container()->get_xcloner_remote_storage();
792
-
793
- $return = array();
794
-
795
- try
796
- {
797
- if(method_exists($xcloner_remote_storage, "copy_backup_remote_to_local"))
798
- {
799
- $return = call_user_func_array(array($xcloner_remote_storage, "copy_backup_remote_to_local"), array($backup_file, $storage_type));
800
- }
801
- }catch(Exception $e){
802
-
803
- $return['error'] = 1;
804
- $return['message'] = $e->getMessage();
805
- }
806
-
807
- if(!$return)
808
- {
809
- $return['error'] = 1;
810
- $return['message'] = "Upload failed, please check the error log for more information!";
811
- }
812
-
813
-
814
- $this->send_response($return, 0);
815
-
816
- }
817
-
818
- /*
819
- *
820
- * Upload backup to remote API
821
- *
822
- */
823
- public function upload_backup_to_remote()
824
- {
825
- $this->check_access();
826
-
827
- $backup_file = $this->xcloner_sanitization->sanitize_input_as_string($_POST['file']);
828
- $storage_type = $this->xcloner_sanitization->sanitize_input_as_string($_POST['storage_type']);
829
-
830
- $xcloner_remote_storage = $this->get_xcloner_container()->get_xcloner_remote_storage();
831
-
832
- $return = array();
833
-
834
- try
835
- {
836
- if(method_exists($xcloner_remote_storage, "upload_backup_to_storage"))
837
- {
838
- $return = call_user_func_array(array($xcloner_remote_storage, "upload_backup_to_storage"), array($backup_file, $storage_type));
839
- }
840
- }catch(Exception $e){
841
-
842
- $return['error'] = 1;
843
- $return['message'] = $e->getMessage();
844
- }
845
-
846
- if(!$return)
847
- {
848
- $return['error'] = 1;
849
- $return['message'] = "Upload failed, please check the error log for more information!";
850
- }
851
-
852
-
853
- $this->send_response($return, 0);
854
-
855
- }
856
-
857
- /*
858
- *
859
- * Remote Storage Status Save
860
- *
861
- */
862
- public function remote_storage_save_status()
863
- {
864
- $this->check_access();
865
-
866
- $xcloner_remote_storage = $this->get_xcloner_container()->get_xcloner_remote_storage();
867
-
868
- $return['finished'] = $xcloner_remote_storage->change_storage_status($_POST['id'], $_POST['value']);
869
-
870
- $this->send_response($return, 0);
871
- }
872
-
873
-
874
- public function download_restore_script()
875
- {
876
- $this->check_access();
877
-
878
- @ob_end_clean();
879
-
880
- $adapter = new Local(dirname(__DIR__) ,LOCK_EX, 'SKIP_LINKS');
881
- $xcloner_plugin_filesystem = new Filesystem($adapter, new Config([
882
- 'disable_asserts' => true,
883
- ]));
884
-
885
- /* Generate PHAR FILE
886
- $file = 'restore/vendor.built';
887
-
888
- if(file_exists($file))
889
- unlink($file);
890
- $phar2 = new Phar($file, 0, 'vendor.phar');
891
-
892
- // add all files in the project, only include php files
893
- $phar2->buildFromIterator(
894
- new RecursiveIteratorIterator(
895
- new RecursiveDirectoryIterator(__DIR__.'/vendor/')),
896
- __DIR__);
897
-
898
- $phar2->setStub($phar2->createDefaultStub('vendor/autoload.php', 'vendor/autoload.php'));
899
- * */
900
-
901
- $tmp_file = $this->xcloner_settings->get_xcloner_tmp_path().DS."xcloner-restore.tgz";
902
-
903
- $tar = new Tar();
904
- $tar->create($tmp_file);
905
-
906
- $tar->addFile(dirname(__DIR__)."/restore/vendor.build.txt", "vendor.phar");
907
- //$tar->addFile(dirname(__DIR__)."/restore/vendor.tgz", "vendor.tgz");
908
-
909
- $files = $xcloner_plugin_filesystem->listContents("vendor/", true);
910
- foreach($files as $file)
911
- {
912
- $tar->addFile(dirname(__DIR__).DS.$file['path'], $file['path']);
913
- }
914
-
915
- $content = file_get_contents(dirname(__DIR__)."/restore/xcloner_restore.php");
916
- $content = str_replace("define('AUTH_KEY', '');", "define('AUTH_KEY', '".md5(AUTH_KEY)."');", $content);
917
-
918
- $tar->addData("xcloner_restore.php", $content);
919
-
920
- $tar->close();
921
-
922
- if (file_exists($tmp_file)) {
923
- header('Content-Description: File Transfer');
924
- header('Content-Type: application/octet-stream');
925
- header('Content-Disposition: attachment; filename="'.basename($tmp_file).'"');
926
- header('Expires: 0');
927
- header('Cache-Control: must-revalidate');
928
- header('Pragma: public');
929
- header('Content-Length: ' . filesize($tmp_file));
930
- readfile($tmp_file);
931
-
932
- }
933
-
934
- @unlink($tmp_file);
935
- exit;
936
- }
937
-
938
- /*
939
- *
940
- * Download backup by Name from the Storage Path
941
- *
942
- */
943
- public function download_backup_by_name()
944
- {
945
- $this->check_access();
946
-
947
- @ob_end_clean();
948
-
949
- $backup_name = $this->xcloner_sanitization->sanitize_input_as_string($_GET['name']);
950
-
951
-
952
- $metadata = $this->xcloner_file_system->get_storage_filesystem()->getMetadata($backup_name);
953
- $read_stream = $this->xcloner_file_system->get_storage_filesystem()->readStream($backup_name);
954
-
955
-
956
- header('Pragma: public');
957
- header('Expires: 0');
958
- header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
959
- header('Cache-Control: private', false);
960
- header('Content-Transfer-Encoding: binary');
961
- header('Content-Disposition: attachment; filename="'.$metadata['path'].'";');
962
- header('Content-Type: application/octet-stream');
963
- header('Content-Length: ' . $metadata['size']);
964
-
965
- @ob_end_clean();
966
-
967
- $chunkSize = 1024 * 1024;
968
- while (!feof($read_stream))
969
- {
970
- $buffer = fread($read_stream, $chunkSize);
971
- echo $buffer;
972
- }
973
- fclose($read_stream);
974
- exit;
975
-
976
- }
977
-
978
-
979
- public function restore_upload_backup()
980
- {
981
- $this->check_access();
982
-
983
- $return['part'] = 0;
984
- $return['total_parts'] = 0;
985
- $return['uploaded_size'] = 0;
986
- $is_multipart = 0;
987
-
988
- $file = $this->xcloner_sanitization->sanitize_input_as_string($_POST['file']);
989
- $hash = $this->xcloner_sanitization->sanitize_input_as_string($_POST['hash']);
990
-
991
- if(isset($_POST['part']))
992
- $return['part'] = $this->xcloner_sanitization->sanitize_input_as_int($_POST['part']);
993
-
994
- if(isset($_POST['uploaded_size']))
995
- $return['uploaded_size'] = $this->xcloner_sanitization->sanitize_input_as_int($_POST['uploaded_size']);
996
-
997
- $start = $this->xcloner_sanitization->sanitize_input_as_string($_POST['start']);
998
- $target_url = $this->xcloner_sanitization->sanitize_input_as_string($_POST['target_url']);
999
-
1000
- $return['total_size'] = $this->xcloner_file_system->get_backup_size($file);
1001
-
1002
- if($this->xcloner_file_system->is_multipart($file))
1003
- {
1004
- $backup_parts = $this->xcloner_file_system->get_multipart_files($file);
1005
-
1006
- $return['total_parts'] = sizeof($backup_parts)+1;
1007
-
1008
- if($return['part'] and isset($backup_parts[$return['part']-1]))
1009
- {
1010
- $file = $backup_parts[$return['part']-1];
1011
- }
1012
-
1013
- $is_multipart = 1;
1014
- }
1015
-
1016
- try{
1017
-
1018
- $xcloner_file_transfer = $this->get_xcloner_container()->get_xcloner_file_transfer();
1019
- $xcloner_file_transfer->set_target($target_url);
1020
- $return['start'] = $xcloner_file_transfer->transfer_file($file, $start, $hash);
1021
-
1022
- }catch(Exception $e){
1023
-
1024
- $return = array();
1025
- $return['error'] = true;
1026
- $return['status'] = 500;
1027
- $return['message'] = "CURL communication error with the restore host. ".$e->getMessage();
1028
- $this->send_response( $return, 0);
1029
-
1030
- }
1031
-
1032
- $return['status'] = 200;
1033
-
1034
- //we have finished the upload
1035
- if(!$return['start'] and $is_multipart)
1036
- {
1037
- $return['part']++;
1038
- $return['uploaded_size'] += $this->xcloner_file_system->get_storage_filesystem()->getSize($file);
1039
- }
1040
-
1041
- $this->send_response( $return, 0);
1042
- }
1043
-
1044
- public function restore_backup()
1045
- {
1046
- $this->check_access();
1047
-
1048
- define("XCLONER_PLUGIN_ACCESS", 1);
1049
- include_once(dirname(__DIR__) .DS."restore".DS."xcloner_restore.php");
1050
- return;
1051
- }
1052
-
1053
- /*
1054
- *
1055
- * Send the json response back
1056
- *
1057
- */
1058
- private function send_response($data, $attach_hash = 1)
1059
- {
1060
-
1061
- if($attach_hash and null !== $this->xcloner_settings->get_hash())
1062
- {
1063
- $data['hash'] = $this->xcloner_settings->get_hash();
1064
- }
1065
-
1066
- if( ob_get_length() )
1067
- ob_clean();
1068
- wp_send_json($data);
1069
-
1070
- die();
1071
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1072
  }
1
  <?php
2
+ /**
3
+ * XCloner - Backup and Restore backup plugin for Wordpress
4
+ *
5
+ * class-xcloner-api.php
6
+ * @author Liuta Ovidiu <info@thinkovi.com>
7
+ *
8
+ * This program is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation; either version 2 of the License, or
11
+ * (at your option) any later version.
12
+ *
13
+ * This program is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ * GNU General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU General Public License
19
+ * along with this program; if not, write to the Free Software
20
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21
+ * MA 02110-1301, USA.
22
+ *
23
+ * @link https://github.com/ovidiul/XCloner-Wordpress
24
+ *
25
+ * @modified 7/31/18 3:00 PM
26
+ *
27
+ */
28
 
29
  use League\Flysystem\Config;
30
  use League\Flysystem\Filesystem;
37
  use splitbrain\PHPArchive\FileInfo;
38
 
39
 
40
+ /**
41
+ * XCloner Api Class
42
+ */
43
+ class Xcloner_Api
44
+ {
45
+
46
+ private $xcloner_database;
47
+ private $xcloner_settings;
48
+ private $xcloner_file_system;
49
+ private $xcloner_requirements;
50
+ private $xcloner_sanitization;
51
+ private $archive_system;
52
+ private $form_params;
53
+ private $logger;
54
+ private $xcloner_container;
55
+
56
+ /**
57
+ * XCloner_Api construct class
58
+ *
59
+ * @param Xcloner $xcloner_container [description]
60
+ */
61
+ public function __construct(Xcloner $xcloner_container)
62
+ {
63
+ global $wpdb;
64
+
65
+ if (WP_DEBUG) {
66
+ error_reporting(0);
67
+ }
68
+
69
+ if (ob_get_length()) {
70
+ ob_end_clean();
71
+ }
72
+ ob_start();
73
+
74
+ $wpdb->show_errors = false;
75
+
76
+ $this->xcloner_container = $xcloner_container;
77
+
78
+ $this->xcloner_settings = $xcloner_container->get_xcloner_settings();
79
+ $this->logger = $xcloner_container->get_xcloner_logger()->withName("xcloner_api");
80
+ $this->xcloner_file_system = $xcloner_container->get_xcloner_filesystem();
81
+ $this->xcloner_sanitization = $xcloner_container->get_xcloner_sanitization();
82
+ $this->xcloner_requirements = $xcloner_container->get_xcloner_requirements();
83
+ $this->archive_system = $xcloner_container->get_archive_system();
84
+ $this->xcloner_database = $xcloner_container->get_xcloner_database();
85
+ $this->xcloner_scheduler = $xcloner_container->get_xcloner_scheduler();
86
+
87
+ if (isset($_POST['API_ID'])) {
88
+ $this->logger->info("Processing ajax request ID " . substr($this->xcloner_sanitization->sanitize_input_as_string($_POST['API_ID']),
89
+ 0, 15));
90
+ }
91
+
92
+ }
93
+
94
+ /**
95
+ * Get XCloner Container
96
+ * @return XCloner return the XCloner container
97
+ */
98
+ public function get_xcloner_container()
99
+ {
100
+ return $this->xcloner_container;
101
+ }
102
+
103
+ /**
104
+ * Check if user has access to this class
105
+ * @return die() returns die() if user is not allowed
106
+ * @link http://www.wordpress.org
107
+ */
108
+ private function check_access()
109
+ {
110
+ if (function_exists('current_user_can') && !current_user_can('manage_options')) {
111
+ die("Not allowed access here!");
112
+ }
113
+ }
114
+
115
+ /**
116
+ * Initialize the database connection
117
+ */
118
+ public function init_db()
119
+ {
120
+ return;
121
+
122
+
123
+ $data['dbHostname'] = $this->xcloner_settings->get_db_hostname();
124
+ $data['dbUsername'] = $this->xcloner_settings->get_db_username();
125
+ $data['dbPassword'] = $this->xcloner_settings->get_db_password();
126
+ $data['dbDatabase'] = $this->xcloner_settings->get_db_database();
127
+
128
+
129
+ $data['recordsPerSession'] = $this->xcloner_settings->get_xcloner_option('xcloner_database_records_per_request');
130
+ $data['TEMP_DBPROCESS_FILE'] = $this->xcloner_settings->get_xcloner_tmp_path() . DS . ".database";
131
+ $data['TEMP_DUMP_FILE'] = $this->xcloner_settings->get_xcloner_tmp_path() . DS . "database-sql.sql";
132
+
133
+ try {
134
+ $this->xcloner_database->init($data);
135
+
136
+ } catch (Exception $e) {
137
+
138
+ $this->send_response($e->getMessage());
139
+ $this->logger->error($e->getMessage());
140
+
141
+ }
142
+
143
+ return $this->xcloner_database;
144
+
145
+
146
+ }
147
+
148
+ /*
149
+ * Save Schedule API
150
+ */
151
+ public function save_schedule()
152
+ {
153
+ global $wpdb;
154
+
155
+ $this->check_access();
156
+
157
+ $scheduler = $this->xcloner_scheduler;
158
+ $params = array();
159
+ $schedule = array();
160
+ $response = array();
161
+
162
+ if (isset($_POST['data'])) {
163
+ $params = json_decode(stripslashes($_POST['data']));
164
+ }
165
+
166
+ $this->process_params($params);
167
+
168
+ if (isset($_POST['id'])) {
169
+
170
+ $this->form_params['backup_params']['backup_name'] = $this->xcloner_sanitization->sanitize_input_as_string($_POST['backup_name']);
171
+ $this->form_params['backup_params']['email_notification'] = $this->xcloner_sanitization->sanitize_input_as_string($_POST['email_notification']);
172
+ if ($_POST['diff_start_date']) {
173
+ $this->form_params['backup_params']['diff_start_date'] = strtotime($this->xcloner_sanitization->sanitize_input_as_string($_POST['diff_start_date']));
174
+ } else {
175
+ $this->form_params['backup_params']['diff_start_date'] = "";
176
+ }
177
+ $this->form_params['backup_params']['schedule_name'] = $this->xcloner_sanitization->sanitize_input_as_string($_POST['schedule_name']);
178
+ $this->form_params['backup_params']['start_at'] = strtotime($_POST['schedule_start_date']);
179
+ $this->form_params['backup_params']['schedule_frequency'] = $this->xcloner_sanitization->sanitize_input_as_string($_POST['schedule_frequency']);
180
+ $this->form_params['backup_params']['schedule_storage'] = $this->xcloner_sanitization->sanitize_input_as_string($_POST['schedule_storage']);
181
+ $this->form_params['database'] = (stripslashes($this->xcloner_sanitization->sanitize_input_as_raw($_POST['table_params'])));
182
+ $this->form_params['excluded_files'] = (stripslashes($this->xcloner_sanitization->sanitize_input_as_raw($_POST['excluded_files'])));
183
+
184
+ //$this->form_params['backup_params']['backup_type'] = $this->xcloner_sanitization->sanitize_input_as_string($_POST['backup_type']);
185
+
186
+ $tables = explode(PHP_EOL, $this->form_params['database']);
187
+ $return = array();
188
+
189
+ foreach ($tables as $table) {
190
+ $table = str_replace("\r", "", $table);
191
+ $data = explode(".", $table);
192
+ if (isset($data[1])) {
193
+ $return[$data[0]][] = $data[1];
194
+ }
195
+ }
196
+
197
+ $this->form_params['database'] = ($return);
198
+
199
+ $excluded_files = explode(PHP_EOL, $this->form_params['excluded_files']);
200
+ $return = array();
201
+
202
+ foreach ($excluded_files as $file) {
203
+ $file = str_replace("\r", "", $file);
204
+ if ($file) {
205
+ $return[] = $file;
206
+ }
207
+ }
208
+
209
+ $this->form_params['excluded_files'] = ($return);
210
+
211
+ $schedule['start_at'] = $this->form_params['backup_params']['start_at'];
212
+
213
+ if (!isset($_POST['status'])) {
214
+ $schedule['status'] = 0;
215
+ } else {
216
+ $schedule['status'] = $this->xcloner_sanitization->sanitize_input_as_int($_POST['status']);
217
+ }
218
+ } else {
219
+
220
+ $schedule['status'] = 1;
221
+ $schedule['start_at'] = strtotime($this->form_params['backup_params']['schedule_start_date'] .
222
+ " " . $this->form_params['backup_params']['schedule_start_time']);
223
+
224
+ if ($schedule['start_at'] <= time()) {
225
+ $schedule['start_at'] = "";
226
+ }
227
+ }
228
+
229
+ if (!$schedule['start_at']) {
230
+ $schedule['start_at'] = date('Y-m-d H:i:s', time());
231
+ } else {
232
+ $schedule['start_at'] = date('Y-m-d H:i:s',
233
+ $schedule['start_at'] - (get_option('gmt_offset') * HOUR_IN_SECONDS));
234
+ }
235
+
236
+ $schedule['name'] = $this->form_params['backup_params']['schedule_name'];
237
+ $schedule['recurrence'] = $this->form_params['backup_params']['schedule_frequency'];
238
+ if (!isset($this->form_params['backup_params']['schedule_storage'])) {
239
+ $this->form_params['backup_params']['schedule_storage'] = "";
240
+ }
241
+ $schedule['remote_storage'] = $this->form_params['backup_params']['schedule_storage'];
242
+ //$schedule['backup_type'] = $this->form_params['backup_params']['backup_type'];
243
+ $schedule['params'] = json_encode($this->form_params);
244
+
245
+ if (!isset($_POST['id'])) {
246
+ $wpdb->insert(
247
+ $wpdb->prefix . 'xcloner_scheduler',
248
+ $schedule,
249
+ array(
250
+ '%s',
251
+ '%s'
252
+ )
253
+ );
254
+ } else {
255
+ $wpdb->update(
256
+ $wpdb->prefix . 'xcloner_scheduler',
257
+ $schedule,
258
+ array('id' => $_POST['id']),
259
+ array(
260
+ '%s',
261
+ '%s'
262
+ )
263
+ );
264
+ }
265
+ if (isset($_POST['id'])) {
266
+ $scheduler->update_cron_hook($_POST['id']);
267
+ }
268
+
269
+ if ($wpdb->last_error) {
270
  $response['error'] = 1;
271
+ $response['error_message'] = $wpdb->last_error/*."--".$wpdb->last_query*/
272
+ ;
273
+
274
  }
275
+
276
  $scheduler->update_wp_cron_hooks();
277
+ $response['finished'] = 1;
278
+
279
+ $this->send_response($response);
280
+ }
281
+
282
+ /*
283
+ *
284
+ * Backup Files API
285
+ *
286
+ */
287
+ public function backup_files()
288
+ {
289
+ $this->check_access();
290
+
291
+ $params = json_decode(stripslashes($_POST['data']));
292
+
293
+ $init = (int)$_POST['init'];
294
+
295
+ if ($params === null) {
296
+ die('{"status":false,"msg":"The post_data parameter must be valid JSON"}');
297
+ }
298
+
299
+ $this->process_params($params);
300
+
301
+ $return['finished'] = 1;
302
+
303
+ //$return = $this->archive_system->start_incremental_backup($this->form_params['backup_params'], $this->form_params['extra'], $init);
304
+ try {
305
+ $return = $this->archive_system->start_incremental_backup($this->form_params['backup_params'],
306
+ $this->form_params['extra'], $init);
307
+ } catch (Exception $e) {
308
+ $return = array();
309
+ $return['error'] = true;
310
+ $return['status'] = 500;
311
+ $return['error_message'] = $e->getMessage();
312
+
313
+ return $this->send_response($return, $hash = 1);
314
+ }
315
+
316
+ if ($return['finished']) {
317
+ $return['extra']['backup_parent'] = $this->archive_system->get_archive_name_with_extension();
318
+ if ($this->xcloner_file_system->is_part($this->archive_system->get_archive_name_with_extension())) {
319
+ $return['extra']['backup_parent'] = $this->archive_system->get_archive_name_multipart();
320
+ }
321
+ }
322
+
323
+ $data = $return;
324
+
325
+ //check if backup is finished
326
+ if ($return['finished']) {
327
+ if (isset($this->form_params['backup_params']['email_notification']) and $to = $this->form_params['backup_params']['email_notification']) {
328
+ try {
329
+ $from = "";
330
+ $subject = "";
331
+ $additional['lines_total'] = $return['extra']['lines_total'];
332
+ $this->archive_system->send_notification($to, $from, $subject, $return['extra']['backup_parent'],
333
+ $this->form_params, "", $additional);
334
+ } catch (Exception $e) {
335
+ $this->logger->error($e->getMessage());
336
+ }
337
+ }
338
+ $this->xcloner_file_system->remove_tmp_filesystem();
339
+ }
340
+
341
+ return $this->send_response($data, $hash = 1);
342
+ }
343
+
344
+ /*
345
+ *
346
+ * Backup Database API
347
+ *
348
+ */
349
+ public function backup_database()
350
+ {
351
+ $this->check_access();
352
+
353
+ $params = json_decode(stripslashes($_POST['data']));
354
+
355
+ $init = (int)$_POST['init'];
356
+
357
+ if ($params === null) {
358
+ die('{"status":false,"msg":"The post_data parameter must be valid JSON"}');
359
+ }
360
+
361
+ $this->process_params($params);
362
+
363
+ //$xcloner_database = $this->init_db();
364
+ $return = $this->xcloner_database->start_database_recursion($this->form_params['database'],
365
+ $this->form_params['extra'], $init);
366
+
367
+ if (isset($return['error']) and $return['error']) {
368
+ $data['finished'] = 1;
369
+ } else {
370
+ $data['finished'] = $return['finished'];
371
+ }
372
+
373
+ $data['extra'] = $return;
374
+
375
+ return $this->send_response($data, $hash = 1);
376
+ }
377
+
378
+ /*
379
+ *
380
+ * Scan Filesystem API
381
+ *
382
+ */
383
+ public function scan_filesystem()
384
+ {
385
+ $this->check_access();
386
+
387
+ $params = json_decode(stripslashes($_POST['data']));
388
+ $init = (int)$_POST['init'];
389
+
390
+ if ($params === null) {
391
+ die('{"status":false,"msg":"The post_data parameter must be valid JSON"}');
392
+ }
393
+
394
+ $hash = $this->process_params($params);
395
+
396
+ $this->xcloner_file_system->set_excluded_files($this->form_params['excluded_files']);
397
+
398
+ $return = $this->xcloner_file_system->start_file_recursion($init);
399
+
400
+ $data["finished"] = !$return;
401
+ $data["total_files_num"] = $this->xcloner_file_system->get_scanned_files_num();
402
+ $data["last_logged_file"] = $this->xcloner_file_system->last_logged_file();
403
+ $data["total_files_size"] = sprintf("%.2f",
404
+ $this->xcloner_file_system->get_scanned_files_total_size() / (1024 * 1024));
405
+
406
+ return $this->send_response($data, $hash = 1);
407
+ }
408
+
409
+ /*
410
+ *
411
+ * Process params sent by the user
412
+ *
413
+ */
414
+ private function process_params($params)
415
+ {
416
+ if (isset($params->hash)) {
417
+ $this->xcloner_settings->set_hash($params->hash);
418
+ }
419
+
420
+ $this->form_params['extra'] = array();
421
+ $this->form_params['backup_params'] = array();
422
+
423
+ $this->form_params['database'] = array();
424
+
425
+ if (isset($params->backup_params)) {
426
+ foreach ($params->backup_params as $param) {
427
+ $this->form_params['backup_params'][$param->name] = $this->xcloner_sanitization->sanitize_input_as_string($param->value);
428
+ $this->logger->debug("Adding form parameter " . $param->name . "." . $param->value . "\n", array(
429
+ 'POST',
430
+ 'fields filter'
431
+ ));
432
+ }
433
+ }
434
+
435
+ $this->form_params['database'] = array();
436
+
437
+ if (isset($params->table_params)) {
438
+ foreach ($params->table_params as $param) {
439
+ $this->form_params['database'][$param->parent][] = $this->xcloner_sanitization->sanitize_input_as_raw($param->id);
440
+ $this->logger->debug("Adding database filter " . $param->parent . "." . $param->id . "\n", array(
441
+ 'POST',
442
+ 'database filter'
443
+ ));
444
+ }
445
+ }
446
+
447
+ $this->form_params['excluded_files'] = array();
448
+ if (isset($params->files_params)) {
449
+ foreach ($params->files_params as $param) {
450
+ $this->form_params['excluded_files'][] = $this->xcloner_sanitization->sanitize_input_as_relative_path($param->id);
451
+ }
452
+
453
+ $unique_exclude_files = array();
454
+
455
+ foreach ($params->files_params as $key => $param) {
456
+ if (!in_array($param->parent, $this->form_params['excluded_files'])) {
457
+ //$this->form_params['excluded_files'][] = $this->xcloner_sanitization->sanitize_input_as_relative_path($param->id);
458
+ $unique_exclude_files[] = $param->id;
459
+ $this->logger->debug("Adding file filter " . $param->id . "\n", array(
460
+ 'POST',
461
+ 'exclude files filter'
462
+ ));
463
+ }
464
+ }
465
+ $this->form_params['excluded_files'] = (array)$unique_exclude_files;
466
+
467
+ }
468
+
469
+ //$this->form_params['excluded_files'] = array_merge($this->form_params['excluded_files'], $this->exclude_files_by_default);
470
+
471
+ if (isset($params->extra)) {
472
+ foreach ($params->extra as $key => $value) {
473
+ $this->form_params['extra'][$key] = $this->xcloner_sanitization->sanitize_input_as_raw($value);
474
+ }
475
+ }
476
+
477
+ if (isset($this->form_params['backup_params']['diff_start_date']) and $this->form_params['backup_params']['diff_start_date']) {
478
+ $this->form_params['backup_params']['diff_start_date'] = strtotime($this->form_params['backup_params']['diff_start_date']);
479
+ $this->xcloner_file_system->set_diff_timestamp_start($this->form_params['backup_params']['diff_start_date']);
480
+ }
481
+
482
+ return $this->xcloner_settings->get_hash();
483
+ }
484
+
485
+ /*
486
+ *
487
+ * Get file list for tree view API
488
+ *
489
+ */
490
+ public function get_file_system_action()
491
+ {
492
+ $this->check_access();
493
+
494
+ $folder = $this->xcloner_sanitization->sanitize_input_as_relative_path($_POST['id']);
495
+
496
+ $data = array();
497
+
498
+ if ($folder == "#") {
499
+
500
+ $folder = "/";
501
+ $data[] = array(
502
+ 'id' => $folder,
503
+ 'parent' => '#',
504
+ 'text' => $this->xcloner_settings->get_xcloner_start_path(),
505
+ //'children' => true,
506
+ 'state' => array('selected' => false, 'opened' => true),
507
+ 'icon' => plugin_dir_url(dirname(__FILE__)) . "/admin/assets/file-icon-root.png"
508
+ );
509
+ }
510
+
511
+ try {
512
+ $files = $this->xcloner_file_system->list_directory($folder);
513
+ } catch (Exception $e) {
514
+
515
+ print $e->getMessage();
516
+ $this->logger->error($e->getMessage());
517
+
518
+ return;
519
+ }
520
+
521
+ $type = array();
522
+ foreach ($files as $key => $row) {
523
+ $type[$key] = $row['type'];
524
+ }
525
+ array_multisort($type, SORT_ASC, $files);
526
+
527
+ foreach ($files as $file) {
528
+ $children = false;
529
+ $text = $file['basename'];
530
+
531
+ if ($file['type'] == "dir") {
532
+ $children = true;
533
+ } else {
534
+ $text .= " (" . $this->xcloner_requirements->file_format_size($file['size']) . ")";
535
+ }
536
+
537
+ if ($this->xcloner_file_system->is_excluded($file)) {
538
+ $selected = true;
539
+ } else {
540
+ $selected = false;
541
+ }
542
+
543
+ $data[] = array(
544
+ 'id' => $file['path'],
545
+ 'parent' => $folder,
546
+ 'text' => $text,
547
+ //'title' => "test",
548
+ 'children' => $children,
549
+ 'state' => array('selected' => $selected, 'opened' => false, "checkbox_disabled" => $selected),
550
+ 'icon' => plugin_dir_url(dirname(__FILE__)) . "/admin/assets/file-icon-" . strtolower(substr($file['type'],
551
+ 0, 1)) . ".png"
552
+ );
553
+ }
554
+
555
+
556
+ return $this->send_response($data, 0);
557
+ }
558
+
559
+ /*
560
+ *
561
+ * Get databases/tables list for frontend tree display API
562
+ *
563
+ */
564
+ public function get_database_tables_action()
565
+ {
566
+ $this->check_access();
567
+
568
+ $database = $this->xcloner_sanitization->sanitize_input_as_raw($_POST['id']);
569
+
570
+ $data = array();
571
+
572
+ $xcloner_backup_only_wp_tables = $this->xcloner_settings->get_xcloner_option('xcloner_backup_only_wp_tables');
573
+
574
+ if ($database == "#") {
575
+ try {
576
+ $return = $this->xcloner_database->get_all_databases();
577
+ } catch (Exception $e) {
578
+ $this->logger->error($e->getMessage());
579
+ }
580
+
581
+ foreach ($return as $database) {
582
+ if ($xcloner_backup_only_wp_tables and $database['name'] != $this->xcloner_settings->get_db_database()) {
583
+ continue;
584
+ }
585
+
586
+ $state = array();
587
+
588
+ if ($database['name'] == $this->xcloner_settings->get_db_database()) {
589
+ $state['selected'] = true;
590
+ if ($database['num_tables'] < 25) {
591
+ $state['opened'] = false;
592
+ }
593
+ }
594
+
595
+ $data[] = array(
596
+ 'id' => $database['name'],
597
+ 'parent' => '#',
598
+ 'text' => $database['name'] . " (" . (int)$database['num_tables'] . ")",
599
+ 'children' => true,
600
+ 'state' => $state,
601
+ 'icon' => plugin_dir_url(dirname(__FILE__)) . "/admin/assets/database-icon.png"
602
+ );
603
+ }
604
+
605
+ } else {
606
+
607
+ try {
608
+ $return = $this->xcloner_database->list_tables($database, "", 1);
609
+ } catch (Exception $e) {
610
+ $this->logger->error($e->getMessage());
611
+ }
612
+
613
+ foreach ($return as $table) {
614
+ $state = array();
615
+
616
+ if ($xcloner_backup_only_wp_tables and !stristr($table['name'],
617
+ $this->xcloner_settings->get_table_prefix())) {
618
+ continue;
619
+ }
620
+
621
+ if (isset($database['name']) and $database['name'] == $this->xcloner_settings->get_db_database()) {
622
+ $state = array('selected' => true);
623
+ }
624
+
625
+ $data[] = array(
626
+ 'id' => $database . "." . $table['name'],
627
+ 'parent' => $database,
628
+ 'text' => $table['name'] . " (" . (int)$table['records'] . ")",
629
+ 'children' => false,
630
+ 'state' => $state,
631
+ 'icon' => plugin_dir_url(dirname(__FILE__)) . "/admin/assets/table-icon.png"
632
+ );
633
+ }
634
+ }
635
+
636
+ return $this->send_response($data, 0);
637
+ }
638
+
639
+ /*
640
+ *
641
+ * Get schedule by id API
642
+ *
643
+ */
644
+ public function get_schedule_by_id()
645
+ {
646
+ $this->check_access();
647
+
648
+ $schedule_id = $this->xcloner_sanitization->sanitize_input_as_int($_GET['id']);
649
+ $scheduler = $this->xcloner_scheduler;
650
+ $data = $scheduler->get_schedule_by_id($schedule_id);
651
+
652
+ $data['start_at'] = date("Y-m-d H:i",
653
+ strtotime($data['start_at']) + (get_option('gmt_offset') * HOUR_IN_SECONDS));
654
+ if (isset($data['backup_params']->diff_start_date) && $data['backup_params']->diff_start_date != "") {
655
+ $data['backup_params']->diff_start_date = date("Y-m-d", ($data['backup_params']->diff_start_date));
656
+ }
657
+
658
+ return $this->send_response($data);
659
+ }
660
+
661
+ /*
662
+ *
663
+ * Get Schedule list API
664
+ *
665
+ */
666
+ public function get_scheduler_list()
667
+ {
668
+ $this->check_access();
669
+
670
+ $scheduler = $this->xcloner_scheduler;
671
+ $data = $scheduler->get_scheduler_list();
672
+ $return['data'] = array();
673
+
674
+ foreach ($data as $res) {
675
+ $action = "<a href=\"#" . $res->id . "\" class=\"edit\" title='Edit'> <i class=\"material-icons \">edit</i></a>
676
+ <a href=\"#" . $res->id . "\" class=\"delete\" title='Delete'><i class=\"material-icons \">delete</i></a>";
677
+ if ($res->status) {
678
+ $status = '<i class="material-icons active status">timer</i>';
679
+ } else {
680
+ $status = '<i class="material-icons status inactive">timer_off</i>';
681
+ }
682
+
683
+ $next_run_time = wp_next_scheduled('xcloner_scheduler_' . $res->id, array($res->id));
684
+
685
+ $next_run = date(get_option('date_format') . " " . get_option('time_format'), $next_run_time);
686
+
687
+ $remote_storage = $res->remote_storage;
688
+
689
+ if (!$next_run_time >= time()) {
690
+ $next_run = " ";
691
+ }
692
+
693
+ if (trim($next_run)) {
694
+ $date_text = date(get_option('date_format') . " " . get_option('time_format'),
695
+ $next_run_time + (get_option('gmt_offset') * HOUR_IN_SECONDS));
696
+
697
+ if ($next_run_time >= time()) {
698
+ $next_run = "in " . human_time_diff($next_run_time, time());
699
+ } else {
700
+ $next_run = __("executed", 'xcloner-backup-and-restore');
701
+ }
702
+
703
+ $next_run = "<a href='#' title='" . $date_text . "'>" . $next_run . "</a>";
704
+ //$next_run .=" ($date_text)";
705
+ }
706
+
707
+ $backup_text = "";
708
+ $backup_size = "";
709
+ $backup_time = "";
710
+
711
+ if ($res->last_backup) {
712
+ if ($this->xcloner_file_system->get_storage_filesystem()->has($res->last_backup)) {
713
+ $metadata = $this->xcloner_file_system->get_storage_filesystem()->getMetadata($res->last_backup);
714
+ $backup_size = size_format($this->xcloner_file_system->get_backup_size($res->last_backup));
715
+ $backup_time = date(get_option('date_format') . " " . get_option('time_format'),
716
+ $metadata['timestamp'] + (get_option('gmt_offset') * HOUR_IN_SECONDS));
717
+ }
718
+
719
+ $backup_text = "<span title='" . $backup_time . "' class='shorten_string'>" . $res->last_backup . " (" . $backup_size . ")</span>";
720
+ }
721
+
722
+ $schedules = wp_get_schedules();
723
+
724
+ if (isset($schedules[$res->recurrence])) {
725
+ $res->recurrence = $schedules[$res->recurrence]['display'];
726
+ }
727
+
728
+ $return['data'][] = array(
729
+ $res->id,
730
+ $res->name,
731
+ $res->recurrence,/*$res->start_at,*/
732
+ $next_run,
733
+ $remote_storage,
734
+ $backup_text,
735
+ $status,
736
+ $action
737
+ );
738
+ }
739
+
740
+ return $this->send_response($return, 0);
741
+ }
742
+
743
+ /*
744
+ *
745
+ * Delete Schedule by ID API
746
+ *
747
+ */
748
+ public function delete_schedule_by_id()
749
+ {
750
+ $this->check_access();
751
+
752
+ $schedule_id = $this->xcloner_sanitization->sanitize_input_as_int($_GET['id']);
753
+ $scheduler = $this->xcloner_scheduler;
754
+ $data['finished'] = $scheduler->delete_schedule_by_id($schedule_id);
755
+
756
+ return $this->send_response($data);
757
+ }
758
+
759
+ /*
760
+ *
761
+ * Delete backup by name from the storage path
762
+ *
763
+ */
764
+ public function delete_backup_by_name()
765
+ {
766
+ $this->check_access();
767
+
768
+ $backup_name = $this->xcloner_sanitization->sanitize_input_as_string($_POST['name']);
769
+ $storage_selection = $this->xcloner_sanitization->sanitize_input_as_string($_POST['storage_selection']);
770
+
771
+ $data['finished'] = $this->xcloner_file_system->delete_backup_by_name($backup_name, $storage_selection);
772
+
773
+ return $this->send_response($data);
774
+ }
775
+
776
+ public function list_backup_files()
777
+ {
778
+ $this->check_access();
779
+
780
+ $backup_parts = array();
781
+
782
+ $source_backup_file = $this->xcloner_sanitization->sanitize_input_as_string($_POST['file']);
783
+ $start = $this->xcloner_sanitization->sanitize_input_as_int($_POST['start']);
784
+ $return['part'] = $this->xcloner_sanitization->sanitize_input_as_int($_POST['part']);
785
+
786
+ $backup_file = $source_backup_file;
787
+
788
+ if ($this->xcloner_file_system->is_multipart($backup_file)) {
789
+ $backup_parts = $this->xcloner_file_system->get_multipart_files($backup_file);
790
+ $backup_file = $backup_parts[$return['part']];
791
+ }
792
+
793
+ try {
794
+ $tar = new Tar();
795
+ $tar->open($this->xcloner_settings->get_xcloner_store_path() . DS . $backup_file, $start);
796
+
797
+ $data = $tar->contents(get_option('xcloner_files_to_process_per_request'));
798
+ } catch (Exception $e) {
799
+ $return['error'] = true;
800
+ $return['message'] = $e->getMessage();
801
+ $this->send_response($return, 0);
802
+ }
803
+
804
+ $return['files'] = array();
805
+ $return['finished'] = 1;
806
+ $return['total_size'] = filesize($this->xcloner_settings->get_xcloner_store_path() . DS . $backup_file);
807
+ $i = 0;
808
+
809
+ if (isset($data['extracted_files']) and is_array($data['extracted_files'])) {
810
+ foreach ($data['extracted_files'] as $file) {
811
+ $return['files'][$i]['path'] = $file->getPath();
812
+ $return['files'][$i]['size'] = $file->getSize();
813
+ $return['files'][$i]['mtime'] = date(get_option('date_format') . " " . get_option('time_format'),
814
+ $file->getMtime());
815
+
816
+ $i++;
817
+ }
818
+ }
819
+
820
+ if (isset($data['start'])) {
821
+ $return['start'] = $data['start'];
822
+ $return['finished'] = 0;
823
+ } else {
824
+ if ($this->xcloner_file_system->is_multipart($source_backup_file)) {
825
+ $return['start'] = 0;
826
+
827
+ ++$return['part'];
828
+
829
+ if ($return['part'] < sizeof($backup_parts)) {
830
+ $return['finished'] = 0;
831
+ }
832
+
833
+ }
834
+ }
835
+
836
+ $this->send_response($return, 0);
837
+ }
838
+
839
+ /*
840
+ * Copy remote backup to local storage
841
+ */
842
+ public function copy_backup_remote_to_local()
843
+ {
844
+
845
+ $this->check_access();
846
+
847
+ $backup_file = $this->xcloner_sanitization->sanitize_input_as_string($_POST['file']);
848
+ $storage_type = $this->xcloner_sanitization->sanitize_input_as_string($_POST['storage_type']);
849
+
850
+ $xcloner_remote_storage = $this->get_xcloner_container()->get_xcloner_remote_storage();
851
+
852
+ $return = array();
853
+
854
+ try {
855
+ if (method_exists($xcloner_remote_storage, "copy_backup_remote_to_local")) {
856
+ $return = call_user_func_array(array(
857
+ $xcloner_remote_storage,
858
+ "copy_backup_remote_to_local"
859
+ ), array($backup_file, $storage_type));
860
+ }
861
+ } catch (Exception $e) {
862
+
863
+ $return['error'] = 1;
864
+ $return['message'] = $e->getMessage();
865
+ }
866
+
867
+ if (!$return) {
868
+ $return['error'] = 1;
869
+ $return['message'] = "Upload failed, please check the error log for more information!";
870
+ }
871
+
872
+
873
+ $this->send_response($return, 0);
874
+
875
+ }
876
+
877
+ /*
878
+ *
879
+ * Upload backup to remote API
880
+ *
881
+ */
882
+ public function upload_backup_to_remote()
883
+ {
884
+ $this->check_access();
885
+
886
+ $backup_file = $this->xcloner_sanitization->sanitize_input_as_string($_POST['file']);
887
+ $storage_type = $this->xcloner_sanitization->sanitize_input_as_string($_POST['storage_type']);
888
+
889
+ $xcloner_remote_storage = $this->get_xcloner_container()->get_xcloner_remote_storage();
890
+
891
+ $return = array();
892
+
893
+ try {
894
+ if (method_exists($xcloner_remote_storage, "upload_backup_to_storage")) {
895
+ $return = call_user_func_array(array(
896
+ $xcloner_remote_storage,
897
+ "upload_backup_to_storage"
898
+ ), array($backup_file, $storage_type));
899
+ }
900
+ } catch (Exception $e) {
901
+
902
+ $return['error'] = 1;
903
+ $return['message'] = $e->getMessage();
904
+ }
905
+
906
+ if (!$return) {
907
+ $return['error'] = 1;
908
+ $return['message'] = "Upload failed, please check the error log for more information!";
909
+ }
910
+
911
+
912
+ $this->send_response($return, 0);
913
+
914
+ }
915
+
916
+ /*
917
+ *
918
+ * Remote Storage Status Save
919
+ *
920
+ */
921
+ public function remote_storage_save_status()
922
+ {
923
+ $this->check_access();
924
+
925
+ $xcloner_remote_storage = $this->get_xcloner_container()->get_xcloner_remote_storage();
926
+
927
+ $return['finished'] = $xcloner_remote_storage->change_storage_status($_POST['id'], $_POST['value']);
928
+
929
+ $this->send_response($return, 0);
930
+ }
931
+
932
+
933
+ public function download_restore_script()
934
+ {
935
+ $this->check_access();
936
+
937
+ @ob_end_clean();
938
+
939
+ $adapter = new Local(dirname(__DIR__), LOCK_EX, 'SKIP_LINKS');
940
+ $xcloner_plugin_filesystem = new Filesystem($adapter, new Config([
941
+ 'disable_asserts' => true,
942
+ ]));
943
+
944
+ /* Generate PHAR FILE
945
+ $file = 'restore/vendor.built';
946
+
947
+ if(file_exists($file))
948
+ unlink($file);
949
+ $phar2 = new Phar($file, 0, 'vendor.phar');
950
+
951
+ // add all files in the project, only include php files
952
+ $phar2->buildFromIterator(
953
+ new RecursiveIteratorIterator(
954
+ new RecursiveDirectoryIterator(__DIR__.'/vendor/')),
955
+ __DIR__);
956
+
957
+ $phar2->setStub($phar2->createDefaultStub('vendor/autoload.php', 'vendor/autoload.php'));
958
+ * */
959
+
960
+ $tmp_file = $this->xcloner_settings->get_xcloner_tmp_path() . DS . "xcloner-restore.tgz";
961
+
962
+ $tar = new Tar();
963
+ $tar->create($tmp_file);
964
+
965
+ $tar->addFile(dirname(__DIR__) . "/restore/vendor.build.txt", "vendor.phar");
966
+ //$tar->addFile(dirname(__DIR__)."/restore/vendor.tgz", "vendor.tgz");
967
+
968
+ $files = $xcloner_plugin_filesystem->listContents("vendor/", true);
969
+ foreach ($files as $file) {
970
+ $tar->addFile(dirname(__DIR__) . DS . $file['path'], $file['path']);
971
+ }
972
+
973
+ $content = file_get_contents(dirname(__DIR__) . "/restore/xcloner_restore.php");
974
+ $content = str_replace("define('AUTH_KEY', '');", "define('AUTH_KEY', '" . md5(AUTH_KEY) . "');", $content);
975
+
976
+ $tar->addData("xcloner_restore.php", $content);
977
+
978
+ $tar->close();
979
+
980
+ if (file_exists($tmp_file)) {
981
+ header('Content-Description: File Transfer');
982
+ header('Content-Type: application/octet-stream');
983
+ header('Content-Disposition: attachment; filename="' . basename($tmp_file) . '"');
984
+ header('Expires: 0');
985
+ header('Cache-Control: must-revalidate');
986
+ header('Pragma: public');
987
+ header('Content-Length: ' . filesize($tmp_file));
988
+ readfile($tmp_file);
989
+
990
+ }
991
+
992
+ @unlink($tmp_file);
993
+ exit;
994
+ }
995
+
996
+ /*
997
+ *
998
+ * Download backup by Name from the Storage Path
999
+ *
1000
+ */
1001
+ public function download_backup_by_name()
1002
+ {
1003
+ $this->check_access();
1004
+
1005
+ @ob_end_clean();
1006
+
1007
+ $backup_name = $this->xcloner_sanitization->sanitize_input_as_string($_GET['name']);
1008
+
1009
+
1010
+ $metadata = $this->xcloner_file_system->get_storage_filesystem()->getMetadata($backup_name);
1011
+ $read_stream = $this->xcloner_file_system->get_storage_filesystem()->readStream($backup_name);
1012
+
1013
+
1014
+ header('Pragma: public');
1015
+ header('Expires: 0');
1016
+ header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
1017
+ header('Cache-Control: private', false);
1018
+ header('Content-Transfer-Encoding: binary');
1019
+ header('Content-Disposition: attachment; filename="' . $metadata['path'] . '";');
1020
+ header('Content-Type: application/octet-stream');
1021
+ header('Content-Length: ' . $metadata['size']);
1022
+
1023
+ @ob_end_clean();
1024
+
1025
+ $chunkSize = 1024 * 1024;
1026
+ while (!feof($read_stream)) {
1027
+ $buffer = fread($read_stream, $chunkSize);
1028
+ echo $buffer;
1029
+ }
1030
+ fclose($read_stream);
1031
+ exit;
1032
+
1033
+ }
1034
+
1035
+ /*
1036
+ * Restore upload backup
1037
+ */
1038
+ public function restore_upload_backup()
1039
+ {
1040
+ $this->check_access();
1041
+
1042
+ $return['part'] = 0;
1043
+ $return['total_parts'] = 0;
1044
+ $return['uploaded_size'] = 0;
1045
+ $is_multipart = 0;
1046
+
1047
+ $file = $this->xcloner_sanitization->sanitize_input_as_string($_POST['file']);
1048
+ $hash = $this->xcloner_sanitization->sanitize_input_as_string($_POST['hash']);
1049
+
1050
+ if (isset($_POST['part'])) {
1051
+ $return['part'] = $this->xcloner_sanitization->sanitize_input_as_int($_POST['part']);
1052
+ }
1053
+
1054
+ if (isset($_POST['uploaded_size'])) {
1055
+ $return['uploaded_size'] = $this->xcloner_sanitization->sanitize_input_as_int($_POST['uploaded_size']);
1056
+ }
1057
+
1058
+ $start = $this->xcloner_sanitization->sanitize_input_as_string($_POST['start']);
1059
+ $target_url = $this->xcloner_sanitization->sanitize_input_as_string($_POST['target_url']);
1060
+
1061
+ $return['total_size'] = $this->xcloner_file_system->get_backup_size($file);
1062
+
1063
+ if ($this->xcloner_file_system->is_multipart($file)) {
1064
+ $backup_parts = $this->xcloner_file_system->get_multipart_files($file);
1065
+
1066
+ $return['total_parts'] = sizeof($backup_parts) + 1;
1067
+
1068
+ if ($return['part'] and isset($backup_parts[$return['part'] - 1])) {
1069
+ $file = $backup_parts[$return['part'] - 1];
1070
+ }
1071
+
1072
+ $is_multipart = 1;
1073
+ }
1074
+
1075
+ try {
1076
+
1077
+ $xcloner_file_transfer = $this->get_xcloner_container()->get_xcloner_file_transfer();
1078
+ $xcloner_file_transfer->set_target($target_url);
1079
+ $return['start'] = $xcloner_file_transfer->transfer_file($file, $start, $hash);
1080
+
1081
+ } catch (Exception $e) {
1082
+
1083
+ $return = array();
1084
+ $return['error'] = true;
1085
+ $return['status'] = 500;
1086
+ $return['message'] = "CURL communication error with the restore host. " . $e->getMessage();
1087
+ $this->send_response($return, 0);
1088
+
1089
+ }
1090
+
1091
+ $return['status'] = 200;
1092
+
1093
+ //we have finished the upload
1094
+ if (!$return['start'] and $is_multipart) {
1095
+ $return['part']++;
1096
+ $return['uploaded_size'] += $this->xcloner_file_system->get_storage_filesystem()->getSize($file);
1097
+ }
1098
+
1099
+ $this->send_response($return, 0);
1100
+ }
1101
+
1102
+ /*
1103
+ * Restore backup
1104
+ */
1105
+ public function restore_backup()
1106
+ {
1107
+ $this->check_access();
1108
+
1109
+ define("XCLONER_PLUGIN_ACCESS", 1);
1110
+ include_once(dirname(__DIR__) . DS . "restore" . DS . "xcloner_restore.php");
1111
+
1112
+ return;
1113
+ }
1114
+
1115
+ /*
1116
+ *
1117
+ * Send the json response back
1118
+ *
1119
+ */
1120
+ private function send_response($data, $attach_hash = 1)
1121
+ {
1122
+
1123
+ if ($attach_hash and null !== $this->xcloner_settings->get_hash()) {
1124
+ $data['hash'] = $this->xcloner_settings->get_hash();
1125
+ }
1126
+
1127
+ if (ob_get_length()) {
1128
+ ob_clean();
1129
+ }
1130
+ wp_send_json($data);
1131
+
1132
+ die();
1133
+ }
1134
  }
includes/class-xcloner-archive.php CHANGED
@@ -1,608 +1,721 @@
1
  <?php
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  use splitbrain\PHPArchive\Tar;
3
  use splitbrain\PHPArchive\Archive;
4
  use splitbrain\PHPArchive\FileInfo;
5
 
 
 
 
 
6
  class Xcloner_Archive extends Tar
7
  {
8
- /*
9
- * bytes
10
- */
11
- private $file_size_per_request_limit = 52428800 ; //50MB = 52428800; 1MB = 1048576
12
- private $files_to_process_per_request = 250; //block of 512 bytes
13
- private $compression_level = 0; //0-9 , 0 uncompressed
14
- private $xcloner_split_backup_limit = 2048; //2048MB
15
- private $processed_size_bytes = 0 ;
16
-
17
- private $archive_name;
18
- private $backup_archive;
19
- private $filesystem;
20
- private $logger;
21
- private $xcloner_settings;
22
-
23
- public function __construct(Xcloner $xcloner_container, $archive_name = "")
24
- {
25
- $this->filesystem = $xcloner_container->get_xcloner_filesystem();
26
- $this->logger = $xcloner_container->get_xcloner_logger()->withName("xcloner_archive");
27
- $this->xcloner_settings = $xcloner_container->get_xcloner_settings();
28
-
29
- if($value = $this->xcloner_settings->get_xcloner_option('xcloner_size_limit_per_request'))
30
- $this->file_size_per_request_limit = $value*1024*1024; //MB
31
-
32
- if($value = $this->xcloner_settings->get_xcloner_option('xcloner_files_to_process_per_request'))
33
- $this->files_to_process_per_request = $value;
34
-
35
- if($value = get_option('xcloner_backup_compression_level'))
36
- $this->compression_level = $value;
37
-
38
- if($value = get_option('xcloner_split_backup_limit'))
39
- $this->xcloner_split_backup_limit = $value;
40
-
41
- $this->xcloner_split_backup_limit = $this->xcloner_split_backup_limit * 1024*1024; //transform to bytes
42
-
43
- if(isset($archive_name) && $archive_name)
44
- {
45
- $this->set_archive_name($archive_name);
46
- }
47
- }
48
-
49
- /*
50
- *
51
- * Rename backup archive
52
- *
53
- */
54
- public function rename_archive($old_name, $new_name)
55
- {
56
- $this->logger->info(sprintf("Renaming backup archive %s to %s", $old_name, $new_name));
57
- $storage_filesystem = $this->filesystem->get_storage_filesystem();
58
- $storage_filesystem->rename($old_name, $new_name);
59
- }
60
-
61
- /*
62
- *
63
- * Set the backup archive name
64
- *
65
- */
66
- public function set_archive_name($name = "", $part = 0)
67
- {
68
-
69
- $this->archive_name = $this->filesystem->process_backup_name($name);
70
-
71
- if($diff_timestamp_start = $this->filesystem->get_diff_timestamp_start())
72
- {
73
- //$this->archive_name = $this->archive_name."-diff-".date("Y-m-d_H-i",$diff_timestamp_start);
74
- $new_name = $this->archive_name;
75
-
76
- if(!stristr($new_name, "-diff"))
77
- $new_name = $this->archive_name . "-diff".date("Y-m-d_H-i",$diff_timestamp_start);
78
-
79
- $this->archive_name = $new_name;
80
-
81
- }
82
-
83
- if(isset($part) and $part)
84
- {
85
- $new_name = preg_replace('/-part(\d*)/', "-part".$part, $this->archive_name);
86
- if(!stristr($new_name, "-part"))
87
- $new_name = $this->archive_name . "-part".$part;
88
-
89
- $this->archive_name = $new_name;
90
- }
91
-
92
- return $this;
93
- }
94
-
95
- /*
96
- *
97
- * Returns the backup archive name
98
- *
99
- */
100
- public function get_archive_name()
101
- {
102
- return $this->archive_name;
103
- }
104
-
105
- /*
106
- *
107
- * Returns the multipart naming for the backup archive
108
- *
109
- */
110
- public function get_archive_name_multipart()
111
- {
112
- $new_name = preg_replace('/-part(\d*)/', "", $this->archive_name);
113
- return $new_name."-multipart".$this->xcloner_settings->get_backup_extension_name(".csv");
114
- }
115
-
116
- /*
117
- *
118
- * Returns the full backup name including extension
119
- *
120
- */
121
- public function get_archive_name_with_extension()
122
- {
123
- return $this->archive_name.$this->xcloner_settings->get_backup_extension_name();
124
- }
125
-
126
- /*
127
- *
128
- * Send notification error by E-Mail
129
- *
130
- */
131
- public function send_notification_error($to, $from, $subject, $backup_name, $params, $error_message)
132
- {
133
-
134
- $body = "";
135
- $body .= sprintf(__("Backup Site Url: %s"), get_site_url());
136
- $body .= "<br /><>";
137
-
138
- $body .= sprintf(__("Error Message: %s"), $error_message);
139
-
140
- $this->logger->info(sprintf("Sending backup error notification to %s", $to));
141
-
142
- $admin_email = get_option("admin_email");
143
-
144
- $headers = array('Content-Type: text/html; charset=UTF-8');
145
-
146
- if($admin_email and $from )
147
- $headers[] = 'From: '.$from.' <'.$admin_email.'>';
148
-
149
- $return = wp_mail( $to, $subject, $body, $headers );
150
-
151
- return $return;
152
- }
153
-
154
- /*
155
- *
156
- * Send backup archive notfication by E-Mail
157
- *
158
- */
159
- public function send_notification($to, $from, $subject, $backup_name, $params, $error_message="", $additional = array())
160
- {
161
- if(!$from)
162
- {
163
- $from = "XCloner Backup";
164
- }
165
-
166
- if(($error_message))
167
- {
168
- return $this->send_notification_error($to, $from, $subject, $backup_name, $params, $error_message);
169
- }
170
-
171
- $params = (array)$params;
172
-
173
- if(!$subject)
174
- {
175
- $subject = sprintf(__("New backup generated %s") ,$backup_name);
176
- }
177
-
178
- $body = sprintf(__("Generated Backup Size: %s"), size_format($this->filesystem->get_backup_size($backup_name)));
179
- $body .= "<br /><br />";
180
-
181
- if(isset($additional['lines_total']))
182
- {
183
- $body .= sprintf(__("Total files added: %s"), $additional['lines_total']);
184
- $body .= "<br /><br />";
185
- }
186
-
187
- $backup_parts = $this->filesystem->get_multipart_files($backup_name);
188
-
189
- if(!$backups_counter = sizeof($backup_parts))
190
- $backups_counter = 1;
191
-
192
- $body .= sprintf(__("Backup Parts: %s"), $backups_counter);
193
- $body .= "<br />";
194
-
195
- if(sizeof($backup_parts))
196
- {
197
- $body .= implode("<br />",$backup_parts);
198
- $body .= "<br />";
199
- }
200
-
201
- $body.= "<br />";
202
-
203
- $body .= sprintf(__("Backup Site Url: %s"), get_site_url());
204
- $body .= "<br />";
205
-
206
- if(isset($params['backup_params']->backup_comments))
207
- {
208
- $body .= __("Backup Comments: ").$params['backup_params']->backup_comments;
209
- $body .= "<br /><br />";
210
- }
211
-
212
- if($this->xcloner_settings->get_xcloner_option('xcloner_enable_log'))
213
- $body .= __("Latest 50 Log Lines: ")."<br />".implode("<br />\n", $this->logger->getLastDebugLines(50));
214
-
215
- $attachments = $this->filesystem->get_backup_attachments();
216
-
217
- $attachments_archive = $this->xcloner_settings->get_xcloner_tmp_path().DS."info.tgz";
218
-
219
- $tar = new Tar();
220
- $tar->create($attachments_archive);
221
-
222
- foreach($attachments as $key => $file)
223
- {
224
- $tar->addFile($file, basename($file));
225
- }
226
- $tar->close();
227
-
228
- $this->logger->info(sprintf("Sending backup notification to %s", $to));
229
-
230
- $admin_email = get_option("admin_email");
231
-
232
- $headers = array('Content-Type: text/html; charset=UTF-8', 'From: '.$from.' <'.$admin_email.'>');
233
-
234
- $return = wp_mail( $to, $subject, $body, $headers, array($attachments_archive) );
235
-
236
- return $return;
237
- }
238
-
239
- /*
240
- *
241
- * Incremental Backup method
242
- *
243
- */
244
- public function start_incremental_backup($backup_params, $extra_params, $init)
245
- {
246
- $return = array();
247
-
248
- if(!isset($extra_params['backup_part']))
249
- $extra_params['backup_part'] = 0;
250
-
251
- $return['extra']['backup_part'] = $extra_params['backup_part'];
252
-
253
- if(isset( $extra_params['backup_archive_name']))
254
- $this->set_archive_name($extra_params['backup_archive_name'], $return['extra']['backup_part']);
255
- else
256
- $this->set_archive_name($backup_params['backup_name']);
257
-
258
- if(!$this->get_archive_name())
259
- $this->set_archive_name();
260
-
261
- $this->backup_archive = new Tar();
262
- $this->backup_archive->setCompression($this->compression_level);
263
-
264
- $archive_info = $this->filesystem->get_storage_path_file_info($this->get_archive_name_with_extension());
265
-
266
- if($init)
267
- {
268
- $this->logger->info(sprintf(__("Initializing the backup archive %s"), $this->get_archive_name()));
269
-
270
- $this->backup_archive->create($archive_info->getPath().DS.$archive_info->getFilename());
271
-
272
- $return['extra']['backup_init'] = 1;
273
-
274
- }else{
275
- $this->logger->info(sprintf(__("Opening for append the backup archive %s"), $this->get_archive_name()));
276
-
277
- $this->backup_archive->openForAppend($archive_info->getPath().DS.$archive_info->getFilename());
278
-
279
- $return['extra']['backup_init'] = 0;
280
-
281
- }
282
-
283
- $return['extra']['backup_archive_name'] = $this->get_archive_name();
284
- $return['extra']['backup_archive_name_full'] = $this->get_archive_name_with_extension();
285
-
286
- if(!isset($extra_params['start_at_line']))
287
- $extra_params['start_at_line'] = 0;
288
-
289
- if(!isset($extra_params['start_at_byte']))
290
- $extra_params['start_at_byte'] = 0;
291
-
292
- if(!$this->filesystem->get_tmp_filesystem()->has($this->filesystem->get_included_files_handler()))
293
- {
294
- $this->logger->error(sprintf("Missing the includes file handler %s, aborting...", $this->filesystem->get_included_files_handler()));
295
-
296
- $return['finished'] = 1;
297
- return $return;
298
- }
299
-
300
- $included_files_handler = $this->filesystem->get_included_files_handler(1);
301
-
302
- $file = new SplFileObject($included_files_handler);
303
-
304
- $file->seek(PHP_INT_MAX);
305
-
306
- $return['extra']['lines_total'] = ($file->key()-1);
307
-
308
- //we skip the first CSV line with headers
309
- if(!$extra_params['start_at_line'])
310
- {
311
- $file->seek(1);
312
- }else{
313
- $file->seek($extra_params['start_at_line']+1);
314
- }
315
-
316
- $this->processed_size_bytes = 0;
317
-
318
- $counter = 0;
319
-
320
- $start_byte = $extra_params['start_at_byte'];
321
-
322
- $byte_limit = 0;
323
-
324
- while(!$file->eof() and $counter<=$this->files_to_process_per_request)
325
- {
326
- $current_line_str = $file->current();
327
-
328
- $line = str_getcsv($current_line_str);
329
-
330
- $relative_path = stripslashes($line[0]);
331
-
332
- $start_filesystem = "start_filesystem";
333
-
334
- if(isset($line[4])){
335
- $start_filesystem = $line[4];
336
- }
337
-
338
- //$adapter = $this->filesystem->get_adapter($start_filesystem);
339
-
340
- if(!$relative_path || !$this->filesystem->get_filesystem($start_filesystem)->has($relative_path))
341
- {
342
- if($relative_path != "")
343
- {
344
- $this->logger->error(sprintf("Could not add file %b to backup archive, file not found", $relative_path));
345
- }
346
-
347
- $extra_params['start_at_line']++;
348
- $file->next();
349
- continue;
350
- }
351
-
352
- $file_info = $this->filesystem->get_filesystem($start_filesystem)->getMetadata($relative_path);
353
-
354
- if(!isset($file_info['size']))
355
- $file_info['size'] = 0;
356
-
357
- if($start_filesystem == "tmp_filesystem")
358
- {
359
- $file_info['archive_prefix_path'] = $this->xcloner_settings->get_xcloner_tmp_path_suffix();
360
- }
361
-
362
- $byte_limit = (int)$this->file_size_per_request_limit/512;
363
-
364
- $append = 0;
365
-
366
- if($file_info['size'] > $byte_limit*512 or $start_byte)
367
- $append = 1;
368
-
369
- if(!isset($return['extra']['backup_size']))
370
- $return['extra']['backup_size'] =0;
371
-
372
- $return['extra']['backup_size'] = $archive_info->getSize();
373
-
374
- $estimated_new_size = $return['extra']['backup_size'] + $file_info['size'];
375
-
376
- //we create a new backup part if we reach the Split Achive Limit
377
- if($this->xcloner_split_backup_limit and ($estimated_new_size > $this->xcloner_split_backup_limit) and (!$start_byte))
378
- {
379
- $this->logger->info(sprintf("Backup size limit %s bytes reached, file add estimate %s, attempt to create a new archive ",$this->xcloner_split_backup_limit, $estimated_new_size));
380
- list($archive_info, $return['extra']['backup_part']) = $this->create_new_backup_part($return['extra']['backup_part']);
381
-
382
- if($file_info['size'] > $this->xcloner_split_backup_limit)
383
- {
384
- $this->logger->info(sprintf("Excluding %s file as it's size(%s) is bigger than the backup split limit of %s and it won't fit a single backup file",$file_info['path'], $file_info['size'], $this->xcloner_split_backup_limit));
385
- $extra_params['start_at_line']++;
386
- }
387
-
388
- $return['extra']['start_at_line'] = $extra_params['start_at_line'];
389
- $return['extra']['start_at_byte'] = 0;
390
-
391
- $return['finished'] = 0;
392
-
393
- return $return;
394
- }
395
-
396
- list($bytes_wrote, $last_position) = $this->add_file_to_archive( $file_info, $start_byte, $byte_limit, $append, $start_filesystem);
397
- $this->processed_size_bytes += $bytes_wrote;
398
-
399
- //echo" - processed ".$this->processed_size_bytes." bytes ".$this->file_size_per_request_limit." last_position:".$last_position." \n";
400
- $return['extra']['processed_file'] = $file_info['path'];
401
- $return['extra']['processed_file_size'] = $file_info['size'];
402
- $return['extra']['backup_size'] = $archive_info->getSize();
403
-
404
- if($last_position>0){
405
- $start_byte = $last_position;
406
- }
407
- else{
408
- $extra_params['start_at_line']++;
409
- $file->next();
410
- $start_byte = 0;
411
- $counter++;
412
- }
413
-
414
- if($this->processed_size_bytes >= $this->file_size_per_request_limit)
415
- {
416
- clearstatcache();
417
- $return['extra']['backup_size'] = $archive_info->getSize();
418
-
419
- $return['finished'] = 0;
420
- $return['extra']['start_at_line'] = $extra_params['start_at_line'];
421
- $return['extra']['start_at_byte'] = $last_position;
422
- $this->logger->info(sprintf("Reached the maximum %s request data limit, returning response", $this->file_size_per_request_limit));
423
- return $return;
424
- }
425
- }
426
-
427
- if(!$file->eof())
428
- {
429
- clearstatcache();
430
- $return['extra']['backup_size'] = $archive_info->getSize();
431
-
432
- $return['finished'] = 0;
433
- $return['extra']['start_at_line'] = $extra_params['start_at_line'];
434
- $return['extra']['start_at_byte'] = $last_position;
435
- $this->logger->info(sprintf("We have reached the maximum files to process per request limit of %s, returning response", $this->files_to_process_per_request));
436
-
437
- return $return;
438
- }
439
-
440
- //close the backup archive by adding 2*512 blocks of zero bytes
441
- $this->logger->info(sprintf("Closing the backup archive %s with 2*512 zero bytes blocks.", $this->get_archive_name_with_extension()));
442
- $this->backup_archive->close();
443
-
444
- if($return['extra']['backup_part'])
445
- $this->write_multipart_file($this->get_archive_name_with_extension());
446
-
447
- $return['extra']['start_at_line'] = $extra_params['start_at_line']-1;
448
-
449
- if(isset($file_info))
450
- {
451
- $return['extra']['processed_file'] = $file_info['path'];
452
- $return['extra']['processed_file_size'] = $file_info['size'];
453
- }
454
-
455
- clearstatcache();
456
- $return['extra']['backup_size'] = $archive_info->getSize();
457
-
458
- $return['finished'] = 1;
459
- return $return;
460
- }
461
-
462
- /*
463
- *
464
- * Write multipart file components
465
- *
466
- */
467
- private function write_multipart_file($path)
468
- {
469
- $path = $this->get_archive_name_with_extension();
470
-
471
- $file = $this->filesystem->get_filesystem("storage_filesystem_append")->getMetadata($path);
472
- //print_r($file_info);
473
- $line = '"'.$file['path'].'","'.$file['timestamp'].'","'.$file['size'].'"'.PHP_EOL;
474
-
475
-
476
- $this->filesystem->get_filesystem("storage_filesystem_append")
477
- ->write($this->get_archive_name_multipart(), $line);
478
- }
479
-
480
- /*
481
- *
482
- * Create a new backup part
483
- *
484
- */
485
- private function create_new_backup_part($part = 0)
486
- {
487
- //close the backup archive by adding 2*512 blocks of zero bytes
488
- $this->logger->info(sprintf("Closing the backup archive %s with 2*512 zero bytes blocks.", $this->get_archive_name_with_extension()));
489
- $this->backup_archive->close();
490
-
491
- if(!$part)
492
- {
493
- $old_name = $this->get_archive_name_with_extension();
494
- $this->set_archive_name($this->get_archive_name(), ++$part);
495
- $this->rename_archive($old_name, $this->get_archive_name_with_extension());
496
-
497
- if($this->filesystem->get_storage_filesystem()->has($this->get_archive_name_multipart()))
498
- $this->filesystem->get_storage_filesystem()->delete($this->get_archive_name_multipart());
499
-
500
- $this->write_multipart_file($this->get_archive_name_with_extension());
501
-
502
- }else
503
- {
504
- $this->logger->info(sprintf("Creating new multipart info file %s",$this->get_archive_name_with_extension()));
505
- $this->write_multipart_file($this->get_archive_name_with_extension());
506
- }
507
-
508
- $this->set_archive_name($this->get_archive_name(), ++$part);
509
-
510
- $this->logger->info(sprintf("Creating new backup archive part %s", $this->get_archive_name_with_extension()));
511
-
512
- $this->backup_archive = new Tar();
513
- $this->backup_archive->setCompression($this->compression_level);
514
- $archive_info = $this->filesystem->get_storage_path_file_info($this->get_archive_name_with_extension());
515
- $this->backup_archive->create($archive_info->getPath().DS.$archive_info->getFilename());
516
-
517
- return array($archive_info, $part);
518
-
519
- }
520
-
521
- /*
522
- *
523
- * Add file to archive
524
- *
525
- */
526
- public function add_file_to_archive($file_info, $start_at_byte, $byte_limit = 0, $append, $filesystem)
527
- {
528
-
529
- $start_adapter = $this->filesystem->get_adapter($filesystem);
530
- $start_filesystem = $this->filesystem->get_adapter($filesystem);
531
-
532
- if(!$file_info['path'])
533
- return;
534
-
535
- if(isset($file_info['archive_prefix_path']))
536
- $file_info['target_path'] = $file_info['archive_prefix_path']."/".$file_info['path'];
537
- else
538
- $file_info['target_path'] = $file_info['path'];
539
-
540
- $last_position = $start_at_byte;
541
-
542
- //$start_adapter = $this->filesystem->get_start_adapter();
543
-
544
- if(!$append){
545
- $bytes_wrote = $file_info['size'];
546
- $this->logger->info(sprintf("Adding %s bytes of file %s to archive %s ", $bytes_wrote, $file_info['target_path'], $this->get_archive_name_with_extension()));
547
- $this->backup_archive->addFile($start_adapter->applyPathPrefix($file_info['path']), $file_info['target_path']);
548
- }
549
- else{
550
- $tmp_file = md5($file_info['path']);
551
-
552
- //we isolate file to tmp if we are at byte 0, the starting point of file reading
553
- if(!$start_at_byte)
554
- {
555
- $this->logger->info(sprintf("Copying %s file to tmp filesystem file %s to prevent reading changes", $file_info['path'], $tmp_file));
556
- $file_stream = $start_filesystem->readStream($file_info['path']);
557
-
558
- if(is_resource($file_stream['stream']))
559
- $this->filesystem->get_tmp_filesystem()->writeStream($tmp_file, $file_stream['stream']);
560
- }
561
-
562
- if($this->filesystem->get_tmp_filesystem()->has($tmp_file))
563
- {
564
- $is_tmp = 1;
565
- $last_position = $this->backup_archive->appendFileData($this->filesystem->get_tmp_filesystem_adapter()->applyPathPrefix($tmp_file), $file_info['target_path'], $start_at_byte, $byte_limit);
566
- }
567
- else{
568
- $is_tmp = 0;
569
- $last_position = $this->backup_archive->appendFileData($start_adapter->applyPathPrefix($file_info['path']), $file_info['target_path'], $start_at_byte, $byte_limit);
570
- }
571
-
572
-
573
- if($last_position == -1)
574
- {
575
- $bytes_wrote = $file_info['size'] - $start_at_byte;
576
- }
577
- else
578
- {
579
- $bytes_wrote = $last_position - $start_at_byte;
580
- }
581
-
582
-
583
- if($is_tmp)
584
- {
585
- $this->logger->info(sprintf("Appended %s bytes, starting position %s, of tmp file %s (%s) to archive %s ", $bytes_wrote, $start_at_byte, $tmp_file, $file_info['target_path'], $this->get_archive_name()));
586
- }
587
- else{
588
- $this->logger->info(sprintf("Appended %s bytes, starting position %s, of original file %s to archive %s ", $bytes_wrote, $start_at_byte, $file_info['target_path'], $tmp_file, $this->get_archive_name()));
589
- }
590
-
591
- //we delete here the isolated tmp file
592
- if($last_position == -1)
593
- {
594
- if($this->filesystem->get_tmp_filesystem_adapter()->has($tmp_file))
595
- {
596
- $this->logger->info(sprintf("Deleting %s from the tmp filesystem", $tmp_file));
597
- $this->filesystem->get_tmp_filesystem_adapter()->delete($tmp_file);
598
- }
599
- }
600
-
601
- }
602
-
603
- return array($bytes_wrote, $last_position);
604
- }
605
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
606
  /**
607
  * Open a TAR archive and put the file cursor at the end for data appending
608
  *
@@ -640,21 +753,22 @@ class Xcloner_Archive extends Tar
640
  $this->backup_archive->closed = false;
641
  }
642
  */
643
-
644
- /**
645
  * Append data to a file to the current TAR archive using an existing file in the filesystem
646
  *
647
- * @param string $file path to the original file
648
- * @param int $start starting reading position in file
649
- * @param int $end end position in reading multiple with 512
650
- * @param string|FileInfo $fileinfo either the name to us in archive (string) or a FileInfo oject with all meta data, empty to take from original
 
651
  * @throws ArchiveIOException
652
  */
653
  /*
654
  * public function appendFileData($file, $fileinfo = '', $start = 0, $limit = 0)
655
  {
656
  $end = $start+($limit*512);
657
-
658
  //check to see if we are at the begining of writing the file
659
  if(!$start)
660
  {
@@ -662,15 +776,15 @@ class Xcloner_Archive extends Tar
662
  $fileinfo = FileInfo::fromPath($file, $fileinfo);
663
  }
664
  }
665
-
666
  if ($this->closed) {
667
  throw new ArchiveIOException('Archive has been closed, files can no longer be added');
668
  }
669
 
670
  $fp = fopen($file, 'rb');
671
-
672
  fseek($fp, $start);
673
-
674
  if (!$fp) {
675
  throw new ArchiveIOException('Could not open file for reading: '.$file);
676
  }
@@ -678,7 +792,7 @@ class Xcloner_Archive extends Tar
678
  // create file header
679
  if(!$start)
680
  $this->backup_archive->writeFileHeader($fileinfo);
681
-
682
  $bytes = 0;
683
  // write data
684
  while ($end >=ftell($fp) and !feof($fp) ) {
@@ -692,33 +806,33 @@ class Xcloner_Archive extends Tar
692
  $packed = pack("a512", $data);
693
  $bytes += $this->backup_archive->writebytes($packed);
694
  }
695
-
696
-
697
-
698
  //if we are not at the end of file, we return the current position for incremental writing
699
  if(!feof($fp))
700
  $last_position = ftell($fp);
701
  else
702
  $last_position = -1;
703
-
704
  fclose($fp);
705
-
706
  return $last_position;
707
  }*/
708
-
709
  /**
710
  * Adds a file to a TAR archive by appending it's data
711
  *
712
- * @param string $archive name of the archive file
713
- * @param string $file name of the file to read data from
714
- * @param string $start start position from where to start reading data
715
  * @throws ArchiveIOException
716
  */
717
- /*public function addFileToArchive($archive, $file, $start = 0)
718
- {
719
- $this->openForAppend($archive);
720
- return $start = $this->appendFileData($file, $start, $this->file_size_per_request_limit);
721
- }
722
- */
723
 
724
  }
1
  <?php
2
+ /**
3
+ * XCloner - Backup and Restore backup plugin for Wordpress
4
+ *
5
+ * class-xcloner-archive.php
6
+ * @author Liuta Ovidiu <info@thinkovi.com>
7
+ *
8
+ * This program is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation; either version 2 of the License, or
11
+ * (at your option) any later version.
12
+ *
13
+ * This program is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ * GNU General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU General Public License
19
+ * along with this program; if not, write to the Free Software
20
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21
+ * MA 02110-1301, USA.
22
+ *
23
+ * @link https://github.com/ovidiul/XCloner-Wordpress
24
+ *
25
+ * @modified 7/31/18 3:10 PM
26
+ *
27
+ */
28
+
29
  use splitbrain\PHPArchive\Tar;
30
  use splitbrain\PHPArchive\Archive;
31
  use splitbrain\PHPArchive\FileInfo;
32
 
33
+ /**
34
+ * Class responsible for adding files to Tar
35
+ * Class Xcloner_Archive
36
+ */
37
  class Xcloner_Archive extends Tar
38
  {
39
+ /**
40
+ * Process file size per API request
41
+ * @var float|int
42
+ */
43
+ private $file_size_per_request_limit = 52428800; //50MB = 52428800; 1MB = 1048576
44
+ /**
45
+ * Files count to process per API request
46
+ * @var int
47
+ */
48
+ private $files_to_process_per_request = 250; //block of 512 bytes
49
+ /**
50
+ * Compression level, 0-uncompressed, 9-maximum compression
51
+ * @var int
52
+ */
53
+ private $compression_level = 0; //0-9 , 0 uncompressed
54
+ /**
55
+ * Split backup size limit
56
+ * Create a new backup archive file once the set size is reached
57
+ * @var float|int
58
+ */
59
+ private $xcloner_split_backup_limit = 2048; //2048MB
60
+ /**
61
+ * Number of processed bytes
62
+ * @var int
63
+ */
64
+ private $processed_size_bytes = 0;
65
+
66
+ /**
67
+ * Archive name
68
+ * @var string
69
+ */
70
+ private $archive_name;
71
+ /**
72
+ * @var Tar
73
+ */
74
+ private $backup_archive;
75
+ /**
76
+ * @var Xcloner_File_System
77
+ */
78
+ private $filesystem;
79
+ /**
80
+ * @var Xcloner_Logger
81
+ */
82
+ private $logger;
83
+ /**
84
+ * @var Xcloner_Settings
85
+ */
86
+ private $xcloner_settings;
87
+
88
+ /**
89
+ * [__construct description]
90
+ * @param Xcloner $xcloner_container XCloner Container
91
+ * @param string $archive_name Achive Name
92
+ */
93
+ public function __construct(Xcloner $xcloner_container, $archive_name = "")
94
+ {
95
+ $this->filesystem = $xcloner_container->get_xcloner_filesystem();
96
+ $this->logger = $xcloner_container->get_xcloner_logger()->withName("xcloner_archive");
97
+ $this->xcloner_settings = $xcloner_container->get_xcloner_settings();
98
+
99
+ if ($value = $this->xcloner_settings->get_xcloner_option('xcloner_size_limit_per_request')) {
100
+ $this->file_size_per_request_limit = $value * 1024 * 1024;
101
+ } //MB
102
+
103
+ if ($value = $this->xcloner_settings->get_xcloner_option('xcloner_files_to_process_per_request')) {
104
+ $this->files_to_process_per_request = $value;
105
+ }
106
+
107
+ if ($value = get_option('xcloner_backup_compression_level')) {
108
+ $this->compression_level = $value;
109
+ }
110
+
111
+ if ($value = get_option('xcloner_split_backup_limit')) {
112
+ $this->xcloner_split_backup_limit = $value;
113
+ }
114
+
115
+ $this->xcloner_split_backup_limit = $this->xcloner_split_backup_limit * 1024 * 1024; //transform to bytes
116
+
117
+ if (isset($archive_name) && $archive_name) {
118
+ $this->set_archive_name($archive_name);
119
+ }
120
+ }
121
+
122
+ /*
123
+ * Rename backup archive
124
+ *
125
+ * @param string $old_name
126
+ * @param string $new_name
127
+ *
128
+ */
129
+ public function rename_archive($old_name, $new_name)
130
+ {
131
+ $this->logger->info(sprintf("Renaming backup archive %s to %s", $old_name, $new_name));
132
+ $storage_filesystem = $this->filesystem->get_storage_filesystem();
133
+ $storage_filesystem->rename($old_name, $new_name);
134
+ }
135
+
136
+ /*
137
+ *
138
+ * Set the backup archive name
139
+ *
140
+ */
141
+ public function set_archive_name($name = "", $part = 0)
142
+ {
143
+
144
+ $this->archive_name = $this->filesystem->process_backup_name($name);
145
+
146
+ if ($diff_timestamp_start = $this->filesystem->get_diff_timestamp_start()) {
147
+ //$this->archive_name = $this->archive_name."-diff-".date("Y-m-d_H-i",$diff_timestamp_start);
148
+ $new_name = $this->archive_name;
149
+
150
+ if (!stristr($new_name, "-diff")) {
151
+ $new_name = $this->archive_name . "-diff" . date("Y-m-d_H-i", $diff_timestamp_start);
152
+ }
153
+
154
+ $this->archive_name = $new_name;
155
+
156
+ }
157
+
158
+ if (isset($part) and $part) {
159
+ $new_name = preg_replace('/-part(\d*)/', "-part" . $part, $this->archive_name);
160
+ if (!stristr($new_name, "-part")) {
161
+ $new_name = $this->archive_name . "-part" . $part;
162
+ }
163
+
164
+ $this->archive_name = $new_name;
165
+ }
166
+
167
+ return $this;
168
+ }
169
+
170
+ /*
171
+ *
172
+ * Returns the backup archive name
173
+ *
174
+ * @return string archive name
175
+ */
176
+ public function get_archive_name()
177
+ {
178
+ return $this->archive_name;
179
+ }
180
+
181
+ /*
182
+ *
183
+ * Returns the multipart naming for the backup archive
184
+ *
185
+ * @return string multi-part backup name
186
+ */
187
+ public function get_archive_name_multipart()
188
+ {
189
+ $new_name = preg_replace('/-part(\d*)/', "", $this->archive_name);
190
+ return $new_name . "-multipart" . $this->xcloner_settings->get_backup_extension_name(".csv");
191
+ }
192
+
193
+ /*
194
+ *
195
+ * Returns the full backup name including extension
196
+ *
197
+ */
198
+ public function get_archive_name_with_extension()
199
+ {
200
+ return $this->archive_name . $this->xcloner_settings->get_backup_extension_name();
201
+ }
202
+
203
+ /*
204
+ *
205
+ * Send notification error by E-Mail
206
+ *
207
+ * @param $to
208
+ * @param $from
209
+ * @param $subject
210
+ * @param $backup_name
211
+ * @param $params
212
+ * @param $error_message
213
+ *
214
+ * @return bool
215
+ */
216
+ public function send_notification_error($to, $from, $subject, $backup_name, $params, $error_message)
217
+ {
218
+
219
+ $body = "";
220
+ $body .= sprintf(__("Backup Site Url: %s"), get_site_url());
221
+ $body .= "<br /><>";
222
+
223
+ $body .= sprintf(__("Error Message: %s"), $error_message);
224
+
225
+ $this->logger->info(sprintf("Sending backup error notification to %s", $to));
226
+
227
+ $admin_email = get_option("admin_email");
228
+
229
+ $headers = array('Content-Type: text/html; charset=UTF-8');
230
+
231
+ if ($admin_email and $from) {
232
+ $headers[] = 'From: ' . $from . ' <' . $admin_email . '>';
233
+ }
234
+
235
+ $return = wp_mail($to, $subject, $body, $headers);
236
+
237
+ return $return;
238
+ }
239
+
240
+ /*
241
+ *
242
+ * Send backup archive notfication by E-Mail
243
+ *
244
+ * @param $to
245
+ * @param $from
246
+ * @param $subject
247
+ * @param $backup_name
248
+ * @param $params
249
+ * @param string $error_message
250
+ * @param array $additional
251
+ *
252
+ * @return bool
253
+ */
254
+ public function send_notification(
255
+ $to,
256
+ $from,
257
+ $subject,
258
+ $backup_name,
259
+ $params,
260
+ $error_message = "",
261
+ $additional = array()
262
+ ) {
263
+ if (!$from) {
264
+ $from = "XCloner Backup";
265
+ }
266
+
267
+ if (($error_message)) {
268
+ return $this->send_notification_error($to, $from, $subject, $backup_name, $params, $error_message);
269
+ }
270
+
271
+ $params = (array)$params;
272
+
273
+ if (!$subject) {
274
+ $subject = sprintf(__("New backup generated %s"), $backup_name);
275
+ }
276
+
277
+ $body = sprintf(__("Generated Backup Size: %s"), size_format($this->filesystem->get_backup_size($backup_name)));
278
+ $body .= "<br /><br />";
279
+
280
+ if (isset($additional['lines_total'])) {
281
+ $body .= sprintf(__("Total files added: %s"), $additional['lines_total']);
282
+ $body .= "<br /><br />";
283
+ }
284
+
285
+ $backup_parts = $this->filesystem->get_multipart_files($backup_name);
286
+
287
+ if (!$backups_counter = sizeof($backup_parts)) {
288
+ $backups_counter = 1;
289
+ }
290
+
291
+ $body .= sprintf(__("Backup Parts: %s"), $backups_counter);
292
+ $body .= "<br />";
293
+
294
+ if (sizeof($backup_parts)) {
295
+ $body .= implode("<br />", $backup_parts);
296
+ $body .= "<br />";
297
+ }
298
+
299
+ $body .= "<br />";
300
+
301
+ $body .= sprintf(__("Backup Site Url: %s"), get_site_url());
302
+ $body .= "<br />";
303
+
304
+ if (isset($params['backup_params']->backup_comments)) {
305
+ $body .= __("Backup Comments: ") . $params['backup_params']->backup_comments;
306
+ $body .= "<br /><br />";
307
+ }
308
+
309
+ if ($this->xcloner_settings->get_xcloner_option('xcloner_enable_log')) {
310
+ $body .= __("Latest 50 Log Lines: ") . "<br />" . implode("<br />\n",
311
+ $this->logger->getLastDebugLines(50));
312
+ }
313
+
314
+ $attachments = $this->filesystem->get_backup_attachments();
315
+
316
+ $attachments_archive = $this->xcloner_settings->get_xcloner_tmp_path() . DS . "info.tgz";
317
+
318
+ $tar = new Tar();
319
+ $tar->create($attachments_archive);
320
+
321
+ foreach ($attachments as $key => $file) {
322
+ $tar->addFile($file, basename($file));
323
+ }
324
+ $tar->close();
325
+
326
+ $this->logger->info(sprintf("Sending backup notification to %s", $to));
327
+
328
+ $admin_email = get_option("admin_email");
329
+
330
+ $headers = array('Content-Type: text/html; charset=UTF-8', 'From: ' . $from . ' <' . $admin_email . '>');
331
+
332
+ $return = wp_mail($to, $subject, $body, $headers, array($attachments_archive));
333
+
334
+ return $return;
335
+ }
336
+
337
+ /*
338
+ *
339
+ * Incremental Backup method
340
+ *
341
+ */
342
+ public function start_incremental_backup($backup_params, $extra_params, $init)
343
+ {
344
+ $return = array();
345
+
346
+ if (!isset($extra_params['backup_part'])) {
347
+ $extra_params['backup_part'] = 0;
348
+ }
349
+
350
+ $return['extra']['backup_part'] = $extra_params['backup_part'];
351
+
352
+ if (isset($extra_params['backup_archive_name'])) {
353
+ $this->set_archive_name($extra_params['backup_archive_name'], $return['extra']['backup_part']);
354
+ } else {
355
+ $this->set_archive_name($backup_params['backup_name']);
356
+ }
357
+
358
+ if (!$this->get_archive_name()) {
359
+ $this->set_archive_name();
360
+ }
361
+
362
+ $this->backup_archive = new Tar();
363
+ $this->backup_archive->setCompression($this->compression_level);
364
+
365
+ $archive_info = $this->filesystem->get_storage_path_file_info($this->get_archive_name_with_extension());
366
+
367
+ if ($init) {
368
+ $this->logger->info(sprintf(__("Initializing the backup archive %s"), $this->get_archive_name()));
369
+
370
+ $this->backup_archive->create($archive_info->getPath() . DS . $archive_info->getFilename());
371
+
372
+ $return['extra']['backup_init'] = 1;
373
+
374
+ } else {
375
+ $this->logger->info(sprintf(__("Opening for append the backup archive %s"), $this->get_archive_name()));
376
+
377
+ $this->backup_archive->openForAppend($archive_info->getPath() . DS . $archive_info->getFilename());
378
+
379
+ $return['extra']['backup_init'] = 0;
380
+
381
+ }
382
+
383
+ $return['extra']['backup_archive_name'] = $this->get_archive_name();
384
+ $return['extra']['backup_archive_name_full'] = $this->get_archive_name_with_extension();
385
+
386
+ if (!isset($extra_params['start_at_line'])) {
387
+ $extra_params['start_at_line'] = 0;
388
+ }
389
+
390
+ if (!isset($extra_params['start_at_byte'])) {
391
+ $extra_params['start_at_byte'] = 0;
392
+ }
393
+
394
+ if (!$this->filesystem->get_tmp_filesystem()->has($this->filesystem->get_included_files_handler())) {
395
+ $this->logger->error(sprintf("Missing the includes file handler %s, aborting...",
396
+ $this->filesystem->get_included_files_handler()));
397
+
398
+ $return['finished'] = 1;
399
+ return $return;
400
+ }
401
+
402
+ $included_files_handler = $this->filesystem->get_included_files_handler(1);
403
+
404
+ $file = new SplFileObject($included_files_handler);
405
+
406
+ $file->seek(PHP_INT_MAX);
407
+
408
+ $return['extra']['lines_total'] = ($file->key() - 1);
409
+
410
+ //we skip the first CSV line with headers
411
+ if (!$extra_params['start_at_line']) {
412
+ $file->seek(1);
413
+ } else {
414
+ $file->seek($extra_params['start_at_line'] + 1);
415
+ }
416
+
417
+ $this->processed_size_bytes = 0;
418
+
419
+ $counter = 0;
420
+
421
+ $start_byte = $extra_params['start_at_byte'];
422
+
423
+ $byte_limit = 0;
424
+
425
+ while (!$file->eof() and $counter <= $this->files_to_process_per_request) {
426
+ $current_line_str = $file->current();
427
+
428
+ $line = str_getcsv($current_line_str);
429
+
430
+ $relative_path = stripslashes($line[0]);
431
+
432
+ $start_filesystem = "start_filesystem";
433
+
434
+ if (isset($line[4])) {
435
+ $start_filesystem = $line[4];
436
+ }
437
+
438
+ //$adapter = $this->filesystem->get_adapter($start_filesystem);
439
+
440
+ if (!$relative_path || !$this->filesystem->get_filesystem($start_filesystem)->has($relative_path)) {
441
+ if ($relative_path != "") {
442
+ $this->logger->error(sprintf("Could not add file %b to backup archive, file not found",
443
+ $relative_path));
444
+ }
445
+
446
+ $extra_params['start_at_line']++;
447
+ $file->next();
448
+ continue;
449
+ }
450
+
451
+ $file_info = $this->filesystem->get_filesystem($start_filesystem)->getMetadata($relative_path);
452
+
453
+ if (!isset($file_info['size'])) {
454
+ $file_info['size'] = 0;
455
+ }
456
+
457
+ if ($start_filesystem == "tmp_filesystem") {
458
+ $file_info['archive_prefix_path'] = $this->xcloner_settings->get_xcloner_tmp_path_suffix();
459
+ }
460
+
461
+ $byte_limit = (int)$this->file_size_per_request_limit / 512;
462
+
463
+ $append = 0;
464
+
465
+ if ($file_info['size'] > $byte_limit * 512 or $start_byte) {
466
+ $append = 1;
467
+ }
468
+
469
+ if (!isset($return['extra']['backup_size'])) {
470
+ $return['extra']['backup_size'] = 0;
471
+ }
472
+
473
+ $return['extra']['backup_size'] = $archive_info->getSize();
474
+
475
+ $estimated_new_size = $return['extra']['backup_size'] + $file_info['size'];
476
+
477
+ //we create a new backup part if we reach the Split Achive Limit
478
+ if ($this->xcloner_split_backup_limit and ($estimated_new_size > $this->xcloner_split_backup_limit) and (!$start_byte)) {
479
+ $this->logger->info(sprintf("Backup size limit %s bytes reached, file add estimate %s, attempt to create a new archive ",
480
+ $this->xcloner_split_backup_limit, $estimated_new_size));
481
+ list($archive_info, $return['extra']['backup_part']) = $this->create_new_backup_part($return['extra']['backup_part']);
482
+
483
+ if ($file_info['size'] > $this->xcloner_split_backup_limit) {
484
+ $this->logger->info(sprintf("Excluding %s file as it's size(%s) is bigger than the backup split limit of %s and it won't fit a single backup file",
485
+ $file_info['path'], $file_info['size'], $this->xcloner_split_backup_limit));
486
+ $extra_params['start_at_line']++;
487
+ }
488
+
489
+ $return['extra']['start_at_line'] = $extra_params['start_at_line'];
490
+ $return['extra']['start_at_byte'] = 0;
491
+
492
+ $return['finished'] = 0;
493
+
494
+ return $return;
495
+ }
496
+
497
+ list($bytes_wrote, $last_position) = $this->add_file_to_archive($file_info, $start_byte, $byte_limit,
498
+ $append, $start_filesystem);
499
+ $this->processed_size_bytes += $bytes_wrote;
500
+
501
+ //echo" - processed ".$this->processed_size_bytes." bytes ".$this->file_size_per_request_limit." last_position:".$last_position." \n";
502
+ $return['extra']['processed_file'] = $file_info['path'];
503
+ $return['extra']['processed_file_size'] = $file_info['size'];
504
+ $return['extra']['backup_size'] = $archive_info->getSize();
505
+
506
+ if ($last_position > 0) {
507
+ $start_byte = $last_position;
508
+ } else {
509
+ $extra_params['start_at_line']++;
510
+ $file->next();
511
+ $start_byte = 0;
512
+ $counter++;
513
+ }
514
+
515
+ if ($this->processed_size_bytes >= $this->file_size_per_request_limit) {
516
+ clearstatcache();
517
+ $return['extra']['backup_size'] = $archive_info->getSize();
518
+
519
+ $return['finished'] = 0;
520
+ $return['extra']['start_at_line'] = $extra_params['start_at_line'];
521
+ $return['extra']['start_at_byte'] = $last_position;
522
+ $this->logger->info(sprintf("Reached the maximum %s request data limit, returning response",
523
+ $this->file_size_per_request_limit));
524
+ return $return;
525
+ }
526
+ }
527
+
528
+ if (!$file->eof()) {
529
+ clearstatcache();
530
+ $return['extra']['backup_size'] = $archive_info->getSize();
531
+
532
+ $return['finished'] = 0;
533
+ $return['extra']['start_at_line'] = $extra_params['start_at_line'];
534
+ $return['extra']['start_at_byte'] = $last_position;
535
+ $this->logger->info(sprintf("We have reached the maximum files to process per request limit of %s, returning response",
536
+ $this->files_to_process_per_request));
537
+
538
+ return $return;
539
+ }
540
+
541
+ //close the backup archive by adding 2*512 blocks of zero bytes
542
+ $this->logger->info(sprintf("Closing the backup archive %s with 2*512 zero bytes blocks.",
543
+ $this->get_archive_name_with_extension()));
544
+ $this->backup_archive->close();
545
+
546
+ /**
547
+ * XCloner HOOK backup_archive_finished.
548
+ *
549
+ * This will get triggered when a backup archive is finished writing.
550
+ */
551
+ //do_action('backup_archive_finished', $this->backup_archive, $this);
552
+
553
+ //updating archive_info
554
+ $archive_info = $this->filesystem->get_storage_path_file_info($this->get_archive_name_with_extension());
555
+
556
+ if ($return['extra']['backup_part']) {
557
+ $this->write_multipart_file($this->get_archive_name_with_extension());
558
+ }
559
+
560
+ $return['extra']['start_at_line'] = $extra_params['start_at_line'] - 1;
561
+
562
+ if (isset($file_info)) {
563
+ $return['extra']['processed_file'] = $file_info['path'];
564
+ $return['extra']['processed_file_size'] = $file_info['size'];
565
+ }
566
+
567
+ clearstatcache();
568
+ $return['extra']['backup_size'] = $archive_info->getSize();
569
+
570
+ $return['finished'] = 1;
571
+ return $return;
572
+ }
573
+
574
+ /*
575
+ *
576
+ * Write multipart file components
577
+ *
578
+ */
579
+ private function write_multipart_file($path)
580
+ {
581
+ $path = $this->get_archive_name_with_extension();
582
+
583
+ $file = $this->filesystem->get_filesystem("storage_filesystem_append")->getMetadata($path);
584
+ //print_r($file_info);
585
+ $line = '"' . $file['path'] . '","' . $file['timestamp'] . '","' . $file['size'] . '"' . PHP_EOL;
586
+
587
+
588
+ $this->filesystem->get_filesystem("storage_filesystem_append")
589
+ ->write($this->get_archive_name_multipart(), $line);
590
+ }
591
+
592
+ /*
593
+ *
594
+ * Create a new backup part
595
+ *
596
+ */
597
+ private function create_new_backup_part($part = 0)
598
+ {
599
+ //close the backup archive by adding 2*512 blocks of zero bytes
600
+ $this->logger->info(sprintf("Closing the backup archive %s with 2*512 zero bytes blocks.",
601
+ $this->get_archive_name_with_extension()));
602
+ $this->backup_archive->close();
603
+
604
+ if (!$part) {
605
+ $old_name = $this->get_archive_name_with_extension();
606
+ $this->set_archive_name($this->get_archive_name(), ++$part);
607
+ $this->rename_archive($old_name, $this->get_archive_name_with_extension());
608
+
609
+ if ($this->filesystem->get_storage_filesystem()->has($this->get_archive_name_multipart())) {
610
+ $this->filesystem->get_storage_filesystem()->delete($this->get_archive_name_multipart());
611
+ }
612
+
613
+ $this->write_multipart_file($this->get_archive_name_with_extension());
614
+
615
+ } else {
616
+ $this->logger->info(sprintf("Creating new multipart info file %s",
617
+ $this->get_archive_name_with_extension()));
618
+ $this->write_multipart_file($this->get_archive_name_with_extension());
619
+ }
620
+
621
+ $this->set_archive_name($this->get_archive_name(), ++$part);
622
+
623
+ $this->logger->info(sprintf("Creating new backup archive part %s", $this->get_archive_name_with_extension()));
624
+
625
+ $this->backup_archive = new Tar();
626
+ $this->backup_archive->setCompression($this->compression_level);
627
+ $archive_info = $this->filesystem->get_storage_path_file_info($this->get_archive_name_with_extension());
628
+ $this->backup_archive->create($archive_info->getPath() . DS . $archive_info->getFilename());
629
+
630
+ return array($archive_info, $part);
631
+
632
+ }
633
+
634
+ /*
635
+ *
636
+ * Add file to archive
637
+ *
638
+ */
639
+ public function add_file_to_archive($file_info, $start_at_byte, $byte_limit = 0, $append, $filesystem)
640
+ {
641
+
642
+ $start_adapter = $this->filesystem->get_adapter($filesystem);
643
+ $start_filesystem = $this->filesystem->get_adapter($filesystem);
644
+
645
+ if (!$file_info['path']) {
646
+ return;
647
+ }
648
+
649
+ if (isset($file_info['archive_prefix_path'])) {
650
+ $file_info['target_path'] = $file_info['archive_prefix_path'] . "/" . $file_info['path'];
651
+ } else {
652
+ $file_info['target_path'] = $file_info['path'];
653
+ }
654
+
655
+ $last_position = $start_at_byte;
656
+
657
+ //$start_adapter = $this->filesystem->get_start_adapter();
658
+
659
+ if (!$append) {
660
+ $bytes_wrote = $file_info['size'];
661
+ $this->logger->info(sprintf("Adding %s bytes of file %s to archive %s ", $bytes_wrote,
662
+ $file_info['target_path'], $this->get_archive_name_with_extension()));
663
+ $this->backup_archive->addFile($start_adapter->applyPathPrefix($file_info['path']),
664
+ $file_info['target_path']);
665
+ } else {
666
+ $tmp_file = md5($file_info['path']);
667
+
668
+ //we isolate file to tmp if we are at byte 0, the starting point of file reading
669
+ if (!$start_at_byte) {
670
+ $this->logger->info(sprintf("Copying %s file to tmp filesystem file %s to prevent reading changes",
671
+ $file_info['path'], $tmp_file));
672
+ $file_stream = $start_filesystem->readStream($file_info['path']);
673
+
674
+ if (is_resource($file_stream['stream'])) {
675
+ $this->filesystem->get_tmp_filesystem()->writeStream($tmp_file, $file_stream['stream']);
676
+ }
677
+ }
678
+
679
+ if ($this->filesystem->get_tmp_filesystem()->has($tmp_file)) {
680
+ $is_tmp = 1;
681
+ $last_position = $this->backup_archive->appendFileData($this->filesystem->get_tmp_filesystem_adapter()
682
+ ->applyPathPrefix($tmp_file),
683
+ $file_info['target_path'], $start_at_byte, $byte_limit);
684
+ } else {
685
+ $is_tmp = 0;
686
+ $last_position = $this->backup_archive->appendFileData($start_adapter->applyPathPrefix($file_info['path']),
687
+ $file_info['target_path'], $start_at_byte, $byte_limit);
688
+ }
689
+
690
+
691
+ if ($last_position == -1) {
692
+ $bytes_wrote = $file_info['size'] - $start_at_byte;
693
+ } else {
694
+ $bytes_wrote = $last_position - $start_at_byte;
695
+ }
696
+
697
+
698
+ if ($is_tmp) {
699
+ $this->logger->info(sprintf("Appended %s bytes, starting position %s, of tmp file %s (%s) to archive %s ",
700
+ $bytes_wrote, $start_at_byte, $tmp_file, $file_info['target_path'], $this->get_archive_name()));
701
+ } else {
702
+ $this->logger->info(sprintf("Appended %s bytes, starting position %s, of original file %s to archive %s ",
703
+ $bytes_wrote, $start_at_byte, $file_info['target_path'], $tmp_file, $this->get_archive_name()));
704
+ }
705
+
706
+ //we delete here the isolated tmp file
707
+ if ($last_position == -1) {
708
+ if ($this->filesystem->get_tmp_filesystem_adapter()->has($tmp_file)) {
709
+ $this->logger->info(sprintf("Deleting %s from the tmp filesystem", $tmp_file));
710
+ $this->filesystem->get_tmp_filesystem_adapter()->delete($tmp_file);
711
+ }
712
+ }
713
+
714
+ }
715
+
716
+ return array($bytes_wrote, $last_position);
717
+ }
718
+
719
  /**
720
  * Open a TAR archive and put the file cursor at the end for data appending
721
  *
753
  $this->backup_archive->closed = false;
754
  }
755
  */
756
+
757
+ /**
758
  * Append data to a file to the current TAR archive using an existing file in the filesystem
759
  *
760
+ * @param string $file path to the original file
761
+ * @param int $start starting reading position in file
762
+ * @param int $end end position in reading multiple with 512
763
+ * @param string|FileInfo $fileinfo either the name to us in archive (string) or a FileInfo oject with
764
+ * all meta data, empty to take from original
765
  * @throws ArchiveIOException
766
  */
767
  /*
768
  * public function appendFileData($file, $fileinfo = '', $start = 0, $limit = 0)
769
  {
770
  $end = $start+($limit*512);
771
+
772
  //check to see if we are at the begining of writing the file
773
  if(!$start)
774
  {
776
  $fileinfo = FileInfo::fromPath($file, $fileinfo);
777
  }
778
  }
779
+
780
  if ($this->closed) {
781
  throw new ArchiveIOException('Archive has been closed, files can no longer be added');
782
  }
783
 
784
  $fp = fopen($file, 'rb');
785
+
786
  fseek($fp, $start);
787
+
788
  if (!$fp) {
789
  throw new ArchiveIOException('Could not open file for reading: '.$file);
790
  }
792
  // create file header
793
  if(!$start)
794
  $this->backup_archive->writeFileHeader($fileinfo);
795
+
796
  $bytes = 0;
797
  // write data
798
  while ($end >=ftell($fp) and !feof($fp) ) {
806
  $packed = pack("a512", $data);
807
  $bytes += $this->backup_archive->writebytes($packed);
808
  }
809
+
810
+
811
+
812
  //if we are not at the end of file, we return the current position for incremental writing
813
  if(!feof($fp))
814
  $last_position = ftell($fp);
815
  else
816
  $last_position = -1;
817
+
818
  fclose($fp);
819
+
820
  return $last_position;
821
  }*/
822
+
823
  /**
824
  * Adds a file to a TAR archive by appending it's data
825
  *
826
+ * @param string $archive name of the archive file
827
+ * @param string $file name of the file to read data from
828
+ * @param string $start start position from where to start reading data
829
  * @throws ArchiveIOException
830
  */
831
+ /*public function addFileToArchive($archive, $file, $start = 0)
832
+ {
833
+ $this->openForAppend($archive);
834
+ return $start = $this->appendFileData($file, $start, $this->file_size_per_request_limit);
835
+ }
836
+ */
837
 
838
  }
includes/class-xcloner-deactivator.php CHANGED
@@ -1,13 +1,29 @@
1
  <?php
2
-
3
  /**
4
- * Fired during plugin deactivation
5
  *
6
- * @link http://www.thinkovi.com
7
- * @since 1.0.0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  *
9
- * @package Xcloner
10
- * @subpackage Xcloner/includes
11
  */
12
 
13
  /**
@@ -19,7 +35,9 @@
19
  * @package Xcloner
20
  * @subpackage Xcloner/includes
21
  * @author Liuta Ovidiu <info@thinkovi.com>
 
22
  */
 
23
  class Xcloner_Deactivator {
24
 
25
  /**
@@ -30,18 +48,16 @@ class Xcloner_Deactivator {
30
  * @since 1.0.0
31
  */
32
  public static function deactivate() {
33
-
34
  global $xcloner_plugin;
35
-
36
- if(is_a($xcloner_plugin, 'Xcloner'))
37
- {
38
- try{
39
  $xcloner_plugin->get_xcloner_filesystem()->cleanup_tmp_directories();
40
- }catch(Exception $e)
41
- {
42
- $xcloner_plugin->trigger_message_notice($e->getMessage());
43
  }
44
-
45
  $xcloner_scheduler = $xcloner_plugin->get_xcloner_scheduler();
46
  $xcloner_scheduler->deactivate_wp_cron_hooks();
47
  }
1
  <?php
 
2
  /**
3
+ * XCloner - Backup and Restore backup plugin for Wordpress
4
  *
5
+ * class-xcloner-deactivator.php
6
+ * @author Liuta Ovidiu <info@thinkovi.com>
7
+ *
8
+ * This program is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation; either version 2 of the License, or
11
+ * (at your option) any later version.
12
+ *
13
+ * This program is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ * GNU General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU General Public License
19
+ * along with this program; if not, write to the Free Software
20
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21
+ * MA 02110-1301, USA.
22
+ *
23
+ * @link https://github.com/ovidiul/XCloner-Wordpress
24
+ *
25
+ * @modified 7/31/18 3:28 PM
26
  *
 
 
27
  */
28
 
29
  /**
35
  * @package Xcloner
36
  * @subpackage Xcloner/includes
37
  * @author Liuta Ovidiu <info@thinkovi.com>
38
+ * @link http://www.thinkovi.com
39
  */
40
+
41
  class Xcloner_Deactivator {
42
 
43
  /**
48
  * @since 1.0.0
49
  */
50
  public static function deactivate() {
51
+
52
  global $xcloner_plugin;
53
+
54
+ if ( is_a( $xcloner_plugin, 'Xcloner' ) ) {
55
+ try {
 
56
  $xcloner_plugin->get_xcloner_filesystem()->cleanup_tmp_directories();
57
+ } catch ( Exception $e ) {
58
+ $xcloner_plugin->trigger_message_notice( $e->getMessage() );
 
59
  }
60
+
61
  $xcloner_scheduler = $xcloner_plugin->get_xcloner_scheduler();
62
  $xcloner_scheduler->deactivate_wp_cron_hooks();
63
  }
includes/class-xcloner-file-system.php CHANGED
@@ -1,992 +1,1072 @@
1
  <?php
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  use League\Flysystem\Config;
3
  use League\Flysystem\Filesystem;
4
  use League\Flysystem\Util;
5
  use League\Flysystem\Adapter\Local;
6
 
7
- class Xcloner_File_System{
8
-
9
- private $excluded_files = "";
10
- private $additional_regex_patterns = array();
11
- private $excluded_files_by_default = array("administrator/backups", "wp-content/backups");
12
- private $included_files_handler = "backup_files.csv";
13
- private $temp_dir_handler = ".dir";
14
- public $filesystem;
15
- public $tmp_filesystem;
16
- public $storage_filesystem;
17
- private $xcloner_settings_append;
18
- private $xcloner_container;
19
- private $diff_timestamp_start = "";
20
-
21
- private $logger;
22
- private $start_adapter;
23
- private $tmp_adapter;
24
- private $storage_adapter;
25
- private $xcloner_requirements;
26
- private $xcloner_settings;
27
- private $start_filesystem;
28
- private $tmp_filesystem_append;
29
- private $storage_filesystem_append;
30
-
31
- private $files_counter;
32
- private $files_size;
33
- private $last_logged_file;
34
- private $folders_to_process_per_session = 25;
35
- private $backup_archive_extensions = array("tar", "tgz", "tar.gz", "gz", "csv");
36
- private $backup_name_tags = array('[time]', '[hostname]', '[domain]');
37
-
38
- public function __construct(Xcloner $xcloner_container, $hash = "")
39
- {
40
- $this->xcloner_container = $xcloner_container;
41
-
42
- $this->logger = $xcloner_container->get_xcloner_logger()->withName("xcloner_file_system");
43
- $this->xcloner_settings = $xcloner_container->get_xcloner_settings();
44
-
45
- try{
46
-
47
- $this->start_adapter = new Local($this->xcloner_settings->get_xcloner_start_path(),LOCK_EX, 'SKIP_LINKS');
48
- $this->start_filesystem = new Filesystem($this->start_adapter, new Config([
49
- 'disable_asserts' => true,
50
- ]));
51
-
52
- $this->tmp_adapter = new Local($this->xcloner_settings->get_xcloner_tmp_path(),LOCK_EX, 'SKIP_LINKS');
53
- $this->tmp_filesystem = new Filesystem($this->tmp_adapter, new Config([
54
- 'disable_asserts' => true,
55
- ]));
56
- $adapter = new Local($this->xcloner_settings->get_xcloner_tmp_path(),LOCK_EX|FILE_APPEND, 'SKIP_LINKS');
57
- $this->tmp_filesystem_append = new Filesystem($adapter, new Config([
58
- 'disable_asserts' => true,
59
- ]));
60
-
61
- $adapter = new Local($this->xcloner_settings->get_xcloner_store_path(),LOCK_EX, 'SKIP_LINKS');
62
- $this->storage_filesystem = new Filesystem($adapter, new Config([
63
- 'disable_asserts' => true,
64
- ]));
65
-
66
- $this->storage_adapter = new Local($this->xcloner_settings->get_xcloner_store_path(),FILE_APPEND, 'SKIP_LINKS');
67
- $this->storage_filesystem_append = new Filesystem($this->storage_adapter, new Config([
68
- 'disable_asserts' => true,
69
- ]));
70
- }catch(Exception $e){
71
- $this->logger->error("Filesystem Initialization Error: ".$e->getMessage());
72
- }
73
-
74
-
75
- if($value = get_option('xcloner_directories_to_scan_per_request'))
76
- $this->folders_to_process_per_session = $value;
77
-
78
- }
79
-
80
- public function set_diff_timestamp_start($timestamp = "")
81
- {
82
- if($timestamp)
83
- {
84
- $this->logger->info(sprintf("Setting Differential Timestamp To %s", date("Y-m-d", $timestamp)), array("FILESYSTEM", "DIFF"));
85
- $this->diff_timestamp_start = $timestamp;
86
- }
87
- }
88
-
89
- public function get_diff_timestamp_start()
90
- {
91
- return $this->diff_timestamp_start;
92
- }
93
-
94
- private function get_xcloner_container()
95
- {
96
- return $this->xcloner_container;
97
- }
98
-
99
-
100
- public function set_hash($hash)
101
- {
102
- $this->xcloner_settings->set_hash($hash);
103
- }
104
-
105
- public function get_hash($hash)
106
- {
107
- $this->xcloner_settings->get_hash();
108
- }
109
-
110
- public function get_tmp_filesystem()
111
- {
112
- return $this->tmp_filesystem;
113
- }
114
-
115
- public function get_storage_filesystem($remote_storage_selection = "")
116
- {
117
- if($remote_storage_selection != "")
118
- {
119
- $remote_storage = $this->get_xcloner_container()->get_xcloner_remote_storage();
120
- $method = "get_".$remote_storage_selection."_filesystem";
121
-
122
- if(!method_exists($remote_storage, $method))
123
- return false;
124
-
125
- list($adapter, $filesystem) = $remote_storage->$method();
126
-
127
- return $filesystem;
128
- }
129
-
130
- return $this->storage_filesystem;
131
- }
132
-
133
- public function get_tmp_filesystem_adapter()
134
- {
135
- return $this->tmp_adapter;
136
- }
137
-
138
- public function get_tmp_filesystem_append()
139
- {
140
- return $this->tmp_filesystem_append;
141
- }
142
-
143
- public function get_start_adapter()
144
- {
145
- return $this->start_adapter;
146
- }
147
-
148
- public function get_start_filesystem()
149
- {
150
- return $this->start_filesystem;
151
- }
152
-
153
- public function get_logger()
154
- {
155
- return $this->logger;
156
- }
157
-
158
- public function get_start_path_file_info($file)
159
- {
160
- $info= $this->getMetadataFull('start_adapter', $file);
161
- return $this->start_filesystem->normalizeFileInfo($info);
162
- }
163
-
164
- public function get_storage_path_file_info($file)
165
- {
166
- return $this->getMetadataFull('storage_adapter', $file);
167
- }
168
-
169
- public function get_included_files_handler($metadata = 0)
170
- {
171
- $path = $this->included_files_handler;
172
- if(!$metadata)
173
- return $path;
174
-
175
- $spl_info = $this->getMetadataFull('tmp_adapter', $path);
176
- return $spl_info;
177
-
178
- }
179
-
180
- public function get_temp_dir_handler()
181
- {
182
- return $this->temp_dir_handler;
183
- }
184
-
185
- public function get_latest_backup()
186
- {
187
- $files = $this->get_backup_archives_list();
188
-
189
- if(is_array($files))
190
- $this->sort_by($files, "timestamp","desc");
191
-
192
- $new_list = array();
193
-
194
- foreach($files as $key=>$file)
195
- if(!isset($file['parent']))
196
- $new_list[] = ($files[$key]);
197
-
198
- if(isset($new_list[0]))
199
- return $new_list[0];
200
- }
201
-
202
- public function get_latest_backups()
203
- {
204
- $files = $this->get_backup_archives_list();
205
-
206
- if(is_array($files))
207
- $this->sort_by($files, "timestamp","desc");
208
-
209
- $new_list = array();
210
-
211
- foreach($files as $key=>$file)
212
- if(!isset($file['parent']))
213
- $new_list[] = ($files[$key]);
214
-
215
- return $new_list;
216
- }
217
-
218
- public function get_storage_usage()
219
- {
220
- $files = $this->get_backup_archives_list();
221
- $total = 0;
222
-
223
- if(is_array($files))
224
- foreach($files as $file)
225
- $total += $file['size'];
226
-
227
- return $total;
228
- }
229
-
230
- public function is_part($backup_name)
231
- {
232
- if(stristr($backup_name, "-part"))
233
- return true;
234
-
235
- return false;
236
- }
237
-
238
- public function is_multipart($backup_name)
239
- {
240
- if(stristr($backup_name, "-multipart"))
241
- return true;
242
-
243
- return false;
244
- }
245
-
246
- public function get_backup_size($backup_name)
247
- {
248
- $backup_size = $this->get_storage_filesystem()->getSize($backup_name);
249
- if($this->is_multipart($backup_name))
250
- {
251
- $backup_parts = $this->get_multipart_files($backup_name);
252
- foreach($backup_parts as $part_file)
253
- $backup_size += $this->get_storage_filesystem()->getSize($part_file);
254
- }
255
-
256
- return $backup_size;
257
- }
258
-
259
- public function get_multipart_files($backup_name, $storage_selection = "")
260
- {
261
- $files = array();
262
-
263
- if($this->is_multipart($backup_name))
264
- {
265
- $lines = explode(PHP_EOL, $this->get_storage_filesystem($storage_selection)->read($backup_name));
266
- foreach($lines as $line)
267
- {
268
- if($line)
269
- {
270
- $data = str_getcsv($line);
271
- $files[] = $data[0];
272
- }
273
- }
274
- }
275
-
276
- return $files;
277
- }
278
-
279
- public function delete_backup_by_name($backup_name, $storage_selection = "")
280
- {
281
- if($this->is_multipart($backup_name))
282
- {
283
- $lines = explode(PHP_EOL, $this->get_storage_filesystem($storage_selection)->read($backup_name));
284
- foreach($lines as $line)
285
- {
286
- if($line)
287
- {
288
- $data = str_getcsv($line);
289
- $this->get_storage_filesystem($storage_selection)->delete($data[0]);
290
- }
291
- }
292
- }
293
-
294
- if($this->get_storage_filesystem($storage_selection)->delete($backup_name))
295
- $return = true;
296
- else
297
- $return = false;
298
-
299
- return $return;
300
- }
301
-
302
- public function getMetadataFull($adapter = "storage_adapter" , $path)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
303
  {
304
  $location = $this->$adapter->applyPathPrefix($path);
305
  $spl_info = new SplFileInfo($location);
306
-
307
  return ($spl_info);
308
  }
309
-
310
-
311
- public function get_backup_archives_list($storage_selection = "")
312
- {
313
- $list = array();
314
-
315
-
316
- if(method_exists($this->get_storage_filesystem($storage_selection), "listContents"))
317
- $list = $this->get_storage_filesystem($storage_selection)->listContents();
318
-
319
-
320
- $backup_files = array();
321
- $parents = array();
322
-
323
- foreach($list as $file_info)
324
- {
325
- if(isset($file_info['extension']) and $file_info['extension'] == "csv")
326
- {
327
- $data = array();
328
-
329
- $lines = explode(PHP_EOL, $this->get_storage_filesystem($storage_selection)->read($file_info['path']));
330
- foreach($lines as $line)
331
- if($line)
332
- {
333
- $data = str_getcsv($line);
334
- if(is_array($data)){
335
- $parents[$data[0]] = $file_info['basename'];
336
- $file_info['childs'][] = $data;
337
- $file_info['size'] += $data[2];
338
- }
339
- }
340
-
341
- }
342
-
343
- if($file_info['type'] == 'file' and isset($file_info['extension']) and in_array($file_info['extension'], $this->backup_archive_extensions))
344
- $backup_files[$file_info['path']] = $file_info;
345
- }
346
-
347
- foreach($backup_files as $key=>$file_info)
348
- {
349
- if(!isset($backup_files[$key]['timestamp']))
350
- {
351
- //$backup_files[$key]['timestamp'] = $this->get_storage_filesystem($storage_selection)->getTimestamp($file_info['path']);
352
- }
353
-
354
- if(isset($parents[$file_info['basename']]))
355
- $backup_files[$key]['parent'] = $parents[$file_info['basename']];
356
- }
357
-
358
- return $backup_files;
359
- }
360
-
361
- public function start_file_recursion($init = 0)
362
- {
363
- if($init)
364
- {
365
- $this->logger->info(sprintf(__("Starting the filesystem scanner on root folder %s"), $this->xcloner_settings->get_xcloner_start_path()));
366
- $this->do_system_init();
367
- }
368
-
369
- if($this->tmp_filesystem->has($this->get_temp_dir_handler())){
370
- //.dir exists, we presume we have files to iterate
371
- $content = $this->tmp_filesystem->read($this->get_temp_dir_handler());
372
- $files = array_filter(explode("\n", $content));
373
- $this->tmp_filesystem->delete($this->get_temp_dir_handler());
374
-
375
- $counter = 0;
376
- foreach($files as $file)
377
- {
378
- if($counter < $this->folders_to_process_per_session){
379
- $this->build_files_list($file);
380
- $counter++;
381
- }else{
382
- $this->tmp_filesystem_append->write($this->get_temp_dir_handler(), $file."\n");
383
- }
384
- }
385
- }else{
386
- $this->build_files_list();
387
- }
388
-
389
- if($this->scan_finished())
390
- {
391
- $metadata_dumpfile = $this->get_tmp_filesystem()->getMetadata("index.html");
392
- $this->store_file($metadata_dumpfile, 'tmp_filesystem');
393
- $this->files_counter++;
394
-
395
- //adding included dump file to the included files list
396
- if($this->get_tmp_filesystem()->has($this->get_included_files_handler()))
397
- {
398
- $metadata_dumpfile = $this->get_tmp_filesystem()->getMetadata($this->get_included_files_handler());
399
- $this->store_file($metadata_dumpfile, 'tmp_filesystem');
400
- $this->files_counter++;
401
- }
402
-
403
- //adding a default index.html to the temp xcloner folder
404
- if(!$this->get_tmp_filesystem()->has("index.html"))
405
- {
406
- $this->get_tmp_filesystem()->write("index.html","");
407
- }
408
-
409
- //adding the default log file
410
- if($this->get_tmp_filesystem()->has($this->xcloner_settings->get_logger_filename(1)))
411
- {
412
- $metadata_dumpfile = $this->get_tmp_filesystem()->getMetadata($this->xcloner_settings->get_logger_filename(1));
413
- $this->store_file($metadata_dumpfile, 'tmp_filesystem');
414
- $this->files_counter++;
415
- }
416
-
417
- return false;
418
- }
419
-
420
- return true;
421
- }
422
-
423
- public function get_backup_attachments()
424
- {
425
- $return = array();
426
-
427
- $files_list_file = $this->xcloner_settings->get_xcloner_tmp_path().DS.$this->get_included_files_handler();
428
- if(file_exists($files_list_file))
429
- {
430
- $return[] = $files_list_file;
431
- }
432
-
433
- if($this->xcloner_settings->get_xcloner_option('xcloner_enable_log'))
434
- {
435
- $log_file = $this->xcloner_settings->get_xcloner_tmp_path().DS.$this->xcloner_settings->get_logger_filename(1);
436
- if(!file_exists($log_file))
437
- {
438
- $log_file = $this->xcloner_settings->get_xcloner_store_path().DS.$this->xcloner_settings->get_logger_filename();
439
- }
440
-
441
- if(file_exists($log_file))
442
- {
443
- $return[] = $log_file;
444
- }
445
- }
446
-
447
- return $return;
448
- }
449
-
450
- public function remove_tmp_filesystem()
451
- {
452
- //delete the temporary folder
453
- $this->logger->debug(sprintf("Deleting the temporary storage folder %s", $this->xcloner_settings->get_xcloner_tmp_path()));
454
-
455
- $contents = $this->get_tmp_filesystem()->listContents();
456
-
457
- if(is_array($contents))
458
- foreach($contents as $file_info)
459
- $this->get_tmp_filesystem()->delete($file_info['path']);
460
-
461
- @rmdir($this->xcloner_settings->get_xcloner_tmp_path());
462
-
463
- return;
464
- }
465
-
466
- public function cleanup_tmp_directories()
467
- {
468
- $adapter = new Local($this->xcloner_settings->get_xcloner_tmp_path(false),LOCK_EX|FILE_APPEND, 'SKIP_LINKS');
469
- $tmp_filesystem = new Filesystem($adapter, new Config([
470
- 'disable_asserts' => true,
471
- ]));
472
-
473
- $contents = $tmp_filesystem->listContents();
474
-
475
- foreach($contents as $file)
476
- {
477
-
478
- if(preg_match("/.xcloner-(.*)/",$file['path']))
479
- {
480
- if($file['timestamp'] < strtotime("-1days"))
481
- {
482
- $tmp_filesystem->deleteDir($file['path']);
483
- $this->logger->debug(sprintf("Delete temporary directory %s", $file['path']));
484
- }
485
- }
486
- }
487
-
488
- return true;
489
- }
490
-
491
- private function do_system_init()
492
- {
493
- $this->files_counter = 0;
494
-
495
- if(!$this->storage_filesystem->has("index.html"))
496
- $this->storage_filesystem->write("index.html","");
497
-
498
- if(!$this->tmp_filesystem->has("index.html"))
499
- $this->tmp_filesystem->write("index.html","");
500
-
501
- if($this->tmp_filesystem->has($this->get_included_files_handler()))
502
- $this->tmp_filesystem->delete($this->get_included_files_handler());
503
-
504
- if($this->tmp_filesystem->has($this->get_temp_dir_handler()))
505
- $this->tmp_filesystem->delete($this->get_temp_dir_handler());
506
- }
507
-
508
- public function get_scanned_files_num()
509
- {
510
- return $this->files_counter;
511
- }
512
-
513
- public function get_scanned_files_total_size()
514
- {
515
- return $this->files_size;
516
- }
517
-
518
- public function last_logged_file()
519
- {
520
- return $this->last_logged_file;
521
- }
522
-
523
- public static function is_regex($regex) {
524
- return preg_match("/^\^(.*)\$$/i",$regex);
525
- }
526
-
527
- public function set_excluded_files($excluded_files = array())
528
- {
529
- if(!is_array($excluded_files))
530
- {
531
- $excluded_files = array();
532
- }
533
-
534
- foreach($excluded_files as $excl)
535
- {
536
-
537
- if($this->is_regex($excl))
538
- {
539
- $this->additional_regex_patterns[] = $excl;
540
- }
541
- }
542
-
543
- $this->excluded_files = array_merge($excluded_files, $this->excluded_files_by_default);
544
-
545
- return $this->excluded_files;
546
- }
547
-
548
- public function get_excluded_files()
549
- {
550
- return $this->excluded_files_by_default;
551
- }
552
-
553
- public function list_directory($path)
554
- {
555
- return $this->start_filesystem->listContents($path);
556
- }
557
-
558
- public function build_files_list($folder = "")
559
- {
560
- $this->logger->debug(sprintf(("Building the files system list")));
561
-
562
- //if we start with the root folder(empty value), we initializa the file system
563
- if(!$folder){
564
-
565
- }
566
-
567
- try{
568
-
569
- $files = $this->start_filesystem->listContents($folder);
570
- foreach($files as $file)
571
- {
572
- if(!is_readable($this->xcloner_settings->get_xcloner_start_path().DS.$file['path']))
573
- {
574
- $this->logger->info(sprintf(__("Excluding %s from the filesystem list, file not readable"), $file['path']), array("FILESYSTEM SCAN","NOT READABLE"));
575
- }
576
- elseif(!$matching_pattern = $this->is_excluded($file) ){
577
- $this->logger->info(sprintf(__("Adding %s to the filesystem list"), $file['path']), array("FILESYSTEM SCAN","INCLUDE"));
578
- $file['visibility'] = $this->start_filesystem->getVisibility($file['path']);
579
- if($this->store_file($file))
580
- {
581
- $this->files_counter++;
582
- }
583
- if(isset($file['size']))
584
- $this->files_size += $file['size'];
585
-
586
- }else{
587
- $this->logger->info(sprintf(__("Excluding %s from the filesystem list, matching pattern %s"), $file['path'], $matching_pattern), array("FILESYSTEM SCAN","EXCLUDE"));
588
- }
589
- }
590
-
591
- }catch(Exception $e){
592
-
593
- $this->logger->error($e->getMessage());
594
-
595
- }
596
-
597
- }
598
-
599
- public function estimate_read_write_time()
600
- {
601
- $tmp_file = ".xcloner".substr(md5(time()), 0, 5);
602
-
603
- $start_time = microtime();
604
-
605
- $data = str_repeat(rand(0,9), 1024*1024); //write 1MB data
606
-
607
- try{
608
- $this->tmp_filesystem->write($tmp_file, $data);
609
-
610
- $end_time = microtime() - $start_time;
611
-
612
- $return['writing_time'] = $end_time;
613
-
614
- $return['reading_time'] = $this->estimate_reading_time($tmp_file);
615
-
616
- $this->tmp_filesystem->delete($tmp_file);
617
-
618
- }catch(Exception $e){
619
-
620
- $this->logger->error($e->getMessage());
621
-
622
- }
623
-
624
- return $return;
625
- }
626
-
627
- public function backup_storage_cleanup()
628
- {
629
- $this->logger->info(sprintf(("Cleaning the backup storage on matching rules")));
630
-
631
- $_storage_size = 0;
632
- $_backup_files_list = array();
633
-
634
- //rule date limit
635
- $current_timestamp = strtotime("-".$this->xcloner_settings->get_xcloner_option('xcloner_cleanup_retention_limit_days')." days");
636
-
637
- $files = $this->storage_filesystem->listContents();
638
-
639
- if(is_array($files))
640
- foreach($files as $file)
641
- {
642
- if(isset($file['extension']) and in_array($file['extension'], $this->backup_archive_extensions))
643
- {
644
- $_storage_size += $file['size']; //bytes
645
- $_backup_files_list[] = $file;
646
- }
647
- }
648
-
649
-
650
- $this->sort_by($_backup_files_list, "timestamp","asc");
651
-
652
- $_backups_counter = sizeof($_backup_files_list);
653
-
654
- foreach($_backup_files_list as $file)
655
- {
656
- //processing rule folder capacity
657
- if($this->xcloner_settings->get_xcloner_option('xcloner_cleanup_capacity_limit') &&
658
- $_storage_size >= ($set_storage_limit = 1024*1024*$this->xcloner_settings->get_xcloner_option('xcloner_cleanup_capacity_limit'))) //bytes
659
- {
660
- $this->storage_filesystem->delete($file['path']);
661
- $_storage_size -= $file['size'];
662
- $this->logger->info("Deleting backup ".$file['path']." matching rule", array("STORAGE SIZE LIMIT", $_storage_size." >= ".$set_storage_limit));
663
- }
664
-
665
- //processing rule days limit
666
- if($this->xcloner_settings->get_xcloner_option('xcloner_cleanup_retention_limit_days') && $current_timestamp >= $file['timestamp'])
667
- {
668
- $this->storage_filesystem->delete($file['path']);
669
- $this->logger->info("Deleting backup ".$file['path']." matching rule", array("RETENTION LIMIT TIMESTAMP", $file['timestamp']." =< ".$this->xcloner_settings->get_xcloner_option('xcloner_cleanup_retention_limit_days')));
670
- }
671
-
672
- //processing backup countert limit
673
- if($this->xcloner_settings->get_xcloner_option('xcloner_cleanup_retention_limit_archives') && $_backups_counter >= $this->xcloner_settings->get_xcloner_option('xcloner_cleanup_retention_limit_archives'))
674
- {
675
- $this->storage_filesystem->delete($file['path']);
676
- $_backups_counter--;
677
- $this->logger->info("Deleting backup ".$file['path']." matching rule", array("BACKUP QUANTITY LIMIT", $_backups_counter." >= ".$this->xcloner_settings->get_xcloner_option('xcloner_cleanup_retention_limit_archives')));
678
- }
679
-
680
-
681
- }
682
-
683
- }
684
-
685
- public function estimate_reading_time($tmp_file)
686
- {
687
- $this->logger->debug(sprintf(("Estimating file system reading time")));
688
-
689
- $start_time = microtime();
690
-
691
- $this->tmp_filesystem->read($tmp_file);
692
-
693
- $end_time = microtime() - $start_time;
694
-
695
- return $end_time;
696
-
697
- }
698
-
699
- public function process_backup_name($name = "", $max_length=100)
700
- {
701
- if(!$name)
702
- $name = $this->xcloner_settings->get_default_backup_name();
703
-
704
- foreach($this->backup_name_tags as $tag)
705
- {
706
- if($tag == '[time]')
707
- $name = str_replace($tag, date("Y-m-d_H-i"),$name);
708
- elseif($tag == '[hostname]')
709
- $name = str_replace($tag, gethostname() ,$name);
710
- elseif($tag == '[domain]')
711
- {
712
- $domain = parse_url(admin_url(), PHP_URL_HOST);
713
- $name = str_replace($tag, $domain ,$name);
714
- }
715
- }
716
-
717
- if($max_length)
718
- $name = substr($name, 0, $max_length);
719
-
720
- return $name;
721
- }
722
-
723
- public function sort_by( &$array, $field, $direction = 'asc')
724
- {
725
- if(strtolower($direction) == "desc" || $direction == SORT_DESC)
726
- $direction = SORT_DESC;
727
- else
728
- $direction = SORT_ASC;
729
-
730
- $array = $this->array_orderby($array, $field, $direction);
731
-
732
- return true;
733
- }
734
-
735
- private function array_orderby()
736
- {
737
- $args = func_get_args();
738
- $data = array_shift($args);
739
-
740
- foreach ($args as $n => $field) {
741
- if (is_string($field)) {
742
- $tmp = array();
743
- foreach ($data as $key => $row)
744
- {
745
- if(is_array($row))
746
- $tmp[$key] = $row[$field];
747
- else
748
- $tmp[$key] = $row->$field;
749
- }
750
- $args[$n] = $tmp;
751
- }
752
- }
753
- $args[] = &$data;
754
-
755
- call_user_func_array('array_multisort', $args);
756
-
757
- return array_pop($args);
758
- }
759
-
760
- private function check_file_diff_time($file)
761
- {
762
- if($this->get_diff_timestamp_start() != "")
763
- {
764
- $fileMeta = $this->getMetadataFull("start_adapter", $file['path']);
765
- $timestamp = $fileMeta->getMTime();
766
- if($timestamp < $fileMeta->getCTime())
767
- {
768
- $timestamp = $fileMeta->getCTime();
769
- }
770
-
771
- if($timestamp <= $this->get_diff_timestamp_start())
772
- {
773
- return " file DIFF timestamp ".$timestamp." < ". $this->diff_timestamp_start;
774
- }
775
- }
776
-
777
- return false;
778
- }
779
-
780
- public function is_excluded($file)
781
- {
782
- $this->logger->debug(sprintf(("Checking if %s is excluded"), $file['path']));
783
-
784
- if($xcloner_exclude_files_larger_than_mb = $this->xcloner_settings->get_xcloner_option('xcloner_exclude_files_larger_than_mb'))
785
- {
786
- if(isset($file['size']) && $file['size'] > $this->calc_to_bytes($xcloner_exclude_files_larger_than_mb))
787
- return "> ".$xcloner_exclude_files_larger_than_mb."MB";
788
- }
789
-
790
- if(!is_array($this->excluded_files) || !sizeof($this->excluded_files))
791
- {
792
- $this->set_excluded_files();
793
- }
794
-
795
- if(is_array($this->excluded_files))
796
- foreach($this->excluded_files as $excluded_file_pattern)
797
- {
798
- if($excluded_file_pattern == "/")
799
- $needle = "$";
800
- else
801
- $needle = "$".$excluded_file_pattern;
802
-
803
- if(strstr("$".$file['path'], $needle)){
804
- return $excluded_file_pattern;
805
- }
806
- }
807
-
808
- if( $regex = $this->is_excluded_regex($file))
809
- return $regex;
810
-
811
- if($file['type'] == "file")
812
- {
813
- $check_file_diff_timestamp = $this->check_file_diff_time($file);
814
- if($check_file_diff_timestamp)
815
- {
816
- return $check_file_diff_timestamp;
817
- }
818
- }
819
-
820
- return false;
821
- }
822
-
823
- /*REGEX examples
824
- *
825
- * exclude all except .php file
826
- * PATTERN: ^(.*)\.(.+)$(?<!(php))
827
- *
828
- * exclude all except .php and .txt
829
- * PATTERN: ^(.*)\.(.+)$(?<!(php|txt))";
830
- *
831
- * exclude all .svn and .git
832
- * PATTERN: ^(.*)\.(svn|git)(.*)$";
833
- *
834
- * exclude root directory /test
835
- * PATTERN: "^\/test(.*)$";
836
- *
837
- * exclude the wp-admin folder
838
- * PATTERN: ^(\/wp-admin)(.*)$";
839
- *
840
- * exclude the wp-admin, wp-includes and wp-config.php
841
- * PATTERN: ^\/(wp-admin|wp-includes|wp-config.php)(.*)$";
842
- *
843
- * exclude all .avi files
844
- * PATTERN: ^(.*)$(?<=(avi))";
845
- *
846
- * exclude all .jpg and gif files
847
- * PATTERN: ^(.*)$(?<=(gif|jpg))";
848
- *
849
- * exclude all cache folders from wp-content/
850
- * PATTERN: ^\/wp-content(.*)\/cache($|\/)(.*)";
851
- *
852
- * exclude the backup folders
853
- * PATTERN: (^|^\/)(wp-content\/backups|administrator\/backups)(.*)$";
854
- */
855
- private function is_excluded_regex($file)
856
- {
857
- //$this->logger->debug(sprintf(("Checking if %s is excluded"), $file['path']));
858
-
859
- $regex_patterns = explode(PHP_EOL, $this->xcloner_settings->get_xcloner_option('xcloner_regex_exclude'));
860
-
861
- if(is_array($this->additional_regex_patterns))
862
- {
863
- $regex_patterns = array_merge($regex_patterns, $this->additional_regex_patterns);
864
- }
865
-
866
- //print_r($regex_patterns);exit;
867
-
868
- if(is_array($regex_patterns))
869
- {
870
- //$this->excluded_files = array();
871
- //$this->excluded_files[] ="(.*)\.(git)(.*)$";
872
- //$this->excluded_files[] ="wp-content\/backups(.*)$";
873
-
874
- foreach($regex_patterns as $excluded_file_pattern)
875
- {
876
-
877
- if( substr($excluded_file_pattern, strlen($excluded_file_pattern)-1, strlen($excluded_file_pattern)) == "\r")
878
- $excluded_file_pattern = substr($excluded_file_pattern, 0, strlen($excluded_file_pattern)-1);
879
-
880
- if($file['path'] == "/")
881
- $needle = "/";
882
- else
883
- $needle = "/".$file['path'];
884
- //echo $needle."---".$excluded_file_pattern."---\n";
885
-
886
- if(@preg_match("/(^|^\/)".$excluded_file_pattern."/i", $needle)){
887
- return $excluded_file_pattern;
888
- }
889
- }
890
- }
891
-
892
- return false;
893
- }
894
-
895
- public function store_file($file, $storage = 'start_filesystem')
896
- {
897
- $this->logger->debug(sprintf("Storing %s in the backup list", $file['path']));
898
-
899
- if(!isset($file['size']))
900
- $file['size'] = 0;
901
- if(!isset($file['visibility']))
902
- $file['visibility'] = "private";
903
-
904
- $csv_filename = str_replace('"','""', $file['path']);
905
-
906
- $line = '"'.($csv_filename).'","'.$file['timestamp'].'","'.$file['size'].'","'.$file['visibility'].'","'.$storage.'"'.PHP_EOL;
907
-
908
- $this->last_logged_file = $file['path'];
909
-
910
- if($file['type'] == "dir"){
911
- try{
912
- $this->tmp_filesystem_append->write($this->get_temp_dir_handler(), $file['path']."\n");
913
- }catch(Exception $e){
914
- $this->logger->error($e->getMessage());
915
- }
916
- }
917
-
918
- if($this->get_diff_timestamp_start())
919
- {
920
- if($file['type'] != "file" && $response = $this->check_file_diff_time($file))
921
- {
922
- $this->logger->info(sprintf("Directory %s archiving skipped on differential backup %s", $file['path'], $response), array("FILESYSTEM SCAN","DIR DIFF"));
923
- return false;
924
- }
925
- }
926
-
927
- try{
928
- if(!$this->tmp_filesystem_append->has($this->get_included_files_handler()))
929
- {
930
- //adding fix for UTF-8 CSV preview
931
- $start_line = "\xEF\xBB\xBF".'"Filename","Timestamp","Size","Visibility","Storage"'.PHP_EOL;
932
- $this->tmp_filesystem_append->write($this->get_included_files_handler(), $start_line);
933
- }
934
-
935
- $this->tmp_filesystem_append->write($this->get_included_files_handler(), $line);
936
-
937
- }catch(Exception $e){
938
-
939
- $this->logger->error($e->getMessage());
940
- }
941
-
942
- return true;
943
- }
944
-
945
- public function get_fileystem_handler()
946
- {
947
- return $this;
948
- }
949
-
950
- public function get_filesystem($system = "")
951
- {
952
- if($system == "storage_filesystem_append")
953
- return $this->storage_filesystem_append;
954
- elseif($system == "tmp_filesystem_append")
955
- return $this->tmp_filesystem_append;
956
- elseif($system == "tmp_filesystem")
957
- return $this->tmp_filesystem;
958
- elseif($system == "storage_filesystem")
959
- return $this->storage_filesystem;
960
- else
961
- return $this->start_filesystem;
962
- }
963
-
964
- public function get_adapter($system)
965
- {
966
- if($system == "tmp_filesystem")
967
- return $this->tmp_adapter;
968
- elseif($system == "storage_filesystem")
969
- return $this->storage_adapter;
970
- else
971
- return $this->start_adapter;
972
- }
973
-
974
- private function scan_finished()
975
- {
976
- if($this->tmp_filesystem_append->has($this->get_temp_dir_handler()) && $this->tmp_filesystem_append->getSize($this->get_temp_dir_handler()))
977
- return false;
978
-
979
- if($this->tmp_filesystem->has($this->get_temp_dir_handler()))
980
- $this->tmp_filesystem->delete($this->get_temp_dir_handler());
981
-
982
- $this->logger->debug(sprintf(("File scan finished")));
983
-
984
- return true;
985
- }
986
-
987
- private function calc_to_bytes($mb_size)
988
- {
989
- return $mb_size*(1024*1024);
990
- }
991
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
992
  }
1
  <?php
2
+ /**
3
+ * XCloner - Backup and Restore backup plugin for Wordpress
4
+ *
5
+ * class-xcloner-file-system.php
6
+ * @author Liuta Ovidiu <info@thinkovi.com>
7
+ *
8
+ * This program is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation; either version 2 of the License, or
11
+ * (at your option) any later version.
12
+ *
13
+ * This program is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ * GNU General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU General Public License
19
+ * along with this program; if not, write to the Free Software
20
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21
+ * MA 02110-1301, USA.
22
+ *
23
+ * @link https://github.com/ovidiul/XCloner-Wordpress
24
+ *
25
+ * @modified 7/31/18 3:46 PM
26
+ *
27
+ */
28
+
29
  use League\Flysystem\Config;
30
  use League\Flysystem\Filesystem;
31
  use League\Flysystem\Util;
32
  use League\Flysystem\Adapter\Local;
33
 
34
+ /**
35
+ * Class Xcloner_File_System
36
+ */
37
+ class Xcloner_File_System
38
+ {
39
+
40
+ private $excluded_files = "";
41
+ private $additional_regex_patterns = array();
42
+ private $excluded_files_by_default = array("administrator/backups", "wp-content/backups");
43
+ private $included_files_handler = "backup_files.csv";
44
+ private $temp_dir_handler = ".dir";
45
+ public $filesystem;
46
+ public $tmp_filesystem;
47
+ public $storage_filesystem;
48
+ private $xcloner_container;
49
+ private $diff_timestamp_start = "";
50
+
51
+ private $logger;
52
+ private $start_adapter;
53
+ private $tmp_adapter;
54
+ private $storage_adapter;
55
+ private $xcloner_settings;
56
+ private $start_filesystem;
57
+ private $tmp_filesystem_append;
58
+ private $storage_filesystem_append;
59
+
60
+ private $files_counter;
61
+ private $files_size;
62
+ private $last_logged_file;
63
+ private $folders_to_process_per_session = 25;
64
+ private $backup_archive_extensions = array("tar", "tgz", "tar.gz", "gz", "csv");
65
+ private $backup_name_tags = array('[time]', '[hostname]', '[domain]');
66
+
67
+ /**
68
+ * Xcloner_File_System constructor.
69
+ * @param Xcloner $xcloner_container
70
+ * @param string $hash
71
+ */
72
+ public function __construct(Xcloner $xcloner_container, $hash = "")
73
+ {
74
+ $this->xcloner_container = $xcloner_container;
75
+
76
+ $this->logger = $xcloner_container->get_xcloner_logger()->withName("xcloner_file_system");
77
+ $this->xcloner_settings = $xcloner_container->get_xcloner_settings();
78
+
79
+ try {
80
+
81
+ $this->start_adapter = new Local($this->xcloner_settings->get_xcloner_start_path(), LOCK_EX, 'SKIP_LINKS');
82
+ $this->start_filesystem = new Filesystem($this->start_adapter, new Config([
83
+ 'disable_asserts' => true,
84
+ ]));
85
+
86
+ $this->tmp_adapter = new Local($this->xcloner_settings->get_xcloner_tmp_path(), LOCK_EX, 'SKIP_LINKS');
87
+ $this->tmp_filesystem = new Filesystem($this->tmp_adapter, new Config([
88
+ 'disable_asserts' => true,
89
+ ]));
90
+ $adapter = new Local($this->xcloner_settings->get_xcloner_tmp_path(), LOCK_EX | FILE_APPEND, 'SKIP_LINKS');
91
+ $this->tmp_filesystem_append = new Filesystem($adapter, new Config([
92
+ 'disable_asserts' => true,
93
+ ]));
94
+
95
+ $adapter = new Local($this->xcloner_settings->get_xcloner_store_path(), LOCK_EX, 'SKIP_LINKS');
96
+ $this->storage_filesystem = new Filesystem($adapter, new Config([
97
+ 'disable_asserts' => true,
98
+ ]));
99
+
100
+ $this->storage_adapter = new Local($this->xcloner_settings->get_xcloner_store_path(), FILE_APPEND,
101
+ 'SKIP_LINKS');
102
+ $this->storage_filesystem_append = new Filesystem($this->storage_adapter, new Config([
103
+ 'disable_asserts' => true,
104
+ ]));
105
+ } catch (Exception $e) {
106
+ $this->logger->error("Filesystem Initialization Error: " . $e->getMessage());
107
+ }
108
+
109
+
110
+ if ($value = get_option('xcloner_directories_to_scan_per_request')) {
111
+ $this->folders_to_process_per_session = $value;
112
+ }
113
+
114
+ }
115
+
116
+ /**
117
+ * Set differential timestamp date
118
+ * @param string $timestamp
119
+ */
120
+ public function set_diff_timestamp_start($timestamp = "")
121
+ {
122
+ if ($timestamp) {
123
+ $this->logger->info(sprintf("Setting Differential Timestamp To %s", date("Y-m-d", $timestamp)), array(
124
+ "FILESYSTEM",
125
+ "DIFF"
126
+ ));
127
+ $this->diff_timestamp_start = $timestamp;
128
+ }
129
+ }
130
+
131
+ /**
132
+ * Gets the differential timestamp date
133
+ * @return string
134
+ */
135
+ public function get_diff_timestamp_start()
136
+ {
137
+ return $this->diff_timestamp_start;
138
+ }
139
+
140
+ private function get_xcloner_container()
141
+ {
142
+ return $this->xcloner_container;
143
+ }
144
+
145
+ public function set_hash($hash)
146
+ {
147
+ $this->xcloner_settings->set_hash($hash);
148
+ }
149
+
150
+ public function get_hash($hash)
151
+ {
152
+ $this->xcloner_settings->get_hash();
153
+ }
154
+
155
+ public function get_tmp_filesystem()
156
+ {
157
+ return $this->tmp_filesystem;
158
+ }
159
+
160
+ public function get_storage_filesystem($remote_storage_selection = "")
161
+ {
162
+ if ($remote_storage_selection != "") {
163
+ $remote_storage = $this->get_xcloner_container()->get_xcloner_remote_storage();
164
+ $method = "get_" . $remote_storage_selection . "_filesystem";
165
+
166
+ if (!method_exists($remote_storage, $method)) {
167
+ return false;
168
+ }
169
+
170
+ list($adapter, $filesystem) = $remote_storage->$method();
171
+
172
+ return $filesystem;
173
+ }
174
+
175
+ return $this->storage_filesystem;
176
+ }
177
+
178
+ public function get_tmp_filesystem_adapter()
179
+ {
180
+ return $this->tmp_adapter;
181
+ }
182
+
183
+ public function get_tmp_filesystem_append()
184
+ {
185
+ return $this->tmp_filesystem_append;
186
+ }
187
+
188
+ public function get_start_adapter()
189
+ {
190
+ return $this->start_adapter;
191
+ }
192
+
193
+ public function get_start_filesystem()
194
+ {
195
+ return $this->start_filesystem;
196
+ }
197
+
198
+ public function get_logger()
199
+ {
200
+ return $this->logger;
201
+ }
202
+
203
+ public function get_start_path_file_info($file)
204
+ {
205
+ $info = $this->getMetadataFull('start_adapter', $file);
206
+
207
+ return $this->start_filesystem->normalizeFileInfo($info);
208
+ }
209
+
210
+ public function get_storage_path_file_info($file)
211
+ {
212
+ return $this->getMetadataFull('storage_adapter', $file);
213
+ }
214
+
215
+ public function get_included_files_handler($metadata = 0)
216
+ {
217
+ $path = $this->included_files_handler;
218
+ if (!$metadata) {
219
+ return $path;
220
+ }
221
+
222
+ $spl_info = $this->getMetadataFull('tmp_adapter', $path);
223
+
224
+ return $spl_info;
225
+
226
+ }
227
+
228
+ public function get_temp_dir_handler()
229
+ {
230
+ return $this->temp_dir_handler;
231
+ }
232
+
233
+ public function get_latest_backup()
234
+ {
235
+ $files = $this->get_backup_archives_list();
236
+
237
+ if (is_array($files)) {
238
+ $this->sort_by($files, "timestamp", "desc");
239
+ }
240
+
241
+ $new_list = array();
242
+
243
+ foreach ($files as $key => $file) {
244
+ if (!isset($file['parent'])) {
245
+ $new_list[] = ($files[$key]);
246
+ }
247
+ }
248
+
249
+ if (isset($new_list[0])) {
250
+ return $new_list[0];
251
+ }
252
+ }
253
+
254
+ public function get_latest_backups()
255
+ {
256
+ $files = $this->get_backup_archives_list();
257
+
258
+ if (is_array($files)) {
259
+ $this->sort_by($files, "timestamp", "desc");
260
+ }
261
+
262
+ $new_list = array();
263
+
264
+ foreach ($files as $key => $file) {
265
+ if (!isset($file['parent'])) {
266
+ $new_list[] = ($files[$key]);
267
+ }
268
+ }
269
+
270
+ return $new_list;
271
+ }
272
+
273
+ public function get_storage_usage()
274
+ {
275
+ $files = $this->get_backup_archives_list();
276
+ $total = 0;
277
+
278
+ if (is_array($files)) {
279
+ foreach ($files as $file) {
280
+ $total += $file['size'];
281
+ }
282
+ }
283
+
284
+ return $total;
285
+ }
286
+
287
+ public function is_part($backup_name)
288
+ {
289
+ if (stristr($backup_name, "-part")) {
290
+ return true;
291
+ }
292
+
293
+ return false;
294
+ }
295
+
296
+ public function is_multipart($backup_name)
297
+ {
298
+ if (stristr($backup_name, "-multipart")) {
299
+ return true;
300
+ }
301
+
302
+ return false;
303
+ }
304
+
305
+ public function get_backup_size($backup_name)
306
+ {
307
+ $backup_size = $this->get_storage_filesystem()->getSize($backup_name);
308
+ if ($this->is_multipart($backup_name)) {
309
+ $backup_parts = $this->get_multipart_files($backup_name);
310
+ foreach ($backup_parts as $part_file) {
311
+ $backup_size += $this->get_storage_filesystem()->getSize($part_file);
312
+ }
313
+ }
314
+
315
+ return $backup_size;
316
+ }
317
+
318
+ public function get_multipart_files($backup_name, $storage_selection = "")
319
+ {
320
+ $files = array();
321
+
322
+ if ($this->is_multipart($backup_name)) {
323
+ $lines = explode(PHP_EOL, $this->get_storage_filesystem($storage_selection)->read($backup_name));
324
+ foreach ($lines as $line) {
325
+ if ($line) {
326
+ $data = str_getcsv($line);
327
+ $files[] = $data[0];
328
+ }
329
+ }
330
+ }
331
+
332
+ return $files;
333
+ }
334
+
335
+ public function delete_backup_by_name($backup_name, $storage_selection = "")
336
+ {
337
+ if ($this->is_multipart($backup_name)) {
338
+ $lines = explode(PHP_EOL, $this->get_storage_filesystem($storage_selection)->read($backup_name));
339
+ foreach ($lines as $line) {
340
+ if ($line) {
341
+ $data = str_getcsv($line);
342
+ $this->get_storage_filesystem($storage_selection)->delete($data[0]);
343
+ }
344
+ }
345
+ }
346
+
347
+ if ($this->get_storage_filesystem($storage_selection)->delete($backup_name)) {
348
+ $return = true;
349
+ } else {
350
+ $return = false;
351
+ }
352
+
353
+ return $return;
354
+ }
355
+
356
+ public function getMetadataFull($adapter = "storage_adapter", $path)
357
  {
358
  $location = $this->$adapter->applyPathPrefix($path);
359
  $spl_info = new SplFileInfo($location);
360
+
361
  return ($spl_info);
362
  }
363
+
364
+
365
+ public function get_backup_archives_list($storage_selection = "")
366
+ {
367
+ $list = array();
368
+
369
+
370
+ if (method_exists($this->get_storage_filesystem($storage_selection), "listContents")) {
371
+ $list = $this->get_storage_filesystem($storage_selection)->listContents();
372
+ }
373
+
374
+ $backup_files = array();
375
+ $parents = array();
376
+
377
+ foreach ($list as $file_info) {
378
+ if (isset($file_info['extension']) and $file_info['extension'] == "csv") {
379
+ $data = array();
380
+
381
+ $lines = explode(PHP_EOL, $this->get_storage_filesystem($storage_selection)->read($file_info['path']));
382
+ foreach ($lines as $line) {
383
+ if ($line) {
384
+ $data = str_getcsv($line);
385
+ if (is_array($data)) {
386
+ $parents[$data[0]] = $file_info['basename'];
387
+ $file_info['childs'][] = $data;
388
+ $file_info['size'] += $data[2];
389
+ }
390
+ }
391
+ }
392
+
393
+ }
394
+
395
+ if ($file_info['type'] == 'file' and isset($file_info['extension']) and in_array($file_info['extension'],
396
+ $this->backup_archive_extensions)) {
397
+ $backup_files[$file_info['path']] = $file_info;
398
+ }
399
+ }
400
+
401
+ foreach ($backup_files as $key => $file_info) {
402
+ if (!isset($backup_files[$key]['timestamp'])) {
403
+ //$backup_files[$key]['timestamp'] = $this->get_storage_filesystem($storage_selection)->getTimestamp($file_info['path']);
404
+ }
405
+
406
+ if (isset($parents[$file_info['basename']])) {
407
+ $backup_files[$key]['parent'] = $parents[$file_info['basename']];
408
+ }
409
+ }
410
+
411
+ return $backup_files;
412
+ }
413
+
414
+ public function start_file_recursion($init = 0)
415
+ {
416
+ if ($init) {
417
+ $this->logger->info(sprintf(__("Starting the filesystem scanner on root folder %s"),
418
+ $this->xcloner_settings->get_xcloner_start_path()));
419
+ $this->do_system_init();
420
+ }
421
+
422
+ if ($this->tmp_filesystem->has($this->get_temp_dir_handler())) {
423
+ //.dir exists, we presume we have files to iterate
424
+ $content = $this->tmp_filesystem->read($this->get_temp_dir_handler());
425
+ $files = array_filter(explode("\n", $content));
426
+ $this->tmp_filesystem->delete($this->get_temp_dir_handler());
427
+
428
+ $counter = 0;
429
+ foreach ($files as $file) {
430
+ if ($counter < $this->folders_to_process_per_session) {
431
+ $this->build_files_list($file);
432
+ $counter++;
433
+ } else {
434
+ $this->tmp_filesystem_append->write($this->get_temp_dir_handler(), $file . "\n");
435
+ }
436
+ }
437
+ } else {
438
+ $this->build_files_list();
439
+ }
440
+
441
+ if ($this->scan_finished()) {
442
+ $metadata_dumpfile = $this->get_tmp_filesystem()->getMetadata("index.html");
443
+ $this->store_file($metadata_dumpfile, 'tmp_filesystem');
444
+ $this->files_counter++;
445
+
446
+ //adding included dump file to the included files list
447
+ if ($this->get_tmp_filesystem()->has($this->get_included_files_handler())) {
448
+ $metadata_dumpfile = $this->get_tmp_filesystem()->getMetadata($this->get_included_files_handler());
449
+ $this->store_file($metadata_dumpfile, 'tmp_filesystem');
450
+ $this->files_counter++;
451
+ }
452
+
453
+ //adding a default index.html to the temp xcloner folder
454
+ if (!$this->get_tmp_filesystem()->has("index.html")) {
455
+ $this->get_tmp_filesystem()->write("index.html", "");
456
+ }
457
+
458
+ //adding the default log file
459
+ if ($this->get_tmp_filesystem()->has($this->xcloner_settings->get_logger_filename(1))) {
460
+ $metadata_dumpfile = $this->get_tmp_filesystem()->getMetadata($this->xcloner_settings->get_logger_filename(1));
461
+ $this->store_file($metadata_dumpfile, 'tmp_filesystem');
462
+ $this->files_counter++;
463
+ }
464
+
465
+ return false;
466
+ }
467
+
468
+ return true;
469
+ }
470
+
471
+ public function get_backup_attachments()
472
+ {
473
+ $return = array();
474
+
475
+ $files_list_file = $this->xcloner_settings->get_xcloner_tmp_path() . DS . $this->get_included_files_handler();
476
+ if (file_exists($files_list_file)) {
477
+ $return[] = $files_list_file;
478
+ }
479
+
480
+ if ($this->xcloner_settings->get_xcloner_option('xcloner_enable_log')) {
481
+ $log_file = $this->xcloner_settings->get_xcloner_tmp_path() . DS . $this->xcloner_settings->get_logger_filename(1);
482
+ if (!file_exists($log_file)) {
483
+ $log_file = $this->xcloner_settings->get_xcloner_store_path() . DS . $this->xcloner_settings->get_logger_filename();
484
+ }
485
+
486
+ if (file_exists($log_file)) {
487
+ $return[] = $log_file;
488
+ }
489
+ }
490
+
491
+ return $return;
492
+ }
493
+
494
+ public function remove_tmp_filesystem()
495
+ {
496
+ //delete the temporary folder
497
+ $this->logger->debug(sprintf("Deleting the temporary storage folder %s",
498
+ $this->xcloner_settings->get_xcloner_tmp_path()));
499
+
500
+ $contents = $this->get_tmp_filesystem()->listContents();
501
+
502
+ if (is_array($contents)) {
503
+ foreach ($contents as $file_info) {
504
+ $this->get_tmp_filesystem()->delete($file_info['path']);
505
+ }
506
+ }
507
+
508
+ @rmdir($this->xcloner_settings->get_xcloner_tmp_path());
509
+
510
+ return;
511
+ }
512
+
513
+ public function cleanup_tmp_directories()
514
+ {
515
+ $adapter = new Local($this->xcloner_settings->get_xcloner_tmp_path(false), LOCK_EX | FILE_APPEND, 'SKIP_LINKS');
516
+ $tmp_filesystem = new Filesystem($adapter, new Config([
517
+ 'disable_asserts' => true,
518
+ ]));
519
+
520
+ $contents = $tmp_filesystem->listContents();
521
+
522
+ foreach ($contents as $file) {
523
+
524
+ if (preg_match("/.xcloner-(.*)/", $file['path'])) {
525
+ if ($file['timestamp'] < strtotime("-1days")) {
526
+ $tmp_filesystem->deleteDir($file['path']);
527
+ $this->logger->debug(sprintf("Delete temporary directory %s", $file['path']));
528
+ }
529
+ }
530
+ }
531
+
532
+ return true;
533
+ }
534
+
535
+ private function do_system_init()
536
+ {
537
+ $this->files_counter = 0;
538
+
539
+ if (!$this->storage_filesystem->has("index.html")) {
540
+ $this->storage_filesystem->write("index.html", "");
541
+ }
542
+
543
+ if (!$this->tmp_filesystem->has("index.html")) {
544
+ $this->tmp_filesystem->write("index.html", "");
545
+ }
546
+
547
+ if ($this->tmp_filesystem->has($this->get_included_files_handler())) {
548
+ $this->tmp_filesystem->delete($this->get_included_files_handler());
549
+ }
550
+
551
+ if ($this->tmp_filesystem->has($this->get_temp_dir_handler())) {
552
+ $this->tmp_filesystem->delete($this->get_temp_dir_handler());
553
+ }
554
+ }
555
+
556
+ public function get_scanned_files_num()
557
+ {
558
+ return $this->files_counter;
559
+ }
560
+
561
+ public function get_scanned_files_total_size()
562
+ {
563
+ return $this->files_size;
564
+ }
565
+
566
+ public function last_logged_file()
567
+ {
568
+ return $this->last_logged_file;
569
+ }
570
+
571
+ public static function is_regex($regex)
572
+ {
573
+ return preg_match("/^\^(.*)\$$/i", $regex);
574
+ }
575
+
576
+ public function set_excluded_files($excluded_files = array())
577
+ {
578
+ if (!is_array($excluded_files)) {
579
+ $excluded_files = array();
580
+ }
581
+
582
+ foreach ($excluded_files as $excl) {
583
+
584
+ if ($this->is_regex($excl)) {
585
+ $this->additional_regex_patterns[] = $excl;
586
+ }
587
+ }
588
+
589
+ $this->excluded_files = array_merge($excluded_files, $this->excluded_files_by_default);
590
+
591
+ return $this->excluded_files;
592
+ }
593
+
594
+ public function get_excluded_files()
595
+ {
596
+ return $this->excluded_files_by_default;
597
+ }
598
+
599
+ public function list_directory($path)
600
+ {
601
+ return $this->start_filesystem->listContents($path);
602
+ }
603
+
604
+ public function build_files_list($folder = "")
605
+ {
606
+ $this->logger->debug(sprintf(("Building the files system list")));
607
+
608
+ //if we start with the root folder(empty value), we initializa the file system
609
+ if (!$folder) {
610
+
611
+ }
612
+
613
+ try {
614
+
615
+ $files = $this->start_filesystem->listContents($folder);
616
+ foreach ($files as $file) {
617
+ if (!is_readable($this->xcloner_settings->get_xcloner_start_path() . DS . $file['path'])) {
618
+ $this->logger->info(sprintf(__("Excluding %s from the filesystem list, file not readable"),
619
+ $file['path']), array(
620
+ "FILESYSTEM SCAN",
621
+ "NOT READABLE"
622
+ ));
623
+ } elseif (!$matching_pattern = $this->is_excluded($file)) {
624
+ $this->logger->info(sprintf(__("Adding %s to the filesystem list"), $file['path']), array(
625
+ "FILESYSTEM SCAN",
626
+ "INCLUDE"
627
+ ));
628
+ $file['visibility'] = $this->start_filesystem->getVisibility($file['path']);
629
+ if ($this->store_file($file)) {
630
+ $this->files_counter++;
631
+ }
632
+ if (isset($file['size'])) {
633
+ $this->files_size += $file['size'];
634
+ }
635
+
636
+ } else {
637
+ $this->logger->info(sprintf(__("Excluding %s from the filesystem list, matching pattern %s"),
638
+ $file['path'], $matching_pattern), array(
639
+ "FILESYSTEM SCAN",
640
+ "EXCLUDE"
641
+ ));
642
+ }
643
+ }
644
+
645
+ } catch (Exception $e) {
646
+
647
+ $this->logger->error($e->getMessage());
648
+
649
+ }
650
+
651
+ }
652
+
653
+ public function estimate_read_write_time()
654
+ {
655
+ $tmp_file = ".xcloner" . substr(md5(time()), 0, 5);
656
+
657
+ $start_time = microtime(true);
658
+
659
+ $data = str_repeat(rand(0, 9), 1024 * 1024); //write 1MB data
660
+
661
+ try {
662
+ $this->tmp_filesystem->write($tmp_file, $data);
663
+
664
+ $end_time = microtime(true) - $start_time;
665
+
666
+ $return['writing_time'] = $end_time;
667
+
668
+ $return['reading_time'] = $this->estimate_reading_time($tmp_file);
669
+
670
+ $this->tmp_filesystem->delete($tmp_file);
671
+
672
+ } catch (Exception $e) {
673
+
674
+ $this->logger->error($e->getMessage());
675
+
676
+ }
677
+
678
+ return $return;
679
+ }
680
+
681
+ public function backup_storage_cleanup()
682
+ {
683
+ $this->logger->info(sprintf(("Cleaning the backup storage on matching rules")));
684
+
685
+ $_storage_size = 0;
686
+ $_backup_files_list = array();
687
+
688
+ //rule date limit
689
+ $current_timestamp = strtotime("-" . $this->xcloner_settings->get_xcloner_option('xcloner_cleanup_retention_limit_days') . " days");
690
+
691
+ $files = $this->storage_filesystem->listContents();
692
+
693
+ if (is_array($files)) {
694
+ foreach ($files as $file) {
695
+ if (isset($file['extension']) and in_array($file['extension'], $this->backup_archive_extensions)) {
696
+ $_storage_size += $file['size']; //bytes
697
+ $_backup_files_list[] = $file;
698
+ }
699
+ }
700
+ }
701
+
702
+
703
+ $this->sort_by($_backup_files_list, "timestamp", "asc");
704
+
705
+ $_backups_counter = sizeof($_backup_files_list);
706
+
707
+ foreach ($_backup_files_list as $file) {
708
+ //processing rule folder capacity
709
+ if ($this->xcloner_settings->get_xcloner_option('xcloner_cleanup_capacity_limit') &&
710
+ $_storage_size >= ($set_storage_limit = 1024 * 1024 * $this->xcloner_settings->get_xcloner_option('xcloner_cleanup_capacity_limit'))) //bytes
711
+ {
712
+ $this->storage_filesystem->delete($file['path']);
713
+ $_storage_size -= $file['size'];
714
+ $this->logger->info("Deleting backup " . $file['path'] . " matching rule", array(
715
+ "STORAGE SIZE LIMIT",
716
+ $_storage_size . " >= " . $set_storage_limit
717
+ ));
718
+ }
719
+
720
+ //processing rule days limit
721
+ if ($this->xcloner_settings->get_xcloner_option('xcloner_cleanup_retention_limit_days') && $current_timestamp >= $file['timestamp']) {
722
+ $this->storage_filesystem->delete($file['path']);
723
+ $this->logger->info("Deleting backup " . $file['path'] . " matching rule", array(
724
+ "RETENTION LIMIT TIMESTAMP",
725
+ $file['timestamp'] . " =< " . $this->xcloner_settings->get_xcloner_option('xcloner_cleanup_retention_limit_days')
726
+ ));
727
+ }
728
+
729
+ //processing backup countert limit
730
+ if ($this->xcloner_settings->get_xcloner_option('xcloner_cleanup_retention_limit_archives') && $_backups_counter >= $this->xcloner_settings->get_xcloner_option('xcloner_cleanup_retention_limit_archives')) {
731
+ $this->storage_filesystem->delete($file['path']);
732
+ $_backups_counter--;
733
+ $this->logger->info("Deleting backup " . $file['path'] . " matching rule", array(
734
+ "BACKUP QUANTITY LIMIT",
735
+ $_backups_counter . " >= " . $this->xcloner_settings->get_xcloner_option('xcloner_cleanup_retention_limit_archives')
736
+ ));
737
+ }
738
+
739
+
740
+ }
741
+
742
+ }
743
+
744
+ public function estimate_reading_time($tmp_file)
745
+ {
746
+ $this->logger->debug(sprintf(("Estimating file system reading time")));
747
+
748
+ $start_time = microtime(true);
749
+
750
+ if ($this->tmp_filesystem->has($tmp_file)) {
751
+ $this->tmp_filesystem->read($tmp_file);
752
+ }
753
+
754
+ $end_time = microtime(true) - $start_time;
755
+
756
+ return $end_time;
757
+
758
+ }
759
+
760
+ public function process_backup_name($name = "", $max_length = 100)
761
+ {
762
+ if (!$name) {
763
+ $name = $this->xcloner_settings->get_default_backup_name();
764
+ }
765
+
766
+ foreach ($this->backup_name_tags as $tag) {
767
+ if ($tag == '[time]') {
768
+ $name = str_replace($tag, date("Y-m-d_H-i"), $name);
769
+ } elseif ($tag == '[hostname]') {
770
+ $name = str_replace($tag, gethostname(), $name);
771
+ } elseif ($tag == '[domain]') {
772
+ $domain = parse_url(admin_url(), PHP_URL_HOST);
773
+ $name = str_replace($tag, $domain, $name);
774
+ }
775
+ }
776
+
777
+ if ($max_length) {
778
+ $name = substr($name, 0, $max_length);
779
+ }
780
+
781
+ return $name;
782
+ }
783
+
784
+ public function sort_by(&$array, $field, $direction = 'asc')
785
+ {
786
+ if (strtolower($direction) == "desc" || $direction == SORT_DESC) {
787
+ $direction = SORT_DESC;
788
+ } else {
789
+ $direction = SORT_ASC;
790
+ }
791
+
792
+ $array = $this->array_orderby($array, $field, $direction);
793
+
794
+ return true;
795
+ }
796
+
797
+ private function array_orderby()
798
+ {
799
+ $args = func_get_args();
800
+ $data = array_shift($args);
801
+
802
+ foreach ($args as $n => $field) {
803
+ if (is_string($field)) {
804
+ $tmp = array();
805
+ foreach ($data as $key => $row) {
806
+ if (is_array($row)) {
807
+ $tmp[$key] = $row[$field];
808
+ } else {
809
+ $tmp[$key] = $row->$field;
810
+ }
811
+ }
812
+ $args[$n] = $tmp;
813
+ }
814
+ }
815
+ $args[] = &$data;
816
+
817
+ call_user_func_array('array_multisort', $args);
818
+
819
+ return array_pop($args);
820
+ }
821
+
822
+ private function check_file_diff_time($file)
823
+ {
824
+ if ($this->get_diff_timestamp_start() != "") {
825
+ $fileMeta = $this->getMetadataFull("start_adapter", $file['path']);
826
+ $timestamp = $fileMeta->getMTime();
827
+ if ($timestamp < $fileMeta->getCTime()) {
828
+ $timestamp = $fileMeta->getCTime();
829
+ }
830
+
831
+ if ($timestamp <= $this->get_diff_timestamp_start()) {
832
+ return " file DIFF timestamp " . $timestamp . " < " . $this->diff_timestamp_start;
833
+ }
834
+ }
835
+
836
+ return false;
837
+ }
838
+
839
+ public function is_excluded($file)
840
+ {
841
+ $this->logger->debug(sprintf(("Checking if %s is excluded"), $file['path']));
842
+
843
+ if ($xcloner_exclude_files_larger_than_mb = $this->xcloner_settings->get_xcloner_option('xcloner_exclude_files_larger_than_mb')) {
844
+ if (isset($file['size']) && $file['size'] > $this->calc_to_bytes($xcloner_exclude_files_larger_than_mb)) {
845
+ return "> " . $xcloner_exclude_files_larger_than_mb . "MB";
846
+ }
847
+ }
848
+
849
+ if (!is_array($this->excluded_files) || !sizeof($this->excluded_files)) {
850
+ $this->set_excluded_files();
851
+ }
852
+
853
+ if (is_array($this->excluded_files)) {
854
+ foreach ($this->excluded_files as $excluded_file_pattern) {
855
+ if ($excluded_file_pattern == "/") {
856
+ $needle = "$";
857
+ } else {
858
+ $needle = "$" . $excluded_file_pattern;
859
+ }
860
+
861
+ if (strstr("$" . $file['path'], $needle)) {
862
+ return $excluded_file_pattern;
863
+ }
864
+ }
865
+ }
866
+
867
+ if ($regex = $this->is_excluded_regex($file)) {
868
+ return $regex;
869
+ }
870
+
871
+ if ($file['type'] == "file") {
872
+ $check_file_diff_timestamp = $this->check_file_diff_time($file);
873
+ if ($check_file_diff_timestamp) {
874
+ return $check_file_diff_timestamp;
875
+ }
876
+ }
877
+
878
+ return false;
879
+ }
880
+
881
+ /*REGEX examples
882
+ *
883
+ * exclude all except .php file
884
+ * PATTERN: ^(.*)\.(.+)$(?<!(php))
885
+ *
886
+ * exclude all except .php and .txt
887
+ * PATTERN: ^(.*)\.(.+)$(?<!(php|txt))";
888
+ *
889
+ * exclude all .svn and .git
890
+ * PATTERN: ^(.*)\.(svn|git)(.*)$";
891
+ *
892
+ * exclude root directory /test
893
+ * PATTERN: "^\/test(.*)$";
894
+ *
895
+ * exclude the wp-admin folder
896
+ * PATTERN: ^(\/wp-admin)(.*)$";
897
+ *
898
+ * exclude the wp-admin, wp-includes and wp-config.php
899
+ * PATTERN: ^\/(wp-admin|wp-includes|wp-config.php)(.*)$";
900
+ *
901
+ * exclude all .avi files
902
+ * PATTERN: ^(.*)$(?<=(avi))";
903
+ *
904
+ * exclude all .jpg and gif files
905
+ * PATTERN: ^(.*)$(?<=(gif|jpg))";
906
+ *
907
+ * exclude all cache folders from wp-content/
908
+ * PATTERN: ^\/wp-content(.*)\/cache($|\/)(.*)";
909
+ *
910
+ * exclude the backup folders
911
+ * PATTERN: (^|^\/)(wp-content\/backups|administrator\/backups)(.*)$";
912
+ */
913
+ private function is_excluded_regex($file)
914
+ {
915
+ //$this->logger->debug(sprintf(("Checking if %s is excluded"), $file['path']));
916
+
917
+ $regex_patterns = explode(PHP_EOL, $this->xcloner_settings->get_xcloner_option('xcloner_regex_exclude'));
918
+
919
+ if (is_array($this->additional_regex_patterns)) {
920
+ $regex_patterns = array_merge($regex_patterns, $this->additional_regex_patterns);
921
+ }
922
+
923
+ //print_r($regex_patterns);exit;
924
+
925
+ if (is_array($regex_patterns)) {
926
+ //$this->excluded_files = array();
927
+ //$this->excluded_files[] ="(.*)\.(git)(.*)$";
928
+ //$this->excluded_files[] ="wp-content\/backups(.*)$";
929
+
930
+ foreach ($regex_patterns as $excluded_file_pattern) {
931
+
932
+ if (substr($excluded_file_pattern, strlen($excluded_file_pattern) - 1,
933
+ strlen($excluded_file_pattern)) == "\r") {
934
+ $excluded_file_pattern = substr($excluded_file_pattern, 0, strlen($excluded_file_pattern) - 1);
935
+ }
936
+
937
+ if ($file['path'] == "/") {
938
+ $needle = "/";
939
+ } else {
940
+ $needle = "/" . $file['path'];
941
+ }
942
+ //echo $needle."---".$excluded_file_pattern."---\n";
943
+
944
+ if (@preg_match("/(^|^\/)" . $excluded_file_pattern . "/i", $needle)) {
945
+ return $excluded_file_pattern;
946
+ }
947
+ }
948
+ }
949
+
950
+ return false;
951
+ }
952
+
953
+ public function store_file($file, $storage = 'start_filesystem')
954
+ {
955
+ $this->logger->debug(sprintf("Storing %s in the backup list", $file['path']));
956
+
957
+ if (!isset($file['size'])) {
958
+ $file['size'] = 0;
959
+ }
960
+ if (!isset($file['visibility'])) {
961
+ $file['visibility'] = "private";
962
+ }
963
+
964
+ $csv_filename = str_replace('"', '""', $file['path']);
965
+
966
+ $line = '"' . ($csv_filename) . '","' . $file['timestamp'] . '","' . $file['size'] . '","' . $file['visibility'] . '","' . $storage . '"' . PHP_EOL;
967
+
968
+ $this->last_logged_file = $file['path'];
969
+
970
+ if ($file['type'] == "dir") {
971
+ try {
972
+ $this->tmp_filesystem_append->write($this->get_temp_dir_handler(), $file['path'] . "\n");
973
+ } catch (Exception $e) {
974
+ $this->logger->error($e->getMessage());
975
+ }
976
+ }
977
+
978
+ if ($this->get_diff_timestamp_start()) {
979
+ if ($file['type'] != "file" && $response = $this->check_file_diff_time($file)) {
980
+ $this->logger->info(sprintf("Directory %s archiving skipped on differential backup %s", $file['path'],
981
+ $response), array(
982
+ "FILESYSTEM SCAN",
983
+ "DIR DIFF"
984
+ ));
985
+
986
+ return false;
987
+ }
988
+ }
989
+
990
+ try {
991
+ if (!$this->tmp_filesystem_append->has($this->get_included_files_handler())) {
992
+ //adding fix for UTF-8 CSV preview
993
+ $start_line = "\xEF\xBB\xBF" . '"Filename","Timestamp","Size","Visibility","Storage"' . PHP_EOL;
994
+ $this->tmp_filesystem_append->write($this->get_included_files_handler(), $start_line);
995
+ }
996
+
997
+ $this->tmp_filesystem_append->write($this->get_included_files_handler(), $line);
998
+
999
+ } catch (Exception $e) {
1000
+
1001
+ $this->logger->error($e->getMessage());
1002
+ }
1003
+
1004
+ return true;
1005
+ }
1006
+
1007
+ public function get_fileystem_handler()
1008
+ {
1009
+ return $this;
1010
+ }
1011
+
1012
+ public function get_filesystem($system = "")
1013
+ {
1014
+ if ($system == "storage_filesystem_append") {
1015
+ return $this->storage_filesystem_append;
1016
+ } elseif ($system == "tmp_filesystem_append") {
1017
+ return $this->tmp_filesystem_append;
1018
+ } elseif ($system == "tmp_filesystem") {
1019
+ return $this->tmp_filesystem;
1020
+ } elseif ($system == "storage_filesystem") {
1021
+ return $this->storage_filesystem;
1022
+ } else {
1023
+ return $this->start_filesystem;
1024
+ }
1025
+ }
1026
+
1027
+ public function get_adapter($system)
1028
+ {
1029
+ if ($system == "tmp_filesystem") {
1030
+ return $this->tmp_adapter;
1031
+ } elseif ($system == "storage_filesystem") {
1032
+ return $this->storage_adapter;
1033
+ } else {
1034
+ return $this->start_adapter;
1035
+ }
1036
+ }
1037
+
1038
+ /**
1039
+ * File scan finished
1040
+ * Method called when file scan is finished
1041
+ *
1042
+ * @return bool
1043
+ */
1044
+ private function scan_finished()
1045
+ {
1046
+ if ($this->tmp_filesystem_append->has($this->get_temp_dir_handler()) &&
1047
+ $this->tmp_filesystem_append->getSize($this->get_temp_dir_handler())) {
1048
+ return false;
1049
+ }
1050
+
1051
+ if ($this->tmp_filesystem->has($this->get_temp_dir_handler())) {
1052
+ $this->tmp_filesystem->delete($this->get_temp_dir_handler());
1053
+ }
1054
+
1055
+ $this->logger->debug(sprintf(("File scan finished")));
1056
+
1057
+ return true;
1058
+ }
1059
+
1060
+ /**
1061
+ * Calculate bytes from MB value
1062
+ *
1063
+ * @param int $mb_size
1064
+ *
1065
+ * @return float|int
1066
+ */
1067
+ private function calc_to_bytes($mb_size)
1068
+ {
1069
+ return $mb_size * (1024 * 1024);
1070
+ }
1071
+
1072
  }
includes/class-xcloner-file-transfer.php CHANGED
@@ -1,102 +1,164 @@
1
  <?php
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
 
3
- class Xcloner_File_Transfer extends Xcloner_File_System{
4
-
5
- private $target_url;
6
- private $transfer_limit = 1048576; //bytes 1MB= 1048576 300KB = 358400
7
-
8
-
9
- public function set_target($target_url)
10
- {
11
- return $this->target_url= $target_url;
12
- }
13
-
14
- public function get_target()
15
- {
16
- return $this->target_url;
17
- }
18
-
19
-
20
- public function transfer_file($file, $start = 0, $hash = "")
21
- {
22
- if(!$this->target_url)
23
- throw new Exception("Please setup a target url for upload");
24
-
25
-
26
- $fp = $this->get_storage_filesystem()->readStream($file);
27
-
28
- fseek($fp, $start, SEEK_SET);
29
-
30
- $binary_data = fread($fp, $this->transfer_limit);
31
-
32
- $tmp_filename = "xcloner_upload_".substr(md5(time()), 0, 5);
33
-
34
- $this->get_tmp_filesystem()->write($tmp_filename, $binary_data);
35
-
36
- $tmp_file_path = $this->get_tmp_filesystem_adapter()->applyPathPrefix($tmp_filename);
37
-
38
- $send_array = array();
39
-
40
- $send_array['file'] = $file;
41
- $send_array['start'] = $start;
42
- $send_array['xcloner_action'] = "write_file";
43
- $send_array['hash'] = $hash;
44
- #$send_array['blob'] = $binary_data;
45
- $send_array['blob'] = $this->curl_file_create($tmp_file_path,'application/x-binary',$tmp_filename);
46
-
47
- //$data = http_build_query($send_array);
48
-
49
- $this->get_logger()->info(sprintf("Sending curl request to %s with %s data of file %s starting position %s using temporary file %s", $this->target_url, $this->transfer_limit, $file, $start, $tmp_filename));
50
-
51
-
52
- $ch = curl_init();
53
- curl_setopt($ch, CURLOPT_URL,$this->target_url);
54
-
55
- curl_setopt($ch, CURLOPT_POST, 1);
56
- curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
  curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
58
  curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 60);
59
  curl_setopt($ch, CURLOPT_TIMEOUT, 1200);
60
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
61
-
62
- curl_setopt($ch, CURLOPT_POSTFIELDS, $send_array );
63
- curl_setopt($ch, CURLOPT_VERBOSE, true);
64
-
65
- $original_result = curl_exec ($ch);
66
-
67
- $this->get_tmp_filesystem()->delete($tmp_filename);
68
-
69
- $result = json_decode($original_result);
70
-
71
- if(!$result)
72
- throw new Exception("We have received no valid response from the remote host, original message: ". $original_result);
73
-
74
- if($result->status != 200)
75
- {
76
- throw new Exception($result->response);
77
- }
78
-
79
- if(ftell($fp) >= $this->get_storage_filesystem()->getSize($file))
80
- {
81
- $this->get_logger()->info(sprintf("Upload done for file %s to target url %s, transferred a total of %s bytes", $file, $this->target_url, ftell($fp)));
82
- $this->remove_tmp_filesystem();
83
- return false;
84
- }
85
-
86
- return ftell($fp);
87
- }
88
-
89
- private function curl_file_create($filename, $mimetype = '', $postname = '') {
90
- if (!function_exists('curl_file_create')) {
91
-
92
- return "@$filename;filename="
93
- . ($postname ?: basename($filename))
94
- . ($mimetype ? ";type=$mimetype" : '');
95
-
96
- }else{
97
-
98
- return curl_file_create($filename, $mimetype, $postname);
99
-
100
- }
101
- }
 
 
 
 
 
 
 
 
 
102
  }
1
  <?php
2
+ /**
3
+ * XCloner - Backup and Restore backup plugin for Wordpress
4
+ *
5
+ * class-xcloner-file-transfer.php
6
+ * @author Liuta Ovidiu <info@thinkovi.com>
7
+ *
8
+ * This program is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation; either version 2 of the License, or
11
+ * (at your option) any later version.
12
+ *
13
+ * This program is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ * GNU General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU General Public License
19
+ * along with this program; if not, write to the Free Software
20
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21
+ * MA 02110-1301, USA.
22
+ *
23
+ * @link https://github.com/ovidiul/XCloner-Wordpress
24
+ *
25
+ * @modified 7/25/18 1:46 PM
26
+ *
27
+ */
28
 
29
+ class Xcloner_File_Transfer extends Xcloner_File_System
30
+ {
31
+
32
+ /**
33
+ * Target url web address of the restore script
34
+ * @var string
35
+ */
36
+ private $target_url;
37
+ /**
38
+ * Transfer data limit in bytes
39
+ * @var int
40
+ */
41
+ private $transfer_limit = 1048576; //bytes 1MB= 1048576 300KB = 358400
42
+
43
+
44
+ /**
45
+ * @param $target_url
46
+ *
47
+ * @return mixed
48
+ */
49
+ public function set_target($target_url)
50
+ {
51
+ return $this->target_url = $target_url;
52
+ }
53
+
54
+ /**
55
+ * @return mixed
56
+ */
57
+ public function get_target()
58
+ {
59
+ return $this->target_url;
60
+ }
61
+
62
+
63
+ /**
64
+ * @param $file
65
+ * @param int $start
66
+ * @param string $hash
67
+ *
68
+ * @return bool|int
69
+ * @throws Exception
70
+ */
71
+ public function transfer_file($file, $start = 0, $hash = "")
72
+ {
73
+ if (!$this->target_url) {
74
+ throw new Exception("Please setup a target url for upload");
75
+ }
76
+
77
+
78
+ $fp = $this->get_storage_filesystem()->readStream($file);
79
+
80
+ fseek($fp, $start, SEEK_SET);
81
+
82
+ $binary_data = fread($fp, $this->transfer_limit);
83
+
84
+ $tmp_filename = "xcloner_upload_" . substr(md5(time()), 0, 5);
85
+
86
+ $this->get_tmp_filesystem()->write($tmp_filename, $binary_data);
87
+
88
+ $tmp_file_path = $this->get_tmp_filesystem_adapter()->applyPathPrefix($tmp_filename);
89
+
90
+ $send_array = array();
91
+
92
+ $send_array['file'] = $file;
93
+ $send_array['start'] = $start;
94
+ $send_array['xcloner_action'] = "write_file";
95
+ $send_array['hash'] = $hash;
96
+ #$send_array['blob'] = $binary_data;
97
+ $send_array['blob'] = $this->curl_file_create($tmp_file_path, 'application/x-binary', $tmp_filename);
98
+
99
+ //$data = http_build_query($send_array);
100
+
101
+ $this->get_logger()->info(sprintf("Sending curl request to %s with %s data of file %s starting position %s using temporary file %s",
102
+ $this->target_url, $this->transfer_limit, $file, $start, $tmp_filename));
103
+
104
+
105
+ $ch = curl_init();
106
+ curl_setopt($ch, CURLOPT_URL, $this->target_url);
107
+
108
+ curl_setopt($ch, CURLOPT_POST, 1);
109
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
110
  curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
111
  curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 60);
112
  curl_setopt($ch, CURLOPT_TIMEOUT, 1200);
113
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
114
+
115
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $send_array);
116
+ curl_setopt($ch, CURLOPT_VERBOSE, true);
117
+
118
+ $original_result = curl_exec($ch);
119
+
120
+ $this->get_tmp_filesystem()->delete($tmp_filename);
121
+
122
+ $result = json_decode($original_result);
123
+
124
+ if (!$result) {
125
+ throw new Exception("We have received no valid response from the remote host, original message: " . $original_result);
126
+ }
127
+
128
+ if ($result->status != 200) {
129
+ throw new Exception($result->response);
130
+ }
131
+
132
+ if (ftell($fp) >= $this->get_storage_filesystem()->getSize($file)) {
133
+ $this->get_logger()->info(sprintf("Upload done for file %s to target url %s, transferred a total of %s bytes",
134
+ $file, $this->target_url, ftell($fp)));
135
+ $this->remove_tmp_filesystem();
136
+
137
+ return false;
138
+ }
139
+
140
+ return ftell($fp);
141
+ }
142
+
143
+ /**
144
+ * @param $filename
145
+ * @param string $mimetype
146
+ * @param string $postname
147
+ *
148
+ * @return CURLFile|string
149
+ */
150
+ private function curl_file_create($filename, $mimetype = '', $postname = '')
151
+ {
152
+ if (!function_exists('curl_file_create')) {
153
+
154
+ return "@$filename;filename="
155
+ . ($postname ?: basename($filename))
156
+ . ($mimetype ? ";type=$mimetype" : '');
157
+
158
+ } else {
159
+
160
+ return curl_file_create($filename, $mimetype, $postname);
161
+
162
+ }
163
+ }
164
  }
includes/class-xcloner-i18n.php CHANGED
@@ -1,18 +1,32 @@
1
  <?php
2
-
3
  /**
4
- * Define the internationalization functionality
5
  *
6
- * Loads and defines the internationalization files for this plugin
7
- * so that it is ready for translation.
8
  *
9
- * @link http://www.thinkovi.com
10
- * @since 1.0.0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  *
12
- * @package Xcloner
13
- * @subpackage Xcloner/includes
14
  */
15
 
 
16
  /**
17
  * Define the internationalization functionality.
18
  *
@@ -24,24 +38,24 @@
24
  * @subpackage Xcloner/includes
25
  * @author Liuta Ovidiu <info@thinkovi.com>
26
  */
27
- class Xcloner_i18n {
28
-
29
-
30
- /**
31
- * Load the plugin text domain for translation.
32
- *
33
- * @since 1.0.0
34
- */
35
- public function load_plugin_textdomain() {
36
-
37
- load_plugin_textdomain(
38
- 'xcloner-backup-and-restore',
39
- false,
40
- dirname( dirname( plugin_basename( __FILE__ ) ) ) . '/languages/'
41
- );
42
-
43
- }
44
-
45
 
46
 
47
  }
1
  <?php
 
2
  /**
3
+ * XCloner - Backup and Restore backup plugin for Wordpress
4
  *
5
+ * class-xcloner-i18n.php
6
+ * @author Liuta Ovidiu <info@thinkovi.com>
7
  *
8
+ * This program is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation; either version 2 of the License, or
11
+ * (at your option) any later version.
12
+ *
13
+ * This program is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ * GNU General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU General Public License
19
+ * along with this program; if not, write to the Free Software
20
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21
+ * MA 02110-1301, USA.
22
+ *
23
+ * @link https://github.com/ovidiul/XCloner-Wordpress
24
+ *
25
+ * @modified 7/25/18 1:46 PM
26
  *
 
 
27
  */
28
 
29
+
30
  /**
31
  * Define the internationalization functionality.
32
  *
38
  * @subpackage Xcloner/includes
39
  * @author Liuta Ovidiu <info@thinkovi.com>
40
  */
41
+ class Xcloner_i18n
42
+ {
43
+
44
+ /**
45
+ * Load the plugin text domain for translation.
46
+ *
47
+ * @since 1.0.0
48
+ */
49
+ public function load_plugin_textdomain()
50
+ {
51
+
52
+ load_plugin_textdomain(
53
+ 'xcloner-backup-and-restore',
54
+ false,
55
+ dirname(dirname(plugin_basename(__FILE__))) . '/languages/'
56
+ );
57
+
58
+ }
59
 
60
 
61
  }
includes/class-xcloner-loader.php CHANGED
@@ -1,15 +1,32 @@
1
  <?php
2
-
3
  /**
4
- * Register all actions and filters for the plugin
5
  *
6
- * @link http://www.thinkovi.com
7
- * @since 1.0.0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  *
9
- * @package Xcloner
10
- * @subpackage Xcloner/includes
11
  */
12
 
 
13
  /**
14
  * Register all actions and filters for the plugin.
15
  *
@@ -21,132 +38,157 @@
21
  * @subpackage Xcloner/includes
22
  * @author Liuta Ovidiu <info@thinkovi.com>
23
  */
24
- class Xcloner_Loader {
25
-
26
- /**
27
- * The array of actions registered with WordPress.
28
- *
29
- * @since 1.0.0
30
- * @access protected
31
- * @var array $actions The actions registered with WordPress to fire when the plugin loads.
32
- */
33
- protected $actions;
34
-
35
- /**
36
- * The array of filters registered with WordPress.
37
- *
38
- * @since 1.0.0
39
- * @access protected
40
- * @var array $filters The filters registered with WordPress to fire when the plugin loads.
41
- */
42
- protected $filters;
43
-
44
- private $xcloner_plugin;
45
- /**
46
- * Initialize the collections used to maintain the actions and filters.
47
- *
48
- * @since 1.0.0
49
- */
50
- public function __construct(Xcloner $xcloner_container) {
51
-
52
- $this->actions = array();
53
- $this->filters = array();
54
-
55
- $this->xcloner_container = $xcloner_container;
56
-
57
- }
58
-
59
- public function xcloner_backup_add_admin_menu()
60
- {
61
- if ( function_exists('add_menu_page') )
62
- add_menu_page( __('Site Backup','xcloner-backup-and-restore'), __('Site Backup','xcloner-backup-and-restore'), 'manage_options', 'xcloner_init_page', array($this->xcloner_container, 'xcloner_display'), 'dashicons-backup');
63
-
64
- if ( function_exists('add_submenu_page') )
65
- {
66
-
67
- add_submenu_page( 'xcloner_init_page', __('XCloner Dashboard','xcloner-backup-and-restore'), __('Dashboard','xcloner-backup-and-restore'), 'manage_options', 'xcloner_init_page', array($this->xcloner_container, 'xcloner_display'));
68
- add_submenu_page( 'xcloner_init_page', __('XCloner Backup Settings','xcloner-backup-and-restore'), __('Settings','xcloner-backup-and-restore'), 'manage_options', 'xcloner_settings_page', array($this->xcloner_container, 'xcloner_display'));
69
- add_submenu_page( 'xcloner_init_page', __('Remote Storage Settings','xcloner-backup-and-restore'), __('Remote Storage','xcloner-backup-and-restore'), 'manage_options', 'xcloner_remote_storage_page', array($this->xcloner_container, 'xcloner_display'));
70
- add_submenu_page( 'xcloner_init_page', __('Manage Backups','xcloner-backup-and-restore'), __('Manage Backups','xcloner-backup-and-restore'), 'manage_options', 'xcloner_manage_backups_page', array($this->xcloner_container, 'xcloner_display'));
71
- add_submenu_page( 'xcloner_init_page', __('Scheduled Backups','xcloner-backup-and-restore'), __('Scheduled Backups','xcloner-backup-and-restore'), 'manage_options', 'xcloner_scheduled_backups_page', array($this->xcloner_container, 'xcloner_display'));
72
- add_submenu_page( 'xcloner_init_page', __('Generate Backups','xcloner-backup-and-restore'), __('Generate Backups','xcloner-backup-and-restore'), 'manage_options', 'xcloner_generate_backups_page', array($this->xcloner_container, 'xcloner_display'));
73
- add_submenu_page( 'xcloner_init_page', __('Restore Backups','xcloner-backup-and-restore'), __('Restore Backups','xcloner-backup-and-restore'), 'manage_options', 'xcloner_restore_page', array($this->xcloner_container, 'xcloner_display'));
74
- }
75
-
76
- }
77
-
78
-
79
- /**
80
- * Add a new action to the collection to be registered with WordPress.
81
- *
82
- * @since 1.0.0
83
- * @param string $hook The name of the WordPress action that is being registered.
84
- * @param object $component A reference to the instance of the object on which the action is defined.
85
- * @param string $callback The name of the function definition on the $component.
86
- * @param int $priority Optional. he priority at which the function should be fired. Default is 10.
87
- * @param int $accepted_args Optional. The number of arguments that should be passed to the $callback. Default is 1.
88
- */
89
- public function add_action( $hook, $component, $callback, $priority = 10, $accepted_args = 1 ) {
90
- $this->actions = $this->add( $this->actions, $hook, $component, $callback, $priority, $accepted_args );
91
- }
92
-
93
- /**
94
- * Add a new filter to the collection to be registered with WordPress.
95
- *
96
- * @since 1.0.0
97
- * @param string $hook The name of the WordPress filter that is being registered.
98
- * @param object $component A reference to the instance of the object on which the filter is defined.
99
- * @param string $callback The name of the function definition on the $component.
100
- * @param int $priority Optional. he priority at which the function should be fired. Default is 10.
101
- * @param int $accepted_args Optional. The number of arguments that should be passed to the $callback. Default is 1
102
- */
103
- public function add_filter( $hook, $component, $callback, $priority = 10, $accepted_args = 1 ) {
104
- $this->filters = $this->add( $this->filters, $hook, $component, $callback, $priority, $accepted_args );
105
- }
106
-
107
- /**
108
- * A utility function that is used to register the actions and hooks into a single
109
- * collection.
110
- *
111
- * @since 1.0.0
112
- * @access private
113
- * @param array $hooks The collection of hooks that is being registered (that is, actions or filters).
114
- * @param string $hook The name of the WordPress filter that is being registered.
115
- * @param object $component A reference to the instance of the object on which the filter is defined.
116
- * @param string $callback The name of the function definition on the $component.
117
- * @param int $priority The priority at which the function should be fired.
118
- * @param int $accepted_args The number of arguments that should be passed to the $callback.
119
- * @return array The collection of actions and filters registered with WordPress.
120
- */
121
- private function add( $hooks, $hook, $component, $callback, $priority, $accepted_args ) {
122
-
123
- $hooks[] = array(
124
- 'hook' => $hook,
125
- 'component' => $component,
126
- 'callback' => $callback,
127
- 'priority' => $priority,
128
- 'accepted_args' => $accepted_args
129
- );
130
-
131
- return $hooks;
132
-
133
- }
134
-
135
- /**
136
- * Register the filters and actions with WordPress.
137
- *
138
- * @since 1.0.0
139
- */
140
- public function run() {
141
-
142
- foreach ( $this->filters as $hook ) {
143
- add_filter( $hook['hook'], array( $hook['component'], $hook['callback'] ), $hook['priority'], $hook['accepted_args'] );
144
- }
145
-
146
- foreach ( $this->actions as $hook ) {
147
- add_action( $hook['hook'], array( $hook['component'], $hook['callback'] ), $hook['priority'], $hook['accepted_args'] );
148
- }
149
-
150
- }
151
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
152
  }
1
  <?php
 
2
  /**
3
+ * XCloner - Backup and Restore backup plugin for Wordpress
4
  *
5
+ * class-xcloner-loader.php
6
+ * @author Liuta Ovidiu <info@thinkovi.com>
7
+ *
8
+ * This program is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation; either version 2 of the License, or
11
+ * (at your option) any later version.
12
+ *
13
+ * This program is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ * GNU General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU General Public License
19
+ * along with this program; if not, write to the Free Software
20
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21
+ * MA 02110-1301, USA.
22
+ *
23
+ * @link https://github.com/ovidiul/XCloner-Wordpress
24
+ *
25
+ * @modified 7/25/18 1:46 PM
26
  *
 
 
27
  */
28
 
29
+
30
  /**
31
  * Register all actions and filters for the plugin.
32
  *
38
  * @subpackage Xcloner/includes
39
  * @author Liuta Ovidiu <info@thinkovi.com>
40
  */
41
+ class Xcloner_Loader
42
+ {
43
+
44
+ /**
45
+ * The array of actions registered with WordPress.
46
+ *
47
+ * @since 1.0.0
48
+ * @access protected
49
+ * @var array $actions The actions registered with WordPress to fire when the plugin loads.
50
+ */
51
+ protected $actions;
52
+
53
+ /**
54
+ * The array of filters registered with WordPress.
55
+ *
56
+ * @since 1.0.0
57
+ * @access protected
58
+ * @var array $filters The filters registered with WordPress to fire when the plugin loads.
59
+ */
60
+ protected $filters;
61
+
62
+ private $xcloner_plugin;
63
+
64
+ /**
65
+ * Initialize the collections used to maintain the actions and filters.
66
+ *
67
+ * @since 1.0.0
68
+ */
69
+ public function __construct(Xcloner $xcloner_container)
70
+ {
71
+
72
+ $this->actions = array();
73
+ $this->filters = array();
74
+
75
+ $this->xcloner_container = $xcloner_container;
76
+
77
+ }
78
+
79
+ public function xcloner_backup_add_admin_menu()
80
+ {
81
+ if (function_exists('add_menu_page')) {
82
+ add_menu_page(__('Site Backup', 'xcloner-backup-and-restore'),
83
+ __('Site Backup', 'xcloner-backup-and-restore'), 'manage_options', 'xcloner_init_page',
84
+ array($this->xcloner_container, 'xcloner_display'), 'dashicons-backup');
85
+ }
86
+
87
+ if (function_exists('add_submenu_page')) {
88
+
89
+ add_submenu_page('xcloner_init_page', __('XCloner Dashboard', 'xcloner-backup-and-restore'),
90
+ __('Dashboard', 'xcloner-backup-and-restore'), 'manage_options', 'xcloner_init_page',
91
+ array($this->xcloner_container, 'xcloner_display'));
92
+ add_submenu_page('xcloner_init_page', __('XCloner Backup Settings', 'xcloner-backup-and-restore'),
93
+ __('Settings', 'xcloner-backup-and-restore'), 'manage_options', 'xcloner_settings_page',
94
+ array($this->xcloner_container, 'xcloner_display'));
95
+ add_submenu_page('xcloner_init_page', __('Remote Storage Settings', 'xcloner-backup-and-restore'),
96
+ __('Remote Storage', 'xcloner-backup-and-restore'), 'manage_options', 'xcloner_remote_storage_page',
97
+ array($this->xcloner_container, 'xcloner_display'));
98
+ add_submenu_page('xcloner_init_page', __('Manage Backups', 'xcloner-backup-and-restore'),
99
+ __('Manage Backups', 'xcloner-backup-and-restore'), 'manage_options', 'xcloner_manage_backups_page',
100
+ array($this->xcloner_container, 'xcloner_display'));
101
+ add_submenu_page('xcloner_init_page', __('Scheduled Backups', 'xcloner-backup-and-restore'),
102
+ __('Scheduled Backups', 'xcloner-backup-and-restore'), 'manage_options',
103
+ 'xcloner_scheduled_backups_page', array($this->xcloner_container, 'xcloner_display'));
104
+ add_submenu_page('xcloner_init_page', __('Generate Backups', 'xcloner-backup-and-restore'),
105
+ __('Generate Backups', 'xcloner-backup-and-restore'), 'manage_options', 'xcloner_generate_backups_page',
106
+ array($this->xcloner_container, 'xcloner_display'));
107
+ add_submenu_page('xcloner_init_page', __('Restore Backups', 'xcloner-backup-and-restore'),
108
+ __('Restore Backups', 'xcloner-backup-and-restore'), 'manage_options', 'xcloner_restore_page',
109
+ array($this->xcloner_container, 'xcloner_display'));
110
+ }
111
+
112
+ }
113
+
114
+
115
+ /**
116
+ * Add a new action to the collection to be registered with WordPress.
117
+ *
118
+ * @since 1.0.0
119
+ * @param string $hook The name of the WordPress action that is being registered.
120
+ * @param object $component A reference to the instance of the object on which the action is defined.
121
+ * @param string $callback The name of the function definition on the $component.
122
+ * @param int $priority Optional. he priority at which the function should be fired. Default is 10.
123
+ * @param int $accepted_args Optional. The number of arguments that should be passed to the $callback. Default is 1.
124
+ */
125
+ public function add_action($hook, $component, $callback, $priority = 10, $accepted_args = 1)
126
+ {
127
+ $this->actions = $this->add($this->actions, $hook, $component, $callback, $priority, $accepted_args);
128
+ }
129
+
130
+ /**
131
+ * Add a new filter to the collection to be registered with WordPress.
132
+ *
133
+ * @since 1.0.0
134
+ * @param string $hook The name of the WordPress filter that is being registered.
135
+ * @param object $component A reference to the instance of the object on which the filter is defined.
136
+ * @param string $callback The name of the function definition on the $component.
137
+ * @param int $priority Optional. he priority at which the function should be fired. Default is 10.
138
+ * @param int $accepted_args Optional. The number of arguments that should be passed to the $callback. Default is 1
139
+ */
140
+ public function add_filter($hook, $component, $callback, $priority = 10, $accepted_args = 1)
141
+ {
142
+ $this->filters = $this->add($this->filters, $hook, $component, $callback, $priority, $accepted_args);
143
+ }
144
+
145
+ /**
146
+ * A utility function that is used to register the actions and hooks into a single
147
+ * collection.
148
+ *
149
+ * @since 1.0.0
150
+ * @access private
151
+ * @param array $hooks The collection of hooks that is being registered (that is, actions or filters).
152
+ * @param string $hook The name of the WordPress filter that is being registered.
153
+ * @param object $component A reference to the instance of the object on which the filter is defined.
154
+ * @param string $callback The name of the function definition on the $component.
155
+ * @param int $priority The priority at which the function should be fired.
156
+ * @param int $accepted_args The number of arguments that should be passed to the $callback.
157
+ * @return array The collection of actions and filters registered with WordPress.
158
+ */
159
+ private function add($hooks, $hook, $component, $callback, $priority, $accepted_args)
160
+ {
161
+
162
+ $hooks[] = array(
163
+ 'hook' => $hook,
164
+ 'component' => $component,
165
+ 'callback' => $callback,
166
+ 'priority' => $priority,
167
+ 'accepted_args' => $accepted_args
168
+ );
169
+
170
+ return $hooks;
171
+
172
+ }
173
+
174
+ /**
175
+ * Register the filters and actions with WordPress.
176
+ *
177
+ * @since 1.0.0
178
+ */
179
+ public function run()
180
+ {
181
+
182
+ foreach ($this->filters as $hook) {
183
+ add_filter($hook['hook'], array($hook['component'], $hook['callback']), $hook['priority'],
184
+ $hook['accepted_args']);
185
+ }
186
+
187
+ foreach ($this->actions as $hook) {
188
+ add_action($hook['hook'], array($hook['component'], $hook['callback']), $hook['priority'],
189
+ $hook['accepted_args']);
190
+ }
191
+
192
+ }
193
+
194
  }
includes/class-xcloner-logger.php CHANGED
@@ -4,117 +4,106 @@ use Monolog\Logger;
4
  use Monolog\Handler\StreamHandler;
5
  use Monolog\Handler\RotatingFileHandler;
6
 
7
- class Xcloner_Logger extends Logger{
8
-
9
- private $logger_path ;
10
  private $max_logger_files = 7;
11
  private $main_logger_url;
12
-
13
- public function __construct(Xcloner $xcloner_container, $logger_name = "xcloner_logger")
14
- {
15
- if(!$xcloner_container->get_xcloner_settings())
16
- {
17
- $xcloner_settings = new Xcloner_Settings($xcloner_container);
18
- }else{
19
- $xcloner_settings = $xcloner_container->get_xcloner_settings();
20
  }
21
-
22
  $hash = $xcloner_settings->get_hash();
23
- if($hash == "-".$xcloner_settings->get_server_unique_hash(5))
24
- {
25
  $hash = "";
26
  }
27
-
28
- $logger_path = $xcloner_settings->get_xcloner_store_path().DS.$xcloner_settings->get_logger_filename();
29
- $logger_path_tmp = "";
30
-
31
- if($hash)
32
- {
33
- $logger_path_tmp = $xcloner_settings->get_xcloner_tmp_path().DS.$xcloner_settings->get_logger_filename(1);
34
  }
35
-
36
  $this->logger_path = $logger_path;
37
-
38
- if(!is_dir($xcloner_settings->get_xcloner_store_path()) or !is_writable($xcloner_settings->get_xcloner_store_path()))
39
- {
40
- $logger_path = 'php://stderr';
41
  $logger_path_tmp = "";
42
  }
43
-
44
- if(!$xcloner_settings->get_xcloner_option('xcloner_enable_log'))
45
- {
46
- $logger_path = 'php://stderr';
47
  $logger_path_tmp = "";
48
  }
49
-
50
  // create a log channel
51
- parent::__construct($logger_name);
52
-
53
  $debug_level = Logger::INFO;
54
-
55
- if(WP_DEBUG)
56
- {
57
  $debug_level = Logger::DEBUG;
58
  }
59
 
60
-
61
- if($logger_path)
62
- {
63
- if(!$xcloner_settings->get_xcloner_option('xcloner_enable_log'))
64
- {
65
- $stream = new StreamHandler($logger_path, $debug_level);
66
- }else{
67
- $stream = new RotatingFileHandler($logger_path, $this->max_logger_files, $debug_level);
68
  }
69
-
70
- $this->pushHandler($stream);
71
-
72
- $this->main_logger_url = $stream->getUrl();
73
  }
74
-
75
- if($hash and $logger_path_tmp)
76
- {
77
- $this->pushHandler(new StreamHandler($logger_path_tmp, $debug_level));
78
  }
79
-
80
  //return $this;
81
  }
82
-
83
- function get_main_logger_url()
84
- {
85
  return $this->main_logger_url;
86
  }
87
-
88
- function getLastDebugLines($totalLines = 200)
89
- {
90
  $lines = array();
91
-
92
- if(!file_exists($this->main_logger_url) or !is_readable($this->main_logger_url))
93
  return false;
94
-
95
- $fp = fopen($this->main_logger_url, 'r');
96
- fseek($fp, -1, SEEK_END);
97
- $pos = ftell($fp);
 
98
  $lastLine = "";
99
-
100
  // Loop backword until we have our lines or we reach the start
101
- while($pos > 0 && count($lines) < $totalLines) {
102
-
103
- $C = fgetc($fp);
104
- if($C == "\n") {
105
- // skip empty lines
106
- if(trim($lastLine) != "") {
107
- $lines[] = $lastLine;
108
- }
109
- $lastLine = '';
110
- } else {
111
- $lastLine = $C.$lastLine;
112
- }
113
- fseek($fp, $pos--);
114
  }
115
-
116
- $lines = array_reverse($lines);
117
-
118
  return $lines;
119
  }
120
  }
4
  use Monolog\Handler\StreamHandler;
5
  use Monolog\Handler\RotatingFileHandler;
6
 
7
+ class Xcloner_Logger extends Logger {
8
+
9
+ private $logger_path;
10
  private $max_logger_files = 7;
11
  private $main_logger_url;
12
+
13
+ public function __construct( Xcloner $xcloner_container, $logger_name = "xcloner_logger" ) {
14
+ if ( ! $xcloner_container->get_xcloner_settings() ) {
15
+ $xcloner_settings = new Xcloner_Settings( $xcloner_container );
16
+ } else {
17
+ $xcloner_settings = $xcloner_container->get_xcloner_settings();
 
 
18
  }
19
+
20
  $hash = $xcloner_settings->get_hash();
21
+ if ( $hash == "-" . $xcloner_settings->get_server_unique_hash( 5 ) ) {
 
22
  $hash = "";
23
  }
24
+
25
+ $logger_path = $xcloner_settings->get_xcloner_store_path() . DS . $xcloner_settings->get_logger_filename();
26
+ $logger_path_tmp = "";
27
+
28
+ if ( $hash ) {
29
+ $logger_path_tmp = $xcloner_settings->get_xcloner_tmp_path() . DS . $xcloner_settings->get_logger_filename( 1 );
 
30
  }
31
+
32
  $this->logger_path = $logger_path;
33
+
34
+ if ( ! is_dir( $xcloner_settings->get_xcloner_store_path() ) or ! is_writable( $xcloner_settings->get_xcloner_store_path() ) ) {
35
+ $logger_path = 'php://stderr';
 
36
  $logger_path_tmp = "";
37
  }
38
+
39
+ if ( ! $xcloner_settings->get_xcloner_option( 'xcloner_enable_log' ) ) {
40
+ $logger_path = 'php://stderr';
 
41
  $logger_path_tmp = "";
42
  }
43
+
44
  // create a log channel
45
+ parent::__construct( $logger_name );
46
+
47
  $debug_level = Logger::INFO;
48
+
49
+ if ( WP_DEBUG ) {
 
50
  $debug_level = Logger::DEBUG;
51
  }
52
 
53
+
54
+ if ( $logger_path ) {
55
+ if ( ! $xcloner_settings->get_xcloner_option( 'xcloner_enable_log' ) ) {
56
+ $stream = new StreamHandler( $logger_path, $debug_level );
57
+ } else {
58
+ $stream = new RotatingFileHandler( $logger_path, $this->max_logger_files, $debug_level );
 
 
59
  }
60
+
61
+ $this->pushHandler( $stream );
62
+
63
+ $this->main_logger_url = $stream->getUrl();
64
  }
65
+
66
+ if ( $hash and $logger_path_tmp ) {
67
+ $this->pushHandler( new StreamHandler( $logger_path_tmp, $debug_level ) );
 
68
  }
69
+
70
  //return $this;
71
  }
72
+
73
+ function get_main_logger_url() {
 
74
  return $this->main_logger_url;
75
  }
76
+
77
+ function getLastDebugLines( $totalLines = 200 ) {
 
78
  $lines = array();
79
+
80
+ if ( ! file_exists( $this->main_logger_url ) or ! is_readable( $this->main_logger_url ) ) {
81
  return false;
82
+ }
83
+
84
+ $fp = fopen( $this->main_logger_url, 'r' );
85
+ fseek( $fp, - 1, SEEK_END );
86
+ $pos = ftell( $fp );
87
  $lastLine = "";
88
+
89
  // Loop backword until we have our lines or we reach the start
90
+ while ( $pos > 0 && count( $lines ) < $totalLines ) {
91
+
92
+ $C = fgetc( $fp );
93
+ if ( $C == "\n" ) {
94
+ // skip empty lines
95
+ if ( trim( $lastLine ) != "" ) {
96
+ $lines[] = $lastLine;
97
+ }
98
+ $lastLine = '';
99
+ } else {
100
+ $lastLine = $C . $lastLine;
101
+ }
102
+ fseek( $fp, $pos -- );
103
  }
104
+
105
+ $lines = array_reverse( $lines );
106
+
107
  return $lines;
108
  }
109
  }
includes/class-xcloner-remote-storage.php CHANGED
@@ -1,4 +1,31 @@
1
  <?php
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  use League\Flysystem\Config;
3
  use League\Flysystem\Filesystem;
4
 
@@ -6,8 +33,6 @@ use League\Flysystem\Adapter\Ftp as Adapter;
6
 
7
  use League\Flysystem\Sftp\SftpAdapter;
8
 
9
- #use League\Flysystem\Dropbox\DropboxAdapter;
10
- #use Dropbox\Client;
11
  use Srmklive\Dropbox\Client\DropboxClient;
12
  use Srmklive\Dropbox\Adapter\DropboxAdapter;
13
 
@@ -18,707 +43,736 @@ use Aws\S3\S3Client;
18
  use League\Flysystem\AwsS3v3\AwsS3Adapter;
19
 
20
  use Mhetreramesh\Flysystem\BackblazeAdapter;
21
- use ChrisWhite\B2\Client as B2Client;
22
 
23
  use Sabre\DAV\Client as SabreClient;
24
  use League\Flysystem\WebDAV\WebDAVAdapter;
25
 
26
- class Xcloner_Remote_Storage{
27
-
28
- private $gdrive_app_name = "XCloner Backup and Restore";
29
-
 
 
 
30
  private $storage_fields = array(
31
- "option_prefix" => "xcloner_",
32
- "ftp" => array(
33
- "text" => "FTP",
34
- "ftp_enable" => "int",
35
- "ftp_hostname" => "string",
36
- "ftp_port" => "int",
37
- "ftp_username" => "string",
38
- "ftp_password" => "raw",
39
- "ftp_path" => "path",
40
- "ftp_transfer_mode" => "int",
41
- "ftp_ssl_mode" => "int",
42
- "ftp_timeout" => "int",
43
- "ftp_cleanup_days" => "float",
44
- ),
45
- "sftp" => array(
46
- "text" => "SFTP",
47
- "sftp_enable" => "int",
48
- "sftp_hostname" => "string",
49
- "sftp_port" => "int",
50
- "sftp_username" => "string",
51
- "sftp_password" => "raw",
52
- "sftp_path" => "path",
53
- "sftp_private_key" => "raw",
54
- "sftp_timeout" => "int",
55
- "sftp_cleanup_days" => "float",
56
- ),
57
- "aws" => array(
58
- "text" => "S3",
59
- "aws_enable" => "int",
60
- "aws_key" => "string",
61
- "aws_secret" => "string",
62
- "aws_endpoint" => "string",
63
- "aws_region" => "string",
64
- "aws_bucket_name" => "string",
65
- "aws_prefix" => "string",
66
- "aws_cleanup_days" => "float",
67
- ),
68
- "dropbox" => array(
69
- "text" => "Dropbox",
70
- "dropbox_enable" => "int",
71
- "dropbox_access_token" => "string",
72
- "dropbox_app_secret" => "string",
73
- "dropbox_prefix" => "string",
74
- "dropbox_cleanup_days" => "float",
75
- ),
76
- "azure" => array(
77
- "text" => "Azure BLOB",
78
- "azure_enable" => "int",
79
- "azure_account_name" => "string",
80
- "azure_api_key" => "string",
81
- "azure_container" => "string",
82
- "azure_cleanup_days" => "float",
83
- ),
84
- "backblaze" => array(
85
- "text" => "Backblaze",
86
- "backblaze_enable" => "int",
87
- "backblaze_account_id" => "string",
88
- "backblaze_application_key" => "string",
89
- "backblaze_bucket_name" => "string",
90
- "backblaze_cleanup_days" => "float",
91
- ),
92
-
93
- "webdav" => array(
94
- "text" => "WebDAV",
95
- "webdav_enable" => "int",
96
- "webdav_url" => "string",
97
- "webdav_username" => "string",
98
- "webdav_password" => "string",
99
- "webdav_target_folder" => "string",
100
- "webdav_cleanup_days" => "float",
101
- ),
102
-
103
- "gdrive" => array(
104
- "text" => "Google Drive",
105
- "gdrive_enable" => "int",
106
- "gdrive_access_code" => "string",
107
- "gdrive_client_id" => "string",
108
- "gdrive_client_secret" => "string",
109
- "gdrive_target_folder" => "string",
110
- "gdrive_cleanup_days" => "float",
111
- "gdrive_empty_trash" => "int",
112
- ),
113
- );
114
-
115
- private $aws_regions = array(
116
- 'us-east-1'=>'US East (N. Virginia)',
117
- 'us-east-2'=>'US East (Ohio)',
118
- 'us-west-1'=>'US West (N. California)',
119
- 'us-west-2'=>'US West (Oregon)',
120
- 'ca-central-1'=>'Canada (Central)',
121
- 'eu-west-1'=>'EU (Ireland)',
122
- 'eu-central-1'=>'EU (Frankfurt)',
123
- 'eu-west-2'=>'EU (London)',
124
- 'ap-northeast-1'=>'Asia Pacific (Tokyo)',
125
- 'ap-northeast-2'=>'Asia Pacific (Seoul)',
126
- 'ap-southeast-1'=>'Asia Pacific (Singapore)',
127
- 'ap-southeast-2'=>'Asia Pacific (Sydney)',
128
- 'ap-south-1'=>'Asia Pacific (Mumbai)',
129
- 'sa-east-1'=>'South America (São Paulo)'
130
- );
131
-
132
  private $xcloner_sanitization;
133
  private $xcloner_file_system;
134
  private $logger;
135
  private $xcloner;
136
-
137
- public function __construct(Xcloner $xcloner_container)
138
- {
139
- $this->xcloner_sanitization = $xcloner_container->get_xcloner_sanitization();
140
- $this->xcloner_file_system = $xcloner_container->get_xcloner_filesystem();
141
- $this->logger = $xcloner_container->get_xcloner_logger()->withName("xcloner_remote_storage");
142
- $this->xcloner = $xcloner_container;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
143
  }
144
-
145
- private function get_xcloner_container()
146
- {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
147
  return $this->xcloner_container;
148
  }
149
-
150
- public function get_available_storages()
151
- {
152
  $return = array();
153
- foreach($this->storage_fields as $storage=>$data)
154
- {
155
- $check_field = $this->storage_fields["option_prefix"].$storage."_enable";
156
- if(get_option($check_field))
157
- $return[$storage] = $data['text'];
158
  }
159
-
160
  return $return;
161
  }
162
-
163
- public function save($action = "ftp")
164
- {
165
- if(!$action)
166
- {
167
  return false;
168
  }
169
-
170
- $storage = $this->xcloner_sanitization->sanitize_input_as_string($action);
171
- $this->logger->debug(sprintf("Saving the remote storage %s options", strtoupper($action)));
172
-
173
- if(is_array($this->storage_fields[$storage]))
174
- {
175
- foreach($this->storage_fields[$storage] as $field=>$validation)
176
- {
177
- $check_field = $this->storage_fields["option_prefix"].$field;
178
- $sanitize_method = "sanitize_input_as_".$validation;
179
-
180
- if(!isset($_POST[$check_field]))
181
- $_POST[$check_field] = 0;
182
-
183
- if(!method_exists($this->xcloner_sanitization, $sanitize_method))
184
  $sanitize_method = "sanitize_input_as_string";
185
-
186
- $sanitized_value = $this->xcloner_sanitization->$sanitize_method(stripslashes($_POST[$check_field]));
187
- update_option($check_field, $sanitized_value);
 
188
  }
189
-
190
- $this->xcloner->trigger_message(__("%s storage settings saved.", 'xcloner-backup-and-restore'), "success", $this->storage_fields[$action]['text']);
191
  }
192
-
193
  }
194
-
195
- public function check($action = "ftp")
196
- {
197
- try{
198
- $this->verify_filesystem($action);
199
- $this->xcloner->trigger_message(__("%s connection is valid.", 'xcloner-backup-and-restore'), "success", $this->storage_fields[$action]['text']);
200
- $this->logger->debug(sprintf("Connection to remote storage %s is valid", strtoupper($action)));
201
- }catch(Exception $e){
202
- $this->xcloner->trigger_message("%s connection error: ".$e->getMessage(), "error", $this->storage_fields[$action]['text']);
203
  }
204
  }
205
-
206
- public function verify_filesystem($storage_type)
207
- {
208
- $method = "get_".$storage_type."_filesystem";
209
-
210
- $this->logger->info(sprintf("Checking validity of the remote storage %s filesystem", strtoupper($storage_type)));
211
-
212
- if(!method_exists($this, $method))
213
  return false;
214
-
215
- list($adapter, $filesystem) = $this->$method();
216
-
217
- $test_file = substr(".xcloner_".md5(time()), 0, 15);
218
-
219
- if($storage_type == "gdrive")
220
- {
221
- if(!is_array($filesystem->listContents()))
222
- throw new Exception(__("Could not read data",'xcloner-backup-and-restore'));
223
- $this->logger->debug(sprintf("I can list data from remote storage %s", strtoupper($storage_type)));
224
-
 
225
  return true;
226
  }
227
-
228
  //testing write access
229
- if(!$filesystem->write($test_file, "data"))
230
- throw new Exception(__("Could not write data",'xcloner-backup-and-restore'));
231
- $this->logger->debug(sprintf("I can write data to remote storage %s", strtoupper($storage_type)));
232
-
 
233
  //testing read access
234
- if(!$filesystem->has($test_file))
235
- throw new Exception(__("Could not read data",'xcloner-backup-and-restore'));
236
- $this->logger->debug(sprintf("I can read data to remote storage %s", strtoupper($storage_type)));
237
-
 
238
  //delete test file
239
- if(!$filesystem->delete($test_file))
240
- throw new Exception(__("Could not delete data",'xcloner-backup-and-restore'));
241
- $this->logger->debug(sprintf("I can delete data to remote storage %s", strtoupper($storage_type)));
242
-
 
243
  return true;
244
  }
245
-
246
- public function upload_backup_to_storage($file, $storage)
247
- {
248
- if(!$this->xcloner_file_system->get_storage_filesystem()->has($file))
249
- {
250
- $this->logger->info(sprintf("File not found %s in local storage", $file));
251
  return false;
252
  }
253
-
254
- $method = "get_".$storage."_filesystem";
255
-
256
- if(!method_exists($this, $method))
257
  return false;
258
-
259
- list($remote_storage_adapter, $remote_storage_filesystem) = $this->$method();
260
-
 
261
  //doing remote storage cleaning here
262
- $this->clean_remote_storage($storage, $remote_storage_filesystem);
263
-
264
- $this->logger->info(sprintf("Transferring backup %s to remote storage %s", $file, strtoupper($storage)), array(""));
265
-
266
  /*if(!$this->xcloner_file_system->get_storage_filesystem()->has($file))
267
  {
268
  $this->logger->info(sprintf("File not found %s in local storage", $file));
269
  return false;
270
  }*/
271
-
272
- $backup_file_stream = $this->xcloner_file_system->get_storage_filesystem()->readStream($file);
273
 
274
- if(!$remote_storage_filesystem->writeStream($file, $backup_file_stream))
275
- {
276
- $this->logger->info(sprintf("Could not transfer file %s", $file));
 
 
277
  return false;
278
  }
279
-
280
- if($this->xcloner_file_system->is_multipart($file))
281
- {
282
- $parts = $this->xcloner_file_system->get_multipart_files($file);
283
- if(is_array($parts))
284
- foreach($parts as $part_file)
285
- {
286
- $this->logger->info(sprintf("Transferring backup %s to remote storage %s", $part_file, strtoupper($storage)), array(""));
287
-
288
- $backup_file_stream = $this->xcloner_file_system->get_storage_filesystem()->readStream($part_file);
289
- if(!$remote_storage_filesystem->writeStream($part_file, $backup_file_stream))
290
  return false;
 
291
  }
 
292
  }
293
-
294
- $this->logger->info(sprintf("Upload done, disconnecting from remote storage %s", strtoupper($storage)));
295
-
296
  return true;
297
-
298
  }
299
-
300
- public function copy_backup_remote_to_local($file, $storage)
301
- {
302
- $method = "get_".$storage."_filesystem";
303
-
304
  $target_filename = $file;
305
-
306
- if(!method_exists($this, $method))
307
  return false;
308
-
309
- list($remote_storage_adapter, $remote_storage_filesystem) = $this->$method();
310
-
311
- if(!$remote_storage_filesystem->has($file))
312
- {
313
- $this->logger->info(sprintf("File not found %s in remote storage %s", $file, strtoupper($storage)));
 
314
  return false;
315
  }
316
-
317
- if($storage == "gdrive")
318
- {
319
- $metadata = $remote_storage_filesystem->getMetadata($file);
320
- $target_filename = $metadata['filename'].".".$metadata['extension'];
321
  }
322
-
323
- $this->logger->info(sprintf("Transferring backup %s to local storage from %s storage", $file, strtoupper($storage)), array(""));
324
-
325
- $backup_file_stream = $remote_storage_filesystem->readStream($file);
326
 
327
- if(!$this->xcloner_file_system->get_storage_filesystem()->writeStream($target_filename, $backup_file_stream))
328
- {
329
- $this->logger->info(sprintf("Could not transfer file %s", $file));
 
 
 
 
330
  return false;
331
  }
332
-
333
- if($this->xcloner_file_system->is_multipart($target_filename))
334
- {
335
- $parts = $this->xcloner_file_system->get_multipart_files($file, $storage);
336
- if(is_array($parts))
337
- foreach($parts as $part_file)
338
- {
339
- $this->logger->info(sprintf("Transferring backup %s to local storage from %s storage", $part_file, strtoupper($storage)), array(""));
340
-
341
- $backup_file_stream = $remote_storage_filesystem->readStream($part_file);
342
- if(!$this->xcloner_file_system->get_storage_filesystem()->writeStream($part_file, $backup_file_stream))
343
  return false;
 
344
  }
 
345
  }
346
-
347
- $this->logger->info(sprintf("Upload done, disconnecting from remote storage %s", strtoupper($storage)));
348
-
349
  return true;
350
-
351
  }
352
-
353
- public function clean_remote_storage($storage, $remote_storage_filesystem)
354
- {
355
- $check_field = $this->storage_fields["option_prefix"].$storage."_cleanup_days";
356
- if($expire_days = get_option($check_field))
357
- {
358
- $this->logger->info(sprintf("Doing %s remote storage cleanup for %s days limit", strtoupper($storage), $expire_days));
359
  $files = $remote_storage_filesystem->listContents();
360
-
361
- $current_timestamp = strtotime("-".$expire_days." days");
362
-
363
- if(is_array($files))
364
- foreach($files as $file)
365
- {
366
- $file['timestamp'] = $remote_storage_filesystem->getTimestamp($file['path']);
367
-
368
- if($current_timestamp >= $file['timestamp'])
369
- {
370
- $remote_storage_filesystem->delete($file['path']);
371
- $this->logger->info("Deleting remote file ".$file['path']." matching rule", array("RETENTION LIMIT TIMESTAMP", $file['timestamp']." =< ".$expire_days));
 
 
 
372
  }
373
-
374
  }
375
  }
376
  }
377
-
378
- public function get_azure_filesystem()
379
- {
380
- $this->logger->info(sprintf("Creating the AZURE BLOB remote storage connection"), array(""));
381
-
382
- if (version_compare(phpversion(), '5.6.0', '<'))
383
- {
384
- throw new Exception("AZURE BLOB requires PHP 5.6 to be installed!");
385
  }
386
-
387
- if (!class_exists('XmlWriter'))
388
- {
389
- throw new Exception("AZURE BLOB requires libxml PHP module to be installed with XmlWriter class enabled!");
390
  }
391
-
392
  $endpoint = sprintf(
393
- 'DefaultEndpointsProtocol=https;AccountName=%s;AccountKey=%s',
394
- get_option("xcloner_azure_account_name"),
395
- get_option("xcloner_azure_api_key")
396
  );
397
-
398
- $blobRestProxy = ServicesBuilder::getInstance()->createBlobService($endpoint);
399
-
400
- $adapter = new AzureAdapter($blobRestProxy, get_option("xcloner_azure_container"));
401
-
402
- $filesystem = new Filesystem($adapter, new Config([
403
- 'disable_asserts' => true,
404
- ]));
405
-
406
- return array($adapter, $filesystem);
407
  }
408
-
409
- public function get_dropbox_filesystem()
410
- {
411
- $this->logger->info(sprintf("Creating the DROPBOX remote storage connection"), array(""));
412
-
413
- if (version_compare(phpversion(), '5.6.0', '<'))
414
- {
415
- throw new Exception("DROPBOX requires PHP 5.6 to be installed!");
416
  }
417
-
418
- $client = new DropboxClient(get_option("xcloner_dropbox_access_token"));
419
- $adapter = new DropboxAdapter($client, get_option("xcloner_dropbox_prefix"));
420
-
421
- $filesystem = new Filesystem($adapter, new Config([
422
- 'disable_asserts' => true,
423
- ]));
424
 
425
- return array($adapter, $filesystem);
 
 
 
 
 
 
 
426
  }
427
-
428
- public function get_aws_filesystem()
429
- {
430
- $this->logger->info(sprintf("Creating the S3 remote storage connection"), array(""));
431
-
432
- if (version_compare(phpversion(), '5.6.0', '<'))
433
- {
434
- throw new Exception("S3 class requires PHP 5.6 to be installed!");
435
  }
436
-
437
- if (!class_exists('XmlWriter'))
438
- {
439
- throw new Exception("AZURE BLOB requires libxml PHP module to be installed with XmlWriter class enabled!");
440
  }
441
-
442
-
443
  $credentials = array(
444
- 'credentials' => array(
445
- 'key' => get_option("xcloner_aws_key"),
446
- 'secret' => get_option("xcloner_aws_secret")
447
- ),
448
- 'region' => get_option("xcloner_aws_region"),
449
- 'version' => 'latest',
450
  );
451
-
452
- if(get_option('xcloner_aws_endpoint') != "" && !get_option("xcloner_aws_region")){
453
-
454
- $credentials['endpoint'] = get_option('xcloner_aws_endpoint');
455
  #$credentials['use_path_style_endpoint'] = true;
456
  #$credentials['bucket_endpoint'] = false;
457
-
458
-
459
- }
460
-
461
-
462
- $client = new S3Client($credentials);
463
-
464
- $adapter = new AwsS3Adapter($client, get_option("xcloner_aws_bucket_name"), get_option("xcloner_aws_prefix"));
465
- $filesystem = new Filesystem($adapter, new Config([
466
- 'disable_asserts' => true,
467
- ]));
468
-
469
- return array($adapter, $filesystem);
470
  }
471
-
472
- public function get_backblaze_filesystem()
473
- {
474
- $this->logger->info(sprintf("Creating the BACKBLAZE remote storage connection"), array(""));
475
-
476
- if (version_compare(phpversion(), '5.6.0', '<'))
477
- {
478
- throw new Exception("BACKBLAZE API requires PHP 5.6 to be installed!");
479
- }
480
-
481
-
482
- $client = new B2Client(get_option("xcloner_backblaze_account_id"), get_option("xcloner_backblaze_application_key"));
483
- $adapter = new BackblazeAdapter($client, get_option("xcloner_backblaze_bucket_name"));
484
-
485
- $filesystem = new Filesystem($adapter, new Config([
486
- 'disable_asserts' => true,
487
- ]));
488
-
489
- return array($adapter, $filesystem);
490
  }
491
-
492
- public function get_webdav_filesystem()
493
- {
494
- $this->logger->info(sprintf("Creating the WEBDAV remote storage connection"), array(""));
495
-
496
- if (version_compare(phpversion(), '5.6.0', '<'))
497
- {
498
- throw new Exception("WEBDAV API requires PHP 5.6 to be installed!");
499
  }
500
-
501
  $settings = array(
502
- 'baseUri' => get_option("xcloner_webdav_url"),
503
- 'userName' => get_option("xcloner_webdav_username"),
504
- 'password' => get_option("xcloner_webdav_password"),
505
  //'proxy' => 'locahost:8888',
506
  );
507
-
508
-
509
- $client = new SabreClient($settings);
510
- $adapter = new WebDAVAdapter($client, get_option("xcloner_webdav_target_folder"));
511
- $filesystem = new Filesystem($adapter, new Config([
512
- 'disable_asserts' => true,
513
- ]));
514
-
515
- return array($adapter, $filesystem);
516
  }
517
-
518
-
519
- public function gdrive_construct()
520
- {
521
 
522
  //if((function_exists("is_plugin_active") && !is_plugin_active("xcloner-google-drive/xcloner-google-drive.php")) || !file_exists(__DIR__ . "/../../xcloner-google-drive/vendor/autoload.php"))
523
- if(!class_exists('Google_Client'))
524
- {
525
  return false;
526
  }
527
-
528
  //require_once(__DIR__ . "/../../xcloner-google-drive/vendor/autoload.php");
529
-
530
  $client = new \Google_Client();
531
- $client->setApplicationName($this->gdrive_app_name);
532
- $client->setClientId(get_option("xcloner_gdrive_client_id"));
533
- $client->setClientSecret(get_option("xcloner_gdrive_client_secret"));
534
-
535
  //$redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF']."?page=xcloner_remote_storage_page&action=set_gdrive_code";
536
  $redirect_uri = "urn:ietf:wg:oauth:2.0:oob";
537
-
538
- $client->setRedirectUri($redirect_uri); //urn:ietf:wg:oauth:2.0:oob
539
- $client->addScope("https://www.googleapis.com/auth/drive");
540
- $client->setAccessType('offline');
541
-
542
  return $client;
543
  }
544
-
545
- public function get_gdrive_auth_url()
546
- {
547
  $client = $this->gdrive_construct();
548
-
549
- if(!$client)
550
  return false;
551
-
 
552
  return $authUrl = $client->createAuthUrl();
553
  }
554
-
555
- public function set_access_token($code)
556
- {
557
  $client = $this->gdrive_construct();
558
-
559
- if(!$client)
560
- {
561
  $error_msg = "Could not initialize the Google Drive Class, please check that the xcloner-google-drive plugin is enabled...";
562
- $this->logger->error($error_msg);
 
563
  return false;
564
  }
565
 
566
- $token = $client->fetchAccessTokenWithAuthCode($code);
567
- $client->setAccessToken($token);
568
-
569
- update_option("xcloner_gdrive_access_token", $token['access_token']);
570
- update_option("xcloner_gdrive_refresh_token", $token['refresh_token']);
571
-
572
- $redirect_url = ('http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF']."?page=xcloner_remote_storage_page#gdrive");
573
-
574
  ?>
575
- <script>
576
- window.location='<?php echo $redirect_url?>';
577
- </script>
578
  <?php
579
-
580
  }
581
-
582
  /*
583
  * php composer.phar remove nao-pon/flysystem-google-drive
584
  *
585
  */
586
- public function get_gdrive_filesystem()
587
- {
588
-
589
- if (version_compare(phpversion(), '5.6.0', '<'))
590
- {
591
- throw new Exception("Google Drive API requires PHP 5.6 to be installed!");
592
  }
593
-
594
- $this->logger->info(sprintf("Creating the Google Drive remote storage connection"), array(""));
595
-
596
  $client = $this->gdrive_construct();
597
-
598
- if(!$client)
599
- {
600
  $error_msg = "Could not initialize the Google Drive Class, please check that the xcloner-google-drive plugin is enabled...";
601
- $this->logger->error($error_msg);
602
- throw new Exception($error_msg);
603
- }
604
-
605
- $client->refreshToken(get_option("xcloner_gdrive_refresh_token"));
606
-
607
- $service = new \Google_Service_Drive($client);
608
-
609
  /*if( get_option("xcloner_gdrive_empty_trash",0) ){
610
  $this->logger->info(sprintf("Doing a Google Drive emptyTrash call"), array(""));
611
  $service->files->emptyTrash();
612
  }*/
613
-
614
  $parent = 'root';
615
- $dir = basename( get_option("xcloner_gdrive_target_folder"));
616
-
617
- $folderID = get_option("xcloner_gdrive_target_folder");
618
-
619
- $tmp = parse_url($folderID);
620
-
621
- if(isset($tmp['query']))
622
- {
623
- $folderID = str_replace("id=", "", $tmp['query']);
624
  }
625
-
626
- if(stristr($folderID, "/"))
627
- {
628
- $query = sprintf('mimeType = \'application/vnd.google-apps.folder\' and \'%s\' in parents and name contains \'%s\'', $parent, $dir);
629
- $response = $service->files->listFiles([
630
- 'pageSize' => 1,
631
- 'q' => $query
632
- ]);
633
-
634
- if(sizeof($response))
635
- {
636
- foreach ($response as $obj) {
637
- $folderID = $obj->getId();
638
  }
639
- }else{
640
- $this->xcloner->trigger_message(sprintf(__("Could not find folder ID by name %s", 'xcloner-backup-and-restore'), $folderID), "error");
641
  }
642
  }
643
-
644
- $this->logger->info(sprintf("Using target folder with ID %s on the remote storage", $folderID));
645
-
646
- if(class_exists('XCloner_Google_Drive_Adapter')){
647
- $adapter = new XCloner_Google_Drive_Adapter($service, $folderID);
648
- }else{
649
- $adapter = new \Hypweb\Flysystem\GoogleDrive\GoogleDriveAdapter($service, $folderID);
650
- }
651
-
652
- $filesystem = new \League\Flysystem\Filesystem($adapter, new Config([
653
- 'disable_asserts' => true,
654
- ]));
655
-
656
-
657
- return array($adapter, $filesystem);
658
  }
659
-
660
- public function get_ftp_filesystem()
661
- {
662
- $this->logger->info(sprintf("Creating the FTP remote storage connection"), array(""));
663
-
664
- $adapter = new Adapter([
665
- 'host' => get_option("xcloner_ftp_hostname"),
666
- 'username' => get_option("xcloner_ftp_username"),
667
- 'password' => get_option("xcloner_ftp_password"),
668
-
669
- /** optional config settings */
670
- 'port' => get_option("xcloner_ftp_port", 21),
671
- 'root' => get_option("xcloner_ftp_path"),
672
- 'passive' => get_option("xcloner_ftp_transfer_mode"),
673
- 'ssl' => get_option("xcloner_ftp_ssl_mode"),
674
- 'timeout' => get_option("xcloner_ftp_timeout", 30),
675
- ]);
676
-
677
  $adapter->connect();
678
-
679
- $filesystem = new Filesystem($adapter, new Config([
680
- 'disable_asserts' => true,
681
- ]));
682
-
683
- return array($adapter, $filesystem);
684
  }
685
-
686
- public function get_sftp_filesystem()
687
- {
688
- $this->logger->info(sprintf("Creating the SFTP remote storage connection"), array(""));
689
-
690
- $adapter = new SftpAdapter([
691
- 'host' => get_option("xcloner_sftp_hostname"),
692
- 'username' => get_option("xcloner_sftp_username"),
693
- 'password' => get_option("xcloner_sftp_password"),
694
-
695
- /** optional config settings */
696
- 'port' => get_option("xcloner_sftp_port", 22),
697
- 'root' => get_option("xcloner_sftp_path"),
698
- 'privateKey' => get_option("xcloner_sftp_private_key"),
699
- 'timeout' => get_option("xcloner_ftp_timeout", 30),
700
- ]);
701
-
702
  $adapter->connect();
703
-
704
- $filesystem = new Filesystem($adapter, new Config([
705
- 'disable_asserts' => true,
706
- ]));
707
-
708
- return array($adapter, $filesystem);
709
  }
710
-
711
- public function change_storage_status($field, $value)
712
- {
713
- $field = $this->xcloner_sanitization->sanitize_input_as_string($field);
714
- $value = $this->xcloner_sanitization->sanitize_input_as_int($value);
715
 
716
- return update_option($field, $value);
 
 
 
 
717
  }
718
-
719
- public function get_aws_regions()
720
- {
721
  return $this->aws_regions;
722
  }
723
-
724
  }
1
  <?php
2
+ /**
3
+ * XCloner - Backup and Restore backup plugin for Wordpress
4
+ *
5
+ * class-xcloner-remote-storage.php
6
+ * @author Liuta Ovidiu <info@thinkovi.com>
7
+ *
8
+ * This program is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation; either version 2 of the License, or
11
+ * (at your option) any later version.
12
+ *
13
+ * This program is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ * GNU General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU General Public License
19
+ * along with this program; if not, write to the Free Software
20
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21
+ * MA 02110-1301, USA.
22
+ *
23
+ * @link https://github.com/ovidiul/XCloner-Wordpress
24
+ *
25
+ * @modified 7/25/18 2:15 PM
26
+ *
27
+ */
28
+
29
  use League\Flysystem\Config;
30
  use League\Flysystem\Filesystem;
31
 
33
 
34
  use League\Flysystem\Sftp\SftpAdapter;
35
 
 
 
36
  use Srmklive\Dropbox\Client\DropboxClient;
37
  use Srmklive\Dropbox\Adapter\DropboxAdapter;
38
 
43
  use League\Flysystem\AwsS3v3\AwsS3Adapter;
44
 
45
  use Mhetreramesh\Flysystem\BackblazeAdapter;
46
+ use BackblazeB2\Client as B2Client;
47
 
48
  use Sabre\DAV\Client as SabreClient;
49
  use League\Flysystem\WebDAV\WebDAVAdapter;
50
 
51
+ /**
52
+ * Class Xcloner_Remote_Storage
53
+ */
54
+ class Xcloner_Remote_Storage {
55
+
56
+ private $gdrive_app_name = "XCloner Backup and Restore";
57
+
58
  private $storage_fields = array(
59
+ "option_prefix" => "xcloner_",
60
+ "ftp" => array(
61
+ "text" => "FTP",
62
+ "ftp_enable" => "int",
63
+ "ftp_hostname" => "string",
64
+ "ftp_port" => "int",
65
+ "ftp_username" => "string",
66
+ "ftp_password" => "raw",
67
+ "ftp_path" => "path",
68
+ "ftp_transfer_mode" => "int",
69
+ "ftp_ssl_mode" => "int",
70
+ "ftp_timeout" => "int",
71
+ "ftp_cleanup_days" => "float",
72
+ ),
73
+ "sftp" => array(
74
+ "text" => "SFTP",
75
+ "sftp_enable" => "int",
76
+ "sftp_hostname" => "string",
77
+ "sftp_port" => "int",
78
+ "sftp_username" => "string",
79
+ "sftp_password" => "raw",
80
+ "sftp_path" => "path",
81
+ "sftp_private_key" => "raw",
82
+ "sftp_timeout" => "int",
83
+ "sftp_cleanup_days" => "float",
84
+ ),
85
+ "aws" => array(
86
+ "text" => "S3",
87
+ "aws_enable" => "int",
88
+ "aws_key" => "string",
89
+ "aws_secret" => "raw",
90
+ "aws_endpoint" => "string",
91
+ "aws_region" => "string",
92
+ "aws_bucket_name" => "string",
93
+ "aws_prefix" => "string",
94
+ "aws_cleanup_days" => "float",
95
+ ),
96
+ "dropbox" => array(
97
+ "text" => "Dropbox",
98
+ "dropbox_enable" => "int",
99
+ "dropbox_access_token" => "string",
100
+ "dropbox_app_secret" => "raw",
101
+ "dropbox_prefix" => "string",
102
+ "dropbox_cleanup_days" => "float",
103
+ ),
104
+ "azure" => array(
105
+ "text" => "Azure BLOB",
106
+ "azure_enable" => "int",
107
+ "azure_account_name" => "string",
108
+ "azure_api_key" => "string",
109
+ "azure_container" => "string",
110
+ "azure_cleanup_days" => "float",
111
+ ),
112
+ "backblaze" => array(
113
+ "text" => "Backblaze",
114
+ "backblaze_enable" => "int",
115
+ "backblaze_account_id" => "string",
116
+ "backblaze_application_key" => "string",
117
+ "backblaze_bucket_name" => "string",
118
+ "backblaze_cleanup_days" => "float",
119
+ ),
120
+
121
+ "webdav" => array(
122
+ "text" => "WebDAV",
123
+ "webdav_enable" => "int",
124
+ "webdav_url" => "string",
125
+ "webdav_username" => "string",
126
+ "webdav_password" => "raw",
127
+ "webdav_target_folder" => "string",
128
+ "webdav_cleanup_days" => "float",
129
+ ),
130
+
131
+ "gdrive" => array(
132
+ "text" => "Google Drive",
133
+ "gdrive_enable" => "int",
134
+ "gdrive_access_code" => "string",
135
+ "gdrive_client_id" => "string",
136
+ "gdrive_client_secret" => "raw",
137
+ "gdrive_target_folder" => "string",
138
+ "gdrive_cleanup_days" => "float",
139
+ "gdrive_empty_trash" => "int",
140
+ ),
141
+ );
142
+
143
+ private $aws_regions = array(
144
+ 'us-east-1' => 'US East (N. Virginia)',
145
+ 'us-east-2' => 'US East (Ohio)',
146
+ 'us-west-1' => 'US West (N. California)',
147
+ 'us-west-2' => 'US West (Oregon)',
148
+ 'ca-central-1' => 'Canada (Central)',
149
+ 'eu-west-1' => 'EU (Ireland)',
150
+ 'eu-central-1' => 'EU (Frankfurt)',
151
+ 'eu-west-2' => 'EU (London)',
152
+ 'ap-northeast-1' => 'Asia Pacific (Tokyo)',
153
+ 'ap-northeast-2' => 'Asia Pacific (Seoul)',
154
+ 'ap-southeast-1' => 'Asia Pacific (Singapore)',
155
+ 'ap-southeast-2' => 'Asia Pacific (Sydney)',
156
+ 'ap-south-1' => 'Asia Pacific (Mumbai)',
157
+ 'sa-east-1' => 'South America (São Paulo)'
158
+ );
159
+
160
  private $xcloner_sanitization;
161
  private $xcloner_file_system;
162
  private $logger;
163
  private $xcloner;
164
+
165
+ public function __construct( Xcloner $xcloner_container ) {
166
+ $this->xcloner_sanitization = $xcloner_container->get_xcloner_sanitization();
167
+ $this->xcloner_file_system = $xcloner_container->get_xcloner_filesystem();
168
+ $this->logger = $xcloner_container->get_xcloner_logger()->withName( "xcloner_remote_storage" );
169
+ $this->xcloner = $xcloner_container;
170
+
171
+ foreach($this->storage_fields as $main_key=>$array){
172
+
173
+ if(is_array($array)) {
174
+ foreach ($array as $key => $type) {
175
+
176
+ if( $type == "raw") {
177
+ add_filter("pre_update_option_" . $this->storage_fields['option_prefix'] . $key,
178
+ function ($value) {
179
+
180
+ return $this->simple_crypt($value, 'e');
181
+
182
+ }, 10, 1);
183
+
184
+ add_filter("option_" . $this->storage_fields['option_prefix'] . $key, function ($value) {
185
+
186
+ return $this->simple_crypt($value, 'd');
187
+
188
+ }, 10, 1);
189
+ }
190
+
191
+ }
192
+ }
193
+ }
194
+
195
  }
196
+
197
+ /**
198
+ * Encrypts and Decrypt a string based on openssl lib
199
+ *
200
+ * @param $string
201
+ * @param string $action
202
+ * @return string
203
+ */
204
+ private function simple_crypt( $string, $action = 'e' ) {
205
+ // you may change these values to your own
206
+ $secret_key = NONCE_KEY;
207
+ $secret_iv = NONCE_SALT;
208
+
209
+ $output = $string;
210
+ $encrypt_method = "AES-256-CBC";
211
+ $key = hash( 'sha256', $secret_key );
212
+ $iv = substr( hash( 'sha256', $secret_iv ), 0, 16 );
213
+
214
+ if( $action == 'e' && function_exists('openssl_encrypt')) {
215
+ $output = base64_encode( openssl_encrypt( $string, $encrypt_method, $key, 0, $iv ) );
216
+ }
217
+ else if( $action == 'd' && function_exists('openssl_decrypt') && base64_decode( $string )){
218
+ $decrypt = openssl_decrypt( base64_decode( $string ), $encrypt_method, $key, 0, $iv );
219
+ if($decrypt) {
220
+ //we check if decrypt was succesful
221
+ $output = $decrypt;
222
+ }
223
+ }
224
+
225
+ return $output;
226
+ }
227
+
228
+ private function get_xcloner_container() {
229
  return $this->xcloner_container;
230
  }
231
+
232
+ public function get_available_storages() {
 
233
  $return = array();
234
+ foreach ( $this->storage_fields as $storage => $data ) {
235
+ $check_field = $this->storage_fields["option_prefix"] . $storage . "_enable";
236
+ if ( get_option( $check_field ) ) {
237
+ $return[ $storage ] = $data['text'];
238
+ }
239
  }
240
+
241
  return $return;
242
  }
243
+
244
+ public function save( $action = "ftp" ) {
245
+ if ( ! $action ) {
 
 
246
  return false;
247
  }
248
+
249
+ $storage = $this->xcloner_sanitization->sanitize_input_as_string( $action );
250
+ $this->logger->debug( sprintf( "Saving the remote storage %s options", strtoupper( $action ) ) );
251
+
252
+ if ( is_array( $this->storage_fields[ $storage ] ) ) {
253
+ foreach ( $this->storage_fields[ $storage ] as $field => $validation ) {
254
+ $check_field = $this->storage_fields["option_prefix"] . $field;
255
+ $sanitize_method = "sanitize_input_as_" . $validation;
256
+
257
+ if ( ! isset( $_POST[ $check_field ] ) ) {
258
+ $_POST[ $check_field ] = 0;
259
+ }
260
+
261
+ if ( ! method_exists( $this->xcloner_sanitization, $sanitize_method ) ) {
 
262
  $sanitize_method = "sanitize_input_as_string";
263
+ }
264
+
265
+ $sanitized_value = $this->xcloner_sanitization->$sanitize_method( stripslashes( $_POST[ $check_field ] ) );
266
+ update_option( $check_field, $sanitized_value );
267
  }
268
+
269
+ $this->xcloner->trigger_message( __( "%s storage settings saved.", 'xcloner-backup-and-restore' ), "success", $this->storage_fields[ $action ]['text'] );
270
  }
271
+
272
  }
273
+
274
+ public function check( $action = "ftp" ) {
275
+ try {
276
+ $this->verify_filesystem( $action );
277
+ $this->xcloner->trigger_message( __( "%s connection is valid.", 'xcloner-backup-and-restore' ), "success", $this->storage_fields[ $action ]['text'] );
278
+ $this->logger->debug( sprintf( "Connection to remote storage %s is valid", strtoupper( $action ) ) );
279
+ } catch ( Exception $e ) {
280
+ $this->xcloner->trigger_message( "%s connection error: " . $e->getMessage(), "error", $this->storage_fields[ $action ]['text'] );
 
281
  }
282
  }
283
+
284
+ public function verify_filesystem( $storage_type ) {
285
+ $method = "get_" . $storage_type . "_filesystem";
286
+
287
+ $this->logger->info( sprintf( "Checking validity of the remote storage %s filesystem", strtoupper( $storage_type ) ) );
288
+
289
+ if ( ! method_exists( $this, $method ) ) {
 
290
  return false;
291
+ }
292
+
293
+ list( $adapter, $filesystem ) = $this->$method();
294
+
295
+ $test_file = substr( ".xcloner_" . md5( time() ), 0, 15 );
296
+
297
+ if ( $storage_type == "gdrive" ) {
298
+ if ( ! is_array( $filesystem->listContents() ) ) {
299
+ throw new Exception( __( "Could not read data", 'xcloner-backup-and-restore' ) );
300
+ }
301
+ $this->logger->debug( sprintf( "I can list data from remote storage %s", strtoupper( $storage_type ) ) );
302
+
303
  return true;
304
  }
305
+
306
  //testing write access
307
+ if ( ! $filesystem->write( $test_file, "data" ) ) {
308
+ throw new Exception( __( "Could not write data", 'xcloner-backup-and-restore' ) );
309
+ }
310
+ $this->logger->debug( sprintf( "I can write data to remote storage %s", strtoupper( $storage_type ) ) );
311
+
312
  //testing read access
313
+ if ( ! $filesystem->has( $test_file ) ) {
314
+ throw new Exception( __( "Could not read data", 'xcloner-backup-and-restore' ) );
315
+ }
316
+ $this->logger->debug( sprintf( "I can read data to remote storage %s", strtoupper( $storage_type ) ) );
317
+
318
  //delete test file
319
+ if ( ! $filesystem->delete( $test_file ) ) {
320
+ throw new Exception( __( "Could not delete data", 'xcloner-backup-and-restore' ) );
321
+ }
322
+ $this->logger->debug( sprintf( "I can delete data to remote storage %s", strtoupper( $storage_type ) ) );
323
+
324
  return true;
325
  }
326
+
327
+ public function upload_backup_to_storage( $file, $storage ) {
328
+ if ( ! $this->xcloner_file_system->get_storage_filesystem()->has( $file ) ) {
329
+ $this->logger->info( sprintf( "File not found %s in local storage", $file ) );
330
+
 
331
  return false;
332
  }
333
+
334
+ $method = "get_" . $storage . "_filesystem";
335
+
336
+ if ( ! method_exists( $this, $method ) ) {
337
  return false;
338
+ }
339
+
340
+ list( $remote_storage_adapter, $remote_storage_filesystem ) = $this->$method();
341
+
342
  //doing remote storage cleaning here
343
+ $this->clean_remote_storage( $storage, $remote_storage_filesystem );
344
+
345
+ $this->logger->info( sprintf( "Transferring backup %s to remote storage %s", $file, strtoupper( $storage ) ), array( "" ) );
346
+
347
  /*if(!$this->xcloner_file_system->get_storage_filesystem()->has($file))
348
  {
349
  $this->logger->info(sprintf("File not found %s in local storage", $file));
350
  return false;
351
  }*/
 
 
352
 
353
+ $backup_file_stream = $this->xcloner_file_system->get_storage_filesystem()->readStream( $file );
354
+
355
+ if ( ! $remote_storage_filesystem->writeStream( $file, $backup_file_stream ) ) {
356
+ $this->logger->info( sprintf( "Could not transfer file %s", $file ) );
357
+
358
  return false;
359
  }
360
+
361
+ if ( $this->xcloner_file_system->is_multipart( $file ) ) {
362
+ $parts = $this->xcloner_file_system->get_multipart_files( $file );
363
+ if ( is_array( $parts ) ) {
364
+ foreach ( $parts as $part_file ) {
365
+ $this->logger->info( sprintf( "Transferring backup %s to remote storage %s", $part_file, strtoupper( $storage ) ), array( "" ) );
366
+
367
+ $backup_file_stream = $this->xcloner_file_system->get_storage_filesystem()->readStream( $part_file );
368
+ if ( ! $remote_storage_filesystem->writeStream( $part_file, $backup_file_stream ) ) {
 
 
369
  return false;
370
+ }
371
  }
372
+ }
373
  }
374
+
375
+ $this->logger->info( sprintf( "Upload done, disconnecting from remote storage %s", strtoupper( $storage ) ) );
376
+
377
  return true;
378
+
379
  }
380
+
381
+ public function copy_backup_remote_to_local( $file, $storage ) {
382
+ $method = "get_" . $storage . "_filesystem";
383
+
 
384
  $target_filename = $file;
385
+
386
+ if ( ! method_exists( $this, $method ) ) {
387
  return false;
388
+ }
389
+
390
+ list( $remote_storage_adapter, $remote_storage_filesystem ) = $this->$method();
391
+
392
+ if ( ! $remote_storage_filesystem->has( $file ) ) {
393
+ $this->logger->info( sprintf( "File not found %s in remote storage %s", $file, strtoupper( $storage ) ) );
394
+
395
  return false;
396
  }
397
+
398
+ if ( $storage == "gdrive" ) {
399
+ $metadata = $remote_storage_filesystem->getMetadata( $file );
400
+ $target_filename = $metadata['filename'] . "." . $metadata['extension'];
 
401
  }
 
 
 
 
402
 
403
+ $this->logger->info( sprintf( "Transferring backup %s to local storage from %s storage", $file, strtoupper( $storage ) ), array( "" ) );
404
+
405
+ $backup_file_stream = $remote_storage_filesystem->readStream( $file );
406
+
407
+ if ( ! $this->xcloner_file_system->get_storage_filesystem()->writeStream( $target_filename, $backup_file_stream ) ) {
408
+ $this->logger->info( sprintf( "Could not transfer file %s", $file ) );
409
+
410
  return false;
411
  }
412
+
413
+ if ( $this->xcloner_file_system->is_multipart( $target_filename ) ) {
414
+ $parts = $this->xcloner_file_system->get_multipart_files( $file, $storage );
415
+ if ( is_array( $parts ) ) {
416
+ foreach ( $parts as $part_file ) {
417
+ $this->logger->info( sprintf( "Transferring backup %s to local storage from %s storage", $part_file, strtoupper( $storage ) ), array( "" ) );
418
+
419
+ $backup_file_stream = $remote_storage_filesystem->readStream( $part_file );
420
+ if ( ! $this->xcloner_file_system->get_storage_filesystem()->writeStream( $part_file, $backup_file_stream ) ) {
 
 
421
  return false;
422
+ }
423
  }
424
+ }
425
  }
426
+
427
+ $this->logger->info( sprintf( "Upload done, disconnecting from remote storage %s", strtoupper( $storage ) ) );
428
+
429
  return true;
430
+
431
  }
432
+
433
+ public function clean_remote_storage( $storage, $remote_storage_filesystem ) {
434
+ $check_field = $this->storage_fields["option_prefix"] . $storage . "_cleanup_days";
435
+ if ( $expire_days = get_option( $check_field ) ) {
436
+ $this->logger->info( sprintf( "Doing %s remote storage cleanup for %s days limit", strtoupper( $storage ), $expire_days ) );
 
 
437
  $files = $remote_storage_filesystem->listContents();
438
+
439
+ $current_timestamp = strtotime( "-" . $expire_days . " days" );
440
+
441
+ if ( is_array( $files ) ) {
442
+ foreach ( $files as $file ) {
443
+ $file['timestamp'] = $remote_storage_filesystem->getTimestamp( $file['path'] );
444
+
445
+ if ( $current_timestamp >= $file['timestamp'] ) {
446
+ $remote_storage_filesystem->delete( $file['path'] );
447
+ $this->logger->info( "Deleting remote file " . $file['path'] . " matching rule", array(
448
+ "RETENTION LIMIT TIMESTAMP",
449
+ $file['timestamp'] . " =< " . $expire_days
450
+ ) );
451
+ }
452
+
453
  }
 
454
  }
455
  }
456
  }
457
+
458
+ public function get_azure_filesystem() {
459
+ $this->logger->info( sprintf( "Creating the AZURE BLOB remote storage connection" ), array( "" ) );
460
+
461
+ if ( version_compare( phpversion(), '5.6.0', '<' ) ) {
462
+ throw new Exception( "AZURE BLOB requires PHP 5.6 to be installed!" );
 
 
463
  }
464
+
465
+ if ( ! class_exists( 'XmlWriter' ) ) {
466
+ throw new Exception( "AZURE BLOB requires libxml PHP module to be installed with XmlWriter class enabled!" );
 
467
  }
468
+
469
  $endpoint = sprintf(
470
+ 'DefaultEndpointsProtocol=https;AccountName=%s;AccountKey=%s',
471
+ get_option( "xcloner_azure_account_name" ),
472
+ get_option( "xcloner_azure_api_key" )
473
  );
474
+
475
+ $blobRestProxy = ServicesBuilder::getInstance()->createBlobService( $endpoint );
476
+
477
+ $adapter = new AzureAdapter( $blobRestProxy, get_option( "xcloner_azure_container" ) );
478
+
479
+ $filesystem = new Filesystem( $adapter, new Config( [
480
+ 'disable_asserts' => true,
481
+ ] ) );
482
+
483
+ return array( $adapter, $filesystem );
484
  }
485
+
486
+ public function get_dropbox_filesystem() {
487
+ $this->logger->info( sprintf( "Creating the DROPBOX remote storage connection" ), array( "" ) );
488
+
489
+ if ( version_compare( phpversion(), '5.6.0', '<' ) ) {
490
+ throw new Exception( "DROPBOX requires PHP 5.6 to be installed!" );
 
 
491
  }
 
 
 
 
 
 
 
492
 
493
+ $client = new DropboxClient( get_option( "xcloner_dropbox_access_token" ) );
494
+ $adapter = new DropboxAdapter( $client, get_option( "xcloner_dropbox_prefix" ) );
495
+
496
+ $filesystem = new Filesystem( $adapter, new Config( [
497
+ 'disable_asserts' => true,
498
+ ] ) );
499
+
500
+ return array( $adapter, $filesystem );
501
  }
502
+
503
+ public function get_aws_filesystem() {
504
+ $this->logger->info( sprintf( "Creating the S3 remote storage connection" ), array( "" ) );
505
+
506
+ if ( version_compare( phpversion(), '5.6.0', '<' ) ) {
507
+ throw new Exception( "S3 class requires PHP 5.6 to be installed!" );
 
 
508
  }
509
+
510
+ if ( ! class_exists( 'XmlWriter' ) ) {
511
+ throw new Exception( "AZURE BLOB requires libxml PHP module to be installed with XmlWriter class enabled!" );
 
512
  }
513
+
514
+
515
  $credentials = array(
516
+ 'credentials' => array(
517
+ 'key' => get_option( "xcloner_aws_key" ),
518
+ 'secret' => get_option( "xcloner_aws_secret" )
519
+ ),
520
+ 'region' => get_option( "xcloner_aws_region" ),
521
+ 'version' => 'latest',
522
  );
523
+
524
+ if ( get_option( 'xcloner_aws_endpoint' ) != "" && ! get_option( "xcloner_aws_region" ) ) {
525
+
526
+ $credentials['endpoint'] = get_option( 'xcloner_aws_endpoint' );
527
  #$credentials['use_path_style_endpoint'] = true;
528
  #$credentials['bucket_endpoint'] = false;
529
+
530
+
531
+ }
532
+
533
+ $client = new S3Client( $credentials );
534
+
535
+ $adapter = new AwsS3Adapter( $client, get_option( "xcloner_aws_bucket_name" ), get_option( "xcloner_aws_prefix" ) );
536
+ $filesystem = new Filesystem( $adapter, new Config( [
537
+ 'disable_asserts' => true,
538
+ ] ) );
539
+
540
+ return array( $adapter, $filesystem );
 
541
  }
542
+
543
+ public function get_backblaze_filesystem() {
544
+ $this->logger->info( sprintf( "Creating the BACKBLAZE remote storage connection" ), array( "" ) );
545
+
546
+ if ( version_compare( phpversion(), '5.6.0', '<' ) ) {
547
+ throw new Exception( "BACKBLAZE API requires PHP 5.6 to be installed!" );
548
+ }
549
+
550
+
551
+ $client = new B2Client( get_option( "xcloner_backblaze_account_id" ), get_option( "xcloner_backblaze_application_key" ) );
552
+ $adapter = new BackblazeAdapter( $client, get_option( "xcloner_backblaze_bucket_name" ) );
553
+
554
+ $filesystem = new Filesystem( $adapter, new Config( [
555
+ 'disable_asserts' => true,
556
+ ] ) );
557
+
558
+ return array( $adapter, $filesystem );
 
 
559
  }
560
+
561
+ public function get_webdav_filesystem() {
562
+ $this->logger->info( sprintf( "Creating the WEBDAV remote storage connection" ), array( "" ) );
563
+
564
+ if ( version_compare( phpversion(), '5.6.0', '<' ) ) {
565
+ throw new Exception( "WEBDAV API requires PHP 5.6 to be installed!" );
 
 
566
  }
567
+
568
  $settings = array(
569
+ 'baseUri' => get_option( "xcloner_webdav_url" ),
570
+ 'userName' => get_option( "xcloner_webdav_username" ),
571
+ 'password' => get_option( "xcloner_webdav_password" ),
572
  //'proxy' => 'locahost:8888',
573
  );
574
+
575
+
576
+ $client = new SabreClient( $settings );
577
+ $adapter = new WebDAVAdapter( $client, get_option( "xcloner_webdav_target_folder" ) );
578
+ $filesystem = new Filesystem( $adapter, new Config( [
579
+ 'disable_asserts' => true,
580
+ ] ) );
581
+
582
+ return array( $adapter, $filesystem );
583
  }
584
+
585
+
586
+ public function gdrive_construct() {
 
587
 
588
  //if((function_exists("is_plugin_active") && !is_plugin_active("xcloner-google-drive/xcloner-google-drive.php")) || !file_exists(__DIR__ . "/../../xcloner-google-drive/vendor/autoload.php"))
589
+ if ( ! class_exists( 'Google_Client' ) ) {
 
590
  return false;
591
  }
592
+
593
  //require_once(__DIR__ . "/../../xcloner-google-drive/vendor/autoload.php");
594
+
595
  $client = new \Google_Client();
596
+ $client->setApplicationName( $this->gdrive_app_name );
597
+ $client->setClientId( get_option( "xcloner_gdrive_client_id" ) );
598
+ $client->setClientSecret( get_option( "xcloner_gdrive_client_secret" ) );
599
+
600
  //$redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF']."?page=xcloner_remote_storage_page&action=set_gdrive_code";
601
  $redirect_uri = "urn:ietf:wg:oauth:2.0:oob";
602
+
603
+ $client->setRedirectUri( $redirect_uri ); //urn:ietf:wg:oauth:2.0:oob
604
+ $client->addScope( "https://www.googleapis.com/auth/drive" );
605
+ $client->setAccessType( 'offline' );
606
+
607
  return $client;
608
  }
609
+
610
+ public function get_gdrive_auth_url() {
 
611
  $client = $this->gdrive_construct();
612
+
613
+ if ( ! $client ) {
614
  return false;
615
+ }
616
+
617
  return $authUrl = $client->createAuthUrl();
618
  }
619
+
620
+ public function set_access_token( $code ) {
 
621
  $client = $this->gdrive_construct();
622
+
623
+ if ( ! $client ) {
 
624
  $error_msg = "Could not initialize the Google Drive Class, please check that the xcloner-google-drive plugin is enabled...";
625
+ $this->logger->error( $error_msg );
626
+
627
  return false;
628
  }
629
 
630
+ $token = $client->fetchAccessTokenWithAuthCode( $code );
631
+ $client->setAccessToken( $token );
632
+
633
+ update_option( "xcloner_gdrive_access_token", $token['access_token'] );
634
+ update_option( "xcloner_gdrive_refresh_token", $token['refresh_token'] );
635
+
636
+ $redirect_url = ( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'] . "?page=xcloner_remote_storage_page#gdrive" );
637
+
638
  ?>
639
+ <script>
640
+ window.location = '<?php echo $redirect_url?>';
641
+ </script>
642
  <?php
643
+
644
  }
645
+
646
  /*
647
  * php composer.phar remove nao-pon/flysystem-google-drive
648
  *
649
  */
650
+ public function get_gdrive_filesystem() {
651
+
652
+ if ( version_compare( phpversion(), '5.6.0', '<' ) ) {
653
+ throw new Exception( "Google Drive API requires PHP 5.6 to be installed!" );
 
 
654
  }
655
+
656
+ $this->logger->info( sprintf( "Creating the Google Drive remote storage connection" ), array( "" ) );
657
+
658
  $client = $this->gdrive_construct();
659
+
660
+ if ( ! $client ) {
 
661
  $error_msg = "Could not initialize the Google Drive Class, please check that the xcloner-google-drive plugin is enabled...";
662
+ $this->logger->error( $error_msg );
663
+ throw new Exception( $error_msg );
664
+ }
665
+
666
+ $client->refreshToken( get_option( "xcloner_gdrive_refresh_token" ) );
667
+
668
+ $service = new \Google_Service_Drive( $client );
669
+
670
  /*if( get_option("xcloner_gdrive_empty_trash",0) ){
671
  $this->logger->info(sprintf("Doing a Google Drive emptyTrash call"), array(""));
672
  $service->files->emptyTrash();
673
  }*/
674
+
675
  $parent = 'root';
676
+ $dir = basename( get_option( "xcloner_gdrive_target_folder" ) );
677
+
678
+ $folderID = get_option( "xcloner_gdrive_target_folder" );
679
+
680
+ $tmp = parse_url( $folderID );
681
+
682
+ if ( isset( $tmp['query'] ) ) {
683
+ $folderID = str_replace( "id=", "", $tmp['query'] );
 
684
  }
685
+
686
+ if ( stristr( $folderID, "/" ) ) {
687
+ $query = sprintf( 'mimeType = \'application/vnd.google-apps.folder\' and \'%s\' in parents and name contains \'%s\'', $parent, $dir );
688
+ $response = $service->files->listFiles( [
689
+ 'pageSize' => 1,
690
+ 'q' => $query
691
+ ] );
692
+
693
+ if ( sizeof( $response ) ) {
694
+ foreach ( $response as $obj ) {
695
+ $folderID = $obj->getId();
 
 
696
  }
697
+ } else {
698
+ $this->xcloner->trigger_message( sprintf( __( "Could not find folder ID by name %s", 'xcloner-backup-and-restore' ), $folderID ), "error" );
699
  }
700
  }
701
+
702
+ $this->logger->info( sprintf( "Using target folder with ID %s on the remote storage", $folderID ) );
703
+
704
+ if ( class_exists( 'XCloner_Google_Drive_Adapter' ) ) {
705
+ $adapter = new XCloner_Google_Drive_Adapter( $service, $folderID );
706
+ } else {
707
+ $adapter = new \Hypweb\Flysystem\GoogleDrive\GoogleDriveAdapter( $service, $folderID );
708
+ }
709
+
710
+ $filesystem = new \League\Flysystem\Filesystem( $adapter, new Config( [
711
+ 'disable_asserts' => true,
712
+ ] ) );
713
+
714
+
715
+ return array( $adapter, $filesystem );
716
  }
717
+
718
+ public function get_ftp_filesystem() {
719
+ $this->logger->info( sprintf( "Creating the FTP remote storage connection" ), array( "" ) );
720
+
721
+ $adapter = new Adapter( [
722
+ 'host' => get_option( "xcloner_ftp_hostname" ),
723
+ 'username' => get_option( "xcloner_ftp_username" ),
724
+ 'password' => get_option( "xcloner_ftp_password" ),
725
+
726
+ /** optional config settings */
727
+ 'port' => get_option( "xcloner_ftp_port", 21 ),
728
+ 'root' => get_option( "xcloner_ftp_path" ),
729
+ 'passive' => get_option( "xcloner_ftp_transfer_mode" ),
730
+ 'ssl' => get_option( "xcloner_ftp_ssl_mode" ),
731
+ 'timeout' => get_option( "xcloner_ftp_timeout", 30 ),
732
+ ] );
733
+
 
734
  $adapter->connect();
735
+
736
+ $filesystem = new Filesystem( $adapter, new Config( [
737
+ 'disable_asserts' => true,
738
+ ] ) );
739
+
740
+ return array( $adapter, $filesystem );
741
  }
742
+
743
+ public function get_sftp_filesystem() {
744
+ $this->logger->info( sprintf( "Creating the SFTP remote storage connection" ), array( "" ) );
745
+
746
+ $adapter = new SftpAdapter( [
747
+ 'host' => get_option( "xcloner_sftp_hostname" ),
748
+ 'username' => get_option( "xcloner_sftp_username" ),
749
+ 'password' => get_option( "xcloner_sftp_password" ),
750
+
751
+ /** optional config settings */
752
+ 'port' => get_option( "xcloner_sftp_port", 22 ),
753
+ 'root' => get_option( "xcloner_sftp_path" ),
754
+ 'privateKey' => get_option( "xcloner_sftp_private_key" ),
755
+ 'timeout' => get_option( "xcloner_ftp_timeout", 30 ),
756
+ ] );
757
+
 
758
  $adapter->connect();
759
+
760
+ $filesystem = new Filesystem( $adapter, new Config( [
761
+ 'disable_asserts' => true,
762
+ ] ) );
763
+
764
+ return array( $adapter, $filesystem );
765
  }
 
 
 
 
 
766
 
767
+ public function change_storage_status( $field, $value ) {
768
+ $field = $this->xcloner_sanitization->sanitize_input_as_string( $field );
769
+ $value = $this->xcloner_sanitization->sanitize_input_as_int( $value );
770
+
771
+ return update_option( $field, $value );
772
  }
773
+
774
+ public function get_aws_regions() {
 
775
  return $this->aws_regions;
776
  }
777
+
778
  }
includes/class-xcloner-requirements.php CHANGED
@@ -1,69 +1,67 @@
1
  <?php
2
 
3
- class Xcloner_Requirements
4
- {
5
-
6
- var $min_php_version = "5.6.0";
7
- var $safe_mode = "Off";
8
-
9
  private $xcloner_settings;
10
  private $xcloner_container;
11
-
12
- public function __construct(Xcloner $xcloner_container)
13
- {
14
  $this->xcloner_container = $xcloner_container;
15
- $this->xcloner_settings = $xcloner_container->get_xcloner_settings();
16
  }
17
-
18
- private function get_xcloner_container()
19
- {
20
  return $this->xcloner_container;
21
  }
22
-
23
- public function check_backup_ready_status()
24
- {
25
- if(!$this->check_min_php_version(1))
26
  return false;
27
-
28
- if(!$this->check_safe_mode(1))
 
29
  return false;
30
-
31
- if(!$this->check_xcloner_start_path(1))
 
32
  return false;
33
-
34
- if(!$this->check_xcloner_store_path(1))
 
35
  return false;
36
-
37
- if(!$this->check_xcloner_tmp_path(1))
 
38
  return false;
39
-
40
- return true;
 
41
  }
42
-
43
- public function get_constant($var)
44
- {
45
  return $this->$var;
46
  }
47
-
48
- public function check_min_php_version($return_bool = 0)
49
- {
50
-
51
- if($return_bool == 1)
52
- {
53
- if(version_compare(phpversion(), $this->min_php_version, '<'))
54
  return false;
55
- else
56
  return true;
 
57
  }
58
-
59
  return phpversion();
60
  }
61
-
62
- public function check_safe_mode($return_bool=0)
63
- {
64
  /*no longer needed for PHP 7*/
65
  $safe_mode = "Off";
66
-
67
  /*if($return_bool)
68
  {
69
  if( ini_get('safe_mode') )
@@ -75,98 +73,97 @@ class Xcloner_Requirements
75
  if( ini_get('safe_mode') )
76
  $safe_mode = "On";
77
  * */
78
-
79
  return $safe_mode;
80
  }
81
-
82
- public function check_xcloner_start_path($return_bool=0)
83
- {
84
  $path = $this->xcloner_settings->get_xcloner_start_path();
85
-
86
- if($return_bool)
87
- {
88
- if(!file_exists($path))
89
  return false;
90
-
91
- return is_readable($path);
 
92
  }
93
-
94
  return $path;
95
  }
96
-
97
- public function check_xcloner_tmp_path($return_bool=0)
98
- {
99
  $path = $this->xcloner_settings->get_xcloner_tmp_path();
100
-
101
- if($return_bool)
102
- {
103
- if(!file_exists($path))
104
  return false;
105
-
106
- if(!is_writeable($path))
107
- @chmod($path, 0777);
108
-
109
- return is_writeable($path);
 
 
110
  }
111
-
112
  return $path;
113
  }
114
-
115
- public function check_xcloner_store_path($return_bool=0)
116
- {
117
  $path = $this->xcloner_settings->get_xcloner_store_path();
118
-
119
- if($return_bool)
120
- {
121
- if(!file_exists($path))
122
  return false;
123
-
124
- if(!is_writeable($path))
125
- @chmod($path, 0777);
126
-
127
- return is_writeable($path);
 
 
128
  }
129
-
130
  return $path;
131
  }
132
-
133
- public function get_max_execution_time()
134
- {
135
- return ini_get('max_execution_time');
136
  }
137
-
138
- public function get_memory_limit()
139
- {
140
- return ini_get('memory_limit');
141
  }
142
-
143
- public function get_open_basedir()
144
- {
145
- $open_basedir = ini_get('open_basedir');
146
-
147
- if(!$open_basedir)
148
  $open_basedir = "none";
149
- return $open_basedir;
 
 
150
  }
151
-
152
- public function get_free_disk_space()
153
- {
154
- return $this->file_format_size(disk_free_space($this->xcloner_settings->get_xcloner_store_path()));
155
  }
156
-
157
- public function file_format_size($bytes, $decimals = 2) {
158
- $unit_list = array('B', 'KB', 'MB', 'GB', 'PB');
159
-
160
- if ($bytes == 0) {
161
- return $bytes . ' ' . $unit_list[0];
162
- }
163
-
164
- $unit_count = count($unit_list);
165
- for ($i = $unit_count - 1; $i >= 0; $i--) {
166
- $power = $i * 10;
167
- if (($bytes >> $power) >= 1)
168
- return round($bytes / (1 << $power), $decimals) . ' ' . $unit_list[$i];
169
- }
 
170
  }
171
  }
 
172
  ?>
1
  <?php
2
 
3
+ class Xcloner_Requirements {
4
+
5
+ var $min_php_version = "5.6.0";
6
+ var $safe_mode = "Off";
7
+
 
8
  private $xcloner_settings;
9
  private $xcloner_container;
10
+
11
+ public function __construct( Xcloner $xcloner_container ) {
 
12
  $this->xcloner_container = $xcloner_container;
13
+ $this->xcloner_settings = $xcloner_container->get_xcloner_settings();
14
  }
15
+
16
+ private function get_xcloner_container() {
 
17
  return $this->xcloner_container;
18
  }
19
+
20
+ public function check_backup_ready_status() {
21
+ if ( ! $this->check_min_php_version( 1 ) ) {
 
22
  return false;
23
+ }
24
+
25
+ if ( ! $this->check_safe_mode( 1 ) ) {
26
  return false;
27
+ }
28
+
29
+ if ( ! $this->check_xcloner_start_path( 1 ) ) {
30
  return false;
31
+ }
32
+
33
+ if ( ! $this->check_xcloner_store_path( 1 ) ) {
34
  return false;
35
+ }
36
+
37
+ if ( ! $this->check_xcloner_tmp_path( 1 ) ) {
38
  return false;
39
+ }
40
+
41
+ return true;
42
  }
43
+
44
+ public function get_constant( $var ) {
 
45
  return $this->$var;
46
  }
47
+
48
+ public function check_min_php_version( $return_bool = 0 ) {
49
+
50
+ if ( $return_bool == 1 ) {
51
+ if ( version_compare( phpversion(), $this->min_php_version, '<' ) ) {
 
 
52
  return false;
53
+ } else {
54
  return true;
55
+ }
56
  }
57
+
58
  return phpversion();
59
  }
60
+
61
+ public function check_safe_mode( $return_bool = 0 ) {
 
62
  /*no longer needed for PHP 7*/
63
  $safe_mode = "Off";
64
+
65
  /*if($return_bool)
66
  {
67
  if( ini_get('safe_mode') )
73
  if( ini_get('safe_mode') )
74
  $safe_mode = "On";
75
  * */
76
+
77
  return $safe_mode;
78
  }
79
+
80
+ public function check_xcloner_start_path( $return_bool = 0 ) {
 
81
  $path = $this->xcloner_settings->get_xcloner_start_path();
82
+
83
+ if ( $return_bool ) {
84
+ if ( ! file_exists( $path ) ) {
 
85
  return false;
86
+ }
87
+
88
+ return is_readable( $path );
89
  }
90
+
91
  return $path;
92
  }
93
+
94
+ public function check_xcloner_tmp_path( $return_bool = 0 ) {
 
95
  $path = $this->xcloner_settings->get_xcloner_tmp_path();
96
+
97
+ if ( $return_bool ) {
98
+ if ( ! file_exists( $path ) ) {
 
99
  return false;
100
+ }
101
+
102
+ if ( ! is_writeable( $path ) ) {
103
+ @chmod( $path, 0777 );
104
+ }
105
+
106
+ return is_writeable( $path );
107
  }
108
+
109
  return $path;
110
  }
111
+
112
+ public function check_xcloner_store_path( $return_bool = 0 ) {
 
113
  $path = $this->xcloner_settings->get_xcloner_store_path();
114
+
115
+ if ( $return_bool ) {
116
+ if ( ! file_exists( $path ) ) {
 
117
  return false;
118
+ }
119
+
120
+ if ( ! is_writeable( $path ) ) {
121
+ @chmod( $path, 0777 );
122
+ }
123
+
124
+ return is_writeable( $path );
125
  }
126
+
127
  return $path;
128
  }
129
+
130
+ public function get_max_execution_time() {
131
+ return ini_get( 'max_execution_time' );
 
132
  }
133
+
134
+ public function get_memory_limit() {
135
+ return ini_get( 'memory_limit' );
 
136
  }
137
+
138
+ public function get_open_basedir() {
139
+ $open_basedir = ini_get( 'open_basedir' );
140
+
141
+ if ( ! $open_basedir ) {
 
142
  $open_basedir = "none";
143
+ }
144
+
145
+ return $open_basedir;
146
  }
147
+
148
+ public function get_free_disk_space() {
149
+ return $this->file_format_size( disk_free_space( $this->xcloner_settings->get_xcloner_store_path() ) );
 
150
  }
151
+
152
+ public function file_format_size( $bytes, $decimals = 2 ) {
153
+ $unit_list = array( 'B', 'KB', 'MB', 'GB', 'PB' );
154
+
155
+ if ( $bytes == 0 ) {
156
+ return $bytes . ' ' . $unit_list[0];
157
+ }
158
+
159
+ $unit_count = count( $unit_list );
160
+ for ( $i = $unit_count - 1; $i >= 0; $i -- ) {
161
+ $power = $i * 10;
162
+ if ( ( $bytes >> $power ) >= 1 ) {
163
+ return round( $bytes / ( 1 << $power ), $decimals ) . ' ' . $unit_list[ $i ];
164
+ }
165
+ }
166
  }
167
  }
168
+
169
  ?>
includes/class-xcloner-sanitization.php CHANGED
@@ -1,64 +1,59 @@
1
  <?php
 
2
  use League\Flysystem\Util;
3
 
4
  class Xcloner_Sanitization {
5
-
6
- public function __construct(){}
7
-
8
- public function sanitize_input_as_int($option)
9
- {
10
- return filter_var($option, FILTER_SANITIZE_NUMBER_INT);
11
  }
12
-
13
- public function sanitize_input_as_float($option)
14
- {
15
- return filter_var($option, FILTER_VALIDATE_FLOAT);
16
  }
17
-
18
- public function sanitize_input_as_string($option)
19
- {
20
- return filter_var($option, FILTER_SANITIZE_STRING);
21
  }
22
-
23
- public function sanitize_input_as_absolute_path($option)
24
- {
25
- $path = filter_var($option, FILTER_SANITIZE_URL);
26
-
27
- try{
28
- $option = Util::normalizePath($path);
29
- }catch(Exception $e){
30
- add_settings_error('xcloner_error_message', '', __($e->getMessage()), 'error');
31
  }
32
-
33
- if($path and !is_dir($path)){
34
- add_settings_error('xcloner_error_message', '', __(sprintf('Invalid Server Path %s',$option)), 'error');
 
35
  return false;
36
  }
37
-
38
  return $path;
39
  }
40
-
41
- public function sanitize_input_as_path($option)
42
- {
43
- return filter_var($option, FILTER_SANITIZE_URL);
44
  }
45
-
46
- public function sanitize_input_as_relative_path($option)
47
- {
48
- $option = filter_var($option, FILTER_SANITIZE_URL);
49
- $option = str_replace("..", "", $option);
50
-
51
  return $option;
52
  }
53
-
54
- public function sanitize_input_as_email($option)
55
- {
56
- return filter_var($option, FILTER_SANITIZE_EMAIL);
57
  }
58
 
59
- public function sanitize_input_as_raw($option)
60
- {
61
- return filter_var($option, FILTER_UNSAFE_RAW);
62
  }
63
-
64
  }
1
  <?php
2
+
3
  use League\Flysystem\Util;
4
 
5
  class Xcloner_Sanitization {
6
+
7
+ public function __construct() {
8
+ }
9
+
10
+ public function sanitize_input_as_int( $option ) {
11
+ return filter_var( $option, FILTER_SANITIZE_NUMBER_INT );
12
  }
13
+
14
+ public function sanitize_input_as_float( $option ) {
15
+ return filter_var( $option, FILTER_VALIDATE_FLOAT );
 
16
  }
17
+
18
+ public function sanitize_input_as_string( $option ) {
19
+ return filter_var( $option, FILTER_SANITIZE_STRING );
 
20
  }
21
+
22
+ public function sanitize_input_as_absolute_path( $option ) {
23
+ $path = filter_var( $option, FILTER_SANITIZE_URL );
24
+
25
+ try {
26
+ $option = Util::normalizePath( $path );
27
+ } catch ( Exception $e ) {
28
+ add_settings_error( 'xcloner_error_message', '', __( $e->getMessage() ), 'error' );
 
29
  }
30
+
31
+ if ( $path and ! is_dir( $path ) ) {
32
+ add_settings_error( 'xcloner_error_message', '', __( sprintf( 'Invalid Server Path %s', $option ) ), 'error' );
33
+
34
  return false;
35
  }
36
+
37
  return $path;
38
  }
39
+
40
+ public function sanitize_input_as_path( $option ) {
41
+ return filter_var( $option, FILTER_SANITIZE_URL );
 
42
  }
43
+
44
+ public function sanitize_input_as_relative_path( $option ) {
45
+ $option = filter_var( $option, FILTER_SANITIZE_URL );
46
+ $option = str_replace( "..", "", $option );
47
+
 
48
  return $option;
49
  }
50
+
51
+ public function sanitize_input_as_email( $option ) {
52
+ return filter_var( $option, FILTER_SANITIZE_EMAIL );
 
53
  }
54
 
55
+ public function sanitize_input_as_raw( $option ) {
56
+ return filter_var( $option, FILTER_UNSAFE_RAW );
 
57
  }
58
+
59
  }
includes/class-xcloner-scheduler.php CHANGED
@@ -1,396 +1,372 @@
1
  <?php
2
 
3
- class Xcloner_Scheduler{
4
-
5
  private $db;
6
  private $scheduler_table = "xcloner_scheduler";
7
-
8
  private $xcloner_remote_storage;
9
  private $archive_system;
10
  private $xcloner_database;
11
  private $xcloner_settings;
12
  private $logger;
13
  private $xcloner_file_system;
14
-
15
- private $allowed_schedules = array("hourly", "twicedaily", "daily", "weekly", "monthly");
 
16
  /*public function __call($method, $args) {
17
  echo "$method is not defined";
18
  }*/
19
 
20
- public function __construct(Xcloner $xcloner_container)
21
- {
22
  global $wpdb;
23
-
24
- $this->db = $wpdb;
25
- $wpdb->show_errors = false;
26
-
27
- $this->xcloner_container = $xcloner_container;
28
- $this->xcloner_settings = $xcloner_container->get_xcloner_settings();
29
-
30
- $this->scheduler_table = $this->db->prefix.$this->scheduler_table;
31
  }
32
-
33
- private function get_xcloner_container()
34
- {
35
  return $this->xcloner_container;
36
  }
37
-
38
- private function set_xcloner_container(Xcloner $container)
39
- {
40
  $this->xcloner_container = $container;
41
  }
42
-
43
- public function get_scheduler_list($return_only_enabled = 0 )
44
- {
45
- $list = $this->db->get_results("SELECT * FROM ".$this->scheduler_table);
46
-
47
- if($return_only_enabled)
48
- {
49
- $new_list= array();
50
-
51
- foreach($list as $res)
52
- if($res->status)
53
- {
54
- $res->next_run_time = wp_next_scheduled('xcloner_scheduler_'.$res->id, array($res->id))+(get_option( 'gmt_offset' ) * HOUR_IN_SECONDS);
55
- $new_list[] = $res;
56
  }
57
- $list = $new_list;
 
58
  }
 
59
  return $list;
60
  }
61
-
62
- public function get_next_run_schedule($xcloner_file_system = "")
63
- {
64
- $list = $this->get_scheduler_list($return_only_enabled = 1);
65
 
66
  return $list;
67
  }
68
-
69
- public function get_schedule_by_id_object($id)
70
- {
71
- $data = $this->db->get_row("SELECT * FROM ".$this->scheduler_table." WHERE id=".$id);
72
-
73
  return $data;
74
  }
75
-
76
- public function get_schedule_by_id($id)
77
- {
78
- $data = $this->db->get_row("SELECT * FROM ".$this->scheduler_table." WHERE id=".$id, ARRAY_A);
79
-
80
- if(!$data)
81
  return false;
82
-
83
- $params = json_decode($data['params']);
84
-
 
85
  //print_r($params);
86
- $data['params'] = "";
87
- $data['backup_params'] = $params->backup_params;
88
- $data['table_params'] = json_encode($params->database);
89
- $data['excluded_files'] = json_encode($params->excluded_files);
90
-
91
-
92
  return $data;
93
  }
94
-
95
- public function delete_schedule_by_id($id)
96
- {
97
- $hook = 'xcloner_scheduler_'.$id;
98
- wp_clear_scheduled_hook( $hook, array($id) );
99
-
100
- $data = $this->db->delete( $this->scheduler_table , array( 'id' => $id ) );
101
-
102
  return $data;
103
  }
104
-
105
- public function deactivate_wp_cron_hooks()
106
- {
107
  $list = $this->get_scheduler_list();
108
-
109
- foreach($list as $schedule)
110
- {
111
- $hook = 'xcloner_scheduler_'.$schedule->id;
112
-
113
- $timestamp = wp_next_scheduled( $hook , array($schedule->id) );
114
- wp_unschedule_event( $timestamp, $hook, array($schedule->id) );
115
  }
116
  }
117
-
118
- public function update_wp_cron_hooks()
119
- {
120
  $list = $this->get_scheduler_list();
121
-
122
- foreach($list as $schedule)
123
- {
124
- $hook = 'xcloner_scheduler_'.$schedule->id;
125
-
126
  //adding the xcloner_scheduler hook with xcloner_scheduler_callback callback
127
- add_action( $hook, array($this, 'xcloner_scheduler_callback'), 10, 1 );
128
-
129
- if ( ! wp_next_scheduled( $hook, array($schedule->id) ) and $schedule->status) {
130
-
131
- if($schedule->recurrence == "single")
132
- {
133
- wp_schedule_single_event( strtotime($schedule->start_at), $hook, array($schedule->id));
134
- }else{
135
- wp_schedule_event( strtotime($schedule->start_at), $schedule->recurrence, $hook, array($schedule->id) );
136
  }
137
-
138
- }elseif(!$schedule->status)
139
- {
140
- $timestamp = wp_next_scheduled( $hook , array($schedule->id) );
141
- wp_unschedule_event( $timestamp, $hook, array($schedule->id) );
142
  }
143
  }
144
-
145
  }
146
-
147
- public function update_cron_hook($id)
148
- {
149
- $schedule = $this->get_schedule_by_id_object($id);
150
- $hook = 'xcloner_scheduler_'.$schedule->id;
151
-
152
- $timestamp = wp_next_scheduled( $hook , array($schedule->id) );
153
- wp_unschedule_event( $timestamp, $hook, array($schedule->id) );
154
-
155
- if ($schedule->status) {
156
-
157
- if($schedule->recurrence == "single")
158
- {
159
- wp_schedule_single_event( strtotime($schedule->start_at), $hook, array($schedule->id));
160
- }else{
161
- wp_schedule_event( strtotime($schedule->start_at), $schedule->recurrence, $hook, array($schedule->id) );
162
  }
163
-
164
  }
165
- }
166
-
167
- public function disable_single_cron($schedule_id)
168
- {
169
- $hook = 'xcloner_scheduler_'.$schedule_id;
170
- $timestamp = wp_next_scheduled( $hook , array($schedule_id) );
171
- wp_unschedule_event( $timestamp, $hook, array($schedule_id) );
172
-
173
  $schedule['status'] = 0;
174
-
175
- $update = $this->db->update(
176
- $this->scheduler_table,
177
- $schedule,
178
- array( 'id' => $schedule_id ),
179
- array(
180
- '%s',
181
- '%s'
182
- )
183
- );
184
- return $update;
 
185
  }
186
-
187
- public function update_hash($schedule_id, $hash)
188
- {
189
  $schedule['hash'] = $hash;
190
-
191
- $update = $this->db->update(
192
- $this->scheduler_table,
193
- $schedule,
194
- array( 'id' => $schedule_id ),
195
- array(
196
- '%s',
197
- '%s'
198
- )
199
- );
200
- return $update;
201
- }
202
-
203
- public function update_last_backup($schedule_id, $last_backup)
204
- {
205
  $schedule['last_backup'] = $last_backup;
206
-
207
- $update = $this->db->update(
208
- $this->scheduler_table,
209
- $schedule,
210
- array( 'id' => $schedule_id ),
211
- array(
212
- '%s',
213
- '%s'
214
- )
215
- );
216
- return $update;
217
- }
218
-
219
- private function _xcloner_scheduler_callback($id, $schedule)
220
- {
221
- set_time_limit(0);
222
-
223
  $xcloner = new XCloner();
224
  $xcloner->init();
225
- $this->set_xcloner_container($xcloner);
226
-
227
  #$hash = $this->xcloner_settings->get_hash();
228
  #$this->get_xcloner_container()->get_xcloner_settings()->set_hash($hash);
229
-
230
  //$this->xcloner_settings = $this->get_xcloner_container()->get_xcloner_settings();
231
- $this->xcloner_file_system = $this->get_xcloner_container()->get_xcloner_filesystem();
232
- $this->xcloner_database = $this->get_xcloner_container()->get_xcloner_database();
233
- $this->archive_system = $this->get_xcloner_container()->get_archive_system();
234
- $this->logger = $this->get_xcloner_container()->get_xcloner_logger()->withName("xcloner_scheduler");
235
- $this->xcloner_remote_storage = $this->get_xcloner_container()->get_xcloner_remote_storage();
236
-
237
- $this->logger->info(sprintf("New schedule hash is %s", $this->xcloner_settings->get_hash()));
238
-
239
- if(isset($schedule['backup_params']->diff_start_date) && $schedule['backup_params']->diff_start_date)
240
- {
241
- $this->xcloner_file_system->set_diff_timestamp_start($schedule['backup_params']->diff_start_date);
242
  }
243
-
244
- if($schedule['recurrence'] == "single")
245
- {
246
- $this->disable_single_cron($schedule['id']);
247
  }
248
-
249
- if(!$schedule)
250
- {
251
- $this->logger->info(sprintf("Could not load schedule with id'%s'", $id), array("CRON"));
252
  return;
253
  }
254
-
255
  //echo $this->get_xcloner_container()->get_xcloner_settings()->get_hash(); exit;
256
-
257
- $this->update_hash($schedule['id'], $this->xcloner_settings->get_hash());
258
-
259
- $this->logger->info(sprintf("Starting cron schedule '%s'", $schedule['name']), array("CRON"));
260
-
261
- $this->xcloner_file_system->set_excluded_files(json_decode($schedule['excluded_files']));
262
-
263
- $init = 1;
264
  $continue = 1;
265
 
266
- while($continue)
267
- {
268
- $continue = $this->xcloner_file_system->start_file_recursion($init);
269
-
270
  $init = 0;
271
  }
272
-
273
- $this->logger->info(sprintf("File scan finished"), array("CRON"));
274
-
275
- $this->logger->info(sprintf("Starting the database backup"), array("CRON"));
276
-
277
- $init = 1;
278
  $return['finished'] = 0;
279
-
280
- while(!$return['finished'])
281
- {
282
- $return = $this->xcloner_database->start_database_recursion((array)json_decode($schedule['table_params']), $return, $init);
283
- $init = 0;
284
  }
285
-
286
- $this->logger->info(sprintf("Database backup done"), array("CRON"));
287
-
288
- $this->logger->info(sprintf("Starting file archive process"), array("CRON"));
289
-
290
- $init = 0;
291
  $return['finished'] = 0;
292
- $return['extra'] = array();
293
-
294
- while(!$return['finished'])
295
- {
296
- $return = $this->archive_system->start_incremental_backup((array)$schedule['backup_params'], $return['extra'], $init);
297
- $init = 0;
298
  }
299
- $this->logger->info(sprintf("File archive process FINISHED."), array("CRON"));
300
-
301
  //getting the last backup archive file
302
  $return['extra']['backup_parent'] = $this->archive_system->get_archive_name_with_extension();
303
- if($this->xcloner_file_system->is_part($this->archive_system->get_archive_name_with_extension()))
304
- $return['extra']['backup_parent'] = $this->archive_system->get_archive_name_multipart();
305
-
306
- $this->update_last_backup($schedule['id'], $return['extra']['backup_parent']);
307
-
308
- if(isset($schedule['remote_storage']) && $schedule['remote_storage'] && array_key_exists($schedule['remote_storage'], $this->xcloner_remote_storage->get_available_storages()))
309
- {
310
  $backup_file = $return['extra']['backup_parent'];
311
-
312
- $this->logger->info(sprintf("Transferring backup to remote storage %s", strtoupper($schedule['remote_storage'])), array("CRON"));
313
-
314
- if(method_exists($this->xcloner_remote_storage, "upload_backup_to_storage"))
315
- call_user_func_array(array($this->xcloner_remote_storage, "upload_backup_to_storage"), array($backup_file, $schedule['remote_storage']));
 
 
 
 
316
  }
317
-
318
- if(isset($schedule['backup_params']->email_notification) and $to=$schedule['backup_params']->email_notification)
319
- {
320
- try{
321
- $from = "";
322
  $additional['lines_total'] = $return['extra']['lines_total'];
323
- $subject = sprintf(__("%s - new backup generated %s") , $schedule['name'], $return['extra']['backup_parent']);
324
-
325
- $this->archive_system->send_notification($to, $from, $subject, $return['extra']['backup_parent'], $schedule, "", $additional);
326
-
327
- }catch(Exception $e)
328
- {
329
- $this->logger->error($e->getMessage());
330
  }
331
  }
332
-
333
  //CHECK IF WE SHOULD DELETE BACKUP AFTER REMOTE TRANSFER IS DONE
334
- if($schedule['remote_storage'] && $this->xcloner_settings->get_xcloner_option('xcloner_cleanup_delete_after_remote_transfer'))
335
- {
336
- $this->logger->info(sprintf("Deleting %s from local storage matching rule xcloner_cleanup_delete_after_remote_transfer",$return['extra']['backup_parent']));
337
- $this->xcloner_file_system->delete_backup_by_name($return['extra']['backup_parent']);
338
-
339
  }
340
-
341
  $this->xcloner_file_system->remove_tmp_filesystem();
342
-
343
  $this->xcloner_file_system->backup_storage_cleanup();
344
-
345
  //DO TMP FILESYSTEM CLEANUP
346
  $this->xcloner_file_system->cleanup_tmp_directories();
347
  }
348
-
349
- public function xcloner_scheduler_callback($id, $schedule = "")
350
- {
351
- if($id)
352
- {
353
- $schedule = $this->get_schedule_by_id($id);
354
  }
355
-
356
- try{
357
 
358
- $this->_xcloner_scheduler_callback($id, $schedule);
359
-
360
- }catch(Exception $e){
361
-
 
 
362
  //send email to site admin if email notification is not set in the scheduler
363
- if(!isset($schedule['backup_params']->email_notification) || !$schedule['backup_params']->email_notification)
364
- {
365
- $schedule['backup_params']->email_notification = get_option('admin_email');
366
  }
367
-
368
- if(isset($schedule['backup_params']->email_notification) && $to=$schedule['backup_params']->email_notification)
369
- {
370
  $from = "";
371
- $this->archive_system->send_notification($to, $from, $schedule['name']." - backup error","", "", $e->getMessage());
372
  }
373
-
374
  }
375
-
376
  }
377
-
378
- public function get_available_intervals()
379
- {
380
- $schedules = wp_get_schedules();
381
  $new_schedules = array();
382
-
383
- foreach ($schedules as $key => $row) {
384
- if(in_array($key, $this->allowed_schedules))
385
- {
386
- $new_schedules[$key] = $row;
387
- $intervals[$key] = $row['interval'];
388
  }
389
  }
390
-
391
- array_multisort($intervals, SORT_ASC, $new_schedules);
 
392
  return $new_schedules;
393
  }
394
-
395
-
396
  }
1
  <?php
2
 
3
+ class Xcloner_Scheduler {
4
+
5
  private $db;
6
  private $scheduler_table = "xcloner_scheduler";
7
+
8
  private $xcloner_remote_storage;
9
  private $archive_system;
10
  private $xcloner_database;
11
  private $xcloner_settings;
12
  private $logger;
13
  private $xcloner_file_system;
14
+
15
+ private $allowed_schedules = array( "hourly", "twicedaily", "daily", "weekly", "monthly" );
16
+
17
  /*public function __call($method, $args) {
18
  echo "$method is not defined";
19
  }*/
20
 
21
+ public function __construct( Xcloner $xcloner_container ) {
 
22
  global $wpdb;
23
+
24
+ $this->db = $wpdb;
25
+ $wpdb->show_errors = false;
26
+
27
+ $this->xcloner_container = $xcloner_container;
28
+ $this->xcloner_settings = $xcloner_container->get_xcloner_settings();
29
+
30
+ $this->scheduler_table = $this->db->prefix . $this->scheduler_table;
31
  }
32
+
33
+ private function get_xcloner_container() {
 
34
  return $this->xcloner_container;
35
  }
36
+
37
+ private function set_xcloner_container( Xcloner $container ) {
 
38
  $this->xcloner_container = $container;
39
  }
40
+
41
+ public function get_scheduler_list( $return_only_enabled = 0 ) {
42
+ $list = $this->db->get_results( "SELECT * FROM " . $this->scheduler_table );
43
+
44
+ if ( $return_only_enabled ) {
45
+ $new_list = array();
46
+
47
+ foreach ( $list as $res ) {
48
+ if ( $res->status ) {
49
+ $res->next_run_time = wp_next_scheduled( 'xcloner_scheduler_' . $res->id, array( $res->id ) ) + ( get_option( 'gmt_offset' ) * HOUR_IN_SECONDS );
50
+ $new_list[] = $res;
 
 
 
51
  }
52
+ }
53
+ $list = $new_list;
54
  }
55
+
56
  return $list;
57
  }
58
+
59
+ public function get_next_run_schedule( $xcloner_file_system = "" ) {
60
+ $list = $this->get_scheduler_list( $return_only_enabled = 1 );
 
61
 
62
  return $list;
63
  }
64
+
65
+ public function get_schedule_by_id_object( $id ) {
66
+ $data = $this->db->get_row( "SELECT * FROM " . $this->scheduler_table . " WHERE id=" . $id );
67
+
 
68
  return $data;
69
  }
70
+
71
+ public function get_schedule_by_id( $id ) {
72
+ $data = $this->db->get_row( "SELECT * FROM " . $this->scheduler_table . " WHERE id=" . $id, ARRAY_A );
73
+
74
+ if ( ! $data ) {
 
75
  return false;
76
+ }
77
+
78
+ $params = json_decode( $data['params'] );
79
+
80
  //print_r($params);
81
+ $data['params'] = "";
82
+ $data['backup_params'] = $params->backup_params;
83
+ $data['table_params'] = json_encode( $params->database );
84
+ $data['excluded_files'] = json_encode( $params->excluded_files );
85
+
86
+
87
  return $data;
88
  }
89
+
90
+ public function delete_schedule_by_id( $id ) {
91
+ $hook = 'xcloner_scheduler_' . $id;
92
+ wp_clear_scheduled_hook( $hook, array( $id ) );
93
+
94
+ $data = $this->db->delete( $this->scheduler_table, array( 'id' => $id ) );
95
+
 
96
  return $data;
97
  }
98
+
99
+ public function deactivate_wp_cron_hooks() {
 
100
  $list = $this->get_scheduler_list();
101
+
102
+ foreach ( $list as $schedule ) {
103
+ $hook = 'xcloner_scheduler_' . $schedule->id;
104
+
105
+ $timestamp = wp_next_scheduled( $hook, array( $schedule->id ) );
106
+ wp_unschedule_event( $timestamp, $hook, array( $schedule->id ) );
 
107
  }
108
  }
109
+
110
+ public function update_wp_cron_hooks() {
 
111
  $list = $this->get_scheduler_list();
112
+
113
+ foreach ( $list as $schedule ) {
114
+ $hook = 'xcloner_scheduler_' . $schedule->id;
115
+
 
116
  //adding the xcloner_scheduler hook with xcloner_scheduler_callback callback
117
+ add_action( $hook, array( $this, 'xcloner_scheduler_callback' ), 10, 1 );
118
+
119
+ if ( ! wp_next_scheduled( $hook, array( $schedule->id ) ) and $schedule->status ) {
120
+
121
+ if ( $schedule->recurrence == "single" ) {
122
+ wp_schedule_single_event( strtotime( $schedule->start_at ), $hook, array( $schedule->id ) );
123
+ } else {
124
+ wp_schedule_event( strtotime( $schedule->start_at ), $schedule->recurrence, $hook, array( $schedule->id ) );
 
125
  }
126
+
127
+ } elseif ( ! $schedule->status ) {
128
+ $timestamp = wp_next_scheduled( $hook, array( $schedule->id ) );
129
+ wp_unschedule_event( $timestamp, $hook, array( $schedule->id ) );
 
130
  }
131
  }
132
+
133
  }
134
+
135
+ public function update_cron_hook( $id ) {
136
+ $schedule = $this->get_schedule_by_id_object( $id );
137
+ $hook = 'xcloner_scheduler_' . $schedule->id;
138
+
139
+ $timestamp = wp_next_scheduled( $hook, array( $schedule->id ) );
140
+ wp_unschedule_event( $timestamp, $hook, array( $schedule->id ) );
141
+
142
+ if ( $schedule->status ) {
143
+
144
+ if ( $schedule->recurrence == "single" ) {
145
+ wp_schedule_single_event( strtotime( $schedule->start_at ), $hook, array( $schedule->id ) );
146
+ } else {
147
+ wp_schedule_event( strtotime( $schedule->start_at ), $schedule->recurrence, $hook, array( $schedule->id ) );
 
 
148
  }
149
+
150
  }
151
+ }
152
+
153
+ public function disable_single_cron( $schedule_id ) {
154
+ $hook = 'xcloner_scheduler_' . $schedule_id;
155
+ $timestamp = wp_next_scheduled( $hook, array( $schedule_id ) );
156
+ wp_unschedule_event( $timestamp, $hook, array( $schedule_id ) );
157
+
 
158
  $schedule['status'] = 0;
159
+
160
+ $update = $this->db->update(
161
+ $this->scheduler_table,
162
+ $schedule,
163
+ array( 'id' => $schedule_id ),
164
+ array(
165
+ '%s',
166
+ '%s'
167
+ )
168
+ );
169
+
170
+ return $update;
171
  }
172
+
173
+ public function update_hash( $schedule_id, $hash ) {
 
174
  $schedule['hash'] = $hash;
175
+
176
+ $update = $this->db->update(
177
+ $this->scheduler_table,
178
+ $schedule,
179
+ array( 'id' => $schedule_id ),
180
+ array(
181
+ '%s',
182
+ '%s'
183
+ )
184
+ );
185
+
186
+ return $update;
187
+ }
188
+
189
+ public function update_last_backup( $schedule_id, $last_backup ) {
190
  $schedule['last_backup'] = $last_backup;
191
+
192
+ $update = $this->db->update(
193
+ $this->scheduler_table,
194
+ $schedule,
195
+ array( 'id' => $schedule_id ),
196
+ array(
197
+ '%s',
198
+ '%s'
199
+ )
200
+ );
201
+
202
+ return $update;
203
+ }
204
+
205
+ private function _xcloner_scheduler_callback( $id, $schedule ) {
206
+ set_time_limit( 0 );
207
+
208
  $xcloner = new XCloner();
209
  $xcloner->init();
210
+ $this->set_xcloner_container( $xcloner );
211
+
212
  #$hash = $this->xcloner_settings->get_hash();
213
  #$this->get_xcloner_container()->get_xcloner_settings()->set_hash($hash);
214
+
215
  //$this->xcloner_settings = $this->get_xcloner_container()->get_xcloner_settings();
216
+ $this->xcloner_file_system = $this->get_xcloner_container()->get_xcloner_filesystem();
217
+ $this->xcloner_database = $this->get_xcloner_container()->get_xcloner_database();
218
+ $this->archive_system = $this->get_xcloner_container()->get_archive_system();
219
+ $this->logger = $this->get_xcloner_container()->get_xcloner_logger()->withName( "xcloner_scheduler" );
220
+ $this->xcloner_remote_storage = $this->get_xcloner_container()->get_xcloner_remote_storage();
221
+
222
+ $this->logger->info( sprintf( "New schedule hash is %s", $this->xcloner_settings->get_hash() ) );
223
+
224
+ if ( isset( $schedule['backup_params']->diff_start_date ) && $schedule['backup_params']->diff_start_date ) {
225
+ $this->xcloner_file_system->set_diff_timestamp_start( $schedule['backup_params']->diff_start_date );
 
226
  }
227
+
228
+ if ( $schedule['recurrence'] == "single" ) {
229
+ $this->disable_single_cron( $schedule['id'] );
 
230
  }
231
+
232
+ if ( ! $schedule ) {
233
+ $this->logger->info( sprintf( "Could not load schedule with id'%s'", $id ), array( "CRON" ) );
234
+
235
  return;
236
  }
237
+
238
  //echo $this->get_xcloner_container()->get_xcloner_settings()->get_hash(); exit;
239
+
240
+ $this->update_hash( $schedule['id'], $this->xcloner_settings->get_hash() );
241
+
242
+ $this->logger->info( sprintf( "Starting cron schedule '%s'", $schedule['name'] ), array( "CRON" ) );
243
+
244
+ $this->xcloner_file_system->set_excluded_files( json_decode( $schedule['excluded_files'] ) );
245
+
246
+ $init = 1;
247
  $continue = 1;
248
 
249
+ while ( $continue ) {
250
+ $continue = $this->xcloner_file_system->start_file_recursion( $init );
251
+
 
252
  $init = 0;
253
  }
254
+
255
+ $this->logger->info( sprintf( "File scan finished" ), array( "CRON" ) );
256
+
257
+ $this->logger->info( sprintf( "Starting the database backup" ), array( "CRON" ) );
258
+
259
+ $init = 1;
260
  $return['finished'] = 0;
261
+
262
+ while ( ! $return['finished'] ) {
263
+ $return = $this->xcloner_database->start_database_recursion( (array) json_decode( $schedule['table_params'] ), $return, $init );
264
+ $init = 0;
 
265
  }
266
+
267
+ $this->logger->info( sprintf( "Database backup done" ), array( "CRON" ) );
268
+
269
+ $this->logger->info( sprintf( "Starting file archive process" ), array( "CRON" ) );
270
+
271
+ $init = 0;
272
  $return['finished'] = 0;
273
+ $return['extra'] = array();
274
+
275
+ while ( ! $return['finished'] ) {
276
+ $return = $this->archive_system->start_incremental_backup( (array) $schedule['backup_params'], $return['extra'], $init );
277
+ $init = 0;
 
278
  }
279
+ $this->logger->info( sprintf( "File archive process FINISHED." ), array( "CRON" ) );
280
+
281
  //getting the last backup archive file
282
  $return['extra']['backup_parent'] = $this->archive_system->get_archive_name_with_extension();
283
+ if ( $this->xcloner_file_system->is_part( $this->archive_system->get_archive_name_with_extension() ) ) {
284
+ $return['extra']['backup_parent'] = $this->archive_system->get_archive_name_multipart();
285
+ }
286
+
287
+ $this->update_last_backup( $schedule['id'], $return['extra']['backup_parent'] );
288
+
289
+ if ( isset( $schedule['remote_storage'] ) && $schedule['remote_storage'] && array_key_exists( $schedule['remote_storage'], $this->xcloner_remote_storage->get_available_storages() ) ) {
290
  $backup_file = $return['extra']['backup_parent'];
291
+
292
+ $this->logger->info( sprintf( "Transferring backup to remote storage %s", strtoupper( $schedule['remote_storage'] ) ), array( "CRON" ) );
293
+
294
+ if ( method_exists( $this->xcloner_remote_storage, "upload_backup_to_storage" ) ) {
295
+ call_user_func_array( array(
296
+ $this->xcloner_remote_storage,
297
+ "upload_backup_to_storage"
298
+ ), array( $backup_file, $schedule['remote_storage'] ) );
299
+ }
300
  }
301
+
302
+ if ( isset( $schedule['backup_params']->email_notification ) and $to = $schedule['backup_params']->email_notification ) {
303
+ try {
304
+ $from = "";
 
305
  $additional['lines_total'] = $return['extra']['lines_total'];
306
+ $subject = sprintf( __( "%s - new backup generated %s" ), $schedule['name'], $return['extra']['backup_parent'] );
307
+
308
+ $this->archive_system->send_notification( $to, $from, $subject, $return['extra']['backup_parent'], $schedule, "", $additional );
309
+
310
+ } catch ( Exception $e ) {
311
+ $this->logger->error( $e->getMessage() );
 
312
  }
313
  }
314
+
315
  //CHECK IF WE SHOULD DELETE BACKUP AFTER REMOTE TRANSFER IS DONE
316
+ if ( $schedule['remote_storage'] && $this->xcloner_settings->get_xcloner_option( 'xcloner_cleanup_delete_after_remote_transfer' ) ) {
317
+ $this->logger->info( sprintf( "Deleting %s from local storage matching rule xcloner_cleanup_delete_after_remote_transfer", $return['extra']['backup_parent'] ) );
318
+ $this->xcloner_file_system->delete_backup_by_name( $return['extra']['backup_parent'] );
319
+
 
320
  }
321
+
322
  $this->xcloner_file_system->remove_tmp_filesystem();
323
+
324
  $this->xcloner_file_system->backup_storage_cleanup();
325
+
326
  //DO TMP FILESYSTEM CLEANUP
327
  $this->xcloner_file_system->cleanup_tmp_directories();
328
  }
329
+
330
+ public function xcloner_scheduler_callback( $id, $schedule = "" ) {
331
+ if ( $id ) {
332
+ $schedule = $this->get_schedule_by_id( $id );
 
 
333
  }
 
 
334
 
335
+ try {
336
+
337
+ $this->_xcloner_scheduler_callback( $id, $schedule );
338
+
339
+ } catch ( Exception $e ) {
340
+
341
  //send email to site admin if email notification is not set in the scheduler
342
+ if ( ! isset( $schedule['backup_params']->email_notification ) || ! $schedule['backup_params']->email_notification ) {
343
+ $schedule['backup_params']->email_notification = get_option( 'admin_email' );
 
344
  }
345
+
346
+ if ( isset( $schedule['backup_params']->email_notification ) && $to = $schedule['backup_params']->email_notification ) {
 
347
  $from = "";
348
+ $this->archive_system->send_notification( $to, $from, $schedule['name'] . " - backup error", "", "", $e->getMessage() );
349
  }
350
+
351
  }
352
+
353
  }
354
+
355
+ public function get_available_intervals() {
356
+ $schedules = wp_get_schedules();
 
357
  $new_schedules = array();
358
+
359
+ foreach ( $schedules as $key => $row ) {
360
+ if ( in_array( $key, $this->allowed_schedules ) ) {
361
+ $new_schedules[ $key ] = $row;
362
+ $intervals[ $key ] = $row['interval'];
 
363
  }
364
  }
365
+
366
+ array_multisort( $intervals, SORT_ASC, $new_schedules );
367
+
368
  return $new_schedules;
369
  }
370
+
371
+
372
  }
includes/class-xcloner-settings.php CHANGED
@@ -1,489 +1,530 @@
1
  <?php
2
 
3
- class Xcloner_Settings
4
- {
5
  private $logger_file = "xcloner_main_%s.log";
6
  private $logger_file_hash = "xcloner%s.log";
7
- private $hash ;
8
  private $xcloner_sanitization;
9
  private $xcloner_container;
10
-
11
- public function __construct(Xcloner $xcloner_container, $hash = "")
12
- {
13
  $this->xcloner_container = $xcloner_container;
14
- if(isset($hash))
15
- $this->set_hash($hash);
 
16
  }
17
-
18
- private function get_xcloner_container()
19
- {
20
  return $this->xcloner_container;
21
  }
22
-
23
- public function get_logger_filename($include_hash = 0)
24
- {
25
- if($include_hash)
26
- $filename = sprintf($this->logger_file_hash, $this->get_hash());
27
- else
28
- $filename = sprintf($this->logger_file, $this->get_server_unique_hash(5));
29
-
30
  return $filename;
31
  }
32
-
33
- public function get_xcloner_start_path()
34
- {
35
- if(!get_option('xcloner_start_path') or !is_dir(get_option('xcloner_start_path')))
36
- $path = realpath(ABSPATH);
37
- else
38
- $path = get_option('xcloner_start_path');
39
-
40
  return $path;
41
  }
42
-
43
- public function get_xcloner_dir_path($dir)
44
- {
45
- $path = self::get_xcloner_start_path().DS.$dir;
46
-
47
  return $path;
48
  }
49
-
50
- public function get_xcloner_store_path()
51
- {
52
- if(!get_option('xcloner_store_path') or !is_dir(get_option('xcloner_store_path')))
53
- $path = realpath(XCLONER_STORAGE_PATH);
54
- else
55
- $path = get_option('xcloner_store_path');
56
-
57
  return $path;
58
  }
59
-
60
- public function get_xcloner_tmp_path_suffix()
61
- {
62
- return "xcloner".$this->get_hash();
63
  }
64
-
65
-
66
- public function get_xcloner_tmp_path($suffix = true)
67
- {
68
- if(get_option('xcloner_force_tmp_path_site_root'))
69
- {
70
  $path = $this->get_xcloner_store_path();
71
- }else{
72
-
73
  $path = sys_get_temp_dir();
74
- if(!is_dir($path))
75
- {
76
- @mkdir($path);
77
- @chmod($path, 0777);
78
  }
79
-
80
- if(!is_dir($path) or !is_writeable($path))
81
- {
82
  $path = $this->get_xcloner_store_path();
83
  }
84
  }
85
-
86
- if($suffix)
87
- {
88
- $path = $path.DS.".".$this->get_xcloner_tmp_path_suffix();
89
  }
90
-
91
  return $path;
92
  }
93
-
94
- public function get_enable_mysql_backup()
95
- {
96
- if(get_option('xcloner_enable_mysql_backup'))
97
  return true;
98
-
99
- return false;
 
100
  }
101
-
102
- public function get_backup_extension_name($ext = "")
103
- {
104
- if(!$ext)
105
- {
106
- if(get_option('xcloner_backup_compression_level'))
107
  $ext = ".tgz";
108
- else
109
  $ext = ".tar";
110
- }
111
- return ($this->get_hash()).$ext;
 
 
112
  }
113
-
114
- public function get_hash()
115
- {
116
- if(!$this->hash){
117
- $this->set_hash("-".$this->get_server_unique_hash(5));
118
  }
119
-
120
  //echo $this->hash;
121
  return $this->hash;
122
  }
123
-
124
- public function generate_new_hash()
125
- {
126
- $hash = "-".md5(rand());
127
-
128
- $this->set_hash(substr( $hash, 0, 6));
129
-
130
  return $hash;
131
  }
132
-
133
- public function set_hash($hash = "")
134
- {
135
- if(substr($hash, 0, 1) != "-" and strlen($hash))
136
- $hash = "-".$hash;
137
-
138
- $this->hash = substr( $hash, 0, 6);
139
-
140
  return $this;
141
  }
142
-
143
- public function get_default_backup_name()
144
- {
145
- $data = parse_url(get_site_url());
146
-
147
- $backup_name = "backup_[domain]".(isset($data['port'])?"_".$data['port']:"")."-[time]-".($this->get_enable_mysql_backup()?"sql":"nosql");
148
-
149
  return $backup_name;
150
  }
151
-
152
- public function get_db_hostname()
153
- {
154
  global $wpdb;
155
-
156
- if(!$data = get_option('xcloner_mysql_hostname'))
157
  $data = $wpdb->dbhost;
158
-
 
159
  return $data;
160
  }
161
-
162
- public function get_db_username()
163
- {
164
  global $wpdb;
165
-
166
- if(!$data = get_option('xcloner_mysql_username'))
167
  $data = $wpdb->dbuser;
168
-
 
169
  return $data;
170
  }
171
-
172
- public function get_db_password()
173
- {
174
  global $wpdb;
175
-
176
- if(!$data = get_option('xcloner_mysql_password'))
177
  $data = $wpdb->dbpassword;
178
-
 
179
  return $data;
180
  }
181
-
182
- public function get_db_database()
183
- {
184
  global $wpdb;
185
-
186
- if(!$data = get_option('xcloner_mysql_database'))
187
  $data = $wpdb->dbname;
188
-
 
189
  return $data;
190
  }
191
-
192
- public function get_table_prefix()
193
- {
194
  global $wpdb;
195
-
196
  return $wpdb->prefix;
197
  }
198
-
199
- public function get_xcloner_option($option)
200
- {
201
- $data = get_option($option);
202
-
203
  return $data;
204
  }
205
-
206
- public function get_server_unique_hash($strlen = 0)
207
- {
208
- $hash = md5(get_home_url().__DIR__);
209
-
210
- if($strlen)
211
- $hash = substr($hash, 0, $strlen);
212
-
213
  return $hash;
214
  }
215
-
216
- public function settings_init()
217
- {
218
- global $wpdb;
219
- $this->xcloner_sanitization = $this->get_xcloner_container()->get_xcloner_sanitization();
220
-
221
- //ADDING MISSING OPTIONS
222
- if( false == get_option( 'xcloner_mysql_settings_page' ) ) {
223
  add_option( 'xcloner_mysql_settings_page' );
224
  } // end if
225
-
226
- if( false == get_option( 'xcloner_cron_settings_page' ) ) {
227
  add_option( 'xcloner_cron_settings_page' );
228
  } // end if
229
-
230
- if( false == get_option( 'xcloner_system_settings_page' ) ) {
231
  add_option( 'xcloner_system_settings_page' );
232
  } // end if
233
-
234
- if( false == get_option( 'xcloner_cleanup_settings_page' ) ) {
235
  add_option( 'xcloner_cleanup_settings_page' );
236
  } // end if
237
-
238
-
239
- //ADDING SETTING SECTIONS
240
- //GENERAL section
241
- add_settings_section(
242
- 'xcloner_general_settings_group',
243
- __(' '),
244
- array($this, 'xcloner_settings_section_cb'),
245
- 'xcloner_settings_page'
246
- );
247
- //MYSQL section
248
- add_settings_section(
249
- 'xcloner_mysql_settings_group',
250
- __(' '),
251
- array($this, 'xcloner_settings_section_cb'),
252
- 'xcloner_mysql_settings_page'
253
- );
254
-
255
- //SYSTEM section
256
- add_settings_section(
257
- 'xcloner_system_settings_group',
258
- __('These are advanced options recommended for developers!','xcloner-backup-and-restore'),
259
- array($this, 'xcloner_settings_section_cb'),
260
- 'xcloner_system_settings_page'
261
- );
262
-
263
- //CLEANUP section
264
- add_settings_section(
265
- 'xcloner_cleanup_settings_group',
266
- __(' '),
267
- array($this, 'xcloner_settings_section_cb'),
268
- 'xcloner_cleanup_settings_page'
269
- );
270
-
271
-
272
  //CRON section
273
- add_settings_section(
274
- 'xcloner_cron_settings_group',
275
- __(' '),
276
- array($this, 'xcloner_settings_section_cb'),
277
- 'xcloner_cron_settings_page'
278
- );
279
-
280
-
281
-
282
  //REGISTERING THE 'GENERAL SECTION' FIELDS
283
- register_setting('xcloner_general_settings_group', 'xcloner_backup_compression_level', array($this->xcloner_sanitization, "sanitize_input_as_int"));
284
- add_settings_field(
285
- 'xcloner_backup_compression_level',
286
- __('Backup Compression Level','xcloner-backup-and-restore'),
287
- array($this, 'do_form_range_field'),
288
- 'xcloner_settings_page',
289
- 'xcloner_general_settings_group',
290
- array('xcloner_backup_compression_level',
291
- __('Options between [0-9]. Value 0 means no compression, while 9 is maximum compression affecting cpu load','xcloner-backup-and-restore'),
292
- 0,
293
- 9
294
- )
295
- );
296
-
297
- register_setting('xcloner_general_settings_group', 'xcloner_start_path', array($this->xcloner_sanitization, "sanitize_input_as_absolute_path"));
298
- add_settings_field(
299
- 'xcloner_start_path',
300
- __('Backup Start Location','xcloner-backup-and-restore'),
301
- array($this, 'do_form_text_field'),
302
- 'xcloner_settings_page',
303
- 'xcloner_general_settings_group',
304
- array('xcloner_start_path',
305
- __('Base path location from where XCloner can start the Backup.','xcloner-backup-and-restore'),
 
 
 
 
 
 
 
 
306
  $this->get_xcloner_start_path(),
307
  //'disabled'
308
- )
309
- );
310
-
311
- register_setting('xcloner_general_settings_group', 'xcloner_store_path', array($this->xcloner_sanitization, "sanitize_input_as_absolute_path"));
312
- add_settings_field(
313
- 'xcloner_store_path',
314
- __('Backup Storage Location','xcloner-backup-and-restore'),
315
- array($this, 'do_form_text_field'),
316
- 'xcloner_settings_page',
317
- 'xcloner_general_settings_group',
318
- array('xcloner_store_path',
319
- __('Location where XCloner will store the Backup archives.','xcloner-backup-and-restore'),
320
- $this->get_xcloner_store_path(),
 
 
 
 
321
  //'disabled'
322
- )
323
- );
324
-
325
- register_setting('xcloner_general_settings_group', 'xcloner_enable_log', array($this->xcloner_sanitization, "sanitize_input_as_int"));
326
- add_settings_field(
327
- 'xcloner_enable_log',
328
- __('Enable XCloner Backup Log','xcloner-backup-and-restore'),
329
- array($this, 'do_form_switch_field'),
330
- 'xcloner_settings_page',
331
- 'xcloner_general_settings_group',
332
- array('xcloner_enable_log',
333
- sprintf(__('Enable the XCloner Backup log. You will find it stored unde the Backup Storage Location, file %s','xcloner-backup-and-restore'), $this->get_logger_filename())
334
- )
335
- );
336
-
337
- register_setting('xcloner_general_settings_group', 'xcloner_enable_pre_update_backup', array($this->xcloner_sanitization, "sanitize_input_as_int"));
338
- add_settings_field(
339
- 'xcloner_enable_pre_update_backup',
340
- __('Generate Backups before Automatic WP Upgrades','xcloner-backup-and-restore'),
341
- array($this, 'do_form_switch_field'),
342
- 'xcloner_settings_page',
343
- 'xcloner_general_settings_group',
344
- array('xcloner_enable_pre_update_backup',
345
- sprintf(__('Attempt to generate a core, plugins, themes or languages files backup before the automatic update of Wordpress core, plugins, themes or languages files.','xcloner-backup-and-restore'), $this->get_logger_filename())
346
- )
347
- );
348
-
349
- register_setting('xcloner_general_settings_group', 'xcloner_regex_exclude', array($this->xcloner_sanitization, "sanitize_input_as_raw"));
350
- add_settings_field(
351
- 'xcloner_regex_exclude',
352
- __('Regex Exclude Files','xcloner-backup-and-restore'),
353
- array($this, 'do_form_textarea_field'),
354
- 'xcloner_settings_page',
355
- 'xcloner_general_settings_group',
356
- array('xcloner_regex_exclude',
357
- __('Regular expression match to exclude files and folders, example patterns provided below, one pattern per line','xcloner-backup-and-restore'),
 
 
 
 
 
 
 
 
 
 
 
 
358
  //$this->get_xcloner_store_path(),
359
  //'disabled'
360
- )
361
- );
362
-
363
  //REGISTERING THE 'MYSQL SECTION' FIELDS
364
- register_setting('xcloner_mysql_settings_group', 'xcloner_enable_mysql_backup', array($this->xcloner_sanitization, "sanitize_input_as_int"));
365
- add_settings_field(
366
- 'xcloner_enable_mysql_backup',
367
- __('Enable Mysql Backup','xcloner-backup-and-restore'),
368
- array($this, 'do_form_switch_field'),
369
- 'xcloner_mysql_settings_page',
370
- 'xcloner_mysql_settings_group',
371
- array('xcloner_enable_mysql_backup',
372
- __('Enable Mysql Backup Option. If you don\'t want to backup the database, you can disable this.','xcloner-backup-and-restore')
373
- )
374
- );
375
-
376
- register_setting('xcloner_mysql_settings_group', 'xcloner_backup_only_wp_tables');
377
- add_settings_field(
378
- 'xcloner_backup_only_wp_tables',
379
- __('Backup only WP tables','xcloner-backup-and-restore'),
380
- array($this, 'do_form_switch_field'),
381
- 'xcloner_mysql_settings_page',
382
- 'xcloner_mysql_settings_group',
383
- array('xcloner_backup_only_wp_tables',
384
- sprintf(__('Enable this if you only want to Backup only tables starting with \'%s\' prefix','xcloner-backup-and-restore'), $this->get_table_prefix())
385
- )
386
- );
387
-
388
- register_setting('xcloner_mysql_settings_group', 'xcloner_mysql_hostname', array($this->xcloner_sanitization, "sanitize_input_as_raw"));
389
- add_settings_field(
390
- 'xcloner_mysql_hostname',
391
- __('Mysql Hostname','xcloner-backup-and-restore'),
392
- array($this, 'do_form_text_field'),
393
- 'xcloner_mysql_settings_page',
394
- 'xcloner_mysql_settings_group',
395
- array('xcloner_mysql_hostname',
396
- __('Wordpress mysql hostname','xcloner-backup-and-restore'),
 
 
 
 
 
 
 
 
 
397
  $this->get_db_hostname(),
398
  'disabled'
399
- )
400
- );
401
 
402
- register_setting('xcloner_mysql_settings_group', 'xcloner_mysql_username', array($this->xcloner_sanitization, "sanitize_input_as_raw"));
403
- add_settings_field(
404
- 'xcloner_mysql_username',
405
- __('Mysql Username','xcloner-backup-and-restore'),
406
- array($this, 'do_form_text_field'),
407
- 'xcloner_mysql_settings_page',
408
- 'xcloner_mysql_settings_group',
409
- array('xcloner_mysql_username',
410
- __('Wordpress mysql username','xcloner-backup-and-restore'),
 
 
 
 
411
  $this->get_db_username(),
412
  'disabled'
413
- )
414
- );
415
-
416
- register_setting('xcloner_mysql_settings_group', 'xcloner_mysql_database', array($this->xcloner_sanitization, "sanitize_input_as_raw"));
417
- add_settings_field(
418
- 'xcloner_mysql_database',
419
- __('Mysql Database','xcloner-backup-and-restore'),
420
- array($this, 'do_form_text_field'),
421
- 'xcloner_mysql_settings_page',
422
- 'xcloner_mysql_settings_group',
423
- array('xcloner_mysql_database',
424
- __('Wordpress mysql database','xcloner-backup-and-restore'),
 
 
 
 
425
  $this->get_db_database(),
426
  'disabled'
427
- )
428
- );
429
-
430
- //REGISTERING THE 'SYSTEM SECTION' FIELDS
431
- register_setting('xcloner_system_settings_group', 'xcloner_size_limit_per_request', array($this->xcloner_sanitization, "sanitize_input_as_int"));
432
- add_settings_field(
433
- 'xcloner_size_limit_per_request',
434
- __('Data Size Limit Per Request','xcloner-backup-and-restore'),
435
- array($this, 'do_form_range_field'),
436
- 'xcloner_system_settings_page',
437
- 'xcloner_system_settings_group',
438
- array('xcloner_size_limit_per_request',
439
- __('Use this option to set how much file data can XCloner backup in one AJAX request. Range 0-1024 MB','xcloner-backup-and-restore'),
440
- 0,
441
- 1024
442
- )
443
- );
444
-
445
- register_setting('xcloner_system_settings_group', 'xcloner_files_to_process_per_request', array($this->xcloner_sanitization, "sanitize_input_as_int"));
446
- add_settings_field(
447
- 'xcloner_files_to_process_per_request',
448
- __('Files To Process Per Request','xcloner-backup-and-restore'),
449
- array($this, 'do_form_range_field'),
450
- 'xcloner_system_settings_page',
451
- 'xcloner_system_settings_group',
452
- array('xcloner_files_to_process_per_request',
453
- __('Use this option to set how many files XCloner should process at one time before doing another AJAX call','xcloner-backup-and-restore'),
454
- 0,
455
- 1000
456
- )
457
- );
458
-
459
- register_setting('xcloner_system_settings_group', 'xcloner_directories_to_scan_per_request', array($this->xcloner_sanitization, "sanitize_input_as_int"));
460
- add_settings_field(
461
- 'xcloner_directories_to_scan_per_request',
462
- __('Directories To Scan Per Request','xcloner-backup-and-restore'),
463
- array($this, 'do_form_range_field'),
464
- 'xcloner_system_settings_page',
465
- 'xcloner_system_settings_group',
466
- array('xcloner_directories_to_scan_per_request',
467
- __('Use this option to set how many directories XCloner should scan at one time before doing another AJAX call','xcloner-backup-and-restore'),
468
- 0,
469
- 1000
470
- )
471
- );
472
-
473
- register_setting('xcloner_system_settings_group', 'xcloner_database_records_per_request', array($this->xcloner_sanitization, "sanitize_input_as_int"));
474
- add_settings_field(
475
- 'xcloner_database_records_per_request',
476
- __('Database Records Per Request','xcloner-backup-and-restore'),
477
- array($this, 'do_form_range_field'),
478
- 'xcloner_system_settings_page',
479
- 'xcloner_system_settings_group',
480
- array('xcloner_database_records_per_request',
481
- __('Use this option to set how many database table records should be fetched per AJAX request, or set to 0 to fetch all. Range 0-100000 records','xcloner-backup-and-restore'),
482
- 0,
483
- 100000
484
- )
485
- );
486
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
487
  /*register_setting('xcloner_system_settings_group', 'xcloner_diff_backup_recreate_period', array($this->xcloner_sanitization, "sanitize_input_as_int"));
488
  add_settings_field(
489
  'xcloner_diff_backup_recreate_period',
@@ -495,261 +536,332 @@ class Xcloner_Settings
495
  __('Use this option to set when a full backup should be recreated if the scheduled backup type is set to \'Full Backup+Differential Backups\' ','xcloner-backup-and-restore'),
496
  )
497
  );*/
498
-
499
- register_setting('xcloner_system_settings_group', 'xcloner_exclude_files_larger_than_mb', array($this->xcloner_sanitization, "sanitize_input_as_int"));
500
- add_settings_field(
501
- 'xcloner_exclude_files_larger_than_mb',
502
- __('Exclude files larger than (MB)','xcloner-backup-and-restore'),
503
- array($this, 'do_form_number_field'),
504
- 'xcloner_system_settings_page',
505
- 'xcloner_system_settings_group',
506
- array('xcloner_exclude_files_larger_than_mb',
507
- __('Use this option to automatically exclude files larger than a certain size in MB, or set to 0 to include all. Range 0-1000 MB','xcloner-backup-and-restore'),
508
- )
509
- );
510
-
511
- register_setting('xcloner_system_settings_group', 'xcloner_split_backup_limit', array($this->xcloner_sanitization, "sanitize_input_as_int"));
512
- add_settings_field(
513
- 'xcloner_split_backup_limit',
514
- __('Split Backup Archive Limit (MB)','xcloner-backup-and-restore'),
515
- array($this, 'do_form_number_field'),
516
- 'xcloner_system_settings_page',
517
- 'xcloner_system_settings_group',
518
- array('xcloner_split_backup_limit',
519
- __('Use this option to automatically split the backup archive into smaller parts. Range 0-10000 MB','xcloner-backup-and-restore'),
520
- )
521
- );
522
-
523
- register_setting('xcloner_system_settings_group', 'xcloner_force_tmp_path_site_root');
524
- add_settings_field(
525
- 'xcloner_force_tmp_path_site_root',
526
- __('Force Temporary Path Within XCloner Storage','xcloner-backup-and-restore'),
527
- array($this, 'do_form_switch_field'),
528
- 'xcloner_system_settings_page',
529
- 'xcloner_system_settings_group',
530
- array('xcloner_force_tmp_path_site_root',
531
- sprintf(__('Enable this option if you want the XCloner Temporary Path to be within your XCloner Storage Location','xcloner-backup-and-restore'), $this->get_table_prefix())
532
- )
533
- );
534
-
 
 
 
 
 
 
 
 
 
535
  //REGISTERING THE 'CLEANUP SECTION' FIELDS
536
- register_setting('xcloner_cleanup_settings_group', 'xcloner_cleanup_retention_limit_days', array($this->xcloner_sanitization, "sanitize_input_as_int"));
537
- add_settings_field(
538
- 'xcloner_cleanup_retention_limit_days',
539
- __('Cleanup by Date(days)','xcloner-backup-and-restore'),
540
- array($this, 'do_form_number_field'),
541
- 'xcloner_cleanup_settings_page',
542
- 'xcloner_cleanup_settings_group',
543
- array('xcloner_cleanup_retention_limit_days',
544
- __('Specify the maximum number of days a backup archive can be kept on the server. 0 disables this option','xcloner-backup-and-restore')
 
 
 
 
545
  )
546
- );
547
-
548
- register_setting('xcloner_cleanup_settings_group', 'xcloner_cleanup_retention_limit_archives', array($this->xcloner_sanitization, "sanitize_input_as_int"));
549
- add_settings_field(
550
- 'xcloner_cleanup_retention_limit_archives',
551
- __('Cleanup by Quantity','xcloner-backup-and-restore'),
552
- array($this, 'do_form_number_field'),
553
- 'xcloner_cleanup_settings_page',
554
- 'xcloner_cleanup_settings_group',
555
- array('xcloner_cleanup_retention_limit_archives',
556
- __('Specify the maximum number of backup archives to keep on the server. 0 disables this option','xcloner-backup-and-restore')
 
 
 
 
557
  )
558
- );
559
-
560
- register_setting('xcloner_cleanup_settings_group', 'xcloner_cleanup_capacity_limit', array($this->xcloner_sanitization, "sanitize_input_as_int"));
561
- add_settings_field(
562
- 'xcloner_cleanup_capacity_limit',
563
- __('Cleanup by Capacity(MB)','xcloner-backup-and-restore'),
564
- array($this, 'do_form_number_field'),
565
- 'xcloner_cleanup_settings_page',
566
- 'xcloner_cleanup_settings_group',
567
- array('xcloner_cleanup_capacity_limit',
568
- __('Remove oldest backups if all created backups exceed the configured limit in Megabytes. 0 disables this option','xcloner-backup-and-restore')
 
 
 
 
569
  )
570
- );
571
-
572
- register_setting('xcloner_cleanup_settings_group', 'xcloner_cleanup_delete_after_remote_transfer', array($this->xcloner_sanitization, "sanitize_input_as_int"));
573
- add_settings_field(
574
- 'xcloner_cleanup_delete_after_remote_transfer',
575
- __('Delete Backup After Remote Storage Transfer','xcloner-backup-and-restore'),
576
- array($this, 'do_form_switch_field'),
577
- 'xcloner_cleanup_settings_page',
578
- 'xcloner_cleanup_settings_group',
579
- array('xcloner_cleanup_delete_after_remote_transfer',
580
- __('Remove backup created automatically from local storage after sending the backup to Remote Storage','xcloner-backup-and-restore')
 
 
 
 
581
  )
582
- );
583
-
584
  //REGISTERING THE 'CRON SECTION' FIELDS
585
- register_setting('xcloner_cron_settings_group', 'xcloner_cron_frequency');
586
- add_settings_field(
587
- 'xcloner_cron_frequency',
588
- __('Cron frequency','xcloner-backup-and-restore'),
589
- array($this, 'do_form_text_field'),
590
- 'xcloner_cron_settings_page',
591
- 'xcloner_cron_settings_group',
592
- array('xcloner_cron_frequency',
593
- __('Cron frequency')
 
594
  )
595
- );
596
  }
597
-
598
-
599
-
600
-
601
  /**
602
  * callback functions
603
  */
604
-
605
  // section content cb
606
- public function xcloner_settings_section_cb()
607
- {
608
- //echo '<p>WPOrg Section Introduction.</p>';
609
  }
610
-
611
  // text field content cb
612
- public function do_form_text_field($params)
613
- {
614
- if(!isset($params['3']))
615
  $params[3] = 0;
616
- if(!isset($params['2']))
617
- $params[2] = 0;
618
-
619
- list($fieldname, $label, $value, $disabled) = $params;
620
-
621
- if(!$value)
622
- $value = get_option($fieldname);
623
- // output the field
624
- ?>
625
- <div class="row">
626
- <div class="input-field col s10 m10 l8">
627
- <input class="validate" <?php echo ($disabled)?"disabled":""?> name="<?php echo $fieldname?>" id="<?php echo $fieldname?>" type="text" class="validate" value="<?php echo isset($value) ? esc_attr($value) : ''; ?>">
628
- </div>
629
- <div class="col s2 m2 ">
630
- <a class="btn-floating tooltipped btn-small" data-position="left" data-delay="50" data-tooltip="<?php echo $label?>" data-tooltip-id=""><i class="material-icons">help_outline</i></a>
631
- </div>
632
- </div>
633
-
634
-
635
- <?php
 
 
 
 
 
 
636
  }
637
-
638
  // textarea field content cb
639
- public function do_form_textarea_field($params)
640
- {
641
- if(!isset($params['3']))
642
  $params[3] = 0;
643
- if(!isset($params['2']))
644
- $params[2] = 0;
645
-
646
- list($fieldname, $label, $value, $disabled) = $params;
647
-
648
- if(!$value)
649
- $value = get_option($fieldname);
650
- // output the field
651
- ?>
652
- <div class="row">
653
- <div class="input-field col s10 m10 l8">
654
- <textarea class="validate" <?php echo ($disabled)?"disabled":""?> name="<?php echo $fieldname?>" id="<?php echo $fieldname?>" type="text" class="validate" value=""><?php echo isset($value) ? esc_attr($value) : ''; ?></textarea>
655
- </div>
656
- <div class="col s2 m2 ">
657
- <a class="btn-floating tooltipped btn-small" data-position="center" data-html="true" data-delay="50" data-tooltip="<?php echo $label?>" data-tooltip-id=""><i class="material-icons">help_outline</i></a>
658
- </div>
659
- <div class="col s12">
660
- <ul class="xcloner_regex_exclude_limit">
661
- <li>Exclude all except .php file: <span class="regex_pattern"><?php echo htmlentities('(.*)\.(.+)$(?<!(php))')?></span></li>
662
- <li>Exclude all except .php and .txt: <span class="regex_pattern"> <?php echo htmlentities('(.*)\.(.+)$(?<!(php|txt))')?></span></li>
663
- <li>Exclude all .avi files: <span class="regex_pattern"> <?php echo htmlentities('(.*)\.(.+)$(?<=(avi))')?></span></li>
664
- <li>Exclude all .jpg,.gif and .png files: <span class="regex_pattern"> <?php echo htmlentities('(.*)\.(.+)$(?<=(gif|png|jpg))')?></span></li>
665
- <li>Exclude all .svn and .git: <span class="regex_pattern"> <?php echo htmlentities('(.*)\.(svn|git)(.*)$')?></span></li>
666
- <li>Exclude root directory /test: <span class="regex_pattern"> <?php echo htmlentities('\/test(.*)$')?></span> or <span class="regex_pattern"> <?php echo htmlentities('test(.*)$')?></span></li>
667
- <li>Exclude the wp-admin folder: <span class="regex_pattern"> <?php echo htmlentities('(\/wp-admin)(.*)$')?></span></li>
668
- <li>Exclude the wp-content/uploads folder: <span class="regex_pattern"> <?php echo htmlentities('(\/wp-content\/uploads)(.*)$')?></span></li>
669
- <li>Exclude the wp-admin, wp-includes and wp-config.php: <span class="regex_pattern"> <?php echo htmlentities('\/(wp-admin|wp-includes|wp-config.php)(.*)$')?></span></li>
670
- <li>Exclude wp-content/updraft and wp/content/uploads/wp_all_backup folder :<span class="regex_pattern">\/(wp-content\/updraft|\/wp-content\/uploads\/wp_all_backup)(.*)$</span></li>
671
- <li>Exclude all cache folders from wp-content/ and it's subdirectories: <span class="regex_pattern"> <?php echo htmlentities('\/wp-content(.*)\/cache($|\/)(.*)')?></span></li>
672
- <li>Exclude wp-content/cache/ folder: <span class="regex_pattern"> <?php echo htmlentities('\/wp-content\/cache(.*)')?></span></li>
673
- <li>Exclude all error_log files: <span class="regex_pattern"> <?php echo htmlentities('(.*)error_log$')?></span></li>
674
- </ul>
675
- </div>
676
- </div>
677
-
678
-
679
- <?php
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
680
  }
681
-
682
  // number field content cb
683
- public function do_form_number_field($params)
684
- {
685
- if(!isset($params['3']))
686
  $params[3] = 0;
687
- if(!isset($params['2']))
688
- $params[2] = 0;
689
-
690
- list($fieldname, $label, $value, $disabled) = $params;
691
-
692
- if(!$value)
693
- $value = get_option($fieldname);
694
- // output the field
695
- ?>
696
- <div class="row">
697
- <div class="input-field col s10 m5 l3">
698
- <input class="validate" <?php echo ($disabled)?"disabled":""?> name="<?php echo $fieldname?>" id="<?php echo $fieldname?>" type="number" class="validate" value="<?php echo isset($value) ? esc_attr($value) : ''; ?>">
699
- </div>
700
- <div class="col s2 m2 ">
701
- <a class="btn-floating tooltipped btn-small" data-html="true" data-position="center" data-delay="50" data-tooltip="<?php echo $label?>" data-tooltip-id=""><i class="material-icons">help_outline</i></a>
702
- </div>
703
- </div>
704
-
705
-
706
- <?php
 
 
 
 
 
 
707
  }
708
-
709
- public function do_form_range_field($params)
710
- {
711
- if(!isset($params['4']))
712
  $params[4] = 0;
713
-
714
- list($fieldname, $label, $range_start, $range_end, $disabled) = $params;
715
- $value = get_option($fieldname);
716
- ?>
717
- <div class="row">
718
- <div class="input-field col s10 m10 l8">
719
- <p class="range-field">
720
- <input <?php echo ($disabled)?"disabled":""?> type="range" name="<?php echo $fieldname?>" id="<?php echo $fieldname?>" min="<?php echo $range_start?>" max="<?php echo $range_end?>" value="<?php echo isset($value) ? esc_attr($value) : ''; ?>" />
721
- </p>
722
- </div>
723
- <div class="col s2 m2 ">
724
- <a class="btn-floating tooltipped btn-small" data-html="true" data-position="center" data-delay="50" data-tooltip="<?php echo $label?>" data-tooltip-id=""><i class="material-icons">help_outline</i></a>
725
- </div>
726
- </div>
727
- <?php
 
 
 
 
 
 
728
  }
729
-
730
-
731
- public function do_form_switch_field($params)
732
- {
733
- if(!isset($params['2']))
734
  $params[2] = 0;
735
- list($fieldname, $label, $disabled) = $params;
736
- $value = get_option($fieldname);
737
- ?>
738
- <div class="row">
739
- <div class="input-field col s10 m5 l3">
740
- <div class="switch">
741
- <label>
742
- Off
743
- <input <?php echo ($disabled)?"disabled":""?> type="checkbox" name="<?php echo $fieldname?>" id="<?php echo $fieldname?>" value="1" <?php echo ($value) ? 'checked="checked"' : ''; ?>">
744
- <span class="lever"></span>
745
- On
746
- </label>
747
- </div>
748
- </div>
749
- <div class="col s2 m2">
750
- <a class="btn-floating tooltipped btn-small" data-position="center" data-delay="50" data-tooltip="<?php echo $label?>" data-tooltip-id=""><i class="material-icons">help_outline</i></a>
751
- </div>
752
- </div>
753
- <?php
 
 
 
 
 
 
754
  }
755
  }
1
  <?php
2
 
3
+ class Xcloner_Settings {
 
4
  private $logger_file = "xcloner_main_%s.log";
5
  private $logger_file_hash = "xcloner%s.log";
6
+ private $hash;
7
  private $xcloner_sanitization;
8
  private $xcloner_container;
9
+
10
+ public function __construct( Xcloner $xcloner_container, $hash = "" ) {
 
11
  $this->xcloner_container = $xcloner_container;
12
+ if ( isset( $hash ) ) {
13
+ $this->set_hash( $hash );
14
+ }
15
  }
16
+
17
+ private function get_xcloner_container() {
 
18
  return $this->xcloner_container;
19
  }
20
+
21
+ public function get_logger_filename( $include_hash = 0 ) {
22
+ if ( $include_hash ) {
23
+ $filename = sprintf( $this->logger_file_hash, $this->get_hash() );
24
+ } else {
25
+ $filename = sprintf( $this->logger_file, $this->get_server_unique_hash( 5 ) );
26
+ }
27
+
28
  return $filename;
29
  }
30
+
31
+ public function get_xcloner_start_path() {
32
+ if ( ! get_option( 'xcloner_start_path' ) or ! is_dir( get_option( 'xcloner_start_path' ) ) ) {
33
+ $path = realpath( ABSPATH );
34
+ } else {
35
+ $path = get_option( 'xcloner_start_path' );
36
+ }
37
+
38
  return $path;
39
  }
40
+
41
+ public function get_xcloner_dir_path( $dir ) {
42
+ $path = self::get_xcloner_start_path() . DS . $dir;
43
+
 
44
  return $path;
45
  }
46
+
47
+ public function get_xcloner_store_path() {
48
+ if ( ! get_option( 'xcloner_store_path' ) or ! is_dir( get_option( 'xcloner_store_path' ) ) ) {
49
+ $path = realpath( XCLONER_STORAGE_PATH );
50
+ } else {
51
+ $path = get_option( 'xcloner_store_path' );
52
+ }
53
+
54
  return $path;
55
  }
56
+
57
+ public function get_xcloner_tmp_path_suffix() {
58
+ return "xcloner" . $this->get_hash();
 
59
  }
60
+
61
+
62
+ public function get_xcloner_tmp_path( $suffix = true ) {
63
+ if ( get_option( 'xcloner_force_tmp_path_site_root' ) ) {
 
 
64
  $path = $this->get_xcloner_store_path();
65
+ } else {
66
+
67
  $path = sys_get_temp_dir();
68
+ if ( ! is_dir( $path ) ) {
69
+ @mkdir( $path );
70
+ @chmod( $path, 0777 );
 
71
  }
72
+
73
+ if ( ! is_dir( $path ) or ! is_writeable( $path ) ) {
 
74
  $path = $this->get_xcloner_store_path();
75
  }
76
  }
77
+
78
+ if ( $suffix ) {
79
+ $path = $path . DS . "." . $this->get_xcloner_tmp_path_suffix();
 
80
  }
81
+
82
  return $path;
83
  }
84
+
85
+ public function get_enable_mysql_backup() {
86
+ if ( get_option( 'xcloner_enable_mysql_backup' ) ) {
 
87
  return true;
88
+ }
89
+
90
+ return false;
91
  }
92
+
93
+ public function get_backup_extension_name( $ext = "" ) {
94
+ if ( ! $ext ) {
95
+ if ( get_option( 'xcloner_backup_compression_level' ) ) {
 
 
96
  $ext = ".tgz";
97
+ } else {
98
  $ext = ".tar";
99
+ }
100
+ }
101
+
102
+ return ( $this->get_hash() ) . $ext;
103
  }
104
+
105
+ public function get_hash() {
106
+ if ( ! $this->hash ) {
107
+ $this->set_hash( "-" . $this->get_server_unique_hash( 5 ) );
 
108
  }
109
+
110
  //echo $this->hash;
111
  return $this->hash;
112
  }
113
+
114
+ public function generate_new_hash() {
115
+ $hash = "-" . md5( rand() );
116
+
117
+ $this->set_hash( substr( $hash, 0, 6 ) );
118
+
 
119
  return $hash;
120
  }
121
+
122
+ public function set_hash( $hash = "" ) {
123
+ if ( substr( $hash, 0, 1 ) != "-" and strlen( $hash ) ) {
124
+ $hash = "-" . $hash;
125
+ }
126
+
127
+ $this->hash = substr( $hash, 0, 6 );
128
+
129
  return $this;
130
  }
131
+
132
+ public function get_default_backup_name() {
133
+ $data = parse_url( get_site_url() );
134
+
135
+ $backup_name = "backup_[domain]" . ( isset( $data['port'] ) ? "_" . $data['port'] : "" ) . "-[time]-" . ( $this->get_enable_mysql_backup() ? "sql" : "nosql" );
136
+
 
137
  return $backup_name;
138
  }
139
+
140
+ public function get_db_hostname() {
 
141
  global $wpdb;
142
+
143
+ if ( ! $data = get_option( 'xcloner_mysql_hostname' ) ) {
144
  $data = $wpdb->dbhost;
145
+ }
146
+
147
  return $data;
148
  }
149
+
150
+ public function get_db_username() {
 
151
  global $wpdb;
152
+
153
+ if ( ! $data = get_option( 'xcloner_mysql_username' ) ) {
154
  $data = $wpdb->dbuser;
155
+ }
156
+
157
  return $data;
158
  }
159
+
160
+ public function get_db_password() {
 
161
  global $wpdb;
162
+
163
+ if ( ! $data = get_option( 'xcloner_mysql_password' ) ) {
164
  $data = $wpdb->dbpassword;
165
+ }
166
+
167
  return $data;
168
  }
169
+
170
+ public function get_db_database() {
 
171
  global $wpdb;
172
+
173
+ if ( ! $data = get_option( 'xcloner_mysql_database' ) ) {
174
  $data = $wpdb->dbname;
175
+ }
176
+
177
  return $data;
178
  }
179
+
180
+ public function get_table_prefix() {
 
181
  global $wpdb;
182
+
183
  return $wpdb->prefix;
184
  }
185
+
186
+ public function get_xcloner_option( $option ) {
187
+ $data = get_option( $option );
188
+
 
189
  return $data;
190
  }
191
+
192
+ public function get_server_unique_hash( $strlen = 0 ) {
193
+ $hash = md5( get_home_url() . __DIR__ );
194
+
195
+ if ( $strlen ) {
196
+ $hash = substr( $hash, 0, $strlen );
197
+ }
198
+
199
  return $hash;
200
  }
201
+
202
+ public function settings_init() {
203
+ global $wpdb;
204
+ $this->xcloner_sanitization = $this->get_xcloner_container()->get_xcloner_sanitization();
205
+
206
+ //ADDING MISSING OPTIONS
207
+ if ( false == get_option( 'xcloner_mysql_settings_page' ) ) {
 
208
  add_option( 'xcloner_mysql_settings_page' );
209
  } // end if
210
+
211
+ if ( false == get_option( 'xcloner_cron_settings_page' ) ) {
212
  add_option( 'xcloner_cron_settings_page' );
213
  } // end if
214
+
215
+ if ( false == get_option( 'xcloner_system_settings_page' ) ) {
216
  add_option( 'xcloner_system_settings_page' );
217
  } // end if
218
+
219
+ if ( false == get_option( 'xcloner_cleanup_settings_page' ) ) {
220
  add_option( 'xcloner_cleanup_settings_page' );
221
  } // end if
222
+
223
+
224
+ //ADDING SETTING SECTIONS
225
+ //GENERAL section
226
+ add_settings_section(
227
+ 'xcloner_general_settings_group',
228
+ __( ' ' ),
229
+ array( $this, 'xcloner_settings_section_cb' ),
230
+ 'xcloner_settings_page'
231
+ );
232
+ //MYSQL section
233
+ add_settings_section(
234
+ 'xcloner_mysql_settings_group',
235
+ __( ' ' ),
236
+ array( $this, 'xcloner_settings_section_cb' ),
237
+ 'xcloner_mysql_settings_page'
238
+ );
239
+
240
+ //SYSTEM section
241
+ add_settings_section(
242
+ 'xcloner_system_settings_group',
243
+ __( 'These are advanced options recommended for developers!', 'xcloner-backup-and-restore' ),
244
+ array( $this, 'xcloner_settings_section_cb' ),
245
+ 'xcloner_system_settings_page'
246
+ );
247
+
248
+ //CLEANUP section
249
+ add_settings_section(
250
+ 'xcloner_cleanup_settings_group',
251
+ __( ' ' ),
252
+ array( $this, 'xcloner_settings_section_cb' ),
253
+ 'xcloner_cleanup_settings_page'
254
+ );
255
+
256
+
257
  //CRON section
258
+ add_settings_section(
259
+ 'xcloner_cron_settings_group',
260
+ __( ' ' ),
261
+ array( $this, 'xcloner_settings_section_cb' ),
262
+ 'xcloner_cron_settings_page'
263
+ );
264
+
265
+
 
266
  //REGISTERING THE 'GENERAL SECTION' FIELDS
267
+ register_setting( 'xcloner_general_settings_group', 'xcloner_backup_compression_level', array(
268
+ $this->xcloner_sanitization,
269
+ "sanitize_input_as_int"
270
+ ) );
271
+ add_settings_field(
272
+ 'xcloner_backup_compression_level',
273
+ __( 'Backup Compression Level', 'xcloner-backup-and-restore' ),
274
+ array( $this, 'do_form_range_field' ),
275
+ 'xcloner_settings_page',
276
+ 'xcloner_general_settings_group',
277
+ array(
278
+ 'xcloner_backup_compression_level',
279
+ __( 'Options between [0-9]. Value 0 means no compression, while 9 is maximum compression affecting cpu load', 'xcloner-backup-and-restore' ),
280
+ 0,
281
+ 9
282
+ )
283
+ );
284
+
285
+ register_setting( 'xcloner_general_settings_group', 'xcloner_start_path', array(
286
+ $this->xcloner_sanitization,
287
+ "sanitize_input_as_absolute_path"
288
+ ) );
289
+ add_settings_field(
290
+ 'xcloner_start_path',
291
+ __( 'Backup Start Location', 'xcloner-backup-and-restore' ),
292
+ array( $this, 'do_form_text_field' ),
293
+ 'xcloner_settings_page',
294
+ 'xcloner_general_settings_group',
295
+ array(
296
+ 'xcloner_start_path',
297
+ __( 'Base path location from where XCloner can start the Backup.', 'xcloner-backup-and-restore' ),
298
  $this->get_xcloner_start_path(),
299
  //'disabled'
300
+ )
301
+ );
302
+
303
+ register_setting( 'xcloner_general_settings_group', 'xcloner_store_path', array(
304
+ $this->xcloner_sanitization,
305
+ "sanitize_input_as_absolute_path"
306
+ ) );
307
+ add_settings_field(
308
+ 'xcloner_store_path',
309
+ __( 'Backup Storage Location', 'xcloner-backup-and-restore' ),
310
+ array( $this, 'do_form_text_field' ),
311
+ 'xcloner_settings_page',
312
+ 'xcloner_general_settings_group',
313
+ array(
314
+ 'xcloner_store_path',
315
+ __( 'Location where XCloner will store the Backup archives.', 'xcloner-backup-and-restore' ),
316
+ $this->get_xcloner_store_path(),
317
  //'disabled'
318
+ )
319
+ );
320
+
321
+ register_setting( 'xcloner_general_settings_group', 'xcloner_enable_log', array(
322
+ $this->xcloner_sanitization,
323
+ "sanitize_input_as_int"
324
+ ) );
325
+ add_settings_field(
326
+ 'xcloner_enable_log',
327
+ __( 'Enable XCloner Backup Log', 'xcloner-backup-and-restore' ),
328
+ array( $this, 'do_form_switch_field' ),
329
+ 'xcloner_settings_page',
330
+ 'xcloner_general_settings_group',
331
+ array(
332
+ 'xcloner_enable_log',
333
+ sprintf( __( 'Enable the XCloner Backup log. You will find it stored unde the Backup Storage Location, file %s', 'xcloner-backup-and-restore' ), $this->get_logger_filename() )
334
+ )
335
+ );
336
+
337
+ register_setting( 'xcloner_general_settings_group', 'xcloner_enable_pre_update_backup', array(
338
+ $this->xcloner_sanitization,
339
+ "sanitize_input_as_int"
340
+ ) );
341
+ add_settings_field(
342
+ 'xcloner_enable_pre_update_backup',
343
+ __( 'Generate Backups before Automatic WP Upgrades', 'xcloner-backup-and-restore' ),
344
+ array( $this, 'do_form_switch_field' ),
345
+ 'xcloner_settings_page',
346
+ 'xcloner_general_settings_group',
347
+ array(
348
+ 'xcloner_enable_pre_update_backup',
349
+ sprintf( __( 'Attempt to generate a core, plugins, themes or languages files backup before the automatic update of Wordpress core, plugins, themes or languages files.', 'xcloner-backup-and-restore' ), $this->get_logger_filename() )
350
+ )
351
+ );
352
+
353
+ register_setting( 'xcloner_general_settings_group', 'xcloner_regex_exclude', array(
354
+ $this->xcloner_sanitization,
355
+ "sanitize_input_as_raw"
356
+ ) );
357
+ add_settings_field(
358
+ 'xcloner_regex_exclude',
359
+ __( 'Regex Exclude Files', 'xcloner-backup-and-restore' ),
360
+ array( $this, 'do_form_textarea_field' ),
361
+ 'xcloner_settings_page',
362
+ 'xcloner_general_settings_group',
363
+ array(
364
+ 'xcloner_regex_exclude',
365
+ __( 'Regular expression match to exclude files and folders, example patterns provided below, one pattern per line', 'xcloner-backup-and-restore' ),
366
  //$this->get_xcloner_store_path(),
367
  //'disabled'
368
+ )
369
+ );
370
+
371
  //REGISTERING THE 'MYSQL SECTION' FIELDS
372
+ register_setting( 'xcloner_mysql_settings_group', 'xcloner_enable_mysql_backup', array(
373
+ $this->xcloner_sanitization,
374
+ "sanitize_input_as_int"
375
+ ) );
376
+ add_settings_field(
377
+ 'xcloner_enable_mysql_backup',
378
+ __( 'Enable Mysql Backup', 'xcloner-backup-and-restore' ),
379
+ array( $this, 'do_form_switch_field' ),
380
+ 'xcloner_mysql_settings_page',
381
+ 'xcloner_mysql_settings_group',
382
+ array(
383
+ 'xcloner_enable_mysql_backup',
384
+ __( 'Enable Mysql Backup Option. If you don\'t want to backup the database, you can disable this.', 'xcloner-backup-and-restore' )
385
+ )
386
+ );
387
+
388
+ register_setting( 'xcloner_mysql_settings_group', 'xcloner_backup_only_wp_tables' );
389
+ add_settings_field(
390
+ 'xcloner_backup_only_wp_tables',
391
+ __( 'Backup only WP tables', 'xcloner-backup-and-restore' ),
392
+ array( $this, 'do_form_switch_field' ),
393
+ 'xcloner_mysql_settings_page',
394
+ 'xcloner_mysql_settings_group',
395
+ array(
396
+ 'xcloner_backup_only_wp_tables',
397
+ sprintf( __( 'Enable this if you only want to Backup only tables starting with \'%s\' prefix', 'xcloner-backup-and-restore' ), $this->get_table_prefix() )
398
+ )
399
+ );
400
+
401
+ register_setting( 'xcloner_mysql_settings_group', 'xcloner_mysql_hostname', array(
402
+ $this->xcloner_sanitization,
403
+ "sanitize_input_as_raw"
404
+ ) );
405
+ add_settings_field(
406
+ 'xcloner_mysql_hostname',
407
+ __( 'Mysql Hostname', 'xcloner-backup-and-restore' ),
408
+ array( $this, 'do_form_text_field' ),
409
+ 'xcloner_mysql_settings_page',
410
+ 'xcloner_mysql_settings_group',
411
+ array(
412
+ 'xcloner_mysql_hostname',
413
+ __( 'Wordpress mysql hostname', 'xcloner-backup-and-restore' ),
414
  $this->get_db_hostname(),
415
  'disabled'
416
+ )
417
+ );
418
 
419
+ register_setting( 'xcloner_mysql_settings_group', 'xcloner_mysql_username', array(
420
+ $this->xcloner_sanitization,
421
+ "sanitize_input_as_raw"
422
+ ) );
423
+ add_settings_field(
424
+ 'xcloner_mysql_username',
425
+ __( 'Mysql Username', 'xcloner-backup-and-restore' ),
426
+ array( $this, 'do_form_text_field' ),
427
+ 'xcloner_mysql_settings_page',
428
+ 'xcloner_mysql_settings_group',
429
+ array(
430
+ 'xcloner_mysql_username',
431
+ __( 'Wordpress mysql username', 'xcloner-backup-and-restore' ),
432
  $this->get_db_username(),
433
  'disabled'
434
+ )
435
+ );
436
+
437
+ register_setting( 'xcloner_mysql_settings_group', 'xcloner_mysql_database', array(
438
+ $this->xcloner_sanitization,
439
+ "sanitize_input_as_raw"
440
+ ) );
441
+ add_settings_field(
442
+ 'xcloner_mysql_database',
443
+ __( 'Mysql Database', 'xcloner-backup-and-restore' ),
444
+ array( $this, 'do_form_text_field' ),
445
+ 'xcloner_mysql_settings_page',
446
+ 'xcloner_mysql_settings_group',
447
+ array(
448
+ 'xcloner_mysql_database',
449
+ __( 'Wordpress mysql database', 'xcloner-backup-and-restore' ),
450
  $this->get_db_database(),
451
  'disabled'
452
+ )
453
+ );
454
+
455
+ //REGISTERING THE 'SYSTEM SECTION' FIELDS
456
+ register_setting( 'xcloner_system_settings_group', 'xcloner_size_limit_per_request', array(
457
+ $this->xcloner_sanitization,
458
+ "sanitize_input_as_int"
459
+ ) );
460
+ add_settings_field(
461
+ 'xcloner_size_limit_per_request',
462
+ __( 'Data Size Limit Per Request', 'xcloner-backup-and-restore' ),
463
+ array( $this, 'do_form_range_field' ),
464
+ 'xcloner_system_settings_page',
465
+ 'xcloner_system_settings_group',
466
+ array(
467
+ 'xcloner_size_limit_per_request',
468
+ __( 'Use this option to set how much file data can XCloner backup in one AJAX request. Range 0-1024 MB', 'xcloner-backup-and-restore' ),
469
+ 0,
470
+ 1024
471
+ )
472
+ );
473
+
474
+ register_setting( 'xcloner_system_settings_group', 'xcloner_files_to_process_per_request', array(
475
+ $this->xcloner_sanitization,
476
+ "sanitize_input_as_int"
477
+ ) );
478
+ add_settings_field(
479
+ 'xcloner_files_to_process_per_request',
480
+ __( 'Files To Process Per Request', 'xcloner-backup-and-restore' ),
481
+ array( $this, 'do_form_range_field' ),
482
+ 'xcloner_system_settings_page',
483
+ 'xcloner_system_settings_group',
484
+ array(
485
+ 'xcloner_files_to_process_per_request',
486
+ __( 'Use this option to set how many files XCloner should process at one time before doing another AJAX call', 'xcloner-backup-and-restore' ),
487
+ 0,
488
+ 1000
489
+ )
490
+ );
491
+
492
+ register_setting( 'xcloner_system_settings_group', 'xcloner_directories_to_scan_per_request', array(
493
+ $this->xcloner_sanitization,
494
+ "sanitize_input_as_int"
495
+ ) );
496
+ add_settings_field(
497
+ 'xcloner_directories_to_scan_per_request',
498
+ __( 'Directories To Scan Per Request', 'xcloner-backup-and-restore' ),
499
+ array( $this, 'do_form_range_field' ),
500
+ 'xcloner_system_settings_page',
501
+ 'xcloner_system_settings_group',
502
+ array(
503
+ 'xcloner_directories_to_scan_per_request',
504
+ __( 'Use this option to set how many directories XCloner should scan at one time before doing another AJAX call', 'xcloner-backup-and-restore' ),
505
+ 0,
506
+ 1000
507
+ )
508
+ );
509
+
510
+ register_setting( 'xcloner_system_settings_group', 'xcloner_database_records_per_request', array(
511
+ $this->xcloner_sanitization,
512
+ "sanitize_input_as_int"
513
+ ) );
514
+ add_settings_field(
515
+ 'xcloner_database_records_per_request',
516
+ __( 'Database Records Per Request', 'xcloner-backup-and-restore' ),
517
+ array( $this, 'do_form_range_field' ),
518
+ 'xcloner_system_settings_page',
519
+ 'xcloner_system_settings_group',
520
+ array(
521
+ 'xcloner_database_records_per_request',
522
+ __( 'Use this option to set how many database table records should be fetched per AJAX request, or set to 0 to fetch all. Range 0-100000 records', 'xcloner-backup-and-restore' ),
523
+ 0,
524
+ 100000
525
+ )
526
+ );
527
+
528
  /*register_setting('xcloner_system_settings_group', 'xcloner_diff_backup_recreate_period', array($this->xcloner_sanitization, "sanitize_input_as_int"));
529
  add_settings_field(
530
  'xcloner_diff_backup_recreate_period',
536
  __('Use this option to set when a full backup should be recreated if the scheduled backup type is set to \'Full Backup+Differential Backups\' ','xcloner-backup-and-restore'),
537
  )
538
  );*/
539
+
540
+ register_setting( 'xcloner_system_settings_group', 'xcloner_exclude_files_larger_than_mb', array(
541
+ $this->xcloner_sanitization,
542
+ "sanitize_input_as_int"
543
+ ) );
544
+ add_settings_field(
545
+ 'xcloner_exclude_files_larger_than_mb',
546
+ __( 'Exclude files larger than (MB)', 'xcloner-backup-and-restore' ),
547
+ array( $this, 'do_form_number_field' ),
548
+ 'xcloner_system_settings_page',
549
+ 'xcloner_system_settings_group',
550
+ array(
551
+ 'xcloner_exclude_files_larger_than_mb',
552
+ __( 'Use this option to automatically exclude files larger than a certain size in MB, or set to 0 to include all. Range 0-1000 MB', 'xcloner-backup-and-restore' ),
553
+ )
554
+ );
555
+
556
+ register_setting( 'xcloner_system_settings_group', 'xcloner_split_backup_limit', array(
557
+ $this->xcloner_sanitization,
558
+ "sanitize_input_as_int"
559
+ ) );
560
+ add_settings_field(
561
+ 'xcloner_split_backup_limit',
562
+ __( 'Split Backup Archive Limit (MB)', 'xcloner-backup-and-restore' ),
563
+ array( $this, 'do_form_number_field' ),
564
+ 'xcloner_system_settings_page',
565
+ 'xcloner_system_settings_group',
566
+ array(
567
+ 'xcloner_split_backup_limit',
568
+ __( 'Use this option to automatically split the backup archive into smaller parts. Range 0-10000 MB', 'xcloner-backup-and-restore' ),
569
+ )
570
+ );
571
+
572
+ register_setting( 'xcloner_system_settings_group', 'xcloner_force_tmp_path_site_root' );
573
+ add_settings_field(
574
+ 'xcloner_force_tmp_path_site_root',
575
+ __( 'Force Temporary Path Within XCloner Storage', 'xcloner-backup-and-restore' ),
576
+ array( $this, 'do_form_switch_field' ),
577
+ 'xcloner_system_settings_page',
578
+ 'xcloner_system_settings_group',
579
+ array(
580
+ 'xcloner_force_tmp_path_site_root',
581
+ sprintf( __( 'Enable this option if you want the XCloner Temporary Path to be within your XCloner Storage Location', 'xcloner-backup-and-restore' ), $this->get_table_prefix() )
582
+ )
583
+ );
584
+
585
  //REGISTERING THE 'CLEANUP SECTION' FIELDS
586
+ register_setting( 'xcloner_cleanup_settings_group', 'xcloner_cleanup_retention_limit_days', array(
587
+ $this->xcloner_sanitization,
588
+ "sanitize_input_as_int"
589
+ ) );
590
+ add_settings_field(
591
+ 'xcloner_cleanup_retention_limit_days',
592
+ __( 'Cleanup by Date(days)', 'xcloner-backup-and-restore' ),
593
+ array( $this, 'do_form_number_field' ),
594
+ 'xcloner_cleanup_settings_page',
595
+ 'xcloner_cleanup_settings_group',
596
+ array(
597
+ 'xcloner_cleanup_retention_limit_days',
598
+ __( 'Specify the maximum number of days a backup archive can be kept on the server. 0 disables this option', 'xcloner-backup-and-restore' )
599
  )
600
+ );
601
+
602
+ register_setting( 'xcloner_cleanup_settings_group', 'xcloner_cleanup_retention_limit_archives', array(
603
+ $this->xcloner_sanitization,
604
+ "sanitize_input_as_int"
605
+ ) );
606
+ add_settings_field(
607
+ 'xcloner_cleanup_retention_limit_archives',
608
+ __( 'Cleanup by Quantity', 'xcloner-backup-and-restore' ),
609
+ array( $this, 'do_form_number_field' ),
610
+ 'xcloner_cleanup_settings_page',
611
+ 'xcloner_cleanup_settings_group',
612
+ array(
613
+ 'xcloner_cleanup_retention_limit_archives',
614
+ __( 'Specify the maximum number of backup archives to keep on the server. 0 disables this option', 'xcloner-backup-and-restore' )
615
  )
616
+ );
617
+
618
+ register_setting( 'xcloner_cleanup_settings_group', 'xcloner_cleanup_capacity_limit', array(
619
+ $this->xcloner_sanitization,
620
+ "sanitize_input_as_int"
621
+ ) );
622
+ add_settings_field(
623
+ 'xcloner_cleanup_capacity_limit',
624
+ __( 'Cleanup by Capacity(MB)', 'xcloner-backup-and-restore' ),
625
+ array( $this, 'do_form_number_field' ),
626
+ 'xcloner_cleanup_settings_page',
627
+ 'xcloner_cleanup_settings_group',
628
+ array(
629
+ 'xcloner_cleanup_capacity_limit',
630
+ __( 'Remove oldest backups if all created backups exceed the configured limit in Megabytes. 0 disables this option', 'xcloner-backup-and-restore' )
631
  )
632
+ );
633
+
634
+ register_setting( 'xcloner_cleanup_settings_group', 'xcloner_cleanup_delete_after_remote_transfer', array(
635
+ $this->xcloner_sanitization,
636
+ "sanitize_input_as_int"
637
+ ) );
638
+ add_settings_field(
639
+ 'xcloner_cleanup_delete_after_remote_transfer',
640
+ __( 'Delete Backup After Remote Storage Transfer', 'xcloner-backup-and-restore' ),
641
+ array( $this, 'do_form_switch_field' ),
642
+ 'xcloner_cleanup_settings_page',
643
+ 'xcloner_cleanup_settings_group',
644
+ array(
645
+ 'xcloner_cleanup_delete_after_remote_transfer',
646
+ __( 'Remove backup created automatically from local storage after sending the backup to Remote Storage', 'xcloner-backup-and-restore' )
647
  )
648
+ );
649
+
650
  //REGISTERING THE 'CRON SECTION' FIELDS
651
+ register_setting( 'xcloner_cron_settings_group', 'xcloner_cron_frequency' );
652
+ add_settings_field(
653
+ 'xcloner_cron_frequency',
654
+ __( 'Cron frequency', 'xcloner-backup-and-restore' ),
655
+ array( $this, 'do_form_text_field' ),
656
+ 'xcloner_cron_settings_page',
657
+ 'xcloner_cron_settings_group',
658
+ array(
659
+ 'xcloner_cron_frequency',
660
+ __( 'Cron frequency' )
661
  )
662
+ );
663
  }
664
+
665
+
666
+
667
+
668
  /**
669
  * callback functions
670
  */
671
+
672
  // section content cb
673
+ public function xcloner_settings_section_cb() {
674
+ //echo '<p>WPOrg Section Introduction.</p>';
 
675
  }
676
+
677
  // text field content cb
678
+ public function do_form_text_field( $params ) {
679
+ if ( ! isset( $params['3'] ) ) {
 
680
  $params[3] = 0;
681
+ }
682
+ if ( ! isset( $params['2'] ) ) {
683
+ $params[2] = 0;
684
+ }
685
+
686
+ list( $fieldname, $label, $value, $disabled ) = $params;
687
+
688
+ if ( ! $value ) {
689
+ $value = get_option( $fieldname );
690
+ }
691
+ // output the field
692
+ ?>
693
+ <div class="row">
694
+ <div class="input-field col s10 m10 l8">
695
+ <input class="validate" <?php echo ( $disabled ) ? "disabled" : "" ?> name="<?php echo $fieldname ?>"
696
+ id="<?php echo $fieldname ?>" type="text" class="validate"
697
+ value="<?php echo isset( $value ) ? esc_attr( $value ) : ''; ?>">
698
+ </div>
699
+ <div class="col s2 m2 ">
700
+ <a class="btn-floating tooltipped btn-small" data-position="left" data-delay="50"
701
+ data-tooltip="<?php echo $label ?>" data-tooltip-id=""><i class="material-icons">help_outline</i></a>
702
+ </div>
703
+ </div>
704
+
705
+
706
+ <?php
707
  }
708
+
709
  // textarea field content cb
710
+ public function do_form_textarea_field( $params ) {
711
+ if ( ! isset( $params['3'] ) ) {
 
712
  $params[3] = 0;
713
+ }
714
+ if ( ! isset( $params['2'] ) ) {
715
+ $params[2] = 0;
716
+ }
717
+
718
+ list( $fieldname, $label, $value, $disabled ) = $params;
719
+
720
+ if ( ! $value ) {
721
+ $value = get_option( $fieldname );
722
+ }
723
+ // output the field
724
+ ?>
725
+ <div class="row">
726
+ <div class="input-field col s10 m10 l8">
727
+ <textarea class="validate" <?php echo ( $disabled ) ? "disabled" : "" ?> name="<?php echo $fieldname ?>"
728
+ id="<?php echo $fieldname ?>" type="text" class="validate"
729
+ value=""><?php echo isset( $value ) ? esc_attr( $value ) : ''; ?></textarea>
730
+ </div>
731
+ <div class="col s2 m2 ">
732
+ <a class="btn-floating tooltipped btn-small" data-position="center" data-html="true" data-delay="50"
733
+ data-tooltip="<?php echo $label ?>" data-tooltip-id=""><i class="material-icons">help_outline</i></a>
734
+ </div>
735
+ <div class="col s12">
736
+ <ul class="xcloner_regex_exclude_limit">
737
+ <li>Exclude all except .php file: <span
738
+ class="regex_pattern"><?php echo htmlentities( '(.*)\.(.+)$(?<!(php))' ) ?></span></li>
739
+ <li>Exclude all except .php and .txt: <span
740
+ class="regex_pattern"> <?php echo htmlentities( '(.*)\.(.+)$(?<!(php|txt))' ) ?></span>
741
+ </li>
742
+ <li>Exclude all .avi files: <span
743
+ class="regex_pattern"> <?php echo htmlentities( '(.*)\.(.+)$(?<=(avi))' ) ?></span></li>
744
+ <li>Exclude all .jpg,.gif and .png files: <span
745
+ class="regex_pattern"> <?php echo htmlentities( '(.*)\.(.+)$(?<=(gif|png|jpg))' ) ?></span>
746
+ </li>
747
+ <li>Exclude all .svn and .git: <span
748
+ class="regex_pattern"> <?php echo htmlentities( '(.*)\.(svn|git)(.*)$' ) ?></span></li>
749
+ <li>Exclude root directory /test: <span
750
+ class="regex_pattern"> <?php echo htmlentities( '\/test(.*)$' ) ?></span> or <span
751
+ class="regex_pattern"> <?php echo htmlentities( 'test(.*)$' ) ?></span></li>
752
+ <li>Exclude the wp-admin folder: <span
753
+ class="regex_pattern"> <?php echo htmlentities( '(\/wp-admin)(.*)$' ) ?></span></li>
754
+ <li>Exclude the wp-content/uploads folder: <span
755
+ class="regex_pattern"> <?php echo htmlentities( '(\/wp-content\/uploads)(.*)$' ) ?></span>
756
+ </li>
757
+ <li>Exclude the wp-admin, wp-includes and wp-config.php: <span
758
+ class="regex_pattern"> <?php echo htmlentities( '\/(wp-admin|wp-includes|wp-config.php)(.*)$' ) ?></span>
759
+ </li>
760
+ <li>Exclude wp-content/updraft and wp/content/uploads/wp_all_backup folder :<span
761
+ class="regex_pattern">\/(wp-content\/updraft|\/wp-content\/uploads\/wp_all_backup)(.*)$</span>
762
+ </li>
763
+ <li>Exclude all cache folders from wp-content/ and it's subdirectories: <span
764
+ class="regex_pattern"> <?php echo htmlentities( '\/wp-content(.*)\/cache($|\/)(.*)' ) ?></span>
765
+ </li>
766
+ <li>Exclude wp-content/cache/ folder: <span
767
+ class="regex_pattern"> <?php echo htmlentities( '\/wp-content\/cache(.*)' ) ?></span>
768
+ </li>
769
+ <li>Exclude all error_log files: <span
770
+ class="regex_pattern"> <?php echo htmlentities( '(.*)error_log$' ) ?></span></li>
771
+ </ul>
772
+ </div>
773
+ </div>
774
+
775
+
776
+ <?php
777
  }
778
+
779
  // number field content cb
780
+ public function do_form_number_field( $params ) {
781
+ if ( ! isset( $params['3'] ) ) {
 
782
  $params[3] = 0;
783
+ }
784
+ if ( ! isset( $params['2'] ) ) {
785
+ $params[2] = 0;
786
+ }
787
+
788
+ list( $fieldname, $label, $value, $disabled ) = $params;
789
+
790
+ if ( ! $value ) {
791
+ $value = get_option( $fieldname );
792
+ }
793
+ // output the field
794
+ ?>
795
+ <div class="row">
796
+ <div class="input-field col s10 m5 l3">
797
+ <input class="validate" <?php echo ( $disabled ) ? "disabled" : "" ?> name="<?php echo $fieldname ?>"
798
+ id="<?php echo $fieldname ?>" type="number" class="validate"
799
+ value="<?php echo isset( $value ) ? esc_attr( $value ) : ''; ?>">
800
+ </div>
801
+ <div class="col s2 m2 ">
802
+ <a class="btn-floating tooltipped btn-small" data-html="true" data-position="center" data-delay="50"
803
+ data-tooltip="<?php echo $label ?>" data-tooltip-id=""><i class="material-icons">help_outline</i></a>
804
+ </div>
805
+ </div>
806
+
807
+
808
+ <?php
809
  }
810
+
811
+ public function do_form_range_field( $params ) {
812
+ if ( ! isset( $params['4'] ) ) {
 
813
  $params[4] = 0;
814
+ }
815
+
816
+ list( $fieldname, $label, $range_start, $range_end, $disabled ) = $params;
817
+ $value = get_option( $fieldname );
818
+ ?>
819
+ <div class="row">
820
+ <div class="input-field col s10 m10 l8">
821
+ <p class="range-field">
822
+ <input <?php echo ( $disabled ) ? "disabled" : "" ?> type="range" name="<?php echo $fieldname ?>"
823
+ id="<?php echo $fieldname ?>"
824
+ min="<?php echo $range_start ?>"
825
+ max="<?php echo $range_end ?>"
826
+ value="<?php echo isset( $value ) ? esc_attr( $value ) : ''; ?>"/>
827
+ </p>
828
+ </div>
829
+ <div class="col s2 m2 ">
830
+ <a class="btn-floating tooltipped btn-small" data-html="true" data-position="center" data-delay="50"
831
+ data-tooltip="<?php echo $label ?>" data-tooltip-id=""><i class="material-icons">help_outline</i></a>
832
+ </div>
833
+ </div>
834
+ <?php
835
  }
836
+
837
+
838
+ public function do_form_switch_field( $params ) {
839
+ if ( ! isset( $params['2'] ) ) {
 
840
  $params[2] = 0;
841
+ }
842
+ list( $fieldname, $label, $disabled ) = $params;
843
+ $value = get_option( $fieldname );
844
+ ?>
845
+ <div class="row">
846
+ <div class="input-field col s10 m5 l3">
847
+ <div class="switch">
848
+ <label>
849
+ Off
850
+ <input <?php echo ( $disabled ) ? "disabled" : "" ?> type="checkbox"
851
+ name="<?php echo $fieldname ?>"
852
+ id="<?php echo $fieldname ?>"
853
+ value="1" <?php echo ( $value ) ? 'checked="checked"' : ''; ?>
854
+ ">
855
+ <span class="lever"></span>
856
+ On
857
+ </label>
858
+ </div>
859
+ </div>
860
+ <div class="col s2 m2">
861
+ <a class="btn-floating tooltipped btn-small" data-position="center" data-delay="50"
862
+ data-tooltip="<?php echo $label ?>" data-tooltip-id=""><i class="material-icons">help_outline</i></a>
863
+ </div>
864
+ </div>
865
+ <?php
866
  }
867
  }
includes/class-xcloner.php CHANGED
@@ -1,16 +1,29 @@
1
  <?php
2
-
3
  /**
4
- * The file that defines the core plugin class
5
  *
6
- * A class definition that includes attributes and functions used across both the
7
- * public-facing side of the site and the admin area.
8
  *
9
- * @link http://www.thinkovi.com
10
- * @since 1.0.0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  *
12
- * @package Xcloner
13
- * @subpackage Xcloner/includes
14
  */
15
 
16
  /**
@@ -26,6 +39,7 @@
26
  * @package Xcloner
27
  * @subpackage Xcloner/includes
28
  * @author Liuta Ovidiu <info@thinkovi.com>
 
29
  */
30
  class Xcloner {
31
 
@@ -38,7 +52,7 @@ class Xcloner {
38
  * @var Xcloner_Loader $loader Maintains and registers all hooks for the plugin.
39
  */
40
  protected $loader;
41
-
42
  /**
43
  * The unique identifier of this plugin.
44
  *
@@ -47,7 +61,7 @@ class Xcloner {
47
  * @var string $plugin_name The string used to uniquely identify this plugin.
48
  */
49
  protected $plugin_name;
50
-
51
  protected $plugin_admin;
52
 
53
  /**
@@ -58,8 +72,8 @@ class Xcloner {
58
  * @var string $version The current version of the plugin.
59
  */
60
  protected $version;
61
-
62
- private $xcloner_settings;
63
  private $xcloner_logger;
64
  private $xcloner_sanitization;
65
  private $xcloner_requirements;
@@ -78,80 +92,80 @@ class Xcloner {
78
  *
79
  * @since 1.0.0
80
  */
81
- public function init()
82
  {
83
  register_shutdown_function(array($this, 'exception_handler'));
84
-
85
  $this->plugin_name = 'xcloner';
86
  $this->version = '4.0.4';
87
-
88
  $this->load_dependencies();
89
  $this->set_locale();
90
  $this->define_admin_hooks();
91
  $this->define_public_hooks();
92
-
93
  $this->define_admin_menu();
94
  $this->define_plugin_settings();
95
-
96
  $this->define_ajax_hooks();
97
  $this->define_cron_hooks();
98
-
99
  }
100
-
101
  public function get_xcloner_settings()
102
  {
103
  return $this->xcloner_settings;
104
  }
105
-
106
  public function get_xcloner_filesystem()
107
  {
108
  return $this->xcloner_filesystem;
109
  }
110
-
111
  public function get_xcloner_logger()
112
  {
113
  return $this->xcloner_logger;
114
  }
115
-
116
  public function get_xcloner_sanitization()
117
  {
118
  return $this->xcloner_sanitization;
119
  }
120
-
121
  public function get_xcloner_requirements()
122
  {
123
  return $this->xcloner_requirements;
124
  }
125
-
126
  public function get_archive_system()
127
  {
128
  return $this->archive_system;
129
  }
130
-
131
  public function get_xcloner_database()
132
  {
133
  return $this->xcloner_database;
134
  }
135
-
136
  public function get_xcloner_scheduler()
137
  {
138
  return $this->xcloner_scheduler;
139
  }
140
-
141
  public function get_xcloner_remote_storage()
142
  {
143
  return $this->xcloner_remote_storage;
144
  }
145
-
146
  public function get_xcloner_file_transfer()
147
  {
148
  return $this->xcloner_file_transfer;
149
  }
150
-
151
  public function check_dependencies(){
152
-
153
  $backup_storage_path = realpath(__DIR__.DS."..".DS."..".DS."..").DS."backups".DS;
154
-
155
  define("XCLONER_STORAGE_PATH", realpath($backup_storage_path));
156
 
157
  if(!is_dir($backup_storage_path))
@@ -163,25 +177,25 @@ class Xcloner {
163
  $this->trigger_message($message, $status, $backup_storage_path);
164
  return;
165
  }
166
- }
167
  if(!is_writable($backup_storage_path))
168
  {
169
  $status = "error";
170
  $message = sprintf(__("Unable to write to the Backup Storage Location Folder %s . Please fix this before starting the backup process."), $backup_storage_path);
171
  $this->trigger_message($message, $status, $backup_storage_path);
172
-
173
  return;
174
  }
175
-
176
  }
177
-
178
  public function trigger_message($message, $status = "error", $message_param1 = "", $message_param2 = "", $message_param3 = "")
179
  {
180
  $message = sprintf(__($message), $message_param1, $message_param2, $message_param3);
181
  add_action( 'xcloner_admin_notices', array($this,"trigger_message_notice"), 10, 2);
182
  do_action( 'xcloner_admin_notices', $message, $status);
183
  }
184
-
185
  public function trigger_message_notice($message, $status = "success")
186
  {
187
  ?>
@@ -225,57 +239,57 @@ class Xcloner {
225
  * The class responsible for defining all actions that occur in the admin area.
226
  */
227
  require_once plugin_dir_path( dirname( __FILE__ ) ) . 'admin/class-xcloner-admin.php';
228
-
229
  /**
230
  * The class responsible for debugging XCloner.
231
  */
232
  require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-xcloner-logger.php';
233
-
234
  /**
235
  * The class responsible for defining the admin settings area.
236
  */
237
  require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-xcloner-settings.php';
238
-
239
  /**
240
  * The class responsible for defining the Remote Storage settings area.
241
  */
242
  require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-xcloner-remote-storage.php';
243
-
244
  /**
245
  * The class responsible for implementing the database backup methods.
246
  */
247
  require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-xcloner-database.php';
248
-
249
  /**
250
  * The class responsible for sanitization of users input.
251
  */
252
  require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-xcloner-sanitization.php';
253
-
254
  /**
255
  * The class responsible for XCloner system requirements validation.
256
  */
257
  require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-xcloner-requirements.php';
258
-
259
  /**
260
  * The class responsible for XCloner backup archive creation.
261
  */
262
  require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-xcloner-archive.php';
263
-
264
  /**
265
  * The class responsible for XCloner API requests.
266
  */
267
  require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-xcloner-api.php';
268
-
269
  /**
270
  * The class responsible for the XCloner File System methods.
271
  */
272
  require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-xcloner-file-system.php';
273
-
274
  /**
275
  * The class responsible for the XCloner File Transfer methods.
276
  */
277
  require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-xcloner-file-transfer.php';
278
-
279
  /**
280
  * The class responsible for the XCloner Scheduler methods.
281
  */
@@ -286,7 +300,7 @@ class Xcloner {
286
  * side of the site.
287
  */
288
  require_once plugin_dir_path( dirname( __FILE__ ) ) . 'public/class-xcloner-public.php';
289
-
290
  $this->loader = new Xcloner_Loader($this);
291
 
292
  }
@@ -305,7 +319,7 @@ class Xcloner {
305
  $plugin_i18n = new Xcloner_i18n();
306
 
307
  $this->loader->add_action( 'plugins_loaded', $plugin_i18n, 'load_plugin_textdomain' );
308
-
309
  //wp_localize_script( 'ajax-script', 'my_ajax_object',
310
  // array( 'ajax_url' => admin_url( 'admin-ajax.php' ) ) );
311
 
@@ -319,42 +333,44 @@ class Xcloner {
319
  * @access private
320
  */
321
  private function define_admin_hooks() {
322
-
323
  $plugin_admin = new Xcloner_Admin( $this );
324
  $this->plugin_admin = $plugin_admin;
325
 
326
  $this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_styles' );
327
  $this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_scripts' );
328
-
 
329
  }
330
-
331
  /**
332
  * Register the Admin Sidebar menu
333
- *
334
- * @access private
 
335
  */
336
  private function define_admin_menu(){
337
-
338
  add_action('admin_menu', array($this->loader, 'xcloner_backup_add_admin_menu'));
339
-
340
  }
341
-
342
  private function define_plugin_settings(){
343
  /**
344
  * register wporg_settings_init to the admin_init action hook
345
  */
346
 
347
  $this->xcloner_settings = new XCloner_Settings($this);
348
-
349
  if(defined('DOING_CRON') || isset($_POST['hash'])){
350
-
351
  if(defined('DOING_CRON') || $_POST['hash'] == "generate_hash"){
352
  $this->xcloner_settings->generate_new_hash();
353
  }else{
354
  $this->xcloner_settings->set_hash($_POST['hash']);
355
  }
356
  }
357
-
358
  if(defined('DOING_CRON') || !isset($_POST['hash']))
359
  {
360
  add_action( 'shutdown', function(){
@@ -362,19 +378,19 @@ class Xcloner {
362
  $this->xcloner_file_system->remove_tmp_filesystem();
363
  });
364
  }
365
-
366
  $this->xcloner_sanitization = new Xcloner_Sanitization();
367
  $this->xcloner_requirements = new Xcloner_Requirements($this);
368
-
369
  add_action('admin_init', array($this->xcloner_settings, 'settings_init'));
370
-
371
  //adding links to the Manage Plugins Wordpress page for XCloner
372
  add_filter('plugin_action_links', array($this, 'add_plugin_action_links'), 10, 2);
373
-
374
-
375
-
376
  }
377
-
378
  /*
379
  * type = core|plugin|theme|translation
380
  */
@@ -383,15 +399,15 @@ class Xcloner {
383
  if(!$type)
384
  {
385
  return false;
386
- }
387
-
388
  $this->get_xcloner_logger()->info(sprintf("Doing automatic backup before %s upgrade, pre_auto_update hook.", $type));
389
-
390
- $content_dir = str_replace(ABSPATH, "", WP_CONTENT_DIR);
391
  $plugins_dir = str_replace(ABSPATH, "", WP_PLUGIN_DIR);
392
  $langs_dir = $content_dir . DS . "languages";
393
  $themes_dir = $content_dir . DS . "themes";
394
-
395
  switch ( $type ) {
396
  case 'core':
397
  $exclude_files = array(
@@ -399,17 +415,17 @@ class Xcloner {
399
  );
400
  break;
401
  case 'plugin':
402
-
403
  $dir_array = explode(DS, $plugins_dir);
404
-
405
  foreach($dir_array as $dir)
406
  {
407
  $data .= "\/".$dir;
408
  $regex .= $data."$|";
409
  }
410
-
411
  $regex .= "\/".implode("\/", $dir_array);
412
-
413
  $exclude_files = array(
414
  "^(?!(".$regex."))(.*)$",
415
  );
@@ -417,55 +433,55 @@ class Xcloner {
417
  case 'theme':
418
 
419
  $dir_array = explode(DS, $themes_dir);
420
-
421
  foreach($dir_array as $dir)
422
  {
423
  $data .= "\/".$dir;
424
  $regex .= $data."$|";
425
  }
426
-
427
  $regex .= "\/".implode("\/", $dir_array);
428
-
429
  $exclude_files = array(
430
  "^(?!(".$regex."))(.*)$",
431
- );
432
  break;
433
  case 'translation':
434
 
435
  $dir_array = explode(DS, $langs_dir);
436
-
437
  foreach($dir_array as $dir)
438
  {
439
  $data .= "\/".$dir;
440
  $regex .= $data."$|";
441
  }
442
-
443
  $regex .= "\/".implode("\/", $dir_array);
444
-
445
  $exclude_files = array(
446
  "^(?!(".$regex."))(.*)$",
447
- );
448
  break;
449
  }
450
-
451
  $schedule = array();
452
-
453
  $schedule['id'] = 0;
454
  $schedule['name'] = "pre_auto_update";
455
  $schedule['recurrence'] = "single";
456
  $schedule['excluded_files'] = json_encode($exclude_files);
457
  $schedule['table_params'] = json_encode(array("#" => array($this->get_xcloner_settings()->get_db_database())));
458
-
459
  $schedule['backup_params'] = new stdClass();
460
  $schedule['backup_params']->email_notification = get_option('admin_email');
461
  $schedule['backup_params']->backup_name = "backup_pre_auto_update_".$type."_[domain]-[time]-sql";
462
-
463
  try{
464
  $this->xcloner_scheduler->xcloner_scheduler_callback(0, $schedule);
465
  }catch(Exception $e){
466
  $this->get_xcloner_logger()->error($e->getMessage());
467
  }
468
-
469
  }
470
 
471
  /**
@@ -483,19 +499,19 @@ class Xcloner {
483
  $this->loader->add_action( 'wp_enqueue_scripts', $plugin_public, 'enqueue_scripts' );
484
 
485
  }
486
-
487
  public function exception_handler() {
488
-
489
  $logger = new XCloner_Logger($this, "php_system");
490
  $error = error_get_last();
491
-
492
  if($error['type'] and $logger)
493
  {
494
  $logger->info($this->friendly_error_type ($error['type']).": ".var_export($error, true));
495
  }
496
-
497
  }
498
-
499
  function friendly_error_type($type) {
500
  static $levels=null;
501
  if ($levels===null) {
@@ -507,24 +523,24 @@ class Xcloner {
507
  }
508
  return (isset($levels[$type]) ? $levels[$type] : "Error #{$type}");
509
  }
510
-
511
  private function define_ajax_hooks()
512
  {
513
  //adding the pre-update hook
514
-
515
  if(is_admin() || defined('DOING_CRON'))
516
  {
517
  $this->xcloner_logger = new XCloner_Logger($this, "xcloner_api");
518
  $this->xcloner_filesystem = new Xcloner_File_System($this);
519
-
520
  //$this->xcloner_filesystem->set_diff_timestamp_start (strtotime("-15 days"));
521
-
522
  $this->archive_system = new Xcloner_Archive($this);
523
  $this->xcloner_database = new Xcloner_Database($this);
524
  $this->xcloner_scheduler = new Xcloner_Scheduler($this);
525
  $this->xcloner_remote_storage = new Xcloner_Remote_Storage($this);
526
  $this->xcloner_file_transfer = new Xcloner_File_Transfer($this);
527
-
528
  $xcloner_api = new Xcloner_Api($this);
529
 
530
  add_action( 'wp_ajax_get_database_tables_action', array($xcloner_api,'get_database_tables_action') );
@@ -546,65 +562,65 @@ class Xcloner {
546
  add_action( 'wp_ajax_copy_backup_remote_to_local', array($xcloner_api,'copy_backup_remote_to_local') );
547
  add_action( 'wp_ajax_restore_backup', array($xcloner_api,'restore_backup') );
548
  add_action( 'admin_notices', array($this, 'xcloner_error_admin_notices' ));
549
-
550
  }
551
-
552
  //Do a pre-update backup of targeted files
553
  if($this->get_xcloner_settings()->get_xcloner_option('xcloner_enable_pre_update_backup'))
554
  {
555
  add_action("pre_auto_update", array($this, "pre_auto_update"), 1, 3);
556
  }
557
  }
558
-
559
  function add_plugin_action_links($links, $file) {
560
  if ($file == plugin_basename(dirname(dirname(__FILE__)) . '/xcloner.php'))
561
- {
562
  $links[] = '<a href="admin.php?page=xcloner_settings_page">'.__('Settings', 'xcloner-backup-and-restore').'</a>';
563
  $links[] = '<a href="admin.php?page=xcloner_generate_backups_page">'.__('Generate Backup', 'xcloner-backup-and-restore').'</a>';
564
  }
565
-
566
  return $links;
567
  }
568
-
569
  public function xcloner_error_admin_notices() {
570
  settings_errors( 'xcloner_error_message' );
571
  }
572
-
573
  public function define_cron_hooks()
574
  {
575
  //registering new schedule intervals
576
  add_filter( 'cron_schedules', array($this, 'add_new_intervals'));
577
-
578
-
579
  $xcloner_scheduler = $this->get_xcloner_scheduler();
580
  $xcloner_scheduler->update_wp_cron_hooks();
581
-
582
  }
583
-
584
- function add_new_intervals($schedules)
585
  {
586
  //weekly scheduler interval
587
  $schedules['weekly'] = array(
588
  'interval' => 604800,
589
  'display' => __('Once Weekly', 'xcloner-backup-and-restore')
590
  );
591
-
592
  //monthly scheduler interval
593
  $schedules['monthly'] = array(
594
  'interval' => 2635200,
595
  'display' => __('Once Monthly', 'xcloner-backup-and-restore')
596
  );
597
-
598
  //monthly scheduler interval
599
  $schedules['twicedaily'] = array(
600
  'interval' => 43200,
601
  'display' => __('Twice Daily', 'xcloner-backup-and-restore')
602
  );
603
-
604
  return $schedules;
605
  }
606
 
607
-
608
  /**
609
  * Run the loader to execute all of the hooks with WordPress.
610
  *
@@ -644,28 +660,28 @@ class Xcloner {
644
  public function get_version() {
645
  return $this->version;
646
  }
647
-
648
  function xcloner_display()
649
- {
650
  // check user capabilities
651
  if (!current_user_can('manage_options')) {
652
  return;
653
  }
654
-
655
  $page = sanitize_key($_GET['page']);
656
 
657
  if($page)
658
  {
659
  $this->display($page);
660
  }
661
-
662
  }
663
-
664
  public function display($page)
665
  {
666
  $plugin_admin = new Xcloner_Admin($this);
667
  $this->plugin_admin = $plugin_admin;
668
-
669
  call_user_func_array(array($this->plugin_admin, $page), array());
670
  }
671
  }
1
  <?php
 
2
  /**
3
+ * XCloner - Backup and Restore backup plugin for Wordpress
4
  *
5
+ * class-xcloner.php
6
+ * @author Liuta Ovidiu <info@thinkovi.com>
7
  *
8
+ * This program is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation; either version 2 of the License, or
11
+ * (at your option) any later version.
12
+ *
13
+ * This program is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ * GNU General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU General Public License
19
+ * along with this program; if not, write to the Free Software
20
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21
+ * MA 02110-1301, USA.
22
+ *
23
+ * @link https://github.com/ovidiul/XCloner-Wordpress
24
+ *
25
+ * @modified 7/31/18 3:29 PM
26
  *
 
 
27
  */
28
 
29
  /**
39
  * @package Xcloner
40
  * @subpackage Xcloner/includes
41
  * @author Liuta Ovidiu <info@thinkovi.com>
42
+ * @link http://www.thinkovi.com
43
  */
44
  class Xcloner {
45
 
52
  * @var Xcloner_Loader $loader Maintains and registers all hooks for the plugin.
53
  */
54
  protected $loader;
55
+
56
  /**
57
  * The unique identifier of this plugin.
58
  *
61
  * @var string $plugin_name The string used to uniquely identify this plugin.
62
  */
63
  protected $plugin_name;
64
+
65
  protected $plugin_admin;
66
 
67
  /**
72
  * @var string $version The current version of the plugin.
73
  */
74
  protected $version;
75
+
76
+ private $xcloner_settings;
77
  private $xcloner_logger;
78
  private $xcloner_sanitization;
79
  private $xcloner_requirements;
92
  *
93
  * @since 1.0.0
94
  */
95
+ public function init()
96
  {
97
  register_shutdown_function(array($this, 'exception_handler'));
98
+
99
  $this->plugin_name = 'xcloner';
100
  $this->version = '4.0.4';
101
+
102
  $this->load_dependencies();
103
  $this->set_locale();
104
  $this->define_admin_hooks();
105
  $this->define_public_hooks();
106
+
107
  $this->define_admin_menu();
108
  $this->define_plugin_settings();
109
+
110
  $this->define_ajax_hooks();
111
  $this->define_cron_hooks();
112
+
113
  }
114
+
115
  public function get_xcloner_settings()
116
  {
117
  return $this->xcloner_settings;
118
  }
119
+
120
  public function get_xcloner_filesystem()
121
  {
122
  return $this->xcloner_filesystem;
123
  }
124
+
125
  public function get_xcloner_logger()
126
  {
127
  return $this->xcloner_logger;
128
  }
129
+
130
  public function get_xcloner_sanitization()
131
  {
132
  return $this->xcloner_sanitization;
133
  }
134
+
135
  public function get_xcloner_requirements()
136
  {
137
  return $this->xcloner_requirements;
138
  }
139
+
140
  public function get_archive_system()
141
  {
142
  return $this->archive_system;
143
  }
144
+
145
  public function get_xcloner_database()
146
  {
147
  return $this->xcloner_database;
148
  }
149
+
150
  public function get_xcloner_scheduler()
151
  {
152
  return $this->xcloner_scheduler;
153
  }
154
+
155
  public function get_xcloner_remote_storage()
156
  {
157
  return $this->xcloner_remote_storage;
158
  }
159
+
160
  public function get_xcloner_file_transfer()
161
  {
162
  return $this->xcloner_file_transfer;
163
  }
164
+
165
  public function check_dependencies(){
166
+
167
  $backup_storage_path = realpath(__DIR__.DS."..".DS."..".DS."..").DS."backups".DS;
168
+
169
  define("XCLONER_STORAGE_PATH", realpath($backup_storage_path));
170
 
171
  if(!is_dir($backup_storage_path))
177
  $this->trigger_message($message, $status, $backup_storage_path);
178
  return;
179
  }
180
+ }
181
  if(!is_writable($backup_storage_path))
182
  {
183
  $status = "error";
184
  $message = sprintf(__("Unable to write to the Backup Storage Location Folder %s . Please fix this before starting the backup process."), $backup_storage_path);
185
  $this->trigger_message($message, $status, $backup_storage_path);
186
+
187
  return;
188
  }
189
+
190
  }
191
+
192
  public function trigger_message($message, $status = "error", $message_param1 = "", $message_param2 = "", $message_param3 = "")
193
  {
194
  $message = sprintf(__($message), $message_param1, $message_param2, $message_param3);
195
  add_action( 'xcloner_admin_notices', array($this,"trigger_message_notice"), 10, 2);
196
  do_action( 'xcloner_admin_notices', $message, $status);
197
  }
198
+
199
  public function trigger_message_notice($message, $status = "success")
200
  {
201
  ?>
239
  * The class responsible for defining all actions that occur in the admin area.
240
  */
241
  require_once plugin_dir_path( dirname( __FILE__ ) ) . 'admin/class-xcloner-admin.php';
242
+
243
  /**
244
  * The class responsible for debugging XCloner.
245
  */
246
  require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-xcloner-logger.php';
247
+
248
  /**
249
  * The class responsible for defining the admin settings area.
250
  */
251
  require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-xcloner-settings.php';
252
+
253
  /**
254
  * The class responsible for defining the Remote Storage settings area.
255
  */
256
  require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-xcloner-remote-storage.php';
257
+
258
  /**
259
  * The class responsible for implementing the database backup methods.
260
  */
261
  require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-xcloner-database.php';
262
+
263
  /**
264
  * The class responsible for sanitization of users input.
265
  */
266
  require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-xcloner-sanitization.php';
267
+
268
  /**
269
  * The class responsible for XCloner system requirements validation.
270
  */
271
  require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-xcloner-requirements.php';
272
+
273
  /**
274
  * The class responsible for XCloner backup archive creation.
275
  */
276
  require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-xcloner-archive.php';
277
+
278
  /**
279
  * The class responsible for XCloner API requests.
280
  */
281
  require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-xcloner-api.php';
282
+
283
  /**
284
  * The class responsible for the XCloner File System methods.
285
  */
286
  require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-xcloner-file-system.php';
287
+
288
  /**
289
  * The class responsible for the XCloner File Transfer methods.
290
  */
291
  require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-xcloner-file-transfer.php';
292
+
293
  /**
294
  * The class responsible for the XCloner Scheduler methods.
295
  */
300
  * side of the site.
301
  */
302
  require_once plugin_dir_path( dirname( __FILE__ ) ) . 'public/class-xcloner-public.php';
303
+
304
  $this->loader = new Xcloner_Loader($this);
305
 
306
  }
319
  $plugin_i18n = new Xcloner_i18n();
320
 
321
  $this->loader->add_action( 'plugins_loaded', $plugin_i18n, 'load_plugin_textdomain' );
322
+
323
  //wp_localize_script( 'ajax-script', 'my_ajax_object',
324
  // array( 'ajax_url' => admin_url( 'admin-ajax.php' ) ) );
325
 
333
  * @access private
334
  */
335
  private function define_admin_hooks() {
336
+
337
  $plugin_admin = new Xcloner_Admin( $this );
338
  $this->plugin_admin = $plugin_admin;
339
 
340
  $this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_styles' );
341
  $this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_scripts' );
342
+
343
+ add_action( 'backup_archive_finished', array($this, 'do_action_after_backup_finished'), 10, 2);
344
  }
345
+
346
  /**
347
  * Register the Admin Sidebar menu
348
+ *
349
+ * @access private
350
+ *
351
  */
352
  private function define_admin_menu(){
353
+
354
  add_action('admin_menu', array($this->loader, 'xcloner_backup_add_admin_menu'));
355
+
356
  }
357
+
358
  private function define_plugin_settings(){
359
  /**
360
  * register wporg_settings_init to the admin_init action hook
361
  */
362
 
363
  $this->xcloner_settings = new XCloner_Settings($this);
364
+
365
  if(defined('DOING_CRON') || isset($_POST['hash'])){
366
+
367
  if(defined('DOING_CRON') || $_POST['hash'] == "generate_hash"){
368
  $this->xcloner_settings->generate_new_hash();
369
  }else{
370
  $this->xcloner_settings->set_hash($_POST['hash']);
371
  }
372
  }
373
+
374
  if(defined('DOING_CRON') || !isset($_POST['hash']))
375
  {
376
  add_action( 'shutdown', function(){
378
  $this->xcloner_file_system->remove_tmp_filesystem();
379
  });
380
  }
381
+
382
  $this->xcloner_sanitization = new Xcloner_Sanitization();
383
  $this->xcloner_requirements = new Xcloner_Requirements($this);
384
+
385
  add_action('admin_init', array($this->xcloner_settings, 'settings_init'));
386
+
387
  //adding links to the Manage Plugins Wordpress page for XCloner
388
  add_filter('plugin_action_links', array($this, 'add_plugin_action_links'), 10, 2);
389
+
390
+
391
+
392
  }
393
+
394
  /*
395
  * type = core|plugin|theme|translation
396
  */
399
  if(!$type)
400
  {
401
  return false;
402
+ }
403
+
404
  $this->get_xcloner_logger()->info(sprintf("Doing automatic backup before %s upgrade, pre_auto_update hook.", $type));
405
+
406
+ $content_dir = str_replace(ABSPATH, "", WP_CONTENT_DIR);
407
  $plugins_dir = str_replace(ABSPATH, "", WP_PLUGIN_DIR);
408
  $langs_dir = $content_dir . DS . "languages";
409
  $themes_dir = $content_dir . DS . "themes";
410
+
411
  switch ( $type ) {
412
  case 'core':
413
  $exclude_files = array(
415
  );
416
  break;
417
  case 'plugin':
418
+
419
  $dir_array = explode(DS, $plugins_dir);
420
+
421
  foreach($dir_array as $dir)
422
  {
423
  $data .= "\/".$dir;
424
  $regex .= $data."$|";
425
  }
426
+
427
  $regex .= "\/".implode("\/", $dir_array);
428
+
429
  $exclude_files = array(
430
  "^(?!(".$regex."))(.*)$",
431
  );
433
  case 'theme':
434
 
435
  $dir_array = explode(DS, $themes_dir);
436
+
437
  foreach($dir_array as $dir)
438
  {
439
  $data .= "\/".$dir;
440
  $regex .= $data."$|";
441
  }
442
+
443
  $regex .= "\/".implode("\/", $dir_array);
444
+
445
  $exclude_files = array(
446
  "^(?!(".$regex."))(.*)$",
447
+ );
448
  break;
449
  case 'translation':
450
 
451
  $dir_array = explode(DS, $langs_dir);
452
+
453
  foreach($dir_array as $dir)
454
  {
455
  $data .= "\/".$dir;
456
  $regex .= $data."$|";
457
  }
458
+
459
  $regex .= "\/".implode("\/", $dir_array);
460
+
461
  $exclude_files = array(
462
  "^(?!(".$regex."))(.*)$",
463
+ );
464
  break;
465
  }
466
+
467
  $schedule = array();
468
+
469
  $schedule['id'] = 0;
470
  $schedule['name'] = "pre_auto_update";
471
  $schedule['recurrence'] = "single";
472
  $schedule['excluded_files'] = json_encode($exclude_files);
473
  $schedule['table_params'] = json_encode(array("#" => array($this->get_xcloner_settings()->get_db_database())));
474
+
475
  $schedule['backup_params'] = new stdClass();
476
  $schedule['backup_params']->email_notification = get_option('admin_email');
477
  $schedule['backup_params']->backup_name = "backup_pre_auto_update_".$type."_[domain]-[time]-sql";
478
+
479
  try{
480
  $this->xcloner_scheduler->xcloner_scheduler_callback(0, $schedule);
481
  }catch(Exception $e){
482
  $this->get_xcloner_logger()->error($e->getMessage());
483
  }
484
+
485
  }
486
 
487
  /**
499
  $this->loader->add_action( 'wp_enqueue_scripts', $plugin_public, 'enqueue_scripts' );
500
 
501
  }
502
+
503
  public function exception_handler() {
504
+
505
  $logger = new XCloner_Logger($this, "php_system");
506
  $error = error_get_last();
507
+
508
  if($error['type'] and $logger)
509
  {
510
  $logger->info($this->friendly_error_type ($error['type']).": ".var_export($error, true));
511
  }
512
+
513
  }
514
+
515
  function friendly_error_type($type) {
516
  static $levels=null;
517
  if ($levels===null) {
523
  }
524
  return (isset($levels[$type]) ? $levels[$type] : "Error #{$type}");
525
  }
526
+
527
  private function define_ajax_hooks()
528
  {
529
  //adding the pre-update hook
530
+
531
  if(is_admin() || defined('DOING_CRON'))
532
  {
533
  $this->xcloner_logger = new XCloner_Logger($this, "xcloner_api");
534
  $this->xcloner_filesystem = new Xcloner_File_System($this);
535
+
536
  //$this->xcloner_filesystem->set_diff_timestamp_start (strtotime("-15 days"));
537
+
538
  $this->archive_system = new Xcloner_Archive($this);
539
  $this->xcloner_database = new Xcloner_Database($this);
540
  $this->xcloner_scheduler = new Xcloner_Scheduler($this);
541
  $this->xcloner_remote_storage = new Xcloner_Remote_Storage($this);
542
  $this->xcloner_file_transfer = new Xcloner_File_Transfer($this);
543
+
544
  $xcloner_api = new Xcloner_Api($this);
545
 
546
  add_action( 'wp_ajax_get_database_tables_action', array($xcloner_api,'get_database_tables_action') );
562
  add_action( 'wp_ajax_copy_backup_remote_to_local', array($xcloner_api,'copy_backup_remote_to_local') );
563
  add_action( 'wp_ajax_restore_backup', array($xcloner_api,'restore_backup') );
564
  add_action( 'admin_notices', array($this, 'xcloner_error_admin_notices' ));
565
+
566
  }
567
+
568
  //Do a pre-update backup of targeted files
569
  if($this->get_xcloner_settings()->get_xcloner_option('xcloner_enable_pre_update_backup'))
570
  {
571
  add_action("pre_auto_update", array($this, "pre_auto_update"), 1, 3);
572
  }
573
  }
574
+
575
  function add_plugin_action_links($links, $file) {
576
  if ($file == plugin_basename(dirname(dirname(__FILE__)) . '/xcloner.php'))
577
+ {
578
  $links[] = '<a href="admin.php?page=xcloner_settings_page">'.__('Settings', 'xcloner-backup-and-restore').'</a>';
579
  $links[] = '<a href="admin.php?page=xcloner_generate_backups_page">'.__('Generate Backup', 'xcloner-backup-and-restore').'</a>';
580
  }
581
+
582
  return $links;
583
  }
584
+
585
  public function xcloner_error_admin_notices() {
586
  settings_errors( 'xcloner_error_message' );
587
  }
588
+
589
  public function define_cron_hooks()
590
  {
591
  //registering new schedule intervals
592
  add_filter( 'cron_schedules', array($this, 'add_new_intervals'));
593
+
594
+
595
  $xcloner_scheduler = $this->get_xcloner_scheduler();
596
  $xcloner_scheduler->update_wp_cron_hooks();
597
+
598
  }
599
+
600
+ function add_new_intervals($schedules)
601
  {
602
  //weekly scheduler interval
603
  $schedules['weekly'] = array(
604
  'interval' => 604800,
605
  'display' => __('Once Weekly', 'xcloner-backup-and-restore')
606
  );
607
+
608
  //monthly scheduler interval
609
  $schedules['monthly'] = array(
610
  'interval' => 2635200,
611
  'display' => __('Once Monthly', 'xcloner-backup-and-restore')
612
  );
613
+
614
  //monthly scheduler interval
615
  $schedules['twicedaily'] = array(
616
  'interval' => 43200,
617
  'display' => __('Twice Daily', 'xcloner-backup-and-restore')
618
  );
619
+
620
  return $schedules;
621
  }
622
 
623
+
624
  /**
625
  * Run the loader to execute all of the hooks with WordPress.
626
  *
660
  public function get_version() {
661
  return $this->version;
662
  }
663
+
664
  function xcloner_display()
665
+ {
666
  // check user capabilities
667
  if (!current_user_can('manage_options')) {
668
  return;
669
  }
670
+
671
  $page = sanitize_key($_GET['page']);
672
 
673
  if($page)
674
  {
675
  $this->display($page);
676
  }
677
+
678
  }
679
+
680
  public function display($page)
681
  {
682
  $plugin_admin = new Xcloner_Admin($this);
683
  $this->plugin_admin = $plugin_admin;
684
+
685
  call_user_func_array(array($this->plugin_admin, $page), array());
686
  }
687
  }
public/class-xcloner-public.php CHANGED
@@ -27,7 +27,7 @@ class Xcloner_Public {
27
  *
28
  * @since 1.0.0
29
  * @access private
30
- * @var string $plugin_name The ID of this plugin.
31
  */
32
  private $plugin_name;
33
 
@@ -36,7 +36,7 @@ class Xcloner_Public {
36
  *
37
  * @since 1.0.0
38
  * @access private
39
- * @var string $version The current version of this plugin.
40
  */
41
  private $version;
42
 
@@ -44,13 +44,14 @@ class Xcloner_Public {
44
  * Initialize the class and set its properties.
45
  *
46
  * @since 1.0.0
47
- * @param string $plugin_name The name of the plugin.
48
- * @param string $version The version of this plugin.
 
49
  */
50
  public function __construct( Xcloner $xcloner_container ) {
51
 
52
- $this->plugin_name = $xcloner_container->get_plugin_name();
53
- $this->version = $xcloner_container->get_version();
54
 
55
  }
56
 
27
  *
28
  * @since 1.0.0
29
  * @access private
30
+ * @var string $plugin_name The ID of this plugin.
31
  */
32
  private $plugin_name;
33
 
36
  *
37
  * @since 1.0.0
38
  * @access private
39
+ * @var string $version The current version of this plugin.
40
  */
41
  private $version;
42
 
44
  * Initialize the class and set its properties.
45
  *
46
  * @since 1.0.0
47
+ *
48
+ * @param string $plugin_name The name of the plugin.
49
+ * @param string $version The version of this plugin.
50
  */
51
  public function __construct( Xcloner $xcloner_container ) {
52
 
53
+ $this->plugin_name = $xcloner_container->get_plugin_name();
54
+ $this->version = $xcloner_container->get_version();
55
 
56
  }
57
 
vendor/composer/ClassLoader.php CHANGED
@@ -374,10 +374,14 @@ class ClassLoader
374
 
375
  $first = $class[0];
376
  if (isset($this->prefixLengthsPsr4[$first])) {
377
- foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) {
378
- if (0 === strpos($class, $prefix)) {
379
- foreach ($this->prefixDirsPsr4[$prefix] as $dir) {
380
- if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
 
 
 
 
381
  return $file;
382
  }
383
  }
374
 
375
  $first = $class[0];
376
  if (isset($this->prefixLengthsPsr4[$first])) {
377
+ $subPath = $class;
378
+ while (false !== $lastPos = strrpos($subPath, '\\')) {
379
+ $subPath = substr($subPath, 0, $lastPos);
380
+ $search = $subPath.'\\';
381
+ if (isset($this->prefixDirsPsr4[$search])) {
382
+ $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
383
+ foreach ($this->prefixDirsPsr4[$search] as $dir) {
384
+ if (file_exists($file = $dir . $pathEnd)) {
385
  return $file;
386
  }
387
  }
vendor/composer/LICENSE CHANGED
@@ -1,5 +1,5 @@
1
 
2
- Copyright (c) 2016 Nils Adermann, Jordi Boggiano
3
 
4
  Permission is hereby granted, free of charge, to any person obtaining a copy
5
  of this software and associated documentation files (the "Software"), to deal
1
 
2
+ Copyright (c) Nils Adermann, Jordi Boggiano
3
 
4
  Permission is hereby granted, free of charge, to any person obtaining a copy
5
  of this software and associated documentation files (the "Software"), to deal
vendor/composer/autoload_files.php CHANGED
@@ -8,15 +8,16 @@ $baseDir = dirname($vendorDir);
8
  return array(
9
  'c964ee0ededf28c96ebd9db5099ef910' => $vendorDir . '/guzzlehttp/promises/src/functions_include.php',
10
  'a0edc8309cc5e1d60e3047b5df6b7052' => $vendorDir . '/guzzlehttp/psr7/src/functions_include.php',
11
- '37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php',
12
  '383eaff206634a77a1be54e64e6459c7' => $vendorDir . '/sabre/uri/lib/functions.php',
 
13
  'b067bc7112e384b61c701452d53a14a8' => $vendorDir . '/mtdowling/jmespath.php/src/JmesPath.php',
14
- '3569eecfeed3bcf0bad3c998a494ecb8' => $vendorDir . '/sabre/xml/lib/Deserializer/functions.php',
15
- '93aa591bc4ca510c520999e34229ee79' => $vendorDir . '/sabre/xml/lib/Serializer/functions.php',
16
  '2b9d0f43f9552984cfa82fee95491826' => $vendorDir . '/sabre/event/lib/coroutine.php',
17
  'd81bab31d3feb45bfe2f283ea3c8fdf7' => $vendorDir . '/sabre/event/lib/Loop/functions.php',
18
  'a1cce3d26cc15c00fcd0b3354bd72c88' => $vendorDir . '/sabre/event/lib/Promise/functions.php',
 
 
19
  '8a9dc1de0ca7e01f3e08231539562f61' => $vendorDir . '/aws/aws-sdk-php/src/functions.php',
20
  'ebdb698ed4152ae445614b69b5e4bb6a' => $vendorDir . '/sabre/http/lib/functions.php',
 
21
  'decc78cc4436b1292c6c0d151b19445c' => $vendorDir . '/phpseclib/phpseclib/phpseclib/bootstrap.php',
22
  );
8
  return array(
9
  'c964ee0ededf28c96ebd9db5099ef910' => $vendorDir . '/guzzlehttp/promises/src/functions_include.php',
10
  'a0edc8309cc5e1d60e3047b5df6b7052' => $vendorDir . '/guzzlehttp/psr7/src/functions_include.php',
 
11
  '383eaff206634a77a1be54e64e6459c7' => $vendorDir . '/sabre/uri/lib/functions.php',
12
+ '37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php',
13
  'b067bc7112e384b61c701452d53a14a8' => $vendorDir . '/mtdowling/jmespath.php/src/JmesPath.php',
 
 
14
  '2b9d0f43f9552984cfa82fee95491826' => $vendorDir . '/sabre/event/lib/coroutine.php',
15
  'd81bab31d3feb45bfe2f283ea3c8fdf7' => $vendorDir . '/sabre/event/lib/Loop/functions.php',
16
  'a1cce3d26cc15c00fcd0b3354bd72c88' => $vendorDir . '/sabre/event/lib/Promise/functions.php',
17
+ '3569eecfeed3bcf0bad3c998a494ecb8' => $vendorDir . '/sabre/xml/lib/Deserializer/functions.php',
18
+ '93aa591bc4ca510c520999e34229ee79' => $vendorDir . '/sabre/xml/lib/Serializer/functions.php',
19
  '8a9dc1de0ca7e01f3e08231539562f61' => $vendorDir . '/aws/aws-sdk-php/src/functions.php',
20
  'ebdb698ed4152ae445614b69b5e4bb6a' => $vendorDir . '/sabre/http/lib/functions.php',
21
+ '5255c38a0faeba867671b61dfda6d864' => $vendorDir . '/paragonie/random_compat/lib/random.php',
22
  'decc78cc4436b1292c6c0d151b19445c' => $vendorDir . '/phpseclib/phpseclib/phpseclib/bootstrap.php',
23
  );
vendor/composer/autoload_psr4.php CHANGED
@@ -32,7 +32,7 @@ return array(
32
  'GuzzleHttp\\Psr7\\' => array($vendorDir . '/guzzlehttp/psr7/src'),
33
  'GuzzleHttp\\Promise\\' => array($vendorDir . '/guzzlehttp/promises/src'),
34
  'GuzzleHttp\\' => array($vendorDir . '/guzzlehttp/guzzle/src'),
35
- 'ChrisWhite\\B2\\' => array($vendorDir . '/cwhite92/b2-sdk-php/src'),
36
  'BackblazeB2\\' => array($vendorDir . '/gliterd/backblaze-b2/src'),
37
  'Aws\\' => array($vendorDir . '/aws/aws-sdk-php/src'),
38
  );
32
  'GuzzleHttp\\Psr7\\' => array($vendorDir . '/guzzlehttp/psr7/src'),
33
  'GuzzleHttp\\Promise\\' => array($vendorDir . '/guzzlehttp/promises/src'),
34
  'GuzzleHttp\\' => array($vendorDir . '/guzzlehttp/guzzle/src'),
35
+ 'Defuse\\Crypto\\' => array($vendorDir . '/defuse/php-encryption/src'),
36
  'BackblazeB2\\' => array($vendorDir . '/gliterd/backblaze-b2/src'),
37
  'Aws\\' => array($vendorDir . '/aws/aws-sdk-php/src'),
38
  );
vendor/composer/autoload_static.php CHANGED
@@ -9,16 +9,17 @@ class ComposerStaticInit571f9d19802717f7be61d57b40d60b28
9
  public static $files = array (
10
  'c964ee0ededf28c96ebd9db5099ef910' => __DIR__ . '/..' . '/guzzlehttp/promises/src/functions_include.php',
11
  'a0edc8309cc5e1d60e3047b5df6b7052' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/functions_include.php',
12
- '37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php',
13
  '383eaff206634a77a1be54e64e6459c7' => __DIR__ . '/..' . '/sabre/uri/lib/functions.php',
 
14
  'b067bc7112e384b61c701452d53a14a8' => __DIR__ . '/..' . '/mtdowling/jmespath.php/src/JmesPath.php',
15
- '3569eecfeed3bcf0bad3c998a494ecb8' => __DIR__ . '/..' . '/sabre/xml/lib/Deserializer/functions.php',
16
- '93aa591bc4ca510c520999e34229ee79' => __DIR__ . '/..' . '/sabre/xml/lib/Serializer/functions.php',
17
  '2b9d0f43f9552984cfa82fee95491826' => __DIR__ . '/..' . '/sabre/event/lib/coroutine.php',
18
  'd81bab31d3feb45bfe2f283ea3c8fdf7' => __DIR__ . '/..' . '/sabre/event/lib/Loop/functions.php',
19
  'a1cce3d26cc15c00fcd0b3354bd72c88' => __DIR__ . '/..' . '/sabre/event/lib/Promise/functions.php',
 
 
20
  '8a9dc1de0ca7e01f3e08231539562f61' => __DIR__ . '/..' . '/aws/aws-sdk-php/src/functions.php',
21
  'ebdb698ed4152ae445614b69b5e4bb6a' => __DIR__ . '/..' . '/sabre/http/lib/functions.php',
 
22
  'decc78cc4436b1292c6c0d151b19445c' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/bootstrap.php',
23
  );
24
 
@@ -73,9 +74,9 @@ class ComposerStaticInit571f9d19802717f7be61d57b40d60b28
73
  'GuzzleHttp\\Promise\\' => 19,
74
  'GuzzleHttp\\' => 11,
75
  ),
76
- 'C' =>
77
  array (
78
- 'ChrisWhite\\B2\\' => 14,
79
  ),
80
  'B' =>
81
  array (
@@ -192,9 +193,9 @@ class ComposerStaticInit571f9d19802717f7be61d57b40d60b28
192
  array (
193
  0 => __DIR__ . '/..' . '/guzzlehttp/guzzle/src',
194
  ),
195
- 'ChrisWhite\\B2\\' =>
196
  array (
197
- 0 => __DIR__ . '/..' . '/cwhite92/b2-sdk-php/src',
198
  ),
199
  'BackblazeB2\\' =>
200
  array (
9
  public static $files = array (
10
  'c964ee0ededf28c96ebd9db5099ef910' => __DIR__ . '/..' . '/guzzlehttp/promises/src/functions_include.php',
11
  'a0edc8309cc5e1d60e3047b5df6b7052' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/functions_include.php',
 
12
  '383eaff206634a77a1be54e64e6459c7' => __DIR__ . '/..' . '/sabre/uri/lib/functions.php',
13
+ '37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php',
14
  'b067bc7112e384b61c701452d53a14a8' => __DIR__ . '/..' . '/mtdowling/jmespath.php/src/JmesPath.php',
 
 
15
  '2b9d0f43f9552984cfa82fee95491826' => __DIR__ . '/..' . '/sabre/event/lib/coroutine.php',
16
  'd81bab31d3feb45bfe2f283ea3c8fdf7' => __DIR__ . '/..' . '/sabre/event/lib/Loop/functions.php',
17
  'a1cce3d26cc15c00fcd0b3354bd72c88' => __DIR__ . '/..' . '/sabre/event/lib/Promise/functions.php',
18
+ '3569eecfeed3bcf0bad3c998a494ecb8' => __DIR__ . '/..' . '/sabre/xml/lib/Deserializer/functions.php',
19
+ '93aa591bc4ca510c520999e34229ee79' => __DIR__ . '/..' . '/sabre/xml/lib/Serializer/functions.php',
20
  '8a9dc1de0ca7e01f3e08231539562f61' => __DIR__ . '/..' . '/aws/aws-sdk-php/src/functions.php',
21
  'ebdb698ed4152ae445614b69b5e4bb6a' => __DIR__ . '/..' . '/sabre/http/lib/functions.php',
22
+ '5255c38a0faeba867671b61dfda6d864' => __DIR__ . '/..' . '/paragonie/random_compat/lib/random.php',
23
  'decc78cc4436b1292c6c0d151b19445c' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/bootstrap.php',
24
  );
25
 
74
  'GuzzleHttp\\Promise\\' => 19,
75
  'GuzzleHttp\\' => 11,
76
  ),
77
+ 'D' =>
78
  array (
79
+ 'Defuse\\Crypto\\' => 14,
80
  ),
81
  'B' =>
82
  array (
193
  array (
194
  0 => __DIR__ . '/..' . '/guzzlehttp/guzzle/src',
195
  ),
196
+ 'Defuse\\Crypto\\' =>
197
  array (
198
+ 0 => __DIR__ . '/..' . '/defuse/php-encryption/src',
199
  ),
200
  'BackblazeB2\\' =>
201
  array (
vendor/composer/installed.json CHANGED
@@ -1,135 +1,163 @@
1
  [
2
  {
3
- "name": "psr/log",
4
- "version": "1.0.2",
5
- "version_normalized": "1.0.2.0",
6
  "source": {
7
  "type": "git",
8
- "url": "https://github.com/php-fig/log.git",
9
- "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d"
10
  },
11
  "dist": {
12
  "type": "zip",
13
- "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d",
14
- "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d",
15
  "shasum": ""
16
  },
17
  "require": {
18
- "php": ">=5.3.0"
 
 
 
 
 
 
 
 
19
  },
20
- "time": "2016-10-10T12:19:37+00:00",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  "type": "library",
22
  "extra": {
23
  "branch-alias": {
24
- "dev-master": "1.0.x-dev"
25
  }
26
  },
27
- "installation-source": "dist",
28
  "autoload": {
29
  "psr-4": {
30
- "Psr\\Log\\": "Psr/Log/"
31
- }
 
 
 
32
  },
33
  "notification-url": "https://packagist.org/downloads/",
34
  "license": [
35
- "MIT"
36
  ],
37
  "authors": [
38
  {
39
- "name": "PHP-FIG",
40
- "homepage": "http://www.php-fig.org/"
41
  }
42
  ],
43
- "description": "Common interface for logging libraries",
44
- "homepage": "https://github.com/php-fig/log",
45
  "keywords": [
46
- "log",
47
- "psr",
48
- "psr-3"
 
 
 
 
 
49
  ]
50
  },
51
  {
52
- "name": "guzzlehttp/promises",
53
- "version": "v1.3.1",
54
- "version_normalized": "1.3.1.0",
55
  "source": {
56
  "type": "git",
57
- "url": "https://github.com/guzzle/promises.git",
58
- "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646"
59
  },
60
  "dist": {
61
  "type": "zip",
62
- "url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646",
63
- "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646",
64
  "shasum": ""
65
  },
66
- "require": {
67
- "php": ">=5.5.0"
68
- },
69
- "require-dev": {
70
- "phpunit/phpunit": "^4.0"
71
- },
72
- "time": "2016-12-20T10:07:11+00:00",
73
- "type": "library",
74
  "extra": {
75
- "branch-alias": {
76
- "dev-master": "1.4-dev"
 
 
 
 
 
 
 
 
 
77
  }
78
  },
79
- "installation-source": "dist",
80
- "autoload": {
81
- "psr-4": {
82
- "GuzzleHttp\\Promise\\": "src/"
83
- },
84
- "files": [
85
- "src/functions_include.php"
86
- ]
87
- },
88
  "notification-url": "https://packagist.org/downloads/",
89
  "license": [
90
  "MIT"
91
  ],
92
  "authors": [
93
  {
94
- "name": "Michael Dowling",
95
- "email": "mtdowling@gmail.com",
96
- "homepage": "https://github.com/mtdowling"
97
  }
98
  ],
99
- "description": "Guzzle promises library",
100
- "keywords": [
101
- "promise"
102
- ]
103
  },
104
  {
105
- "name": "psr/http-message",
106
- "version": "1.0.1",
107
- "version_normalized": "1.0.1.0",
108
  "source": {
109
  "type": "git",
110
- "url": "https://github.com/php-fig/http-message.git",
111
- "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363"
112
  },
113
  "dist": {
114
  "type": "zip",
115
- "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363",
116
- "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363",
117
  "shasum": ""
118
  },
119
  "require": {
120
- "php": ">=5.3.0"
 
 
121
  },
122
- "time": "2016-08-06T14:39:51+00:00",
123
- "type": "library",
124
- "extra": {
125
- "branch-alias": {
126
- "dev-master": "1.0.x-dev"
127
- }
128
  },
 
 
 
 
 
129
  "installation-source": "dist",
130
  "autoload": {
131
  "psr-4": {
132
- "Psr\\Http\\Message\\": "src/"
133
  }
134
  },
135
  "notification-url": "https://packagist.org/downloads/",
@@ -138,61 +166,60 @@
138
  ],
139
  "authors": [
140
  {
141
- "name": "PHP-FIG",
142
- "homepage": "http://www.php-fig.org/"
 
 
 
 
 
 
143
  }
144
  ],
145
- "description": "Common interface for HTTP messages",
146
- "homepage": "https://github.com/php-fig/http-message",
147
  "keywords": [
148
- "http",
149
- "http-message",
150
- "psr",
151
- "psr-7",
152
- "request",
153
- "response"
 
 
 
 
154
  ]
155
  },
156
  {
157
- "name": "microsoft/azure-storage",
158
- "version": "v0.10.2",
159
- "version_normalized": "0.10.2.0",
160
  "source": {
161
  "type": "git",
162
- "url": "https://github.com/Azure/azure-storage-php.git",
163
- "reference": "27de05b00c1858d6e1c6adbc489efa90e0342f82"
164
  },
165
  "dist": {
166
  "type": "zip",
167
- "url": "https://api.github.com/repos/Azure/azure-storage-php/zipball/27de05b00c1858d6e1c6adbc489efa90e0342f82",
168
- "reference": "27de05b00c1858d6e1c6adbc489efa90e0342f82",
169
  "shasum": ""
170
  },
171
  "require": {
172
- "guzzlehttp/guzzle": "~6.0",
173
  "php": ">=5.5.0"
174
  },
175
  "require-dev": {
176
- "mikey179/vfsstream": "~1.6",
177
- "pdepend/pdepend": "~2.2",
178
- "phploc/phploc": "~2.1",
179
- "phpmd/phpmd": "@stable",
180
- "phpunit/phpunit": "~4.0",
181
- "sebastian/phpcpd": "~2.0",
182
- "squizlabs/php_codesniffer": "2.*",
183
- "theseer/phpdox": "~0.8"
184
  },
185
- "time": "2016-08-19T08:32:57+00:00",
186
  "type": "library",
187
- "extra": {
188
- "branch-alias": {
189
- "dev-master": "0.10.x-dev"
190
- }
191
- },
192
- "installation-source": "dist",
193
  "autoload": {
194
  "psr-4": {
195
- "MicrosoftAzure\\Storage\\": "src/"
196
  }
197
  },
198
  "notification-url": "https://packagist.org/downloads/",
@@ -201,54 +228,66 @@
201
  ],
202
  "authors": [
203
  {
204
- "name": "Azure Storage PHP SDK",
205
- "email": "dmsh@microsoft.com"
 
 
206
  }
207
  ],
208
- "description": "This project provides a set of PHP client libraries that make it easy to access Microsoft Azure storage APIs.",
 
209
  "keywords": [
210
- "azure",
211
- "php",
212
- "sdk",
 
 
 
213
  "storage"
214
- ],
215
- "abandoned": "microsoft/azure-storage-blob, microsoft/azure-storage-table, microsoft/azure-storage-queue, microsoft/azure-storage-file"
216
  },
217
  {
218
- "name": "league/flysystem-azure",
219
- "version": "1.0.4",
220
- "version_normalized": "1.0.4.0",
221
  "source": {
222
  "type": "git",
223
- "url": "https://github.com/thephpleague/flysystem-azure.git",
224
- "reference": "0b9838c4f75ee41bc390357b0350e9a62e3b3a1f"
225
  },
226
  "dist": {
227
  "type": "zip",
228
- "url": "https://api.github.com/repos/thephpleague/flysystem-azure/zipball/0b9838c4f75ee41bc390357b0350e9a62e3b3a1f",
229
- "reference": "0b9838c4f75ee41bc390357b0350e9a62e3b3a1f",
230
  "shasum": ""
231
  },
232
  "require": {
233
- "league/flysystem": "~1.0",
234
- "microsoft/azure-storage": "~0.10.1",
235
- "php": ">=5.5.0"
236
  },
237
  "require-dev": {
238
- "mockery/mockery": "~0.9",
239
- "phpunit/phpunit": "~4.0"
 
240
  },
241
- "time": "2016-07-10T19:08:39+00:00",
 
 
 
242
  "type": "library",
243
  "extra": {
244
  "branch-alias": {
245
- "dev-master": "1.0-dev"
246
  }
247
  },
248
- "installation-source": "dist",
249
  "autoload": {
 
 
 
250
  "psr-4": {
251
- "League\\Flysystem\\Azure\\": "src/"
252
  }
253
  },
254
  "notification-url": "https://packagist.org/downloads/",
@@ -257,50 +296,58 @@
257
  ],
258
  "authors": [
259
  {
260
- "name": "Frank de Jonge",
261
- "email": "info@frenky.net"
 
262
  }
263
  ],
264
- "description": "Flysystem adapter for Windows Azure"
 
 
 
 
 
 
 
 
 
 
265
  },
266
  {
267
- "name": "mtdowling/jmespath.php",
268
- "version": "2.4.0",
269
- "version_normalized": "2.4.0.0",
270
  "source": {
271
  "type": "git",
272
- "url": "https://github.com/jmespath/jmespath.php.git",
273
- "reference": "adcc9531682cf87dfda21e1fd5d0e7a41d292fac"
274
  },
275
  "dist": {
276
  "type": "zip",
277
- "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/adcc9531682cf87dfda21e1fd5d0e7a41d292fac",
278
- "reference": "adcc9531682cf87dfda21e1fd5d0e7a41d292fac",
279
  "shasum": ""
280
  },
281
  "require": {
282
- "php": ">=5.4.0"
283
  },
284
  "require-dev": {
285
- "phpunit/phpunit": "~4.0"
286
  },
287
- "time": "2016-12-03T22:08:25+00:00",
288
- "bin": [
289
- "bin/jp.php"
290
- ],
291
  "type": "library",
292
  "extra": {
293
  "branch-alias": {
294
- "dev-master": "2.0-dev"
295
  }
296
  },
297
  "installation-source": "dist",
298
  "autoload": {
299
  "psr-4": {
300
- "JmesPath\\": "src/"
301
  },
302
  "files": [
303
- "src/JmesPath.php"
304
  ]
305
  },
306
  "notification-url": "https://packagist.org/downloads/",
@@ -314,309 +361,298 @@
314
  "homepage": "https://github.com/mtdowling"
315
  }
316
  ],
317
- "description": "Declaratively specify how to extract elements from a JSON document",
318
  "keywords": [
319
- "json",
320
- "jsonpath"
321
  ]
322
  },
323
  {
324
- "name": "sabre/uri",
325
- "version": "1.2.1",
326
- "version_normalized": "1.2.1.0",
327
  "source": {
328
  "type": "git",
329
- "url": "https://github.com/sabre-io/uri.git",
330
- "reference": "ada354d83579565949d80b2e15593c2371225e61"
331
  },
332
  "dist": {
333
  "type": "zip",
334
- "url": "https://api.github.com/repos/sabre-io/uri/zipball/ada354d83579565949d80b2e15593c2371225e61",
335
- "reference": "ada354d83579565949d80b2e15593c2371225e61",
336
  "shasum": ""
337
  },
338
  "require": {
339
- "php": ">=5.4.7"
 
 
 
 
340
  },
341
  "require-dev": {
342
- "phpunit/phpunit": ">=4.0,<6.0",
343
- "sabre/cs": "~1.0.0"
344
  },
345
- "time": "2017-02-20T19:59:28+00:00",
346
  "type": "library",
347
- "installation-source": "dist",
 
 
 
 
 
348
  "autoload": {
349
- "files": [
350
- "lib/functions.php"
351
- ],
352
  "psr-4": {
353
- "Sabre\\Uri\\": "lib/"
354
- }
 
 
 
355
  },
356
  "notification-url": "https://packagist.org/downloads/",
357
  "license": [
358
- "BSD-3-Clause"
359
  ],
360
  "authors": [
361
  {
362
- "name": "Evert Pot",
363
- "email": "me@evertpot.com",
364
- "homepage": "http://evertpot.com/",
365
- "role": "Developer"
 
 
 
366
  }
367
  ],
368
- "description": "Functions for making sense out of URIs.",
369
- "homepage": "http://sabre.io/uri/",
370
  "keywords": [
371
- "rfc3986",
 
 
 
 
372
  "uri",
373
  "url"
374
  ]
375
  },
376
  {
377
- "name": "sabre/xml",
378
- "version": "1.5.0",
379
- "version_normalized": "1.5.0.0",
380
  "source": {
381
  "type": "git",
382
- "url": "https://github.com/sabre-io/xml.git",
383
- "reference": "59b20e5bbace9912607481634f97d05a776ffca7"
384
  },
385
  "dist": {
386
  "type": "zip",
387
- "url": "https://api.github.com/repos/sabre-io/xml/zipball/59b20e5bbace9912607481634f97d05a776ffca7",
388
- "reference": "59b20e5bbace9912607481634f97d05a776ffca7",
389
  "shasum": ""
390
  },
391
  "require": {
392
- "ext-dom": "*",
393
- "ext-xmlreader": "*",
394
- "ext-xmlwriter": "*",
395
- "lib-libxml": ">=2.6.20",
396
- "php": ">=5.5.5",
397
- "sabre/uri": ">=1.0,<3.0.0"
398
  },
399
  "require-dev": {
400
- "phpunit/phpunit": "*",
401
- "sabre/cs": "~1.0.0"
 
402
  },
403
- "time": "2016-10-09T22:57:52+00:00",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
404
  "type": "library",
405
- "installation-source": "dist",
 
 
 
 
 
406
  "autoload": {
407
  "psr-4": {
408
- "Sabre\\Xml\\": "lib/"
409
- },
410
- "files": [
411
- "lib/Deserializer/functions.php",
412
- "lib/Serializer/functions.php"
413
- ]
414
  },
415
  "notification-url": "https://packagist.org/downloads/",
416
  "license": [
417
- "BSD-3-Clause"
418
  ],
419
  "authors": [
420
  {
421
- "name": "Evert Pot",
422
- "email": "me@evertpot.com",
423
- "homepage": "http://evertpot.com/",
424
- "role": "Developer"
425
- },
426
- {
427
- "name": "Markus Staab",
428
- "email": "markus.staab@redaxo.de",
429
- "role": "Developer"
430
  }
431
  ],
432
- "description": "sabre/xml is an XML library that you may not hate.",
433
- "homepage": "https://sabre.io/xml/",
434
  "keywords": [
435
- "XMLReader",
436
- "XMLWriter",
437
- "dom",
438
- "xml"
 
 
 
 
 
 
 
 
 
 
 
 
 
439
  ]
440
  },
441
  {
442
- "name": "sabre/event",
443
- "version": "3.0.0",
444
- "version_normalized": "3.0.0.0",
445
  "source": {
446
  "type": "git",
447
- "url": "https://github.com/sabre-io/event.git",
448
- "reference": "831d586f5a442dceacdcf5e9c4c36a4db99a3534"
449
  },
450
  "dist": {
451
  "type": "zip",
452
- "url": "https://api.github.com/repos/sabre-io/event/zipball/831d586f5a442dceacdcf5e9c4c36a4db99a3534",
453
- "reference": "831d586f5a442dceacdcf5e9c4c36a4db99a3534",
454
  "shasum": ""
455
  },
456
  "require": {
457
- "php": ">=5.5"
 
 
458
  },
459
  "require-dev": {
460
- "phpunit/phpunit": "*",
461
- "sabre/cs": "~0.0.4"
462
  },
463
- "time": "2015-11-05T20:14:39+00:00",
464
  "type": "library",
465
- "installation-source": "dist",
 
 
 
 
 
466
  "autoload": {
467
  "psr-4": {
468
- "Sabre\\Event\\": "lib/"
469
- },
470
- "files": [
471
- "lib/coroutine.php",
472
- "lib/Loop/functions.php",
473
- "lib/Promise/functions.php"
474
- ]
475
  },
476
  "notification-url": "https://packagist.org/downloads/",
477
  "license": [
478
- "BSD-3-Clause"
479
  ],
480
  "authors": [
481
  {
482
- "name": "Evert Pot",
483
- "email": "me@evertpot.com",
484
- "homepage": "http://evertpot.com/",
485
- "role": "Developer"
486
  }
487
  ],
488
- "description": "sabre/event is a library for lightweight event-based programming",
489
- "homepage": "http://sabre.io/event/",
490
- "keywords": [
491
- "EventEmitter",
492
- "async",
493
- "events",
494
- "hooks",
495
- "plugin",
496
- "promise",
497
- "signal"
498
- ]
499
  },
500
  {
501
- "name": "sabre/dav",
502
- "version": "3.2.2",
503
- "version_normalized": "3.2.2.0",
504
  "source": {
505
  "type": "git",
506
- "url": "https://github.com/sabre-io/dav.git",
507
- "reference": "e987775e619728f12205606c9cc3ee565ffb1516"
508
  },
509
  "dist": {
510
  "type": "zip",
511
- "url": "https://api.github.com/repos/sabre-io/dav/zipball/e987775e619728f12205606c9cc3ee565ffb1516",
512
- "reference": "e987775e619728f12205606c9cc3ee565ffb1516",
513
  "shasum": ""
514
  },
515
  "require": {
516
- "ext-ctype": "*",
517
- "ext-date": "*",
518
- "ext-dom": "*",
519
- "ext-iconv": "*",
520
- "ext-mbstring": "*",
521
- "ext-pcre": "*",
522
- "ext-simplexml": "*",
523
- "ext-spl": "*",
524
- "lib-libxml": ">=2.7.0",
525
- "php": ">=5.5.0",
526
- "psr/log": "^1.0",
527
- "sabre/event": ">=2.0.0, <4.0.0",
528
- "sabre/http": "^4.2.1",
529
- "sabre/uri": "^1.0.1",
530
- "sabre/vobject": "^4.1.0",
531
- "sabre/xml": "^1.4.0"
532
  },
533
  "require-dev": {
534
- "evert/phpdoc-md": "~0.1.0",
535
- "monolog/monolog": "^1.18",
536
- "phpunit/phpunit": "> 4.8, <6.0.0",
537
- "sabre/cs": "^1.0.0"
538
- },
539
- "suggest": {
540
- "ext-curl": "*",
541
- "ext-pdo": "*"
542
  },
543
- "time": "2017-02-15T03:06:08+00:00",
544
- "bin": [
545
- "bin/sabredav",
546
- "bin/naturalselection"
547
- ],
548
  "type": "library",
549
  "extra": {
550
  "branch-alias": {
551
- "dev-master": "3.1.0-dev"
552
  }
553
  },
554
  "installation-source": "dist",
555
  "autoload": {
556
  "psr-4": {
557
- "Sabre\\DAV\\": "lib/DAV/",
558
- "Sabre\\DAVACL\\": "lib/DAVACL/",
559
- "Sabre\\CalDAV\\": "lib/CalDAV/",
560
- "Sabre\\CardDAV\\": "lib/CardDAV/"
561
  }
562
  },
563
  "notification-url": "https://packagist.org/downloads/",
564
  "license": [
565
- "BSD-3-Clause"
566
  ],
567
  "authors": [
568
  {
569
- "name": "Evert Pot",
570
- "email": "me@evertpot.com",
571
- "homepage": "http://evertpot.com/",
572
- "role": "Developer"
573
  }
574
  ],
575
- "description": "WebDAV Framework for PHP",
576
- "homepage": "http://sabre.io/",
577
- "keywords": [
578
- "CalDAV",
579
- "CardDAV",
580
- "WebDAV",
581
- "framework",
582
- "iCalendar"
583
- ]
584
  },
585
  {
586
- "name": "league/flysystem-webdav",
587
- "version": "1.0.5",
588
- "version_normalized": "1.0.5.0",
589
  "source": {
590
  "type": "git",
591
- "url": "https://github.com/thephpleague/flysystem-webdav.git",
592
- "reference": "5fb6f5a45e5f2a5519a26032d98ad7d7c65f81d7"
593
  },
594
  "dist": {
595
  "type": "zip",
596
- "url": "https://api.github.com/repos/thephpleague/flysystem-webdav/zipball/5fb6f5a45e5f2a5519a26032d98ad7d7c65f81d7",
597
- "reference": "5fb6f5a45e5f2a5519a26032d98ad7d7c65f81d7",
598
  "shasum": ""
599
  },
600
  "require": {
601
  "league/flysystem": "~1.0",
602
- "php": ">=5.5.0",
603
- "sabre/dav": "~3.1"
604
  },
605
  "require-dev": {
606
- "mockery/mockery": "~0.9",
607
  "phpunit/phpunit": "~4.0"
608
  },
609
- "time": "2016-12-14T11:28:55+00:00",
610
  "type": "library",
611
  "extra": {
612
  "branch-alias": {
613
  "dev-master": "1.0-dev"
614
  }
615
  },
616
- "installation-source": "dist",
617
  "autoload": {
618
  "psr-4": {
619
- "League\\Flysystem\\WebDAV\\": "src"
620
  }
621
  },
622
  "notification-url": "https://packagist.org/downloads/",
@@ -629,43 +665,43 @@
629
  "email": "info@frenky.net"
630
  }
631
  ],
632
- "description": "Flysystem adapter for WebDAV"
633
  },
634
  {
635
- "name": "league/flysystem-sftp",
636
- "version": "1.0.14",
637
- "version_normalized": "1.0.14.0",
638
  "source": {
639
  "type": "git",
640
- "url": "https://github.com/thephpleague/flysystem-sftp.git",
641
- "reference": "f28d742a3e81258417293fd9a179a350154ab8f7"
642
  },
643
  "dist": {
644
  "type": "zip",
645
- "url": "https://api.github.com/repos/thephpleague/flysystem-sftp/zipball/f28d742a3e81258417293fd9a179a350154ab8f7",
646
- "reference": "f28d742a3e81258417293fd9a179a350154ab8f7",
647
  "shasum": ""
648
  },
649
  "require": {
650
  "league/flysystem": "~1.0",
651
- "php": ">=5.4.0",
652
- "phpseclib/phpseclib": "~2.0"
653
  },
654
  "require-dev": {
655
- "mockery/mockery": "0.9.*",
656
  "phpunit/phpunit": "~4.0"
657
  },
658
- "time": "2017-07-11T12:29:45+00:00",
659
  "type": "library",
660
  "extra": {
661
  "branch-alias": {
662
  "dev-master": "1.0-dev"
663
  }
664
  },
665
- "installation-source": "source",
666
  "autoload": {
667
  "psr-4": {
668
- "League\\Flysystem\\Sftp\\": "src/"
669
  }
670
  },
671
  "notification-url": "https://packagist.org/downloads/",
@@ -678,47 +714,41 @@
678
  "email": "info@frenky.net"
679
  }
680
  ],
681
- "description": "Flysystem adapter for SFTP"
682
  },
683
  {
684
- "name": "phpseclib/phpseclib",
685
- "version": "2.0.11",
686
- "version_normalized": "2.0.11.0",
687
  "source": {
688
  "type": "git",
689
- "url": "https://github.com/phpseclib/phpseclib.git",
690
- "reference": "7053f06f91b3de78e143d430e55a8f7889efc08b"
691
  },
692
  "dist": {
693
  "type": "zip",
694
- "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/7053f06f91b3de78e143d430e55a8f7889efc08b",
695
- "reference": "7053f06f91b3de78e143d430e55a8f7889efc08b",
696
  "shasum": ""
697
  },
698
  "require": {
699
- "php": ">=5.3.3"
 
 
 
 
700
  },
701
  "require-dev": {
702
- "phing/phing": "~2.7",
703
- "phpunit/phpunit": "^4.8.35|^5.7|^6.0",
704
- "sami/sami": "~2.0",
705
- "squizlabs/php_codesniffer": "~2.0"
706
- },
707
- "suggest": {
708
- "ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.",
709
- "ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.",
710
- "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.",
711
- "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations."
712
  },
713
- "time": "2018-04-15T16:55:05+00:00",
714
  "type": "library",
715
  "installation-source": "source",
716
  "autoload": {
717
- "files": [
718
- "phpseclib/bootstrap.php"
719
- ],
720
  "psr-4": {
721
- "phpseclib\\": "phpseclib/"
722
  }
723
  },
724
  "notification-url": "https://packagist.org/downloads/",
@@ -727,155 +757,130 @@
727
  ],
728
  "authors": [
729
  {
730
- "name": "Jim Wigginton",
731
- "email": "terrafrost@php.net",
732
- "role": "Lead Developer"
733
- },
734
- {
735
- "name": "Patrick Monnerat",
736
- "email": "pm@datasphere.ch",
737
- "role": "Developer"
738
- },
739
- {
740
- "name": "Andreas Fischer",
741
- "email": "bantu@phpbb.com",
742
- "role": "Developer"
743
- },
744
- {
745
- "name": "Hans-Jürgen Petrich",
746
- "email": "petrich@tronic-media.com",
747
- "role": "Developer"
748
- },
749
- {
750
- "name": "Graham Campbell",
751
- "email": "graham@alt-three.com",
752
  "role": "Developer"
753
  }
754
  ],
755
- "description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.",
756
- "homepage": "http://phpseclib.sourceforge.net",
757
  "keywords": [
758
- "BigInteger",
759
- "aes",
760
- "asn.1",
761
- "asn1",
762
- "blowfish",
763
- "crypto",
764
- "cryptography",
765
- "encryption",
766
- "rsa",
767
- "security",
768
- "sftp",
769
- "signature",
770
- "signing",
771
- "ssh",
772
- "twofish",
773
- "x.509",
774
- "x509"
775
  ]
776
  },
777
  {
778
- "name": "components/jquery",
779
- "version": "3.3.1",
780
- "version_normalized": "3.3.1.0",
781
  "source": {
782
  "type": "git",
783
- "url": "https://github.com/components/jquery.git",
784
- "reference": "459648cda77875519c5da3ae1dd0ed5d170aa649"
785
  },
786
  "dist": {
787
  "type": "zip",
788
- "url": "https://api.github.com/repos/components/jquery/zipball/459648cda77875519c5da3ae1dd0ed5d170aa649",
789
- "reference": "459648cda77875519c5da3ae1dd0ed5d170aa649",
790
  "shasum": ""
791
  },
792
- "time": "2018-03-04T13:23:48+00:00",
793
- "type": "component",
794
- "extra": {
795
- "component": {
796
- "scripts": [
797
- "jquery.js"
798
- ],
799
- "files": [
800
- "jquery.min.js",
801
- "jquery.min.map",
802
- "jquery.slim.js",
803
- "jquery.slim.min.js",
804
- "jquery.slim.min.map"
805
- ]
 
 
 
 
 
 
 
 
 
 
 
806
  }
807
  },
808
- "installation-source": "source",
809
  "notification-url": "https://packagist.org/downloads/",
810
  "license": [
811
  "MIT"
812
  ],
813
  "authors": [
814
  {
815
- "name": "JS Foundation and other contributors"
 
816
  }
817
  ],
818
- "description": "jQuery JavaScript Library",
819
- "homepage": "http://jquery.com"
 
 
 
 
 
 
820
  },
821
  {
822
- "name": "vakata/jstree",
823
- "version": "3.3.5",
824
- "version_normalized": "3.3.5.0",
825
  "source": {
826
  "type": "git",
827
- "url": "https://github.com/vakata/jstree.git",
828
- "reference": "0097fab41981daf36c234b73b683166daabd5f28"
829
  },
830
  "dist": {
831
  "type": "zip",
832
- "url": "https://api.github.com/repos/vakata/jstree/zipball/0097fab41981daf36c234b73b683166daabd5f28",
833
- "reference": "0097fab41981daf36c234b73b683166daabd5f28",
834
  "shasum": ""
835
  },
836
  "require": {
837
- "components/jquery": ">=1.9.1"
838
  },
839
- "suggest": {
840
- "robloach/component-installer": "Allows installation of Components via Composer"
841
  },
842
- "time": "2018-01-02T08:13:23+00:00",
843
- "type": "component",
844
  "extra": {
845
- "component": {
846
- "scripts": [
847
- "dist/jstree.js"
848
- ],
849
- "styles": [
850
- "dist/themes/default/style.css"
851
- ],
852
- "images": [
853
- "dist/themes/default/32px.png",
854
- "dist/themes/default/40px.png",
855
- "dist/themes/default/throbber.gif"
856
- ],
857
- "files": [
858
- "dist/jstree.min.js",
859
- "dist/themes/default/style.min.css",
860
- "dist/themes/default/32px.png",
861
- "dist/themes/default/40px.png",
862
- "dist/themes/default/throbber.gif"
863
- ]
864
  }
865
  },
866
  "installation-source": "source",
 
 
 
 
 
867
  "notification-url": "https://packagist.org/downloads/",
868
  "license": [
869
- "MIT"
870
  ],
871
  "authors": [
872
  {
873
- "name": "Ivan Bozhanov",
874
- "email": "jstree@jstree.com"
 
875
  }
876
  ],
877
- "description": "jsTree is jquery plugin, that provides interactive trees.",
878
- "homepage": "http://jstree.com"
879
  },
880
  {
881
  "name": "monolog/monolog",
@@ -958,44 +963,43 @@
958
  ]
959
  },
960
  {
961
- "name": "guzzlehttp/psr7",
962
- "version": "1.4.2",
963
- "version_normalized": "1.4.2.0",
964
  "source": {
965
  "type": "git",
966
- "url": "https://github.com/guzzle/psr7.git",
967
- "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c"
968
  },
969
  "dist": {
970
  "type": "zip",
971
- "url": "https://api.github.com/repos/guzzle/psr7/zipball/f5b8a8512e2b58b0071a7280e39f14f72e05d87c",
972
- "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c",
973
  "shasum": ""
974
  },
975
  "require": {
976
- "php": ">=5.4.0",
977
- "psr/http-message": "~1.0"
978
- },
979
- "provide": {
980
- "psr/http-message-implementation": "1.0"
981
  },
982
  "require-dev": {
983
  "phpunit/phpunit": "~4.0"
984
  },
985
- "time": "2017-03-20T17:10:46+00:00",
 
 
 
986
  "type": "library",
987
  "extra": {
988
  "branch-alias": {
989
- "dev-master": "1.4-dev"
990
  }
991
  },
992
- "installation-source": "source",
993
  "autoload": {
994
  "psr-4": {
995
- "GuzzleHttp\\Psr7\\": "src/"
996
  },
997
  "files": [
998
- "src/functions_include.php"
999
  ]
1000
  },
1001
  "notification-url": "https://packagist.org/downloads/",
@@ -1007,66 +1011,45 @@
1007
  "name": "Michael Dowling",
1008
  "email": "mtdowling@gmail.com",
1009
  "homepage": "https://github.com/mtdowling"
1010
- },
1011
- {
1012
- "name": "Tobias Schultze",
1013
- "homepage": "https://github.com/Tobion"
1014
  }
1015
  ],
1016
- "description": "PSR-7 message implementation that also provides common utility methods",
1017
  "keywords": [
1018
- "http",
1019
- "message",
1020
- "request",
1021
- "response",
1022
- "stream",
1023
- "uri",
1024
- "url"
1025
  ]
1026
  },
1027
  {
1028
- "name": "guzzlehttp/guzzle",
1029
- "version": "6.3.3",
1030
- "version_normalized": "6.3.3.0",
1031
  "source": {
1032
  "type": "git",
1033
- "url": "https://github.com/guzzle/guzzle.git",
1034
- "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba"
1035
  },
1036
  "dist": {
1037
  "type": "zip",
1038
- "url": "https://api.github.com/repos/guzzle/guzzle/zipball/407b0cb880ace85c9b63c5f9551db498cb2d50ba",
1039
- "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba",
1040
  "shasum": ""
1041
  },
1042
  "require": {
1043
- "guzzlehttp/promises": "^1.0",
1044
- "guzzlehttp/psr7": "^1.4",
1045
- "php": ">=5.5"
1046
  },
1047
  "require-dev": {
1048
- "ext-curl": "*",
1049
- "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0",
1050
- "psr/log": "^1.0"
1051
  },
1052
  "suggest": {
1053
- "psr/log": "Required for using the Log middleware"
1054
  },
1055
- "time": "2018-04-22T15:46:56+00:00",
1056
  "type": "library",
1057
- "extra": {
1058
- "branch-alias": {
1059
- "dev-master": "6.3-dev"
1060
- }
1061
- },
1062
- "installation-source": "source",
1063
  "autoload": {
1064
  "files": [
1065
- "src/functions_include.php"
1066
- ],
1067
- "psr-4": {
1068
- "GuzzleHttp\\": "src/"
1069
- }
1070
  },
1071
  "notification-url": "https://packagist.org/downloads/",
1072
  "license": [
@@ -1074,76 +1057,58 @@
1074
  ],
1075
  "authors": [
1076
  {
1077
- "name": "Michael Dowling",
1078
- "email": "mtdowling@gmail.com",
1079
- "homepage": "https://github.com/mtdowling"
1080
  }
1081
  ],
1082
- "description": "Guzzle is a PHP HTTP client library",
1083
- "homepage": "http://guzzlephp.org/",
1084
  "keywords": [
1085
- "client",
1086
- "curl",
1087
- "framework",
1088
- "http",
1089
- "http client",
1090
- "rest",
1091
- "web service"
1092
  ]
1093
  },
1094
  {
1095
- "name": "league/flysystem",
1096
- "version": "1.0.45",
1097
- "version_normalized": "1.0.45.0",
1098
  "source": {
1099
  "type": "git",
1100
- "url": "https://github.com/thephpleague/flysystem.git",
1101
- "reference": "a99f94e63b512d75f851b181afcdf0ee9ebef7e6"
1102
  },
1103
  "dist": {
1104
  "type": "zip",
1105
- "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/a99f94e63b512d75f851b181afcdf0ee9ebef7e6",
1106
- "reference": "a99f94e63b512d75f851b181afcdf0ee9ebef7e6",
1107
  "shasum": ""
1108
  },
1109
  "require": {
1110
- "php": ">=5.5.9"
1111
- },
1112
- "conflict": {
1113
- "league/flysystem-sftp": "<1.0.6"
1114
  },
1115
  "require-dev": {
1116
- "ext-fileinfo": "*",
1117
- "phpspec/phpspec": "^3.4",
1118
- "phpunit/phpunit": "^5.7"
 
1119
  },
1120
  "suggest": {
1121
- "ext-fileinfo": "Required for MimeType",
1122
- "ext-ftp": "Allows you to use FTP server storage",
1123
- "ext-openssl": "Allows you to use FTPS server storage",
1124
- "league/flysystem-aws-s3-v2": "Allows you to use S3 storage with AWS SDK v2",
1125
- "league/flysystem-aws-s3-v3": "Allows you to use S3 storage with AWS SDK v3",
1126
- "league/flysystem-azure": "Allows you to use Windows Azure Blob storage",
1127
- "league/flysystem-cached-adapter": "Flysystem adapter decorator for metadata caching",
1128
- "league/flysystem-eventable-filesystem": "Allows you to use EventableFilesystem",
1129
- "league/flysystem-rackspace": "Allows you to use Rackspace Cloud Files",
1130
- "league/flysystem-sftp": "Allows you to use SFTP server storage via phpseclib",
1131
- "league/flysystem-webdav": "Allows you to use WebDAV storage",
1132
- "league/flysystem-ziparchive": "Allows you to use ZipArchive adapter",
1133
- "spatie/flysystem-dropbox": "Allows you to use Dropbox storage",
1134
- "srmklive/flysystem-dropbox-v2": "Allows you to use Dropbox storage for PHP 5 applications"
1135
  },
1136
- "time": "2018-05-07T08:44:23+00:00",
1137
  "type": "library",
1138
- "extra": {
1139
- "branch-alias": {
1140
- "dev-master": "1.1-dev"
1141
- }
1142
- },
1143
  "installation-source": "source",
1144
  "autoload": {
 
 
 
1145
  "psr-4": {
1146
- "League\\Flysystem\\": "src/"
1147
  }
1148
  },
1149
  "notification-url": "https://packagist.org/downloads/",
@@ -1152,66 +1117,82 @@
1152
  ],
1153
  "authors": [
1154
  {
1155
- "name": "Frank de Jonge",
1156
- "email": "info@frenky.net"
1157
- }
1158
- ],
1159
- "description": "Filesystem abstraction: Many filesystems, one API.",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1160
  "keywords": [
1161
- "Cloud Files",
1162
- "WebDAV",
1163
- "abstraction",
1164
- "aws",
1165
- "cloud",
1166
- "copy.com",
1167
- "dropbox",
1168
- "file systems",
1169
- "files",
1170
- "filesystem",
1171
- "filesystems",
1172
- "ftp",
1173
- "rackspace",
1174
- "remote",
1175
- "s3",
1176
  "sftp",
1177
- "storage"
 
 
 
 
 
1178
  ]
1179
  },
1180
  {
1181
- "name": "league/flysystem-aws-s3-v3",
1182
- "version": "1.0.19",
1183
- "version_normalized": "1.0.19.0",
1184
  "source": {
1185
  "type": "git",
1186
- "url": "https://github.com/thephpleague/flysystem-aws-s3-v3.git",
1187
- "reference": "f135691ef6761542af301b7c9880f140fb12dc74"
1188
  },
1189
  "dist": {
1190
  "type": "zip",
1191
- "url": "https://api.github.com/repos/thephpleague/flysystem-aws-s3-v3/zipball/f135691ef6761542af301b7c9880f140fb12dc74",
1192
- "reference": "f135691ef6761542af301b7c9880f140fb12dc74",
1193
  "shasum": ""
1194
  },
1195
  "require": {
1196
- "aws/aws-sdk-php": "^3.0.0",
1197
- "league/flysystem": "^1.0.40",
1198
- "php": ">=5.5.0"
1199
- },
1200
- "require-dev": {
1201
- "henrikbjorn/phpspec-code-coverage": "~1.0.1",
1202
- "phpspec/phpspec": "^2.0.0"
1203
  },
1204
- "time": "2018-03-27T20:33:59+00:00",
1205
  "type": "library",
1206
  "extra": {
1207
  "branch-alias": {
1208
- "dev-master": "1.0-dev"
1209
  }
1210
  },
1211
- "installation-source": "source",
1212
  "autoload": {
1213
  "psr-4": {
1214
- "League\\Flysystem\\AwsS3v3\\": "src/"
1215
  }
1216
  },
1217
  "notification-url": "https://packagist.org/downloads/",
@@ -1220,88 +1201,50 @@
1220
  ],
1221
  "authors": [
1222
  {
1223
- "name": "Frank de Jonge",
1224
- "email": "info@frenky.net"
1225
  }
1226
  ],
1227
- "description": "Flysystem adapter for the AWS S3 SDK v3.x"
 
 
 
 
 
 
 
 
 
1228
  },
1229
  {
1230
- "name": "mikey179/vfsStream",
1231
- "version": "v1.6.5",
1232
- "version_normalized": "1.6.5.0",
1233
  "source": {
1234
  "type": "git",
1235
- "url": "https://github.com/mikey179/vfsStream.git",
1236
- "reference": "d5fec95f541d4d71c4823bb5e30cf9b9e5b96145"
1237
  },
1238
  "dist": {
1239
  "type": "zip",
1240
- "url": "https://api.github.com/repos/mikey179/vfsStream/zipball/d5fec95f541d4d71c4823bb5e30cf9b9e5b96145",
1241
- "reference": "d5fec95f541d4d71c4823bb5e30cf9b9e5b96145",
1242
  "shasum": ""
1243
  },
1244
  "require": {
1245
  "php": ">=5.3.0"
1246
  },
1247
- "require-dev": {
1248
- "phpunit/phpunit": "~4.5"
1249
- },
1250
- "time": "2017-08-01T08:02:14+00:00",
1251
  "type": "library",
1252
  "extra": {
1253
  "branch-alias": {
1254
- "dev-master": "1.6.x-dev"
1255
- }
1256
- },
1257
- "installation-source": "source",
1258
- "autoload": {
1259
- "psr-0": {
1260
- "org\\bovigo\\vfs\\": "src/main/php"
1261
- }
1262
- },
1263
- "notification-url": "https://packagist.org/downloads/",
1264
- "license": [
1265
- "BSD-3-Clause"
1266
- ],
1267
- "authors": [
1268
- {
1269
- "name": "Frank Kleine",
1270
- "homepage": "http://frankkleine.de/",
1271
- "role": "Developer"
1272
  }
1273
- ],
1274
- "description": "Virtual file system to mock the real file system in unit tests.",
1275
- "homepage": "http://vfs.bovigo.org/"
1276
- },
1277
- {
1278
- "name": "gliterd/backblaze-b2",
1279
- "version": "0.0.3",
1280
- "version_normalized": "0.0.3.0",
1281
- "source": {
1282
- "type": "git",
1283
- "url": "https://github.com/gliterd/backblaze-b2.git",
1284
- "reference": "eeaedb198fe10e0fb7d94ffaa9aa6ab207d7e9c6"
1285
- },
1286
- "dist": {
1287
- "type": "zip",
1288
- "url": "https://api.github.com/repos/gliterd/backblaze-b2/zipball/eeaedb198fe10e0fb7d94ffaa9aa6ab207d7e9c6",
1289
- "reference": "eeaedb198fe10e0fb7d94ffaa9aa6ab207d7e9c6",
1290
- "shasum": ""
1291
  },
1292
- "require": {
1293
- "guzzlehttp/guzzle": "^6.1",
1294
- "php": ">=5.5.0"
1295
- },
1296
- "require-dev": {
1297
- "phpunit/phpunit": "4.8.*"
1298
- },
1299
- "time": "2017-08-09T13:57:57+00:00",
1300
- "type": "library",
1301
- "installation-source": "source",
1302
  "autoload": {
1303
  "psr-4": {
1304
- "BackblazeB2\\": "src/"
1305
  }
1306
  },
1307
  "notification-url": "https://packagist.org/downloads/",
@@ -1310,131 +1253,160 @@
1310
  ],
1311
  "authors": [
1312
  {
1313
- "name": "Ramesh Mhetre",
1314
- "email": "mhetreramesh@gmail.com",
1315
- "homepage": "https://gliterd.com",
1316
- "role": "Developer"
1317
  }
1318
  ],
1319
- "description": "PHP SDK for working with backblaze B2 cloud storage.",
1320
- "homepage": "https://github.com/gliterd/b2-sdk-php",
1321
  "keywords": [
1322
- "b2",
1323
- "backblaze",
1324
- "backup",
1325
- "cloud",
1326
- "cloud-storage",
1327
- "filesystem",
1328
- "storage"
1329
  ]
1330
  },
1331
  {
1332
- "name": "cwhite92/b2-sdk-php",
1333
- "version": "v1.3.0",
1334
- "version_normalized": "1.3.0.0",
1335
  "source": {
1336
  "type": "git",
1337
- "url": "https://github.com/cwhite92/b2-sdk-php.git",
1338
- "reference": "68c054af3c857f08506e9ee9f3c017972cb6bee8"
1339
  },
1340
  "dist": {
1341
  "type": "zip",
1342
- "url": "https://api.github.com/repos/cwhite92/b2-sdk-php/zipball/68c054af3c857f08506e9ee9f3c017972cb6bee8",
1343
- "reference": "68c054af3c857f08506e9ee9f3c017972cb6bee8",
1344
  "shasum": ""
1345
  },
1346
  "require": {
1347
- "guzzlehttp/guzzle": "^6.1",
1348
- "php": ">=5.5.0"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1349
  },
1350
  "require-dev": {
1351
- "phpunit/phpunit": "4.8.*"
 
 
 
 
 
 
 
1352
  },
1353
- "time": "2016-08-24T13:31:19+00:00",
 
 
 
 
1354
  "type": "library",
1355
- "installation-source": "source",
 
 
 
 
 
1356
  "autoload": {
1357
  "psr-4": {
1358
- "ChrisWhite\\B2\\": "src/"
 
 
 
1359
  }
1360
  },
1361
  "notification-url": "https://packagist.org/downloads/",
1362
  "license": [
1363
- "MIT"
1364
  ],
1365
  "authors": [
1366
  {
1367
- "name": "Chris White",
1368
- "email": "chris@cwhite.me",
1369
- "homepage": "https://cwhite.me"
 
1370
  }
1371
  ],
1372
- "description": "A SDK for working with B2 cloud storage.",
1373
- "homepage": "https://github.com/cwhite92/b2-sdk-php",
1374
  "keywords": [
1375
- "b2",
1376
- "backblaze",
1377
- "backup",
1378
- "cloud",
1379
- "filesystem",
1380
- "storage"
1381
  ]
1382
  },
1383
  {
1384
- "name": "mhetreramesh/flysystem-backblaze",
1385
- "version": "1.0.10",
1386
- "version_normalized": "1.0.10.0",
1387
  "source": {
1388
  "type": "git",
1389
- "url": "https://github.com/gliterd/flysystem-backblaze.git",
1390
- "reference": "3f753cbce283edc9774a62c10690699533a7b86e"
1391
  },
1392
  "dist": {
1393
  "type": "zip",
1394
- "url": "https://api.github.com/repos/gliterd/flysystem-backblaze/zipball/3f753cbce283edc9774a62c10690699533a7b86e",
1395
- "reference": "3f753cbce283edc9774a62c10690699533a7b86e",
1396
- "shasum": ""
1397
- },
1398
- "require": {
1399
- "cwhite92/b2-sdk-php": "^1.2",
1400
- "gliterd/backblaze-b2": "*",
1401
- "league/flysystem": "~1.0",
1402
- "mikey179/vfsstream": "*",
1403
- "php": ">=5.5.0"
1404
  },
1405
  "require-dev": {
1406
- "phpunit/phpunit": "~4.0||~5.0",
1407
- "scrutinizer/ocular": "~1.1",
1408
- "squizlabs/php_codesniffer": "~2.3"
1409
  },
1410
- "time": "2017-12-20T16:10:51+00:00",
1411
  "type": "library",
1412
- "installation-source": "source",
1413
  "autoload": {
1414
  "psr-4": {
1415
- "Mhetreramesh\\Flysystem\\": "src"
1416
- }
 
 
 
 
 
1417
  },
1418
  "notification-url": "https://packagist.org/downloads/",
1419
  "license": [
1420
- "MIT"
1421
  ],
1422
  "authors": [
1423
  {
1424
- "name": "Ramesh Mhetre",
1425
- "email": "mhetreramesh@gmail.com",
1426
- "homepage": "https://about.me/rameshmhetre",
1427
  "role": "Developer"
1428
  }
1429
  ],
1430
- "description": "Backblaze adapter for the flysystem filesystem abstraction library",
1431
- "homepage": "https://github.com/mhetreramesh/flysystem-backblaze",
1432
  "keywords": [
1433
- "Flysystem",
1434
- "api",
1435
- "backblaze",
1436
- "client",
1437
- "filesystem"
 
 
1438
  ]
1439
  },
1440
  {
@@ -1495,6 +1467,59 @@
1495
  "http"
1496
  ]
1497
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1498
  {
1499
  "name": "sabre/vobject",
1500
  "version": "4.1.6",
@@ -1594,6 +1619,71 @@
1594
  "xCard"
1595
  ]
1596
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1597
  {
1598
  "name": "splitbrain/php-archive",
1599
  "version": "1.0.10",
@@ -1702,85 +1792,62 @@
1702
  ]
1703
  },
1704
  {
1705
- "name": "aws/aws-sdk-php",
1706
- "version": "3.56.5",
1707
- "version_normalized": "3.56.5.0",
1708
  "source": {
1709
  "type": "git",
1710
- "url": "https://github.com/aws/aws-sdk-php.git",
1711
- "reference": "d5b8f10a6e51174fab6a0222e1f0dfae2323e75d"
1712
  },
1713
  "dist": {
1714
  "type": "zip",
1715
- "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/d5b8f10a6e51174fab6a0222e1f0dfae2323e75d",
1716
- "reference": "d5b8f10a6e51174fab6a0222e1f0dfae2323e75d",
1717
  "shasum": ""
1718
  },
1719
  "require": {
1720
- "ext-json": "*",
1721
- "ext-pcre": "*",
1722
- "ext-simplexml": "*",
1723
- "ext-spl": "*",
1724
- "guzzlehttp/guzzle": "^5.3.1|^6.2.1",
1725
- "guzzlehttp/promises": "~1.0",
1726
- "guzzlehttp/psr7": "^1.4.1",
1727
- "mtdowling/jmespath.php": "~2.2",
1728
- "php": ">=5.5"
1729
- },
1730
- "require-dev": {
1731
- "andrewsville/php-token-reflection": "^1.4",
1732
- "aws/aws-php-sns-message-validator": "~1.0",
1733
- "behat/behat": "~3.0",
1734
- "doctrine/cache": "~1.4",
1735
- "ext-dom": "*",
1736
- "ext-openssl": "*",
1737
- "nette/neon": "^2.3",
1738
- "phpunit/phpunit": "^4.8.35|^5.4.3",
1739
- "psr/cache": "^1.0"
1740
  },
1741
  "suggest": {
1742
- "aws/aws-php-sns-message-validator": "To validate incoming SNS notifications",
1743
- "doctrine/cache": "To use the DoctrineCacheAdapter",
1744
- "ext-curl": "To send requests using cURL",
1745
- "ext-openssl": "Allows working with CloudFront private distributions and verifying received SNS messages"
1746
  },
1747
- "time": "2018-05-21T20:15:18+00:00",
1748
- "type": "library",
1749
  "extra": {
1750
- "branch-alias": {
1751
- "dev-master": "3.0-dev"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1752
  }
1753
  },
1754
  "installation-source": "source",
1755
- "autoload": {
1756
- "psr-4": {
1757
- "Aws\\": "src/"
1758
- },
1759
- "files": [
1760
- "src/functions.php"
1761
- ]
1762
- },
1763
  "notification-url": "https://packagist.org/downloads/",
1764
  "license": [
1765
- "Apache-2.0"
1766
  ],
1767
  "authors": [
1768
  {
1769
- "name": "Amazon Web Services",
1770
- "homepage": "http://aws.amazon.com"
1771
  }
1772
  ],
1773
- "description": "AWS SDK for PHP - Use Amazon Web Services in your PHP project",
1774
- "homepage": "http://aws.amazon.com/sdkforphp",
1775
- "keywords": [
1776
- "amazon",
1777
- "aws",
1778
- "cloud",
1779
- "dynamodb",
1780
- "ec2",
1781
- "glacier",
1782
- "s3",
1783
- "sdk"
1784
- ]
1785
  }
1786
  ]
1
  [
2
  {
3
+ "name": "aws/aws-sdk-php",
4
+ "version": "3.56.5",
5
+ "version_normalized": "3.56.5.0",
6
  "source": {
7
  "type": "git",
8
+ "url": "https://github.com/aws/aws-sdk-php.git",
9
+ "reference": "d5b8f10a6e51174fab6a0222e1f0dfae2323e75d"
10
  },
11
  "dist": {
12
  "type": "zip",
13
+ "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/d5b8f10a6e51174fab6a0222e1f0dfae2323e75d",
14
+ "reference": "d5b8f10a6e51174fab6a0222e1f0dfae2323e75d",
15
  "shasum": ""
16
  },
17
  "require": {
18
+ "ext-json": "*",
19
+ "ext-pcre": "*",
20
+ "ext-simplexml": "*",
21
+ "ext-spl": "*",
22
+ "guzzlehttp/guzzle": "^5.3.1|^6.2.1",
23
+ "guzzlehttp/promises": "~1.0",
24
+ "guzzlehttp/psr7": "^1.4.1",
25
+ "mtdowling/jmespath.php": "~2.2",
26
+ "php": ">=5.5"
27
  },
28
+ "require-dev": {
29
+ "andrewsville/php-token-reflection": "^1.4",
30
+ "aws/aws-php-sns-message-validator": "~1.0",
31
+ "behat/behat": "~3.0",
32
+ "doctrine/cache": "~1.4",
33
+ "ext-dom": "*",
34
+ "ext-openssl": "*",
35
+ "nette/neon": "^2.3",
36
+ "phpunit/phpunit": "^4.8.35|^5.4.3",
37
+ "psr/cache": "^1.0"
38
+ },
39
+ "suggest": {
40
+ "aws/aws-php-sns-message-validator": "To validate incoming SNS notifications",
41
+ "doctrine/cache": "To use the DoctrineCacheAdapter",
42
+ "ext-curl": "To send requests using cURL",
43
+ "ext-openssl": "Allows working with CloudFront private distributions and verifying received SNS messages"
44
+ },
45
+ "time": "2018-05-21T20:15:18+00:00",
46
  "type": "library",
47
  "extra": {
48
  "branch-alias": {
49
+ "dev-master": "3.0-dev"
50
  }
51
  },
52
+ "installation-source": "source",
53
  "autoload": {
54
  "psr-4": {
55
+ "Aws\\": "src/"
56
+ },
57
+ "files": [
58
+ "src/functions.php"
59
+ ]
60
  },
61
  "notification-url": "https://packagist.org/downloads/",
62
  "license": [
63
+ "Apache-2.0"
64
  ],
65
  "authors": [
66
  {
67
+ "name": "Amazon Web Services",
68
+ "homepage": "http://aws.amazon.com"
69
  }
70
  ],
71
+ "description": "AWS SDK for PHP - Use Amazon Web Services in your PHP project",
72
+ "homepage": "http://aws.amazon.com/sdkforphp",
73
  "keywords": [
74
+ "amazon",
75
+ "aws",
76
+ "cloud",
77
+ "dynamodb",
78
+ "ec2",
79
+ "glacier",
80
+ "s3",
81
+ "sdk"
82
  ]
83
  },
84
  {
85
+ "name": "components/jquery",
86
+ "version": "3.3.1",
87
+ "version_normalized": "3.3.1.0",
88
  "source": {
89
  "type": "git",
90
+ "url": "https://github.com/components/jquery.git",
91
+ "reference": "459648cda77875519c5da3ae1dd0ed5d170aa649"
92
  },
93
  "dist": {
94
  "type": "zip",
95
+ "url": "https://api.github.com/repos/components/jquery/zipball/459648cda77875519c5da3ae1dd0ed5d170aa649",
96
+ "reference": "459648cda77875519c5da3ae1dd0ed5d170aa649",
97
  "shasum": ""
98
  },
99
+ "time": "2018-03-04T13:23:48+00:00",
100
+ "type": "component",
 
 
 
 
 
 
101
  "extra": {
102
+ "component": {
103
+ "scripts": [
104
+ "jquery.js"
105
+ ],
106
+ "files": [
107
+ "jquery.min.js",
108
+ "jquery.min.map",
109
+ "jquery.slim.js",
110
+ "jquery.slim.min.js",
111
+ "jquery.slim.min.map"
112
+ ]
113
  }
114
  },
115
+ "installation-source": "source",
 
 
 
 
 
 
 
 
116
  "notification-url": "https://packagist.org/downloads/",
117
  "license": [
118
  "MIT"
119
  ],
120
  "authors": [
121
  {
122
+ "name": "JS Foundation and other contributors"
 
 
123
  }
124
  ],
125
+ "description": "jQuery JavaScript Library",
126
+ "homepage": "http://jquery.com"
 
 
127
  },
128
  {
129
+ "name": "defuse/php-encryption",
130
+ "version": "v2.2.0",
131
+ "version_normalized": "2.2.0.0",
132
  "source": {
133
  "type": "git",
134
+ "url": "https://github.com/defuse/php-encryption.git",
135
+ "reference": "0d4d27c368ca6798bc162469e43248c363c73495"
136
  },
137
  "dist": {
138
  "type": "zip",
139
+ "url": "https://api.github.com/repos/defuse/php-encryption/zipball/0d4d27c368ca6798bc162469e43248c363c73495",
140
+ "reference": "0d4d27c368ca6798bc162469e43248c363c73495",
141
  "shasum": ""
142
  },
143
  "require": {
144
+ "ext-openssl": "*",
145
+ "paragonie/random_compat": "~2.0",
146
+ "php": ">=5.4.0"
147
  },
148
+ "require-dev": {
149
+ "nikic/php-parser": "^2.0|^3.0|^4.0",
150
+ "phpunit/phpunit": "^4|^5"
 
 
 
151
  },
152
+ "time": "2018-04-23T19:33:40+00:00",
153
+ "bin": [
154
+ "bin/generate-defuse-key"
155
+ ],
156
+ "type": "library",
157
  "installation-source": "dist",
158
  "autoload": {
159
  "psr-4": {
160
+ "Defuse\\Crypto\\": "src"
161
  }
162
  },
163
  "notification-url": "https://packagist.org/downloads/",
166
  ],
167
  "authors": [
168
  {
169
+ "name": "Taylor Hornby",
170
+ "email": "taylor@defuse.ca",
171
+ "homepage": "https://defuse.ca/"
172
+ },
173
+ {
174
+ "name": "Scott Arciszewski",
175
+ "email": "info@paragonie.com",
176
+ "homepage": "https://paragonie.com"
177
  }
178
  ],
179
+ "description": "Secure PHP Encryption Library",
 
180
  "keywords": [
181
+ "aes",
182
+ "authenticated encryption",
183
+ "cipher",
184
+ "crypto",
185
+ "cryptography",
186
+ "encrypt",
187
+ "encryption",
188
+ "openssl",
189
+ "security",
190
+ "symmetric key cryptography"
191
  ]
192
  },
193
  {
194
+ "name": "gliterd/backblaze-b2",
195
+ "version": "1.0.4",
196
+ "version_normalized": "1.0.4.0",
197
  "source": {
198
  "type": "git",
199
+ "url": "https://github.com/gliterd/backblaze-b2.git",
200
+ "reference": "5427b10b93b0ba24f06f80623b502c7d1d7fcd72"
201
  },
202
  "dist": {
203
  "type": "zip",
204
+ "url": "https://api.github.com/repos/gliterd/backblaze-b2/zipball/5427b10b93b0ba24f06f80623b502c7d1d7fcd72",
205
+ "reference": "5427b10b93b0ba24f06f80623b502c7d1d7fcd72",
206
  "shasum": ""
207
  },
208
  "require": {
209
+ "guzzlehttp/guzzle": "^6.1",
210
  "php": ">=5.5.0"
211
  },
212
  "require-dev": {
213
+ "phpunit/phpunit": "4.8.*",
214
+ "scrutinizer/ocular": "~1.1",
215
+ "squizlabs/php_codesniffer": "~2.3"
 
 
 
 
 
216
  },
217
+ "time": "2018-07-03T11:52:32+00:00",
218
  "type": "library",
219
+ "installation-source": "source",
 
 
 
 
 
220
  "autoload": {
221
  "psr-4": {
222
+ "BackblazeB2\\": "src/"
223
  }
224
  },
225
  "notification-url": "https://packagist.org/downloads/",
228
  ],
229
  "authors": [
230
  {
231
+ "name": "Ramesh Mhetre",
232
+ "email": "mhetreramesh@gmail.com",
233
+ "homepage": "https://gliterd.com",
234
+ "role": "Developer"
235
  }
236
  ],
237
+ "description": "PHP SDK for working with backblaze B2 cloud storage.",
238
+ "homepage": "https://github.com/gliterd/b2-sdk-php",
239
  "keywords": [
240
+ "b2",
241
+ "backblaze",
242
+ "backup",
243
+ "cloud",
244
+ "cloud-storage",
245
+ "filesystem",
246
  "storage"
247
+ ]
 
248
  },
249
  {
250
+ "name": "guzzlehttp/guzzle",
251
+ "version": "6.3.3",
252
+ "version_normalized": "6.3.3.0",
253
  "source": {
254
  "type": "git",
255
+ "url": "https://github.com/guzzle/guzzle.git",
256
+ "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba"
257
  },
258
  "dist": {
259
  "type": "zip",
260
+ "url": "https://api.github.com/repos/guzzle/guzzle/zipball/407b0cb880ace85c9b63c5f9551db498cb2d50ba",
261
+ "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba",
262
  "shasum": ""
263
  },
264
  "require": {
265
+ "guzzlehttp/promises": "^1.0",
266
+ "guzzlehttp/psr7": "^1.4",
267
+ "php": ">=5.5"
268
  },
269
  "require-dev": {
270
+ "ext-curl": "*",
271
+ "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0",
272
+ "psr/log": "^1.0"
273
  },
274
+ "suggest": {
275
+ "psr/log": "Required for using the Log middleware"
276
+ },
277
+ "time": "2018-04-22T15:46:56+00:00",
278
  "type": "library",
279
  "extra": {
280
  "branch-alias": {
281
+ "dev-master": "6.3-dev"
282
  }
283
  },
284
+ "installation-source": "source",
285
  "autoload": {
286
+ "files": [
287
+ "src/functions_include.php"
288
+ ],
289
  "psr-4": {
290
+ "GuzzleHttp\\": "src/"
291
  }
292
  },
293
  "notification-url": "https://packagist.org/downloads/",
296
  ],
297
  "authors": [
298
  {
299
+ "name": "Michael Dowling",
300
+ "email": "mtdowling@gmail.com",
301
+ "homepage": "https://github.com/mtdowling"
302
  }
303
  ],
304
+ "description": "Guzzle is a PHP HTTP client library",
305
+ "homepage": "http://guzzlephp.org/",
306
+ "keywords": [
307
+ "client",
308
+ "curl",
309
+ "framework",
310
+ "http",
311
+ "http client",
312
+ "rest",
313
+ "web service"
314
+ ]
315
  },
316
  {
317
+ "name": "guzzlehttp/promises",
318
+ "version": "v1.3.1",
319
+ "version_normalized": "1.3.1.0",
320
  "source": {
321
  "type": "git",
322
+ "url": "https://github.com/guzzle/promises.git",
323
+ "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646"
324
  },
325
  "dist": {
326
  "type": "zip",
327
+ "url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646",
328
+ "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646",
329
  "shasum": ""
330
  },
331
  "require": {
332
+ "php": ">=5.5.0"
333
  },
334
  "require-dev": {
335
+ "phpunit/phpunit": "^4.0"
336
  },
337
+ "time": "2016-12-20T10:07:11+00:00",
 
 
 
338
  "type": "library",
339
  "extra": {
340
  "branch-alias": {
341
+ "dev-master": "1.4-dev"
342
  }
343
  },
344
  "installation-source": "dist",
345
  "autoload": {
346
  "psr-4": {
347
+ "GuzzleHttp\\Promise\\": "src/"
348
  },
349
  "files": [
350
+ "src/functions_include.php"
351
  ]
352
  },
353
  "notification-url": "https://packagist.org/downloads/",
361
  "homepage": "https://github.com/mtdowling"
362
  }
363
  ],
364
+ "description": "Guzzle promises library",
365
  "keywords": [
366
+ "promise"
 
367
  ]
368
  },
369
  {
370
+ "name": "guzzlehttp/psr7",
371
+ "version": "1.4.2",
372
+ "version_normalized": "1.4.2.0",
373
  "source": {
374
  "type": "git",
375
+ "url": "https://github.com/guzzle/psr7.git",
376
+ "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c"
377
  },
378
  "dist": {
379
  "type": "zip",
380
+ "url": "https://api.github.com/repos/guzzle/psr7/zipball/f5b8a8512e2b58b0071a7280e39f14f72e05d87c",
381
+ "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c",
382
  "shasum": ""
383
  },
384
  "require": {
385
+ "php": ">=5.4.0",
386
+ "psr/http-message": "~1.0"
387
+ },
388
+ "provide": {
389
+ "psr/http-message-implementation": "1.0"
390
  },
391
  "require-dev": {
392
+ "phpunit/phpunit": "~4.0"
 
393
  },
394
+ "time": "2017-03-20T17:10:46+00:00",
395
  "type": "library",
396
+ "extra": {
397
+ "branch-alias": {
398
+ "dev-master": "1.4-dev"
399
+ }
400
+ },
401
+ "installation-source": "source",
402
  "autoload": {
 
 
 
403
  "psr-4": {
404
+ "GuzzleHttp\\Psr7\\": "src/"
405
+ },
406
+ "files": [
407
+ "src/functions_include.php"
408
+ ]
409
  },
410
  "notification-url": "https://packagist.org/downloads/",
411
  "license": [
412
+ "MIT"
413
  ],
414
  "authors": [
415
  {
416
+ "name": "Michael Dowling",
417
+ "email": "mtdowling@gmail.com",
418
+ "homepage": "https://github.com/mtdowling"
419
+ },
420
+ {
421
+ "name": "Tobias Schultze",
422
+ "homepage": "https://github.com/Tobion"
423
  }
424
  ],
425
+ "description": "PSR-7 message implementation that also provides common utility methods",
 
426
  "keywords": [
427
+ "http",
428
+ "message",
429
+ "request",
430
+ "response",
431
+ "stream",
432
  "uri",
433
  "url"
434
  ]
435
  },
436
  {
437
+ "name": "league/flysystem",
438
+ "version": "1.0.45",
439
+ "version_normalized": "1.0.45.0",
440
  "source": {
441
  "type": "git",
442
+ "url": "https://github.com/thephpleague/flysystem.git",
443
+ "reference": "a99f94e63b512d75f851b181afcdf0ee9ebef7e6"
444
  },
445
  "dist": {
446
  "type": "zip",
447
+ "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/a99f94e63b512d75f851b181afcdf0ee9ebef7e6",
448
+ "reference": "a99f94e63b512d75f851b181afcdf0ee9ebef7e6",
449
  "shasum": ""
450
  },
451
  "require": {
452
+ "php": ">=5.5.9"
453
+ },
454
+ "conflict": {
455
+ "league/flysystem-sftp": "<1.0.6"
 
 
456
  },
457
  "require-dev": {
458
+ "ext-fileinfo": "*",
459
+ "phpspec/phpspec": "^3.4",
460
+ "phpunit/phpunit": "^5.7"
461
  },
462
+ "suggest": {
463
+ "ext-fileinfo": "Required for MimeType",
464
+ "ext-ftp": "Allows you to use FTP server storage",
465
+ "ext-openssl": "Allows you to use FTPS server storage",
466
+ "league/flysystem-aws-s3-v2": "Allows you to use S3 storage with AWS SDK v2",
467
+ "league/flysystem-aws-s3-v3": "Allows you to use S3 storage with AWS SDK v3",
468
+ "league/flysystem-azure": "Allows you to use Windows Azure Blob storage",
469
+ "league/flysystem-cached-adapter": "Flysystem adapter decorator for metadata caching",
470
+ "league/flysystem-eventable-filesystem": "Allows you to use EventableFilesystem",
471
+ "league/flysystem-rackspace": "Allows you to use Rackspace Cloud Files",
472
+ "league/flysystem-sftp": "Allows you to use SFTP server storage via phpseclib",
473
+ "league/flysystem-webdav": "Allows you to use WebDAV storage",
474
+ "league/flysystem-ziparchive": "Allows you to use ZipArchive adapter",
475
+ "spatie/flysystem-dropbox": "Allows you to use Dropbox storage",
476
+ "srmklive/flysystem-dropbox-v2": "Allows you to use Dropbox storage for PHP 5 applications"
477
+ },
478
+ "time": "2018-05-07T08:44:23+00:00",
479
  "type": "library",
480
+ "extra": {
481
+ "branch-alias": {
482
+ "dev-master": "1.1-dev"
483
+ }
484
+ },
485
+ "installation-source": "source",
486
  "autoload": {
487
  "psr-4": {
488
+ "League\\Flysystem\\": "src/"
489
+ }
 
 
 
 
490
  },
491
  "notification-url": "https://packagist.org/downloads/",
492
  "license": [
493
+ "MIT"
494
  ],
495
  "authors": [
496
  {
497
+ "name": "Frank de Jonge",
498
+ "email": "info@frenky.net"
 
 
 
 
 
 
 
499
  }
500
  ],
501
+ "description": "Filesystem abstraction: Many filesystems, one API.",
 
502
  "keywords": [
503
+ "Cloud Files",
504
+ "WebDAV",
505
+ "abstraction",
506
+ "aws",
507
+ "cloud",
508
+ "copy.com",
509
+ "dropbox",
510
+ "file systems",
511
+ "files",
512
+ "filesystem",
513
+ "filesystems",
514
+ "ftp",
515
+ "rackspace",
516
+ "remote",
517
+ "s3",
518
+ "sftp",
519
+ "storage"
520
  ]
521
  },
522
  {
523
+ "name": "league/flysystem-aws-s3-v3",
524
+ "version": "1.0.19",
525
+ "version_normalized": "1.0.19.0",
526
  "source": {
527
  "type": "git",
528
+ "url": "https://github.com/thephpleague/flysystem-aws-s3-v3.git",
529
+ "reference": "f135691ef6761542af301b7c9880f140fb12dc74"
530
  },
531
  "dist": {
532
  "type": "zip",
533
+ "url": "https://api.github.com/repos/thephpleague/flysystem-aws-s3-v3/zipball/f135691ef6761542af301b7c9880f140fb12dc74",
534
+ "reference": "f135691ef6761542af301b7c9880f140fb12dc74",
535
  "shasum": ""
536
  },
537
  "require": {
538
+ "aws/aws-sdk-php": "^3.0.0",
539
+ "league/flysystem": "^1.0.40",
540
+ "php": ">=5.5.0"
541
  },
542
  "require-dev": {
543
+ "henrikbjorn/phpspec-code-coverage": "~1.0.1",
544
+ "phpspec/phpspec": "^2.0.0"
545
  },
546
+ "time": "2018-03-27T20:33:59+00:00",
547
  "type": "library",
548
+ "extra": {
549
+ "branch-alias": {
550
+ "dev-master": "1.0-dev"
551
+ }
552
+ },
553
+ "installation-source": "source",
554
  "autoload": {
555
  "psr-4": {
556
+ "League\\Flysystem\\AwsS3v3\\": "src/"
557
+ }
 
 
 
 
 
558
  },
559
  "notification-url": "https://packagist.org/downloads/",
560
  "license": [
561
+ "MIT"
562
  ],
563
  "authors": [
564
  {
565
+ "name": "Frank de Jonge",
566
+ "email": "info@frenky.net"
 
 
567
  }
568
  ],
569
+ "description": "Flysystem adapter for the AWS S3 SDK v3.x"
 
 
 
 
 
 
 
 
 
 
570
  },
571
  {
572
+ "name": "league/flysystem-azure",
573
+ "version": "1.0.4",
574
+ "version_normalized": "1.0.4.0",
575
  "source": {
576
  "type": "git",
577
+ "url": "https://github.com/thephpleague/flysystem-azure.git",
578
+ "reference": "0b9838c4f75ee41bc390357b0350e9a62e3b3a1f"
579
  },
580
  "dist": {
581
  "type": "zip",
582
+ "url": "https://api.github.com/repos/thephpleague/flysystem-azure/zipball/0b9838c4f75ee41bc390357b0350e9a62e3b3a1f",
583
+ "reference": "0b9838c4f75ee41bc390357b0350e9a62e3b3a1f",
584
  "shasum": ""
585
  },
586
  "require": {
587
+ "league/flysystem": "~1.0",
588
+ "microsoft/azure-storage": "~0.10.1",
589
+ "php": ">=5.5.0"
 
 
 
 
 
 
 
 
 
 
 
 
 
590
  },
591
  "require-dev": {
592
+ "mockery/mockery": "~0.9",
593
+ "phpunit/phpunit": "~4.0"
 
 
 
 
 
 
594
  },
595
+ "time": "2016-07-10T19:08:39+00:00",
 
 
 
 
596
  "type": "library",
597
  "extra": {
598
  "branch-alias": {
599
+ "dev-master": "1.0-dev"
600
  }
601
  },
602
  "installation-source": "dist",
603
  "autoload": {
604
  "psr-4": {
605
+ "League\\Flysystem\\Azure\\": "src/"
 
 
 
606
  }
607
  },
608
  "notification-url": "https://packagist.org/downloads/",
609
  "license": [
610
+ "MIT"
611
  ],
612
  "authors": [
613
  {
614
+ "name": "Frank de Jonge",
615
+ "email": "info@frenky.net"
 
 
616
  }
617
  ],
618
+ "description": "Flysystem adapter for Windows Azure",
619
+ "abandoned": "league/flysystem-azure-blob-storage"
 
 
 
 
 
 
 
620
  },
621
  {
622
+ "name": "league/flysystem-sftp",
623
+ "version": "1.0.14",
624
+ "version_normalized": "1.0.14.0",
625
  "source": {
626
  "type": "git",
627
+ "url": "https://github.com/thephpleague/flysystem-sftp.git",
628
+ "reference": "f28d742a3e81258417293fd9a179a350154ab8f7"
629
  },
630
  "dist": {
631
  "type": "zip",
632
+ "url": "https://api.github.com/repos/thephpleague/flysystem-sftp/zipball/f28d742a3e81258417293fd9a179a350154ab8f7",
633
+ "reference": "f28d742a3e81258417293fd9a179a350154ab8f7",
634
  "shasum": ""
635
  },
636
  "require": {
637
  "league/flysystem": "~1.0",
638
+ "php": ">=5.4.0",
639
+ "phpseclib/phpseclib": "~2.0"
640
  },
641
  "require-dev": {
642
+ "mockery/mockery": "0.9.*",
643
  "phpunit/phpunit": "~4.0"
644
  },
645
+ "time": "2017-07-11T12:29:45+00:00",
646
  "type": "library",
647
  "extra": {
648
  "branch-alias": {
649
  "dev-master": "1.0-dev"
650
  }
651
  },
652
+ "installation-source": "source",
653
  "autoload": {
654
  "psr-4": {
655
+ "League\\Flysystem\\Sftp\\": "src/"
656
  }
657
  },
658
  "notification-url": "https://packagist.org/downloads/",
665
  "email": "info@frenky.net"
666
  }
667
  ],
668
+ "description": "Flysystem adapter for SFTP"
669
  },
670
  {
671
+ "name": "league/flysystem-webdav",
672
+ "version": "1.0.5",
673
+ "version_normalized": "1.0.5.0",
674
  "source": {
675
  "type": "git",
676
+ "url": "https://github.com/thephpleague/flysystem-webdav.git",
677
+ "reference": "5fb6f5a45e5f2a5519a26032d98ad7d7c65f81d7"
678
  },
679
  "dist": {
680
  "type": "zip",
681
+ "url": "https://api.github.com/repos/thephpleague/flysystem-webdav/zipball/5fb6f5a45e5f2a5519a26032d98ad7d7c65f81d7",
682
+ "reference": "5fb6f5a45e5f2a5519a26032d98ad7d7c65f81d7",
683
  "shasum": ""
684
  },
685
  "require": {
686
  "league/flysystem": "~1.0",
687
+ "php": ">=5.5.0",
688
+ "sabre/dav": "~3.1"
689
  },
690
  "require-dev": {
691
+ "mockery/mockery": "~0.9",
692
  "phpunit/phpunit": "~4.0"
693
  },
694
+ "time": "2016-12-14T11:28:55+00:00",
695
  "type": "library",
696
  "extra": {
697
  "branch-alias": {
698
  "dev-master": "1.0-dev"
699
  }
700
  },
701
+ "installation-source": "dist",
702
  "autoload": {
703
  "psr-4": {
704
+ "League\\Flysystem\\WebDAV\\": "src"
705
  }
706
  },
707
  "notification-url": "https://packagist.org/downloads/",
714
  "email": "info@frenky.net"
715
  }
716
  ],
717
+ "description": "Flysystem adapter for WebDAV"
718
  },
719
  {
720
+ "name": "mhetreramesh/flysystem-backblaze",
721
+ "version": "1.1.4",
722
+ "version_normalized": "1.1.4.0",
723
  "source": {
724
  "type": "git",
725
+ "url": "https://github.com/gliterd/flysystem-backblaze.git",
726
+ "reference": "bce0372dfe40baa1e16b54e93c3400a568059070"
727
  },
728
  "dist": {
729
  "type": "zip",
730
+ "url": "https://api.github.com/repos/gliterd/flysystem-backblaze/zipball/bce0372dfe40baa1e16b54e93c3400a568059070",
731
+ "reference": "bce0372dfe40baa1e16b54e93c3400a568059070",
732
  "shasum": ""
733
  },
734
  "require": {
735
+ "gliterd/backblaze-b2": "*",
736
+ "league/flysystem": "~1.0",
737
+ "mikey179/vfsstream": "*",
738
+ "php": ">=5.6.0",
739
+ "psr/http-message-implementation": "*"
740
  },
741
  "require-dev": {
742
+ "phpunit/phpunit": "~4.0||~5.0",
743
+ "scrutinizer/ocular": "~1.1",
744
+ "squizlabs/php_codesniffer": "~2.3"
 
 
 
 
 
 
 
745
  },
746
+ "time": "2018-06-29T12:06:41+00:00",
747
  "type": "library",
748
  "installation-source": "source",
749
  "autoload": {
 
 
 
750
  "psr-4": {
751
+ "Mhetreramesh\\Flysystem\\": "src"
752
  }
753
  },
754
  "notification-url": "https://packagist.org/downloads/",
757
  ],
758
  "authors": [
759
  {
760
+ "name": "Ramesh Mhetre",
761
+ "email": "mhetreramesh@gmail.com",
762
+ "homepage": "https://about.me/rameshmhetre",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
763
  "role": "Developer"
764
  }
765
  ],
766
+ "description": "Backblaze adapter for the flysystem filesystem abstraction library",
767
+ "homepage": "https://github.com/mhetreramesh/flysystem-backblaze",
768
  "keywords": [
769
+ "Flysystem",
770
+ "api",
771
+ "backblaze",
772
+ "client",
773
+ "filesystem"
 
 
 
 
 
 
 
 
 
 
 
 
774
  ]
775
  },
776
  {
777
+ "name": "microsoft/azure-storage",
778
+ "version": "v0.10.2",
779
+ "version_normalized": "0.10.2.0",
780
  "source": {
781
  "type": "git",
782
+ "url": "https://github.com/Azure/azure-storage-php.git",
783
+ "reference": "27de05b00c1858d6e1c6adbc489efa90e0342f82"
784
  },
785
  "dist": {
786
  "type": "zip",
787
+ "url": "https://api.github.com/repos/Azure/azure-storage-php/zipball/27de05b00c1858d6e1c6adbc489efa90e0342f82",
788
+ "reference": "27de05b00c1858d6e1c6adbc489efa90e0342f82",
789
  "shasum": ""
790
  },
791
+ "require": {
792
+ "guzzlehttp/guzzle": "~6.0",
793
+ "php": ">=5.5.0"
794
+ },
795
+ "require-dev": {
796
+ "mikey179/vfsstream": "~1.6",
797
+ "pdepend/pdepend": "~2.2",
798
+ "phploc/phploc": "~2.1",
799
+ "phpmd/phpmd": "@stable",
800
+ "phpunit/phpunit": "~4.0",
801
+ "sebastian/phpcpd": "~2.0",
802
+ "squizlabs/php_codesniffer": "2.*",
803
+ "theseer/phpdox": "~0.8"
804
+ },
805
+ "time": "2016-08-19T08:32:57+00:00",
806
+ "type": "library",
807
+ "extra": {
808
+ "branch-alias": {
809
+ "dev-master": "0.10.x-dev"
810
+ }
811
+ },
812
+ "installation-source": "dist",
813
+ "autoload": {
814
+ "psr-4": {
815
+ "MicrosoftAzure\\Storage\\": "src/"
816
  }
817
  },
 
818
  "notification-url": "https://packagist.org/downloads/",
819
  "license": [
820
  "MIT"
821
  ],
822
  "authors": [
823
  {
824
+ "name": "Azure Storage PHP SDK",
825
+ "email": "dmsh@microsoft.com"
826
  }
827
  ],
828
+ "description": "This project provides a set of PHP client libraries that make it easy to access Microsoft Azure storage APIs.",
829
+ "keywords": [
830
+ "azure",
831
+ "php",
832
+ "sdk",
833
+ "storage"
834
+ ],
835
+ "abandoned": "microsoft/azure-storage-blob, microsoft/azure-storage-table, microsoft/azure-storage-queue, microsoft/azure-storage-file"
836
  },
837
  {
838
+ "name": "mikey179/vfsStream",
839
+ "version": "v1.6.5",
840
+ "version_normalized": "1.6.5.0",
841
  "source": {
842
  "type": "git",
843
+ "url": "https://github.com/mikey179/vfsStream.git",
844
+ "reference": "d5fec95f541d4d71c4823bb5e30cf9b9e5b96145"
845
  },
846
  "dist": {
847
  "type": "zip",
848
+ "url": "https://api.github.com/repos/mikey179/vfsStream/zipball/d5fec95f541d4d71c4823bb5e30cf9b9e5b96145",
849
+ "reference": "d5fec95f541d4d71c4823bb5e30cf9b9e5b96145",
850
  "shasum": ""
851
  },
852
  "require": {
853
+ "php": ">=5.3.0"
854
  },
855
+ "require-dev": {
856
+ "phpunit/phpunit": "~4.5"
857
  },
858
+ "time": "2017-08-01T08:02:14+00:00",
859
+ "type": "library",
860
  "extra": {
861
+ "branch-alias": {
862
+ "dev-master": "1.6.x-dev"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
863
  }
864
  },
865
  "installation-source": "source",
866
+ "autoload": {
867
+ "psr-0": {
868
+ "org\\bovigo\\vfs\\": "src/main/php"
869
+ }
870
+ },
871
  "notification-url": "https://packagist.org/downloads/",
872
  "license": [
873
+ "BSD-3-Clause"
874
  ],
875
  "authors": [
876
  {
877
+ "name": "Frank Kleine",
878
+ "homepage": "http://frankkleine.de/",
879
+ "role": "Developer"
880
  }
881
  ],
882
+ "description": "Virtual file system to mock the real file system in unit tests.",
883
+ "homepage": "http://vfs.bovigo.org/"
884
  },
885
  {
886
  "name": "monolog/monolog",
963
  ]
964
  },
965
  {
966
+ "name": "mtdowling/jmespath.php",
967
+ "version": "2.4.0",
968
+ "version_normalized": "2.4.0.0",
969
  "source": {
970
  "type": "git",
971
+ "url": "https://github.com/jmespath/jmespath.php.git",
972
+ "reference": "adcc9531682cf87dfda21e1fd5d0e7a41d292fac"
973
  },
974
  "dist": {
975
  "type": "zip",
976
+ "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/adcc9531682cf87dfda21e1fd5d0e7a41d292fac",
977
+ "reference": "adcc9531682cf87dfda21e1fd5d0e7a41d292fac",
978
  "shasum": ""
979
  },
980
  "require": {
981
+ "php": ">=5.4.0"
 
 
 
 
982
  },
983
  "require-dev": {
984
  "phpunit/phpunit": "~4.0"
985
  },
986
+ "time": "2016-12-03T22:08:25+00:00",
987
+ "bin": [
988
+ "bin/jp.php"
989
+ ],
990
  "type": "library",
991
  "extra": {
992
  "branch-alias": {
993
+ "dev-master": "2.0-dev"
994
  }
995
  },
996
+ "installation-source": "dist",
997
  "autoload": {
998
  "psr-4": {
999
+ "JmesPath\\": "src/"
1000
  },
1001
  "files": [
1002
+ "src/JmesPath.php"
1003
  ]
1004
  },
1005
  "notification-url": "https://packagist.org/downloads/",
1011
  "name": "Michael Dowling",
1012
  "email": "mtdowling@gmail.com",
1013
  "homepage": "https://github.com/mtdowling"
 
 
 
 
1014
  }
1015
  ],
1016
+ "description": "Declaratively specify how to extract elements from a JSON document",
1017
  "keywords": [
1018
+ "json",
1019
+ "jsonpath"
 
 
 
 
 
1020
  ]
1021
  },
1022
  {
1023
+ "name": "paragonie/random_compat",
1024
+ "version": "v2.0.15",
1025
+ "version_normalized": "2.0.15.0",
1026
  "source": {
1027
  "type": "git",
1028
+ "url": "https://github.com/paragonie/random_compat.git",
1029
+ "reference": "10bcb46e8f3d365170f6de9d05245aa066b81f09"
1030
  },
1031
  "dist": {
1032
  "type": "zip",
1033
+ "url": "https://api.github.com/repos/paragonie/random_compat/zipball/10bcb46e8f3d365170f6de9d05245aa066b81f09",
1034
+ "reference": "10bcb46e8f3d365170f6de9d05245aa066b81f09",
1035
  "shasum": ""
1036
  },
1037
  "require": {
1038
+ "php": ">=5.2.0"
 
 
1039
  },
1040
  "require-dev": {
1041
+ "phpunit/phpunit": "4.*|5.*"
 
 
1042
  },
1043
  "suggest": {
1044
+ "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
1045
  },
1046
+ "time": "2018-06-08T15:26:40+00:00",
1047
  "type": "library",
1048
+ "installation-source": "dist",
 
 
 
 
 
1049
  "autoload": {
1050
  "files": [
1051
+ "lib/random.php"
1052
+ ]
 
 
 
1053
  },
1054
  "notification-url": "https://packagist.org/downloads/",
1055
  "license": [
1057
  ],
1058
  "authors": [
1059
  {
1060
+ "name": "Paragon Initiative Enterprises",
1061
+ "email": "security@paragonie.com",
1062
+ "homepage": "https://paragonie.com"
1063
  }
1064
  ],
1065
+ "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
 
1066
  "keywords": [
1067
+ "csprng",
1068
+ "polyfill",
1069
+ "pseudorandom",
1070
+ "random"
 
 
 
1071
  ]
1072
  },
1073
  {
1074
+ "name": "phpseclib/phpseclib",
1075
+ "version": "2.0.11",
1076
+ "version_normalized": "2.0.11.0",
1077
  "source": {
1078
  "type": "git",
1079
+ "url": "https://github.com/phpseclib/phpseclib.git",
1080
+ "reference": "7053f06f91b3de78e143d430e55a8f7889efc08b"
1081
  },
1082
  "dist": {
1083
  "type": "zip",
1084
+ "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/7053f06f91b3de78e143d430e55a8f7889efc08b",
1085
+ "reference": "7053f06f91b3de78e143d430e55a8f7889efc08b",
1086
  "shasum": ""
1087
  },
1088
  "require": {
1089
+ "php": ">=5.3.3"
 
 
 
1090
  },
1091
  "require-dev": {
1092
+ "phing/phing": "~2.7",
1093
+ "phpunit/phpunit": "^4.8.35|^5.7|^6.0",
1094
+ "sami/sami": "~2.0",
1095
+ "squizlabs/php_codesniffer": "~2.0"
1096
  },
1097
  "suggest": {
1098
+ "ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.",
1099
+ "ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.",
1100
+ "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.",
1101
+ "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations."
 
 
 
 
 
 
 
 
 
 
1102
  },
1103
+ "time": "2018-04-15T16:55:05+00:00",
1104
  "type": "library",
 
 
 
 
 
1105
  "installation-source": "source",
1106
  "autoload": {
1107
+ "files": [
1108
+ "phpseclib/bootstrap.php"
1109
+ ],
1110
  "psr-4": {
1111
+ "phpseclib\\": "phpseclib/"
1112
  }
1113
  },
1114
  "notification-url": "https://packagist.org/downloads/",
1117
  ],
1118
  "authors": [
1119
  {
1120
+ "name": "Jim Wigginton",
1121
+ "email": "terrafrost@php.net",
1122
+ "role": "Lead Developer"
1123
+ },
1124
+ {
1125
+ "name": "Patrick Monnerat",
1126
+ "email": "pm@datasphere.ch",
1127
+ "role": "Developer"
1128
+ },
1129
+ {
1130
+ "name": "Andreas Fischer",
1131
+ "email": "bantu@phpbb.com",
1132
+ "role": "Developer"
1133
+ },
1134
+ {
1135
+ "name": "Hans-Jürgen Petrich",
1136
+ "email": "petrich@tronic-media.com",
1137
+ "role": "Developer"
1138
+ },
1139
+ {
1140
+ "name": "Graham Campbell",
1141
+ "email": "graham@alt-three.com",
1142
+ "role": "Developer"
1143
+ }
1144
+ ],
1145
+ "description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.",
1146
+ "homepage": "http://phpseclib.sourceforge.net",
1147
  "keywords": [
1148
+ "BigInteger",
1149
+ "aes",
1150
+ "asn.1",
1151
+ "asn1",
1152
+ "blowfish",
1153
+ "crypto",
1154
+ "cryptography",
1155
+ "encryption",
1156
+ "rsa",
1157
+ "security",
 
 
 
 
 
1158
  "sftp",
1159
+ "signature",
1160
+ "signing",
1161
+ "ssh",
1162
+ "twofish",
1163
+ "x.509",
1164
+ "x509"
1165
  ]
1166
  },
1167
  {
1168
+ "name": "psr/http-message",
1169
+ "version": "1.0.1",
1170
+ "version_normalized": "1.0.1.0",
1171
  "source": {
1172
  "type": "git",
1173
+ "url": "https://github.com/php-fig/http-message.git",
1174
+ "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363"
1175
  },
1176
  "dist": {
1177
  "type": "zip",
1178
+ "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363",
1179
+ "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363",
1180
  "shasum": ""
1181
  },
1182
  "require": {
1183
+ "php": ">=5.3.0"
 
 
 
 
 
 
1184
  },
1185
+ "time": "2016-08-06T14:39:51+00:00",
1186
  "type": "library",
1187
  "extra": {
1188
  "branch-alias": {
1189
+ "dev-master": "1.0.x-dev"
1190
  }
1191
  },
1192
+ "installation-source": "dist",
1193
  "autoload": {
1194
  "psr-4": {
1195
+ "Psr\\Http\\Message\\": "src/"
1196
  }
1197
  },
1198
  "notification-url": "https://packagist.org/downloads/",
1201
  ],
1202
  "authors": [
1203
  {
1204
+ "name": "PHP-FIG",
1205
+ "homepage": "http://www.php-fig.org/"
1206
  }
1207
  ],
1208
+ "description": "Common interface for HTTP messages",
1209
+ "homepage": "https://github.com/php-fig/http-message",
1210
+ "keywords": [
1211
+ "http",
1212
+ "http-message",
1213
+ "psr",
1214
+ "psr-7",
1215
+ "request",
1216
+ "response"
1217
+ ]
1218
  },
1219
  {
1220
+ "name": "psr/log",
1221
+ "version": "1.0.2",
1222
+ "version_normalized": "1.0.2.0",
1223
  "source": {
1224
  "type": "git",
1225
+ "url": "https://github.com/php-fig/log.git",
1226
+ "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d"
1227
  },
1228
  "dist": {
1229
  "type": "zip",
1230
+ "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d",
1231
+ "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d",
1232
  "shasum": ""
1233
  },
1234
  "require": {
1235
  "php": ">=5.3.0"
1236
  },
1237
+ "time": "2016-10-10T12:19:37+00:00",
 
 
 
1238
  "type": "library",
1239
  "extra": {
1240
  "branch-alias": {
1241
+ "dev-master": "1.0.x-dev"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1242
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1243
  },
1244
+ "installation-source": "dist",
 
 
 
 
 
 
 
 
 
1245
  "autoload": {
1246
  "psr-4": {
1247
+ "Psr\\Log\\": "Psr/Log/"
1248
  }
1249
  },
1250
  "notification-url": "https://packagist.org/downloads/",
1253
  ],
1254
  "authors": [
1255
  {
1256
+ "name": "PHP-FIG",
1257
+ "homepage": "http://www.php-fig.org/"
 
 
1258
  }
1259
  ],
1260
+ "description": "Common interface for logging libraries",
1261
+ "homepage": "https://github.com/php-fig/log",
1262
  "keywords": [
1263
+ "log",
1264
+ "psr",
1265
+ "psr-3"
 
 
 
 
1266
  ]
1267
  },
1268
  {
1269
+ "name": "sabre/dav",
1270
+ "version": "3.2.2",
1271
+ "version_normalized": "3.2.2.0",
1272
  "source": {
1273
  "type": "git",
1274
+ "url": "https://github.com/sabre-io/dav.git",
1275
+ "reference": "e987775e619728f12205606c9cc3ee565ffb1516"
1276
  },
1277
  "dist": {
1278
  "type": "zip",
1279
+ "url": "https://api.github.com/repos/sabre-io/dav/zipball/e987775e619728f12205606c9cc3ee565ffb1516",
1280
+ "reference": "e987775e619728f12205606c9cc3ee565ffb1516",
1281
  "shasum": ""
1282
  },
1283
  "require": {
1284
+ "ext-ctype": "*",
1285
+ "ext-date": "*",
1286
+ "ext-dom": "*",
1287
+ "ext-iconv": "*",
1288
+ "ext-mbstring": "*",
1289
+ "ext-pcre": "*",
1290
+ "ext-simplexml": "*",
1291
+ "ext-spl": "*",
1292
+ "lib-libxml": ">=2.7.0",
1293
+ "php": ">=5.5.0",
1294
+ "psr/log": "^1.0",
1295
+ "sabre/event": ">=2.0.0, <4.0.0",
1296
+ "sabre/http": "^4.2.1",
1297
+ "sabre/uri": "^1.0.1",
1298
+ "sabre/vobject": "^4.1.0",
1299
+ "sabre/xml": "^1.4.0"
1300
  },
1301
  "require-dev": {
1302
+ "evert/phpdoc-md": "~0.1.0",
1303
+ "monolog/monolog": "^1.18",
1304
+ "phpunit/phpunit": "> 4.8, <6.0.0",
1305
+ "sabre/cs": "^1.0.0"
1306
+ },
1307
+ "suggest": {
1308
+ "ext-curl": "*",
1309
+ "ext-pdo": "*"
1310
  },
1311
+ "time": "2017-02-15T03:06:08+00:00",
1312
+ "bin": [
1313
+ "bin/sabredav",
1314
+ "bin/naturalselection"
1315
+ ],
1316
  "type": "library",
1317
+ "extra": {
1318
+ "branch-alias": {
1319
+ "dev-master": "3.1.0-dev"
1320
+ }
1321
+ },
1322
+ "installation-source": "dist",
1323
  "autoload": {
1324
  "psr-4": {
1325
+ "Sabre\\DAV\\": "lib/DAV/",
1326
+ "Sabre\\DAVACL\\": "lib/DAVACL/",
1327
+ "Sabre\\CalDAV\\": "lib/CalDAV/",
1328
+ "Sabre\\CardDAV\\": "lib/CardDAV/"
1329
  }
1330
  },
1331
  "notification-url": "https://packagist.org/downloads/",
1332
  "license": [
1333
+ "BSD-3-Clause"
1334
  ],
1335
  "authors": [
1336
  {
1337
+ "name": "Evert Pot",
1338
+ "email": "me@evertpot.com",
1339
+ "homepage": "http://evertpot.com/",
1340
+ "role": "Developer"
1341
  }
1342
  ],
1343
+ "description": "WebDAV Framework for PHP",
1344
+ "homepage": "http://sabre.io/",
1345
  "keywords": [
1346
+ "CalDAV",
1347
+ "CardDAV",
1348
+ "WebDAV",
1349
+ "framework",
1350
+ "iCalendar"
 
1351
  ]
1352
  },
1353
  {
1354
+ "name": "sabre/event",
1355
+ "version": "3.0.0",
1356
+ "version_normalized": "3.0.0.0",
1357
  "source": {
1358
  "type": "git",
1359
+ "url": "https://github.com/sabre-io/event.git",
1360
+ "reference": "831d586f5a442dceacdcf5e9c4c36a4db99a3534"
1361
  },
1362
  "dist": {
1363
  "type": "zip",
1364
+ "url": "https://api.github.com/repos/sabre-io/event/zipball/831d586f5a442dceacdcf5e9c4c36a4db99a3534",
1365
+ "reference": "831d586f5a442dceacdcf5e9c4c36a4db99a3534",
1366
+ "shasum": ""
1367
+ },
1368
+ "require": {
1369
+ "php": ">=5.5"
 
 
 
 
1370
  },
1371
  "require-dev": {
1372
+ "phpunit/phpunit": "*",
1373
+ "sabre/cs": "~0.0.4"
 
1374
  },
1375
+ "time": "2015-11-05T20:14:39+00:00",
1376
  "type": "library",
1377
+ "installation-source": "dist",
1378
  "autoload": {
1379
  "psr-4": {
1380
+ "Sabre\\Event\\": "lib/"
1381
+ },
1382
+ "files": [
1383
+ "lib/coroutine.php",
1384
+ "lib/Loop/functions.php",
1385
+ "lib/Promise/functions.php"
1386
+ ]
1387
  },
1388
  "notification-url": "https://packagist.org/downloads/",
1389
  "license": [
1390
+ "BSD-3-Clause"
1391
  ],
1392
  "authors": [
1393
  {
1394
+ "name": "Evert Pot",
1395
+ "email": "me@evertpot.com",
1396
+ "homepage": "http://evertpot.com/",
1397
  "role": "Developer"
1398
  }
1399
  ],
1400
+ "description": "sabre/event is a library for lightweight event-based programming",
1401
+ "homepage": "http://sabre.io/event/",
1402
  "keywords": [
1403
+ "EventEmitter",
1404
+ "async",
1405
+ "events",
1406
+ "hooks",
1407
+ "plugin",
1408
+ "promise",
1409
+ "signal"
1410
  ]
1411
  },
1412
  {
1467
  "http"
1468
  ]
1469
  },
1470
+ {
1471
+ "name": "sabre/uri",
1472
+ "version": "1.2.1",
1473
+ "version_normalized": "1.2.1.0",
1474
+ "source": {
1475
+ "type": "git",
1476
+ "url": "https://github.com/sabre-io/uri.git",
1477
+ "reference": "ada354d83579565949d80b2e15593c2371225e61"
1478
+ },
1479
+ "dist": {
1480
+ "type": "zip",
1481
+ "url": "https://api.github.com/repos/sabre-io/uri/zipball/ada354d83579565949d80b2e15593c2371225e61",
1482
+ "reference": "ada354d83579565949d80b2e15593c2371225e61",
1483
+ "shasum": ""
1484
+ },
1485
+ "require": {
1486
+ "php": ">=5.4.7"
1487
+ },
1488
+ "require-dev": {
1489
+ "phpunit/phpunit": ">=4.0,<6.0",
1490
+ "sabre/cs": "~1.0.0"
1491
+ },
1492
+ "time": "2017-02-20T19:59:28+00:00",
1493
+ "type": "library",
1494
+ "installation-source": "dist",
1495
+ "autoload": {
1496
+ "files": [
1497
+ "lib/functions.php"
1498
+ ],
1499
+ "psr-4": {
1500
+ "Sabre\\Uri\\": "lib/"
1501
+ }
1502
+ },
1503
+ "notification-url": "https://packagist.org/downloads/",
1504
+ "license": [
1505
+ "BSD-3-Clause"
1506
+ ],
1507
+ "authors": [
1508
+ {
1509
+ "name": "Evert Pot",
1510
+ "email": "me@evertpot.com",
1511
+ "homepage": "http://evertpot.com/",
1512
+ "role": "Developer"
1513
+ }
1514
+ ],
1515
+ "description": "Functions for making sense out of URIs.",
1516
+ "homepage": "http://sabre.io/uri/",
1517
+ "keywords": [
1518
+ "rfc3986",
1519
+ "uri",
1520
+ "url"
1521
+ ]
1522
+ },
1523
  {
1524
  "name": "sabre/vobject",
1525
  "version": "4.1.6",
1619
  "xCard"
1620
  ]
1621
  },
1622
+ {
1623
+ "name": "sabre/xml",
1624
+ "version": "1.5.0",
1625
+ "version_normalized": "1.5.0.0",
1626
+ "source": {
1627
+ "type": "git",
1628
+ "url": "https://github.com/sabre-io/xml.git",
1629
+ "reference": "59b20e5bbace9912607481634f97d05a776ffca7"
1630
+ },
1631
+ "dist": {
1632
+ "type": "zip",
1633
+ "url": "https://api.github.com/repos/sabre-io/xml/zipball/59b20e5bbace9912607481634f97d05a776ffca7",
1634
+ "reference": "59b20e5bbace9912607481634f97d05a776ffca7",
1635
+ "shasum": ""
1636
+ },
1637
+ "require": {
1638
+ "ext-dom": "*",
1639
+ "ext-xmlreader": "*",
1640
+ "ext-xmlwriter": "*",
1641
+ "lib-libxml": ">=2.6.20",
1642
+ "php": ">=5.5.5",
1643
+ "sabre/uri": ">=1.0,<3.0.0"
1644
+ },
1645
+ "require-dev": {
1646
+ "phpunit/phpunit": "*",
1647
+ "sabre/cs": "~1.0.0"
1648
+ },
1649
+ "time": "2016-10-09T22:57:52+00:00",
1650
+ "type": "library",
1651
+ "installation-source": "dist",
1652
+ "autoload": {
1653
+ "psr-4": {
1654
+ "Sabre\\Xml\\": "lib/"
1655
+ },
1656
+ "files": [
1657
+ "lib/Deserializer/functions.php",
1658
+ "lib/Serializer/functions.php"
1659
+ ]
1660
+ },
1661
+ "notification-url": "https://packagist.org/downloads/",
1662
+ "license": [
1663
+ "BSD-3-Clause"
1664
+ ],
1665
+ "authors": [
1666
+ {
1667
+ "name": "Evert Pot",
1668
+ "email": "me@evertpot.com",
1669
+ "homepage": "http://evertpot.com/",
1670
+ "role": "Developer"
1671
+ },
1672
+ {
1673
+ "name": "Markus Staab",
1674
+ "email": "markus.staab@redaxo.de",
1675
+ "role": "Developer"
1676
+ }
1677
+ ],
1678
+ "description": "sabre/xml is an XML library that you may not hate.",
1679
+ "homepage": "https://sabre.io/xml/",
1680
+ "keywords": [
1681
+ "XMLReader",
1682
+ "XMLWriter",
1683
+ "dom",
1684
+ "xml"
1685
+ ]
1686
+ },
1687
  {
1688
  "name": "splitbrain/php-archive",
1689
  "version": "1.0.10",
1792
  ]
1793
  },
1794
  {
1795
+ "name": "vakata/jstree",
1796
+ "version": "3.3.5",
1797
+ "version_normalized": "3.3.5.0",
1798
  "source": {
1799
  "type": "git",
1800
+ "url": "https://github.com/vakata/jstree.git",
1801
+ "reference": "0097fab41981daf36c234b73b683166daabd5f28"
1802
  },
1803
  "dist": {
1804
  "type": "zip",
1805
+ "url": "https://api.github.com/repos/vakata/jstree/zipball/0097fab41981daf36c234b73b683166daabd5f28",
1806
+ "reference": "0097fab41981daf36c234b73b683166daabd5f28",
1807
  "shasum": ""
1808
  },
1809
  "require": {
1810
+ "components/jquery": ">=1.9.1"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1811
  },
1812
  "suggest": {
1813
+ "robloach/component-installer": "Allows installation of Components via Composer"
 
 
 
1814
  },
1815
+ "time": "2018-01-02T08:13:23+00:00",
1816
+ "type": "component",
1817
  "extra": {
1818
+ "component": {
1819
+ "scripts": [
1820
+ "dist/jstree.js"
1821
+ ],
1822
+ "styles": [
1823
+ "dist/themes/default/style.css"
1824
+ ],
1825
+ "images": [
1826
+ "dist/themes/default/32px.png",
1827
+ "dist/themes/default/40px.png",
1828
+ "dist/themes/default/throbber.gif"
1829
+ ],
1830
+ "files": [
1831
+ "dist/jstree.min.js",
1832
+ "dist/themes/default/style.min.css",
1833
+ "dist/themes/default/32px.png",
1834
+ "dist/themes/default/40px.png",
1835
+ "dist/themes/default/throbber.gif"
1836
+ ]
1837
  }
1838
  },
1839
  "installation-source": "source",
 
 
 
 
 
 
 
 
1840
  "notification-url": "https://packagist.org/downloads/",
1841
  "license": [
1842
+ "MIT"
1843
  ],
1844
  "authors": [
1845
  {
1846
+ "name": "Ivan Bozhanov",
1847
+ "email": "jstree@jstree.com"
1848
  }
1849
  ],
1850
+ "description": "jsTree is jquery plugin, that provides interactive trees.",
1851
+ "homepage": "http://jstree.com"
 
 
 
 
 
 
 
 
 
 
1852
  }
1853
  ]
vendor/defuse/php-encryption/.gitignore ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ *~
2
+ /test/unit/File/big-generated-file
3
+ /composer.lock
4
+ /vendor
5
+ defuse-crypto.phar
6
+ defuse-crypto.phar.sig
7
+ composer.phar
8
+ box.phar
9
+ phpunit.phar
10
+ phpunit.phar.asc
11
+ test/unit/File/tmp
vendor/defuse/php-encryption/.php_cs ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ $config = Symfony\CS\Config\Config::create()
4
+ ->level(Symfony\CS\FixerInterface::PSR2_LEVEL)
5
+ ->fixers([
6
+ 'blankline_after_open_tag',
7
+ 'empty_return',
8
+ 'extra_empty_lines',
9
+ 'function_typehint_space',
10
+ 'join_function',
11
+ 'method_argument_default_value',
12
+ 'multiline_array_trailing_comma',
13
+ 'no_blank_lines_after_class_opening',
14
+ 'no_empty_lines_after_phpdocs',
15
+ 'phpdoc_indent',
16
+ 'phpdoc_no_access',
17
+ 'phpdoc_no_empty_return',
18
+ 'phpdoc_no_package',
19
+ 'phpdoc_params',
20
+ 'phpdoc_scalar',
21
+ 'phpdoc_separation',
22
+ 'phpdoc_trim',
23
+ 'phpdoc_type_to_var',
24
+ 'phpdoc_types',
25
+ 'phpdoc_var_without_name',
26
+ 'remove_leading_slash_use',
27
+ 'remove_lines_between_uses',
28
+ 'short_bool_cast',
29
+ 'single_quote',
30
+ 'spaces_after_semicolon',
31
+ 'spaces_before_semicolon',
32
+ 'spaces_cast',
33
+ 'standardize_not_equal',
34
+ 'ternary_spaces',
35
+ 'trim_array_spaces',
36
+ 'unneeded_control_parentheses',
37
+ 'unused_use',
38
+ 'whitespacy_lines',
39
+ 'align_double_arrow',
40
+ 'concat_with_spaces',
41
+ 'logical_not_operators_with_successor_space',
42
+ 'multiline_spaces_before_semicolon',
43
+ 'newline_after_open_tag',
44
+ 'ordered_use',
45
+ 'php_unit_construct',
46
+ 'phpdoc_order',
47
+ 'short_array_syntax',
48
+ ]);
49
+
50
+ if (null === $input->getArgument('path')) {
51
+ $config
52
+ ->finder(
53
+ Symfony\CS\Finder\DefaultFinder::create()
54
+ ->in('src')
55
+ ->in('test')
56
+ ->exclude('vendor')
57
+ );
58
+ }
59
+
60
+ return $config;
vendor/defuse/php-encryption/LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Taylor Hornby <https://defuse.ca> and Paragon Initiative
4
+ Enterprises <https://paragonie.com>.
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
7
+ this software and associated documentation files (the "Software"), to deal in
8
+ the Software without restriction, including without limitation the rights to
9
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
10
+ the Software, and to permit persons to whom the Software is furnished to do so,
11
+ subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
18
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
19
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
vendor/defuse/php-encryption/README.md ADDED
@@ -0,0 +1,102 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ php-encryption
2
+ ===============
3
+
4
+ [![Build Status](https://travis-ci.org/defuse/php-encryption.svg?branch=master)](https://travis-ci.org/defuse/php-encryption)
5
+ [![codecov](https://codecov.io/gh/defuse/php-encryption/branch/master/graph/badge.svg)](https://codecov.io/gh/defuse/php-encryption)
6
+ [![Latest Stable Version](https://poser.pugx.org/defuse/php-encryption/v/stable)](https://packagist.org/packages/defuse/php-encryption)
7
+ [![Latest Unstable Version](https://poser.pugx.org/defuse/php-encryption/v/unstable)](https://packagist.org/packages/defuse/php-encryption)
8
+ [![License](https://poser.pugx.org/defuse/php-encryption/license)](https://packagist.org/packages/defuse/php-encryption)
9
+ [![Downloads](https://img.shields.io/packagist/dt/defuse/php-encryption.svg)](https://packagist.org/packages/defuse/php-encryption)
10
+
11
+ This is a library for encrypting data with a key or password in PHP. **It
12
+ requires PHP 5.6 or newer and OpenSSL 1.0.1 or newer.** The current version is
13
+ v2.2.0, which is expected to remain stable and supported by its authors with
14
+ security and bugfixes until at least January 1st, 2020.
15
+
16
+ The library is a joint effort between [Taylor Hornby](https://defuse.ca/) and
17
+ [Scott Arciszewski](https://paragonie.com/blog/author/scott-arcizewski) as well
18
+ as numerous open-source contributors.
19
+
20
+ What separates this library from other PHP encryption libraries is, firstly,
21
+ that it is secure. The authors used to encounter insecure PHP encryption code on
22
+ a daily basis, so they created this library to bring more security to the
23
+ ecosystem. Secondly, this library is "difficult to misuse." Like
24
+ [libsodium](https://github.com/jedisct1/libsodium), its API is designed to be
25
+ easy to use in a secure way and hard to use in an insecure way.
26
+
27
+
28
+ Dependencies
29
+ ------------
30
+
31
+ This library requires no special dependencies except for PHP 5.6 or newer with
32
+ the OpenSSL extensions (version 1.0.1 or later) enabled (this is the default).
33
+ It uses [random\_compat](https://github.com/paragonie/random_compat), which is
34
+ bundled in with this library so that your users will not need to follow any
35
+ special installation steps.
36
+
37
+ Getting Started
38
+ ----------------
39
+
40
+ Start with the [**Tutorial**](docs/Tutorial.md). You can find instructions for
41
+ obtaining this library's code securely in the [Installing and
42
+ Verifying](docs/InstallingAndVerifying.md) documentation.
43
+
44
+ After you've read the tutorial and got the code, refer to the formal
45
+ documentation for each of the classes this library provides:
46
+
47
+ - [Crypto](docs/classes/Crypto.md)
48
+ - [File](docs/classes/File.md)
49
+ - [Key](docs/classes/Key.md)
50
+ - [KeyProtectedByPassword](docs/classes/KeyProtectedByPassword.md)
51
+
52
+ If you encounter difficulties, see the [FAQ](docs/FAQ.md) answers. The fixes to
53
+ the most commonly-reported problems are explained there.
54
+
55
+ If you're a cryptographer and want to understand the nitty-gritty details of how
56
+ this library works, look at the [Cryptography Details](docs/CryptoDetails.md)
57
+ documentation.
58
+
59
+ If you're interested in contributing to this library, see the [Internal
60
+ Developer Documentation](docs/InternalDeveloperDocs.md).
61
+
62
+ Other Language Support
63
+ ----------------------
64
+
65
+ This library is intended for server-side PHP software that needs to encrypt data at rest.
66
+ If you are building software that needs to encrypt client-side, or building a system that
67
+ requires cross-platform encryption/decryption support, we strongly recommend using
68
+ [libsodium](https://download.libsodium.org/doc/bindings_for_other_languages) instead.
69
+
70
+ Examples
71
+ ---------
72
+
73
+ If the documentation is not enough for you to understand how to use this
74
+ library, then you can look at an example project that uses this library:
75
+
76
+ - [encutil](https://github.com/defuse/encutil)
77
+ - [fileencrypt](https://github.com/tsusanka/fileencrypt)
78
+
79
+ Security Audit Status
80
+ ---------------------
81
+
82
+ This code has not been subjected to a formal, paid, security audit. However, it
83
+ has received lots of review from members of the PHP security community, and the
84
+ authors are experienced with cryptography. In all likelihood, you are safer
85
+ using this library than almost any other encryption library for PHP.
86
+
87
+ If you use this library as a part of your business and would like to help fund
88
+ a formal audit, please [contact Taylor Hornby](https://defuse.ca/contact.htm).
89
+
90
+ Public Keys
91
+ ------------
92
+
93
+ The GnuPG public key used to sign releases is available in
94
+ [dist/signingkey.asc](https://github.com/defuse/php-encryption/raw/master/dist/signingkey.asc). Its fingerprint is:
95
+
96
+ ```
97
+ 2FA6 1D8D 99B9 2658 6BAC 3D53 385E E055 A129 1538
98
+ ```
99
+
100
+ You can verify it against Taylor Hornby's [contact
101
+ page](https://defuse.ca/contact.htm) and
102
+ [twitter](https://twitter.com/DefuseSec/status/723741424253059074).
vendor/defuse/php-encryption/bin/generate-defuse-key ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env php
2
+ <?php
3
+
4
+ use Defuse\Crypto\Key;
5
+
6
+ foreach ([__DIR__ . '/../../../autoload.php', __DIR__ . '/../vendor/autoload.php'] as $file) {
7
+ if (file_exists($file)) {
8
+ require $file;
9
+ break;
10
+ }
11
+ }
12
+
13
+ $key = Key::createNewRandomKey();
14
+ echo $key->saveToAsciiSafeString(), "\n";
vendor/defuse/php-encryption/composer.json ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "defuse/php-encryption",
3
+ "description": "Secure PHP Encryption Library",
4
+ "license": "MIT",
5
+ "keywords": ["security", "encryption", "AES", "openssl", "cipher", "cryptography", "symmetric key cryptography", "crypto", "encrypt", "authenticated encryption"],
6
+ "authors": [
7
+ {
8
+ "name": "Taylor Hornby",
9
+ "email": "taylor@defuse.ca",
10
+ "homepage": "https://defuse.ca/"
11
+ },
12
+ {
13
+ "name": "Scott Arciszewski",
14
+ "email": "info@paragonie.com",
15
+ "homepage": "https://paragonie.com"
16
+ }
17
+ ],
18
+ "autoload": {
19
+ "psr-4": {
20
+ "Defuse\\Crypto\\": "src"
21
+ }
22
+ },
23
+ "require": {
24
+ "paragonie/random_compat": "~2.0",
25
+ "ext-openssl": "*",
26
+ "php": ">=5.4.0"
27
+ },
28
+ "require-dev": {
29
+ "phpunit/phpunit": "^4|^5",
30
+ "nikic/php-parser": "^2.0|^3.0|^4.0"
31
+ },
32
+ "bin": [
33
+ "bin/generate-defuse-key"
34
+ ]
35
+ }
vendor/defuse/php-encryption/dist/Makefile ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # This builds defuse-crypto.phar. To run this Makefile, `box` and `composer`
2
+ # must be installed and in your $PATH. Run it from inside the dist/ directory.
3
+
4
+ box := $(shell which box)
5
+ composer := "composer"
6
+
7
+ .PHONY: all
8
+ all: build-phar
9
+
10
+ .PHONY: sign-phar
11
+ sign-phar:
12
+ gpg -u 7B4B2D98 --armor --output defuse-crypto.phar.sig --detach-sig defuse-crypto.phar
13
+
14
+ # ensure we run in clean tree. export git tree and run there.
15
+ .PHONY: build-phar
16
+ build-phar:
17
+ @echo "Creating .phar from revision $(shell git rev-parse HEAD)."
18
+ rm -rf worktree
19
+ install -d worktree
20
+ (cd $(CURDIR)/..; git archive HEAD) | tar -x -C worktree
21
+ $(MAKE) -f $(CURDIR)/Makefile -C worktree defuse-crypto.phar
22
+ mv worktree/*.phar .
23
+ rm -rf worktree
24
+
25
+ .PHONY: clean
26
+ clean:
27
+ rm -vf defuse-crypto.phar defuse-crypto.phar.sig
28
+
29
+ # Inside workdir/:
30
+
31
+ defuse-crypto.phar: dist/box.json composer.lock
32
+ cp dist/box.json .
33
+ php -d phar.readonly=0 $(box) build -c box.json -v
34
+
35
+ composer.lock:
36
+ $(composer) install --no-dev
37
+
vendor/defuse/php-encryption/dist/box.json ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "chmod": "0755",
3
+ "finder": [
4
+ {
5
+ "in": "src",
6
+ "name": "*.php"
7
+ },
8
+ {
9
+ "in": "vendor/composer",
10
+ "name": "*.php"
11
+ },
12
+ {
13
+ "in": "vendor/paragonie",
14
+ "name": "*.php",
15
+ "exclude": "other"
16
+ }
17
+ ],
18
+ "compactors": [
19
+ "Herrera\\Box\\Compactor\\Php"
20
+ ],
21
+ "main": "vendor/autoload.php",
22
+ "output": "defuse-crypto.phar",
23
+ "shebang": false,
24
+ "stub": true
25
+ }
vendor/defuse/php-encryption/dist/signingkey.asc ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ -----BEGIN PGP PUBLIC KEY BLOCK-----
2
+ Version: GnuPG v2
3
+
4
+ mQINBFarvO4BEACdQBaLt6SUBx1cB5liUu1qo+YwVLh9bxTregQtmEREMdTVqXYt
5
+ e5b79uL4pQp2GlKHcEyRURS+6rIIruM0oh9ZYGTJYPAkCDzJxaU2awZeFbfBvpCm
6
+ iF66/O4ZJI4mlT8dFKmxBJxDhfeOR2UmmhDiEsJK9FxBKUzvo/dWrX2pBzf8Y122
7
+ iIaVraSo+tymaf7vriaIf/NnSKhDw8dtQYGM4NMrxxsPTfbCF8XiboDgTkoD2A+6
8
+ NpOJYxA4Veedsf2TP9YLhljH4m5yYlfjjqBzbBCPWuE6Hhy5Xze9mncgDr7LKenm
9
+ Ctf2NxW6y4O3RCI+9eLlBfFWB+KuGV87/b5daetX7NNLbjID8z2rqEa+d6wu5xA5
10
+ Ta2uiVkAOEovr3XnkayZ9zth+Za7w7Ai0ln0N/LVMkM+Gu4z/pJv6HjmTGDM2wJb
11
+ fs+UOM0TFdg+N81Do67XT2M4o0MeHyUqsIiWpYa2Qf1PNmqTQNJnRk8uZZ9I96Nh
12
+ eCgNuCbhsQiYBMicox+xmuWAlGAfA06y0kCtmqGhiBGArdJlWvUqPqGiZ4Hln9z0
13
+ FJmXDOh0Q/FIPxcDg8mKRRbx+lOP389PLsPpj4b2B/4PEgfpCCOwuKpLotATZxC1
14
+ 9JwFk0Y/cvUUkq4a+nAJBNtBbtRJkEesuuUnRq6XexmnE3uUucDcV0XCSwARAQAB
15
+ tCBUYXlsb3IgSG9ybmJ5IDx0YXlsb3JAZGVmdXNlLmNhPokCPQQTAQgAJwUCVqu8
16
+ 7gIbAwUJB4TOAAULCQgHAgYVCAkKCwIEFgIDAQIeAQIXgAAKCRA4XuBVoSkVOJbx
17
+ EACG0F9blPMAsK05EWyNnnS4mw25zPfbaqqEvYbquAeM0nBpRDm7sRn2MNR0AL4g
18
+ 7XrtxE/4qYkdEl6f2wFCQeRhZgxE3w22llredzLme11Hic8hn4i7ysdIw0r9dMMR
19
+ kjgR5UcWpv8iU847czyK09PkKW2EaLRbX2qbA7rNU5qCFKeD4Sy4bBTteISeVsHo
20
+ Vr9o1/bRrMhgZ++ts8hYf0LmujIf5cxp+qcdKwCXSnS/gmmXaKRMCPv/Wdlq9bt6
21
+ LX9jZB9lXBdGxcBJeFOsTG+QRDiVjg3d6i3o3TAKV87ALBI4v2ADEYtN8lviHo3/
22
+ SovVKv6zrUsZHxhoGiLTiksNrYsKMmiMxdJCoOazmtUPnZ4UOtT8NdqMPoKvdoRz
23
+ f4rhZ+f5jSVD9OuX2PDmfyq21Rdiym7Vcgr+uTIFJ3ShRHjWb/ytCwoB2FeGY6+G
24
+ AKY58bTQvUIqEJvSov/+TAqZ4BfOuSdTLcHglV1OdUu2SFZvU2gmyVp0l5elGv5t
25
+ FyUlBJUkQT9MtvsdLOR7vQi8QapV+9LWpqwvaj9hyEJz848DQ2sdYTphUytFHv7H
26
+ k58DAtVhTrVjHyeefjiYtMl6vSAgTjy5LWAUpo5TfhdGrAi0Tdd/GD7amHoWoDy8
27
+ EKXKq2xPLo3JOdkWYQUi5NErzEskfsSzpCOgyDJmGetWK7kCDQRWq7zuARAAu7/i
28
+ cm8cjgLhHEX/bgfwOT2hLOLSjjve0O8YFSuJO9XqIHXqmfVOrqWtfG0Mh4bwlfqc
29
+ MAvBfF5NSSPfAE4ftBAQ1e5jEv8hJeqICpq3IHTFX4etBs49NfNkyveQl/amVTu1
30
+ +/O5J4CuIcsEf3y0Xuu38n7EB3SfMQCWLcOR1NyZoX3bI+CGRpOVVoFse3ljSWL4
31
+ LhLVl0WiEMXULsussEoN+c6x9KCyAi/jFOrxrTrFC//sZesKj6KucoqKGfwMWrrv
32
+ IeRT9Ga8Wn5MJnQu0aWg+zVVYqTedXZLNLODgQIInFnXO0seBXy15yDok1y5bkx2
33
+ sinKg4+mueYaGUpoUti0hM3J3yaC34i6Cwa8MQoLNw1JIS/oNtKjpMxyV10w8aoc
34
+ PHRK3n7UYp10mJHx7aM+lldSKvVS1NTQmI4vloNLwMp324H5ANDFAlRUz7mysVnu
35
+ DEEvigPSPxs5ZYENu/i7pCQC5qHfhrlBrQwTjhegr0pQPcumy2fO5SGC9l/5B7ev
36
+ bqQSZmDeWWoTvh2w2wl5/RWAsgZKx6rDtkCqYx7sSBY17uorrxP24LP4zhq7NxRV
37
+ nfdsLogbCFNVQ66u7qvq5zFccdFtg9h1HQWdS7wbnKSBGZoo5gl6js7GGtxfGbb0
38
+ oQ9kp6eciF4U92r6POhVgbRe4CfPo50nqgZBddkAEQEAAYkCJQQYAQgADwUCVqu8
39
+ 7gIbDAUJB4TOAAAKCRA4XuBVoSkVOFJ8D/9J8IJ4XWUU3FYIaHJ3XeSoxDmTi7d5
40
+ WmNdf1lmwz82MQjG4uw17oCbvQzmj4/a/CM1Ly4v0WwBhUf9aiNErD0ByHASFnuc
41
+ tlQBLVJdk0vRyD0fZakGg64qCA76hiySjMhlGHkQFyP2mDORc2GNu/OqFGm79pXT
42
+ ZUplXxd431E603/agM5xJrweutMMpP1nBFTSEMJvbMNzDVN8I1A1CH4zVmAVxOUk
43
+ sQ5L5rXW+KeXWyiMF24+l2CMnkQ2CxfHpkcpfPJs1Cbt+TIBSSofIqK8QJXrb/2f
44
+ Zpl/ftqW7Xe86rJFrB/Y/77LDWx10rqWEvfCqrBxrMj7ONAQfbKQF/IjAwDN17Wf
45
+ 1K74rqKnRu+KHCyNM89s1iDbQC9kzZfzYt4AEOvAH/ZQDMZffzPSbnfkBerExFpa
46
+ 93XMuiR66jiBsf9IXIQeydpJD4Ogl2sSUSxFEJxJ/bBSxPxC5w7/BVMA7Am1y8Zo
47
+ 3hrpqnX2PBzxG7L0FZ6fYkfR3p8JS7vI6nByBf2IDv8W32wn43olPf+u6uobHLvt
48
+ ttapOjwPAhPDalRuxs9U6WSg06QJkT/0F8TFUPWpsFmKTl+G4Ty7PHWsjeeNHJCL
49
+ 7/5RQboFY3k8Jy3/sIofABO6Un9LJivDuu9PxqA0IgvaS6Mja8JdCCk9Nyk4vHB7
50
+ IEgAL/CYqrk38w==
51
+ =lmD7
52
+ -----END PGP PUBLIC KEY BLOCK-----
vendor/defuse/php-encryption/docs/CryptoDetails.md ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Cryptography Details
2
+ =====================
3
+
4
+ Here is a high-level description of how this library works. Any discrepancy
5
+ between this documentation and the actual implementation will be considered
6
+ a security bug.
7
+
8
+ Let's start with the following definitions:
9
+
10
+ - HKDF-SHA256(*k*, *n*, *info*, *s*) is the key derivation function specified in
11
+ RFC 5869 (using the SHA256 hash function). The parameters are:
12
+ - *k*: The initial keying material.
13
+ - *n*: The number of output bytes.
14
+ - *info*: The info string.
15
+ - *s*: The salt.
16
+ - AES-256-CTR(*m*, *k*, *iv*) is AES-256 encryption in CTR mode. The parameters
17
+ are:
18
+ - *m*: An arbitrary-length (possibly zero-length) message.
19
+ - *k*: A 32-byte key.
20
+ - *iv*: A 16-byte initialization vector (nonce).
21
+ - PBKDF2-SHA256(*p*, *s*, *i*, *n*) is the password-based key derivation
22
+ function defined in RFC 2898 (using the SHA256 hash function). The parameters
23
+ are:
24
+ - *p*: The password string.
25
+ - *s*: The salt string.
26
+ - *i*: The iteration count.
27
+ - *n*: The output length in bytes.
28
+ - VERSION is the string `"\xDE\xF5\x02\x00"`.
29
+ - AUTHINFO is the string `"DefusePHP|V2|KeyForAuthentication"`.
30
+ - ENCRINFO is the string `"DefusePHP|V2|KeyForEncryption"`.
31
+
32
+ To encrypt a message *m* using a 32-byte key *k*, the following steps are taken:
33
+
34
+ 1. Generate a random 32-byte string *salt*.
35
+ 2. Derive the 32-byte authentication key *akey* = HKDF-SHA256(*k*, 32, AUTHINFO, *salt*).
36
+ 3. Derive the 32-byte encryption key *ekey* = HKDF-SHA256(*k*, 32, ENCRINFO, *salt*).
37
+ 4. Generate a random 16-byte initialization vector *iv*.
38
+ 5. Compute *c* = AES-256-CTR(*m*, *ekey*, *iv*).
39
+ 6. Combine *ctxt* = VERSION || *salt* || *iv* || *c*.
40
+ 7. Compute *h* = HMAC-SHA256(*ctxt*, *akey*).
41
+ 8. Output *ctxt* || *h*.
42
+
43
+ Decryption is roughly the reverse process (see the code for details, since the
44
+ security of the decryption routine is highly implementation-dependent).
45
+
46
+ For encryption using a password *p*, steps 1-3 above are replaced by:
47
+
48
+ 1. Generate a random 32-byte string *salt*.
49
+ 2. Compute *k* = PBKDF2-SHA256(SHA256(*p*), *salt*, 100000, 32).
50
+ 3. Derive the 32-byte authentication key *akey* = HKDF-SHA256(*k*, 32, AUTHINFO, *salt*)
51
+ 4. Derive the 32-byte encryption key *ekey* = HKDF-SHA256(*k*, 32, ENCRINFO, *salt*)
52
+
53
+ The remainder of the process is the same. Notice the reuse of the same *salt*
54
+ for PBKDF2-SHA256 and HKDF-SHA256. The prehashing of the password in step 2 is
55
+ done to prevent a [DoS attack using long
56
+ passwords](https://github.com/defuse/php-encryption/issues/230).
57
+
58
+ For `KeyProtectedByPassword`, the serialized key is encrypted according to the
59
+ password encryption defined above. However, the actual password used for
60
+ encryption is the SHA256 hash of the password the user provided. This is done in
61
+ order to provide domain separation between the message encryption in the user's
62
+ application and the internal key encryption done by this library. It fixes
63
+ a [key replacement chosen-protocol
64
+ attack](https://github.com/defuse/php-encryption/issues/240).
vendor/defuse/php-encryption/docs/FAQ.md ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Frequently Asked Questions
2
+ ===========================
3
+
4
+ How do I use this library to encrypt passwords?
5
+ ------------------------------------------------
6
+
7
+ Passwords should not be encrypted, they should be hashed with a *slow* password
8
+ hashing function that's designed to slow down password guessing attacks. See
9
+ [How to Safely Store Your Users' Passwords in
10
+ 2016](https://paragonie.com/blog/2016/02/how-safely-store-password-in-2016).
11
+
12
+ How do I give it the same key every time instead of a new random key?
13
+ ----------------------------------------------------------------------
14
+
15
+ A `Key` object can be saved to a string by calling its `saveToAsciiSafeString()`
16
+ method. You will have to save that string somewhere safe, and then load it back
17
+ into a `Key` object using `Key`'s `loadFromAsciiSafeString` static method.
18
+
19
+ Where you store the string depends on your application. For example if you are
20
+ using `KeyProtectedByPassword` to encrypt files with a user's login password,
21
+ then you should not store the `Key` at all. If you are protecting sensitive data
22
+ on a server that may be compromised, then you should store it in a hardware
23
+ security module. When in doubt, consult a security expert.
24
+
25
+ Why is an EnvironmentIsBrokenException getting thrown?
26
+ -------------------------------------------------------
27
+
28
+ Either you've encountered a bug in this library, or your system doesn't support
29
+ the use of this library. For example, if your system does not have a secure
30
+ random number generator, this library will refuse to run, by throwing that
31
+ exception, instead of falling back to an insecure random number generator.
32
+
33
+ Why am I getting a BadFormatException when loading a Key from a string?
34
+ ------------------------------------------------------------------------
35
+
36
+ If you're getting this exception, then the string you're giving to
37
+ `loadFromAsciiSafeString()` is *not* the same as the string you got from
38
+ `saveToAsciiSafeString()`. Perhaps your database column isn't wide enough and
39
+ it's truncating the string as you insert it?
40
+
41
+ Does encrypting hide the length of the plaintext?
42
+ --------------------------------------------------
43
+
44
+ Encryption does not, and is not intended to, hide the length of the data being
45
+ encrypted. For example, it is not safe to encrypt a field in which only a small
46
+ number of different-length values are possible (e.g. "male" or "female") since
47
+ it would be possible to tell what the plaintext is by looking at the length of
48
+ the ciphertext. In order to do this safely, it is your responsibility to, before
49
+ encrypting, pad the data out to the length of the longest string that will ever
50
+ be encrypted. This way, all plaintexts are the same length, and no information
51
+ about the plaintext can be gleaned from the length of the ciphertext.
vendor/defuse/php-encryption/docs/InstallingAndVerifying.md ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Getting The Code
2
+ =================
3
+
4
+ There are two ways to use this library in your applications. You can either:
5
+
6
+ 1. Use [Composer](https://getcomposer.org/), or
7
+ 2. `require_once` a single `.phar` file in your application.
8
+
9
+ If you are not using either option (for example, because you're using Git submodules), you may need to write your own autoloader ([example](https://gist.github.com/paragonie-scott/949daee819bb7f19c50e5e103170b400)).
10
+
11
+ Option 1: Using Composer
12
+ -------------------------
13
+
14
+ Run this inside the directory of your composer-enabled project:
15
+
16
+ ```sh
17
+ composer require defuse/php-encryption
18
+ ```
19
+
20
+ Unfortunately, composer doesn't provide a way for you to verify that the code
21
+ you're getting was signed by this library's authors. If you want a more secure
22
+ option, use the `.phar` method described below.
23
+
24
+ Option 2: Including a PHAR
25
+ ----------------------------
26
+
27
+ The `.phar` option lets you include this library into your project simply by
28
+ calling `require_once` on a single file. Download `defuse-crypto.phar` and
29
+ `defuse-crypto.phar.sig` from this project's
30
+ [releases](https://github.com/defuse/php-encryption/releases) page.
31
+
32
+ You should verify the integrity of the `.phar`. The `defuse-crypto.phar.sig`
33
+ contains the signature of `defuse-crypto.phar`. It is signed with Taylor
34
+ Hornby's PGP key. You can find Taylor's public key in `dist/signingkey.asc`. You
35
+ can verify the public key's fingerprint against the Taylor Hornby's [contact
36
+ page](https://defuse.ca/contact.htm) and
37
+ [twitter](https://twitter.com/DefuseSec/status/723741424253059074).
38
+
39
+ Once you have verified the signature, it is safe to use the `.phar`. Place it
40
+ somewhere in your file system, e.g. `/var/www/lib/defuse-crypto.phar`, and then
41
+ pass that path to `require_once`.
42
+
43
+ ```php
44
+ <?php
45
+
46
+ require_once('/var/www/lib/defuse-crypto.phar');
47
+
48
+ // ... the Crypto, File, Key, and KeyProtectedByPassword classes are now
49
+ // available ...
50
+
51
+ // ...
52
+ ```
53
+
vendor/defuse/php-encryption/docs/InternalDeveloperDocs.md ADDED
@@ -0,0 +1,166 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Information for the Developers of php-encryption
2
+ =================================================
3
+
4
+ Status
5
+ -------
6
+
7
+ This library is currently frozen under a long-term support release. We do not
8
+ plan to add any new features. We will maintain the library by fixing any bugs
9
+ that are reported, or security vulnerabilities that are found.
10
+
11
+ Development Environment
12
+ ------------------------
13
+
14
+ Development is done on Linux. To run the tests, you will need to have the
15
+ following tools installed:
16
+
17
+ - `php` (with OpenSSL enabled, if you're compiling from source).
18
+ - `gpg`
19
+ - `composer`
20
+
21
+ Running the Tests
22
+ ------------------
23
+
24
+ First do `composer install` and then you can run the tests by running
25
+ `./test.sh`. This will download a PHPUnit PHAR, verify its cryptographic
26
+ signatures, and then use it to run the tests in `test/unit`.
27
+
28
+ Getting and Using Psalm
29
+ -----------------------
30
+
31
+ [Psalm](https://github.com/vimeo/psalm) is a static analysis suite for PHP projects.
32
+ We use Psalm to ensure type safety throughout our library.
33
+
34
+ To install Psalm, you just need to run one command:
35
+
36
+ composer require --dev "vimeo/psalm:dev-master"
37
+
38
+ To verify that your code changes are still strictly type-safe, run the following
39
+ command:
40
+
41
+ vendor/bin/psalm
42
+
43
+ Reporting Bugs
44
+ ---------------
45
+
46
+ Please report bugs, even critical security vulnerabilities, by opening an issue
47
+ on GitHub. We recommend disclosing security vulnerabilities found in this
48
+ library *publicly* as soon as possible.
49
+
50
+ Philosophy
51
+ -----------
52
+
53
+ This library is developed around several core values:
54
+
55
+ - Rule #1: Security is prioritized over everything else.
56
+
57
+ > Whenever there is a conflict between security and some other property,
58
+ > security will be favored. For example, the library has runtime tests,
59
+ > which make it slower, but will hopefully stop it from encrypting stuff
60
+ > if the platform it's running on is broken.
61
+
62
+ - Rule #2: It should be difficult to misuse the library.
63
+
64
+ > We assume the developers using this library have no experience with
65
+ > cryptography. We only assume that they know that the "key" is something
66
+ > you need to encrypt and decrypt the messages, and that it must be kept
67
+ > secret. Whenever possible, the library should refuse to encrypt or decrypt
68
+ > messages when it is not being used correctly.
69
+
70
+ - Rule #3: The library aims only to be compatible with itself.
71
+
72
+ > Other PHP encryption libraries try to support every possible type of
73
+ > encryption, even the insecure ones (e.g. ECB mode). Because there are so
74
+ > many options, inexperienced developers must decide whether to use "CBC
75
+ > mode" or "ECB mode" when both are meaningless terms to them. This
76
+ > inevitably leads to vulnerabilities.
77
+
78
+ > This library will only support one secure mode. A developer using this
79
+ > library will call "encrypt" and "decrypt" methods without worrying about
80
+ > how they are implemented.
81
+
82
+ - Rule #4: The library should require no special installation.
83
+
84
+ > Some PHP encryption libraries, like libsodium-php, are not straightforward
85
+ > to install and cannot packaged with "just download and extract"
86
+ > applications. This library will always be just a handful of PHP files that
87
+ > you can copy to your source tree and require().
88
+
89
+ Publishing Releases
90
+ --------------------
91
+
92
+ To make a release, you will need to install [composer](https://getcomposer.org/)
93
+ and [box](https://github.com/box-project/box2) on your system. They will need to
94
+ be available in your `$PATH` so that running the commands `composer` and `box`
95
+ in your terminal run them, respectively. You will also need the private key for
96
+ signing (ID: 7B4B2D98) available.
97
+
98
+ Once you have those tools installed and the key available follow these steps:
99
+
100
+ **Remember to set the version number in `composer.json`!**
101
+
102
+ Make a fresh clone of the repository:
103
+
104
+ ```
105
+ git clone <url>
106
+ ```
107
+
108
+ Check out the branch you want to release:
109
+
110
+ ```
111
+ git checkout <branchname>
112
+ ```
113
+
114
+ Check that the version number in composer.json is correct:
115
+
116
+ ```
117
+ cat composer.json
118
+ ```
119
+
120
+ Check that the version number and support lifetime in README.md are correct:
121
+
122
+ ```
123
+ cat README.md
124
+ ```
125
+
126
+ Run the tests:
127
+
128
+ ```
129
+ composer install
130
+ ./test.sh
131
+ ```
132
+
133
+ Generate the `.phar`:
134
+
135
+ ```
136
+ cd dist
137
+ make build-phar
138
+ ```
139
+
140
+ Test the `.phar`:
141
+
142
+ ```
143
+ cd ../
144
+ ./test.sh dist/defuse-crypto.phar
145
+ ```
146
+
147
+ Sign the `.phar`:
148
+
149
+ ```
150
+ cd dist
151
+ make sign-phar
152
+ ```
153
+
154
+ Tag the release:
155
+
156
+ ```
157
+ git -c user.signingkey=7B4B2D98 tag -s "<TAG NAME>" -m "<TAG MESSAGE>"
158
+ ```
159
+
160
+ `<TAG NAME>` should be in the format `v2.0.0` and `<TAG MESSAGE>` should look
161
+ like "Release of v2.0.0."
162
+
163
+ Push the tag to github, then use the
164
+ [releases](https://github.com/defuse/php-encryption/releases) page to draft
165
+ a new release for that tag. Upload the `.phar` and the `.phar.sig` file to be
166
+ included as part of that release.
vendor/defuse/php-encryption/docs/Tutorial.md ADDED
@@ -0,0 +1,314 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Tutorial
2
+ =========
3
+
4
+ Hello! If you're reading this file, it's because you want to add encryption to
5
+ one of your PHP projects. My job, as the person writing this documentation, is
6
+ to help you make sure you're doing the right thing and then show you how to use
7
+ this library to do it. To help me help you, please read the documentation
8
+ *carefully* and *deliberately*.
9
+
10
+ A Word of Caution
11
+ ------------------
12
+
13
+ Encryption is not magic dust you can sprinkle on a system to make it more
14
+ secure. The way encryption is integrated into a system's design needs to be
15
+ carefully thought out. Sometimes, encryption is the wrong thing to use. Other
16
+ times, encryption needs to be used in a very specific way in order for it to
17
+ work as intended. Even if you are sure of what you are doing, we strongly
18
+ recommend seeking advice from an expert.
19
+
20
+ The first step is to think about your application's threat model. Ask yourself
21
+ the following questions. Who will want to attack my application, and what will
22
+ they get out of it? Are they trying to steal some information? Trying to alter
23
+ or destroy some information? Or just trying to make the system go down so people
24
+ can't access it? Then ask yourself how encryption can help combat those threats.
25
+ If you're going to add encryption to your application, you should have a very
26
+ clear idea of exactly which kinds of attacks it's helping to secure your
27
+ application against. Once you have your threat model, think about what kinds of
28
+ attacks it *does not* cover, and whether or not you should improve your threat
29
+ model to include those attacks.
30
+
31
+ **This isn't for storing user login passwords:** The most common use of
32
+ cryptography in web applications is to protect the users' login passwords. If
33
+ you're trying to use this library to "encrypt" your users' passwords, you're in
34
+ the wrong place. Passwords shouldn't be *encrypted*, they should be *hashed*
35
+ with a slow computation-heavy function that makes password guessing attacks more
36
+ expensive. See [How to Safely Store Your Users' Passwords in
37
+ 2016](https://paragonie.com/blog/2016/02/how-safely-store-password-in-2016).
38
+
39
+ **This isn't for encrypting network communication:** Likewise, if you're trying
40
+ to encrypt messages sent between two parties over the Internet, you don't want
41
+ to be using this library. For that, set up a TLS connection between the two
42
+ points, or, if it's a chat app, use the [Signal
43
+ Protocol](https://whispersystems.org/blog/advanced-ratcheting/).
44
+
45
+ What this library provides is symmetric encryption for "data at rest." This
46
+ means it is not suitable for use in building protocols where "data is in motion"
47
+ (i.e. moving over a network) except in limited set of cases.
48
+
49
+ Please note that **encryption does not, and is not intended to, hide the
50
+ *length* of the data being encrypted.** For example, it is not safe to encrypt
51
+ a field in which only a small number of different-length values are possible
52
+ (e.g. "male" or "female") since it would be possible to tell what the plaintext
53
+ is by looking at the length of the ciphertext. In order to do this safely, it is
54
+ your responsibility to, before encrypting, pad the data out to the length of the
55
+ longest string that will ever be encrypted. This way, all plaintexts are the
56
+ same length, and no information about the plaintext can be gleaned from the
57
+ length of the ciphertext.
58
+
59
+ Getting the Code
60
+ -----------------
61
+
62
+ There are several different ways to obtain this library's code and to add it to
63
+ your project. Even if you've already cloned the code from GitHub, you should
64
+ take steps to verify the cryptographic signatures to make sure the code you got
65
+ was not intercepted and modified by an attacker.
66
+
67
+ Please head over to the [**Installing and
68
+ Verifying**](InstallingAndVerifying.md) documentation to get the code, and then
69
+ come back here to continue the tutorial.
70
+
71
+ Using the Library
72
+ ------------------
73
+
74
+ I'm going to assume you know what symmetric encryption is, and the difference
75
+ between symmetric and asymmetric encryption. If you don't, I recommend taking
76
+ [Dan Boneh's Cryptography I course](https://www.coursera.org/learn/crypto/) on
77
+ Coursera.
78
+
79
+ To give you a quick introduction to the library, I'm going to explain how it
80
+ would be used in two sterotypical scenarios. Hopefully, one of these sterotypes
81
+ is close enough to what you want to do that you'll be able to figure out what
82
+ needs to be different on your own.
83
+
84
+ ### Formal Documentation
85
+
86
+ While this tutorial should get you up and running fast, it's important to
87
+ understand how this library behaves. Please make sure to read the formal
88
+ documentation of all of the functions you're using, since there are some
89
+ important security warnings there.
90
+
91
+ The following classes are available for you to use:
92
+
93
+ - [Crypto](classes/Crypto.md): Encrypting and decrypting strings.
94
+ - [File](classes/File.md): Encrypting and decrypting files.
95
+ - [Key](classes/Key.md): Represents a secret encryption key.
96
+ - [KeyProtectedByPassword](classes/KeyProtectedByPassword.md): Represents
97
+ a secret encryption key that needs to be "unlocked" by a password before it
98
+ can be used.
99
+
100
+ ### Scenario #1: Keep data secret from the database administrator
101
+
102
+ In this scenario, our threat model is as follows. Alice is a server
103
+ administrator responsible for managing a trusted web server. Eve is a database
104
+ administrator responsible for managing a database server. Dave is a web
105
+ developer working on code that will eventually run on the trusted web server.
106
+
107
+ Let's say Alice and Dave trust each other, and Alice is going to host Dave's
108
+ application on her server. But both Alice and Dave don't trust Eve. They know
109
+ Eve is a good database administrator, but she might have incentive to steal the
110
+ data from the database. They want to keep some of the web application's data
111
+ secret from Eve.
112
+
113
+ In order to do that, Alice will use the included `generate-defuse-key` script
114
+ which generates a random encryption key and prints it to standard output:
115
+
116
+ ```sh
117
+ $ composer require defuse/php-encryption
118
+ $ vendor/bin/generate-defuse-key
119
+ ```
120
+
121
+ Alice will run this script once and save the output to a configuration file, say
122
+ in `/etc/daveapp-secret-key.txt` and set the file permissions so that only the
123
+ user that the website PHP scripts run as can access it.
124
+
125
+ Dave will write his code to load the key from the configuration file:
126
+
127
+ ```php
128
+ <?php
129
+ use Defuse\Crypto\Key;
130
+
131
+ function loadEncryptionKeyFromConfig()
132
+ {
133
+ $keyAscii = // ... load the contents of /etc/daveapp-secret-key.txt
134
+ return Key::loadFromAsciiSafeString($keyAscii);
135
+ }
136
+ ```
137
+
138
+ Then, whenever Dave wants to save a secret value to the database, he will first
139
+ encrypt it:
140
+
141
+ ```php
142
+ <?php
143
+ use Defuse\Crypto\Crypto;
144
+
145
+ // ...
146
+ $key = loadEncryptionKeyFromConfig();
147
+ // ...
148
+ $ciphertext = Crypto::encrypt($secret_data, $key);
149
+ // ... save $ciphertext into the database ...
150
+ ```
151
+
152
+ Whenever Dave wants to get the value back from the database, he must decrypt it
153
+ using the same key:
154
+
155
+ ```php
156
+ <?php
157
+ use Defuse\Crypto\Crypto;
158
+
159
+ // ...
160
+ $key = loadEncryptionKeyFromConfig();
161
+ // ...
162
+ $ciphertext = // ... load $ciphertext from the database
163
+ try {
164
+ $secret_data = Crypto::decrypt($ciphertext, $key);
165
+ } catch (\Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
166
+ // An attack! Either the wrong key was loaded, or the ciphertext has
167
+ // changed since it was created -- either corrupted in the database or
168
+ // intentionally modified by Eve trying to carry out an attack.
169
+
170
+ // ... handle this case in a way that's suitable to your application ...
171
+ }
172
+ ```
173
+
174
+ Note that if anyone ever steals the key from Alice's server, they can decrypt
175
+ all of the ciphertexts that are stored in the database. As part of our threat
176
+ model, we are assuming Alice's server administration skills and Dave's secure
177
+ coding skills are good enough to stop Eve from being able to steal the key.
178
+ Under those assumptions, this solution will prevent Eve from seeing data that's
179
+ stored in the database.
180
+
181
+ However, notice that our threat model says nothing about what could happen if
182
+ Eve wants to *modify* the data. With this solution, Eve will not be able to
183
+ alter any individual ciphertext (because each ciphertext has its own
184
+ cryptographic integrity check), but Eve *will* be able to swap ciphertexts for
185
+ one another, and revert ciphertexts to what they used to be at previous times.
186
+ If we needed to defend against such attacks, we would have to re-design our
187
+ threat model and come up with a different solution.
188
+
189
+ ### Scenario #2: Encrypting account data with the user's login password
190
+
191
+ This scenario is like Scenario 1, but subtly different. The threat model is as
192
+ follows. We have Alice, a server administrator, and Dave, the developer. Alice
193
+ and Dave trust each other, and Alice wants to host Dave's web application,
194
+ including its database, on her server. Alice is worried about her server getting
195
+ hacked. The application will store the users' credit card numbers, and Alice
196
+ wants to protect them in case the server gets hacked.
197
+
198
+ We can model the situation like this: after the server gets hacked, the attacker
199
+ will have read and write access to all data on it until the attack is detected
200
+ and Alice rebuilds the server. We'll call the time the attacker has access to
201
+ the server the *exposure window.* One idea to minimize loss is to encrypt the
202
+ users' credit card numbers using a key made from their login password. Then, as
203
+ long as the users all have strong passwords, and they are never logged in during
204
+ the exposure window, their credit cards will be protected from the attacker.
205
+
206
+ To implement this, Dave will use the `KeyProtectedByPassword` class. When a new
207
+ user account is created, Dave will save a new key to their account, one that's
208
+ protected by their login password:
209
+
210
+ ```php
211
+ <?php
212
+ use Defuse\Crypto\KeyProtectedByPassword;
213
+
214
+ function CreateUserAccount($username, $password)
215
+ {
216
+ // ... other user account creation stuff, including password hashing
217
+
218
+ $protected_key = KeyProtectedByPassword::createRandomPasswordProtectedKey($password);
219
+ $protected_key_encoded = $protected_key->saveToAsciiSafeString();
220
+ // ... save $protected_key_encoded into the user's account record
221
+ }
222
+ ```
223
+
224
+ **WARNING:** Because of the way `KeyProtectedByPassword` is implemented, knowing
225
+ `SHA256($password)` is enough to decrypt a `KeyProtectedByPassword`. To be
226
+ secure, your application MUST NOT EVER compute `SHA256($password)` and use or
227
+ store it for any reason. You must also make sure that other libraries your
228
+ application is using don't compute it either.
229
+
230
+ Then, when the user logs in, Dave's code will load the protected key from the
231
+ user's account record, unlock it to get a `Key` object, and save the `Key`
232
+ object somewhere safe (like temporary memory-backed session storage). Note that
233
+ wherever Dave's code saves the key, it must be destroyed once the user logs out,
234
+ or else the attacker might be able to find users' keys even if they were never
235
+ logged in during the attack.
236
+
237
+ ```php
238
+ <?php
239
+ use Defuse\Crypto\KeyProtectedByPassword;
240
+
241
+ // ... authenticate the user using a good password hashing scheme
242
+ // keep the user's password in $password
243
+
244
+ $protected_key_encoded = // ... load it from the user's account record
245
+ $protected_key = KeyProtectedByPassword::loadFromAsciiSafeString($protected_key_encoded);
246
+ $user_key = $protected_key->unlockKey($password);
247
+ $user_key_encoded = $user_key->saveToAsciiSafeString();
248
+ // ... save $user_key_encoded in the session
249
+ ```
250
+
251
+ ```php
252
+ <?php
253
+ // ... when the user is logging out ...
254
+ // ... securely wipe the saved $user_key_encoded from the system ...
255
+ ```
256
+
257
+ When a user adds their credit card number, Dave's code will get the key from the
258
+ session and use it to encrypt the credit card number:
259
+
260
+ ```php
261
+ <?php
262
+ use Defuse\Crypto\Crypto;
263
+ use Defuse\Crypto\Key;
264
+
265
+ // ...
266
+
267
+ $user_key_encoded = // ... get it out of the session ...
268
+ $user_key = Key::loadFromAsciiSafeString($user_key_encoded);
269
+
270
+ // ...
271
+
272
+ $credit_card_number = // ... get credit card number from the user
273
+ $encrypted_card_number = Crypto::encrypt($credit_card_number, $user_key);
274
+ // ... save $encrypted_card_number in the database
275
+ ```
276
+
277
+ When the application needs to use the credit card number, it will decrypt it:
278
+
279
+ ```php
280
+ <?php
281
+ use Defuse\Crypto\Crypto;
282
+ use Defuse\Crypto\Key;
283
+
284
+ // ...
285
+
286
+ $user_key_encoded = // ... get it out of the session
287
+ $user_key = Key::loadFromAsciiSafeString($user_key_encoded);
288
+
289
+ // ...
290
+
291
+ $encrypted_card_number = // ... load it from the database ...
292
+ try {
293
+ $credit_card_number = Crypto::decrypt($encrypted_card_number, $user_key);
294
+ } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
295
+ // Either there's a bug in our code, we're trying to decrypt with the
296
+ // wrong key, or the encrypted credit card number was corrupted in the
297
+ // database.
298
+
299
+ // ... handle this case ...
300
+ }
301
+ ```
302
+
303
+ With all caveats carefully heeded, this solution limits credit card number
304
+ exposure in the case where Alice's server gets hacked for a short amount of
305
+ time. Remember to think about the attacks that *aren't* included in our threat
306
+ model. The attacker is still free to do all sorts of harmful things like
307
+ modifying the server's data which may go undetected if Alice doesn't have secure
308
+ backups to compare against.
309
+
310
+ Getting Help
311
+ -------------
312
+
313
+ If you're having difficulty using the library, see if your problem is already
314
+ solved by an answer in the [FAQ](FAQ.md).
vendor/defuse/php-encryption/docs/UpgradingFromV1.2.md ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Upgrading From Version 1.2
2
+ ===========================
3
+
4
+ With version 2.0.0 of this library came major changes to the ciphertext format,
5
+ algorithms used for encryption, and API.
6
+
7
+ In version 1.2, keys were represented by 16-byte string variables. In version
8
+ 2.0.0, keys are represented by objects, instances of the `Key` class. This
9
+ change was made in order to make it harder to misuse the API. For example, in
10
+ version 1.2, you could pass in *any* 16-byte string, but in version 2.0.0 you
11
+ need a `Key` object, which you can only get if you're "doing the right thing."
12
+
13
+ This means that for all of your old version 1.2 keys, you'll have to:
14
+
15
+ 1. Generate a new version 2.0.0 key.
16
+ 2. For all of the ciphertexts encrypted under the old key:
17
+ 1. Decrypt the ciphertext using the old version 1.2 key.
18
+ 2. Re-encrypt it using the new version 2.0.0 key.
19
+
20
+ Use the special `Crypto::legacyDecrypt()` method to decrypt the old ciphertexts
21
+ using the old key and then re-encrypt them using `Crypto::encrypt()` with the
22
+ new key. Your code will look something like the following. To avoid data loss,
23
+ securely back up your keys and data before running your upgrade code.
24
+
25
+ ```php
26
+ <?php
27
+
28
+ // ...
29
+
30
+ $legacy_ciphertext = // ... get the ciphertext you want to upgrade ...
31
+ $legacy_key = // ... get the key to decrypt this ciphertext ...
32
+
33
+ // Generate the new key that we'll re-encrypt the ciphertext with.
34
+ $new_key = Key::createNewRandomKey();
35
+ // ... save it somewhere ...
36
+
37
+ // Decrypt it.
38
+ try {
39
+ $plaintext = Crypto::legacyDecrypt($legacy_ciphertext, $legacy_key);
40
+ } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex)
41
+ {
42
+ // ... TODO: handle this case appropriately ...
43
+ }
44
+
45
+ // Re-encrypt it.
46
+ $new_ciphertext = Crypto::encrypt($plaintext, $new_key);
47
+
48
+ // ... replace the old $legacy_ciphertext with the new $new_ciphertext
49
+
50
+ // ...
51
+ ```
vendor/defuse/php-encryption/docs/classes/Crypto.md ADDED
@@ -0,0 +1,280 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Class: Defuse\Crypto\Crypto
2
+ ============================
3
+
4
+ The `Crypto` class provides encryption and decryption of strings either using
5
+ a secret key or secret password. For encryption and decryption of large files,
6
+ see the `File` class.
7
+
8
+ This code for this class is in `src/Crypto.php`.
9
+
10
+ Instance Methods
11
+ -----------------
12
+
13
+ This class has no instance methods.
14
+
15
+ Static Methods
16
+ ---------------
17
+
18
+ ### Crypto::encrypt($plaintext, Key $key, $raw\_binary = false)
19
+
20
+ **Description:**
21
+
22
+ Encrypts a plaintext string using a secret key.
23
+
24
+ **Parameters:**
25
+
26
+ 1. `$plaintext` is the string to encrypt.
27
+ 2. `$key` is an instance of `Key` containing the secret key for encryption.
28
+ 3. `$raw_binary` determines whether the output will be a byte string (true) or
29
+ hex encoded (false, the default).
30
+
31
+ **Return value:**
32
+
33
+ Returns a ciphertext string representing `$plaintext` encrypted with the key
34
+ `$key`. Knowledge of `$key` is required in order to decrypt the ciphertext and
35
+ recover the plaintext.
36
+
37
+ **Exceptions:**
38
+
39
+ - `Defuse\Crypto\Exception\EnvironmentIsBrokenException` is thrown either when
40
+ the platform the code is running on cannot safely perform encryption for some
41
+ reason (e.g. it lacks a secure random number generator), or the runtime tests
42
+ detected a bug in this library.
43
+
44
+ - `\TypeError` is thrown if the parameters are not of the expected types.
45
+
46
+ **Side-effects and performance:**
47
+
48
+ This method runs a small and very fast set of self-tests if it is the very first
49
+ time one of the `Crypto` methods has been called. The performance overhead is
50
+ negligible and can be safely ignored in all applications.
51
+
52
+ **Cautions:**
53
+
54
+ The ciphertext returned by this method is decryptable by anyone with knowledge
55
+ of the key `$key`. It is the caller's responsibility to keep `$key` secret.
56
+ Where `$key` should be stored is up to the caller and depends on the threat
57
+ model the caller is designing their application under. If you are unsure where
58
+ to store `$key`, consult with a professional cryptographer to get help designing
59
+ your application.
60
+
61
+ Please note that **encryption does not, and is not intended to, hide the
62
+ *length* of the data being encrypted.** For example, it is not safe to encrypt
63
+ a field in which only a small number of different-length values are possible
64
+ (e.g. "male" or "female") since it would be possible to tell what the plaintext
65
+ is by looking at the length of the ciphertext. In order to do this safely, it is
66
+ your responsibility to, before encrypting, pad the data out to the length of the
67
+ longest string that will ever be encrypted. This way, all plaintexts are the
68
+ same length, and no information about the plaintext can be gleaned from the
69
+ length of the ciphertext.
70
+
71
+ ### Crypto::decrypt($ciphertext, Key $key, $raw\_binary = false)
72
+
73
+ **Description:**
74
+
75
+ Decrypts a ciphertext string using a secret key.
76
+
77
+ **Parameters:**
78
+
79
+ 1. `$ciphertext` is the ciphertext to be decrypted.
80
+ 2. `$key` is an instance of `Key` containing the secret key for decryption.
81
+ 3. `$raw_binary` must have the same value as the `$raw_binary` given to the
82
+ call to `encrypt()` that generated `$ciphertext`.
83
+
84
+ **Return value:**
85
+
86
+ If the decryption succeeds, returns a string containing the same value as the
87
+ string that was passed to `encrypt()` when `$ciphertext` was produced. Upon
88
+ a successful return, the caller can be assured that `$ciphertext` could not have
89
+ been produced except by someone with knowledge of `$key`.
90
+
91
+ **Exceptions:**
92
+
93
+ - `Defuse\Crypto\Exception\EnvironmentIsBrokenException` is thrown either when
94
+ the platform the code is running on cannot safely perform encryption for some
95
+ reason (e.g. it lacks a secure random number generator), or the runtime tests
96
+ detected a bug in this library.
97
+
98
+ - `Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException` is thrown if
99
+ the `$key` is not the correct key for the given ciphertext, or if the
100
+ ciphertext has been modified (possibly maliciously). There is no way to
101
+ distinguish between these two cases.
102
+
103
+ - `\TypeError` is thrown if the parameters are not of the expected types.
104
+
105
+ **Side-effects and performance:**
106
+
107
+ This method runs a small and very fast set of self-tests if it is the very first
108
+ time one of the `Crypto` methods has been called. The performance overhead is
109
+ negligible and can be safely ignored in all applications.
110
+
111
+ **Cautions:**
112
+
113
+ It is impossible in principle to distinguish between the case where you attempt
114
+ to decrypt with the wrong key and the case where you attempt to decrypt
115
+ a modified (corrupted) ciphertext. It is up to the caller how to best deal with
116
+ this ambiguity, as it depends on the application this library is being used in.
117
+ If in doubt, consult with a professional cryptographer.
118
+
119
+ ### Crypto::encryptWithPassword($plaintext, $password, $raw\_binary = false)
120
+
121
+ **Description:**
122
+
123
+ Encrypts a plaintext string using a secret password.
124
+
125
+ **Parameters:**
126
+
127
+ 1. `$plaintext` is the string to encrypt.
128
+ 2. `$password` is a string containing the secret password used for encryption.
129
+ 3. `$raw_binary` determines whether the output will be a byte string (true) or
130
+ hex encoded (false, the default).
131
+
132
+ **Return value:**
133
+
134
+ Returns a ciphertext string representing `$plaintext` encrypted with a key
135
+ derived from `$password`. Knowledge of `$password` is required in order to
136
+ decrypt the ciphertext and recover the plaintext.
137
+
138
+ **Exceptions:**
139
+
140
+ - `Defuse\Crypto\Exception\EnvironmentIsBrokenException` is thrown either when
141
+ the platform the code is running on cannot safely perform encryption for some
142
+ reason (e.g. it lacks a secure random number generator), or the runtime tests
143
+ detected a bug in this library.
144
+
145
+ - `\TypeError` is thrown if the parameters are not of the expected types.
146
+
147
+ **Side-effects and performance:**
148
+
149
+ This method is intentionally slow, using a lot of CPU resources for a fraction
150
+ of a second. It applies key stretching to the password in order to make password
151
+ guessing attacks more computationally expensive. If you need a faster way to
152
+ encrypt multiple ciphertexts under the same password, see the
153
+ `KeyProtectedByPassword` class.
154
+
155
+ This method runs a small and very fast set of self-tests if it is the very first
156
+ time one of the `Crypto` methods has been called. The performance overhead is
157
+ negligible and can be safely ignored in all applications.
158
+
159
+ **Cautions:**
160
+
161
+ PHP stack traces display (portions of) the arguments passed to methods on the
162
+ call stack. If an exception is thrown inside this call, and it is uncaught, the
163
+ value of `$password` may be leaked out to an attacker through the stack trace.
164
+ We recommend configuring PHP to never output stack traces (either displaying
165
+ them to the user or saving them to log files).
166
+
167
+ ### Crypto::decryptWithPassword($ciphertext, $password, $raw\_binary = false)
168
+
169
+ **Description:**
170
+
171
+ Decrypts a ciphertext string using a secret password.
172
+
173
+ **Parameters:**
174
+
175
+ 1. `$ciphertext` is the ciphertext to be decrypted.
176
+ 2. `$password` is a string containing the secret password used for decryption.
177
+ 3. `$raw_binary` must have the same value as the `$raw_binary` given to the
178
+ call to `encryptWithPassword()` that generated `$ciphertext`.
179
+
180
+ **Return value:**
181
+
182
+ If the decryption succeeds, returns a string containing the same value as the
183
+ string that was passed to `encryptWithPassword()` when `$ciphertext` was
184
+ produced. Upon a successful return, the caller can be assured that `$ciphertext`
185
+ could not have been produced except by someone with knowledge of `$password`.
186
+
187
+ **Exceptions:**
188
+
189
+ - `Defuse\Crypto\Exception\EnvironmentIsBrokenException` is thrown either when
190
+ the platform the code is running on cannot safely perform encryption for some
191
+ reason (e.g. it lacks a secure random number generator), or the runtime tests
192
+ detected a bug in this library.
193
+
194
+ - `Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException` is thrown if
195
+ the `$password` is not the correct password for the given ciphertext, or if
196
+ the ciphertext has been modified (possibly maliciously). There is no way to
197
+ distinguish between these two cases.
198
+
199
+ - `\TypeError` is thrown if the parameters are not of the expected types.
200
+
201
+ **Side-effects:**
202
+
203
+ This method is intentionally slow. It applies key stretching to the password in
204
+ order to make password guessing attacks more computationally expensive. If you
205
+ need a faster way to encrypt multiple ciphertexts under the same password, see
206
+ the `KeyProtectedByPassword` class.
207
+
208
+ This method runs a small and very fast set of self-tests if it is the very first
209
+ time one of the `Crypto` methods has been called. The performance overhead is
210
+ negligible and can be safely ignored in all applications.
211
+
212
+ **Cautions:**
213
+
214
+ PHP stack traces display (portions of) the arguments passed to methods on the
215
+ call stack. If an exception is thrown inside this call, and it is uncaught, the
216
+ value of `$password` may be leaked out to an attacker through the stack trace.
217
+ We recommend configuring PHP to never output stack traces (either displaying
218
+ them to the user or saving them to log files).
219
+
220
+ It is impossible in principle to distinguish between the case where you attempt
221
+ to decrypt with the wrong password and the case where you attempt to decrypt
222
+ a modified (corrupted) ciphertext. It is up to the caller how to best deal with
223
+ this ambiguity, as it depends on the application this library is being used in.
224
+ If in doubt, consult with a professional cryptographer.
225
+
226
+ ### Crypto::legacyDecrypt($ciphertext, $key)
227
+
228
+ **Description:**
229
+
230
+ Decrypts a ciphertext produced by version 1 of this library so that the
231
+ plaintext can be re-encrypted into a version 2 ciphertext. See [Upgrading from
232
+ v1.2](../UpgradingFromV1.2.md).
233
+
234
+ **Parameters:**
235
+
236
+ 1. `$ciphertext` is a ciphertext produced by version 1.x of this library.
237
+ 2. `$key` is a 16-byte string (*not* a Key object) containing the key that was
238
+ used with version 1.x of this library to produce `$ciphertext`.
239
+
240
+ **Return value:**
241
+
242
+ If the decryption succeeds, returns the string that was encrypted to make
243
+ `$ciphertext` by version 1.x of this library. Upon a successful return, the
244
+ caller can be assured that `$ciphertext` could not have been produced except by
245
+ someone with knowledge of `$key`.
246
+
247
+ **Exceptions:**
248
+
249
+ - `Defuse\Crypto\Exception\EnvironmentIsBrokenException` is thrown either when
250
+ the platform the code is running on cannot safely perform encryption for some
251
+ reason (e.g. it lacks a secure random number generator), or the runtime tests
252
+ detected a bug in this library.
253
+
254
+ - `Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException` is thrown if
255
+ the `$key` is not the correct key for the given ciphertext, or if the
256
+ ciphertext has been modified (possibly maliciously). There is no way to
257
+ distinguish between these two cases.
258
+
259
+ - `\TypeError` is thrown if the parameters are not of the expected types.
260
+
261
+ **Side-effects:**
262
+
263
+ This method runs a small and very fast set of self-tests if it is the very first
264
+ time one of the `Crypto` methods has been called. The performance overhead is
265
+ negligible and can be safely ignored in all applications.
266
+
267
+ **Cautions:**
268
+
269
+ PHP stack traces display (portions of) the arguments passed to methods on the
270
+ call stack. If an exception is thrown inside this call, and it is uncaught, the
271
+ value of `$key` may be leaked out to an attacker through the stack trace. We
272
+ recommend configuring PHP to never output stack traces (either displaying them
273
+ to the user or saving them to log files).
274
+
275
+ It is impossible in principle to distinguish between the case where you attempt
276
+ to decrypt with the wrong key and the case where you attempt to decrypt
277
+ a modified (corrupted) ciphertext. It is up to the caller how to best deal with
278
+ this ambiguity, as it depends on the application this library is being used in.
279
+ If in doubt, consult with a professional cryptographer.
280
+
vendor/defuse/php-encryption/docs/classes/File.md ADDED
@@ -0,0 +1,486 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Class: Defuse\Crypto\File
2
+ ==========================
3
+
4
+ Instance Methods
5
+ -----------------
6
+
7
+ This class has no instance methods.
8
+
9
+ Static Methods
10
+ ---------------
11
+
12
+ ### File::encryptFile($inputFilename, $outputFilename, Key $key)
13
+
14
+ **Description:**
15
+
16
+ Encrypts a file using a secret key.
17
+
18
+ **Parameters:**
19
+
20
+ 1. `$inputFilename` is the path to a file containing the plaintext to encrypt.
21
+ 2. `$outputFilename` is the path to save the ciphertext file.
22
+ 3. `$key` is an instance of `Key` containing the secret key for encryption.
23
+
24
+ **Behavior:**
25
+
26
+ Encrypts the contents of the input file, writing the result to the output file.
27
+ If the output file already exists, it is overwritten.
28
+
29
+ **Return value:**
30
+
31
+ Does not return a value.
32
+
33
+ **Exceptions:**
34
+
35
+ - `Defuse\Crypto\Exception\IOException` is thrown if there is an I/O error.
36
+
37
+ - `Defuse\Crypto\Exception\EnvironmentIsBrokenException` is thrown either when
38
+ the platform the code is running on cannot safely perform encryption for some
39
+ reason (e.g. it lacks a secure random number generator), or the runtime tests
40
+ detected a bug in this library.
41
+
42
+ **Side-effects and performance:**
43
+
44
+ None.
45
+
46
+ **Cautions:**
47
+
48
+ The ciphertext output by this method is decryptable by anyone with knowledge of
49
+ the key `$key`. It is the caller's responsibility to keep `$key` secret. Where
50
+ `$key` should be stored is up to the caller and depends on the threat model the
51
+ caller is designing their application under. If you are unsure where to store
52
+ `$key`, consult with a professional cryptographer to get help designing your
53
+ application.
54
+
55
+ Please note that **encryption does not, and is not intended to, hide the
56
+ *length* of the data being encrypted.** For example, it is not safe to encrypt
57
+ a field in which only a small number of different-length values are possible
58
+ (e.g. "male" or "female") since it would be possible to tell what the plaintext
59
+ is by looking at the length of the ciphertext. In order to do this safely, it is
60
+ your responsibility to, before encrypting, pad the data out to the length of the
61
+ longest string that will ever be encrypted. This way, all plaintexts are the
62
+ same length, and no information about the plaintext can be gleaned from the
63
+ length of the ciphertext.
64
+
65
+ ### File::decryptFile($inputFilename, $outputFilename, Key $key)
66
+
67
+ **Description:**
68
+
69
+ Decrypts a file using a secret key.
70
+
71
+ **Parameters:**
72
+
73
+ 1. `$inputFilename` is the path to a file containing the ciphertext to decrypt.
74
+ 2. `$outputFilename` is the path to save the decrypted plaintext file.
75
+ 3. `$key` is an instance of `Key` containing the secret key for decryption.
76
+
77
+ **Behavior:**
78
+
79
+ Decrypts the contents of the input file, writing the result to the output file.
80
+ If the output file already exists, it is overwritten.
81
+
82
+ **Return value:**
83
+
84
+ Does not return a value.
85
+
86
+ **Exceptions:**
87
+
88
+ - `Defuse\Crypto\Exception\IOException` is thrown if there is an I/O error.
89
+
90
+ - `Defuse\Crypto\Exception\EnvironmentIsBrokenException` is thrown either when
91
+ the platform the code is running on cannot safely perform encryption for some
92
+ reason (e.g. it lacks a secure random number generator), or the runtime tests
93
+ detected a bug in this library.
94
+
95
+ - `Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException` is thrown if
96
+ the `$key` is not the correct key for the given ciphertext, or if the
97
+ ciphertext has been modified (possibly maliciously). There is no way to
98
+ distinguish between these two cases.
99
+
100
+ **Side-effects and performance:**
101
+
102
+ The input ciphertext is processed in two passes. The first pass verifies the
103
+ integrity and the second pass performs the actual decryption of the file and
104
+ writing to the output file. This is done in a streaming manner so that only
105
+ a small part of the file is ever loaded into memory at a time.
106
+
107
+ **Cautions:**
108
+
109
+ Be aware that when `Defuse\Crypto\WrongKeyOrModifiedCiphertextException` is
110
+ thrown, some partial plaintext data may have been written to the output. Any
111
+ plaintext data that is output is guaranteed to be a prefix of the original
112
+ plaintext (i.e. at worst it was truncated). This can only happen if an attacker
113
+ modifies the input between the first pass (integrity check) and the second pass
114
+ (decryption) over the file.
115
+
116
+ It is impossible in principle to distinguish between the case where you attempt
117
+ to decrypt with the wrong key and the case where you attempt to decrypt
118
+ a modified (corrupted) ciphertext. It is up to the caller how to best deal with
119
+ this ambiguity, as it depends on the application this library is being used in.
120
+ If in doubt, consult with a professional cryptographer.
121
+
122
+ ### File::encryptFileWithPassword($inputFilename, $outputFilename, $password)
123
+
124
+ **Description:**
125
+
126
+ Encrypts a file with a password.
127
+
128
+ **Parameters:**
129
+
130
+ 1. `$inputFilename` is the path to a file containing the plaintext to encrypt.
131
+ 2. `$outputFilename` is the path to save the ciphertext file.
132
+ 3. `$password` is the password used for decryption.
133
+
134
+ **Behavior:**
135
+
136
+ Encrypts the contents of the input file, writing the result to the output file.
137
+ If the output file already exists, it is overwritten.
138
+
139
+ **Return value:**
140
+
141
+ Does not return a value.
142
+
143
+ **Exceptions:**
144
+
145
+ - `Defuse\Crypto\Exception\IOException` is thrown if there is an I/O error.
146
+
147
+ - `Defuse\Crypto\Exception\EnvironmentIsBrokenException` is thrown either when
148
+ the platform the code is running on cannot safely perform encryption for some
149
+ reason (e.g. it lacks a secure random number generator), or the runtime tests
150
+ detected a bug in this library.
151
+
152
+ **Side-effects and performance:**
153
+
154
+ This method is intentionally slow, using a lot of CPU resources for a fraction
155
+ of a second. It applies key stretching to the password in order to make password
156
+ guessing attacks more computationally expensive. If you need a faster way to
157
+ encrypt multiple ciphertexts under the same password, see the
158
+ `KeyProtectedByPassword` class.
159
+
160
+ **Cautions:**
161
+
162
+ PHP stack traces display (portions of) the arguments passed to methods on the
163
+ call stack. If an exception is thrown inside this call, and it is uncaught, the
164
+ value of `$password` may be leaked out to an attacker through the stack trace.
165
+ We recommend configuring PHP to never output stack traces (either displaying
166
+ them to the user or saving them to log files).
167
+
168
+ Please note that **encryption does not, and is not intended to, hide the
169
+ *length* of the data being encrypted.** For example, it is not safe to encrypt
170
+ a field in which only a small number of different-length values are possible
171
+ (e.g. "male" or "female") since it would be possible to tell what the plaintext
172
+ is by looking at the length of the ciphertext. In order to do this safely, it is
173
+ your responsibility to, before encrypting, pad the data out to the length of the
174
+ longest string that will ever be encrypted. This way, all plaintexts are the
175
+ same length, and no information about the plaintext can be gleaned from the
176
+ length of the ciphertext.
177
+
178
+ ### File::decryptFileWithPassword($inputFilename, $outputFilename, $password)
179
+
180
+ **Description:**
181
+
182
+ Decrypts a file with a password.
183
+
184
+ **Parameters:**
185
+
186
+ 1. `$inputFilename` is the path to a file containing the ciphertext to decrypt.
187
+ 2. `$outputFilename` is the path to save the decrypted plaintext file.
188
+ 3. `$password` is the password used for decryption.
189
+
190
+ **Behavior:**
191
+
192
+ Decrypts the contents of the input file, writing the result to the output file.
193
+ If the output file already exists, it is overwritten.
194
+
195
+ **Return value:**
196
+
197
+ Does not return a value.
198
+
199
+ **Exceptions:**
200
+
201
+ - `Defuse\Crypto\Exception\IOException` is thrown if there is an I/O error.
202
+
203
+ - `Defuse\Crypto\Exception\EnvironmentIsBrokenException` is thrown either when
204
+ the platform the code is running on cannot safely perform encryption for some
205
+ reason (e.g. it lacks a secure random number generator), or the runtime tests
206
+ detected a bug in this library.
207
+
208
+ - `Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException` is thrown if
209
+ the `$password` is not the correct key for the given ciphertext, or if the
210
+ ciphertext has been modified (possibly maliciously). There is no way to
211
+ distinguish between these two cases.
212
+
213
+ **Side-effects and performance:**
214
+
215
+ This method is intentionally slow, using a lot of CPU resources for a fraction
216
+ of a second. It applies key stretching to the password in order to make password
217
+ guessing attacks more computationally expensive. If you need a faster way to
218
+ encrypt multiple ciphertexts under the same password, see the
219
+ `KeyProtectedByPassword` class.
220
+
221
+ The input ciphertext is processed in two passes. The first pass verifies the
222
+ integrity and the second pass performs the actual decryption of the file and
223
+ writing to the output file. This is done in a streaming manner so that only
224
+ a small part of the file is ever loaded into memory at a time.
225
+
226
+ **Cautions:**
227
+
228
+ PHP stack traces display (portions of) the arguments passed to methods on the
229
+ call stack. If an exception is thrown inside this call, and it is uncaught, the
230
+ value of `$password` may be leaked out to an attacker through the stack trace.
231
+ We recommend configuring PHP to never output stack traces (either displaying
232
+ them to the user or saving them to log files).
233
+
234
+ Be aware that when `Defuse\Crypto\WrongKeyOrModifiedCiphertextException` is
235
+ thrown, some partial plaintext data may have been written to the output. Any
236
+ plaintext data that is output is guaranteed to be a prefix of the original
237
+ plaintext (i.e. at worst it was truncated). This can only happen if an attacker
238
+ modifies the input between the first pass (integrity check) and the second pass
239
+ (decryption) over the file.
240
+
241
+ It is impossible in principle to distinguish between the case where you attempt
242
+ to decrypt with the wrong password and the case where you attempt to decrypt
243
+ a modified (corrupted) ciphertext. It is up to the caller how to best deal with
244
+ this ambiguity, as it depends on the application this library is being used in.
245
+ If in doubt, consult with a professional cryptographer.
246
+
247
+ ### File::encryptResource($inputHandle, $outputHandle, Key $key)
248
+
249
+ **Description:**
250
+
251
+ Encrypts a resource (stream) with a secret key.
252
+
253
+ **Parameters:**
254
+
255
+ 1. `$inputHandle` is a handle to a resource (like a file pointer) containing the
256
+ plaintext to encrypt.
257
+ 2. `$outputHandle` is a handle to a resource (like a file pointer) that the
258
+ ciphertext will be written to.
259
+ 3. `$key` is an instance of `Key` containing the secret key for encryption.
260
+
261
+ **Behavior:**
262
+
263
+ Encrypts the data read from the input stream and writes it to the output stream.
264
+
265
+ **Return value:**
266
+
267
+ Does not return a value.
268
+
269
+ **Exceptions:**
270
+
271
+ - `Defuse\Crypto\Exception\IOException` is thrown if there is an I/O error.
272
+
273
+ - `Defuse\Crypto\Exception\EnvironmentIsBrokenException` is thrown either when
274
+ the platform the code is running on cannot safely perform encryption for some
275
+ reason (e.g. it lacks a secure random number generator), or the runtime tests
276
+ detected a bug in this library.
277
+
278
+ **Side-effects and performance:**
279
+
280
+ None.
281
+
282
+ **Cautions:**
283
+
284
+ The ciphertext output by this method is decryptable by anyone with knowledge of
285
+ the key `$key`. It is the caller's responsibility to keep `$key` secret. Where
286
+ `$key` should be stored is up to the caller and depends on the threat model the
287
+ caller is designing their application under. If you are unsure where to store
288
+ `$key`, consult with a professional cryptographer to get help designing your
289
+ application.
290
+
291
+ Please note that **encryption does not, and is not intended to, hide the
292
+ *length* of the data being encrypted.** For example, it is not safe to encrypt
293
+ a field in which only a small number of different-length values are possible
294
+ (e.g. "male" or "female") since it would be possible to tell what the plaintext
295
+ is by looking at the length of the ciphertext. In order to do this safely, it is
296
+ your responsibility to, before encrypting, pad the data out to the length of the
297
+ longest string that will ever be encrypted. This way, all plaintexts are the
298
+ same length, and no information about the plaintext can be gleaned from the
299
+ length of the ciphertext.
300
+
301
+ ### File::decryptResource($inputHandle, $outputHandle, Key $key)
302
+
303
+ **Description:**
304
+
305
+ Decrypts a resource (stream) with a secret key.
306
+
307
+ **Parameters:**
308
+
309
+ 1. `$inputHandle` is a handle to a file-backed resource containing the
310
+ ciphertext to decrypt. It must be a file not a network stream or standard
311
+ input.
312
+ 2. `$outputHandle` is a handle to a resource (like a file pointer) that the
313
+ plaintext will be written to.
314
+ 3. `$key` is an instance of `Key` containing the secret key for decryption.
315
+
316
+ **Behavior:**
317
+
318
+ Decrypts the data read from the input stream and writes it to the output stream.
319
+
320
+ **Return value:**
321
+
322
+ Does not return a value.
323
+
324
+ **Exceptions:**
325
+
326
+ - `Defuse\Crypto\Exception\IOException` is thrown if there is an I/O error.
327
+
328
+ - `Defuse\Crypto\Exception\EnvironmentIsBrokenException` is thrown either when
329
+ the platform the code is running on cannot safely perform encryption for some
330
+ reason (e.g. it lacks a secure random number generator), or the runtime tests
331
+ detected a bug in this library.
332
+
333
+ - `Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException` is thrown if
334
+ the `$key` is not the correct key for the given ciphertext, or if the
335
+ ciphertext has been modified (possibly maliciously). There is no way to
336
+ distinguish between these two cases.
337
+
338
+ **Side-effects and performance:**
339
+
340
+ The input ciphertext is processed in two passes. The first pass verifies the
341
+ integrity and the second pass performs the actual decryption of the file and
342
+ writing to the output file. This is done in a streaming manner so that only
343
+ a small part of the file is ever loaded into memory at a time.
344
+
345
+ **Cautions:**
346
+
347
+ Be aware that when `Defuse\Crypto\WrongKeyOrModifiedCiphertextException` is
348
+ thrown, some partial plaintext data may have been written to the output. Any
349
+ plaintext data that is output is guaranteed to be a prefix of the original
350
+ plaintext (i.e. at worst it was truncated). This can only happen if an attacker
351
+ modifies the input between the first pass (integrity check) and the second pass
352
+ (decryption) over the file.
353
+
354
+ It is impossible in principle to distinguish between the case where you attempt
355
+ to decrypt with the wrong key and the case where you attempt to decrypt
356
+ a modified (corrupted) ciphertext. It is up to the caller how to best deal with
357
+ this ambiguity, as it depends on the application this library is being used in.
358
+ If in doubt, consult with a professional cryptographer.
359
+
360
+ ### File::encryptResourceWithPassword($inputHandle, $outputHandle, $password)
361
+
362
+ **Description:**
363
+
364
+ Encrypts a resource (stream) with a password.
365
+
366
+ **Parameters:**
367
+
368
+ 1. `$inputHandle` is a handle to a resource (like a file pointer) containing the
369
+ plaintext to encrypt.
370
+ 2. `$outputHandle` is a handle to a resource (like a file pointer) that the
371
+ ciphertext will be written to.
372
+ 3. `$password` is the password used for encryption.
373
+
374
+ **Behavior:**
375
+
376
+ Encrypts the data read from the input stream and writes it to the output stream.
377
+
378
+ **Return value:**
379
+
380
+ Does not return a value.
381
+
382
+ **Exceptions:**
383
+
384
+ - `Defuse\Crypto\Exception\IOException` is thrown if there is an I/O error.
385
+
386
+ - `Defuse\Crypto\Exception\EnvironmentIsBrokenException` is thrown either when
387
+ the platform the code is running on cannot safely perform encryption for some
388
+ reason (e.g. it lacks a secure random number generator), or the runtime tests
389
+ detected a bug in this library.
390
+
391
+ **Side-effects and performance:**
392
+
393
+ This method is intentionally slow, using a lot of CPU resources for a fraction
394
+ of a second. It applies key stretching to the password in order to make password
395
+ guessing attacks more computationally expensive. If you need a faster way to
396
+ encrypt multiple ciphertexts under the same password, see the
397
+ `KeyProtectedByPassword` class.
398
+
399
+ **Cautions:**
400
+
401
+ PHP stack traces display (portions of) the arguments passed to methods on the
402
+ call stack. If an exception is thrown inside this call, and it is uncaught, the
403
+ value of `$password` may be leaked out to an attacker through the stack trace.
404
+ We recommend configuring PHP to never output stack traces (either displaying
405
+ them to the user or saving them to log files).
406
+
407
+ Please note that **encryption does not, and is not intended to, hide the
408
+ *length* of the data being encrypted.** For example, it is not safe to encrypt
409
+ a field in which only a small number of different-length values are possible
410
+ (e.g. "male" or "female") since it would be possible to tell what the plaintext
411
+ is by looking at the length of the ciphertext. In order to do this safely, it is
412
+ your responsibility to, before encrypting, pad the data out to the length of the
413
+ longest string that will ever be encrypted. This way, all plaintexts are the
414
+ same length, and no information about the plaintext can be gleaned from the
415
+ length of the ciphertext.
416
+
417
+ ### File::decryptResourceWithPassword($inputHandle, $outputHandle, $password)
418
+
419
+ **Description:**
420
+
421
+ Decrypts a resource (stream) with a password.
422
+
423
+ **Parameters:**
424
+
425
+ 1. `$inputHandle` is a handle to a file-backed resource containing the
426
+ ciphertext to decrypt. It must be a file not a network stream or standard
427
+ input.
428
+ 2. `$outputHandle` is a handle to a resource (like a file pointer) that the
429
+ plaintext will be written to.
430
+ 3. `$password` is the password used for decryption.
431
+
432
+ **Behavior:**
433
+
434
+ Decrypts the data read from the input stream and writes it to the output stream.
435
+
436
+ **Return value:**
437
+
438
+ Does not return a value.
439
+
440
+ **Exceptions:**
441
+
442
+ - `Defuse\Crypto\Exception\IOException` is thrown if there is an I/O error.
443
+
444
+ - `Defuse\Crypto\Exception\EnvironmentIsBrokenException` is thrown either when
445
+ the platform the code is running on cannot safely perform encryption for some
446
+ reason (e.g. it lacks a secure random number generator), or the runtime tests
447
+ detected a bug in this library.
448
+
449
+ - `Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException` is thrown if
450
+ the `$password` is not the correct key for the given ciphertext, or if the
451
+ ciphertext has been modified (possibly maliciously). There is no way to
452
+ distinguish between these two cases.
453
+
454
+ **Side-effects and performance:**
455
+
456
+ This method is intentionally slow, using a lot of CPU resources for a fraction
457
+ of a second. It applies key stretching to the password in order to make password
458
+ guessing attacks more computationally expensive. If you need a faster way to
459
+ encrypt multiple ciphertexts under the same password, see the
460
+ `KeyProtectedByPassword` class.
461
+
462
+ The input ciphertext is processed in two passes. The first pass verifies the
463
+ integrity and the second pass performs the actual decryption of the file and
464
+ writing to the output file. This is done in a streaming manner so that only
465
+ a small part of the file is ever loaded into memory at a time.
466
+
467
+ **Cautions:**
468
+
469
+ PHP stack traces display (portions of) the arguments passed to methods on the
470
+ call stack. If an exception is thrown inside this call, and it is uncaught, the
471
+ value of `$password` may be leaked out to an attacker through the stack trace.
472
+ We recommend configuring PHP to never output stack traces (either displaying
473
+ them to the user or saving them to log files).
474
+
475
+ Be aware that when `Defuse\Crypto\WrongKeyOrModifiedCiphertextException` is
476
+ thrown, some partial plaintext data may have been written to the output. Any
477
+ plaintext data that is output is guaranteed to be a prefix of the original
478
+ plaintext (i.e. at worst it was truncated). This can only happen if an attacker
479
+ modifies the input between the first pass (integrity check) and the second pass
480
+ (decryption) over the file.
481
+
482
+ It is impossible in principle to distinguish between the case where you attempt
483
+ to decrypt with the wrong password and the case where you attempt to decrypt
484
+ a modified (corrupted) ciphertext. It is up to the caller how to best deal with
485
+ this ambiguity, as it depends on the application this library is being used in.
486
+ If in doubt, consult with a professional cryptographer.
vendor/defuse/php-encryption/docs/classes/Key.md ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Class: Defuse\Crypto\Key
2
+ =========================
3
+
4
+ The `Key` class represents a secret key used for encrypting and decrypting. Once
5
+ you have a `Key` instance, you can use it with the `Crypto` class to encrypt and
6
+ decrypt strings and with the `File` class to encrypt and decrypt files.
7
+
8
+ Instance Methods
9
+ -----------------
10
+
11
+ ### saveToAsciiSafeString()
12
+
13
+ **Description:**
14
+
15
+ Saves the encryption key to a string of printable ASCII characters, which can be
16
+ loaded again into a `Key` instance using `Key::loadFromAsciiSafeString()`.
17
+
18
+ **Parameters:**
19
+
20
+ This method does not take any parameters.
21
+
22
+ **Return value:**
23
+
24
+ Returns a string of printable ASCII characters representing this `Key` instance,
25
+ which can be loaded back into an instance of `Key` using
26
+ `Key::loadFromAsciiSafeString()`.
27
+
28
+ **Exceptions:**
29
+
30
+ - `Defuse\Crypto\Exception\EnvironmentIsBrokenException` is thrown either when
31
+ the platform the code is running on cannot safely perform encryption for some
32
+ reason (e.g. it lacks a secure random number generator), or the runtime tests
33
+ detected a bug in this library.
34
+
35
+ **Side-effects and performance:**
36
+
37
+ None.
38
+
39
+ **Cautions:**
40
+
41
+ This method currently returns a hexadecimal string. You should not rely on this
42
+ behavior. For example, it may be improved in the future to return a base64
43
+ string.
44
+
45
+ Static Methods
46
+ ---------------
47
+
48
+ ### Key::createNewRandomKey()
49
+
50
+ **Description:**
51
+
52
+ Generates a new random key and returns an instance of `Key`.
53
+
54
+ **Parameters:**
55
+
56
+ This method does not take any parameters.
57
+
58
+ **Return value:**
59
+
60
+ Returns an instance of `Key` containing a randomly-generated encryption key.
61
+
62
+ **Exceptions:**
63
+
64
+ - `Defuse\Crypto\Exception\EnvironmentIsBrokenException` is thrown either when
65
+ the platform the code is running on cannot safely perform encryption for some
66
+ reason (e.g. it lacks a secure random number generator), or the runtime tests
67
+ detected a bug in this library.
68
+
69
+ **Side-effects and performance:**
70
+
71
+ None.
72
+
73
+ **Cautions:**
74
+
75
+ None.
76
+
77
+ ### Key::loadFromAsciiSafeString($saved\_key\_string, $do\_not\_trim = false)
78
+
79
+ **Description:**
80
+
81
+ Loads an instance of `Key` that was saved to a string by
82
+ `saveToAsciiSafeString()`.
83
+
84
+ By default, this function will call `Encoding::trimTrailingWhitespace()`
85
+ to remove trailing CR, LF, NUL, TAB, and SPACE characters, which are commonly
86
+ appended to files when working with text editors.
87
+
88
+ **Parameters:**
89
+
90
+ 1. `$saved_key_string` is the string returned from `saveToAsciiSafeString()`
91
+ when the original `Key` instance was saved.
92
+ 2. `$do_not_trim` should be set to `TRUE` if you do not wish for the library
93
+ to automatically strip trailing whitespace from the string.
94
+
95
+ **Return value:**
96
+
97
+ Returns an instance of `Key` representing the same encryption key as the one
98
+ that was represented by the `Key` instance that got saved into
99
+ `$saved_key_string` by a call to `saveToAsciiSafeString()`.
100
+
101
+ **Exceptions:**
102
+
103
+ - `Defuse\Crypto\Exception\EnvironmentIsBrokenException` is thrown either when
104
+ the platform the code is running on cannot safely perform encryption for some
105
+ reason (e.g. it lacks a secure random number generator), or the runtime tests
106
+ detected a bug in this library.
107
+
108
+ - `Defuse\Crypto\Exception\BadFormatException` is thrown whenever
109
+ `$saved_key_string` does not represent a valid `Key` instance.
110
+
111
+ **Side-effects and performance:**
112
+
113
+ None.
114
+
115
+ **Cautions:**
116
+
117
+ None.
vendor/defuse/php-encryption/docs/classes/KeyProtectedByPassword.md ADDED
@@ -0,0 +1,259 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Class: Defuse\Crypto\KeyProtectedByPassword
2
+ ============================================
3
+
4
+ The `KeyProtectedByPassword` class represents a key that is "locked" with
5
+ a password. In order to obtain an instance of `Key` that you can use for
6
+ encrypting and decrypting, a `KeyProtectedByPassword` must first be "unlocked"
7
+ by providing the correct password.
8
+
9
+ `KeyProtectedByPassword` provides an alternative to using the
10
+ `encryptWithPassword()`, `decryptWithPassword()`, `encryptFileWithPassword()`,
11
+ and `decryptFileWithPassword()` methods with several advantages:
12
+
13
+ - The slow and computationally-expensive key stretching is run only once when
14
+ you unlock a `KeyProtectedByPassword` to obtain the `Key`.
15
+ - You do not have to keep the original password in memory to encrypt and decrypt
16
+ things. After you've obtained the `Key` from a `KeyProtectedByPassword`, the
17
+ password is no longer necessary.
18
+
19
+ Instance Methods
20
+ -----------------
21
+
22
+ ### saveToAsciiSafeString()
23
+
24
+ **Description:**
25
+
26
+ Saves the protected key to a string of printable ASCII characters, which can be
27
+ loaded again into a `KeyProtectedByPassword` instance using
28
+ `KeyProtectedByPassword::loadFromAsciiSafeString()`.
29
+
30
+ **Parameters:**
31
+
32
+ This method does not take any parameters.
33
+
34
+ **Return value:**
35
+
36
+ Returns a string of printable ASCII characters representing this
37
+ `KeyProtectedByPassword` instance, which can be loaded back into an instance of
38
+ `KeyProtectedByPassword` using
39
+ `KeyProtectedByPassword::loadFromAsciiSafeString()`.
40
+
41
+ **Exceptions:**
42
+
43
+ - `Defuse\Crypto\Exception\EnvironmentIsBrokenException` is thrown either when
44
+ the platform the code is running on cannot safely perform encryption for some
45
+ reason (e.g. it lacks a secure random number generator), or the runtime tests
46
+ detected a bug in this library.
47
+
48
+ **Side-effects and performance:**
49
+
50
+ None.
51
+
52
+ **Cautions:**
53
+
54
+ This method currently returns a hexadecimal string. You should not rely on this
55
+ behavior. For example, it may be improved in the future to return a base64
56
+ string.
57
+
58
+ ### unlockKey($password)
59
+
60
+ **Description:**
61
+
62
+ Unlocks the password-protected key, obtaining a `Key` which can be used for
63
+ encryption and decryption.
64
+
65
+ **Parameters:**
66
+
67
+ 1. `$password` is the password required to unlock this `KeyProtectedByPassword`
68
+ to obtain the `Key`.
69
+
70
+ **Return value:**
71
+
72
+ If `$password` is the correct password, then this method returns an instance of
73
+ the `Key` class.
74
+
75
+ **Exceptions:**
76
+
77
+ - `Defuse\Crypto\Exception\EnvironmentIsBrokenException` is thrown either when
78
+ the platform the code is running on cannot safely perform encryption for some
79
+ reason (e.g. it lacks a secure random number generator), or the runtime tests
80
+ detected a bug in this library.
81
+
82
+ - `Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException` is thrown if
83
+ either the given `$password` is not the correct password for this
84
+ `KeyProtectedByPassword` or the ciphertext stored internally by this object
85
+ has been modified, i.e. it was accidentally corrupted or intentionally
86
+ corrupted by an attacker. There is no way for the caller to distinguish
87
+ between these two cases.
88
+
89
+ **Side-effects and performance:**
90
+
91
+ This method runs a small and very fast set of self-tests if it is the very first
92
+ time this method or one of the `Crypto` methods has been called. The performance
93
+ overhead is negligible and can be safely ignored in all applications.
94
+
95
+ **Cautions:**
96
+
97
+ PHP stack traces display (portions of) the arguments passed to methods on the
98
+ call stack. If an exception is thrown inside this call, and it is uncaught, the
99
+ value of `$password` may be leaked out to an attacker through the stack trace.
100
+ We recommend configuring PHP to never output stack traces (either displaying
101
+ them to the user or saving them to log files).
102
+
103
+ It is impossible in principle to distinguish between the case where you attempt
104
+ to unlock with the wrong password and the case where you attempt to unlock
105
+ a modified (corrupted) `KeyProtectedByPassword`. It is up to the caller how to
106
+ best deal with this ambiguity, as it depends on the application this library is
107
+ being used in. If in doubt, consult with a professional cryptographer.
108
+
109
+ ### changePassword($current\_password, $new\_password)
110
+
111
+ **Description:**
112
+
113
+ Changes the password, so that calling `unlockKey` on this object in the future
114
+ will require you to pass `$new\_password` instead of the old password. It is
115
+ your responsibility to overwrite all stored copies of this
116
+ `KeyProtectedByPassword`. Any copies you leave lying around can still be
117
+ decrypted with the old password.
118
+
119
+ **Parameters:**
120
+
121
+ 1. `$current\_password` is the password that this `KeyProtectedByPassword` is
122
+ currently protected with.
123
+ 2. `$new\_password` is the new password, which the `KeyProtectedByPassword` will
124
+ be protected with once this operation completes.
125
+
126
+ **Return value:**
127
+
128
+ If `$current\_password` is the correct password, then this method updates itself
129
+ to be protected with the new password, and also returns itself.
130
+
131
+ **Exceptions:**
132
+
133
+ - `Defuse\Crypto\Exception\EnvironmentIsBrokenException` is thrown either when
134
+ the platform the code is running on cannot safely perform encryption for some
135
+ reason (e.g. it lacks a secure random number generator), or the runtime tests
136
+ detected a bug in this library.
137
+
138
+ - `Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException` is thrown if
139
+ either the given `$current\_password` is not the correct password for this
140
+ `KeyProtectedByPassword` or the ciphertext stored internally by this object
141
+ has been modified, i.e. it was accidentally corrupted or intentionally
142
+ corrupted by an attacker. There is no way for the caller to distinguish
143
+ between these two cases.
144
+
145
+ **Side-effects and performance:**
146
+
147
+ This method runs a small and very fast set of self-tests if it is the very first
148
+ time this method or one of the `Crypto` methods has been called. The performance
149
+ overhead is negligible and can be safely ignored in all applications.
150
+
151
+ **Cautions:**
152
+
153
+ PHP stack traces display (portions of) the arguments passed to methods on the
154
+ call stack. If an exception is thrown inside this call, and it is uncaught, the
155
+ value of `$password` may be leaked out to an attacker through the stack trace.
156
+ We recommend configuring PHP to never output stack traces (either displaying
157
+ them to the user or saving them to log files).
158
+
159
+ It is impossible in principle to distinguish between the case where you attempt
160
+ to unlock with the wrong password and the case where you attempt to unlock
161
+ a modified (corrupted) `KeyProtectedByPassword`. It is up to the caller how to
162
+ best deal with this ambiguity, as it depends on the application this library is
163
+ being used in. If in doubt, consult with a professional cryptographer.
164
+
165
+ **WARNING:** Because of the way `KeyProtectedByPassword` is implemented, knowing
166
+ `SHA256($password)` is enough to decrypt a `KeyProtectedByPassword`. To be
167
+ secure, your application MUST NOT EVER compute `SHA256($password)` and use or
168
+ store it for any reason. You must also make sure that other libraries your
169
+ application is using don't compute it either.
170
+
171
+ Static Methods
172
+ ---------------
173
+
174
+ ### KeyProtectedByPassword::createRandomPasswordProtectedKey($password)
175
+
176
+ **Description:**
177
+
178
+ Generates a new random key that's protected by the string `$password` and
179
+ returns an instance of `KeyProtectedByPassword`.
180
+
181
+ **Parameters:**
182
+
183
+ 1. `$password` is the password used to protect the random key.
184
+
185
+ **Return value:**
186
+
187
+ Returns an instance of `KeyProtectedByPassword` containing a randomly-generated
188
+ encryption key that's protected by the password `$password`.
189
+
190
+ **Exceptions:**
191
+
192
+ - `Defuse\Crypto\Exception\EnvironmentIsBrokenException` is thrown either when
193
+ the platform the code is running on cannot safely perform encryption for some
194
+ reason (e.g. it lacks a secure random number generator), or the runtime tests
195
+ detected a bug in this library.
196
+
197
+ **Side-effects and performance:**
198
+
199
+ This method runs a small and very fast set of self-tests if it is the very first
200
+ time this method or one of the `Crypto` methods has been called. The performance
201
+ overhead is negligible and can be safely ignored in all applications.
202
+
203
+ **Cautions:**
204
+
205
+ PHP stack traces display (portions of) the arguments passed to methods on the
206
+ call stack. If an exception is thrown inside this call, and it is uncaught, the
207
+ value of `$password` may be leaked out to an attacker through the stack trace.
208
+ We recommend configuring PHP to never output stack traces (either displaying
209
+ them to the user or saving them to log files).
210
+
211
+ Be aware that if you protecting multiple keys with the same password, an
212
+ attacker with write access to your system will be able to swap the protected
213
+ keys around so that the wrong key gets used next time it is unlocked. This could
214
+ lead to data being encrypted with the wrong key, perhaps one that the attacker
215
+ knows.
216
+
217
+ **WARNING:** Because of the way `KeyProtectedByPassword` is implemented, knowing
218
+ `SHA256($password)` is enough to decrypt a `KeyProtectedByPassword`. To be
219
+ secure, your application MUST NOT EVER compute `SHA256($password)` and use or
220
+ store it for any reason. You must also make sure that other libraries your
221
+ application is using don't compute it either.
222
+
223
+ ### KeyProtectedByPassword::loadFromAsciiSafeString($saved\_key\_string)
224
+
225
+ **Description:**
226
+
227
+ Loads an instance of `KeyProtectedByPassword` that was saved to a string by
228
+ `saveToAsciiSafeString()`.
229
+
230
+ **Parameters:**
231
+
232
+ 1. `$saved_key_string` is the string returned from `saveToAsciiSafeString()`
233
+ when the original `KeyProtectedByPassword` instance was saved.
234
+
235
+ **Return value:**
236
+
237
+ Returns an instance of `KeyProtectedByPassword` representing the same
238
+ password-protected key as the one that was represented by the
239
+ `KeyProtectedByPassword` instance that got saved into `$saved_key_string` by
240
+ a call to `saveToAsciiSafeString()`.
241
+
242
+ **Exceptions:**
243
+
244
+ - `Defuse\Crypto\Exception\EnvironmentIsBrokenException` is thrown either when
245
+ the platform the code is running on cannot safely perform encryption for some
246
+ reason (e.g. it lacks a secure random number generator), or the runtime tests
247
+ detected a bug in this library.
248
+
249
+ - `Defuse\Crypto\Exception\BadFormatException` is thrown whenever
250
+ `$saved_key_string` does not represent a valid `KeyProtectedByPassword`
251
+ instance.
252
+
253
+ **Side-effects and performance:**
254
+
255
+ None.
256
+
257
+ **Cautions:**
258
+
259
+ None.
vendor/defuse/php-encryption/psalm.xml ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <psalm
3
+ useDocblockTypes="true"
4
+ >
5
+ <projectFiles>
6
+ <directory name="src" />
7
+ </projectFiles>
8
+ <issueHandlers>
9
+ <DocblockTypeContradiction errorLevel="info" />
10
+ <RedundantConditionGivenDocblockType errorLevel="info" />
11
+ </issueHandlers>
12
+ </psalm>
vendor/defuse/php-encryption/src/Core.php ADDED
@@ -0,0 +1,448 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Defuse\Crypto;
4
+
5
+ use Defuse\Crypto\Exception as Ex;
6
+
7
+ final class Core
8
+ {
9
+ const HEADER_VERSION_SIZE = 4;
10
+ const MINIMUM_CIPHERTEXT_SIZE = 84;
11
+
12
+ const CURRENT_VERSION = "\xDE\xF5\x02\x00";
13
+
14
+ const CIPHER_METHOD = 'aes-256-ctr';
15
+ const BLOCK_BYTE_SIZE = 16;
16
+ const KEY_BYTE_SIZE = 32;
17
+ const SALT_BYTE_SIZE = 32;
18
+ const MAC_BYTE_SIZE = 32;
19
+ const HASH_FUNCTION_NAME = 'sha256';
20
+ const ENCRYPTION_INFO_STRING = 'DefusePHP|V2|KeyForEncryption';
21
+ const AUTHENTICATION_INFO_STRING = 'DefusePHP|V2|KeyForAuthentication';
22
+ const BUFFER_BYTE_SIZE = 1048576;
23
+
24
+ const LEGACY_CIPHER_METHOD = 'aes-128-cbc';
25
+ const LEGACY_BLOCK_BYTE_SIZE = 16;
26
+ const LEGACY_KEY_BYTE_SIZE = 16;
27
+ const LEGACY_HASH_FUNCTION_NAME = 'sha256';
28
+ const LEGACY_MAC_BYTE_SIZE = 32;
29
+ const LEGACY_ENCRYPTION_INFO_STRING = 'DefusePHP|KeyForEncryption';
30
+ const LEGACY_AUTHENTICATION_INFO_STRING = 'DefusePHP|KeyForAuthentication';
31
+
32
+ /*
33
+ * V2.0 Format: VERSION (4 bytes) || SALT (32 bytes) || IV (16 bytes) ||
34
+ * CIPHERTEXT (varies) || HMAC (32 bytes)
35
+ *
36
+ * V1.0 Format: HMAC (32 bytes) || IV (16 bytes) || CIPHERTEXT (varies).
37
+ */
38
+
39
+ /**
40
+ * Adds an integer to a block-sized counter.
41
+ *
42
+ * @param string $ctr
43
+ * @param int $inc
44
+ *
45
+ * @throws Ex\EnvironmentIsBrokenException
46
+ *
47
+ * @return string
48
+ *
49
+ * @psalm-suppress RedundantCondition - It's valid to use is_int to check for overflow.
50
+ */
51
+ public static function incrementCounter($ctr, $inc)
52
+ {
53
+ Core::ensureTrue(
54
+ Core::ourStrlen($ctr) === Core::BLOCK_BYTE_SIZE,
55
+ 'Trying to increment a nonce of the wrong size.'
56
+ );
57
+
58
+ Core::ensureTrue(
59
+ \is_int($inc),
60
+ 'Trying to increment nonce by a non-integer.'
61
+ );
62
+
63
+ // The caller is probably re-using CTR-mode keystream if they increment by 0.
64
+ Core::ensureTrue(
65
+ $inc > 0,
66
+ 'Trying to increment a nonce by a nonpositive amount'
67
+ );
68
+
69
+ Core::ensureTrue(
70
+ $inc <= PHP_INT_MAX - 255,
71
+ 'Integer overflow may occur'
72
+ );
73
+
74
+ /*
75
+ * We start at the rightmost byte (big-endian)
76
+ * So, too, does OpenSSL: http://stackoverflow.com/a/3146214/2224584
77
+ */
78
+ for ($i = Core::BLOCK_BYTE_SIZE - 1; $i >= 0; --$i) {
79
+ $sum = \ord($ctr[$i]) + $inc;
80
+
81
+ /* Detect integer overflow and fail. */
82
+ Core::ensureTrue(\is_int($sum), 'Integer overflow in CTR mode nonce increment');
83
+
84
+ $ctr[$i] = \pack('C', $sum & 0xFF);
85
+ $inc = $sum >> 8;
86
+ }
87
+ return $ctr;
88
+ }
89
+
90
+ /**
91
+ * Returns a random byte string of the specified length.
92
+ *
93
+ * @param int $octets
94
+ *
95
+ * @throws Ex\EnvironmentIsBrokenException
96
+ *
97
+ * @return string
98
+ */
99
+ public static function secureRandom($octets)
100
+ {
101
+ self::ensureFunctionExists('random_bytes');
102
+ try {
103
+ return \random_bytes($octets);
104
+ } catch (\Exception $ex) {
105
+ throw new Ex\EnvironmentIsBrokenException(
106
+ 'Your system does not have a secure random number generator.'
107
+ );
108
+ }
109
+ }
110
+
111
+ /**
112
+ * Computes the HKDF key derivation function specified in
113
+ * http://tools.ietf.org/html/rfc5869.
114
+ *
115
+ * @param string $hash Hash Function
116
+ * @param string $ikm Initial Keying Material
117
+ * @param int $length How many bytes?
118
+ * @param string $info What sort of key are we deriving?
119
+ * @param string $salt
120
+ *
121
+ * @throws Ex\EnvironmentIsBrokenException
122
+ * @psalm-suppress UndefinedFunction - We're checking if the function exists first.
123
+ *
124
+ * @return string
125
+ */
126
+ public static function HKDF($hash, $ikm, $length, $info = '', $salt = null)
127
+ {
128
+ static $nativeHKDF = null;
129
+ if ($nativeHKDF === null) {
130
+ $nativeHKDF = \is_callable('\\hash_hkdf');
131
+ }
132
+ if ($nativeHKDF) {
133
+ if (\is_null($salt)) {
134
+ $salt = '';
135
+ }
136
+ return \hash_hkdf($hash, $ikm, $length, $info, $salt);
137
+ }
138
+
139
+ $digest_length = Core::ourStrlen(\hash_hmac($hash, '', '', true));
140
+
141
+ // Sanity-check the desired output length.
142
+ Core::ensureTrue(
143
+ !empty($length) && \is_int($length) && $length >= 0 && $length <= 255 * $digest_length,
144
+ 'Bad output length requested of HDKF.'
145
+ );
146
+
147
+ // "if [salt] not provided, is set to a string of HashLen zeroes."
148
+ if (\is_null($salt)) {
149
+ $salt = \str_repeat("\x00", $digest_length);
150
+ }
151
+
152
+ // HKDF-Extract:
153
+ // PRK = HMAC-Hash(salt, IKM)
154
+ // The salt is the HMAC key.
155
+ $prk = \hash_hmac($hash, $ikm, $salt, true);
156
+
157
+ // HKDF-Expand:
158
+
159
+ // This check is useless, but it serves as a reminder to the spec.
160
+ Core::ensureTrue(Core::ourStrlen($prk) >= $digest_length);
161
+
162
+ // T(0) = ''
163
+ $t = '';
164
+ $last_block = '';
165
+ for ($block_index = 1; Core::ourStrlen($t) < $length; ++$block_index) {
166
+ // T(i) = HMAC-Hash(PRK, T(i-1) | info | 0x??)
167
+ $last_block = \hash_hmac(
168
+ $hash,
169
+ $last_block . $info . \chr($block_index),
170
+ $prk,
171
+ true
172
+ );
173
+ // T = T(1) | T(2) | T(3) | ... | T(N)
174
+ $t .= $last_block;
175
+ }
176
+
177
+ // ORM = first L octets of T
178
+ /** @var string $orm */
179
+ $orm = Core::ourSubstr($t, 0, $length);
180
+ Core::ensureTrue(\is_string($orm));
181
+ return $orm;
182
+ }
183
+
184
+ /**
185
+ * Checks if two equal-length strings are the same without leaking
186
+ * information through side channels.
187
+ *
188
+ * @param string $expected
189
+ * @param string $given
190
+ *
191
+ * @throws Ex\EnvironmentIsBrokenException
192
+ *
193
+ * @return bool
194
+ */
195
+ public static function hashEquals($expected, $given)
196
+ {
197
+ static $native = null;
198
+ if ($native === null) {
199
+ $native = \function_exists('hash_equals');
200
+ }
201
+ if ($native) {
202
+ return \hash_equals($expected, $given);
203
+ }
204
+
205
+ // We can't just compare the strings with '==', since it would make
206
+ // timing attacks possible. We could use the XOR-OR constant-time
207
+ // comparison algorithm, but that may not be a reliable defense in an
208
+ // interpreted language. So we use the approach of HMACing both strings
209
+ // with a random key and comparing the HMACs.
210
+
211
+ // We're not attempting to make variable-length string comparison
212
+ // secure, as that's very difficult. Make sure the strings are the same
213
+ // length.
214
+ Core::ensureTrue(Core::ourStrlen($expected) === Core::ourStrlen($given));
215
+
216
+ $blind = Core::secureRandom(32);
217
+ $message_compare = \hash_hmac(Core::HASH_FUNCTION_NAME, $given, $blind);
218
+ $correct_compare = \hash_hmac(Core::HASH_FUNCTION_NAME, $expected, $blind);
219
+ return $correct_compare === $message_compare;
220
+ }
221
+ /**
222
+ * Throws an exception if the constant doesn't exist.
223
+ *
224
+ * @param string $name
225
+ * @return void
226
+ *
227
+ * @throws Ex\EnvironmentIsBrokenException
228
+ */
229
+ public static function ensureConstantExists($name)
230
+ {
231
+ Core::ensureTrue(\defined($name));
232
+ }
233
+
234
+ /**
235
+ * Throws an exception if the function doesn't exist.
236
+ *
237
+ * @param string $name
238
+ * @return void
239
+ *
240
+ * @throws Ex\EnvironmentIsBrokenException
241
+ */
242
+ public static function ensureFunctionExists($name)
243
+ {
244
+ Core::ensureTrue(\function_exists($name));
245
+ }
246
+
247
+ /**
248
+ * Throws an exception if the condition is false.
249
+ *
250
+ * @param bool $condition
251
+ * @param string $message
252
+ * @return void
253
+ *
254
+ * @throws Ex\EnvironmentIsBrokenException
255
+ */
256
+ public static function ensureTrue($condition, $message = '')
257
+ {
258
+ if (!$condition) {
259
+ throw new Ex\EnvironmentIsBrokenException($message);
260
+ }
261
+ }
262
+
263
+ /*
264
+ * We need these strlen() and substr() functions because when
265
+ * 'mbstring.func_overload' is set in php.ini, the standard strlen() and
266
+ * substr() are replaced by mb_strlen() and mb_substr().
267
+ */
268
+
269
+ /**
270
+ * Computes the length of a string in bytes.
271
+ *
272
+ * @param string $str
273
+ *
274
+ * @throws Ex\EnvironmentIsBrokenException
275
+ *
276
+ * @return int
277
+ */
278
+ public static function ourStrlen($str)
279
+ {
280
+ static $exists = null;
281
+ if ($exists === null) {
282
+ $exists = \extension_loaded('mbstring') && \ini_get('mbstring.func_overload') !== false && (int)\ini_get('mbstring.func_overload') & MB_OVERLOAD_STRING;
283
+ }
284
+ if ($exists) {
285
+ $length = \mb_strlen($str, '8bit');
286
+ Core::ensureTrue($length !== false);
287
+ return $length;
288
+ } else {
289
+ return \strlen($str);
290
+ }
291
+ }
292
+
293
+ /**
294
+ * Behaves roughly like the function substr() in PHP 7 does.
295
+ *
296
+ * @param string $str
297
+ * @param int $start
298
+ * @param int $length
299
+ *
300
+ * @throws Ex\EnvironmentIsBrokenException
301
+ *
302
+ * @return string|bool
303
+ */
304
+ public static function ourSubstr($str, $start, $length = null)
305
+ {
306
+ static $exists = null;
307
+ if ($exists === null) {
308
+ $exists = \extension_loaded('mbstring') && \ini_get('mbstring.func_overload') !== false && (int)\ini_get('mbstring.func_overload') & MB_OVERLOAD_STRING;
309
+ }
310
+
311
+ // This is required to make mb_substr behavior identical to substr.
312
+ // Without this, mb_substr() would return false, contra to what the
313
+ // PHP documentation says (it doesn't say it can return false.)
314
+ $input_len = Core::ourStrlen($str);
315
+ if ($start === $input_len && !$length) {
316
+ return '';
317
+ }
318
+
319
+ if ($start > $input_len) {
320
+ return false;
321
+ }
322
+
323
+ // mb_substr($str, 0, NULL, '8bit') returns an empty string on PHP 5.3,
324
+ // so we have to find the length ourselves. Also, substr() doesn't
325
+ // accept null for the length.
326
+ if (! isset($length)) {
327
+ if ($start >= 0) {
328
+ $length = $input_len - $start;
329
+ } else {
330
+ $length = -$start;
331
+ }
332
+ }
333
+
334
+ if ($length < 0) {
335
+ throw new \InvalidArgumentException(
336
+ "Negative lengths are not supported with ourSubstr."
337
+ );
338
+ }
339
+
340
+ if ($exists) {
341
+ $substr = \mb_substr($str, $start, $length, '8bit');
342
+ // At this point there are two cases where mb_substr can
343
+ // legitimately return an empty string. Either $length is 0, or
344
+ // $start is equal to the length of the string (both mb_substr and
345
+ // substr return an empty string when this happens). It should never
346
+ // ever return a string that's longer than $length.
347
+ if (Core::ourStrlen($substr) > $length || (Core::ourStrlen($substr) === 0 && $length !== 0 && $start !== $input_len)) {
348
+ throw new Ex\EnvironmentIsBrokenException(
349
+ 'Your version of PHP has bug #66797. Its implementation of
350
+ mb_substr() is incorrect. See the details here:
351
+ https://bugs.php.net/bug.php?id=66797'
352
+ );
353
+ }
354
+ return $substr;
355
+ }
356
+
357
+ return \substr($str, $start, $length);
358
+ }
359
+
360
+ /**
361
+ * Computes the PBKDF2 password-based key derivation function.
362
+ *
363
+ * The PBKDF2 function is defined in RFC 2898. Test vectors can be found in
364
+ * RFC 6070. This implementation of PBKDF2 was originally created by Taylor
365
+ * Hornby, with improvements from http://www.variations-of-shadow.com/.
366
+ *
367
+ * @param string $algorithm The hash algorithm to use. Recommended: SHA256
368
+ * @param string $password The password.
369
+ * @param string $salt A salt that is unique to the password.
370
+ * @param int $count Iteration count. Higher is better, but slower. Recommended: At least 1000.
371
+ * @param int $key_length The length of the derived key in bytes.
372
+ * @param bool $raw_output If true, the key is returned in raw binary format. Hex encoded otherwise.
373
+ *
374
+ * @throws Ex\EnvironmentIsBrokenException
375
+ *
376
+ * @return string A $key_length-byte key derived from the password and salt.
377
+ */
378
+ public static function pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output = false)
379
+ {
380
+ // Type checks:
381
+ if (! \is_string($algorithm)) {
382
+ throw new \InvalidArgumentException(
383
+ 'pbkdf2(): algorithm must be a string'
384
+ );
385
+ }
386
+ if (! \is_string($password)) {
387
+ throw new \InvalidArgumentException(
388
+ 'pbkdf2(): password must be a string'
389
+ );
390
+ }
391
+ if (! \is_string($salt)) {
392
+ throw new \InvalidArgumentException(
393
+ 'pbkdf2(): salt must be a string'
394
+ );
395
+ }
396
+ // Coerce strings to integers with no information loss or overflow
397
+ $count += 0;
398
+ $key_length += 0;
399
+
400
+ $algorithm = \strtolower($algorithm);
401
+ Core::ensureTrue(
402
+ \in_array($algorithm, \hash_algos(), true),
403
+ 'Invalid or unsupported hash algorithm.'
404
+ );
405
+
406
+ // Whitelist, or we could end up with people using CRC32.
407
+ $ok_algorithms = [
408
+ 'sha1', 'sha224', 'sha256', 'sha384', 'sha512',
409
+ 'ripemd160', 'ripemd256', 'ripemd320', 'whirlpool',
410
+ ];
411
+ Core::ensureTrue(
412
+ \in_array($algorithm, $ok_algorithms, true),
413
+ 'Algorithm is not a secure cryptographic hash function.'
414
+ );
415
+
416
+ Core::ensureTrue($count > 0 && $key_length > 0, 'Invalid PBKDF2 parameters.');
417
+
418
+ if (\function_exists('hash_pbkdf2')) {
419
+ // The output length is in NIBBLES (4-bits) if $raw_output is false!
420
+ if (! $raw_output) {
421
+ $key_length = $key_length * 2;
422
+ }
423
+ return \hash_pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output);
424
+ }
425
+
426
+ $hash_length = Core::ourStrlen(\hash($algorithm, '', true));
427
+ $block_count = \ceil($key_length / $hash_length);
428
+
429
+ $output = '';
430
+ for ($i = 1; $i <= $block_count; $i++) {
431
+ // $i encoded as 4 bytes, big endian.
432
+ $last = $salt . \pack('N', $i);
433
+ // first iteration
434
+ $last = $xorsum = \hash_hmac($algorithm, $last, $password, true);
435
+ // perform the other $count - 1 iterations
436
+ for ($j = 1; $j < $count; $j++) {
437
+ $xorsum ^= ($last = \hash_hmac($algorithm, $last, $password, true));
438
+ }
439
+ $output .= $xorsum;
440
+ }
441
+
442
+ if ($raw_output) {
443
+ return (string) Core::ourSubstr($output, 0, $key_length);
444
+ } else {
445
+ return Encoding::binToHex((string) Core::ourSubstr($output, 0, $key_length));
446
+ }
447
+ }
448
+ }
vendor/defuse/php-encryption/src/Crypto.php ADDED
@@ -0,0 +1,445 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Defuse\Crypto;
4
+
5
+ use Defuse\Crypto\Exception as Ex;
6
+
7
+ class Crypto
8
+ {
9
+ /**
10
+ * Encrypts a string with a Key.
11
+ *
12
+ * @param string $plaintext
13
+ * @param Key $key
14
+ * @param bool $raw_binary
15
+ *
16
+ * @throws Ex\EnvironmentIsBrokenException
17
+ * @throws \TypeError
18
+ *
19
+ * @return string
20
+ */
21
+ public static function encrypt($plaintext, $key, $raw_binary = false)
22
+ {
23
+ if (!\is_string($plaintext)) {
24
+ throw new \TypeError(
25
+ 'String expected for argument 1. ' . \ucfirst(\gettype($plaintext)) . ' given instead.'
26
+ );
27
+ }
28
+ if (!($key instanceof Key)) {
29
+ throw new \TypeError(
30
+ 'Key expected for argument 2. ' . \ucfirst(\gettype($key)) . ' given instead.'
31
+ );
32
+ }
33
+ if (!\is_bool($raw_binary)) {
34
+ throw new \TypeError(
35
+ 'Boolean expected for argument 3. ' . \ucfirst(\gettype($raw_binary)) . ' given instead.'
36
+ );
37
+ }
38
+ return self::encryptInternal(
39
+ $plaintext,
40
+ KeyOrPassword::createFromKey($key),
41
+ $raw_binary
42
+ );
43
+ }
44
+
45
+ /**
46
+ * Encrypts a string with a password, using a slow key derivation function
47
+ * to make password cracking more expensive.
48
+ *
49
+ * @param string $plaintext
50
+ * @param string $password
51
+ * @param bool $raw_binary
52
+ *
53
+ * @throws Ex\EnvironmentIsBrokenException
54
+ * @throws \TypeError
55
+ *
56
+ * @return string
57
+ */
58
+ public static function encryptWithPassword($plaintext, $password, $raw_binary = false)
59
+ {
60
+ if (!\is_string($plaintext)) {
61
+ throw new \TypeError(
62
+ 'String expected for argument 1. ' . \ucfirst(\gettype($plaintext)) . ' given instead.'
63
+ );
64
+ }
65
+ if (!\is_string($password)) {
66
+ throw new \TypeError(
67
+ 'String expected for argument 2. ' . \ucfirst(\gettype($password)) . ' given instead.'
68
+ );
69
+ }
70
+ if (!\is_bool($raw_binary)) {
71
+ throw new \TypeError(
72
+ 'Boolean expected for argument 3. ' . \ucfirst(\gettype($raw_binary)) . ' given instead.'
73
+ );
74
+ }
75
+ return self::encryptInternal(
76
+ $plaintext,
77
+ KeyOrPassword::createFromPassword($password),
78
+ $raw_binary
79
+ );
80
+ }
81
+
82
+ /**
83
+ * Decrypts a ciphertext to a string with a Key.
84
+ *
85
+ * @param string $ciphertext
86
+ * @param Key $key
87
+ * @param bool $raw_binary
88
+ *
89
+ * @throws \TypeError
90
+ * @throws Ex\EnvironmentIsBrokenException
91
+ * @throws Ex\WrongKeyOrModifiedCiphertextException
92
+ *
93
+ * @return string
94
+ */
95
+ public static function decrypt($ciphertext, $key, $raw_binary = false)
96
+ {
97
+ if (!\is_string($ciphertext)) {
98
+ throw new \TypeError(
99
+ 'String expected for argument 1. ' . \ucfirst(\gettype($ciphertext)) . ' given instead.'
100
+ );
101
+ }
102
+ if (!($key instanceof Key)) {
103
+ throw new \TypeError(
104
+ 'Key expected for argument 2. ' . \ucfirst(\gettype($key)) . ' given instead.'
105
+ );
106
+ }
107
+ if (!\is_bool($raw_binary)) {
108
+ throw new \TypeError(
109
+ 'Boolean expected for argument 3. ' . \ucfirst(\gettype($raw_binary)) . ' given instead.'
110
+ );
111
+ }
112
+ return self::decryptInternal(
113
+ $ciphertext,
114
+ KeyOrPassword::createFromKey($key),
115
+ $raw_binary
116
+ );
117
+ }
118
+
119
+ /**
120
+ * Decrypts a ciphertext to a string with a password, using a slow key
121
+ * derivation function to make password cracking more expensive.
122
+ *
123
+ * @param string $ciphertext
124
+ * @param string $password
125
+ * @param bool $raw_binary
126
+ *
127
+ * @throws Ex\EnvironmentIsBrokenException
128
+ * @throws Ex\WrongKeyOrModifiedCiphertextException
129
+ * @throws \TypeError
130
+ *
131
+ * @return string
132
+ */
133
+ public static function decryptWithPassword($ciphertext, $password, $raw_binary = false)
134
+ {
135
+ if (!\is_string($ciphertext)) {
136
+ throw new \TypeError(
137
+ 'String expected for argument 1. ' . \ucfirst(\gettype($ciphertext)) . ' given instead.'
138
+ );
139
+ }
140
+ if (!\is_string($password)) {
141
+ throw new \TypeError(
142
+ 'String expected for argument 2. ' . \ucfirst(\gettype($password)) . ' given instead.'
143
+ );
144
+ }
145
+ if (!\is_bool($raw_binary)) {
146
+ throw new \TypeError(
147
+ 'Boolean expected for argument 3. ' . \ucfirst(\gettype($raw_binary)) . ' given instead.'
148
+ );
149
+ }
150
+ return self::decryptInternal(
151
+ $ciphertext,
152
+ KeyOrPassword::createFromPassword($password),
153
+ $raw_binary
154
+ );
155
+ }
156
+
157
+ /**
158
+ * Decrypts a legacy ciphertext produced by version 1 of this library.
159
+ *
160
+ * @param string $ciphertext
161
+ * @param string $key
162
+ *
163
+ * @throws Ex\EnvironmentIsBrokenException
164
+ * @throws Ex\WrongKeyOrModifiedCiphertextException
165
+ * @throws \TypeError
166
+ *
167
+ * @return string
168
+ */
169
+ public static function legacyDecrypt($ciphertext, $key)
170
+ {
171
+ if (!\is_string($ciphertext)) {
172
+ throw new \TypeError(
173
+ 'String expected for argument 1. ' . \ucfirst(\gettype($ciphertext)) . ' given instead.'
174
+ );
175
+ }
176
+ if (!\is_string($key)) {
177
+ throw new \TypeError(
178
+ 'String expected for argument 2. ' . \ucfirst(\gettype($key)) . ' given instead.'
179
+ );
180
+ }
181
+
182
+ RuntimeTests::runtimeTest();
183
+
184
+ // Extract the HMAC from the front of the ciphertext.
185
+ if (Core::ourStrlen($ciphertext) <= Core::LEGACY_MAC_BYTE_SIZE) {
186
+ throw new Ex\WrongKeyOrModifiedCiphertextException(
187
+ 'Ciphertext is too short.'
188
+ );
189
+ }
190
+ /**
191
+ * @var string
192
+ */
193
+ $hmac = Core::ourSubstr($ciphertext, 0, Core::LEGACY_MAC_BYTE_SIZE);
194
+ Core::ensureTrue(\is_string($hmac));
195
+ /**
196
+ * @var string
197
+ */
198
+ $messageCiphertext = Core::ourSubstr($ciphertext, Core::LEGACY_MAC_BYTE_SIZE);
199
+ Core::ensureTrue(\is_string($messageCiphertext));
200
+
201
+ // Regenerate the same authentication sub-key.
202
+ $akey = Core::HKDF(
203
+ Core::LEGACY_HASH_FUNCTION_NAME,
204
+ $key,
205
+ Core::LEGACY_KEY_BYTE_SIZE,
206
+ Core::LEGACY_AUTHENTICATION_INFO_STRING,
207
+ null
208
+ );
209
+
210
+ if (self::verifyHMAC($hmac, $messageCiphertext, $akey)) {
211
+ // Regenerate the same encryption sub-key.
212
+ $ekey = Core::HKDF(
213
+ Core::LEGACY_HASH_FUNCTION_NAME,
214
+ $key,
215
+ Core::LEGACY_KEY_BYTE_SIZE,
216
+ Core::LEGACY_ENCRYPTION_INFO_STRING,
217
+ null
218
+ );
219
+
220
+ // Extract the IV from the ciphertext.
221
+ if (Core::ourStrlen($messageCiphertext) <= Core::LEGACY_BLOCK_BYTE_SIZE) {
222
+ throw new Ex\WrongKeyOrModifiedCiphertextException(
223
+ 'Ciphertext is too short.'
224
+ );
225
+ }
226
+ /**
227
+ * @var string
228
+ */
229
+ $iv = Core::ourSubstr($messageCiphertext, 0, Core::LEGACY_BLOCK_BYTE_SIZE);
230
+ Core::ensureTrue(\is_string($iv));
231
+
232
+ /**
233
+ * @var string
234
+ */
235
+ $actualCiphertext = Core::ourSubstr($messageCiphertext, Core::LEGACY_BLOCK_BYTE_SIZE);
236
+ Core::ensureTrue(\is_string($actualCiphertext));
237
+
238
+ // Do the decryption.
239
+ $plaintext = self::plainDecrypt($actualCiphertext, $ekey, $iv, Core::LEGACY_CIPHER_METHOD);
240
+ return $plaintext;
241
+ } else {
242
+ throw new Ex\WrongKeyOrModifiedCiphertextException(
243
+ 'Integrity check failed.'
244
+ );
245
+ }
246
+ }
247
+
248
+ /**
249
+ * Encrypts a string with either a key or a password.
250
+ *
251
+ * @param string $plaintext
252
+ * @param KeyOrPassword $secret
253
+ * @param bool $raw_binary
254
+ *
255
+ * @return string
256
+ */
257
+ private static function encryptInternal($plaintext, KeyOrPassword $secret, $raw_binary)
258
+ {
259
+ RuntimeTests::runtimeTest();
260
+
261
+ $salt = Core::secureRandom(Core::SALT_BYTE_SIZE);
262
+ $keys = $secret->deriveKeys($salt);
263
+ $ekey = $keys->getEncryptionKey();
264
+ $akey = $keys->getAuthenticationKey();
265
+ $iv = Core::secureRandom(Core::BLOCK_BYTE_SIZE);
266
+
267
+ $ciphertext = Core::CURRENT_VERSION . $salt . $iv . self::plainEncrypt($plaintext, $ekey, $iv);
268
+ $auth = \hash_hmac(Core::HASH_FUNCTION_NAME, $ciphertext, $akey, true);
269
+ $ciphertext = $ciphertext . $auth;
270
+
271
+ if ($raw_binary) {
272
+ return $ciphertext;
273
+ }
274
+ return Encoding::binToHex($ciphertext);
275
+ }
276
+
277
+ /**
278
+ * Decrypts a ciphertext to a string with either a key or a password.
279
+ *
280
+ * @param string $ciphertext
281
+ * @param KeyOrPassword $secret
282
+ * @param bool $raw_binary
283
+ *
284
+ * @throws Ex\EnvironmentIsBrokenException
285
+ * @throws Ex\WrongKeyOrModifiedCiphertextException
286
+ *
287
+ * @return string
288
+ */
289
+ private static function decryptInternal($ciphertext, KeyOrPassword $secret, $raw_binary)
290
+ {
291
+ RuntimeTests::runtimeTest();
292
+
293
+ if (! $raw_binary) {
294
+ try {
295
+ $ciphertext = Encoding::hexToBin($ciphertext);
296
+ } catch (Ex\BadFormatException $ex) {
297
+ throw new Ex\WrongKeyOrModifiedCiphertextException(
298
+ 'Ciphertext has invalid hex encoding.'
299
+ );
300
+ }
301
+ }
302
+
303
+ if (Core::ourStrlen($ciphertext) < Core::MINIMUM_CIPHERTEXT_SIZE) {
304
+ throw new Ex\WrongKeyOrModifiedCiphertextException(
305
+ 'Ciphertext is too short.'
306
+ );
307
+ }
308
+
309
+ // Get and check the version header.
310
+ /** @var string $header */
311
+ $header = Core::ourSubstr($ciphertext, 0, Core::HEADER_VERSION_SIZE);
312
+ if ($header !== Core::CURRENT_VERSION) {
313
+ throw new Ex\WrongKeyOrModifiedCiphertextException(
314
+ 'Bad version header.'
315
+ );
316
+ }
317
+
318
+ // Get the salt.
319
+ /** @var string $salt */
320
+ $salt = Core::ourSubstr(
321
+ $ciphertext,
322
+ Core::HEADER_VERSION_SIZE,
323
+ Core::SALT_BYTE_SIZE
324
+ );
325
+ Core::ensureTrue(\is_string($salt));
326
+
327
+ // Get the IV.
328
+ /** @var string $iv */
329
+ $iv = Core::ourSubstr(
330
+ $ciphertext,
331
+ Core::HEADER_VERSION_SIZE + Core::SALT_BYTE_SIZE,
332
+ Core::BLOCK_BYTE_SIZE
333
+ );
334
+ Core::ensureTrue(\is_string($iv));
335
+
336
+ // Get the HMAC.
337
+ /** @var string $hmac */
338
+ $hmac = Core::ourSubstr(
339
+ $ciphertext,
340
+ Core::ourStrlen($ciphertext) - Core::MAC_BYTE_SIZE,
341
+ Core::MAC_BYTE_SIZE
342
+ );
343
+ Core::ensureTrue(\is_string($hmac));
344
+
345
+ // Get the actual encrypted ciphertext.
346
+ /** @var string $encrypted */
347
+ $encrypted = Core::ourSubstr(
348
+ $ciphertext,
349
+ Core::HEADER_VERSION_SIZE + Core::SALT_BYTE_SIZE +
350
+ Core::BLOCK_BYTE_SIZE,
351
+ Core::ourStrlen($ciphertext) - Core::MAC_BYTE_SIZE - Core::SALT_BYTE_SIZE -
352
+ Core::BLOCK_BYTE_SIZE - Core::HEADER_VERSION_SIZE
353
+ );
354
+ Core::ensureTrue(\is_string($encrypted));
355
+
356
+ // Derive the separate encryption and authentication keys from the key
357
+ // or password, whichever it is.
358
+ $keys = $secret->deriveKeys($salt);
359
+
360
+ if (self::verifyHMAC($hmac, $header . $salt . $iv . $encrypted, $keys->getAuthenticationKey())) {
361
+ $plaintext = self::plainDecrypt($encrypted, $keys->getEncryptionKey(), $iv, Core::CIPHER_METHOD);
362
+ return $plaintext;
363
+ } else {
364
+ throw new Ex\WrongKeyOrModifiedCiphertextException(
365
+ 'Integrity check failed.'
366
+ );
367
+ }
368
+ }
369
+
370
+ /**
371
+ * Raw unauthenticated encryption (insecure on its own).
372
+ *
373
+ * @param string $plaintext
374
+ * @param string $key
375
+ * @param string $iv
376
+ *
377
+ * @throws Ex\EnvironmentIsBrokenException
378
+ *
379
+ * @return string
380
+ */
381
+ protected static function plainEncrypt($plaintext, $key, $iv)
382
+ {
383
+ Core::ensureConstantExists('OPENSSL_RAW_DATA');
384
+ Core::ensureFunctionExists('openssl_encrypt');
385
+ /** @var string $ciphertext */
386
+ $ciphertext = \openssl_encrypt(
387
+ $plaintext,
388
+ Core::CIPHER_METHOD,
389
+ $key,
390
+ OPENSSL_RAW_DATA,
391
+ $iv
392
+ );
393
+
394
+ Core::ensureTrue(\is_string($ciphertext), 'openssl_encrypt() failed');
395
+
396
+ return $ciphertext;
397
+ }
398
+
399
+ /**
400
+ * Raw unauthenticated decryption (insecure on its own).
401
+ *
402
+ * @param string $ciphertext
403
+ * @param string $key
404
+ * @param string $iv
405
+ * @param string $cipherMethod
406
+ *
407
+ * @throws Ex\EnvironmentIsBrokenException
408
+ *
409
+ * @return string
410
+ */
411
+ protected static function plainDecrypt($ciphertext, $key, $iv, $cipherMethod)
412
+ {
413
+ Core::ensureConstantExists('OPENSSL_RAW_DATA');
414
+ Core::ensureFunctionExists('openssl_decrypt');
415
+
416
+ /** @var string $plaintext */
417
+ $plaintext = \openssl_decrypt(
418
+ $ciphertext,
419
+ $cipherMethod,
420
+ $key,
421
+ OPENSSL_RAW_DATA,
422
+ $iv
423
+ );
424
+ Core::ensureTrue(\is_string($plaintext), 'openssl_decrypt() failed.');
425
+
426
+ return $plaintext;
427
+ }
428
+
429
+ /**
430
+ * Verifies an HMAC without leaking information through side-channels.
431
+ *
432
+ * @param string $expected_hmac
433
+ * @param string $message
434
+ * @param string $key
435
+ *
436
+ * @throws Ex\EnvironmentIsBrokenException
437
+ *
438
+ * @return bool
439
+ */
440
+ protected static function verifyHMAC($expected_hmac, $message, $key)
441
+ {
442
+ $message_hmac = \hash_hmac(Core::HASH_FUNCTION_NAME, $message, $key, true);
443
+ return Core::hashEquals($message_hmac, $expected_hmac);
444
+ }
445
+ }
vendor/defuse/php-encryption/src/DerivedKeys.php ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Defuse\Crypto;
4
+
5
+ /**
6
+ * Class DerivedKeys
7
+ * @package Defuse\Crypto
8
+ */
9
+ final class DerivedKeys
10
+ {
11
+ /**
12
+ * @var string
13
+ */
14
+ private $akey = '';
15
+
16
+ /**
17
+ * @var string
18
+ */
19
+ private $ekey = '';
20
+
21
+ /**
22
+ * Returns the authentication key.
23
+ * @return string
24
+ */
25
+ public function getAuthenticationKey()
26
+ {
27
+ return $this->akey;
28
+ }
29
+
30
+ /**
31
+ * Returns the encryption key.
32
+ * @return string
33
+ */
34
+ public function getEncryptionKey()
35
+ {
36
+ return $this->ekey;
37
+ }
38
+
39
+ /**
40
+ * Constructor for DerivedKeys.
41
+ *
42
+ * @param string $akey
43
+ * @param string $ekey
44
+ */
45
+ public function __construct($akey, $ekey)
46
+ {
47
+ $this->akey = $akey;
48
+ $this->ekey = $ekey;
49
+ }
50
+ }
vendor/defuse/php-encryption/src/Encoding.php ADDED
@@ -0,0 +1,268 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Defuse\Crypto;
4
+
5
+ use Defuse\Crypto\Exception as Ex;
6
+
7
+ final class Encoding
8
+ {
9
+ const CHECKSUM_BYTE_SIZE = 32;
10
+ const CHECKSUM_HASH_ALGO = 'sha256';
11
+ const SERIALIZE_HEADER_BYTES = 4;
12
+
13
+ /**
14
+ * Converts a byte string to a hexadecimal string without leaking
15
+ * information through side channels.
16
+ *
17
+ * @param string $byte_string
18
+ *
19
+ * @throws Ex\EnvironmentIsBrokenException
20
+ *
21
+ * @return string
22
+ */
23
+ public static function binToHex($byte_string)
24
+ {
25
+ $hex = '';
26
+ $len = Core::ourStrlen($byte_string);
27
+ for ($i = 0; $i < $len; ++$i) {
28
+ $c = \ord($byte_string[$i]) & 0xf;
29
+ $b = \ord($byte_string[$i]) >> 4;
30
+ $hex .= \pack(
31
+ 'CC',
32
+ 87 + $b + ((($b - 10) >> 8) & ~38),
33
+ 87 + $c + ((($c - 10) >> 8) & ~38)
34
+ );
35
+ }
36
+ return $hex;
37
+ }
38
+
39
+ /**
40
+ * Converts a hexadecimal string into a byte string without leaking
41
+ * information through side channels.
42
+ *
43
+ * @param string $hex_string
44
+ *
45
+ * @throws Ex\BadFormatException
46
+ * @throws Ex\EnvironmentIsBrokenException
47
+ *
48
+ * @return string
49
+ */
50
+ public static function hexToBin($hex_string)
51
+ {
52
+ $hex_pos = 0;
53
+ $bin = '';
54
+ $hex_len = Core::ourStrlen($hex_string);
55
+ $state = 0;
56
+ $c_acc = 0;
57
+
58
+ while ($hex_pos < $hex_len) {
59
+ $c = \ord($hex_string[$hex_pos]);
60
+ $c_num = $c ^ 48;
61
+ $c_num0 = ($c_num - 10) >> 8;
62
+ $c_alpha = ($c & ~32) - 55;
63
+ $c_alpha0 = (($c_alpha - 10) ^ ($c_alpha - 16)) >> 8;
64
+ if (($c_num0 | $c_alpha0) === 0) {
65
+ throw new Ex\BadFormatException(
66
+ 'Encoding::hexToBin() input is not a hex string.'
67
+ );
68
+ }
69
+ $c_val = ($c_num0 & $c_num) | ($c_alpha & $c_alpha0);
70
+ if ($state === 0) {
71
+ $c_acc = $c_val * 16;
72
+ } else {
73
+ $bin .= \pack('C', $c_acc | $c_val);
74
+ }
75
+ $state ^= 1;
76
+ ++$hex_pos;
77
+ }
78
+ return $bin;
79
+ }
80
+
81
+ /**
82
+ * Remove trialing whitespace without table look-ups or branches.
83
+ *
84
+ * Calling this function may leak the length of the string as well as the
85
+ * number of trailing whitespace characters through side-channels.
86
+ *
87
+ * @param string $string
88
+ * @return string
89
+ */
90
+ public static function trimTrailingWhitespace($string = '')
91
+ {
92
+ $length = Core::ourStrlen($string);
93
+ if ($length < 1) {
94
+ return '';
95
+ }
96
+ do {
97
+ $prevLength = $length;
98
+ $last = $length - 1;
99
+ $chr = \ord($string[$last]);
100
+
101
+ /* Null Byte (0x00), a.k.a. \0 */
102
+ // if ($chr === 0x00) $length -= 1;
103
+ $sub = (($chr - 1) >> 8 ) & 1;
104
+ $length -= $sub;
105
+ $last -= $sub;
106
+
107
+ /* Horizontal Tab (0x09) a.k.a. \t */
108
+ $chr = \ord($string[$last]);
109
+ // if ($chr === 0x09) $length -= 1;
110
+ $sub = (((0x08 - $chr) & ($chr - 0x0a)) >> 8) & 1;
111
+ $length -= $sub;
112
+ $last -= $sub;
113
+
114
+ /* New Line (0x0a), a.k.a. \n */
115
+ $chr = \ord($string[$last]);
116
+ // if ($chr === 0x0a) $length -= 1;
117
+ $sub = (((0x09 - $chr) & ($chr - 0x0b)) >> 8) & 1;
118
+ $length -= $sub;
119
+ $last -= $sub;
120
+
121
+ /* Carriage Return (0x0D), a.k.a. \r */
122
+ $chr = \ord($string[$last]);
123
+ // if ($chr === 0x0d) $length -= 1;
124
+ $sub = (((0x0c - $chr) & ($chr - 0x0e)) >> 8) & 1;
125
+ $length -= $sub;
126
+ $last -= $sub;
127
+
128
+ /* Space */
129
+ $chr = \ord($string[$last]);
130
+ // if ($chr === 0x20) $length -= 1;
131
+ $sub = (((0x1f - $chr) & ($chr - 0x21)) >> 8) & 1;
132
+ $length -= $sub;
133
+ } while ($prevLength !== $length && $length > 0);
134
+ return (string) Core::ourSubstr($string, 0, $length);
135
+ }
136
+
137
+ /*
138
+ * SECURITY NOTE ON APPLYING CHECKSUMS TO SECRETS:
139
+ *
140
+ * The checksum introduces a potential security weakness. For example,
141
+ * suppose we apply a checksum to a key, and that an adversary has an
142
+ * exploit against the process containing the key, such that they can
143
+ * overwrite an arbitrary byte of memory and then cause the checksum to
144
+ * be verified and learn the result.
145
+ *
146
+ * In this scenario, the adversary can extract the key one byte at
147
+ * a time by overwriting it with their guess of its value and then
148
+ * asking if the checksum matches. If it does, their guess was right.
149
+ * This kind of attack may be more easy to implement and more reliable
150
+ * than a remote code execution attack.
151
+ *
152
+ * This attack also applies to authenticated encryption as a whole, in
153
+ * the situation where the adversary can overwrite a byte of the key
154
+ * and then cause a valid ciphertext to be decrypted, and then
155
+ * determine whether the MAC check passed or failed.
156
+ *
157
+ * By using the full SHA256 hash instead of truncating it, I'm ensuring
158
+ * that both ways of going about the attack are equivalently difficult.
159
+ * A shorter checksum of say 32 bits might be more useful to the
160
+ * adversary as an oracle in case their writes are coarser grained.
161
+ *
162
+ * Because the scenario assumes a serious vulnerability, we don't try
163
+ * to prevent attacks of this style.
164
+ */
165
+
166
+ /**
167
+ * INTERNAL USE ONLY: Applies a version header, applies a checksum, and
168
+ * then encodes a byte string into a range of printable ASCII characters.
169
+ *
170
+ * @param string $header
171
+ * @param string $bytes
172
+ *
173
+ * @throws Ex\EnvironmentIsBrokenException
174
+ *
175
+ * @return string
176
+ */
177
+ public static function saveBytesToChecksummedAsciiSafeString($header, $bytes)
178
+ {
179
+ // Headers must be a constant length to prevent one type's header from
180
+ // being a prefix of another type's header, leading to ambiguity.
181
+ Core::ensureTrue(
182
+ Core::ourStrlen($header) === self::SERIALIZE_HEADER_BYTES,
183
+ 'Header must be ' . self::SERIALIZE_HEADER_BYTES . ' bytes.'
184
+ );
185
+
186
+ return Encoding::binToHex(
187
+ $header .
188
+ $bytes .
189
+ \hash(
190
+ self::CHECKSUM_HASH_ALGO,
191
+ $header . $bytes,
192
+ true
193
+ )
194
+ );
195
+ }
196
+
197
+ /**
198
+ * INTERNAL USE ONLY: Decodes, verifies the header and checksum, and returns
199
+ * the encoded byte string.
200
+ *
201
+ * @param string $expected_header
202
+ * @param string $string
203
+ *
204
+ * @throws Ex\EnvironmentIsBrokenException
205
+ * @throws Ex\BadFormatException
206
+ *
207
+ * @return string
208
+ */
209
+ public static function loadBytesFromChecksummedAsciiSafeString($expected_header, $string)
210
+ {
211
+ // Headers must be a constant length to prevent one type's header from
212
+ // being a prefix of another type's header, leading to ambiguity.
213
+ Core::ensureTrue(
214
+ Core::ourStrlen($expected_header) === self::SERIALIZE_HEADER_BYTES,
215
+ 'Header must be 4 bytes.'
216
+ );
217
+
218
+ /* If you get an exception here when attempting to load from a file, first pass your
219
+ key to Encoding::trimTrailingWhitespace() to remove newline characters, etc. */
220
+ $bytes = Encoding::hexToBin($string);
221
+
222
+ /* Make sure we have enough bytes to get the version header and checksum. */
223
+ if (Core::ourStrlen($bytes) < self::SERIALIZE_HEADER_BYTES + self::CHECKSUM_BYTE_SIZE) {
224
+ throw new Ex\BadFormatException(
225
+ 'Encoded data is shorter than expected.'
226
+ );
227
+ }
228
+
229
+ /* Grab the version header. */
230
+ $actual_header = (string) Core::ourSubstr($bytes, 0, self::SERIALIZE_HEADER_BYTES);
231
+
232
+ if ($actual_header !== $expected_header) {
233
+ throw new Ex\BadFormatException(
234
+ 'Invalid header.'
235
+ );
236
+ }
237
+
238
+ /* Grab the bytes that are part of the checksum. */
239
+ $checked_bytes = (string) Core::ourSubstr(
240
+ $bytes,
241
+ 0,
242
+ Core::ourStrlen($bytes) - self::CHECKSUM_BYTE_SIZE
243
+ );
244
+
245
+ /* Grab the included checksum. */
246
+ $checksum_a = (string) Core::ourSubstr(
247
+ $bytes,
248
+ Core::ourStrlen($bytes) - self::CHECKSUM_BYTE_SIZE,
249
+ self::CHECKSUM_BYTE_SIZE
250
+ );
251
+
252
+ /* Re-compute the checksum. */
253
+ $checksum_b = \hash(self::CHECKSUM_HASH_ALGO, $checked_bytes, true);
254
+
255
+ /* Check if the checksum matches. */
256
+ if (! Core::hashEquals($checksum_a, $checksum_b)) {
257
+ throw new Ex\BadFormatException(
258
+ "Data is corrupted, the checksum doesn't match"
259
+ );
260
+ }
261
+
262
+ return (string) Core::ourSubstr(
263
+ $bytes,
264
+ self::SERIALIZE_HEADER_BYTES,
265
+ Core::ourStrlen($bytes) - self::SERIALIZE_HEADER_BYTES - self::CHECKSUM_BYTE_SIZE
266
+ );
267
+ }
268
+ }
vendor/defuse/php-encryption/src/Exception/BadFormatException.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Defuse\Crypto\Exception;
4
+
5
+ class BadFormatException extends \Defuse\Crypto\Exception\CryptoException
6
+ {
7
+ }
vendor/defuse/php-encryption/src/Exception/CryptoException.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Defuse\Crypto\Exception;
4
+
5
+ class CryptoException extends \Exception
6
+ {
7
+ }
vendor/defuse/php-encryption/src/Exception/EnvironmentIsBrokenException.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Defuse\Crypto\Exception;
4
+
5
+ class EnvironmentIsBrokenException extends \Defuse\Crypto\Exception\CryptoException
6
+ {
7
+ }
vendor/defuse/php-encryption/src/Exception/IOException.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Defuse\Crypto\Exception;
4
+
5
+ class IOException extends \Defuse\Crypto\Exception\CryptoException
6
+ {
7
+ }
vendor/defuse/php-encryption/src/Exception/WrongKeyOrModifiedCiphertextException.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Defuse\Crypto\Exception;
4
+
5
+ class WrongKeyOrModifiedCiphertextException extends \Defuse\Crypto\Exception\CryptoException
6
+ {
7
+ }
vendor/defuse/php-encryption/src/File.php ADDED
@@ -0,0 +1,762 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Defuse\Crypto;
4
+
5
+ use Defuse\Crypto\Exception as Ex;
6
+
7
+ final class File
8
+ {
9
+ /**
10
+ * Encrypts the input file, saving the ciphertext to the output file.
11
+ *
12
+ * @param string $inputFilename
13
+ * @param string $outputFilename
14
+ * @param Key $key
15
+ * @return void
16
+ *
17
+ * @throws Ex\EnvironmentIsBrokenException
18
+ * @throws Ex\IOException
19
+ */
20
+ public static function encryptFile($inputFilename, $outputFilename, Key $key)
21
+ {
22
+ self::encryptFileInternal(
23
+ $inputFilename,
24
+ $outputFilename,
25
+ KeyOrPassword::createFromKey($key)
26
+ );
27
+ }
28
+
29
+ /**
30
+ * Encrypts a file with a password, using a slow key derivation function to
31
+ * make password cracking more expensive.
32
+ *
33
+ * @param string $inputFilename
34
+ * @param string $outputFilename
35
+ * @param string $password
36
+ * @return void
37
+ *
38
+ * @throws Ex\EnvironmentIsBrokenException
39
+ * @throws Ex\IOException
40
+ */
41
+ public static function encryptFileWithPassword($inputFilename, $outputFilename, $password)
42
+ {
43
+ self::encryptFileInternal(
44
+ $inputFilename,
45
+ $outputFilename,
46
+ KeyOrPassword::createFromPassword($password)
47
+ );
48
+ }
49
+
50
+ /**
51
+ * Decrypts the input file, saving the plaintext to the output file.
52
+ *
53
+ * @param string $inputFilename
54
+ * @param string $outputFilename
55
+ * @param Key $key
56
+ * @return void
57
+ *
58
+ * @throws Ex\EnvironmentIsBrokenException
59
+ * @throws Ex\IOException
60
+ * @throws Ex\WrongKeyOrModifiedCiphertextException
61
+ */
62
+ public static function decryptFile($inputFilename, $outputFilename, Key $key)
63
+ {
64
+ self::decryptFileInternal(
65
+ $inputFilename,
66
+ $outputFilename,
67
+ KeyOrPassword::createFromKey($key)
68
+ );
69
+ }
70
+
71
+ /**
72
+ * Decrypts a file with a password, using a slow key derivation function to
73
+ * make password cracking more expensive.
74
+ *
75
+ * @param string $inputFilename
76
+ * @param string $outputFilename
77
+ * @param string $password
78
+ * @return void
79
+ *
80
+ * @throws Ex\EnvironmentIsBrokenException
81
+ * @throws Ex\IOException
82
+ * @throws Ex\WrongKeyOrModifiedCiphertextException
83
+ */
84
+ public static function decryptFileWithPassword($inputFilename, $outputFilename, $password)
85
+ {
86
+ self::decryptFileInternal(
87
+ $inputFilename,
88
+ $outputFilename,
89
+ KeyOrPassword::createFromPassword($password)
90
+ );
91
+ }
92
+
93
+ /**
94
+ * Takes two resource handles and encrypts the contents of the first,
95
+ * writing the ciphertext into the second.
96
+ *
97
+ * @param resource $inputHandle
98
+ * @param resource $outputHandle
99
+ * @param Key $key
100
+ * @return void
101
+ *
102
+ * @throws Ex\EnvironmentIsBrokenException
103
+ * @throws Ex\WrongKeyOrModifiedCiphertextException
104
+ */
105
+ public static function encryptResource($inputHandle, $outputHandle, Key $key)
106
+ {
107
+ self::encryptResourceInternal(
108
+ $inputHandle,
109
+ $outputHandle,
110
+ KeyOrPassword::createFromKey($key)
111
+ );
112
+ }
113
+
114
+ /**
115
+ * Encrypts the contents of one resource handle into another with a
116
+ * password, using a slow key derivation function to make password cracking
117
+ * more expensive.
118
+ *
119
+ * @param resource $inputHandle
120
+ * @param resource $outputHandle
121
+ * @param string $password
122
+ * @return void
123
+ *
124
+ * @throws Ex\EnvironmentIsBrokenException
125
+ * @throws Ex\IOException
126
+ * @throws Ex\WrongKeyOrModifiedCiphertextException
127
+ */
128
+ public static function encryptResourceWithPassword($inputHandle, $outputHandle, $password)
129
+ {
130
+ self::encryptResourceInternal(
131
+ $inputHandle,
132
+ $outputHandle,
133
+ KeyOrPassword::createFromPassword($password)
134
+ );
135
+ }
136
+
137
+ /**
138
+ * Takes two resource handles and decrypts the contents of the first,
139
+ * writing the plaintext into the second.
140
+ *
141
+ * @param resource $inputHandle
142
+ * @param resource $outputHandle
143
+ * @param Key $key
144
+ * @return void
145
+ *
146
+ * @throws Ex\EnvironmentIsBrokenException
147
+ * @throws Ex\IOException
148
+ * @throws Ex\WrongKeyOrModifiedCiphertextException
149
+ */
150
+ public static function decryptResource($inputHandle, $outputHandle, Key $key)
151
+ {
152
+ self::decryptResourceInternal(
153
+ $inputHandle,
154
+ $outputHandle,
155
+ KeyOrPassword::createFromKey($key)
156
+ );
157
+ }
158
+
159
+ /**
160
+ * Decrypts the contents of one resource into another with a password, using
161
+ * a slow key derivation function to make password cracking more expensive.
162
+ *
163
+ * @param resource $inputHandle
164
+ * @param resource $outputHandle
165
+ * @param string $password
166
+ * @return void
167
+ *
168
+ * @throws Ex\EnvironmentIsBrokenException
169
+ * @throws Ex\IOException
170
+ * @throws Ex\WrongKeyOrModifiedCiphertextException
171
+ */
172
+ public static function decryptResourceWithPassword($inputHandle, $outputHandle, $password)
173
+ {
174
+ self::decryptResourceInternal(
175
+ $inputHandle,
176
+ $outputHandle,
177
+ KeyOrPassword::createFromPassword($password)
178
+ );
179
+ }
180
+
181
+ /**
182
+ * Encrypts a file with either a key or a password.
183
+ *
184
+ * @param string $inputFilename
185
+ * @param string $outputFilename
186
+ * @param KeyOrPassword $secret
187
+ * @return void
188
+ *
189
+ * @throws Ex\CryptoException
190
+ * @throws Ex\IOException
191
+ */
192
+ private static function encryptFileInternal($inputFilename, $outputFilename, KeyOrPassword $secret)
193
+ {
194
+ /* Open the input file. */
195
+ $if = @\fopen($inputFilename, 'rb');
196
+ if ($if === false) {
197
+ throw new Ex\IOException(
198
+ 'Cannot open input file for encrypting: ' .
199
+ self::getLastErrorMessage()
200
+ );
201
+ }
202
+ if (\is_callable('\\stream_set_read_buffer')) {
203
+ /* This call can fail, but the only consequence is performance. */
204
+ \stream_set_read_buffer($if, 0);
205
+ }
206
+
207
+ /* Open the output file. */
208
+ $of = @\fopen($outputFilename, 'wb');
209
+ if ($of === false) {
210
+ \fclose($if);
211
+ throw new Ex\IOException(
212
+ 'Cannot open output file for encrypting: ' .
213
+ self::getLastErrorMessage()
214
+ );
215
+ }
216
+ if (\is_callable('\\stream_set_write_buffer')) {
217
+ /* This call can fail, but the only consequence is performance. */
218
+ \stream_set_write_buffer($of, 0);
219
+ }
220
+
221
+ /* Perform the encryption. */
222
+ try {
223
+ self::encryptResourceInternal($if, $of, $secret);
224
+ } catch (Ex\CryptoException $ex) {
225
+ \fclose($if);
226
+ \fclose($of);
227
+ throw $ex;
228
+ }
229
+
230
+ /* Close the input file. */
231
+ if (\fclose($if) === false) {
232
+ \fclose($of);
233
+ throw new Ex\IOException(
234
+ 'Cannot close input file after encrypting'
235
+ );
236
+ }
237
+
238
+ /* Close the output file. */
239
+ if (\fclose($of) === false) {
240
+ throw new Ex\IOException(
241
+ 'Cannot close output file after encrypting'
242
+ );
243
+ }
244
+ }
245
+
246
+ /**
247
+ * Decrypts a file with either a key or a password.
248
+ *
249
+ * @param string $inputFilename
250
+ * @param string $outputFilename
251
+ * @param KeyOrPassword $secret
252
+ * @return void
253
+ *
254
+ * @throws Ex\CryptoException
255
+ * @throws Ex\IOException
256
+ */
257
+ private static function decryptFileInternal($inputFilename, $outputFilename, KeyOrPassword $secret)
258
+ {
259
+ /* Open the input file. */
260
+ $if = @\fopen($inputFilename, 'rb');
261
+ if ($if === false) {
262
+ throw new Ex\IOException(
263
+ 'Cannot open input file for decrypting: ' .
264
+ self::getLastErrorMessage()
265
+ );
266
+ }
267
+
268
+ if (\is_callable('\\stream_set_read_buffer')) {
269
+ /* This call can fail, but the only consequence is performance. */
270
+ \stream_set_read_buffer($if, 0);
271
+ }
272
+
273
+ /* Open the output file. */
274
+ $of = @\fopen($outputFilename, 'wb');
275
+ if ($of === false) {
276
+ \fclose($if);
277
+ throw new Ex\IOException(
278
+ 'Cannot open output file for decrypting: ' .
279
+ self::getLastErrorMessage()
280
+ );
281
+ }
282
+
283
+ if (\is_callable('\\stream_set_write_buffer')) {
284
+ /* This call can fail, but the only consequence is performance. */
285
+ \stream_set_write_buffer($of, 0);
286
+ }
287
+
288
+ /* Perform the decryption. */
289
+ try {
290
+ self::decryptResourceInternal($if, $of, $secret);
291
+ } catch (Ex\CryptoException $ex) {
292
+ \fclose($if);
293
+ \fclose($of);
294
+ throw $ex;
295
+ }
296
+
297
+ /* Close the input file. */
298
+ if (\fclose($if) === false) {
299
+ \fclose($of);
300
+ throw new Ex\IOException(
301
+ 'Cannot close input file after decrypting'
302
+ );
303
+ }
304
+
305
+ /* Close the output file. */
306
+ if (\fclose($of) === false) {
307
+ throw new Ex\IOException(
308
+ 'Cannot close output file after decrypting'
309
+ );
310
+ }
311
+ }
312
+
313
+ /**
314
+ * Encrypts a resource with either a key or a password.
315
+ *
316
+ * @param resource $inputHandle
317
+ * @param resource $outputHandle
318
+ * @param KeyOrPassword $secret
319
+ * @return void
320
+ *
321
+ * @throws Ex\EnvironmentIsBrokenException
322
+ * @throws Ex\IOException
323
+ */
324
+ private static function encryptResourceInternal($inputHandle, $outputHandle, KeyOrPassword $secret)
325
+ {
326
+ if (! \is_resource($inputHandle)) {
327
+ throw new Ex\IOException(
328
+ 'Input handle must be a resource!'
329
+ );
330
+ }
331
+ if (! \is_resource($outputHandle)) {
332
+ throw new Ex\IOException(
333
+ 'Output handle must be a resource!'
334
+ );
335
+ }
336
+
337
+ $inputStat = \fstat($inputHandle);
338
+ $inputSize = $inputStat['size'];
339
+
340
+ $file_salt = Core::secureRandom(Core::SALT_BYTE_SIZE);
341
+ $keys = $secret->deriveKeys($file_salt);
342
+ $ekey = $keys->getEncryptionKey();
343
+ $akey = $keys->getAuthenticationKey();
344
+
345
+ $ivsize = Core::BLOCK_BYTE_SIZE;
346
+ $iv = Core::secureRandom($ivsize);
347
+
348
+ /* Initialize a streaming HMAC state. */
349
+ /** @var resource $hmac */
350
+ $hmac = \hash_init(Core::HASH_FUNCTION_NAME, HASH_HMAC, $akey);
351
+ Core::ensureTrue(
352
+ \is_resource($hmac) || \is_object($hmac),
353
+ 'Cannot initialize a hash context'
354
+ );
355
+
356
+ /* Write the header, salt, and IV. */
357
+ self::writeBytes(
358
+ $outputHandle,
359
+ Core::CURRENT_VERSION . $file_salt . $iv,
360
+ Core::HEADER_VERSION_SIZE + Core::SALT_BYTE_SIZE + $ivsize
361
+ );
362
+
363
+ /* Add the header, salt, and IV to the HMAC. */
364
+ \hash_update($hmac, Core::CURRENT_VERSION);
365
+ \hash_update($hmac, $file_salt);
366
+ \hash_update($hmac, $iv);
367
+
368
+ /* $thisIv will be incremented after each call to the encryption. */
369
+ $thisIv = $iv;
370
+
371
+ /* How many blocks do we encrypt at a time? We increment by this value. */
372
+ $inc = (int) (Core::BUFFER_BYTE_SIZE / Core::BLOCK_BYTE_SIZE);
373
+
374
+ /* Loop until we reach the end of the input file. */
375
+ $at_file_end = false;
376
+ while (! (\feof($inputHandle) || $at_file_end)) {
377
+ /* Find out if we can read a full buffer, or only a partial one. */
378
+ /** @var int */
379
+ $pos = \ftell($inputHandle);
380
+ if (!\is_int($pos)) {
381
+ throw new Ex\IOException(
382
+ 'Could not get current position in input file during encryption'
383
+ );
384
+ }
385
+ if ($pos + Core::BUFFER_BYTE_SIZE >= $inputSize) {
386
+ /* We're at the end of the file, so we need to break out of the loop. */
387
+ $at_file_end = true;
388
+ $read = self::readBytes(
389
+ $inputHandle,
390
+ $inputSize - $pos
391
+ );
392
+ } else {
393
+ $read = self::readBytes(
394
+ $inputHandle,
395
+ Core::BUFFER_BYTE_SIZE
396
+ );
397
+ }
398
+
399
+ /* Encrypt this buffer. */
400
+ /** @var string */
401
+ $encrypted = \openssl_encrypt(
402
+ $read,
403
+ Core::CIPHER_METHOD,
404
+ $ekey,
405
+ OPENSSL_RAW_DATA,
406
+ $thisIv
407
+ );
408
+
409
+ Core::ensureTrue(\is_string($encrypted), 'OpenSSL encryption error');
410
+
411
+ /* Write this buffer's ciphertext. */
412
+ self::writeBytes($outputHandle, $encrypted, Core::ourStrlen($encrypted));
413
+ /* Add this buffer's ciphertext to the HMAC. */
414
+ \hash_update($hmac, $encrypted);
415
+
416
+ /* Increment the counter by the number of blocks in a buffer. */
417
+ $thisIv = Core::incrementCounter($thisIv, $inc);
418
+ /* WARNING: Usually, unless the file is a multiple of the buffer
419
+ * size, $thisIv will contain an incorrect value here on the last
420
+ * iteration of this loop. */
421
+ }
422
+
423
+ /* Get the HMAC and append it to the ciphertext. */
424
+ $final_mac = \hash_final($hmac, true);
425
+ self::writeBytes($outputHandle, $final_mac, Core::MAC_BYTE_SIZE);
426
+ }
427
+
428
+ /**
429
+ * Decrypts a file-backed resource with either a key or a password.
430
+ *
431
+ * @param resource $inputHandle
432
+ * @param resource $outputHandle
433
+ * @param KeyOrPassword $secret
434
+ * @return void
435
+ *
436
+ * @throws Ex\EnvironmentIsBrokenException
437
+ * @throws Ex\IOException
438
+ * @throws Ex\WrongKeyOrModifiedCiphertextException
439
+ */
440
+ public static function decryptResourceInternal($inputHandle, $outputHandle, KeyOrPassword $secret)
441
+ {
442
+ if (! \is_resource($inputHandle)) {
443
+ throw new Ex\IOException(
444
+ 'Input handle must be a resource!'
445
+ );
446
+ }
447
+ if (! \is_resource($outputHandle)) {
448
+ throw new Ex\IOException(
449
+ 'Output handle must be a resource!'
450
+ );
451
+ }
452
+
453
+ /* Make sure the file is big enough for all the reads we need to do. */
454
+ $stat = \fstat($inputHandle);
455
+ if ($stat['size'] < Core::MINIMUM_CIPHERTEXT_SIZE) {
456
+ throw new Ex\WrongKeyOrModifiedCiphertextException(
457
+ 'Input file is too small to have been created by this library.'
458
+ );
459
+ }
460
+
461
+ /* Check the version header. */
462
+ $header = self::readBytes($inputHandle, Core::HEADER_VERSION_SIZE);
463
+ if ($header !== Core::CURRENT_VERSION) {
464
+ throw new Ex\WrongKeyOrModifiedCiphertextException(
465
+ 'Bad version header.'
466
+ );
467
+ }
468
+
469
+ /* Get the salt. */
470
+ $file_salt = self::readBytes($inputHandle, Core::SALT_BYTE_SIZE);
471
+
472
+ /* Get the IV. */
473
+ $ivsize = Core::BLOCK_BYTE_SIZE;
474
+ $iv = self::readBytes($inputHandle, $ivsize);
475
+
476
+ /* Derive the authentication and encryption keys. */
477
+ $keys = $secret->deriveKeys($file_salt);
478
+ $ekey = $keys->getEncryptionKey();
479
+ $akey = $keys->getAuthenticationKey();
480
+
481
+ /* We'll store the MAC of each buffer-sized chunk as we verify the
482
+ * actual MAC, so that we can check them again when decrypting. */
483
+ $macs = [];
484
+
485
+ /* $thisIv will be incremented after each call to the decryption. */
486
+ $thisIv = $iv;
487
+
488
+ /* How many blocks do we encrypt at a time? We increment by this value. */
489
+ $inc = (int) (Core::BUFFER_BYTE_SIZE / Core::BLOCK_BYTE_SIZE);
490
+
491
+ /* Get the HMAC. */
492
+ if (\fseek($inputHandle, (-1 * Core::MAC_BYTE_SIZE), SEEK_END) === false) {
493
+ throw new Ex\IOException(
494
+ 'Cannot seek to beginning of MAC within input file'
495
+ );
496
+ }
497
+
498
+ /* Get the position of the last byte in the actual ciphertext. */
499
+ /** @var int $cipher_end */
500
+ $cipher_end = \ftell($inputHandle);
501
+ if (!\is_int($cipher_end)) {
502
+ throw new Ex\IOException(
503
+ 'Cannot read input file'
504
+ );
505
+ }
506
+ /* We have the position of the first byte of the HMAC. Go back by one. */
507
+ --$cipher_end;
508
+
509
+ /* Read the HMAC. */
510
+ /** @var string $stored_mac */
511
+ $stored_mac = self::readBytes($inputHandle, Core::MAC_BYTE_SIZE);
512
+
513
+ /* Initialize a streaming HMAC state. */
514
+ /** @var resource $hmac */
515
+ $hmac = \hash_init(Core::HASH_FUNCTION_NAME, HASH_HMAC, $akey);
516
+ Core::ensureTrue(\is_resource($hmac) || \is_object($hmac), 'Cannot initialize a hash context');
517
+
518
+ /* Reset file pointer to the beginning of the file after the header */
519
+ if (\fseek($inputHandle, Core::HEADER_VERSION_SIZE, SEEK_SET) === false) {
520
+ throw new Ex\IOException(
521
+ 'Cannot read seek within input file'
522
+ );
523
+ }
524
+
525
+ /* Seek to the start of the actual ciphertext. */
526
+ if (\fseek($inputHandle, Core::SALT_BYTE_SIZE + $ivsize, SEEK_CUR) === false) {
527
+ throw new Ex\IOException(
528
+ 'Cannot seek input file to beginning of ciphertext'
529
+ );
530
+ }
531
+
532
+ /* PASS #1: Calculating the HMAC. */
533
+
534
+ \hash_update($hmac, $header);
535
+ \hash_update($hmac, $file_salt);
536
+ \hash_update($hmac, $iv);
537
+ /** @var resource $hmac2 */
538
+ $hmac2 = \hash_copy($hmac);
539
+
540
+ $break = false;
541
+ while (! $break) {
542
+ /** @var int $pos */
543
+ $pos = \ftell($inputHandle);
544
+ if (!\is_int($pos)) {
545
+ throw new Ex\IOException(
546
+ 'Could not get current position in input file during decryption'
547
+ );
548
+ }
549
+
550
+ /* Read the next buffer-sized chunk (or less). */
551
+ if ($pos + Core::BUFFER_BYTE_SIZE >= $cipher_end) {
552
+ $break = true;
553
+ $read = self::readBytes(
554
+ $inputHandle,
555
+ $cipher_end - $pos + 1
556
+ );
557
+ } else {
558
+ $read = self::readBytes(
559
+ $inputHandle,
560
+ Core::BUFFER_BYTE_SIZE
561
+ );
562
+ }
563
+
564
+ /* Update the HMAC. */
565
+ \hash_update($hmac, $read);
566
+
567
+ /* Remember this buffer-sized chunk's HMAC. */
568
+ /** @var resource $chunk_mac */
569
+ $chunk_mac = \hash_copy($hmac);
570
+ Core::ensureTrue(\is_resource($chunk_mac) || \is_object($chunk_mac), 'Cannot duplicate a hash context');
571
+ $macs []= \hash_final($chunk_mac);
572
+ }
573
+
574
+ /* Get the final HMAC, which should match the stored one. */
575
+ /** @var string $final_mac */
576
+ $final_mac = \hash_final($hmac, true);
577
+
578
+ /* Verify the HMAC. */
579
+ if (! Core::hashEquals($final_mac, $stored_mac)) {
580
+ throw new Ex\WrongKeyOrModifiedCiphertextException(
581
+ 'Integrity check failed.'
582
+ );
583
+ }
584
+
585
+ /* PASS #2: Decrypt and write output. */
586
+
587
+ /* Rewind to the start of the actual ciphertext. */
588
+ if (\fseek($inputHandle, Core::SALT_BYTE_SIZE + $ivsize + Core::HEADER_VERSION_SIZE, SEEK_SET) === false) {
589
+ throw new Ex\IOException(
590
+ 'Could not move the input file pointer during decryption'
591
+ );
592
+ }
593
+
594
+ $at_file_end = false;
595
+ while (! $at_file_end) {
596
+ /** @var int $pos */
597
+ $pos = \ftell($inputHandle);
598
+ if (!\is_int($pos)) {
599
+ throw new Ex\IOException(
600
+ 'Could not get current position in input file during decryption'
601
+ );
602
+ }
603
+
604
+ /* Read the next buffer-sized chunk (or less). */
605
+ if ($pos + Core::BUFFER_BYTE_SIZE >= $cipher_end) {
606
+ $at_file_end = true;
607
+ $read = self::readBytes(
608
+ $inputHandle,
609
+ $cipher_end - $pos + 1
610
+ );
611
+ } else {
612
+ $read = self::readBytes(
613
+ $inputHandle,
614
+ Core::BUFFER_BYTE_SIZE
615
+ );
616
+ }
617
+
618
+ /* Recalculate the MAC (so far) and compare it with the one we
619
+ * remembered from pass #1 to ensure attackers didn't change the
620
+ * ciphertext after MAC verification. */
621
+ \hash_update($hmac2, $read);
622
+ /** @var resource $calc_mac */
623
+ $calc_mac = \hash_copy($hmac2);
624
+ Core::ensureTrue(\is_resource($calc_mac) || \is_object($calc_mac), 'Cannot duplicate a hash context');
625
+ $calc = \hash_final($calc_mac);
626
+
627
+ if (empty($macs)) {
628
+ throw new Ex\WrongKeyOrModifiedCiphertextException(
629
+ 'File was modified after MAC verification'
630
+ );
631
+ } elseif (! Core::hashEquals(\array_shift($macs), $calc)) {
632
+ throw new Ex\WrongKeyOrModifiedCiphertextException(
633
+ 'File was modified after MAC verification'
634
+ );
635
+ }
636
+
637
+ /* Decrypt this buffer-sized chunk. */
638
+ /** @var string $decrypted */
639
+ $decrypted = \openssl_decrypt(
640
+ $read,
641
+ Core::CIPHER_METHOD,
642
+ $ekey,
643
+ OPENSSL_RAW_DATA,
644
+ $thisIv
645
+ );
646
+ Core::ensureTrue(\is_string($decrypted), 'OpenSSL decryption error');
647
+
648
+ /* Write the plaintext to the output file. */
649
+ self::writeBytes(
650
+ $outputHandle,
651
+ $decrypted,
652
+ Core::ourStrlen($decrypted)
653
+ );
654
+
655
+ /* Increment the IV by the amount of blocks in a buffer. */
656
+ /** @var string $thisIv */
657
+ $thisIv = Core::incrementCounter($thisIv, $inc);
658
+ /* WARNING: Usually, unless the file is a multiple of the buffer
659
+ * size, $thisIv will contain an incorrect value here on the last
660
+ * iteration of this loop. */
661
+ }
662
+ }
663
+
664
+ /**
665
+ * Read from a stream; prevent partial reads.
666
+ *
667
+ * @param resource $stream
668
+ * @param int $num_bytes
669
+ * @return string
670
+ *
671
+ * @throws Ex\IOException
672
+ * @throws Ex\EnvironmentIsBrokenException
673
+ *
674
+ * @return string
675
+ */
676
+ public static function readBytes($stream, $num_bytes)
677
+ {
678
+ Core::ensureTrue($num_bytes >= 0, 'Tried to read less than 0 bytes');
679
+
680
+ if ($num_bytes === 0) {
681
+ return '';
682
+ }
683
+
684
+ $buf = '';
685
+ $remaining = $num_bytes;
686
+ while ($remaining > 0 && ! \feof($stream)) {
687
+ /** @var string $read */
688
+ $read = \fread($stream, $remaining);
689
+ if (!\is_string($read)) {
690
+ throw new Ex\IOException(
691
+ 'Could not read from the file'
692
+ );
693
+ }
694
+ $buf .= $read;
695
+ $remaining -= Core::ourStrlen($read);
696
+ }
697
+ if (Core::ourStrlen($buf) !== $num_bytes) {
698
+ throw new Ex\IOException(
699
+ 'Tried to read past the end of the file'
700
+ );
701
+ }
702
+ return $buf;
703
+ }
704
+
705
+ /**
706
+ * Write to a stream; prevents partial writes.
707
+ *
708
+ * @param resource $stream
709
+ * @param string $buf
710
+ * @param int $num_bytes
711
+ * @return int
712
+ *
713
+ * @throws Ex\IOException
714
+ *
715
+ * @return string
716
+ */
717
+ public static function writeBytes($stream, $buf, $num_bytes = null)
718
+ {
719
+ $bufSize = Core::ourStrlen($buf);
720
+ if ($num_bytes === null) {
721
+ $num_bytes = $bufSize;
722
+ }
723
+ if ($num_bytes > $bufSize) {
724
+ throw new Ex\IOException(
725
+ 'Trying to write more bytes than the buffer contains.'
726
+ );
727
+ }
728
+ if ($num_bytes < 0) {
729
+ throw new Ex\IOException(
730
+ 'Tried to write less than 0 bytes'
731
+ );
732
+ }
733
+ $remaining = $num_bytes;
734
+ while ($remaining > 0) {
735
+ /** @var int $written */
736
+ $written = \fwrite($stream, $buf, $remaining);
737
+ if (!\is_int($written)) {
738
+ throw new Ex\IOException(
739
+ 'Could not write to the file'
740
+ );
741
+ }
742
+ $buf = (string) Core::ourSubstr($buf, $written, null);
743
+ $remaining -= $written;
744
+ }
745
+ return $num_bytes;
746
+ }
747
+
748
+ /**
749
+ * Returns the last PHP error's or warning's message string.
750
+ *
751
+ * @return string
752
+ */
753
+ private static function getLastErrorMessage()
754
+ {
755
+ $error = error_get_last();
756
+ if ($error === null) {
757
+ return '[no PHP error]';
758
+ } else {
759
+ return $error['message'];
760
+ }
761
+ }
762
+ }
vendor/defuse/php-encryption/src/Key.php ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Defuse\Crypto;
4
+
5
+ use Defuse\Crypto\Exception as Ex;
6
+
7
+ final class Key
8
+ {
9
+ const KEY_CURRENT_VERSION = "\xDE\xF0\x00\x00";
10
+ const KEY_BYTE_SIZE = 32;
11
+
12
+ /**
13
+ * @var string
14
+ */
15
+ private $key_bytes;
16
+
17
+ /**
18
+ * Creates new random key.
19
+ *
20
+ * @throws Ex\EnvironmentIsBrokenException
21
+ *
22
+ * @return Key
23
+ */
24
+ public static function createNewRandomKey()
25
+ {
26
+ return new Key(Core::secureRandom(self::KEY_BYTE_SIZE));
27
+ }
28
+
29
+ /**
30
+ * Loads a Key from its encoded form.
31
+ *
32
+ * By default, this function will call Encoding::trimTrailingWhitespace()
33
+ * to remove trailing CR, LF, NUL, TAB, and SPACE characters, which are
34
+ * commonly appended to files when working with text editors.
35
+ *
36
+ * @param string $saved_key_string
37
+ * @param bool $do_not_trim (default: false)
38
+ *
39
+ * @throws Ex\BadFormatException
40
+ * @throws Ex\EnvironmentIsBrokenException
41
+ *
42
+ * @return Key
43
+ */
44
+ public static function loadFromAsciiSafeString($saved_key_string, $do_not_trim = false)
45
+ {
46
+ if (!$do_not_trim) {
47
+ $saved_key_string = Encoding::trimTrailingWhitespace($saved_key_string);
48
+ }
49
+ $key_bytes = Encoding::loadBytesFromChecksummedAsciiSafeString(self::KEY_CURRENT_VERSION, $saved_key_string);
50
+ return new Key($key_bytes);
51
+ }
52
+
53
+ /**
54
+ * Encodes the Key into a string of printable ASCII characters.
55
+ *
56
+ * @throws Ex\EnvironmentIsBrokenException
57
+ *
58
+ * @return string
59
+ */
60
+ public function saveToAsciiSafeString()
61
+ {
62
+ return Encoding::saveBytesToChecksummedAsciiSafeString(
63
+ self::KEY_CURRENT_VERSION,
64
+ $this->key_bytes
65
+ );
66
+ }
67
+
68
+ /**
69
+ * Gets the raw bytes of the key.
70
+ *
71
+ * @return string
72
+ */
73
+ public function getRawBytes()
74
+ {
75
+ return $this->key_bytes;
76
+ }
77
+
78
+ /**
79
+ * Constructs a new Key object from a string of raw bytes.
80
+ *
81
+ * @param string $bytes
82
+ *
83
+ * @throws Ex\EnvironmentIsBrokenException
84
+ */
85
+ private function __construct($bytes)
86
+ {
87
+ Core::ensureTrue(
88
+ Core::ourStrlen($bytes) === self::KEY_BYTE_SIZE,
89
+ 'Bad key length.'
90
+ );
91
+ $this->key_bytes = $bytes;
92
+ }
93
+
94
+ }
vendor/defuse/php-encryption/src/KeyOrPassword.php ADDED
@@ -0,0 +1,149 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Defuse\Crypto;
4
+
5
+ use Defuse\Crypto\Exception as Ex;
6
+
7
+ final class KeyOrPassword
8
+ {
9
+ const PBKDF2_ITERATIONS = 100000;
10
+ const SECRET_TYPE_KEY = 1;
11
+ const SECRET_TYPE_PASSWORD = 2;
12
+
13
+ /**
14
+ * @var int
15
+ */
16
+ private $secret_type = 0;
17
+
18
+ /**
19
+ * @var Key|string
20
+ */
21
+ private $secret;
22
+
23
+ /**
24
+ * Initializes an instance of KeyOrPassword from a key.
25
+ *
26
+ * @param Key $key
27
+ *
28
+ * @return KeyOrPassword
29
+ */
30
+ public static function createFromKey(Key $key)
31
+ {
32
+ return new KeyOrPassword(self::SECRET_TYPE_KEY, $key);
33
+ }
34
+
35
+ /**
36
+ * Initializes an instance of KeyOrPassword from a password.
37
+ *
38
+ * @param string $password
39
+ *
40
+ * @return KeyOrPassword
41
+ */
42
+ public static function createFromPassword($password)
43
+ {
44
+ return new KeyOrPassword(self::SECRET_TYPE_PASSWORD, $password);
45
+ }
46
+
47
+ /**
48
+ * Derives authentication and encryption keys from the secret, using a slow
49
+ * key derivation function if the secret is a password.
50
+ *
51
+ * @param string $salt
52
+ *
53
+ * @throws Ex\CryptoException
54
+ * @throws Ex\EnvironmentIsBrokenException
55
+ *
56
+ * @return DerivedKeys
57
+ */
58
+ public function deriveKeys($salt)
59
+ {
60
+ Core::ensureTrue(
61
+ Core::ourStrlen($salt) === Core::SALT_BYTE_SIZE,
62
+ 'Bad salt.'
63
+ );
64
+
65
+ if ($this->secret_type === self::SECRET_TYPE_KEY) {
66
+ Core::ensureTrue($this->secret instanceof Key);
67
+ /**
68
+ * @psalm-suppress PossiblyInvalidMethodCall
69
+ */
70
+ $akey = Core::HKDF(
71
+ Core::HASH_FUNCTION_NAME,
72
+ $this->secret->getRawBytes(),
73
+ Core::KEY_BYTE_SIZE,
74
+ Core::AUTHENTICATION_INFO_STRING,
75
+ $salt
76
+ );
77
+ /**
78
+ * @psalm-suppress PossiblyInvalidMethodCall
79
+ */
80
+ $ekey = Core::HKDF(
81
+ Core::HASH_FUNCTION_NAME,
82
+ $this->secret->getRawBytes(),
83
+ Core::KEY_BYTE_SIZE,
84
+ Core::ENCRYPTION_INFO_STRING,
85
+ $salt
86
+ );
87
+ return new DerivedKeys($akey, $ekey);
88
+ } elseif ($this->secret_type === self::SECRET_TYPE_PASSWORD) {
89
+ Core::ensureTrue(\is_string($this->secret));
90
+ /* Our PBKDF2 polyfill is vulnerable to a DoS attack documented in
91
+ * GitHub issue #230. The fix is to pre-hash the password to ensure
92
+ * it is short. We do the prehashing here instead of in pbkdf2() so
93
+ * that pbkdf2() still computes the function as defined by the
94
+ * standard. */
95
+
96
+ /**
97
+ * @psalm-suppress PossiblyInvalidArgument
98
+ */
99
+ $prehash = \hash(Core::HASH_FUNCTION_NAME, $this->secret, true);
100
+
101
+ $prekey = Core::pbkdf2(
102
+ Core::HASH_FUNCTION_NAME,
103
+ $prehash,
104
+ $salt,
105
+ self::PBKDF2_ITERATIONS,
106
+ Core::KEY_BYTE_SIZE,
107
+ true
108
+ );
109
+ $akey = Core::HKDF(
110
+ Core::HASH_FUNCTION_NAME,
111
+ $prekey,
112
+ Core::KEY_BYTE_SIZE,
113
+ Core::AUTHENTICATION_INFO_STRING,
114
+ $salt
115
+ );
116
+ /* Note the cryptographic re-use of $salt here. */
117
+ $ekey = Core::HKDF(
118
+ Core::HASH_FUNCTION_NAME,
119
+ $prekey,
120
+ Core::KEY_BYTE_SIZE,
121
+ Core::ENCRYPTION_INFO_STRING,
122
+ $salt
123
+ );
124
+ return new DerivedKeys($akey, $ekey);
125
+ } else {
126
+ throw new Ex\EnvironmentIsBrokenException('Bad secret type.');
127
+ }
128
+ }
129
+
130
+ /**
131
+ * Constructor for KeyOrPassword.
132
+ *
133
+ * @param int $secret_type
134
+ * @param mixed $secret (either a Key or a password string)
135
+ */
136
+ private function __construct($secret_type, $secret)
137
+ {
138
+ // The constructor is private, so these should never throw.
139
+ if ($secret_type === self::SECRET_TYPE_KEY) {
140
+ Core::ensureTrue($secret instanceof Key);
141
+ } elseif ($secret_type === self::SECRET_TYPE_PASSWORD) {
142
+ Core::ensureTrue(\is_string($secret));
143
+ } else {
144
+ throw new Ex\EnvironmentIsBrokenException('Bad secret type.');
145
+ }
146
+ $this->secret_type = $secret_type;
147
+ $this->secret = $secret;
148
+ }
149
+ }
vendor/defuse/php-encryption/src/KeyProtectedByPassword.php ADDED
@@ -0,0 +1,145 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Defuse\Crypto;
4
+
5
+ use Defuse\Crypto\Exception as Ex;
6
+
7
+ final class KeyProtectedByPassword
8
+ {
9
+ const PASSWORD_KEY_CURRENT_VERSION = "\xDE\xF1\x00\x00";
10
+
11
+ /**
12
+ * @var string
13
+ */
14
+ private $encrypted_key = '';
15
+
16
+ /**
17
+ * Creates a random key protected by the provided password.
18
+ *
19
+ * @param string $password
20
+ *
21
+ * @throws Ex\EnvironmentIsBrokenException
22
+ *
23
+ * @return KeyProtectedByPassword
24
+ */
25
+ public static function createRandomPasswordProtectedKey($password)
26
+ {
27
+ $inner_key = Key::createNewRandomKey();
28
+ /* The password is hashed as a form of poor-man's domain separation
29
+ * between this use of encryptWithPassword() and other uses of
30
+ * encryptWithPassword() that the user may also be using as part of the
31
+ * same protocol. */
32
+ $encrypted_key = Crypto::encryptWithPassword(
33
+ $inner_key->saveToAsciiSafeString(),
34
+ \hash(Core::HASH_FUNCTION_NAME, $password, true),
35
+ true
36
+ );
37
+
38
+ return new KeyProtectedByPassword($encrypted_key);
39
+ }
40
+
41
+ /**
42
+ * Loads a KeyProtectedByPassword from its encoded form.
43
+ *
44
+ * @param string $saved_key_string
45
+ *
46
+ * @throws Ex\BadFormatException
47
+ *
48
+ * @return KeyProtectedByPassword
49
+ */
50
+ public static function loadFromAsciiSafeString($saved_key_string)
51
+ {
52
+ $encrypted_key = Encoding::loadBytesFromChecksummedAsciiSafeString(
53
+ self::PASSWORD_KEY_CURRENT_VERSION,
54
+ $saved_key_string
55
+ );
56
+ return new KeyProtectedByPassword($encrypted_key);
57
+ }
58
+
59
+ /**
60
+ * Encodes the KeyProtectedByPassword into a string of printable ASCII
61
+ * characters.
62
+ *
63
+ * @throws Ex\EnvironmentIsBrokenException
64
+ *
65
+ * @return string
66
+ */
67
+ public function saveToAsciiSafeString()
68
+ {
69
+ return Encoding::saveBytesToChecksummedAsciiSafeString(
70
+ self::PASSWORD_KEY_CURRENT_VERSION,
71
+ $this->encrypted_key
72
+ );
73
+ }
74
+
75
+ /**
76
+ * Decrypts the protected key, returning an unprotected Key object that can
77
+ * be used for encryption and decryption.
78
+ *
79
+ * @throws Ex\EnvironmentIsBrokenException
80
+ * @throws Ex\WrongKeyOrModifiedCiphertextException
81
+ *
82
+ * @param string $password
83
+ * @return Key
84
+ */
85
+ public function unlockKey($password)
86
+ {
87
+ try {
88
+ $inner_key_encoded = Crypto::decryptWithPassword(
89
+ $this->encrypted_key,
90
+ \hash(Core::HASH_FUNCTION_NAME, $password, true),
91
+ true
92
+ );
93
+ return Key::loadFromAsciiSafeString($inner_key_encoded);
94
+ } catch (Ex\BadFormatException $ex) {
95
+ /* This should never happen unless an attacker replaced the
96
+ * encrypted key ciphertext with some other ciphertext that was
97
+ * encrypted with the same password. We transform the exception type
98
+ * here in order to make the API simpler, avoiding the need to
99
+ * document that this method might throw an Ex\BadFormatException. */
100
+ throw new Ex\WrongKeyOrModifiedCiphertextException(
101
+ "The decrypted key was found to be in an invalid format. " .
102
+ "This very likely indicates it was modified by an attacker."
103
+ );
104
+ }
105
+ }
106
+
107
+ /**
108
+ * Changes the password.
109
+ *
110
+ * @param string $current_password
111
+ * @param string $new_password
112
+ *
113
+ * @throws Ex\EnvironmentIsBrokenException
114
+ * @throws Ex\WrongKeyOrModifiedCiphertextException
115
+ *
116
+ * @return KeyProtectedByPassword
117
+ */
118
+ public function changePassword($current_password, $new_password)
119
+ {
120
+ $inner_key = $this->unlockKey($current_password);
121
+ /* The password is hashed as a form of poor-man's domain separation
122
+ * between this use of encryptWithPassword() and other uses of
123
+ * encryptWithPassword() that the user may also be using as part of the
124
+ * same protocol. */
125
+ $encrypted_key = Crypto::encryptWithPassword(
126
+ $inner_key->saveToAsciiSafeString(),
127
+ \hash(Core::HASH_FUNCTION_NAME, $new_password, true),
128
+ true
129
+ );
130
+
131
+ $this->encrypted_key = $encrypted_key;
132
+
133
+ return $this;
134
+ }
135
+
136
+ /**
137
+ * Constructor for KeyProtectedByPassword.
138
+ *
139
+ * @param string $encrypted_key
140
+ */
141
+ private function __construct($encrypted_key)
142
+ {
143
+ $this->encrypted_key = $encrypted_key;
144
+ }
145
+ }
vendor/defuse/php-encryption/src/RuntimeTests.php ADDED
@@ -0,0 +1,228 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Defuse\Crypto;
4
+
5
+ use Defuse\Crypto\Exception as Ex;
6
+
7
+ /*
8
+ * We're using static class inheritance to get access to protected methods
9
+ * inside Crypto. To make it easy to know where the method we're calling can be
10
+ * found, within this file, prefix calls with `Crypto::` or `RuntimeTests::`,
11
+ * and don't use `self::`.
12
+ */
13
+
14
+ class RuntimeTests extends Crypto
15
+ {
16
+ /**
17
+ * Runs the runtime tests.
18
+ *
19
+ * @throws Ex\EnvironmentIsBrokenException
20
+ * @return void
21
+ */
22
+ public static function runtimeTest()
23
+ {
24
+ // 0: Tests haven't been run yet.
25
+ // 1: Tests have passed.
26
+ // 2: Tests are running right now.
27
+ // 3: Tests have failed.
28
+ static $test_state = 0;
29
+
30
+ if ($test_state === 1 || $test_state === 2) {
31
+ return;
32
+ }
33
+
34
+ if ($test_state === 3) {
35
+ /* If an intermittent problem caused a test to fail previously, we
36
+ * want that to be indicated to the user with every call to this
37
+ * library. This way, if the user first does something they really
38
+ * don't care about, and just ignores all exceptions, they won't get
39
+ * screwed when they then start to use the library for something
40
+ * they do care about. */
41
+ throw new Ex\EnvironmentIsBrokenException('Tests failed previously.');
42
+ }
43
+
44
+ try {
45
+ $test_state = 2;
46
+
47
+ Core::ensureFunctionExists('openssl_get_cipher_methods');
48
+ if (\in_array(Core::CIPHER_METHOD, \openssl_get_cipher_methods()) === false) {
49
+ throw new Ex\EnvironmentIsBrokenException(
50
+ 'Cipher method not supported. This is normally caused by an outdated ' .
51
+ 'version of OpenSSL (and/or OpenSSL compiled for FIPS compliance). ' .
52
+ 'Please upgrade to a newer version of OpenSSL that supports ' .
53
+ Core::CIPHER_METHOD . ' to use this library.'
54
+ );
55
+ }
56
+
57
+ RuntimeTests::AESTestVector();
58
+ RuntimeTests::HMACTestVector();
59
+ RuntimeTests::HKDFTestVector();
60
+
61
+ RuntimeTests::testEncryptDecrypt();
62
+ Core::ensureTrue(Core::ourStrlen(Key::createNewRandomKey()->getRawBytes()) === Core::KEY_BYTE_SIZE);
63
+
64
+ Core::ensureTrue(Core::ENCRYPTION_INFO_STRING !== Core::AUTHENTICATION_INFO_STRING);
65
+ } catch (Ex\EnvironmentIsBrokenException $ex) {
66
+ // Do this, otherwise it will stay in the "tests are running" state.
67
+ $test_state = 3;
68
+ throw $ex;
69
+ }
70
+
71
+ // Change this to '0' make the tests always re-run (for benchmarking).
72
+ $test_state = 1;
73
+ }
74
+
75
+ /**
76
+ * High-level tests of Crypto operations.
77
+ *
78
+ * @throws Ex\EnvironmentIsBrokenException
79
+ * @return void
80
+ */
81
+ private static function testEncryptDecrypt()
82
+ {
83
+ $key = Key::createNewRandomKey();
84
+ $data = "EnCrYpT EvErYThInG\x00\x00";
85
+
86
+ // Make sure encrypting then decrypting doesn't change the message.
87
+ $ciphertext = Crypto::encrypt($data, $key, true);
88
+ try {
89
+ $decrypted = Crypto::decrypt($ciphertext, $key, true);
90
+ } catch (Ex\WrongKeyOrModifiedCiphertextException $ex) {
91
+ // It's important to catch this and change it into a
92
+ // Ex\EnvironmentIsBrokenException, otherwise a test failure could trick
93
+ // the user into thinking it's just an invalid ciphertext!
94
+ throw new Ex\EnvironmentIsBrokenException();
95
+ }
96
+ Core::ensureTrue($decrypted === $data);
97
+
98
+ // Modifying the ciphertext: Appending a string.
99
+ try {
100
+ Crypto::decrypt($ciphertext . 'a', $key, true);
101
+ throw new Ex\EnvironmentIsBrokenException();
102
+ } catch (Ex\WrongKeyOrModifiedCiphertextException $e) { /* expected */
103
+ }
104
+
105
+ // Modifying the ciphertext: Changing an HMAC byte.
106
+ $indices_to_change = [
107
+ 0, // The header.
108
+ Core::HEADER_VERSION_SIZE + 1, // the salt
109
+ Core::HEADER_VERSION_SIZE + Core::SALT_BYTE_SIZE + 1, // the IV
110
+ Core::HEADER_VERSION_SIZE + Core::SALT_BYTE_SIZE + Core::BLOCK_BYTE_SIZE + 1, // the ciphertext
111
+ ];
112
+
113
+ foreach ($indices_to_change as $index) {
114
+ try {
115
+ $ciphertext[$index] = \chr((\ord($ciphertext[$index]) + 1) % 256);
116
+ Crypto::decrypt($ciphertext, $key, true);
117
+ throw new Ex\EnvironmentIsBrokenException();
118
+ } catch (Ex\WrongKeyOrModifiedCiphertextException $e) { /* expected */
119
+ }
120
+ }
121
+
122
+ // Decrypting with the wrong key.
123
+ $key = Key::createNewRandomKey();
124
+ $data = 'abcdef';
125
+ $ciphertext = Crypto::encrypt($data, $key, true);
126
+ $wrong_key = Key::createNewRandomKey();
127
+ try {
128
+ Crypto::decrypt($ciphertext, $wrong_key, true);
129
+ throw new Ex\EnvironmentIsBrokenException();
130
+ } catch (Ex\WrongKeyOrModifiedCiphertextException $e) { /* expected */
131
+ }
132
+
133
+ // Ciphertext too small.
134
+ $key = Key::createNewRandomKey();
135
+ $ciphertext = \str_repeat('A', Core::MINIMUM_CIPHERTEXT_SIZE - 1);
136
+ try {
137
+ Crypto::decrypt($ciphertext, $key, true);
138
+ throw new Ex\EnvironmentIsBrokenException();
139
+ } catch (Ex\WrongKeyOrModifiedCiphertextException $e) { /* expected */
140
+ }
141
+ }
142
+
143
+ /**
144
+ * Test HKDF against test vectors.
145
+ *
146
+ * @throws Ex\EnvironmentIsBrokenException
147
+ * @return void
148
+ */
149
+ private static function HKDFTestVector()
150
+ {
151
+ // HKDF test vectors from RFC 5869
152
+
153
+ // Test Case 1
154
+ $ikm = \str_repeat("\x0b", 22);
155
+ $salt = Encoding::hexToBin('000102030405060708090a0b0c');
156
+ $info = Encoding::hexToBin('f0f1f2f3f4f5f6f7f8f9');
157
+ $length = 42;
158
+ $okm = Encoding::hexToBin(
159
+ '3cb25f25faacd57a90434f64d0362f2a' .
160
+ '2d2d0a90cf1a5a4c5db02d56ecc4c5bf' .
161
+ '34007208d5b887185865'
162
+ );
163
+ $computed_okm = Core::HKDF('sha256', $ikm, $length, $info, $salt);
164
+ Core::ensureTrue($computed_okm === $okm);
165
+
166
+ // Test Case 7
167
+ $ikm = \str_repeat("\x0c", 22);
168
+ $length = 42;
169
+ $okm = Encoding::hexToBin(
170
+ '2c91117204d745f3500d636a62f64f0a' .
171
+ 'b3bae548aa53d423b0d1f27ebba6f5e5' .
172
+ '673a081d70cce7acfc48'
173
+ );
174
+ $computed_okm = Core::HKDF('sha1', $ikm, $length, '', null);
175
+ Core::ensureTrue($computed_okm === $okm);
176
+ }
177
+
178
+ /**
179
+ * Test HMAC against test vectors.
180
+ *
181
+ * @throws Ex\EnvironmentIsBrokenException
182
+ * @return void
183
+ */
184
+ private static function HMACTestVector()
185
+ {
186
+ // HMAC test vector From RFC 4231 (Test Case 1)
187
+ $key = \str_repeat("\x0b", 20);
188
+ $data = 'Hi There';
189
+ $correct = 'b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7';
190
+ Core::ensureTrue(
191
+ \hash_hmac(Core::HASH_FUNCTION_NAME, $data, $key) === $correct
192
+ );
193
+ }
194
+
195
+ /**
196
+ * Test AES against test vectors.
197
+ *
198
+ * @throws Ex\EnvironmentIsBrokenException
199
+ * @return void
200
+ */
201
+ private static function AESTestVector()
202
+ {
203
+ // AES CTR mode test vector from NIST SP 800-38A
204
+ $key = Encoding::hexToBin(
205
+ '603deb1015ca71be2b73aef0857d7781' .
206
+ '1f352c073b6108d72d9810a30914dff4'
207
+ );
208
+ $iv = Encoding::hexToBin('f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff');
209
+ $plaintext = Encoding::hexToBin(
210
+ '6bc1bee22e409f96e93d7e117393172a' .
211
+ 'ae2d8a571e03ac9c9eb76fac45af8e51' .
212
+ '30c81c46a35ce411e5fbc1191a0a52ef' .
213
+ 'f69f2445df4f9b17ad2b417be66c3710'
214
+ );
215
+ $ciphertext = Encoding::hexToBin(
216
+ '601ec313775789a5b7a7f504bbf3d228' .
217
+ 'f443e3ca4d62b59aca84e990cacaf5c5' .
218
+ '2b0930daa23de94ce87017ba2d84988d' .
219
+ 'dfc9c58db67aada613c2dd08457941a6'
220
+ );
221
+
222
+ $computed_ciphertext = Crypto::plainEncrypt($plaintext, $key, $iv);
223
+ Core::ensureTrue($computed_ciphertext === $ciphertext);
224
+
225
+ $computed_plaintext = Crypto::plainDecrypt($ciphertext, $key, $iv, Core::CIPHER_METHOD);
226
+ Core::ensureTrue($computed_plaintext === $plaintext);
227
+ }
228
+ }
vendor/gliterd/backblaze-b2/CHANGELOG.md ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Changelog
2
+
3
+ All Notable changes to `gliterd/backblaze-b2` will be documented in this file.
4
+
5
+ Updates should follow the [Keep a CHANGELOG](http://keepachangelog.com/) principles.
6
+
7
+ ## NEXT - YYYY-MM-DD
8
+
9
+ ### Added
10
+ - Nothing
11
+
12
+ ### Deprecated
13
+ - Nothing
14
+
15
+ ### Fixed
16
+ - Nothing
17
+
18
+ ### Removed
19
+ - Nothing
20
+
21
+ ### Security
22
+ - Nothing
vendor/gliterd/backblaze-b2/CONDUCT.md ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Contributor Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at `contact@yeello.com`. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4/
vendor/gliterd/backblaze-b2/CONTRIBUTING.md ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Contributing
2
+
3
+ Contributions are **welcome** and will be fully **credited**.
4
+
5
+ We accept contributions via Pull Requests on [Github](https://github.com/mhetreramesh/flysystem-backblaze).
6
+
7
+
8
+ ## Pull Requests
9
+
10
+ - **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - The easiest way to apply the conventions is to install [PHP Code Sniffer](http://pear.php.net/package/PHP_CodeSniffer).
11
+
12
+ - **Add tests!** - Your patch won't be accepted if it doesn't have tests.
13
+
14
+ - **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date.
15
+
16
+ - **Consider our release cycle** - We try to follow [SemVer v2.0.0](http://semver.org/). Randomly breaking public APIs is not an option.
17
+
18
+ - **Create feature branches** - Don't ask us to pull from your master branch.
19
+
20
+ - **One pull request per feature** - If you want to do more than one thing, send multiple pull requests.
21
+
22
+ - **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please [squash them](http://www.git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Changing-Multiple-Commit-Messages) before submitting.
23
+
24
+
25
+ ## Running Tests
26
+
27
+ ``` bash
28
+ $ composer test
29
+ ```
30
+
31
+
32
+ **Happy coding**!
vendor/gliterd/backblaze-b2/LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2017 Gliterd Software
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
vendor/gliterd/backblaze-b2/README.md ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ## Backblaze B2 for PHP
2
+
3
+ [![Author](http://img.shields.io/badge/author-@mhetreramesh-blue.svg?style=flat-square)](https://twitter.com/mhetreramesh)
4
+ [![Latest Version on Packagist](https://img.shields.io/packagist/v/gliterd/backblaze-b2.svg?style=flat-square)](https://packagist.org/packages/gliterd/backblaze-b2)
5
+ [![Software License][ico-license]](LICENSE.md)
6
+ [![Build Status](https://img.shields.io/travis/gliterd/backblaze-b2/master.svg?style=flat-square)](https://travis-ci.org/gliterd/backblaze-b2)
7
+ [![Coverage Status][ico-scrutinizer]][link-scrutinizer]
8
+ [![Quality Score][ico-code-quality]][link-code-quality]
9
+ [![Total Downloads](https://img.shields.io/packagist/dt/gliterd/backblaze-b2.svg?style=flat-square)](https://packagist.org/packages/gliterd/backblaze-b2)
10
+
11
+ `backblaze-b2` is the SDK for working with Backblaze's B2 storage service.
12
+
13
+ ## Install
14
+
15
+ Via Composer
16
+
17
+ ``` bash
18
+ $ composer require gliterd/backblaze-b2
19
+ ```
20
+
21
+ ## Usage
22
+
23
+ ``` php
24
+ use BackblazeB2\Client;
25
+ use BackblazeB2\Bucket;
26
+
27
+ $client = new Client('accountId', 'applicationKey');
28
+ ```
29
+ #### Returns a bucket details
30
+ ``` php
31
+ $bucket = $client->createBucket([
32
+ 'BucketName' => 'my-special-bucket',
33
+ 'BucketType' => Bucket::TYPE_PRIVATE // or TYPE_PUBLIC
34
+ ]);
35
+ ```
36
+
37
+ #### Change the bucket Type
38
+ ``` php
39
+ $updatedBucket = $client->updateBucket([
40
+ 'BucketId' => $bucket->getId(),
41
+ 'BucketType' => Bucket::TYPE_PUBLIC
42
+ ]);
43
+ ```
44
+
45
+ #### List all buckets
46
+ ``` php
47
+ $buckets = $client->listBuckets();
48
+ ```
49
+ #### Delete a bucket
50
+ ``` php
51
+ $client->deleteBucket([
52
+ 'BucketId' => 'YOUR_BUCKET_ID'
53
+ ]);
54
+ ```
55
+
56
+ #### File Upload
57
+ ``` php
58
+ $file = $client->upload([
59
+ 'BucketName' => 'my-special-bucket',
60
+ 'FileName' => 'path/to/upload/to',
61
+ 'Body' => 'I am the file content'
62
+
63
+ // The file content can also be provided via a resource.
64
+ // 'Body' => fopen('/path/to/input', 'r')
65
+ ]);
66
+ ```
67
+
68
+ #### File Download
69
+ ``` php
70
+ $fileContent = $client->download([
71
+ 'FileId' => $file->getId()
72
+
73
+ // Can also identify the file via bucket and path:
74
+ // 'BucketName' => 'my-special-bucket',
75
+ // 'FileName' => 'path/to/file'
76
+
77
+ // Can also save directly to a location on disk. This will cause download() to not return file content.
78
+ // 'SaveAs' => '/path/to/save/location'
79
+ ]);
80
+ ```
81
+
82
+ #### File Delete
83
+ ``` php
84
+ $fileDelete = $client->deleteFile([
85
+ 'FileId' => $file->getId()
86
+
87
+ // Can also identify the file via bucket and path:
88
+ // 'BucketName' => 'my-special-bucket',
89
+ // 'FileName' => 'path/to/file'
90
+ ]);
91
+ ```
92
+
93
+ #### List all files
94
+ ``` php
95
+ $fileList = $client->listFiles([
96
+ 'BucketId' => 'YOUR_BUCKET_ID'
97
+ ]);
98
+ ```
99
+
100
+
101
+ ## Change log
102
+
103
+ Please see [CHANGELOG](CHANGELOG.md) for more information what has changed recently.
104
+
105
+ ## Testing
106
+
107
+ ```bash
108
+ $ vendor/bin/phpunit
109
+ ```
110
+
111
+
112
+ ## Contributing
113
+
114
+ Please see [CONTRIBUTING](CONTRIBUTING.md) and [CONDUCT](CONDUCT.md) for details.
115
+
116
+ ## Security
117
+
118
+ If you discover any security related issues, please email mhetreramesh@gmail.com instead of using the issue tracker.
119
+
120
+ ## Credits
121
+
122
+ - [All Contributors][link-contributors]
123
+
124
+ ## License
125
+
126
+ The MIT License (MIT). Please see [License File](LICENSE.md) for more information.
127
+
128
+ [ico-version]: https://img.shields.io/packagist/v/gliterd/backblaze-b2.svg?style=flat-square
129
+ [ico-license]: https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square
130
+ [ico-travis]: https://img.shields.io/travis/gliterd/backblaze-b2/master.svg?style=flat-square
131
+ [ico-scrutinizer]: https://img.shields.io/scrutinizer/coverage/g/gliterd/backblaze-b2.svg?style=flat-square
132
+ [ico-code-quality]: https://img.shields.io/scrutinizer/g/gliterd/backblaze-b2.svg?style=flat-square
133
+ [ico-downloads]: https://img.shields.io/packagist/dt/gliterd/backblaze-b2.svg?style=flat-square
134
+
135
+ [link-packagist]: https://packagist.org/packages/gliterd/backblaze-b2
136
+ [link-travis]: https://travis-ci.org/gliterd/backblaze-b2
137
+ [link-scrutinizer]: https://scrutinizer-ci.com/g/gliterd/backblaze-b2/code-structure
138
+ [link-code-quality]: https://scrutinizer-ci.com/g/gliterd/backblaze-b2
139
+ [link-downloads]: https://packagist.org/packages/gliterd/backblaze-b2
140
+ [link-author]: https://github.com/gliterd
141
+ [link-contributors]: ../../contributors
vendor/gliterd/backblaze-b2/composer.json ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "gliterd/backblaze-b2",
3
+ "type": "library",
4
+ "description": "PHP SDK for working with backblaze B2 cloud storage.",
5
+ "keywords": ["cloud-storage", "b2", "storage", "backblaze", "cloud", "filesystem", "backup"],
6
+ "homepage": "https://github.com/gliterd/b2-sdk-php",
7
+ "license": "MIT",
8
+ "authors": [
9
+ {
10
+ "name": "Ramesh Mhetre",
11
+ "email": "mhetreramesh@gmail.com",
12
+ "homepage": "https://gliterd.com",
13
+ "role": "Developer"
14
+ }
15
+ ],
16
+ "require": {
17
+ "php": ">=5.5.0",
18
+ "guzzlehttp/guzzle": "^6.1"
19
+ },
20
+ "require-dev": {
21
+ "phpunit/phpunit": "4.8.*",
22
+ "scrutinizer/ocular": "~1.1",
23
+ "squizlabs/php_codesniffer": "~2.3"
24
+ },
25
+ "autoload": {
26
+ "psr-4": {
27
+ "BackblazeB2\\": "src/"
28
+ }
29
+ },
30
+ "autoload-dev": {
31
+ "psr-4": {
32
+ "BackblazeB2\\Tests\\": "tests/"
33
+ }
34
+ },
35
+ "scripts": {
36
+ "test": "phpunit",
37
+ "format": "phpcbf --standard=psr2 src/"
38
+ },
39
+ "config": {
40
+ "sort-packages": true
41
+ }
42
+ }
vendor/gliterd/backblaze-b2/phpunit.hhvm.xml ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <phpunit backupGlobals="false"
3
+ backupStaticAttributes="false"
4
+ bootstrap="./phpunit.php"
5
+ colors="true"
6
+ convertErrorsToExceptions="true"
7
+ convertNoticesToExceptions="true"
8
+ convertWarningsToExceptions="true"
9
+ processIsolation="false"
10
+ stopOnFailure="false"
11
+ syntaxCheck="true"
12
+ verbose="true"
13
+ >
14
+ <testsuites>
15
+ <testsuite name="backblaze-b2">
16
+ <directory suffix=".php">./tests/</directory>
17
+ </testsuite>
18
+ </testsuites>
19
+ <filter>
20
+ <whitelist>
21
+ <directory suffix=".php">./src/</directory>
22
+ </whitelist>
23
+ </filter>
24
+ </phpunit>
vendor/gliterd/backblaze-b2/phpunit.php ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ <?php
2
+
3
+ require __DIR__.'/vendor/autoload.php';
vendor/gliterd/backblaze-b2/phpunit.xml ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <phpunit backupGlobals="false"
3
+ backupStaticAttributes="false"
4
+ bootstrap="./phpunit.php"
5
+ colors="true"
6
+ convertErrorsToExceptions="true"
7
+ convertNoticesToExceptions="true"
8
+ convertWarningsToExceptions="true"
9
+ processIsolation="false"
10
+ stopOnFailure="false"
11
+ syntaxCheck="true"
12
+ verbose="true"
13
+ >
14
+ <testsuites>
15
+ <testsuite name="backblaze-b2">
16
+ <directory suffix=".php">./tests/</directory>
17
+ </testsuite>
18
+ </testsuites>
19
+ <filter>
20
+ <whitelist>
21
+ <directory suffix=".php">./src/</directory>
22
+ </whitelist>
23
+ </filter>
24
+ <logging>
25
+ <log type="coverage-text" target="php://stdout" showUncoveredFiles="true"/>
26
+ <log type="coverage-html" target="coverage" showUncoveredFiles="true"/>
27
+ <log type="coverage-clover" target="coverage.xml" showUncoveredFiles="true"/>
28
+ </logging>
29
+ </phpunit>
vendor/gliterd/backblaze-b2/src/Bucket.php ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace BackblazeB2;
4
+
5
+ class Bucket
6
+ {
7
+ const TYPE_PUBLIC = 'allPublic';
8
+ const TYPE_PRIVATE = 'allPrivate';
9
+
10
+ protected $id;
11
+ protected $name;
12
+ protected $type;
13
+
14
+ /**
15
+ * Bucket constructor.
16
+ *
17
+ * @param $id
18
+ * @param $name
19
+ * @param $type
20
+ */
21
+ public function __construct($id, $name, $type)
22
+ {
23
+ $this->id = $id;
24
+ $this->name = $name;
25
+ $this->type = $type;
26
+ }
27
+
28
+ public function getId()
29
+ {
30
+ return $this->id;
31
+ }
32
+
33
+ public function getName()
34
+ {
35
+ return $this->name;
36
+ }
37
+
38
+ public function getType()
39
+ {
40
+ return $this->type;
41
+ }
42
+ }
vendor/gliterd/backblaze-b2/src/Client.php ADDED
@@ -0,0 +1,479 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace BackblazeB2;
4
+
5
+ use BackblazeB2\Exceptions\NotFoundException;
6
+ use BackblazeB2\Exceptions\ValidationException;
7
+ use BackblazeB2\Http\Client as HttpClient;
8
+
9
+ class Client
10
+ {
11
+ protected $accountId;
12
+ protected $applicationKey;
13
+
14
+ protected $authToken;
15
+ protected $apiUrl;
16
+ protected $downloadUrl;
17
+
18
+ protected $client;
19
+
20
+ /**
21
+ * Client constructor. Accepts the account ID, application key and an optional array of options.
22
+ *
23
+ * @param $accountId
24
+ * @param $applicationKey
25
+ * @param array $options
26
+ */
27
+ public function __construct($accountId, $applicationKey, array $options = [])
28
+ {
29
+ $this->accountId = $accountId;
30
+ $this->applicationKey = $applicationKey;
31
+
32
+ if (isset($options['client'])) {
33
+ $this->client = $options['client'];
34
+ } else {
35
+ $this->client = new HttpClient(['exceptions' => false]);
36
+ }
37
+
38
+ $this->authorizeAccount();
39
+ }
40
+
41
+ /**
42
+ * Create a bucket with the given name and type.
43
+ *
44
+ * @param array $options
45
+ *
46
+ * @throws ValidationException
47
+ *
48
+ * @return Bucket
49
+ */
50
+ public function createBucket(array $options)
51
+ {
52
+ if (!in_array($options['BucketType'], [Bucket::TYPE_PUBLIC, Bucket::TYPE_PRIVATE])) {
53
+ throw new ValidationException(
54
+ sprintf('Bucket type must be %s or %s', Bucket::TYPE_PRIVATE, Bucket::TYPE_PUBLIC)
55
+ );
56
+ }
57
+
58
+ $response = $this->client->request('POST', $this->apiUrl.'/b2_create_bucket', [
59
+ 'headers' => [
60
+ 'Authorization' => $this->authToken,
61
+ ],
62
+ 'json' => [
63
+ 'accountId' => $this->accountId,
64
+ 'bucketName' => $options['BucketName'],
65
+ 'bucketType' => $options['BucketType'],
66
+ ],
67
+ ]);
68
+
69
+ return new Bucket($response['bucketId'], $response['bucketName'], $response['bucketType']);
70
+ }
71
+
72
+ /**
73
+ * Updates the type attribute of a bucket by the given ID.
74
+ *
75
+ * @param array $options
76
+ *
77
+ * @throws ValidationException
78
+ *
79
+ * @return Bucket
80
+ */
81
+ public function updateBucket(array $options)
82
+ {
83
+ if (!in_array($options['BucketType'], [Bucket::TYPE_PUBLIC, Bucket::TYPE_PRIVATE])) {
84
+ throw new ValidationException(
85
+ sprintf('Bucket type must be %s or %s', Bucket::TYPE_PRIVATE, Bucket::TYPE_PUBLIC)
86
+ );
87
+ }
88
+
89
+ if (!isset($options['BucketId']) && isset($options['BucketName'])) {
90
+ $options['BucketId'] = $this->getBucketIdFromName($options['BucketName']);
91
+ }
92
+
93
+ $response = $this->client->request('POST', $this->apiUrl.'/b2_update_bucket', [
94
+ 'headers' => [
95
+ 'Authorization' => $this->authToken,
96
+ ],
97
+ 'json' => [
98
+ 'accountId' => $this->accountId,
99
+ 'bucketId' => $options['BucketId'],
100
+ 'bucketType' => $options['BucketType'],
101
+ ],
102
+ ]);
103
+
104
+ return new Bucket($response['bucketId'], $response['bucketName'], $response['bucketType']);
105
+ }
106
+
107
+ /**
108
+ * Returns a list of bucket objects representing the buckets on the account.
109
+ *
110
+ * @return array
111
+ */
112
+ public function listBuckets()
113
+ {
114
+ $buckets = [];
115
+
116
+ $response = $this->client->request('POST', $this->apiUrl.'/b2_list_buckets', [
117
+ 'headers' => [
118
+ 'Authorization' => $this->authToken,
119
+ ],
120
+ 'json' => [
121
+ 'accountId' => $this->accountId,
122
+ ],
123
+ ]);
124
+
125
+ foreach ($response['buckets'] as $bucket) {
126
+ $buckets[] = new Bucket($bucket['bucketId'], $bucket['bucketName'], $bucket['bucketType']);
127
+ }
128
+
129
+ return $buckets;
130
+ }
131
+
132
+ /**
133
+ * Deletes the bucket identified by its ID.
134
+ *
135
+ * @param array $options
136
+ *
137
+ * @return bool
138
+ */
139
+ public function deleteBucket(array $options)
140
+ {
141
+ if (!isset($options['BucketId']) && isset($options['BucketName'])) {
142
+ $options['BucketId'] = $this->getBucketIdFromName($options['BucketName']);
143
+ }
144
+
145
+ $this->client->request('POST', $this->apiUrl.'/b2_delete_bucket', [
146
+ 'headers' => [
147
+ 'Authorization' => $this->authToken,
148
+ ],
149
+ 'json' => [
150
+ 'accountId' => $this->accountId,
151
+ 'bucketId' => $options['BucketId'],
152
+ ],
153
+ ]);
154
+
155
+ return true;
156
+ }
157
+
158
+ /**
159
+ * Uploads a file to a bucket and returns a File object.
160
+ *
161
+ * @param array $options
162
+ *
163
+ * @return File
164
+ */
165
+ public function upload(array $options)
166
+ {
167
+ // Clean the path if it starts with /.
168
+ if (substr($options['FileName'], 0, 1) === '/') {
169
+ $options['FileName'] = ltrim($options['FileName'], '/');
170
+ }
171
+
172
+ if (!isset($options['BucketId']) && isset($options['BucketName'])) {
173
+ $options['BucketId'] = $this->getBucketIdFromName($options['BucketName']);
174
+ }
175
+
176
+ // Retrieve the URL that we should be uploading to.
177
+ $response = $this->client->request('POST', $this->apiUrl.'/b2_get_upload_url', [
178
+ 'headers' => [
179
+ 'Authorization' => $this->authToken,
180
+ ],
181
+ 'json' => [
182
+ 'bucketId' => $options['BucketId'],
183
+ ],
184
+ ]);
185
+
186
+ $uploadEndpoint = $response['uploadUrl'];
187
+ $uploadAuthToken = $response['authorizationToken'];
188
+
189
+ if (is_resource($options['Body'])) {
190
+ // We need to calculate the file's hash incrementally from the stream.
191
+ $context = hash_init('sha1');
192
+ hash_update_stream($context, $options['Body']);
193
+ $hash = hash_final($context);
194
+
195
+ // Similarly, we have to use fstat to get the size of the stream.
196
+ $size = fstat($options['Body'])['size'];
197
+
198
+ // Rewind the stream before passing it to the HTTP client.
199
+ rewind($options['Body']);
200
+ } else {
201
+ // We've been given a simple string body, it's super simple to calculate the hash and size.
202
+ $hash = sha1($options['Body']);
203
+ $size = mb_strlen($options['Body']);
204
+ }
205
+
206
+ if (!isset($options['FileLastModified'])) {
207
+ $options['FileLastModified'] = round(microtime(true) * 1000);
208
+ }
209
+
210
+ if (!isset($options['FileContentType'])) {
211
+ $options['FileContentType'] = 'b2/x-auto';
212
+ }
213
+
214
+ $response = $this->client->request('POST', $uploadEndpoint, [
215
+ 'headers' => [
216
+ 'Authorization' => $uploadAuthToken,
217
+ 'Content-Type' => $options['FileContentType'],
218
+ 'Content-Length' => $size,
219
+ 'X-Bz-File-Name' => $options['FileName'],
220
+ 'X-Bz-Content-Sha1' => $hash,
221
+ 'X-Bz-Info-src_last_modified_millis' => $options['FileLastModified'],
222
+ ],
223
+ 'body' => $options['Body'],
224
+ ]);
225
+
226
+ return new File(
227
+ $response['fileId'],
228
+ $response['fileName'],
229
+ $response['contentSha1'],
230
+ $response['contentLength'],
231
+ $response['contentType'],
232
+ $response['fileInfo']
233
+ );
234
+ }
235
+
236
+ /**
237
+ * Download a file from a B2 bucket.
238
+ *
239
+ * @param array $options
240
+ *
241
+ * @return bool|mixed|string
242
+ */
243
+ public function download(array $options)
244
+ {
245
+ $requestUrl = null;
246
+ $requestOptions = [
247
+ 'headers' => [
248
+ 'Authorization' => $this->authToken,
249
+ ],
250
+ 'sink' => isset($options['SaveAs']) ? $options['SaveAs'] : null,
251
+ ];
252
+
253
+ if (isset($options['FileId'])) {
254
+ $requestOptions['query'] = ['fileId' => $options['FileId']];
255
+ $requestUrl = $this->downloadUrl.'/b2api/v1/b2_download_file_by_id';
256
+ } else {
257
+ if (!isset($options['BucketName']) && isset($options['BucketId'])) {
258
+ $options['BucketName'] = $this->getBucketNameFromId($options['BucketId']);
259
+ }
260
+
261
+ $requestUrl = sprintf('%s/file/%s/%s', $this->downloadUrl, $options['BucketName'], $options['FileName']);
262
+ }
263
+
264
+ $response = $this->client->request('GET', $requestUrl, $requestOptions, false);
265
+
266
+ return isset($options['SaveAs']) ? true : $response;
267
+ }
268
+
269
+ /**
270
+ * Retrieve a collection of File objects representing the files stored inside a bucket.
271
+ *
272
+ * @param array $options
273
+ *
274
+ * @return array
275
+ */
276
+ public function listFiles(array $options)
277
+ {
278
+ // if FileName is set, we only attempt to retrieve information about that single file.
279
+ $fileName = !empty($options['FileName']) ? $options['FileName'] : null;
280
+
281
+ $nextFileName = null;
282
+ $maxFileCount = 1000;
283
+ $files = [];
284
+
285
+ if (!isset($options['BucketId']) && isset($options['BucketName'])) {
286
+ $options['BucketId'] = $this->getBucketIdFromName($options['BucketName']);
287
+ }
288
+
289
+ if ($fileName) {
290
+ $nextFileName = $fileName;
291
+ $maxFileCount = 1;
292
+ }
293
+
294
+ // B2 returns, at most, 1000 files per "page". Loop through the pages and compile an array of File objects.
295
+ while (true) {
296
+ $response = $this->client->request('POST', $this->apiUrl.'/b2_list_file_names', [
297
+ 'headers' => [
298
+ 'Authorization' => $this->authToken,
299
+ ],
300
+ 'json' => [
301
+ 'bucketId' => $options['BucketId'],
302
+ 'startFileName' => $nextFileName,
303
+ 'maxFileCount' => $maxFileCount,
304
+ ],
305
+ ]);
306
+
307
+ foreach ($response['files'] as $file) {
308
+ // if we have a file name set, only retrieve information if the file name matches
309
+ if (!$fileName || ($fileName === $file['fileName'])) {
310
+ $files[] = new File($file['fileId'], $file['fileName'], null, $file['size']);
311
+ }
312
+ }
313
+
314
+ if ($fileName || $response['nextFileName'] === null) {
315
+ // We've got all the files - break out of loop.
316
+ break;
317
+ }
318
+
319
+ $nextFileName = $response['nextFileName'];
320
+ }
321
+
322
+ return $files;
323
+ }
324
+
325
+ /**
326
+ * Test whether a file exists in B2 for the given bucket.
327
+ *
328
+ * @param array $options
329
+ *
330
+ * @return bool
331
+ */
332
+ public function fileExists(array $options)
333
+ {
334
+ $files = $this->listFiles($options);
335
+
336
+ return !empty($files);
337
+ }
338
+
339
+ /**
340
+ * Returns a single File object representing a file stored on B2.
341
+ *
342
+ * @param array $options
343
+ *
344
+ * @throws NotFoundException If no file id was provided and BucketName + FileName does not resolve to a file, a NotFoundException is thrown.
345
+ *
346
+ * @return File
347
+ */
348
+ public function getFile(array $options)
349
+ {
350
+ if (!isset($options['FileId']) && isset($options['BucketName']) && isset($options['FileName'])) {
351
+ $options['FileId'] = $this->getFileIdFromBucketAndFileName($options['BucketName'], $options['FileName']);
352
+
353
+ if (!$options['FileId']) {
354
+ throw new NotFoundException();
355
+ }
356
+ }
357
+
358
+ $response = $this->client->request('POST', $this->apiUrl.'/b2_get_file_info', [
359
+ 'headers' => [
360
+ 'Authorization' => $this->authToken,
361
+ ],
362
+ 'json' => [
363
+ 'fileId' => $options['FileId'],
364
+ ],
365
+ ]);
366
+
367
+ return new File(
368
+ $response['fileId'],
369
+ $response['fileName'],
370
+ $response['contentSha1'],
371
+ $response['contentLength'],
372
+ $response['contentType'],
373
+ $response['fileInfo'],
374
+ $response['bucketId'],
375
+ $response['action'],
376
+ $response['uploadTimestamp']
377
+ );
378
+ }
379
+
380
+ /**
381
+ * Deletes the file identified by ID from Backblaze B2.
382
+ *
383
+ * @param array $options
384
+ *
385
+ * @return bool
386
+ */
387
+ public function deleteFile(array $options)
388
+ {
389
+ if (!isset($options['FileName'])) {
390
+ $file = $this->getFile($options);
391
+
392
+ $options['FileName'] = $file->getName();
393
+ }
394
+
395
+ if (!isset($options['FileId']) && isset($options['BucketName']) && isset($options['FileName'])) {
396
+ $file = $this->getFile($options);
397
+
398
+ $options['FileId'] = $file->getId();
399
+ }
400
+
401
+ $this->client->request('POST', $this->apiUrl.'/b2_delete_file_version', [
402
+ 'headers' => [
403
+ 'Authorization' => $this->authToken,
404
+ ],
405
+ 'json' => [
406
+ 'fileName' => $options['FileName'],
407
+ 'fileId' => $options['FileId'],
408
+ ],
409
+ ]);
410
+
411
+ return true;
412
+ }
413
+
414
+ /**
415
+ * Authorize the B2 account in order to get an auth token and API/download URLs.
416
+ *
417
+ * @throws \Exception
418
+ */
419
+ protected function authorizeAccount()
420
+ {
421
+ $response = $this->client->request('GET', 'https://api.backblazeb2.com/b2api/v1/b2_authorize_account', [
422
+ 'auth' => [$this->accountId, $this->applicationKey],
423
+ ]);
424
+
425
+ $this->authToken = $response['authorizationToken'];
426
+ $this->apiUrl = $response['apiUrl'].'/b2api/v1';
427
+ $this->downloadUrl = $response['downloadUrl'];
428
+ }
429
+
430
+ /**
431
+ * Maps the provided bucket name to the appropriate bucket ID.
432
+ *
433
+ * @param $name
434
+ *
435
+ * @return null
436
+ */
437
+ protected function getBucketIdFromName($name)
438
+ {
439
+ $buckets = $this->listBuckets();
440
+
441
+ foreach ($buckets as $bucket) {
442
+ if ($bucket->getName() === $name) {
443
+ return $bucket->getId();
444
+ }
445
+ }
446
+ }
447
+
448
+ /**
449
+ * Maps the provided bucket ID to the appropriate bucket name.
450
+ *
451
+ * @param $id
452
+ *
453
+ * @return null
454
+ */
455
+ protected function getBucketNameFromId($id)
456
+ {
457
+ $buckets = $this->listBuckets();
458
+
459
+ foreach ($buckets as $bucket) {
460
+ if ($bucket->getId() === $id) {
461
+ return $bucket->getName();
462
+ }
463
+ }
464
+ }
465
+
466
+ protected function getFileIdFromBucketAndFileName($bucketName, $fileName)
467
+ {
468
+ $files = $this->listFiles([
469
+ 'BucketName' => $bucketName,
470
+ 'FileName' => $fileName,
471
+ ]);
472
+
473
+ foreach ($files as $file) {
474
+ if ($file->getName() === $fileName) {
475
+ return $file->getId();
476
+ }
477
+ }
478
+ }
479
+ }
vendor/gliterd/backblaze-b2/src/ErrorHandler.php ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace BackblazeB2;
4
+
5
+ use BackblazeB2\Exceptions\B2Exception;
6
+ use BackblazeB2\Exceptions\BadJsonException;
7
+ use BackblazeB2\Exceptions\BadValueException;
8
+ use BackblazeB2\Exceptions\BucketAlreadyExistsException;
9
+ use BackblazeB2\Exceptions\BucketNotEmptyException;
10
+ use BackblazeB2\Exceptions\FileNotPresentException;
11
+ use BackblazeB2\Exceptions\NotFoundException;
12
+ use GuzzleHttp\Psr7\Response;
13
+
14
+ class ErrorHandler
15
+ {
16
+ protected static $mappings = [
17
+ 'bad_json' => BadJsonException::class,
18
+ 'bad_value' => BadValueException::class,
19
+ 'duplicate_bucket_name' => BucketAlreadyExistsException::class,
20
+ 'not_found' => NotFoundException::class,
21
+ 'file_not_present' => FileNotPresentException::class,
22
+ 'cannot_delete_non_empty_bucket' => BucketNotEmptyException::class,
23
+ ];
24
+
25
+ public static function handleErrorResponse(Response $response)
26
+ {
27
+ $responseJson = json_decode($response->getBody(), true);
28
+
29
+ if (isset(self::$mappings[$responseJson['code']])) {
30
+ $exceptionClass = self::$mappings[$responseJson['code']];
31
+ } else {
32
+ // We don't have an exception mapped to this response error, throw generic exception
33
+ $exceptionClass = B2Exception::class;
34
+ }
35
+
36
+ throw new $exceptionClass('Received error from B2: '.$responseJson['message']);
37
+ }
38
+ }
vendor/gliterd/backblaze-b2/src/Exceptions/B2Exception.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace BackblazeB2\Exceptions;
4
+
5
+ class B2Exception extends \Exception
6
+ {
7
+ }
vendor/gliterd/backblaze-b2/src/Exceptions/BadJsonException.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace BackblazeB2\Exceptions;
4
+
5
+ class BadJsonException extends \Exception
6
+ {
7
+ }
vendor/gliterd/backblaze-b2/src/Exceptions/BadValueException.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace BackblazeB2\Exceptions;
4
+
5
+ class BadValueException extends \Exception
6
+ {
7
+ }
vendor/gliterd/backblaze-b2/src/Exceptions/BucketAlreadyExistsException.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace BackblazeB2\Exceptions;
4
+
5
+ class BucketAlreadyExistsException extends \Exception
6
+ {
7
+ }
vendor/gliterd/backblaze-b2/src/Exceptions/BucketNotEmptyException.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace BackblazeB2\Exceptions;
4
+
5
+ class BucketNotEmptyException extends \Exception
6
+ {
7
+ }
vendor/gliterd/backblaze-b2/src/Exceptions/FileNotPresentException.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace BackblazeB2\Exceptions;
4
+
5
+ class FileNotPresentException extends \Exception
6
+ {
7
+ }
vendor/gliterd/backblaze-b2/src/Exceptions/NotFoundException.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace BackblazeB2\Exceptions;
4
+
5
+ class NotFoundException extends \Exception
6
+ {
7
+ }
vendor/gliterd/backblaze-b2/src/Exceptions/ValidationException.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace BackblazeB2\Exceptions;
4
+
5
+ class ValidationException extends \Exception
6
+ {
7
+ }
vendor/gliterd/backblaze-b2/src/File.php ADDED
@@ -0,0 +1,114 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace BackblazeB2;
4
+
5
+ class File
6
+ {
7
+ protected $id;
8
+ protected $name;
9
+ protected $hash;
10
+ protected $size;
11
+ protected $type;
12
+ protected $info;
13
+ protected $bucketId;
14
+ protected $action;
15
+ protected $uploadTimestamp;
16
+
17
+ /**
18
+ * File constructor.
19
+ *
20
+ * @param $id
21
+ * @param $name
22
+ * @param $hash
23
+ * @param $size
24
+ * @param $type
25
+ * @param $info
26
+ * @param $bucketId
27
+ * @param $action
28
+ * @param $uploadTimestamp
29
+ */
30
+ public function __construct($id, $name, $hash = null, $size = null, $type = null, $info = null, $bucketId = null, $action = null, $uploadTimestamp = null)
31
+ {
32
+ $this->id = $id;
33
+ $this->name = $name;
34
+ $this->hash = $hash;
35
+ $this->size = $size;
36
+ $this->type = $type;
37
+ $this->info = $info;
38
+ $this->bucketId = $bucketId;
39
+ $this->action = $action;
40
+ $this->uploadTimestamp = $uploadTimestamp;
41
+ }
42
+
43
+ /**
44
+ * @return string
45
+ */
46
+ public function getId()
47
+ {
48
+ return $this->id;
49
+ }
50
+
51
+ /**
52
+ * @return string
53
+ */
54
+ public function getName()
55
+ {
56
+ return $this->name;
57
+ }
58
+
59
+ /**
60
+ * @return string
61
+ */
62
+ public function getHash()
63
+ {
64
+ return $this->hash;
65
+ }
66
+
67
+ /**
68
+ * @return int
69
+ */
70
+ public function getSize()
71
+ {
72
+ return $this->size;
73
+ }
74
+
75
+ /**
76
+ * @return string
77
+ */
78
+ public function getType()
79
+ {
80
+ return $this->type;
81
+ }
82
+
83
+ /**
84
+ * @return array
85
+ */
86
+ public function getInfo()
87
+ {
88
+ return $this->info;
89
+ }
90
+
91
+ /**
92
+ * @return string
93
+ */
94
+ public function getBucketId()
95
+ {
96
+ return $this->bucketId;
97
+ }
98
+
99
+ /**
100
+ * @return string
101
+ */
102
+ public function getAction()
103
+ {
104
+ return $this->action;
105
+ }
106
+
107
+ /**
108
+ * @return string
109
+ */
110
+ public function getUploadTimestamp()
111
+ {
112
+ return $this->uploadTimestamp;
113
+ }
114
+ }
vendor/gliterd/backblaze-b2/src/Http/Client.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace BackblazeB2\Http;
4
+
5
+ use BackblazeB2\ErrorHandler;
6
+ use GuzzleHttp\Client as GuzzleClient;
7
+
8
+ /**
9
+ * Client wrapper around Guzzle.
10
+ */
11
+ class Client extends GuzzleClient
12
+ {
13
+ /**
14
+ * Sends a response to the B2 API, automatically handling decoding JSON and errors.
15
+ *
16
+ * @param string $method
17
+ * @param null $uri
18
+ * @param array $options
19
+ * @param bool $asJson
20
+ *
21
+ * @return mixed|string
22
+ */
23
+ public function request($method, $uri = null, array $options = [], $asJson = true)
24
+ {
25
+ $response = parent::request($method, $uri, $options);
26
+
27
+ if ($response->getStatusCode() !== 200) {
28
+ ErrorHandler::handleErrorResponse($response);
29
+ }
30
+
31
+ if ($asJson) {
32
+ return json_decode($response->getBody(), true);
33
+ }
34
+
35
+ return $response->getBody()->getContents();
36
+ }
37
+ }
vendor/gliterd/backblaze-b2/tests/ClientTest.php ADDED
@@ -0,0 +1,529 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace BackblazeB2\Tests;
4
+
5
+ use BackblazeB2\Bucket;
6
+ use BackblazeB2\Client;
7
+ use BackblazeB2\Exceptions\BadJsonException;
8
+ use BackblazeB2\Exceptions\BadValueException;
9
+ use BackblazeB2\Exceptions\BucketAlreadyExistsException;
10
+ use BackblazeB2\Exceptions\BucketNotEmptyException;
11
+ use BackblazeB2\Exceptions\NotFoundException;
12
+ use BackblazeB2\Exceptions\ValidationException;
13
+ use BackblazeB2\File;
14
+ use GuzzleHttp\Middleware;
15
+ use GuzzleHttp\Psr7\Stream;
16
+
17
+ class ClientTest extends \PHPUnit_Framework_TestCase
18
+ {
19
+ use TestHelper;
20
+
21
+ public function testCreatePublicBucket()
22
+ {
23
+ $guzzle = $this->buildGuzzleFromResponses([
24
+ $this->buildResponseFromStub(200, [], 'authorize_account.json'),
25
+ $this->buildResponseFromStub(200, [], 'create_bucket_public.json'),
26
+ ]);
27
+
28
+ $client = new Client('testId', 'testKey', ['client' => $guzzle]);
29
+
30
+ // Test that we get a public bucket back after creation
31
+ $bucket = $client->createBucket([
32
+ 'BucketName' => 'Test bucket',
33
+ 'BucketType' => Bucket::TYPE_PUBLIC,
34
+ ]);
35
+ $this->assertInstanceOf(Bucket::class, $bucket);
36
+ $this->assertEquals('Test bucket', $bucket->getName());
37
+ $this->assertEquals(Bucket::TYPE_PUBLIC, $bucket->getType());
38
+ }
39
+
40
+ public function testCreatePrivateBucket()
41
+ {
42
+ $guzzle = $this->buildGuzzleFromResponses([
43
+ $this->buildResponseFromStub(200, [], 'authorize_account.json'),
44
+ $this->buildResponseFromStub(200, [], 'create_bucket_private.json'),
45
+ ]);
46
+
47
+ $client = new Client('testId', 'testKey', ['client' => $guzzle]);
48
+
49
+ // Test that we get a private bucket back after creation
50
+ $bucket = $client->createBucket([
51
+ 'BucketName' => 'Test bucket',
52
+ 'BucketType' => Bucket::TYPE_PRIVATE,
53
+ ]);
54
+ $this->assertInstanceOf(Bucket::class, $bucket);
55
+ $this->assertEquals('Test bucket', $bucket->getName());
56
+ $this->assertEquals(Bucket::TYPE_PRIVATE, $bucket->getType());
57
+ }
58
+
59
+ public function testBucketAlreadyExistsExceptionThrown()
60
+ {
61
+ $this->setExpectedException(BucketAlreadyExistsException::class);
62
+
63
+ $guzzle = $this->buildGuzzleFromResponses([
64
+ $this->buildResponseFromStub(200, [], 'authorize_account.json'),
65
+ $this->buildResponseFromStub(400, [], 'create_bucket_exists.json'),
66
+ ]);
67
+
68
+ $client = new Client('testId', 'testKey', ['client' => $guzzle]);
69
+ $client->createBucket([
70
+ 'BucketName' => 'I already exist',
71
+ 'BucketType' => Bucket::TYPE_PRIVATE,
72
+ ]);
73
+ }
74
+
75
+ public function testInvalidBucketTypeThrowsException()
76
+ {
77
+ $this->setExpectedException(ValidationException::class);
78
+
79
+ $guzzle = $this->buildGuzzleFromResponses([
80
+ $this->buildResponseFromStub(200, [], 'authorize_account.json'),
81
+ ]);
82
+
83
+ $client = new Client('testId', 'testKey', ['client' => $guzzle]);
84
+ $client->createBucket([
85
+ 'BucketName' => 'Test bucket',
86
+ 'BucketType' => 'i am not valid',
87
+ ]);
88
+ }
89
+
90
+ public function testUpdateBucketToPrivate()
91
+ {
92
+ $guzzle = $this->buildGuzzleFromResponses([
93
+ $this->buildResponseFromStub(200, [], 'authorize_account.json'),
94
+ $this->buildResponseFromStub(200, [], 'update_bucket_to_private.json'),
95
+ ]);
96
+
97
+ $client = new Client('testId', 'testKey', ['client' => $guzzle]);
98
+
99
+ $bucket = $client->updateBucket([
100
+ 'BucketId' => 'bucketId',
101
+ 'BucketType' => Bucket::TYPE_PRIVATE,
102
+ ]);
103
+
104
+ $this->assertInstanceOf(Bucket::class, $bucket);
105
+ $this->assertEquals('bucketId', $bucket->getId());
106
+ $this->assertEquals(Bucket::TYPE_PRIVATE, $bucket->getType());
107
+ }
108
+
109
+ public function testUpdateBucketToPublic()
110
+ {
111
+ $guzzle = $this->buildGuzzleFromResponses([
112
+ $this->buildResponseFromStub(200, [], 'authorize_account.json'),
113
+