XCloner – Backup and Restore - Version 4.1.0

Version Description

  • added AES-128-CBC backup encryption and decryption option
  • manage backup fixes
  • scheduled backup screen fixes and addon backup encryption option
  • automated backups encryption option addon
  • generate backups encrypt option addon
Download this release

Release Info

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

Code changes from version 4.0.9 to 4.1.0

Files changed (143) hide show
  1. README.md +4 -1
  2. README.txt +12 -3
  3. admin/class-xcloner-admin.php +79 -72
  4. admin/css/xcloner-admin.css +18 -1
  5. admin/js/xcloner-backup-class.js +55 -0
  6. admin/js/xcloner-manage-backups-class.js +433 -311
  7. admin/js/xcloner-scheduler-class.js +7 -0
  8. admin/partials/xcloner_console_page.php +4 -4
  9. admin/partials/xcloner_generate_backups_page.php +106 -67
  10. admin/partials/xcloner_init_page.php +64 -64
  11. admin/partials/xcloner_manage_backups_page.php +92 -10
  12. admin/partials/xcloner_remote_storage_page.php +197 -197
  13. admin/partials/xcloner_restore_page.php +75 -75
  14. admin/partials/xcloner_scheduled_backups_page.php +56 -45
  15. composer.json +4 -3
  16. composer.lock +20 -137
  17. includes/class-xcloner-activator.php +42 -38
  18. includes/class-xcloner-api.php +1249 -898
  19. includes/class-xcloner-archive.php +532 -508
  20. includes/class-xcloner-database.php +103 -98
  21. includes/class-xcloner-deactivator.php +3 -3
  22. includes/class-xcloner-encryption.php +394 -0
  23. includes/class-xcloner-file-system.php +195 -182
  24. includes/class-xcloner-file-transfer.php +100 -99
  25. includes/class-xcloner-i18n.php +13 -13
  26. includes/class-xcloner-loader.php +162 -149
  27. includes/class-xcloner-logger.php +43 -30
  28. includes/class-xcloner-remote-storage.php +586 -536
  29. includes/class-xcloner-requirements.php +40 -40
  30. includes/class-xcloner-sanitization.php +22 -22
  31. includes/class-xcloner-scheduler.php +180 -114
  32. includes/class-xcloner-settings.php +294 -228
  33. includes/class-xcloner.php +161 -119
  34. public/class-xcloner-public.php +3 -5
  35. restore/xcloner_restore.php +508 -271
  36. uninstall.php +1 -1
  37. vendor/composer/ClassLoader.php +2 -2
  38. vendor/composer/autoload_files.php +0 -1
  39. vendor/composer/autoload_psr4.php +0 -1
  40. vendor/composer/autoload_static.php +0 -9
  41. vendor/composer/installed.json +22 -143
  42. vendor/defuse/php-encryption/.gitignore +0 -11
  43. vendor/defuse/php-encryption/.php_cs +0 -60
  44. vendor/defuse/php-encryption/LICENSE +0 -21
  45. vendor/defuse/php-encryption/README.md +0 -102
  46. vendor/defuse/php-encryption/bin/generate-defuse-key +0 -14
  47. vendor/defuse/php-encryption/composer.json +0 -35
  48. vendor/defuse/php-encryption/dist/Makefile +0 -37
  49. vendor/defuse/php-encryption/dist/box.json +0 -25
  50. vendor/defuse/php-encryption/dist/signingkey.asc +0 -52
  51. vendor/defuse/php-encryption/docs/CryptoDetails.md +0 -64
  52. vendor/defuse/php-encryption/docs/FAQ.md +0 -51
  53. vendor/defuse/php-encryption/docs/InstallingAndVerifying.md +0 -53
  54. vendor/defuse/php-encryption/docs/InternalDeveloperDocs.md +0 -166
  55. vendor/defuse/php-encryption/docs/Tutorial.md +0 -314
  56. vendor/defuse/php-encryption/docs/UpgradingFromV1.2.md +0 -51
  57. vendor/defuse/php-encryption/docs/classes/Crypto.md +0 -280
  58. vendor/defuse/php-encryption/docs/classes/File.md +0 -486
  59. vendor/defuse/php-encryption/docs/classes/Key.md +0 -117
  60. vendor/defuse/php-encryption/docs/classes/KeyProtectedByPassword.md +0 -259
  61. vendor/defuse/php-encryption/psalm.xml +0 -12
  62. vendor/defuse/php-encryption/src/Core.php +0 -448
  63. vendor/defuse/php-encryption/src/Crypto.php +0 -445
  64. vendor/defuse/php-encryption/src/DerivedKeys.php +0 -50
  65. vendor/defuse/php-encryption/src/Encoding.php +0 -268
  66. vendor/defuse/php-encryption/src/Exception/BadFormatException.php +0 -7
  67. vendor/defuse/php-encryption/src/Exception/CryptoException.php +0 -7
  68. vendor/defuse/php-encryption/src/Exception/EnvironmentIsBrokenException.php +0 -7
  69. vendor/defuse/php-encryption/src/Exception/IOException.php +0 -7
  70. vendor/defuse/php-encryption/src/Exception/WrongKeyOrModifiedCiphertextException.php +0 -7
  71. vendor/defuse/php-encryption/src/File.php +0 -762
  72. vendor/defuse/php-encryption/src/Key.php +0 -94
  73. vendor/defuse/php-encryption/src/KeyOrPassword.php +0 -149
  74. vendor/defuse/php-encryption/src/KeyProtectedByPassword.php +0 -145
  75. vendor/defuse/php-encryption/src/RuntimeTests.php +0 -228
  76. vendor/gliterd/backblaze-b2/.gitignore +7 -0
  77. vendor/gliterd/backblaze-b2/.scrutinizer.yml +33 -0
  78. vendor/gliterd/backblaze-b2/.travis.yml +9 -0
  79. vendor/league/flysystem-sftp/.travis.yml +1 -5
  80. vendor/league/flysystem-sftp/changelog.md +21 -0
  81. vendor/league/flysystem-sftp/composer.json +3 -8
  82. vendor/league/flysystem-sftp/phpunit.xml +0 -1
  83. vendor/league/flysystem-sftp/readme.md +5 -0
  84. vendor/league/flysystem-sftp/src/SftpAdapter.php +13 -6
  85. vendor/league/flysystem-sftp/tests/SftpAdapterTests.php +54 -10
  86. vendor/league/flysystem/.travis.yml +1 -1
  87. vendor/league/flysystem/README.md +4 -1
  88. vendor/league/flysystem/changelog.md +21 -0
  89. vendor/league/flysystem/composer.json +3 -3
  90. vendor/league/flysystem/docs/_data/menu.yml +1 -0
  91. vendor/league/flysystem/docs/_data/project.yml +1 -1
  92. vendor/league/flysystem/docs/_includes/carbon.html +1 -1
  93. vendor/league/flysystem/docs/_layouts/default.html +19 -19
  94. vendor/league/flysystem/docs/adapter/azure.md +17 -11
  95. vendor/league/flysystem/docs/adapter/phpcr.md +17 -1
  96. vendor/league/flysystem/docs/adapter/sftp.md +1 -1
  97. vendor/league/flysystem/docs/advanced/caching.md +1 -1
  98. vendor/league/flysystem/docs/advanced/mount-manager.md +2 -2
  99. vendor/league/flysystem/docs/advanced/performance.md +1 -1
  100. vendor/league/flysystem/docs/advanced/provided-plugins.md +1 -1
  101. vendor/league/flysystem/docs/advanced/upgrade-to-1.0.0.md +1 -1
  102. vendor/league/flysystem/docs/api.md +4 -4
  103. vendor/league/flysystem/docs/architecture.md +1 -1
  104. vendor/league/flysystem/docs/dist/styles.css +1 -1
  105. vendor/league/flysystem/docs/github.css +2 -2
  106. vendor/league/flysystem/docs/guides/deterministic-programming.md +3 -3
  107. vendor/league/flysystem/docs/img/azure.svg +69 -1
  108. vendor/league/flysystem/docs/index.css +1 -1
  109. vendor/league/flysystem/docs/index.md +17 -4
  110. vendor/league/flysystem/docs/sponsors.md +15 -9
  111. vendor/league/flysystem/docs/tailwind.js +1 -0
  112. vendor/league/flysystem/docs/usage/filesystem-api.md +59 -4
  113. vendor/league/flysystem/src/Adapter/AbstractFtpAdapter.php +0 -5
  114. vendor/league/flysystem/src/Adapter/Local.php +14 -15
  115. vendor/league/flysystem/src/MountManager.php +351 -23
  116. vendor/league/flysystem/src/Util/MimeType.php +164 -168
  117. vendor/league/flysystem/stub/FilesystemSpy.php +354 -0
  118. vendor/league/flysystem/tests/FtpTests.php +25 -0
  119. vendor/league/flysystem/tests/LocalAdapterTests.php +11 -0
  120. vendor/league/flysystem/tests/MountManagerTests.php +55 -15
  121. vendor/league/flysystem/tests/UtilMimeTests.php +7 -0
  122. vendor/paragonie/random_compat/LICENSE +0 -22
  123. vendor/paragonie/random_compat/build-phar.sh +0 -5
  124. vendor/paragonie/random_compat/composer.json +0 -38
  125. vendor/paragonie/random_compat/dist/random_compat.phar.pubkey +0 -5
  126. vendor/paragonie/random_compat/dist/random_compat.phar.pubkey.asc +0 -11
  127. vendor/paragonie/random_compat/lib/byte_safe_strings.php +0 -181
  128. vendor/paragonie/random_compat/lib/cast_to_int.php +0 -75
  129. vendor/paragonie/random_compat/lib/error_polyfill.php +0 -49
  130. vendor/paragonie/random_compat/lib/random.php +0 -226
  131. vendor/paragonie/random_compat/lib/random_bytes_com_dotnet.php +0 -88
  132. vendor/paragonie/random_compat/lib/random_bytes_dev_urandom.php +0 -167
  133. vendor/paragonie/random_compat/lib/random_bytes_libsodium.php +0 -88
  134. vendor/paragonie/random_compat/lib/random_bytes_libsodium_legacy.php +0 -92
  135. vendor/paragonie/random_compat/lib/random_bytes_mcrypt.php +0 -77
  136. vendor/paragonie/random_compat/lib/random_int.php +0 -190
  137. vendor/paragonie/random_compat/other/build_phar.php +0 -57
  138. vendor/paragonie/random_compat/psalm-autoload.php +0 -9
  139. vendor/paragonie/random_compat/psalm.xml +0 -19
  140. vendor/vakata/jstree/README.md +2 -2
  141. vendor/vakata/jstree/bower.json +1 -1
  142. vendor/vakata/jstree/component.json +1 -1
  143. vendor/vakata/jstree/dist/jstree.js +15 -11
README.md CHANGED
@@ -2,10 +2,12 @@
2
 
3
  [![Author](http://img.shields.io/badge/author-@thinkovi-blue.svg?style=flat-square)](https://twitter.com/thinkovi)
4
  [![Software License](https://img.shields.io/badge/license-GPL-brightgreen.svg?style=flat-square)](LICENSE.txt)
5
- [![Build Status](https://scrutinizer-ci.com/g/ovidiul/XCloner-Wordpress/badges/build.png?b=master)](https://scrutinizer-ci.com/g/ovidiul/XCloner-Wordpress/build-status/master)
 
6
 
7
  Backup your Wordpress site, restore to any web location, send your backups to Dropbox, Amazon S3, Azure, FTP, SFTP and many others with XCloner backup plugin.
8
 
 
9
  XCloner is a Backup and Restore plugin that is perfectly integrated with Wordpress.
10
 
11
  XCloner design was specifically created to Generate custom backups of any LAMP website through custom admin inputs, and to be able to Restore the clone on any other location with the help of the automatic Restore script we provide!
@@ -16,6 +18,7 @@ XCloner Backup tool uses Open Source standards like TAR, Mysql and CSV formats s
16
 
17
  * Backup and Restore your Wordpress site easily
18
  * Create compressed and uncompressed backups using TAR open source format
 
19
  * Create automated backups from your Scheduled Backups Section
20
  * Received email notifications of created backups
21
  * Generate automatic backups based on cronjobs, it can run daily, weekly, monthly or even hourly
2
 
3
  [![Author](http://img.shields.io/badge/author-@thinkovi-blue.svg?style=flat-square)](https://twitter.com/thinkovi)
4
  [![Software License](https://img.shields.io/badge/license-GPL-brightgreen.svg?style=flat-square)](LICENSE.txt)
5
+ [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/ovidiul/XCloner-Wordpress/badges/quality-score.png?b=dev)](https://scrutinizer-ci.com/g/ovidiul/XCloner-Wordpress/?branch=master)
6
+ [![Build Status](https://scrutinizer-ci.com/g/ovidiul/XCloner-Wordpress/badges/build.png?b=dev)](https://scrutinizer-ci.com/g/ovidiul/XCloner-Wordpress/build-status/master)
7
 
8
  Backup your Wordpress site, restore to any web location, send your backups to Dropbox, Amazon S3, Azure, FTP, SFTP and many others with XCloner backup plugin.
9
 
10
+
11
  XCloner is a Backup and Restore plugin that is perfectly integrated with Wordpress.
12
 
13
  XCloner design was specifically created to Generate custom backups of any LAMP website through custom admin inputs, and to be able to Restore the clone on any other location with the help of the automatic Restore script we provide!
18
 
19
  * Backup and Restore your Wordpress site easily
20
  * Create compressed and uncompressed backups using TAR open source format
21
+ * Create encrypted backups archives with AES-128-CBC algorithm
22
  * Create automated backups from your Scheduled Backups Section
23
  * Received email notifications of created backups
24
  * Generate automatic backups based on cronjobs, it can run daily, weekly, monthly or even hourly
README.txt CHANGED
@@ -1,12 +1,12 @@
1
  === XCloner - Backup and Restore===
2
  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: 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.
10
 
11
  == Description ==
12
 
@@ -28,6 +28,7 @@ PHP 5.6+ with mod CURL installed
28
 
29
  * Backup and Restore your Wordpress site easily
30
  * Create compressed and uncompressed backups using TAR open source format
 
31
  * Create automated backups from your Scheduled Backups Section
32
  * Received email notifications of created backups
33
  * Generate automatic backups based on cronjobs, it can run daily, weekly, monthly or even hourly
@@ -38,6 +39,7 @@ PHP 5.6+ with mod CURL installed
38
  * Ability to split backups into multiple smaller parts if a certain size limit is reached
39
  * Generate Differential Backups so your backup will include only files modified after a certain date, giving you the option to decrease the total backup space disk usage
40
  * Generate automatic backups before a Wordpress automatic update
 
41
 
42
  == Installation ==
43
 
@@ -112,6 +114,13 @@ Immigration Attorney Montana <a href="https://www.immigrationlawofmt.com" target
112
 
113
  == Changelog ==
114
 
 
 
 
 
 
 
 
115
  = 4.0.9 =
116
  * remote storage password encryption addon for database
117
  * vendor cleanup packages
1
  === XCloner - Backup and Restore===
2
  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, backup encryption, 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.1.0
8
 
9
+ Backup your site, restore to any web location, encrypt and send your backups to Dropbox, Amazon S3, Azure, FTP, SFTP, WebDAV, Google Drive with XCloner plugin.
10
 
11
  == Description ==
12
 
28
 
29
  * Backup and Restore your Wordpress site easily
30
  * Create compressed and uncompressed backups using TAR open source format
31
+ * Create encrypted backups archives with AES-128-CBC algorithm
32
  * Create automated backups from your Scheduled Backups Section
33
  * Received email notifications of created backups
34
  * Generate automatic backups based on cronjobs, it can run daily, weekly, monthly or even hourly
39
  * Ability to split backups into multiple smaller parts if a certain size limit is reached
40
  * Generate Differential Backups so your backup will include only files modified after a certain date, giving you the option to decrease the total backup space disk usage
41
  * Generate automatic backups before a Wordpress automatic update
42
+ * GDPR compliant by added encryption data
43
 
44
  == Installation ==
45
 
114
 
115
  == Changelog ==
116
 
117
+ = 4.1.0 =
118
+ * added AES-128-CBC backup encryption and decryption option
119
+ * manage backup fixes
120
+ * scheduled backup screen fixes and addon backup encryption option
121
+ * automated backups encryption option addon
122
+ * generate backups encrypt option addon
123
+
124
  = 4.0.9 =
125
  * remote storage password encryption addon for database
126
  * vendor cleanup packages
admin/class-xcloner-admin.php CHANGED
@@ -40,23 +40,27 @@ class Xcloner_Admin {
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
  }
@@ -66,9 +70,9 @@ class Xcloner_Admin {
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
 
@@ -84,13 +88,13 @@ class Xcloner_Admin {
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
  }
96
 
@@ -99,9 +103,9 @@ class Xcloner_Admin {
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
 
@@ -118,97 +122,100 @@ class Xcloner_Admin {
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
 
@@ -216,40 +223,40 @@ class Xcloner_Admin {
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
 
@@ -258,27 +265,27 @@ class Xcloner_Admin {
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
 
40
  */
41
  private $version;
42
 
43
+ /**
44
+ * @var Xcloner
45
+ */
46
  private $xcloner_container;
47
 
48
  /**
49
  * Initialize the class and set its properties.
50
  *
51
+ * Xcloner_Admin constructor.
52
+ * @param Xcloner $xcloner_container
 
 
53
  */
54
+ public function __construct(Xcloner $xcloner_container) {
55
 
56
  $this->plugin_name = $xcloner_container->get_plugin_name();
57
  $this->version = $xcloner_container->get_version();
58
  $this->xcloner_container = $xcloner_container;
59
  }
60
 
61
+ /**
62
+ * @return Xcloner
63
+ */
64
  public function get_xcloner_container() {
65
  return $this->xcloner_container;
66
  }
70
  *
71
  * @since 1.0.0
72
  */
73
+ public function enqueue_styles($hook) {
74
 
75
+ if (!stristr($hook, "page_".$this->plugin_name) || (isset($_GET['option']) and $_GET['option'] == "com_cloner")) {
76
  return;
77
  }
78
 
88
  * class.
89
  */
90
 
91
+ wp_enqueue_style($this->plugin_name."_materialize", plugin_dir_url(__FILE__).'css/materialize.min.css', array(), $this->version, 'all');
92
+ wp_enqueue_style($this->plugin_name."_materialize.clockpicker", plugin_dir_url(__FILE__).'css/materialize.clockpicker.css', array(), $this->version, 'all');
93
+ wp_enqueue_style($this->plugin_name."_materialize.icons", '//fonts.googleapis.com/icon?family=Material+Icons', array(), $this->version, 'all');
94
+ wp_enqueue_style($this->plugin_name."_jquery.datatables", plugin_dir_url(__FILE__).'css/jquery.dataTables.min.css', array(), $this->version, 'all');
95
+ wp_enqueue_style($this->plugin_name."_jquery.datatables.responsive", plugin_dir_url(__FILE__).'css/responsive.dataTables.css', array(), $this->version, 'all');
96
+ 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');
97
+ wp_enqueue_style($this->plugin_name, plugin_dir_url(__FILE__).'css/xcloner-admin.css', array(), $this->version, 'all');
98
 
99
  }
100
 
103
  *
104
  * @since 1.0.0
105
  */
106
+ public function enqueue_scripts($hook) {
107
 
108
+ if (!stristr($hook, "page_".$this->plugin_name)) {
109
  return;
110
  }
111
 
122
  */
123
 
124
  add_thickbox();
125
+ wp_enqueue_script('plugin-install');
126
+ wp_enqueue_script('updates');
127
+ wp_enqueue_script($this->plugin_name."_materialize", plugin_dir_url(__FILE__).'js/materialize.min.js', array('jquery'), $this->version, false);
128
+ wp_enqueue_script($this->plugin_name."_materialize.clockpicker", plugin_dir_url(__FILE__).'js/materialize.clockpicker.js', array('jquery'), $this->version, false);
129
+ wp_enqueue_script($this->plugin_name."_jquery.datatables", plugin_dir_url(__FILE__).'js/jquery.dataTables.min.js', array('jquery'), $this->version, false);
130
+ wp_enqueue_script($this->plugin_name."_jquery.datatables.respnsive", plugin_dir_url(__FILE__).'js/dataTables.responsive.js', array('jquery'), $this->version, false);
131
+ wp_enqueue_script($this->plugin_name."_vakata", dirname(plugin_dir_url(__FILE__)).'/vendor/vakata/jstree/dist/jstree.min.js', array('jquery'), '3.3', false);
132
+ wp_enqueue_script($this->plugin_name."_xcloner-backup-class", plugin_dir_url(__FILE__).'js/xcloner-backup-class.js', array('jquery'), $this->version, false);
133
+ wp_enqueue_script($this->plugin_name."_xcloner-scheduler-class", plugin_dir_url(__FILE__).'js/xcloner-scheduler-class.js', array('jquery'), $this->version, false);
134
+ wp_enqueue_script($this->plugin_name."_xcloner-restore-class", plugin_dir_url(__FILE__).'js/xcloner-restore-class.js', array('jquery'), $this->version, false);
135
+ 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);
136
+ 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);
137
+ wp_enqueue_script($this->plugin_name, plugin_dir_url(__FILE__).'js/xcloner-admin.js', array('jquery'), $this->version, false);
138
 
139
 
140
  }
141
 
142
  public function xcloner_init_page() {
143
+ require_once("partials/xcloner_init_page.php");
144
 
145
  }
146
 
147
+ /**
148
+ * Returns the XCloner Storage Page
149
+ */
150
  public function xcloner_remote_storage_page() {
151
  $xcloner_sanitization = $this->get_xcloner_container()->get_xcloner_sanitization();
152
  $remote_storage = $this->get_xcloner_container()->get_xcloner_remote_storage();
153
 
154
 
155
+ if (isset($_POST['action'])) {
156
+ $_POST['action'] = $xcloner_sanitization->sanitize_input_as_string($_POST['action']);
157
+ $remote_storage->save($_POST['action']);
158
  }
159
 
160
+ if (isset($_POST['authentification_code']) && $_POST['authentification_code'] != "") {
161
+ $_POST['authentification_code'] = $xcloner_sanitization->sanitize_input_as_string($_POST['authentification_code']);
162
 
163
+ $remote_storage->set_access_token($_POST['authentification_code']);
164
  }
165
 
166
+ if (isset($_POST['connection_check']) && $_POST['connection_check']) {
167
+ $remote_storage->check($_POST['action']);
168
  }
169
 
170
+ require_once("partials/xcloner_remote_storage_page.php");
171
 
172
  }
173
 
174
  public function xcloner_scheduled_backups_page() {
175
  $requirements = $this->xcloner_container->get_xcloner_requirements();
176
 
177
+ if (!$requirements->check_backup_ready_status()) {
178
+ require_once("partials/xcloner_init_page.php");
179
 
180
  return false;
181
  }
182
 
183
+ require_once("partials/xcloner_scheduled_backups_page.php");
184
 
185
  }
186
 
187
  public function xcloner_manage_backups_page() {
188
+ require_once("partials/xcloner_manage_backups_page.php");
189
 
190
  }
191
 
192
  public function xcloner_debugger_page() {
193
+ require_once("partials/xcloner_console_page.php");
194
 
195
  }
196
 
197
  public function xcloner_restore_page() {
198
+ require_once("partials/xcloner_restore_page.php");
199
 
200
  }
201
 
202
  public function xcloner_generate_backups_page() {
203
  $requirements = $this->xcloner_container->get_xcloner_requirements();
204
 
205
+ if (!$requirements->check_backup_ready_status()) {
206
+ require_once("partials/xcloner_init_page.php");
207
 
208
  return false;
209
  }
210
 
211
+ require_once("partials/xcloner_generate_backups_page.php");
212
 
213
  return;
214
  }
215
 
216
  public function xcloner_settings_page() {
217
  // check user capabilities
218
+ if (!current_user_can('manage_options')) {
219
  return;
220
  }
221
 
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"
250
+ 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>
251
  </li>
252
  <li><a href="?page=xcloner_settings_page&tab=mysql_options"
253
+ 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>
254
  </li>
255
  <li><a href="?page=xcloner_settings_page&tab=system_options"
256
+ 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>
257
  </li>
258
  <li><a href="?page=xcloner_settings_page&tab=cleanup_options"
259
+ 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>
260
  </li>
261
  </ul>
262
 
265
  <form action="options.php" method="post">
266
  <?php
267
 
268
+ if ($active_tab == 'general_options') {
269
 
270
+ settings_fields('xcloner_general_settings_group');
271
+ do_settings_sections('xcloner_settings_page');
272
 
273
+ } elseif ($active_tab == 'mysql_options') {
274
 
275
+ settings_fields('xcloner_mysql_settings_group');
276
+ do_settings_sections('xcloner_mysql_settings_page');
277
+ } elseif ($active_tab == 'system_options') {
278
 
279
+ settings_fields('xcloner_system_settings_group');
280
+ do_settings_sections('xcloner_system_settings_page');
281
+ } elseif ($active_tab == 'cleanup_options') {
282
 
283
+ settings_fields('xcloner_cleanup_settings_group');
284
+ do_settings_sections('xcloner_cleanup_settings_page');
285
  }
286
 
287
  // output save settings button
288
+ submit_button('Save Settings');
289
  ?>
290
  </form>
291
 
admin/css/xcloner-admin.css CHANGED
@@ -166,7 +166,8 @@ textarea.materialize-textarea {
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
 
@@ -368,6 +369,10 @@ ul.files-list li {
368
  white-space: pre;
369
  }
370
 
 
 
 
 
371
  #manage_backups_wrapper #manage_backups_filter {
372
  min-width: 250px;
373
  }
@@ -389,6 +394,18 @@ i.backup_warning {
389
  display: none;
390
  }
391
 
 
 
 
 
 
 
 
 
 
 
 
 
392
  @media only screen and (min-width: 993px) {
393
  .dashboard .backup-ready {
394
  float: right;
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
+ #manage_backups .backup-encryption, #manage_backups .backup-decryption {
171
  color: #4db6ac;
172
  }
173
 
369
  white-space: pre;
370
  }
371
 
372
+ ul.files-list.error{
373
+ color: red;
374
+ }
375
+
376
  #manage_backups_wrapper #manage_backups_filter {
377
  min-width: 250px;
378
  }
394
  display: none;
395
  }
396
 
397
+ .dataTables_wrapper .dataTables_filter input {
398
+ margin-left: 0px;
399
+ }
400
+
401
+ #backup_options .row{
402
+ min-height: 30px;
403
+ }
404
+
405
+ .input-field .switch label {
406
+ color: #000;
407
+ }
408
+
409
  @media only screen and (min-width: 993px) {
410
  .dashboard .backup-ready {
411
  float: right;
admin/js/xcloner-backup-class.js CHANGED
@@ -245,6 +245,11 @@ class Xcloner_Backup {
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
  }
@@ -268,6 +273,56 @@ class Xcloner_Backup {
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();
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
+ if( jQuery('#backup_options #backup_encrypt').is(':checked')) {
249
+ this.do_backup_encryption();
250
+ return;
251
+ }
252
+
253
  //this.restart_backup();
254
  this.do_backup_done()
255
  }
273
  this.do_ajax(elem, 'backup_files', 1);
274
  }
275
 
276
+ do_backup_encryption_callback(elem, action, response) {
277
+
278
+ if (response.extra) {
279
+ this.params.extra = response.extra;
280
+ }
281
+
282
+ jQuery(".backup-encryption .last-logged-file").text('encrypting ' + response.processing_file+' ...');
283
+
284
+ if (response.total_size !== undefined) {
285
+ jQuery(".backup-encryption .progress > div").removeClass('indeterminate').addClass("determinate");
286
+ var percent = parseInt(response.start * 100) / parseInt(response.total_size)
287
+ jQuery(".backup-encryption .progress .determinate").css('width', parseInt(percent) + "%")
288
+ }
289
+
290
+ if (response.error) {
291
+ jQuery(".backup-encryption .status-body").show();
292
+ jQuery(".backup-encryption .status-body").addClass("error").prepend(response.message+" ")
293
+ jQuery(".backup-encryption .progress > div").addClass("determinate").removeClass("indeterminate").css('width', "100%")
294
+ return;
295
+ }
296
+
297
+ if (!response.finished /*&& !this.cancel*/) {
298
+
299
+ this.do_ajax(elem, action);
300
+ return false;
301
+ }
302
+
303
+ //finished
304
+ jQuery(elem).find('.progress > div').css('width', '100%');
305
+ jQuery(".backup-encryption .last-logged-file").text('done');
306
+
307
+ //this.do_backup_database();
308
+ this.do_backup_done()
309
+
310
+ }
311
+
312
+ do_backup_encryption() {
313
+ if (this.cancel)
314
+ return false;
315
+
316
+ var elem = "#generate_backup ul.backup-status li.backup-encryption";
317
+ jQuery(elem).show();
318
+ jQuery(elem + ' .status-body').show();
319
+ jQuery(elem).find('.collapsible-header').trigger('click');
320
+
321
+ jQuery(elem).find('.progress .determinate').css('width', '0%');
322
+
323
+ this.do_ajax(elem, 'backup_encryption', 1);
324
+ }
325
+
326
  do_backup_done() {
327
  var elem = "#generate_backup ul.backup-status li.backup-done";
328
  jQuery(elem).show();
admin/js/xcloner-manage-backups-class.js CHANGED
@@ -1,315 +1,437 @@
1
  /** global: ajaxurl */
2
  /** global: Materialize */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
 
4
- class Xcloner_Manage_Backups{
5
-
6
- constructor()
7
- {
8
- this.file_counter = 0
9
- this.storage_selection = "";
10
-
11
- //this.edit_modal = jQuery('.modal').modal();
12
- }
13
-
14
- download_backup_by_name(id)
15
- {
16
- window.open(ajaxurl+"?action=download_backup_by_name&name="+id);
17
- return false;
18
- }
19
-
20
- delete_backup_by_name(id, elem, dataTable)
21
- {
22
- var $this = this
23
-
24
- if(id){
25
- jQuery.ajax({
26
- url: ajaxurl,
27
- method: 'post',
28
- data: { action : 'delete_backup_by_name', name: id, storage_selection: this.storage_selection},
29
- success: function(response){
30
- if(response.finished)
31
- {
32
- dataTable
33
- .row( jQuery(elem).parents('tr') )
34
- .remove()
35
- .draw();
36
- }
37
- else{
38
- alert("There was an error deleting the file");
39
- }
40
- },
41
- dataType: 'json'
42
- });
43
- }
44
- }
45
-
46
- list_backup_content_callback(backup_file, start = 0, part= 0)
47
- {
48
- var $this = this;
49
-
50
- if(backup_file)
51
- {
52
- jQuery.ajax({
53
- url: ajaxurl,
54
- method: 'post',
55
- data: { action : 'list_backup_files', file: backup_file, start: start, part: part},
56
- success: function(response){
57
-
58
- if(response.error)
59
- {
60
- jQuery("#backup_cotent_modal .files-list").addClass("error").prepend(response.message)
61
- jQuery("#backup_cotent_modal .progress > div").addClass("determinate").removeClass(".indeterminate").css('width', "100%")
62
- return;
63
- }
64
-
65
- var files_text = [];
66
-
67
- for(var i in response.files)
68
- {
69
-
70
- if(response.total_size !== undefined)
71
- {
72
- var percent = parseInt(response.start*100)/parseInt(response.total_size)
73
- //jQuery("#backup_cotent_modal .progress .determinate").css('width', percent + "%")
74
- }
75
-
76
- $this.file_counter++
77
-
78
- files_text[i] = "<li>"+($this.file_counter +". <span title='"+response.files[i].mtime+"'>"+response.files[i].path+"</span> ("+response.files[i].size+" bytes)")+"</li>";
79
- }
80
-
81
- jQuery("#backup_cotent_modal .modal-content .files-list").prepend(files_text.reverse().join("\n"));
82
-
83
- if(!response.finished && jQuery('#backup_cotent_modal').is(':visible'))
84
- {
85
- $this.list_backup_content_callback(backup_file, response.start, response.part)
86
- }
87
- else
88
- {
89
- jQuery("#backup_cotent_modal .progress > div").addClass('determinate').removeClass(".indeterminate").css('width', "100%")
90
- }
91
-
92
- },
93
- error: function(xhr, textStatus, error){
94
- jQuery("#backup_cotent_modal .files-list").addClass("error").prepend(textStatus+error)
95
- },
96
- dataType: 'json'
97
- });
98
- }
99
-
100
- }
101
-
102
-
103
- list_backup_content(backup_file)
104
- {
105
- this.file_counter = 0
106
- jQuery("#backup_cotent_modal .modal-content .files-list").text("").removeClass("error");
107
- jQuery("#backup_cotent_modal .modal-content .backup-name").text(backup_file);
108
- jQuery("#backup_cotent_modal").modal('open');
109
- jQuery("#backup_cotent_modal .progress > div").removeClass('determinate').addClass("indeterminate");
110
-
111
- this.list_backup_content_callback(backup_file)
112
- }
113
-
114
- cloud_upload(backup_file)
115
- {
116
- jQuery('#remote_storage_modal').find(".backup_name").text(backup_file)
117
- jQuery('#remote_storage_modal').find("input.backup_name").val(backup_file)
118
- Materialize.updateTextFields();
119
- jQuery('.col select').material_select();
120
- jQuery("#remote_storage_modal").modal('open')
121
- jQuery("#remote_storage_modal .status").hide();
122
-
123
- jQuery(".remote-storage-form").off("submit").on("submit",function(){
124
- jQuery("#remote_storage_modal .status").show();
125
- jQuery("#remote_storage_modal .status .progress .indeterminate").removeClass("determinate").css("width", "0%");
126
- jQuery("#remote_storage_modal .status-text").removeClass("error").text("");
127
-
128
- var storage_type = jQuery("#remote_storage_modal select").val();
129
-
130
- if(backup_file)
131
- {
132
- jQuery.ajax({
133
- url: ajaxurl,
134
- method: 'post',
135
- data: { action : 'upload_backup_to_remote', file: backup_file, storage_type: storage_type},
136
- success: function(response){
137
- if(response.error)
138
- {
139
- jQuery("#remote_storage_modal .status-text").addClass("error").text(response.message)
140
- }else{
141
- jQuery("#remote_storage_modal .status-text").removeClass("error").text("done")
142
- }
143
-
144
- jQuery("#remote_storage_modal .status .progress .indeterminate").addClass("determinate").css("width", "100%");
145
- },
146
- error: function(xhr, textStatus, error){
147
- jQuery("#remote_storage_modal .status-text").addClass("error").text(textStatus+error)
148
- },
149
- dataType: 'json'
150
- });
151
- }
152
-
153
- return false;
154
- })
155
- }
156
-
157
- copy_remote_to_local(backup_file)
158
- {
159
- jQuery("#local_storage_upload_modal").modal('open');
160
- jQuery("#local_storage_upload_modal .modal-content .backup-name").text(backup_file);
161
- jQuery("#local_storage_upload_modal .status-text").removeClass("error").text("");
162
- jQuery("#local_storage_upload_modal .status .progress .indeterminate").removeClass("determinate").css("width", "0%");
163
-
164
- if(backup_file)
165
- {
166
- jQuery.ajax({
167
- url: ajaxurl,
168
- method: 'post',
169
- data: { action : 'copy_backup_remote_to_local', file: backup_file, storage_type: this.storage_selection},
170
- success: function(response){
171
- if(response.error)
172
- {
173
- jQuery("#local_storage_upload_modal .status-text").addClass("error").text(response.message)
174
- }else{
175
- jQuery("#local_storage_upload_modal .status-text").removeClass("error").text("done")
176
- }
177
-
178
- jQuery("#local_storage_upload_modal .status .progress .indeterminate").addClass("determinate").css("width", "100%");
179
- },
180
- error: function(xhr, textStatus, error){
181
- jQuery("#local_storage_upload_modal .status-text").addClass("error").text(textStatus+error)
182
- },
183
- dataType: 'json'
184
- });
185
- }
186
-
187
- }
188
-
189
- //end class
190
- }
191
-
192
- jQuery(document).ready(function(){
193
-
194
- var xcloner_manage_backups = new Xcloner_Manage_Backups();
195
-
196
- xcloner_manage_backups.storage_selection = getUrlParam('storage_selection');
197
-
198
- jQuery("a.expand-multipart").on("click", function(){
199
- jQuery(this).parent().find("ul.multipart").toggle();
200
- jQuery(this).parent().find("a.expand-multipart.remove").toggle();
201
- jQuery(this).parent().find("a.expand-multipart.add").toggle();
202
- })
203
- var dataTable = jQuery('#manage_backups').DataTable( {
204
- 'responsive': true,
205
- 'bFilter': true,
206
- "order": [[ 2, "desc" ]],
207
- buttons: [
208
- 'selectAll',
209
- 'selectNone'
210
- ],
211
- "language": {
212
- "emptyTable": "No backups available",
213
- buttons: {
214
- selectAll: "Select all items",
215
- selectNone: "Select none"
216
- }
217
- },
218
- columnDefs: [
219
- { targets: 'no-sort', orderable: false }
220
- ],
221
- "columns": [
222
- { "width": "1%" },
223
- { "width": "25%" },
224
- { "width": "5%" },
225
- { "width": "5%" },
226
- { "width": "5%" },
227
- ],
228
- "oLanguage": {
229
- "sSearch": "",
230
- "sSearchPlaceholder" : 'Search Backups',
231
- } ,
232
- //"ajax": ajaxurl+"?action=get_backup_list",
233
- "fnDrawCallback": function( oSettings ) {
234
-
235
- jQuery(this).off("click", ".delete").on("click", ".delete", function(e){
236
-
237
- var hash = jQuery(this).attr('href');
238
- var id = hash.substr(1)
239
- var data = "";
240
-
241
- if(show_delete_alert)
242
- {
243
- if(confirm('Are you sure you want to delete it?'))
244
- {
245
- xcloner_manage_backups.delete_backup_by_name(id, (this), dataTable);
246
- }
247
- }else{
248
- xcloner_manage_backups.delete_backup_by_name(id, (this), dataTable);
249
- }
250
-
251
-
252
- e.preventDefault();
253
- })
254
-
255
- jQuery(this).off("click", ".download").on("click", ".download", function(e){
256
- var hash = jQuery(this).attr('href');
257
- var id = hash.substr(1)
258
- xcloner_manage_backups.download_backup_by_name(id);
259
- e.preventDefault();
260
- })
261
-
262
- jQuery(this).off("click", ".cloud-upload").on("click", ".cloud-upload", function(e){
263
- var hash = jQuery(this).attr('href');
264
- var id = hash.substr(1)
265
- xcloner_manage_backups.cloud_upload(id);
266
- e.preventDefault();
267
- })
268
-
269
- jQuery(this).off("click", ".copy-remote-to-local").on("click", ".copy-remote-to-local", function(e){
270
- var hash = jQuery(this).attr('href');
271
- var id = hash.substr(1)
272
- xcloner_manage_backups.copy_remote_to_local(id);
273
- e.preventDefault();
274
- })
275
-
276
- jQuery(this).off("click", ".list-backup-content").on("click", ".list-backup-content", function(e){
277
- var hash = jQuery(this).attr('href');
278
- var id = hash.substr(1)
279
- xcloner_manage_backups.list_backup_content(id);
280
- e.preventDefault();
281
- })
282
- }
283
- });
284
-
285
- jQuery('#select_all').click(function () {
286
- jQuery('input:checkbox').prop('checked', this.checked);
287
- });
288
-
289
- jQuery(".delete-all").click(function(){
290
- if(confirm('Are you sure you want to delete selected items?'))
291
- {
292
- show_delete_alert = 0;
293
- jQuery('input:checkbox').each(function(){
294
- if(jQuery(this).is(":checked"))
295
- {
296
- jQuery(this).parent().parent().parent().find(".delete").trigger('click');
297
- }
298
- })
299
- show_delete_alert = 1;
300
- }
301
- })
302
-
303
- jQuery("#remote_storage_modal").modal();
304
- jQuery("#local_storage_upload_modal").modal();
305
-
306
- jQuery("#storage_selection").on("change", function(){
307
- console.log(jQuery(this).val());
308
- window.location = window.location.href.split('&storage_selection')[0]+"&storage_selection="+jQuery(this).val();
309
- })
310
-
311
-
312
- var show_delete_alert=1;
313
-
314
-
315
  });
1
  /** global: ajaxurl */
2
  /** global: Materialize */
3
+ var dataTable = "";
4
+
5
+ class Xcloner_Manage_Backups {
6
+
7
+ constructor() {
8
+ this.file_counter = 0
9
+ this.storage_selection = "";
10
+ this.dataTable = "";
11
+ //this.edit_modal = jQuery('.modal').modal();
12
+ }
13
+
14
+ download_backup_by_name(id) {
15
+ window.open(ajaxurl + "?action=download_backup_by_name&name=" + id);
16
+ return false;
17
+ }
18
+
19
+ delete_backup_by_name(id, elem, dataTable) {
20
+ var $this = this
21
+
22
+ if (id) {
23
+ jQuery.ajax({
24
+ url: ajaxurl,
25
+ method: 'post',
26
+ data: {action: 'delete_backup_by_name', name: id, storage_selection: this.storage_selection},
27
+ success: function (response) {
28
+ if (response.finished) {
29
+ dataTable
30
+ .row(jQuery(elem).parents('tr'))
31
+ .remove()
32
+ .draw();
33
+ } else {
34
+ alert("There was an error deleting the file");
35
+ }
36
+ },
37
+ dataType: 'json'
38
+ });
39
+ }
40
+ }
41
+
42
+ list_backup_content_callback(backup_file, start = 0, part = 0) {
43
+ var $this = this;
44
+
45
+ if (backup_file) {
46
+ jQuery.ajax({
47
+ url: ajaxurl,
48
+ method: 'post',
49
+ data: {action: 'list_backup_files', file: backup_file, start: start, part: part},
50
+ success: function (response) {
51
+
52
+ if (response.error) {
53
+ jQuery("#backup_cotent_modal .files-list").addClass("error").prepend(response.message)
54
+ jQuery("#backup_cotent_modal .progress > div").addClass("determinate").removeClass(".indeterminate").css('width', "100%")
55
+ return;
56
+ }
57
+
58
+ var files_text = [];
59
+
60
+ for (var i in response.files) {
61
+
62
+ if (response.total_size !== undefined) {
63
+ var percent = parseInt(response.start * 100) / parseInt(response.total_size)
64
+ //jQuery("#backup_cotent_modal .progress .determinate").css('width', percent + "%")
65
+ }
66
+
67
+ $this.file_counter++
68
+
69
+ files_text[i] = "<li>" + ($this.file_counter + ". <span title='" + response.files[i].mtime + "'>" + response.files[i].path + "</span> (" + response.files[i].size + " bytes)") + "</li>";
70
+ }
71
+
72
+ jQuery("#backup_cotent_modal .modal-content .files-list").prepend(files_text.reverse().join("\n"));
73
+
74
+ if (!response.finished && jQuery('#backup_cotent_modal').is(':visible')) {
75
+ $this.list_backup_content_callback(backup_file, response.start, response.part)
76
+ } else {
77
+ jQuery("#backup_cotent_modal .progress > div").addClass('determinate').removeClass(".indeterminate").css('width', "100%")
78
+ }
79
+
80
+ },
81
+ error: function (xhr, textStatus, error) {
82
+ jQuery("#backup_cotent_modal .files-list").addClass("error").prepend(textStatus + error)
83
+ },
84
+ dataType: 'json'
85
+ });
86
+ }
87
+
88
+ }
89
+
90
+
91
+ list_backup_content(backup_file) {
92
+ this.file_counter = 0
93
+ jQuery("#backup_cotent_modal .modal-content .files-list").text("").removeClass("error");
94
+ jQuery("#backup_cotent_modal .modal-content .backup-name").text(backup_file);
95
+ jQuery("#backup_cotent_modal").modal('open');
96
+ jQuery("#backup_cotent_modal .progress > div").removeClass('determinate').addClass("indeterminate");
97
+
98
+ this.list_backup_content_callback(backup_file)
99
+ }
100
+
101
+ backup_encryption_callback(backup_file, start = 0, part = 0, iv = 0) {
102
+ var $this = this;
103
+
104
+ if (backup_file) {
105
+ jQuery.ajax({
106
+ url: ajaxurl,
107
+ method: 'post',
108
+ data: {action: 'backup_encryption', file: backup_file, start: start, part: part, iv: iv},
109
+ success: function (response) {
110
+
111
+ if (response.total_size !== undefined) {
112
+ jQuery("#backup_encryption_modal .progress > div").removeClass('indeterminate').addClass("determinate");
113
+ var percent = parseInt(response.start * 100) / parseInt(response.total_size)
114
+ jQuery("#backup_encryption_modal .progress .determinate").css('width', parseInt(percent) + "%")
115
+ jQuery("#backup_encryption_modal .modal-content .files-list").text("Encrypting "+response.processing_file+" "+ parseInt(percent) + "%")
116
+ }
117
+
118
+ if (response.error) {
119
+ jQuery("#backup_encryption_modal .notice").show();
120
+ jQuery("#backup_encryption_modal .files-list").addClass("error").prepend(response.message+" ")
121
+ jQuery("#backup_encryption_modal .progress > div").addClass("determinate").removeClass("indeterminate").css('width', "100%")
122
+ return;
123
+ }
124
+
125
+
126
+ if (!response.finished && jQuery('#backup_encryption_modal').is(':visible')) {
127
+ $this.backup_encryption_callback(backup_file, response.start, response.part, response.iv)
128
+ } else {
129
+ jQuery("#backup_encryption_modal .progress > div").addClass('determinate').removeClass("indeterminate").css('width', "100%")
130
+ jQuery("#backup_encryption_modal .modal-content .files-list").text("Done Encrypting.")
131
+ dataTable.ajax.reload();
132
+ }
133
+
134
+ },
135
+ error: function (xhr, textStatus, error) {
136
+ jQuery("#backup_encryption_modal .files-list").addClass("error").prepend(textStatus + error)
137
+ },
138
+ dataType: 'json'
139
+ });
140
+ }
141
+
142
+ }
143
+
144
+
145
+ backup_encryption(backup_file, start = 0) {
146
+ this.file_counter = 0
147
+
148
+ jQuery("#backup_encryption_modal .modal-content .backup-name").text(backup_file);
149
+ jQuery("#backup_encryption_modal").modal('open');
150
+ jQuery("#backup_encryption_modal .progress > div");
151
+ jQuery("#backup_encryption_modal .notice").show();
152
+
153
+ jQuery("#backup_encryption_modal a.btn").attr('onclick', "var xcloner_manage_backups = new Xcloner_Manage_Backups();xcloner_manage_backups.backup_encryption('"+backup_file+"', true)");
154
+ jQuery("#backup_encryption_modal .modal-content .files-list").text("").removeClass("error");
155
+
156
+ if( start ) {
157
+ jQuery("#backup_encryption_modal .notice").hide();
158
+ this.backup_encryption_callback(backup_file)
159
+ }
160
+ }
161
+
162
+ backup_decryption_callback(backup_file, start = 0, part = 0, iv = 0) {
163
+ var $this = this;
164
+
165
+ var decryption_key = jQuery('#backup_decryption_modal #decryption_key').val();
166
+
167
+ if (backup_file) {
168
+ jQuery.ajax({
169
+ url: ajaxurl,
170
+ method: 'post',
171
+ data: {action: 'backup_decryption', file: backup_file, start: start, part: part, iv: iv, decryption_key: decryption_key},
172
+ success: function (response) {
173
+
174
+ if(!response.start){
175
+ response.start = 0;
176
+ }
177
+ if (response.total_size !== undefined) {
178
+ jQuery("#backup_decryption_modal .progress > div").removeClass('indeterminate').addClass("determinate");
179
+ var percent = parseInt(response.start * 100) / parseInt(response.total_size)
180
+ jQuery("#backup_decryption_modal .progress .determinate").css('width', parseInt(percent) + "%")
181
+ jQuery("#backup_decryption_modal .modal-content .files-list").text("Decrypting "+response.processing_file+" "+ parseInt(percent) + "%")
182
+ }
183
+
184
+ if (response.error) {
185
+ jQuery("#backup_decryption_modal .files-list").addClass("error").prepend(response.message+" ")
186
+ jQuery("#backup_decryption_modal .progress > div").addClass("determinate").removeClass("indeterminate").css('width', "100%")
187
+ jQuery("#backup_decryption_modal .notice").show();
188
+ return;
189
+ }
190
+
191
+
192
+ if (!response.finished && jQuery('#backup_decryption_modal').is(':visible')) {
193
+ $this.backup_decryption_callback(backup_file, response.start, response.part, response.iv)
194
+ } else {
195
+ jQuery("#backup_decryption_modal .progress > div").addClass('determinate').removeClass("indeterminate").css('width', "100%")
196
+ jQuery("#backup_decryption_modal .modal-content .files-list").text("Done Decrypting.")
197
+ dataTable.ajax.reload();
198
+ }
199
+
200
+ },
201
+ error: function (xhr, textStatus, error) {
202
+ jQuery("#backup_decryption_modal .files-list").addClass("error").prepend(textStatus + error)
203
+ },
204
+ dataType: 'json'
205
+ });
206
+ }
207
+
208
+ }
209
+
210
+ backup_decryption(backup_file, start = 0) {
211
+ this.file_counter = 0
212
+
213
+ jQuery("#backup_decryption_modal .modal-content .backup-name").text(backup_file);
214
+ jQuery("#backup_decryption_modal").modal('open');
215
+ jQuery("#backup_decryption_modal .progress > div");
216
+ jQuery("#backup_decryption_modal .notice").show();
217
+
218
+ jQuery("#backup_decryption_modal a.btn").attr('onclick', "var xcloner_manage_backups = new Xcloner_Manage_Backups();xcloner_manage_backups.backup_decryption('"+backup_file+"', true)");
219
+ jQuery("#backup_decryption_modal .modal-content .files-list").text("").removeClass("error");
220
+
221
+ if( start ) {
222
+ jQuery("#backup_decryption_modal .notice").hide();
223
+ this.backup_decryption_callback(backup_file)
224
+ }
225
+ }
226
+
227
+ cloud_upload(backup_file) {
228
+ jQuery('#remote_storage_modal').find(".backup_name").text(backup_file)
229
+ jQuery('#remote_storage_modal').find("input.backup_name").val(backup_file)
230
+ Materialize.updateTextFields();
231
+ jQuery('.col select').material_select();
232
+ jQuery("#remote_storage_modal").modal('open')
233
+ jQuery("#remote_storage_modal .status").hide();
234
+
235
+ jQuery(".remote-storage-form").off("submit").on("submit", function () {
236
+ jQuery("#remote_storage_modal .status").show();
237
+ jQuery("#remote_storage_modal .status .progress .indeterminate").removeClass("determinate").css("width", "0%");
238
+ jQuery("#remote_storage_modal .status-text").removeClass("error").text("");
239
+
240
+ var storage_type = jQuery("#remote_storage_modal select").val();
241
+
242
+ if (backup_file) {
243
+ jQuery.ajax({
244
+ url: ajaxurl,
245
+ method: 'post',
246
+ data: {action: 'upload_backup_to_remote', file: backup_file, storage_type: storage_type},
247
+ success: function (response) {
248
+ if (response.error) {
249
+ jQuery("#remote_storage_modal .status-text").addClass("error").text(response.message)
250
+ } else {
251
+ jQuery("#remote_storage_modal .status-text").removeClass("error").text("done")
252
+ }
253
+
254
+ jQuery("#remote_storage_modal .status .progress .indeterminate").addClass("determinate").css("width", "100%");
255
+ },
256
+ error: function (xhr, textStatus, error) {
257
+ jQuery("#remote_storage_modal .status-text").addClass("error").text(textStatus + error)
258
+ },
259
+ dataType: 'json'
260
+ });
261
+ }
262
+
263
+ return false;
264
+ })
265
+ }
266
+
267
+ copy_remote_to_local(backup_file) {
268
+ jQuery("#local_storage_upload_modal").modal('open');
269
+ jQuery("#local_storage_upload_modal .modal-content .backup-name").text(backup_file);
270
+ jQuery("#local_storage_upload_modal .status-text").removeClass("error").text("");
271
+ jQuery("#local_storage_upload_modal .status .progress .indeterminate").removeClass("determinate").css("width", "0%");
272
+
273
+ if (backup_file) {
274
+ jQuery.ajax({
275
+ url: ajaxurl,
276
+ method: 'post',
277
+ data: {action: 'copy_backup_remote_to_local', file: backup_file, storage_type: this.storage_selection},
278
+ success: function (response) {
279
+ if (response.error) {
280
+ jQuery("#local_storage_upload_modal .status-text").addClass("error").text(response.message)
281
+ } else {
282
+ jQuery("#local_storage_upload_modal .status-text").removeClass("error").text("done")
283
+ }
284
+
285
+ jQuery("#local_storage_upload_modal .status .progress .indeterminate").addClass("determinate").css("width", "100%");
286
+ },
287
+ error: function (xhr, textStatus, error) {
288
+ jQuery("#local_storage_upload_modal .status-text").addClass("error").text(textStatus + error)
289
+ },
290
+ dataType: 'json'
291
+ });
292
+ }
293
+
294
+ }
295
+
296
+ //end class
297
+ }
298
+
299
+ jQuery(document).ready(function () {
300
+
301
+ var xcloner_manage_backups = new Xcloner_Manage_Backups();
302
+
303
+ xcloner_manage_backups.storage_selection = getUrlParam('storage_selection');
304
+
305
+ dataTable = jQuery('#manage_backups').DataTable({
306
+ 'responsive': true,
307
+ 'bFilter': true,
308
+ "order": [[2, "desc"]],
309
+ buttons: [
310
+ 'selectAll',
311
+ 'selectNone'
312
+ ],
313
+ "language": {
314
+ "emptyTable": "No backups available",
315
+ buttons: {
316
+ selectAll: "Select all items",
317
+ selectNone: "Select none"
318
+ }
319
+ },
320
+ columnDefs: [
321
+ {targets: 'no-sort', orderable: false}
322
+ ],
323
+ "columns": [
324
+ {"width": "1%"},
325
+ {"width": "25%"},
326
+ {"width": "5%"},
327
+ {"width": "5%"},
328
+ {"width": "9%"},
329
+ ],
330
+ "oLanguage": {
331
+ "sSearch": "",
332
+ "sSearchPlaceholder": 'Search Backups',
333
+ },
334
+ "ajax": ajaxurl+"?action=get_manage_backups_list&storage_selection="+xcloner_manage_backups.storage_selection,
335
+ "fnDrawCallback": function (oSettings) {
336
+
337
+ jQuery("a.expand-multipart").on("click", function () {
338
+ jQuery(this).parent().find("ul.multipart").toggle();
339
+ jQuery(this).parent().find("a.expand-multipart.remove").toggle();
340
+ jQuery(this).parent().find("a.expand-multipart.add").toggle();
341
+ })
342
+
343
+ jQuery(this).off("click", ".delete").on("click", ".delete", function (e) {
344
+
345
+ var hash = jQuery(this).attr('href');
346
+ var id = hash.substr(1)
347
+ var data = "";
348
+
349
+ if (show_delete_alert) {
350
+ if (confirm('Are you sure you want to delete it?')) {
351
+ xcloner_manage_backups.delete_backup_by_name(id, (this), dataTable);
352
+ }
353
+ } else {
354
+ xcloner_manage_backups.delete_backup_by_name(id, (this), dataTable);
355
+ }
356
+
357
+
358
+ e.preventDefault();
359
+ })
360
+
361
+ jQuery(this).off("click", ".download").on("click", ".download", function (e) {
362
+ var hash = jQuery(this).attr('href');
363
+ var id = hash.substr(1)
364
+ xcloner_manage_backups.download_backup_by_name(id);
365
+ e.preventDefault();
366
+ })
367
+
368
+ jQuery(this).off("click", ".cloud-upload").on("click", ".cloud-upload", function (e) {
369
+ var hash = jQuery(this).attr('href');
370
+ var id = hash.substr(1)
371
+ xcloner_manage_backups.cloud_upload(id);
372
+ e.preventDefault();
373
+ })
374
+
375
+ jQuery(this).off("click", ".copy-remote-to-local").on("click", ".copy-remote-to-local", function (e) {
376
+ var hash = jQuery(this).attr('href');
377
+ var id = hash.substr(1)
378
+ xcloner_manage_backups.copy_remote_to_local(id);
379
+ e.preventDefault();
380
+ })
381
+
382
+ jQuery(this).off("click", ".list-backup-content").on("click", ".list-backup-content", function (e) {
383
+ var hash = jQuery(this).attr('href');
384
+ var id = hash.substr(1)
385
+ xcloner_manage_backups.list_backup_content(id);
386
+ e.preventDefault();
387
+ })
388
+
389
+ jQuery(this).off("click", ".backup-encryption").on("click", ".backup-encryption", function (e) {
390
+ var hash = jQuery(this).attr('href');
391
+ var id = hash.substr(1)
392
+ xcloner_manage_backups.backup_encryption(id);
393
+ e.preventDefault();
394
+ })
395
+
396
+ jQuery(this).off("click", ".backup-decryption").on("click", ".backup-decryption", function (e) {
397
+ var hash = jQuery(this).attr('href');
398
+ var id = hash.substr(1)
399
+ xcloner_manage_backups.backup_decryption(id);
400
+ e.preventDefault();
401
+ })
402
+
403
+ }
404
+ });
405
+
406
+ jQuery('#select_all').click(function () {
407
+ jQuery('input:checkbox').prop('checked', this.checked);
408
+ });
409
+
410
+ jQuery(".delete-all").click(function () {
411
+ if (confirm('Are you sure you want to delete selected items?')) {
412
+ show_delete_alert = 0;
413
+ jQuery('input:checkbox').each(function () {
414
+ if (jQuery(this).is(":checked")) {
415
+ jQuery(this).parent().parent().parent().find(".delete").trigger('click');
416
+ }
417
+ })
418
+ show_delete_alert = 1;
419
+ }
420
+ })
421
+
422
+ jQuery("#remote_storage_modal").modal();
423
+ jQuery("#local_storage_upload_modal").modal();
424
+
425
+ jQuery("#storage_selection").on("change", function () {
426
+ window.location = window.location.href.split('&storage_selection')[0] + "&storage_selection=" + jQuery(this).val();
427
+ })
428
+
429
+ jQuery('.modal').on('hide',function(){
430
+ alert('ok')
431
+ })
432
+
433
+
434
+ var show_delete_alert = 1;
435
+
436
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
437
  });
admin/js/xcloner-scheduler-class.js CHANGED
@@ -45,7 +45,9 @@ jQuery(document).ready(function(){
45
  data: { action : 'delete_schedule_by_id', id: id},
46
  success: function(response){
47
  //window.location = "";
 
48
  //alert("Schedule deleted");
 
49
  dataTable
50
  .row( jQuery(elem).parents('tr') )
51
  .remove()
@@ -80,6 +82,11 @@ jQuery(document).ready(function(){
80
  this.edit_modal.find('#schedule_storage>option[value="' + response.remote_storage + '"]').prop('selected', true);
81
  //var date = new Date(response.start_at);
82
  this.edit_modal.find("#schedule_start_date").val(response.start_at)
 
 
 
 
 
83
 
84
  var tables = jQuery.parseJSON(response.table_params)
85
 
45
  data: { action : 'delete_schedule_by_id', id: id},
46
  success: function(response){
47
  //window.location = "";
48
+ //console.log('schedule deleted');
49
  //alert("Schedule deleted");
50
+ jQuery(elem).parents('tr').remove();
51
  dataTable
52
  .row( jQuery(elem).parents('tr') )
53
  .remove()
82
  this.edit_modal.find('#schedule_storage>option[value="' + response.remote_storage + '"]').prop('selected', true);
83
  //var date = new Date(response.start_at);
84
  this.edit_modal.find("#schedule_start_date").val(response.start_at)
85
+
86
+
87
+ if(response.backup_params.backup_encrypt !== undefined && response.backup_params.backup_encrypt == 1) {
88
+ this.edit_modal.find('#backup_encrypt').attr('checked', 'checked')
89
+ }
90
 
91
  var tables = jQuery.parseJSON(response.table_params)
92
 
admin/partials/xcloner_console_page.php CHANGED
@@ -7,17 +7,17 @@ $logger_content = $logger->getLastDebugLines();
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>
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>
admin/partials/xcloner_generate_backups_page.php CHANGED
@@ -8,25 +8,25 @@ $tab = 1;
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
 
@@ -39,11 +39,11 @@ $tab = 1;
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>
@@ -52,12 +52,12 @@ $tab = 1;
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>
@@ -67,24 +67,48 @@ $tab = 1;
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>
@@ -97,11 +121,11 @@ $tab = 1;
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
 
@@ -123,10 +147,10 @@ $tab = 1;
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
 
@@ -161,9 +185,9 @@ $tab = 1;
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>
@@ -175,12 +199,12 @@ $tab = 1;
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>
@@ -204,9 +228,9 @@ $tab = 1;
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>
@@ -219,7 +243,7 @@ $tab = 1;
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>
@@ -227,21 +251,36 @@ $tab = 1;
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
 
@@ -252,8 +291,8 @@ $tab = 1;
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>
@@ -274,9 +313,9 @@ $tab = 1;
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>
@@ -284,18 +323,18 @@ $tab = 1;
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
 
@@ -303,17 +342,17 @@ $tab = 1;
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>
@@ -322,38 +361,38 @@ $tab = 1;
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>
@@ -368,19 +407,19 @@ $tab = 1;
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">
@@ -395,18 +434,18 @@ $tab = 1;
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>
@@ -418,7 +457,7 @@ $tab = 1;
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>
@@ -502,7 +541,7 @@ $tab = 1;
502
  }
503
  });
504
 
505
- <?php if($xcloner_settings->get_enable_mysql_backup()):?>
506
  jQuery('#jstree_database_container').jstree({
507
  'core': {
508
  'check_callback': true,
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
 
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>
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>
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 s6 m5 l4">
81
+ <i class="material-icons prefix">enhanced_encryption</i>
82
+ <label for="backup_comments"><?php echo __('Encrypt Backup', 'xcloner-backup-and-restore') ?></label>
83
+
84
+ </div>
85
+ <div class="input-field col s6 m5 l2">
86
+ <div class="switch">
87
+ <label>
88
+ Off
89
+ <input type="checkbox" name="backup_encrypt" id="backup_encrypt" value="1">
90
+ <span class="lever"></span>
91
+ On
92
+ </label>
93
+ </div>
94
+ </div>
95
+
96
+ <div class="hide-on-small-only s12 m2">
97
+ <a class="btn-floating tooltipped btn-small" data-position="right" data-delay="50"
98
+ data-tooltip="<?php echo __('Enable this option if you want to encrypt the final backup', 'xcloner-backup-and-restore') ?>"
99
+ data-tooltip-id=""><i class="material-icons">help_outline</i></a>
100
+ </div>
101
+ </div>
102
+
103
  <div class="row">
104
  <div class="input-field col s12 m10 l6">
105
  <i class="material-icons prefix">input</i>
106
  <textarea name="backup_comments" id="backup_comments" class="materialize-textarea"></textarea>
107
+ <label for="backup_comments"><?php echo __('Backup Comments', 'xcloner-backup-and-restore') ?></label>
108
  </div>
109
  <div class="hide-on-small-only m2">
110
  <a class="btn-floating tooltipped btn-small" data-position="right" data-delay="50"
111
+ data-tooltip="<?php echo __('Some default backup comments that will be stored inside the backup archive', 'xcloner-backup-and-restore') ?>"
112
  data-tooltip-id=""><i class="material-icons">help_outline</i></a>
113
  </div>
114
  </div>
121
  </div>
122
  </div>
123
 
124
+ <?php if ($xcloner_settings->get_enable_mysql_backup()): ?>
125
  <div id="database_options" class="tab-content">
126
+ <h2><?php echo __('Select database data to include in the backup', 'xcloner-backup-and-restore') ?>:
127
  <a class="btn-floating tooltipped btn-small" data-position="right" data-delay="50"
128
+ 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'); ?>"
129
  data-tooltip-id=""><i class="material-icons">help_outline</i></a>
130
  </h2>
131
 
147
  <?php endif ?>
148
 
149
  <div id="files_options" class="tab-content">
150
+ <h2><?php echo __('Select from below the files/folders you want to exclude from your Backup Archive', 'xcloner-backup-and-restore') ?>
151
  :
152
  <a class="btn-floating tooltipped btn-small" data-position="bottom" data-delay="50" data-html="true"
153
+ 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'); ?>"
154
  data-tooltip-id=""><i class="material-icons">help_outline</i></a>
155
  </h2>
156
 
185
  <ul class="backup-status collapsible" data-collapsible="accordion">
186
  <li class="file-system">
187
  <div class="collapsible-header">
188
+ <i class="material-icons">folder</i><?php echo __('Scanning The File System...', 'xcloner-backup-and-restore') ?>
189
 
190
+ <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>
191
 
192
  <div>
193
  <p class="right"><span class="last-logged-file"></span></p>
199
  </div>
200
  <div class="collapsible-body status-body"></div>
201
  </li>
202
+ <?php if ($xcloner_settings->get_enable_mysql_backup()): ?>
203
  <li class="database-backup">
204
  <div class="collapsible-header">
205
+ <i class="material-icons">storage</i><?php echo __('Generating the Mysql Backup...', 'xcloner-backup-and-restore') ?>
206
 
207
+ <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>
208
 
209
  <div>
210
  <p class="right"><span class="last-logged-table"></span></p>
228
  <?php endif ?>
229
  <li class="files-backup">
230
  <div class="collapsible-header">
231
+ <i class="material-icons">archive</i><?php echo __('Adding Files to Archive...', 'xcloner-backup-and-restore') ?>
232
 
233
+ <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>
234
 
235
  <div>
236
  <p class="right"><span class="last-logged-file"></span></p>
243
  <div class="collapsible-body status-body">
244
  <div class="row">
245
  <div class="col l3 s12">
246
+ <h2><?php echo __("Backup Parts", 'xcloner-backup-and-restore') ?>: </h2>
247
  </div>
248
  <div class="col l9 s12">
249
  <ul class="backup-name"></ul>
251
  </div>
252
  </div>
253
  </li>
254
+ <li class="backup-encryption">
255
+ <div class="collapsible-header">
256
+ <i class="material-icons">enhanced_encryption</i><?php echo __('Encrypting Backup Data...', 'xcloner-backup-and-restore') ?>
257
+
258
+ <p class="right"><span class="status"></span></p>
259
+
260
+ <div>
261
+ <p class="right"><span class="last-logged-file"></span></p>
262
+ </div>
263
+
264
+ <div class="progress">
265
+ <div class="determinate" style="width:0%"></div>
266
+ </div>
267
+ </div>
268
+ </li>
269
  <li class="backup-done">
270
  <div class="collapsible-header">
271
+ <i class="material-icons">done</i><?php echo __('Backup Done', 'xcloner-backup-and-restore') ?>
272
 
273
  <p class="right">
274
+ <?php if (sizeof($available_storages)): ?>
275
  <a href="#" class="cloud-upload"
276
+ title="<?php echo __("Send Backup To Remote Storage", 'xcloner-backup-and-restore') ?>"><i
277
  class="material-icons">cloud_upload</i></a>
278
  <?php endif ?>
279
  <a href="#" class="download"
280
+ title="<?php echo __("Download Backup", 'xcloner-backup-and-restore') ?>"><i
281
  class="material-icons">file_download</i></a>
282
  <a href="#" class="list-backup-content"
283
+ title="<?php echo __("List Backup Content", 'xcloner-backup-and-restore') ?>"><i
284
  class="material-icons">folder_open</i></a>
285
  </p>
286
 
291
  </div>
292
  <div class="collapsible-body center-align">
293
  <div class="row">
294
+ <h5><?php echo __("Thank you for using XCloner.", 'xcloner-backup-and-restore') ?></h5>
295
+ <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>
296
  <a class="twitter-follow-button" href="https://twitter.com/thinkovi"
297
  data-show-count="false">Follow @thinkovi</a>
298
  <script src="//platform.twitter.com/widgets.js" async="" charset="utf-8"></script>
313
 
314
  <div class="row">
315
  <div id="schedule_backup_success" class="col s12 l6 updated settings-error notice is-dismissible">
316
+ <p><strong><?php echo __('Schedule Saved', 'xcloner-backup-and-restore') ?></strong></p>
317
  <button type="button" class="notice-dismiss"><span
318
+ class="screen-reader-text"><?php echo __('(Dismiss this notice.', 'xcloner-backup-and-restore') ?></span>
319
  </button>
320
  </div>
321
  </div>
323
  <div class="row">
324
  <div class="input-field inline col s12 l7">
325
  <input type="text" id="schedule_name" class="" name="schedule_name" required>
326
+ <label for="schedule_name"><?php echo __('Schedule Name', 'xcloner-backup-and-restore') ?></label>
327
  </div>
328
  </div>
329
 
330
  <div class="row">
331
  <div class="input-field inline col s12 m8 l4">
332
  <input type="datetime-local" id="datepicker" class="datepicker" name="schedule_start_date">
333
+ <label for="datepicker"><?php echo __('Schedule Backup To Start On:', 'xcloner-backup-and-restore') ?></label>
334
  </div>
335
  <div class="input-field inline col s12 m4 l3">
336
  <input id="timepicker_ampm_dark" class="timepicker" type="time" name="schedule_start_time">
337
+ <label for="timepicker_ampm_dark"><?php echo __('At:', 'xcloner-backup-and-restore') ?></label>
338
  </div>
339
  </div>
340
 
342
  <div class="row">
343
  <div class="input-field inline col s10 m11 l7">
344
  <select id="backup_type" class="" name="backup_type">
345
+ <option value=""><?php echo __("Full Backup", "xcloner-backup-and-restore"); ?></option>
346
+ <option value="diff"><?php echo __("Differential Backups", "xcloner-backup-and-restore"); ?></option>
347
+ <option value="full_diff"><?php echo __("Full Backup + Differential Backups", "xcloner-backup-and-restore"); ?></option>
348
  </select>
349
+ <label for="backup_type"><?php echo __('Scheduled Backup Type', 'xcloner-backup-and-restore') ?></label>
350
  </div>
351
  <div class="col s2 m1">
352
  <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;'>
353
+ <li><?php echo __("Full Backup = it will generate a full backup of all included files each time schedule runs", "xcloner-backup-and-restore"); ?></li>
354
+ <li><?php echo __("Differentials Backups = backups will include only changed files since the schedule started to run", "xcloner-backup-and-restore"); ?></li>
355
+ <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>
356
  </ul>"><i class="material-icons">help_outline</i></a>
357
  </div>
358
  </div>
361
  <div class="input-field col s12 l7">
362
  <select name="schedule_frequency" id="schedule_frequency" class="validate" required>
363
  <option value="" disabled
364
+ selected><?php echo __('please select', 'xcloner-backup-and-restore') ?></option>
365
  <?php
366
  $schedules = $xcloner_scheduler->get_available_intervals();
367
 
368
+ foreach ($schedules as $key => $schedule) {
369
  ?>
370
  <option value="<?php echo $key ?>"><?php echo $schedule['display'] ?></option>
371
  <?php
372
  }
373
  ?>
374
  </select>
375
+ <label><?php echo __('Schedule Frequency', 'xcloner-backup-and-restore') ?></label>
376
  </div>
377
  </div>
378
 
379
+ <?php if (sizeof($available_storages)): ?>
380
  <div class="row">
381
  <div class="input-field col s12 m12 l7">
382
  <select name="schedule_storage" id="schedule_storage" class="validate">
383
+ <option value="" selected><?php echo __('none', 'xcloner-backup-and-restore') ?></option>
384
+ <?php foreach ($available_storages as $storage => $text): ?>
385
  <option value="<?php echo $storage ?>"><?php echo $text ?></option>
386
  <?php endforeach ?>
387
  </select>
388
+ <label><?php echo __('Send To Remote Storage', 'xcloner-backup-and-restore') ?></label>
389
  </div>
390
  </div>
391
  <?php endif ?>
392
  <div class="row">
393
  <div class="col s12 l7">
394
  <button class="right btn waves-effect waves-light submit_schedule" type="submit"
395
+ name="action"><?php echo __("Submit", 'xcloner-backup-and-restore') ?>
396
  <i class="material-icons right">send</i>
397
  </button>
398
  </div>
407
  class="material-icons medium right">help</i></a>
408
  <div class="modal-content">
409
  <h4 class="title_line"><span class="title"></span></h4>
410
+ <!--<h5 class="title_line"><?php echo __('Message') ?>: <span class="msg.old"></span></h5>-->
411
+ <h5><?php echo __('Response Code', 'xcloner-backup-and-restore') ?>: <span class="status"></span></h5>
412
  <textarea class="body" rows="5"></textarea>
413
  </div>
414
  <div class="modal-footer">
415
+ <a class=" modal-action modal-close waves-effect waves-green btn-flat red darken-2"><?php echo __('Close', 'xcloner-backup-and-restore') ?></a>
416
  </div>
417
  </div>
418
 
419
  <!-- List Backup Content Modal-->
420
  <div id="backup_cotent_modal" class="modal">
421
  <div class="modal-content">
422
+ <h4><?php echo sprintf(__("Listing Backup Content ", 'xcloner-backup-and-restore'), "") ?></h4>
423
  <h5 class="backup-name"></h5>
424
 
425
  <div class="progress">
434
  <form method="POST" class="remote-storage-form">
435
  <input type="hidden" name="file" class="backup_name">
436
  <div class="modal-content">
437
+ <h4><?php echo __("Remote Storage Transfer", 'xcloner-backup-and-restore') ?></h4>
438
  <p>
439
+ <?php if (sizeof($available_storages)): ?>
440
  <div class="row">
441
  <div class="col s12 label">
442
+ <label><?php echo __(sprintf('Send %s to remote storage', "<span class='backup_name'></span>"), 'xcloner-backup-and-restore') ?></label>
443
  </div>
444
  <div class="input-field col s8 m10">
445
  <select name="transfer_storage" id="transfer_storage" class="validate" required>
446
  <option value=""
447
+ selected><?php echo __('please select...', 'xcloner-backup-and-restore') ?></option>
448
+ <?php foreach ($available_storages as $storage => $text): ?>
449
  <option value="<?php echo $storage ?>"><?php echo $text ?></option>
450
  <?php endforeach ?>
451
  </select>
457
  </div>
458
  </div>
459
  <div class="row status">
460
+ <?php echo __("Uploading backup to the selected remote storage...", 'xcloner-backup-and-restore') ?>
461
  <span class="status-text"></span>
462
  <div class="progress">
463
  <div class="indeterminate"></div>
541
  }
542
  });
543
 
544
+ <?php if ($xcloner_settings->get_enable_mysql_backup()):?>
545
  jQuery('#jstree_database_container').jstree({
546
  'core': {
547
  'check_callback': true,
admin/partials/xcloner_init_page.php CHANGED
@@ -20,12 +20,12 @@ $xcloner_scheduler = $this->get_xcloner_container()->get_xcloner_scheduler();
20
 
21
  $logger_content = $logger->getLastDebugLines();
22
 
23
- $date_format = get_option( 'date_format' );
24
- $time_format = get_option( 'time_format' );
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
  }
@@ -34,15 +34,15 @@ if ( $requirements->check_backup_ready_status() ) {
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>
@@ -50,10 +50,10 @@ if ( $requirements->check_backup_ready_status() ) {
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>
@@ -61,10 +61,10 @@ if ( $requirements->check_backup_ready_status() ) {
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>
@@ -87,74 +87,74 @@ if ( $requirements->check_backup_ready_status() ) {
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>
@@ -163,20 +163,20 @@ if ( $requirements->check_backup_ready_status() ) {
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>
@@ -201,71 +201,71 @@ if ( $requirements->check_backup_ready_status() ) {
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>
20
 
21
  $logger_content = $logger->getLastDebugLines();
22
 
23
+ $date_format = get_option('date_format');
24
+ $time_format = get_option('time_format');
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
  }
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>
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>
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>
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 (isset($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>
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>
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>
admin/partials/xcloner_manage_backups_page.php CHANGED
@@ -3,19 +3,23 @@
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);
13
 
14
  $available_storages = $xcloner_remote_storage->get_available_storages();
15
 
16
-
17
  ?>
18
 
 
 
 
 
19
  <div class="row">
20
  <div class="col s12 m6 l9">
21
  <h1><?= esc_html(get_admin_page_title()); ?></h1>
@@ -34,13 +38,13 @@ $available_storages = $xcloner_remote_storage->get_available_storages();
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">
@@ -61,7 +65,7 @@ $available_storages = $xcloner_remote_storage->get_available_storages();
61
 
62
 
63
  <?php
64
- $i = 0;
65
  foreach ($backup_list as $file_info):?>
66
  <?php
67
  if ($storage_selection == "gdrive") {
@@ -125,6 +129,19 @@ $available_storages = $xcloner_remote_storage->get_available_storages();
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',
@@ -156,9 +173,22 @@ $available_storages = $xcloner_remote_storage->get_available_storages();
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
@@ -170,7 +200,7 @@ $available_storages = $xcloner_remote_storage->get_available_storages();
170
  </tr>
171
 
172
  <?php endif ?>
173
- <?php endforeach ?>
174
 
175
  </tbody>
176
  </table>
@@ -191,6 +221,58 @@ $available_storages = $xcloner_remote_storage->get_available_storages();
191
  </div>
192
  </div>
193
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
194
  <!-- Local Transfer Modal-->
195
  <div id="local_storage_upload_modal" class="modal">
196
  <div class="modal-content">
@@ -220,7 +302,7 @@ $available_storages = $xcloner_remote_storage->get_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>
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
+ $xcloner_encryption = $this->get_xcloner_container()->get_xcloner_encryption();
7
  $storage_selection = "";
8
 
9
  if (isset($_GET['storage_selection']) and $_GET['storage_selection']) {
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);
14
 
15
  $available_storages = $xcloner_remote_storage->get_available_storages();
16
 
 
17
  ?>
18
 
19
+ <script>
20
+ var storage_selection = '<?=$storage_selection?>';
21
+ </script>
22
+
23
  <div class="row">
24
  <div class="col s12 m6 l9">
25
  <h1><?= esc_html(get_admin_page_title()); ?></h1>
38
 
39
  <?php foreach ($available_storages as $storage => $text): ?>
40
  <option value="<?php echo $storage ?>"<?php if ($storage == $storage_selection)
41
+ echo "selected" ?>><?php echo $text ?></option>
42
  <?php endforeach ?>
43
  </select>
44
  <?php endif ?>
45
  </div>
46
 
47
+ <table id="manage_backups" style="width:100%">
48
  <thead>
49
  <tr class="grey lighten-2">
50
  <th class="no-sort">
65
 
66
 
67
  <?php
68
+ /*$i = 0;
69
  foreach ($backup_list as $file_info):?>
70
  <?php
71
  if ($storage_selection == "gdrive") {
129
  title="<?php echo __('List Backup Content',
130
  'xcloner-backup-and-restore') ?>"><i
131
  class="material-icons">folder_open</i></a>
132
+
133
+ <?php if($xcloner_encryption->is_encrypted_file($child[0])) :?>
134
+ <a href="#<?php echo $child[0] ?>" class="backup-decryption"
135
+ title="<?php echo __('Backup Decryption', 'xcloner-backup-and-restore') ?>">
136
+ <i class="material-icons">enhanced_encryption</i>
137
+ </a>
138
+ <?php else: ?>
139
+ <a href="#<?php echo $child[0] ?>" class="backup-encryption"
140
+ title="<?php echo __('Backup Encryption', 'xcloner-backup-and-restore') ?>">
141
+ <i class="material-icons">no_encryption</i>
142
+ </a>
143
+ <?php endif?>
144
+
145
  <?php elseif ($storage_selection != "gdrive" && !$xcloner_file_system->get_storage_filesystem()->has($child[0])): ?>
146
  <a href="#<?php echo $child[0] ?>" class="copy-remote-to-local"
147
  title="<?php echo __('Push Backup To Local Storage',
173
  class="material-icons">folder_open</i></a>
174
  <?php endif; ?>
175
 
176
+ <?php if($xcloner_encryption->is_encrypted_file($file_info['basename'])) :?>
177
+ <a href="#<?php echo $file_info['basename'] ?>" class="backup-decryption"
178
+ title="<?php echo __('Backup Decryption', 'xcloner-backup-and-restore') ?>">
179
+ <i class="material-icons">enhanced_encryption</i>
180
+ </a>
181
+ <?php else: ?>
182
+ <a href="#<?php echo $file_info['basename'] ?>" class="backup-encryption"
183
+ title="<?php echo __('Backup Encryption', 'xcloner-backup-and-restore') ?>">
184
+ <i class="material-icons">no_encryption</i>
185
+ </a>
186
+ <?php endif?>
187
+
188
  <a href="#<?php echo $file_info['basename'] ?>" class="delete"
189
+ title="<?php echo __('Delete Backup', 'xcloner-backup-and-restore') ?>">
190
+ <i class="material-icons">delete</i>
191
+ </a>
192
  <?php if ($storage_selection and !$file_exists_on_local_storage): ?>
193
  <a href="#<?php echo $file_info['basename']; ?>" class="copy-remote-to-local"
194
  title="<?php echo __('Push Backup To Local Storage', 'xcloner-backup-and-restore') ?>"><i
200
  </tr>
201
 
202
  <?php endif ?>
203
+ <?php endforeach */?>
204
 
205
  </tbody>
206
  </table>
221
  </div>
222
  </div>
223
 
224
+ <!-- Backup Encryption Modal-->
225
+ <div id="backup_encryption_modal" class="modal">
226
+ <div class="modal-content">
227
+ <h4><?php echo sprintf(__("Backup Content Encryption", 'xcloner-backup-and-restore'), "") ?></h4>
228
+ <h5 class="backup-name"></h5>
229
+
230
+ <div class="progress">
231
+ <div class="determinate"></div>
232
+ </div>
233
+ <div class="notice">
234
+ <p>
235
+ <?php echo __("This option will encrypt your backup archive with your current XCloner Encryption Key.", 'xcloner-backup-and-restore') ?>
236
+ </p>
237
+ <p class="center-align">
238
+ <a class="waves-effect waves-light btn"><?php echo __("START ENCRYPTION", 'xcloner-backup-and-restore') ?></a>
239
+ </p>
240
+ </div>
241
+ <ul class="files-list">
242
+ </ul>
243
+ </div>
244
+ </div>
245
+
246
+ <!-- Backup Decryption Modal-->
247
+ <div id="backup_decryption_modal" class="modal">
248
+ <div class="modal-content">
249
+ <h4><?php echo sprintf(__("Backup Content Decryption", 'xcloner-backup-and-restore'), "") ?></h4>
250
+ <h5 class="backup-name"></h5>
251
+
252
+ <div class="progress">
253
+ <div class="determinate"></div>
254
+ </div>
255
+ <div class="notice">
256
+ <p>
257
+ <?php echo __("This option will decrypt your backup archive with your current XCloner Encryption Key or the key provided below, requires PHP openssl library installed.", 'xcloner-backup-and-restore') ?>
258
+ </p>
259
+ <p>
260
+ <?=__('Provide Alternative Decryption Key:')?>
261
+ <input type="text"
262
+ name="decryption_key"
263
+ id="decryption_key"
264
+ placeholder="<?=__('Decryption Key', 'xcloner-backup-and-restore')?>" />
265
+ </p>
266
+ <p class="center-align">
267
+ <a class="waves-effect waves-light btn"><?php echo __("START DECRYPTION", 'xcloner-backup-and-restore') ?></a>
268
+ </p>
269
+ </div>
270
+ <ul class="files-list">
271
+
272
+ </ul>
273
+ </div>
274
+ </div>
275
+
276
  <!-- Local Transfer Modal-->
277
  <div id="local_storage_upload_modal" class="modal">
278
  <div class="modal-content">
302
  <div class="row">
303
  <div class="col s12 label">
304
  <label><?php echo sprintf(__('Send %s to remote storage', 'xcloner-backup-and-restore'),
305
+ "<span class='backup_name'></span>") ?></label>
306
  </div>
307
  <div class="input-field col s8 m10">
308
  <select name="transfer_storage" id="transfer_storage" class="validate" required>
admin/partials/xcloner_remote_storage_page.php CHANGED
@@ -3,13 +3,13 @@ $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
 
@@ -21,12 +21,12 @@ $gdrive_construct = $remote_storage->gdrive_construct();
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
@@ -36,121 +36,121 @@ $gdrive_construct = $remote_storage->gdrive_construct();
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>
@@ -161,12 +161,12 @@ $gdrive_construct = $remote_storage->gdrive_construct();
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
@@ -176,100 +176,100 @@ $gdrive_construct = $remote_storage->gdrive_construct();
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>
@@ -281,12 +281,12 @@ $gdrive_construct = $remote_storage->gdrive_construct();
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
@@ -301,49 +301,49 @@ $gdrive_construct = $remote_storage->gdrive_construct();
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
  }
@@ -354,59 +354,59 @@ $gdrive_construct = $remote_storage->gdrive_construct();
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>
@@ -418,12 +418,12 @@ $gdrive_construct = $remote_storage->gdrive_construct();
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
@@ -438,20 +438,20 @@ $gdrive_construct = $remote_storage->gdrive_construct();
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>
@@ -459,50 +459,50 @@ $gdrive_construct = $remote_storage->gdrive_construct();
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>
@@ -514,12 +514,12 @@ $gdrive_construct = $remote_storage->gdrive_construct();
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
@@ -534,19 +534,19 @@ $gdrive_construct = $remote_storage->gdrive_construct();
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>
@@ -554,49 +554,49 @@ $gdrive_construct = $remote_storage->gdrive_construct();
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>
@@ -608,12 +608,12 @@ $gdrive_construct = $remote_storage->gdrive_construct();
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
@@ -628,20 +628,20 @@ $gdrive_construct = $remote_storage->gdrive_construct();
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>
@@ -649,53 +649,53 @@ $gdrive_construct = $remote_storage->gdrive_construct();
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>
@@ -707,12 +707,12 @@ $gdrive_construct = $remote_storage->gdrive_construct();
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
@@ -734,74 +734,74 @@ $gdrive_construct = $remote_storage->gdrive_construct();
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>
@@ -813,13 +813,13 @@ $gdrive_construct = $remote_storage->gdrive_construct();
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
@@ -829,7 +829,7 @@ $gdrive_construct = $remote_storage->gdrive_construct();
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">
@@ -837,11 +837,11 @@ $gdrive_construct = $remote_storage->gdrive_construct();
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>
@@ -850,25 +850,25 @@ $gdrive_construct = $remote_storage->gdrive_construct();
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
 
@@ -880,72 +880,72 @@ $gdrive_construct = $remote_storage->gdrive_construct();
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>
@@ -956,26 +956,26 @@ $gdrive_construct = $remote_storage->gdrive_construct();
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>
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
 
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
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>
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
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>
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
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
  }
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>
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
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>
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>
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
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>
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>
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
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>
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>
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
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>
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
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">
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>
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
 
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 __("Automatically Empty 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 __("Disabled", '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 __("Enabled", '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>
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>
admin/partials/xcloner_restore_page.php CHANGED
@@ -11,10 +11,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">
@@ -22,36 +22,36 @@ $backup_list = $xcloner_file_system->get_latest_backups();
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>
@@ -59,7 +59,7 @@ $backup_list = $xcloner_file_system->get_latest_backups();
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>
@@ -68,18 +68,18 @@ $backup_list = $xcloner_file_system->get_latest_backups();
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 ?>
@@ -94,18 +94,18 @@ $backup_list = $xcloner_file_system->get_latest_backups();
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>
@@ -114,13 +114,13 @@ $backup_list = $xcloner_file_system->get_latest_backups();
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>
@@ -135,11 +135,11 @@ $backup_list = $xcloner_file_system->get_latest_backups();
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>
@@ -151,13 +151,13 @@ $backup_list = $xcloner_file_system->get_latest_backups();
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>
@@ -166,41 +166,41 @@ $backup_list = $xcloner_file_system->get_latest_backups();
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>
@@ -216,18 +216,18 @@ $backup_list = $xcloner_file_system->get_latest_backups();
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>
@@ -236,7 +236,7 @@ $backup_list = $xcloner_file_system->get_latest_backups();
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>
@@ -246,68 +246,68 @@ $backup_list = $xcloner_file_system->get_latest_backups();
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; ?>
@@ -319,7 +319,7 @@ $backup_list = $xcloner_file_system->get_latest_backups();
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>
@@ -331,7 +331,7 @@ $backup_list = $xcloner_file_system->get_latest_backups();
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>
@@ -339,20 +339,20 @@ $backup_list = $xcloner_file_system->get_latest_backups();
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
 
@@ -363,13 +363,13 @@ $backup_list = $xcloner_file_system->get_latest_backups();
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">
@@ -387,7 +387,7 @@ $backup_list = $xcloner_file_system->get_latest_backups();
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">
@@ -404,7 +404,7 @@ $backup_list = $xcloner_file_system->get_latest_backups();
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">
@@ -424,8 +424,8 @@ $backup_list = $xcloner_file_system->get_latest_backups();
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>
@@ -435,14 +435,14 @@ $backup_list = $xcloner_file_system->get_latest_backups();
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>
@@ -459,7 +459,7 @@ $backup_list = $xcloner_file_system->get_latest_backups();
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">
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">
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>
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>
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 ?>
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>
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>
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>
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>
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>
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>
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>
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; ?>
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>
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>
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
 
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">
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">
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">
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>
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>
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">
admin/partials/xcloner_scheduled_backups_page.php CHANGED
@@ -4,10 +4,10 @@ $xcloner_scheduler = $this->get_xcloner_container()->get_xcloner_scheduler();
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>
@@ -15,32 +15,32 @@ $available_storages = $xcloner_remote_storage->get_available_storages();
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>
@@ -50,8 +50,8 @@ $available_storages = $xcloner_remote_storage->get_available_storages();
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
 
@@ -65,17 +65,17 @@ $available_storages = $xcloner_remote_storage->get_available_storages();
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>
@@ -85,27 +85,38 @@ $available_storages = $xcloner_remote_storage->get_available_storages();
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
 
@@ -114,18 +125,18 @@ $available_storages = $xcloner_remote_storage->get_available_storages();
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
@@ -135,17 +146,17 @@ $available_storages = $xcloner_remote_storage->get_available_storages();
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 ?>
@@ -154,7 +165,7 @@ $available_storages = $xcloner_remote_storage->get_available_storages();
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
 
@@ -162,7 +173,7 @@ $available_storages = $xcloner_remote_storage->get_available_storages();
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>
@@ -171,7 +182,7 @@ $available_storages = $xcloner_remote_storage->get_available_storages();
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
 
@@ -180,7 +191,7 @@ $available_storages = $xcloner_remote_storage->get_available_storages();
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
 
@@ -189,7 +200,7 @@ $available_storages = $xcloner_remote_storage->get_available_storages();
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>
@@ -199,7 +210,7 @@ $available_storages = $xcloner_remote_storage->get_available_storages();
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>
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>
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>
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
 
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>
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 l6">
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 col s12 l6">
103
+ <div class="switch">
104
+ <label>
105
+ Off
106
+ <input type="checkbox" name="backup_encrypt" id="backup_encrypt" value="1">
107
+ <span class="lever"></span>
108
+ On
109
+ </label>
110
+ </div>
111
+ <label style="top:-0.8em">Encrypt Backup</label>
112
  </div>
113
  <!--<div class="input-field inline col s12 l6">
114
  <select id="backup_type" class="" name="backup_type" id="backup_type">
115
+ <option value=""><?php echo __("Full Backup", "xcloner-backup-and-restore"); ?></option>
116
+ <option value="diff"><?php echo __("Differential Backups", "xcloner-backup-and-restore"); ?></option>
117
+ <option value="full_diff"><?php echo __("Full Backup + Differential Backups", "xcloner-backup-and-restore"); ?></option>
118
  </select>
119
+ <label for="backup_type"><?php echo __('Scheduled Backup Type', 'xcloner-backup-and-restore') ?></label>
120
  </div>-->
121
  </div>
122
 
125
  <input placeholder="" name="schedule_start_date" id="schedule_start_date" type="datetime"
126
  value="">
127
  <label for="schedule_start_date"
128
+ class="active"><?php echo __('Schedule Start At', 'xcloner-backup-and-restore') ?>
129
  :</label>
130
  </div>
131
 
132
  <div class="input-field col s12 l6">
133
  <select name="schedule_frequency" id="schedule_frequency" class="validate" required>
134
  <option value="" disabled
135
+ selected><?php echo __('Schedule Recurrence', 'xcloner-backup-and-restore') ?></option>
136
  <?php
137
  $schedules = $xcloner_scheduler->get_available_intervals();
138
 
139
+ foreach ($schedules as $key => $schedule) {
140
  ?>
141
  <option value="<?php echo $key ?>"><?php echo $schedule['display'] ?></option>
142
  <?php
146
  </div>
147
  </div>
148
 
149
+ <?php if (sizeof($available_storages)): ?>
150
  <div class="row">
151
  <div class="input-field col s12 l12">
152
  <select name="schedule_storage" id="schedule_storage" class="validate">
153
  <option value=""
154
+ selected><?php echo __('none', 'xcloner-backup-and-restore') ?></option>
155
+ <?php foreach ($available_storages as $storage => $text): ?>
156
  <option value="<?php echo $storage ?>"><?php echo $text ?></option>
157
  <?php endforeach ?>
158
  </select>
159
+ <label><?php echo __('Send To Remote Storage ', 'xcloner-backup-and-restore') ?></label>
160
  </div>
161
  </div>
162
  <?php endif ?>
165
  <div class="input-field col s12 l12">
166
  <input placeholder="" name="email_notification" id="email_notification" type="text"
167
  value="">
168
+ <label for="email_notification"><?php echo __('Email Notification Address', 'xcloner-backup-and-restore') ?></label>
169
  </div>
170
  </div>
171
 
173
  <div class="input-field col s12 l12">
174
  <input placeholder="" name="diff_start_date" id="diff_start_date" type="text"
175
  class="datepicker_max_today" value="">
176
+ <label for="diff_start_date"><?php echo __('Backup Only Files Modified/Created After', 'xcloner-backup-and-restore') ?></label>
177
  </div>
178
  </div>
179
  </div>
182
  <div class="row">
183
  <div class="input-field col s12 l12">
184
  <input placeholder="" name="backup_name" id="backup_name" type="text" required value="">
185
+ <label for="backup_name"><?php echo __('Backup Name', 'xcloner-backup-and-restore') ?></label>
186
  </div>
187
  </div>
188
 
191
  <textarea id="table_params" name="table_params" class="materialize-textarea"
192
  rows="15"></textarea>
193
  <label for="table_params"
194
+ class="active"><?php echo __('Included Database Data', 'xcloner-backup-and-restore') ?></label>
195
  </div>
196
  </div>
197
 
200
  <textarea id="excluded_files" name="excluded_files" class="materialize-textarea"
201
  rows="15"></textarea>
202
  <label for="excluded_files"
203
+ class="active"><?php echo __('Excluded Files', 'xcloner-backup-and-restore') ?></label>
204
  </div>
205
  </div>
206
  </div>
210
 
211
  <div class="input-field col s12 ">
212
  <button class="right btn waves-effect waves-light" type="submit"
213
+ name="action"><?php echo __('Save', 'xcloner-backup-and-restore') ?>
214
  <i class="material-icons right">send</i>
215
  </button>
216
  </div>
composer.json CHANGED
@@ -9,8 +9,9 @@
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
  }
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
+ "require-dev": {
16
+ }
17
  }
composer.lock CHANGED
@@ -4,7 +4,7 @@
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",
@@ -128,69 +128,6 @@
128
  "homepage": "http://jquery.com",
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/",
164
- "license": [
165
- "MIT"
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",
@@ -428,28 +365,28 @@
428
  },
429
  {
430
  "name": "league/flysystem",
431
- "version": "1.0.45",
432
  "source": {
433
  "type": "git",
434
  "url": "https://github.com/thephpleague/flysystem.git",
435
- "reference": "a99f94e63b512d75f851b181afcdf0ee9ebef7e6"
436
  },
437
  "dist": {
438
  "type": "zip",
439
- "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/a99f94e63b512d75f851b181afcdf0ee9ebef7e6",
440
- "reference": "a99f94e63b512d75f851b181afcdf0ee9ebef7e6",
441
  "shasum": ""
442
  },
443
  "require": {
 
444
  "php": ">=5.5.9"
445
  },
446
  "conflict": {
447
  "league/flysystem-sftp": "<1.0.6"
448
  },
449
  "require-dev": {
450
- "ext-fileinfo": "*",
451
  "phpspec/phpspec": "^3.4",
452
- "phpunit/phpunit": "^5.7"
453
  },
454
  "suggest": {
455
  "ext-fileinfo": "Required for MimeType",
@@ -508,7 +445,7 @@
508
  "sftp",
509
  "storage"
510
  ],
511
- "time": "2018-05-07T08:44:23+00:00"
512
  },
513
  {
514
  "name": "league/flysystem-aws-s3-v3",
@@ -607,33 +544,28 @@
607
  },
608
  {
609
  "name": "league/flysystem-sftp",
610
- "version": "1.0.14",
611
  "source": {
612
  "type": "git",
613
  "url": "https://github.com/thephpleague/flysystem-sftp.git",
614
- "reference": "f28d742a3e81258417293fd9a179a350154ab8f7"
615
  },
616
  "dist": {
617
  "type": "zip",
618
- "url": "https://api.github.com/repos/thephpleague/flysystem-sftp/zipball/f28d742a3e81258417293fd9a179a350154ab8f7",
619
- "reference": "f28d742a3e81258417293fd9a179a350154ab8f7",
620
  "shasum": ""
621
  },
622
  "require": {
623
  "league/flysystem": "~1.0",
624
- "php": ">=5.4.0",
625
  "phpseclib/phpseclib": "~2.0"
626
  },
627
  "require-dev": {
628
  "mockery/mockery": "0.9.*",
629
- "phpunit/phpunit": "~4.0"
630
  },
631
  "type": "library",
632
- "extra": {
633
- "branch-alias": {
634
- "dev-master": "1.0-dev"
635
- }
636
- },
637
  "autoload": {
638
  "psr-4": {
639
  "League\\Flysystem\\Sftp\\": "src/"
@@ -650,7 +582,7 @@
650
  }
651
  ],
652
  "description": "Flysystem adapter for SFTP",
653
- "time": "2017-07-11T12:29:45+00:00"
654
  },
655
  {
656
  "name": "league/flysystem-webdav",
@@ -992,55 +924,6 @@
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",
@@ -1742,16 +1625,16 @@
1742
  },
1743
  {
1744
  "name": "vakata/jstree",
1745
- "version": "3.3.5",
1746
  "source": {
1747
  "type": "git",
1748
  "url": "https://github.com/vakata/jstree.git",
1749
- "reference": "0097fab41981daf36c234b73b683166daabd5f28"
1750
  },
1751
  "dist": {
1752
  "type": "zip",
1753
- "url": "https://api.github.com/repos/vakata/jstree/zipball/0097fab41981daf36c234b73b683166daabd5f28",
1754
- "reference": "0097fab41981daf36c234b73b683166daabd5f28",
1755
  "shasum": ""
1756
  },
1757
  "require": {
@@ -1795,7 +1678,7 @@
1795
  ],
1796
  "description": "jsTree is jquery plugin, that provides interactive trees.",
1797
  "homepage": "http://jstree.com",
1798
- "time": "2018-01-02T08:13:23+00:00"
1799
  }
1800
  ],
1801
  "packages-dev": [],
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": "e32ba7a3036306157c1f3563665aec57",
8
  "packages": [
9
  {
10
  "name": "aws/aws-sdk-php",
128
  "homepage": "http://jquery.com",
129
  "time": "2018-03-04T13:23:48+00:00"
130
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
131
  {
132
  "name": "gliterd/backblaze-b2",
133
  "version": "1.0.4",
365
  },
366
  {
367
  "name": "league/flysystem",
368
+ "version": "1.0.49",
369
  "source": {
370
  "type": "git",
371
  "url": "https://github.com/thephpleague/flysystem.git",
372
+ "reference": "a63cc83d8a931b271be45148fa39ba7156782ffd"
373
  },
374
  "dist": {
375
  "type": "zip",
376
+ "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/a63cc83d8a931b271be45148fa39ba7156782ffd",
377
+ "reference": "a63cc83d8a931b271be45148fa39ba7156782ffd",
378
  "shasum": ""
379
  },
380
  "require": {
381
+ "ext-fileinfo": "*",
382
  "php": ">=5.5.9"
383
  },
384
  "conflict": {
385
  "league/flysystem-sftp": "<1.0.6"
386
  },
387
  "require-dev": {
 
388
  "phpspec/phpspec": "^3.4",
389
+ "phpunit/phpunit": "^5.7.10"
390
  },
391
  "suggest": {
392
  "ext-fileinfo": "Required for MimeType",
445
  "sftp",
446
  "storage"
447
  ],
448
+ "time": "2018-11-23T23:41:29+00:00"
449
  },
450
  {
451
  "name": "league/flysystem-aws-s3-v3",
544
  },
545
  {
546
  "name": "league/flysystem-sftp",
547
+ "version": "1.0.18",
548
  "source": {
549
  "type": "git",
550
  "url": "https://github.com/thephpleague/flysystem-sftp.git",
551
+ "reference": "61bc5a6ade892b5ac81e62b8c21be2c1798acc2a"
552
  },
553
  "dist": {
554
  "type": "zip",
555
+ "url": "https://api.github.com/repos/thephpleague/flysystem-sftp/zipball/61bc5a6ade892b5ac81e62b8c21be2c1798acc2a",
556
+ "reference": "61bc5a6ade892b5ac81e62b8c21be2c1798acc2a",
557
  "shasum": ""
558
  },
559
  "require": {
560
  "league/flysystem": "~1.0",
561
+ "php": ">=5.6.0",
562
  "phpseclib/phpseclib": "~2.0"
563
  },
564
  "require-dev": {
565
  "mockery/mockery": "0.9.*",
566
+ "phpunit/phpunit": "^5.7.25"
567
  },
568
  "type": "library",
 
 
 
 
 
569
  "autoload": {
570
  "psr-4": {
571
  "League\\Flysystem\\Sftp\\": "src/"
582
  }
583
  ],
584
  "description": "Flysystem adapter for SFTP",
585
+ "time": "2019-01-07T11:56:21+00:00"
586
  },
587
  {
588
  "name": "league/flysystem-webdav",
924
  ],
925
  "time": "2016-12-03T22:08:25+00:00"
926
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
927
  {
928
  "name": "phpseclib/phpseclib",
929
  "version": "2.0.11",
1625
  },
1626
  {
1627
  "name": "vakata/jstree",
1628
+ "version": "3.3.7",
1629
  "source": {
1630
  "type": "git",
1631
  "url": "https://github.com/vakata/jstree.git",
1632
+ "reference": "bc5187e5826244dee5ebdc0e9db2e2652fefe928"
1633
  },
1634
  "dist": {
1635
  "type": "zip",
1636
+ "url": "https://api.github.com/repos/vakata/jstree/zipball/bc5187e5826244dee5ebdc0e9db2e2652fefe928",
1637
+ "reference": "bc5187e5826244dee5ebdc0e9db2e2652fefe928",
1638
  "shasum": ""
1639
  },
1640
  "require": {
1678
  ],
1679
  "description": "jsTree is jquery plugin, that provides interactive trees.",
1680
  "homepage": "http://jstree.com",
1681
+ "time": "2018-11-06T21:15:47+00:00"
1682
  }
1683
  ],
1684
  "packages-dev": [],
includes/class-xcloner-activator.php CHANGED
@@ -61,22 +61,22 @@ class Xcloner_Activator {
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,69 +87,73 @@ class Xcloner_Activator {
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
  }
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
+ if (!get_option('xcloner_regex_exclude')) {
156
+ 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$");
157
  }
158
 
159
  }
includes/class-xcloner-api.php CHANGED
@@ -43,905 +43,1249 @@ use splitbrain\PHPArchive\FileInfo;
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))
@@ -957,178 +1301,185 @@ class Xcloner_Api
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
  }
43
  class Xcloner_Api
44
  {
45
 
46
+ private $xcloner_database;
47
+ private $xcloner_settings;
48
+ private $xcloner_file_system;
49
+ private $xcloner_scheduler;
50
+ private $xcloner_requirements;
51
+ private $xcloner_sanitization;
52
+ private $xcloner_encryption;
53
+ private $xcloner_remote_storage;
54
+ private $archive_system;
55
+ private $form_params;
56
+ private $logger;
57
+ private $xcloner_container;
58
+
59
+ /**
60
+ * XCloner_Api construct class
61
+ *
62
+ * @param Xcloner $xcloner_container [description]
63
+ */
64
+ public function __construct(Xcloner $xcloner_container)
65
+ {
66
+ global $wpdb;
67
+
68
+ if (WP_DEBUG) {
69
+ error_reporting(0);
70
+ }
71
+
72
+ if (ob_get_length()) {
73
+ ob_end_clean();
74
+ }
75
+ ob_start();
76
+
77
+ $wpdb->show_errors = false;
78
+
79
+ $this->xcloner_container = $xcloner_container;
80
+
81
+ $this->xcloner_settings = $xcloner_container->get_xcloner_settings();
82
+ $this->logger = $xcloner_container->get_xcloner_logger()->withName("xcloner_api");
83
+ $this->xcloner_file_system = $xcloner_container->get_xcloner_filesystem();
84
+ $this->xcloner_sanitization = $xcloner_container->get_xcloner_sanitization();
85
+ $this->xcloner_requirements = $xcloner_container->get_xcloner_requirements();
86
+ $this->archive_system = $xcloner_container->get_archive_system();
87
+ $this->xcloner_database = $xcloner_container->get_xcloner_database();
88
+ $this->xcloner_scheduler = $xcloner_container->get_xcloner_scheduler();
89
+ $this->xcloner_encryption = $xcloner_container->get_xcloner_encryption();
90
+ $this->xcloner_remote_storage = $xcloner_container->get_xcloner_remote_storage();
91
+
92
+ if (isset($_POST['API_ID'])) {
93
+ $this->logger->info("Processing ajax request ID ".substr($this->xcloner_sanitization->sanitize_input_as_string($_POST['API_ID']),
94
+ 0, 15));
95
+ }
96
+
97
+ }
98
+
99
+ /**
100
+ * Get XCloner Container
101
+ * @return XCloner return the XCloner container
102
+ */
103
+ public function get_xcloner_container()
104
+ {
105
+ return $this->xcloner_container;
106
+ }
107
+
108
+
109
+ /**
110
+ * Checks API access
111
+ */
112
+ private function check_access()
113
+ {
114
+ if (function_exists('current_user_can') && !current_user_can('manage_options')) {
115
+ $this->send_response(json_encode("Not allowed access here!"));
116
+ }
117
+ }
118
+
119
+ /**
120
+ * Initialize the database connection
121
+ */
122
+ public function init_db()
123
+ {
124
+ return;
125
+
126
+
127
+ $data['dbHostname'] = $this->xcloner_settings->get_db_hostname();
128
+ $data['dbUsername'] = $this->xcloner_settings->get_db_username();
129
+ $data['dbPassword'] = $this->xcloner_settings->get_db_password();
130
+ $data['dbDatabase'] = $this->xcloner_settings->get_db_database();
131
+
132
+
133
+ $data['recordsPerSession'] = $this->xcloner_settings->get_xcloner_option('xcloner_database_records_per_request');
134
+ $data['TEMP_DBPROCESS_FILE'] = $this->xcloner_settings->get_xcloner_tmp_path().DS.".database";
135
+ $data['TEMP_DUMP_FILE'] = $this->xcloner_settings->get_xcloner_tmp_path().DS."database-sql.sql";
136
+
137
+ try {
138
+ $this->xcloner_database->init($data);
139
+
140
+ }catch (Exception $e) {
141
+
142
+ $this->send_response($e->getMessage());
143
+ $this->logger->error($e->getMessage());
144
+
145
+ }
146
+
147
+ return $this->xcloner_database;
148
+
149
+
150
+ }
151
+
152
+ /*
153
  * Save Schedule API
154
  */
155
+ public function save_schedule()
156
+ {
157
+ global $wpdb;
158
+
159
+ $this->check_access();
160
+
161
+ $scheduler = $this->xcloner_scheduler;
162
+ $params = array();
163
+ $schedule = array();
164
+ $response = array();
165
+
166
+ if (isset($_POST['data'])) {
167
+ $params = json_decode(stripslashes($_POST['data']));
168
+ }
169
+
170
+ $this->process_params($params);
171
+
172
+ if (isset($_POST['id'])) {
173
+
174
+ $this->form_params['backup_params']['backup_name'] = $this->xcloner_sanitization->sanitize_input_as_string($_POST['backup_name']);
175
+ $this->form_params['backup_params']['email_notification'] = $this->xcloner_sanitization->sanitize_input_as_string($_POST['email_notification']);
176
+ if ($_POST['diff_start_date']) {
177
+ $this->form_params['backup_params']['diff_start_date'] = strtotime($this->xcloner_sanitization->sanitize_input_as_string($_POST['diff_start_date']));
178
+ } else {
179
+ $this->form_params['backup_params']['diff_start_date'] = "";
180
+ }
181
+ $this->form_params['backup_params']['schedule_name'] = $this->xcloner_sanitization->sanitize_input_as_string($_POST['schedule_name']);
182
+ $this->form_params['backup_params']['backup_encrypt'] = $this->xcloner_sanitization->sanitize_input_as_int($_POST['backup_encrypt']);
183
+ $this->form_params['backup_params']['start_at'] = strtotime($_POST['schedule_start_date']);
184
+ $this->form_params['backup_params']['schedule_frequency'] = $this->xcloner_sanitization->sanitize_input_as_string($_POST['schedule_frequency']);
185
+ $this->form_params['backup_params']['schedule_storage'] = $this->xcloner_sanitization->sanitize_input_as_string($_POST['schedule_storage']);
186
+ $this->form_params['database'] = (stripslashes($this->xcloner_sanitization->sanitize_input_as_raw($_POST['table_params'])));
187
+ $this->form_params['excluded_files'] = (stripslashes($this->xcloner_sanitization->sanitize_input_as_raw($_POST['excluded_files'])));
188
+
189
+ //$this->form_params['backup_params']['backup_type'] = $this->xcloner_sanitization->sanitize_input_as_string($_POST['backup_type']);
190
+
191
+ $tables = explode(PHP_EOL, $this->form_params['database']);
192
+ $return = array();
193
+
194
+ foreach ($tables as $table) {
195
+ $table = str_replace("\r", "", $table);
196
+ $data = explode(".", $table);
197
+ if (isset($data[1])) {
198
+ $return[$data[0]][] = $data[1];
199
+ }
200
+ }
201
+
202
+ $this->form_params['database'] = ($return);
203
+
204
+ $excluded_files = explode(PHP_EOL, $this->form_params['excluded_files']);
205
+ $return = array();
206
+
207
+ foreach ($excluded_files as $file) {
208
+ $file = str_replace("\r", "", $file);
209
+ if ($file) {
210
+ $return[] = $file;
211
+ }
212
+ }
213
+
214
+ $this->form_params['excluded_files'] = ($return);
215
+
216
+ $schedule['start_at'] = $this->form_params['backup_params']['start_at'];
217
+
218
+ if (!isset($_POST['status'])) {
219
+ $schedule['status'] = 0;
220
+ } else {
221
+ $schedule['status'] = $this->xcloner_sanitization->sanitize_input_as_int($_POST['status']);
222
+ }
223
+ } else {
224
+
225
+ $schedule['status'] = 1;
226
+ $schedule['start_at'] = strtotime($this->form_params['backup_params']['schedule_start_date'].
227
+ " ".$this->form_params['backup_params']['schedule_start_time']);
228
+
229
+ if ($schedule['start_at'] <= time()) {
230
+ $schedule['start_at'] = "";
231
+ }
232
+ }
233
+
234
+ if (!$schedule['start_at']) {
235
+ $schedule['start_at'] = date('Y-m-d H:i:s', time());
236
+ } else {
237
+ $schedule['start_at'] = date('Y-m-d H:i:s',
238
+ $schedule['start_at'] - (get_option('gmt_offset') * HOUR_IN_SECONDS));
239
+ }
240
+
241
+ $schedule['name'] = $this->form_params['backup_params']['schedule_name'];
242
+ $schedule['recurrence'] = $this->form_params['backup_params']['schedule_frequency'];
243
+ if (!isset($this->form_params['backup_params']['schedule_storage'])) {
244
+ $this->form_params['backup_params']['schedule_storage'] = "";
245
+ }
246
+ $schedule['remote_storage'] = $this->form_params['backup_params']['schedule_storage'];
247
+ //$schedule['backup_type'] = $this->form_params['backup_params']['backup_type'];
248
+ $schedule['params'] = json_encode($this->form_params);
249
+
250
+ if (!isset($_POST['id'])) {
251
+ $wpdb->insert(
252
+ $wpdb->prefix.'xcloner_scheduler',
253
+ $schedule,
254
+ array(
255
+ '%s',
256
+ '%s'
257
+ )
258
+ );
259
+ } else {
260
+ $wpdb->update(
261
+ $wpdb->prefix.'xcloner_scheduler',
262
+ $schedule,
263
+ array('id' => $_POST['id']),
264
+ array(
265
+ '%s',
266
+ '%s'
267
+ )
268
+ );
269
+ }
270
+ if (isset($_POST['id'])) {
271
+ $scheduler->update_cron_hook($_POST['id']);
272
+ }
273
+
274
+ if ($wpdb->last_error) {
275
+ $response['error'] = 1;
276
+ $response['error_message'] = $wpdb->last_error/*."--".$wpdb->last_query*/
277
+ ;
278
+
279
+ }
280
+
281
+ $scheduler->update_wp_cron_hooks();
282
+ $response['finished'] = 1;
283
+
284
+ $this->send_response($response);
285
+ }
286
+
287
+ /*
288
  *
289
  * Backup Files API
290
  *
291
  */
292
+ public function backup_files()
293
+ {
294
+ $return = array();
295
+ $additional = array();
296
+
297
+ $this->check_access();
298
+
299
+ $params = json_decode(stripslashes($_POST['data']));
300
+
301
+ $init = (int)$_POST['init'];
302
+
303
+ if ($params === null) {
304
+ return $this->send_response('{"status":false,"msg":"The post_data parameter must be valid JSON"}');
305
+ }
306
+
307
+ $this->process_params($params);
308
+
309
+ $return['finished'] = 1;
310
+
311
+ //$return = $this->archive_system->start_incremental_backup($this->form_params['backup_params'], $this->form_params['extra'], $init);
312
+ try {
313
+ $return = $this->archive_system->start_incremental_backup($this->form_params['backup_params'],
314
+ $this->form_params['extra'], $init);
315
+ }catch (Exception $e) {
316
+ $return = array();
317
+ $return['error'] = true;
318
+ $return['status'] = 500;
319
+ $return['error_message'] = $e->getMessage();
320
+
321
+ return $this->send_response($return, $hash = 1);
322
+ }
323
+
324
+ if ($return['finished']) {
325
+ $return['extra']['backup_parent'] = $this->archive_system->get_archive_name_with_extension();
326
+ if ($this->xcloner_file_system->is_part($this->archive_system->get_archive_name_with_extension())) {
327
+ $return['extra']['backup_parent'] = $this->archive_system->get_archive_name_multipart();
328
+ }
329
+ }
330
+
331
+ $data = $return;
332
+
333
+ //check if backup is finished
334
+ if ($return['finished']) {
335
+ if (isset($this->form_params['backup_params']['email_notification']) and $to = $this->form_params['backup_params']['email_notification']) {
336
+ try {
337
+ $from = "";
338
+ $subject = "";
339
+ $additional['lines_total'] = $return['extra']['lines_total'];
340
+ $this->archive_system->send_notification($to, $from, $subject, $return['extra']['backup_parent'],
341
+ $this->form_params, "", $additional);
342
+ }catch (Exception $e) {
343
+ $this->logger->error($e->getMessage());
344
+ }
345
+ }
346
+ $this->xcloner_file_system->remove_tmp_filesystem();
347
+ }
348
+
349
+ return $this->send_response($data, $hash = 1);
350
+ }
351
+
352
+ /*
353
  *
354
  * Backup Database API
355
  *
356
  */
357
+ public function backup_database()
358
+ {
359
+ $data = array();
360
 
361
+ $this->check_access();
362
 
363
+ $params = json_decode(stripslashes($_POST['data']));
364
 
365
+ $init = (int)$_POST['init'];
 
 
366
 
367
+ if ($params === null) {
368
+ return $this->send_response('{"status":false,"msg":"The post_data parameter must be valid JSON"}');
369
+ }
370
 
371
+ $this->process_params($params);
 
 
372
 
373
+ //$xcloner_database = $this->init_db();
374
+ $return = $this->xcloner_database->start_database_recursion($this->form_params['database'],
375
+ $this->form_params['extra'], $init);
 
 
376
 
377
+ if (isset($return['error']) and $return['error']) {
378
+ $data['finished'] = 1;
379
+ } else {
380
+ $data['finished'] = $return['finished'];
381
+ }
382
 
383
+ $data['extra'] = $return;
 
384
 
385
+ return $this->send_response($data, $hash = 1);
386
+ }
387
+
388
+ /*
389
  *
390
  * Scan Filesystem API
391
  *
392
  */
393
+ public function scan_filesystem()
394
+ {
395
+ $data = array();
396
+
397
+ $this->check_access();
398
 
399
+ $params = json_decode(stripslashes($_POST['data']));
400
+ $init = (int)$_POST['init'];
401
 
402
+ if ($params === null) {
403
+ $this->send_response('{"status":false,"msg":"The post_data parameter must be valid JSON"}');
404
+ }
405
 
406
+ $this->process_params($params);
407
 
408
+ $this->xcloner_file_system->set_excluded_files($this->form_params['excluded_files']);
409
 
410
+ $return = $this->xcloner_file_system->start_file_recursion($init);
411
 
412
+ $data["finished"] = !$return;
413
+ $data["total_files_num"] = $this->xcloner_file_system->get_scanned_files_num();
414
+ $data["last_logged_file"] = $this->xcloner_file_system->last_logged_file();
415
+ $data["total_files_size"] = sprintf("%.2f",
416
+ $this->xcloner_file_system->get_scanned_files_total_size() / (1024 * 1024));
417
 
418
+ return $this->send_response($data, $hash = 1);
419
+ }
420
 
421
+ /*
422
  *
423
  * Process params sent by the user
424
  *
425
  */
426
+ private function process_params($params)
427
+ {
428
+ if (isset($params->hash)) {
429
+ $this->xcloner_settings->set_hash($params->hash);
430
+ }
431
+
432
+ $this->form_params['extra'] = array();
433
+ $this->form_params['backup_params'] = array();
434
+
435
+ $this->form_params['database'] = array();
436
+
437
+ if (isset($params->backup_params)) {
438
+ foreach ($params->backup_params as $param) {
439
+ $this->form_params['backup_params'][$param->name] = $this->xcloner_sanitization->sanitize_input_as_string($param->value);
440
+ $this->logger->debug("Adding form parameter ".$param->name.".".$param->value."\n", array(
441
+ 'POST',
442
+ 'fields filter'
443
+ ));
444
+ }
445
+ }
446
+
447
+ $this->form_params['database'] = array();
448
+
449
+ if (isset($params->table_params)) {
450
+ foreach ($params->table_params as $param) {
451
+ $this->form_params['database'][$param->parent][] = $this->xcloner_sanitization->sanitize_input_as_raw($param->id);
452
+ $this->logger->debug("Adding database filter ".$param->parent.".".$param->id."\n", array(
453
+ 'POST',
454
+ 'database filter'
455
+ ));
456
+ }
457
+ }
458
+
459
+ $this->form_params['excluded_files'] = array();
460
+ if (isset($params->files_params)) {
461
+ foreach ($params->files_params as $param) {
462
+ $this->form_params['excluded_files'][] = $this->xcloner_sanitization->sanitize_input_as_relative_path($param->id);
463
+ }
464
+
465
+ $unique_exclude_files = array();
466
+
467
+ foreach ($params->files_params as $key => $param) {
468
+ if (!in_array($param->parent, $this->form_params['excluded_files'])) {
469
+ //$this->form_params['excluded_files'][] = $this->xcloner_sanitization->sanitize_input_as_relative_path($param->id);
470
+ $unique_exclude_files[] = $param->id;
471
+ $this->logger->debug("Adding file filter ".$param->id."\n", array(
472
+ 'POST',
473
+ 'exclude files filter'
474
+ ));
475
+ }
476
+ }
477
+ $this->form_params['excluded_files'] = (array)$unique_exclude_files;
478
+
479
+ }
480
+
481
+ //$this->form_params['excluded_files'] = array_merge($this->form_params['excluded_files'], $this->exclude_files_by_default);
482
+
483
+ if (isset($params->extra)) {
484
+ foreach ($params->extra as $key => $value) {
485
+ $this->form_params['extra'][$key] = $this->xcloner_sanitization->sanitize_input_as_raw($value);
486
+ }
487
+ }
488
+
489
+ if (isset($this->form_params['backup_params']['diff_start_date']) and $this->form_params['backup_params']['diff_start_date']) {
490
+ $this->form_params['backup_params']['diff_start_date'] = strtotime($this->form_params['backup_params']['diff_start_date']);
491
+ $this->xcloner_file_system->set_diff_timestamp_start($this->form_params['backup_params']['diff_start_date']);
492
+ }
493
+
494
+ return $this->xcloner_settings->get_hash();
495
+ }
496
+
497
+ /*
498
  *
499
  * Get file list for tree view API
500
  *
501
  */
502
+ public function get_file_system_action()
503
+ {
504
+ $this->check_access();
505
+
506
+ $folder = $this->xcloner_sanitization->sanitize_input_as_relative_path($_POST['id']);
507
+
508
+ $data = array();
509
+
510
+ if ($folder == "#") {
511
+
512
+ $folder = "/";
513
+ $data[] = array(
514
+ 'id' => $folder,
515
+ 'parent' => '#',
516
+ 'text' => $this->xcloner_settings->get_xcloner_start_path(),
517
+ //'children' => true,
518
+ 'state' => array('selected' => false, 'opened' => true),
519
+ 'icon' => plugin_dir_url(dirname(__FILE__))."/admin/assets/file-icon-root.png"
520
+ );
521
+ }
522
+
523
+ try {
524
+ $files = $this->xcloner_file_system->list_directory($folder);
525
+ }catch (Exception $e) {
526
+
527
+ print $e->getMessage();
528
+ $this->logger->error($e->getMessage());
529
+
530
+ return;
531
+ }
532
+
533
+ $type = array();
534
+ foreach ($files as $key => $row) {
535
+ $type[$key] = $row['type'];
536
+ }
537
+ array_multisort($type, SORT_ASC, $files);
538
+
539
+ foreach ($files as $file) {
540
+ $children = false;
541
+ $text = $file['basename'];
542
+
543
+ if ($file['type'] == "dir") {
544
+ $children = true;
545
+ } else {
546
+ $text .= " (".$this->xcloner_requirements->file_format_size($file['size']).")";
547
+ }
548
+
549
+ if ($this->xcloner_file_system->is_excluded($file)) {
550
+ $selected = true;
551
+ } else {
552
+ $selected = false;
553
+ }
554
+
555
+ $data[] = array(
556
+ 'id' => $file['path'],
557
+ 'parent' => $folder,
558
+ 'text' => $text,
559
+ //'title' => "test",
560
+ 'children' => $children,
561
+ 'state' => array('selected' => $selected, 'opened' => false, "checkbox_disabled" => $selected),
562
+ 'icon' => plugin_dir_url(dirname(__FILE__))."/admin/assets/file-icon-".strtolower(substr($file['type'],
563
+ 0, 1)).".png"
564
+ );
565
+ }
566
+
567
+
568
+ return $this->send_response($data, 0);
569
+ }
570
+
571
+ /*
572
  *
573
  * Get databases/tables list for frontend tree display API
574
  *
575
  */
576
+ public function get_database_tables_action()
577
+ {
578
+ $this->check_access();
579
+
580
+ $database = $this->xcloner_sanitization->sanitize_input_as_raw($_POST['id']);
581
+
582
+ $data = array();
583
+
584
+ $xcloner_backup_only_wp_tables = $this->xcloner_settings->get_xcloner_option('xcloner_backup_only_wp_tables');
585
+
586
+ if ($database == "#") {
587
+ try {
588
+ $return = $this->xcloner_database->get_all_databases();
589
+ }catch (Exception $e) {
590
+ $this->logger->error($e->getMessage());
591
+ }
592
+
593
+ foreach ($return as $database) {
594
+ if ($xcloner_backup_only_wp_tables and $database['name'] != $this->xcloner_settings->get_db_database()) {
595
+ continue;
596
+ }
597
+
598
+ $state = array();
599
+
600
+ if ($database['name'] == $this->xcloner_settings->get_db_database()) {
601
+ $state['selected'] = true;
602
+ if ($database['num_tables'] < 25) {
603
+ $state['opened'] = false;
604
+ }
605
+ }
606
+
607
+ $data[] = array(
608
+ 'id' => $database['name'],
609
+ 'parent' => '#',
610
+ 'text' => $database['name']." (".(int)$database['num_tables'].")",
611
+ 'children' => true,
612
+ 'state' => $state,
613
+ 'icon' => plugin_dir_url(dirname(__FILE__))."/admin/assets/database-icon.png"
614
+ );
615
+ }
616
+
617
+ } else {
618
+
619
+ try {
620
+ $return = $this->xcloner_database->list_tables($database, "", 1);
621
+ }catch (Exception $e) {
622
+ $this->logger->error($e->getMessage());
623
+ }
624
+
625
+ foreach ($return as $table) {
626
+ $state = array();
627
+
628
+ if ($xcloner_backup_only_wp_tables and !stristr($table['name'],
629
+ $this->xcloner_settings->get_table_prefix())) {
630
+ continue;
631
+ }
632
+
633
+ if (isset($database['name']) and $database['name'] == $this->xcloner_settings->get_db_database()) {
634
+ $state = array('selected' => true);
635
+ }
636
+
637
+ $data[] = array(
638
+ 'id' => $database.".".$table['name'],
639
+ 'parent' => $database,
640
+ 'text' => $table['name']." (".(int)$table['records'].")",
641
+ 'children' => false,
642
+ 'state' => $state,
643
+ 'icon' => plugin_dir_url(dirname(__FILE__))."/admin/assets/table-icon.png"
644
+ );
645
+ }
646
+ }
647
+
648
+ return $this->send_response($data, 0);
649
+ }
650
+
651
+ /*
652
  *
653
  * Get schedule by id API
654
  *
655
  */
656
+ public function get_schedule_by_id()
657
+ {
658
+ $this->check_access();
659
 
660
+ $schedule_id = $this->xcloner_sanitization->sanitize_input_as_int($_GET['id']);
661
+ $scheduler = $this->xcloner_scheduler;
662
+ $data = $scheduler->get_schedule_by_id($schedule_id);
663
 
664
+ $data['start_at'] = date("Y-m-d H:i",
665
+ strtotime($data['start_at']) + (get_option('gmt_offset') * HOUR_IN_SECONDS));
666
+ if (isset($data['backup_params']->diff_start_date) && $data['backup_params']->diff_start_date != "") {
667
+ $data['backup_params']->diff_start_date = date("Y-m-d", ($data['backup_params']->diff_start_date));
668
+ }
669
 
670
+ return $this->send_response($data);
671
+ }
672
 
673
+ /*
674
  *
675
  * Get Schedule list API
676
  *
677
  */
678
+ public function get_scheduler_list()
679
+ {
680
+ $return = array();
681
+
682
+ $this->check_access();
683
+
684
+ $scheduler = $this->xcloner_scheduler;
685
+ $data = $scheduler->get_scheduler_list();
686
+ $return['data'] = array();
687
+
688
+ foreach ($data as $res) {
689
+ $action = "<a href=\"#".$res->id."\" class=\"edit\" title='Edit'> <i class=\"material-icons \">edit</i></a>
690
+ <a href=\"#" . $res->id."\" class=\"delete\" title='Delete'><i class=\"material-icons \">delete</i></a>";
691
+ if ($res->status) {
692
+ $status = '<i class="material-icons active status">timer</i>';
693
+ } else {
694
+ $status = '<i class="material-icons status inactive">timer_off</i>';
695
+ }
696
+
697
+ $next_run_time = wp_next_scheduled('xcloner_scheduler_'.$res->id, array($res->id));
698
+
699
+ $next_run = date(get_option('date_format')." ".get_option('time_format'), $next_run_time);
700
+
701
+ $remote_storage = $res->remote_storage;
702
+
703
+ if (!$next_run_time >= time()) {
704
+ $next_run = " ";
705
+ }
706
+
707
+ if (trim($next_run)) {
708
+ $date_text = date(get_option('date_format')." ".get_option('time_format'),
709
+ $next_run_time + (get_option('gmt_offset') * HOUR_IN_SECONDS));
710
+
711
+ if ($next_run_time >= time()) {
712
+ $next_run = "in ".human_time_diff($next_run_time, time());
713
+ } else {
714
+ $next_run = __("executed", 'xcloner-backup-and-restore');
715
+ }
716
+
717
+ $next_run = "<a href='#' title='".$date_text."'>".$next_run."</a>";
718
+ //$next_run .=" ($date_text)";
719
+ }
720
+
721
+ $backup_text = "";
722
+ $backup_size = "";
723
+ $backup_time = "";
724
+
725
+ if ($res->last_backup) {
726
+ if ($this->xcloner_file_system->get_storage_filesystem()->has($res->last_backup)) {
727
+ $metadata = $this->xcloner_file_system->get_storage_filesystem()->getMetadata($res->last_backup);
728
+ $backup_size = size_format($this->xcloner_file_system->get_backup_size($res->last_backup));
729
+ $backup_time = date(get_option('date_format')." ".get_option('time_format'),
730
+ $metadata['timestamp'] + (get_option('gmt_offset') * HOUR_IN_SECONDS));
731
+ }
732
+
733
+ $backup_text = "<span title='".$backup_time."' class='shorten_string'>".$res->last_backup." (".$backup_size.")</span>";
734
+ }
735
+
736
+ $schedules = wp_get_schedules();
737
+
738
+ if (isset($schedules[$res->recurrence])) {
739
+ $res->recurrence = $schedules[$res->recurrence]['display'];
740
+ }
741
+
742
+ $return['data'][] = array(
743
+ $res->id,
744
+ $res->name,
745
+ $res->recurrence, /*$res->start_at,*/
746
+ $next_run,
747
+ $remote_storage,
748
+ $backup_text,
749
+ $status,
750
+ $action
751
+ );
752
+ }
753
+
754
+ return $this->send_response($return, 0);
755
+ }
756
+
757
+ /*
758
  *
759
  * Delete Schedule by ID API
760
  *
761
  */
762
+ public function delete_schedule_by_id()
763
+ {
764
+ $data = array();
765
 
766
+ $this->check_access();
 
 
767
 
768
+ $schedule_id = $this->xcloner_sanitization->sanitize_input_as_int($_GET['id']);
769
+ $scheduler = $this->xcloner_scheduler;
770
+ $data['finished'] = $scheduler->delete_schedule_by_id($schedule_id);
771
 
772
+ return $this->send_response($data);
773
+ }
774
+
775
+ /*
776
  *
777
  * Delete backup by name from the storage path
778
  *
779
  */
780
+ public function delete_backup_by_name()
781
+ {
782
+ $data = array();
783
+
784
+ $this->check_access();
 
 
 
 
 
 
785
 
786
+ $backup_name = $this->xcloner_sanitization->sanitize_input_as_string($_POST['name']);
787
+ $storage_selection = $this->xcloner_sanitization->sanitize_input_as_string($_POST['storage_selection']);
 
788
 
789
+ $data['finished'] = $this->xcloner_file_system->delete_backup_by_name($backup_name, $storage_selection);
790
+
791
+ return $this->send_response($data);
792
+ }
793
+
794
+ /**
795
+ * API Incremental Backup Encryption Method
796
+ */
797
+ public function backup_encryption()
798
+ {
799
+ $this->check_access();
800
+
801
+ $backup_parts = array();
802
+ $return = array();
803
 
 
 
 
804
 
805
+ if (isset($_POST['data'])) {
806
+ $params = json_decode(stripslashes($_POST['data']));
807
+
808
+ $this->process_params($params);
809
+ $source_backup_file = $this->xcloner_sanitization->sanitize_input_as_string($this->form_params['extra']['backup_parent']);
810
+
811
+ if (isset($this->form_params['extra']['start'])) {
812
+ $start = $this->xcloner_sanitization->sanitize_input_as_int($this->form_params['extra']['start']);
813
+ } else {
814
+ $start = 0;
815
+ }
816
+
817
+ if (isset($this->form_params['extra']['iv'])) {
818
+ $iv = $this->xcloner_sanitization->sanitize_input_as_raw($this->form_params['extra']['iv']);
819
+ } else {
820
+ $iv = "";
821
+ }
822
 
823
+ if (isset($this->form_params['extra']['part'])) {
824
+ $return['part'] = (int)$this->xcloner_sanitization->sanitize_input_as_int($this->form_params['extra']['part']);
825
+ } else {
826
+ $return['part'] = 0;
827
+ }
828
 
829
+ } else {
830
+ $source_backup_file = $this->xcloner_sanitization->sanitize_input_as_string($_POST['file']);
831
+ $start = $this->xcloner_sanitization->sanitize_input_as_int($_POST['start']);
832
+ $iv = $this->xcloner_sanitization->sanitize_input_as_raw($_POST['iv']);
833
+ $return['part'] = (int)$this->xcloner_sanitization->sanitize_input_as_int($_POST['part']);
834
+ }
835
 
836
+ $backup_file = $source_backup_file;
 
 
 
 
 
837
 
838
+ if ($this->xcloner_file_system->is_multipart($backup_file)) {
839
+ $backup_parts = $this->xcloner_file_system->get_multipart_files($backup_file);
840
+ $backup_file = $backup_parts[$return['part']];
841
+ }
842
 
843
+ $return['processing_file'] = $backup_file;
844
+ $return['total_size'] = filesize($this->xcloner_settings->get_xcloner_store_path().DS.$backup_file);
 
 
 
 
845
 
846
+ try {
847
+ $this->logger->info(json_encode($_POST));
848
+ $this->logger->info($iv);
849
+ $return = array_merge($return,
850
+ $this->xcloner_encryption->encrypt_file($backup_file, "", "", $start, base64_decode($iv)));
851
+ }catch (\Exception $e) {
852
+ $return['error'] = true;
853
+ $return['message'] = $e->getMessage();
854
+ $return['error_message'] = $e->getMessage();
855
+ }
856
 
857
+ //echo strlen($return['iv']);exit;
 
 
 
 
 
858
 
859
+ if (isset($return['finished']) && $return['finished']) {
860
+ if ($this->xcloner_file_system->is_multipart($source_backup_file)) {
861
+ $return['start'] = 0;
862
 
863
+ ++$return['part'];
864
+
865
+ if ($return['part'] < sizeof($backup_parts)) {
866
+ $return['finished'] = 0;
867
+ }
868
+
869
+ }
870
+ }
871
+
872
+ if (isset($_POST['data'])) {
873
+ $return['extra'] = array_merge($this->form_params['extra'], $return);
874
+ }
875
+
876
+ $this->send_response($return, 0);
877
+ }
878
+
879
+ /**
880
+ * API Incremental Backup Decryption Method
881
+ */
882
+ public function backup_decryption()
883
+ {
884
+ $this->check_access();
885
+
886
+ $backup_parts = array();
887
+ $return = array();
888
+
889
+ $source_backup_file = $this->xcloner_sanitization->sanitize_input_as_string($_POST['file']);
890
+ $start = $this->xcloner_sanitization->sanitize_input_as_int($_POST['start']);
891
+ $iv = $this->xcloner_sanitization->sanitize_input_as_raw($_POST['iv']);
892
+ $decryption_key = $this->xcloner_sanitization->sanitize_input_as_raw($_POST['decryption_key']); ;
893
+ $return['part'] = $this->xcloner_sanitization->sanitize_input_as_int($_POST['part']);
894
+
895
+ $backup_file = $source_backup_file;
896
+
897
+ if ($this->xcloner_file_system->is_multipart($backup_file)) {
898
+ $backup_parts = $this->xcloner_file_system->get_multipart_files($backup_file);
899
+ $backup_file = $backup_parts[$return['part']];
900
+ }
901
+
902
+ $return['processing_file'] = $backup_file;
903
+ $return['total_size'] = filesize($this->xcloner_settings->get_xcloner_store_path().DS.$backup_file);
904
+
905
+ try {
906
+ $return = array_merge($return,
907
+ $this->xcloner_encryption->decrypt_file($backup_file, "", $decryption_key, $start, base64_decode($iv)));
908
+ }catch (\Exception $e) {
909
+ $return['error'] = true;
910
+ $return['message'] = $e->getMessage();
911
+ }
912
+
913
+ if ($return['finished']) {
914
+ if ($this->xcloner_file_system->is_multipart($source_backup_file)) {
915
+ $return['start'] = 0;
916
+
917
+ ++$return['part'];
918
+
919
+ if ($return['part'] < sizeof($backup_parts)) {
920
+ $return['finished'] = 0;
921
+ }
922
+
923
+ }
924
+ }
925
+
926
+ $this->send_response($return, 0);
927
+ }
928
+
929
+ public function get_manage_backups_list() {
930
+
931
+ $this->check_access();
932
+
933
+ $return = array();
934
+ $storage_selection = "";
935
+
936
+ if (isset($_GET['storage_selection']) and $_GET['storage_selection']) {
937
+ $storage_selection = $this->xcloner_sanitization->sanitize_input_as_string($_GET['storage_selection']);
938
+ }
939
+ $available_storages = $this->xcloner_remote_storage->get_available_storages();
940
+
941
+ $backup_list = $this->xcloner_file_system->get_backup_archives_list($storage_selection);
942
+
943
+ $i = -1;
944
+ foreach ($backup_list as $file_info):?>
945
+ <?php
946
+ if ($storage_selection == "gdrive") {
947
+ $file_info['path'] = $file_info['filename'].".".$file_info['extension'];
948
+ }
949
+ $file_exists_on_local_storage = true;
950
+
951
+ if ($storage_selection) {
952
+ if (!$this->xcloner_file_system->get_storage_filesystem()->has($file_info['path'])) {
953
+ $file_exists_on_local_storage = false;
954
+ }
955
+ }
956
+
957
+ ?>
958
+ <?php if (!isset($file_info['parent'])): ?>
959
+
960
+ <?php ob_start(); ?>
961
+ <p>
962
+ <input name="backup[]" value="<?php echo $file_info['basename'] ?>" type="checkbox"
963
+ id="checkbox_<?php echo ++$i ?>">
964
+ <label for="checkbox_<?php echo $i ?>">&nbsp;</label>
965
+ </p>
966
+ <?php
967
+ $return['data'][$i][] = ob_get_contents();
968
+ ob_end_clean();
969
+ ?>
970
+
971
+ <?php ob_start(); ?>
972
+ <span class=""><?php echo $file_info['path'] ?></span>
973
+ <?php if (!$file_exists_on_local_storage): ?>
974
+ <a href="#"
975
+ title="<?php echo __("File does not exists on local storage",
976
+ "xcloner-backup-and-restore") ?>"><i
977
+ class="material-icons backup_warning">warning</i></a>
978
+ <?php endif ?>
979
+ <?php
980
+ if (isset($file_info['childs']) and is_array($file_info['childs'])):
981
+ ?>
982
+ <a href="#" title="expand" class="expand-multipart add"><i
983
+ class="material-icons">add</i></a>
984
+ <a href="#" title="collapse" class="expand-multipart remove"><i class="material-icons">remove</i></a>
985
+ <ul class="multipart">
986
+ <?php foreach ($file_info['childs'] as $child): ?>
987
+ <li>
988
+ <?php echo $child[0] ?> (<?php echo esc_html(size_format($child[2])) ?>)
989
+ <?php
990
+ $child_exists_on_local_storage = true;
991
+ if ($storage_selection) {
992
+ if (!$this->xcloner_file_system->get_storage_filesystem()->has($child[0])) {
993
+ $child_exists_on_local_storage = false;
994
+ }
995
+ }
996
+ ?>
997
+ <?php if (!$child_exists_on_local_storage): ?>
998
+ <a href="#"
999
+ title="<?php echo __("File does not exists on local storage",
1000
+ "xcloner-backup-and-restore") ?>"><i
1001
+ class="material-icons backup_warning">warning</i></a>
1002
+ <?php endif ?>
1003
+ <?php if (!$storage_selection) : ?>
1004
+ <a href="#<?php echo $child[0]; ?>" class="download"
1005
+ title="Download Backup"><i class="material-icons">file_download</i></a>
1006
+
1007
+ <?php if ($this->xcloner_encryption->is_encrypted_file($child[0])) :?>
1008
+ <a href="#<?php echo $child[0] ?>" class="backup-decryption"
1009
+ title="<?php echo __('Backup Decryption', 'xcloner-backup-and-restore') ?>">
1010
+ <i class="material-icons">enhanced_encryption</i>
1011
+ </a>
1012
+ <?php else: ?>
1013
+ <a href="#<?php echo $child[0] ?>" class="list-backup-content"
1014
+ title="<?php echo __('List Backup Content',
1015
+ 'xcloner-backup-and-restore') ?>"><i
1016
+ class="material-icons">folder_open</i></a>
1017
+
1018
+ <a href="#<?php echo $child[0] ?>" class="backup-encryption"
1019
+ title="<?php echo __('Backup Encryption', 'xcloner-backup-and-restore') ?>">
1020
+ <i class="material-icons">no_encryption</i>
1021
+ </a>
1022
+ <?php endif?>
1023
+
1024
+ <?php elseif ($storage_selection != "gdrive" && !$this->xcloner_file_system->get_storage_filesystem()->has($child[0])): ?>
1025
+ <a href="#<?php echo $child[0] ?>" class="copy-remote-to-local"
1026
+ title="<?php echo __('Push Backup To Local Storage',
1027
+ 'xcloner-backup-and-restore') ?>"><i
1028
+ class="material-icons">file_upload</i></a>
1029
+ <?php endif ?>
1030
+ </li>
1031
+ <?php endforeach; ?>
1032
+ </ul>
1033
+ <?php endif; ?>
1034
+ <?php
1035
+ $return['data'][$i][] = ob_get_contents();
1036
+ ob_end_clean();
1037
+ ?>
1038
+ <?php ob_start(); ?>
1039
+ <?php if (isset($file_info['timestamp']))
1040
+ echo date("Y-m-d H:i", $file_info['timestamp'])
1041
+ ?>
1042
+ <?php
1043
+ $return['data'][$i][] = ob_get_contents();
1044
+ ob_end_clean();
1045
+ ?>
1046
+
1047
+ <?php ob_start(); ?>
1048
+ <?php echo esc_html(size_format($file_info['size'])) ?>
1049
+ <?php
1050
+ $return['data'][$i][] = ob_get_contents();
1051
+ ob_end_clean();
1052
+ ?>
1053
+
1054
+ <?php ob_start(); ?>
1055
+ <?php if (!$storage_selection): ?>
1056
+ <a href="#<?php echo $file_info['basename']; ?>" class="download"
1057
+ title="<?php echo __('Download Backup', 'xcloner-backup-and-restore') ?>"><i
1058
+ class="material-icons">file_download</i></a>
1059
+
1060
+ <?php if (sizeof($available_storages)): ?>
1061
+ <a href="#<?php echo $file_info['basename'] ?>" class="cloud-upload"
1062
+ title="<?php echo __('Send Backup To Remote Storage',
1063
+ 'xcloner-backup-and-restore') ?>"><i
1064
+ class="material-icons">cloud_upload</i></a>
1065
+ <?php endif ?>
1066
+ <?php
1067
+ $basename = $file_info['basename'];
1068
+ if (isset($file_info['childs']) and sizeof($file_info['childs']))
1069
+ $basename = $file_info['childs'][0][0];
1070
+ ?>
1071
+ <?php if ($this->xcloner_encryption->is_encrypted_file($basename)) :?>
1072
+ <a href="#<?php echo $file_info['basename'] ?>" class="backup-decryption"
1073
+ title="<?php echo __('Backup Decryption', 'xcloner-backup-and-restore') ?>">
1074
+ <i class="material-icons">enhanced_encryption</i>
1075
+ </a>
1076
+ <?php else: ?>
1077
+ <a href="#<?php echo $file_info['basename'] ?>" class="list-backup-content"
1078
+ title="<?php echo __('List Backup Content', 'xcloner-backup-and-restore') ?>"><i
1079
+ class="material-icons">folder_open</i></a>
1080
+
1081
+ <a href="#<?php echo $file_info['basename'] ?>" class="backup-encryption"
1082
+ title="<?php echo __('Backup Encryption', 'xcloner-backup-and-restore') ?>">
1083
+ <i class="material-icons">no_encryption</i>
1084
+ </a>
1085
+ <?php endif?>
1086
+ <?php endif; ?>
1087
+
1088
+ <a href="#<?php echo $file_info['basename'] ?>" class="delete"
1089
+ title="<?php echo __('Delete Backup', 'xcloner-backup-and-restore') ?>">
1090
+ <i class="material-icons">delete</i>
1091
+ </a>
1092
+ <?php if ($storage_selection and !$file_exists_on_local_storage): ?>
1093
+ <a href="#<?php echo $file_info['basename']; ?>" class="copy-remote-to-local"
1094
+ title="<?php echo __('Push Backup To Local Storage', 'xcloner-backup-and-restore') ?>"><i
1095
+ class="material-icons">file_upload</i></a>
1096
+ <?php endif ?>
1097
+
1098
+ <?php
1099
+ $return['data'][$i][] = ob_get_contents();
1100
+ ob_end_clean(); ?>
1101
+
1102
+ <?php endif ?>
1103
+ <?php endforeach ?>
1104
+ <?php
1105
+ $this->send_response($return, 0);
1106
+ }
1107
+
1108
+ /**
1109
+ * API method to list internal backup files
1110
+ */
1111
+ public function list_backup_files()
1112
+ {
1113
+ $this->check_access();
1114
+
1115
+ $backup_parts = array();
1116
+ $return = array();
1117
+
1118
+ $source_backup_file = $this->xcloner_sanitization->sanitize_input_as_string($_POST['file']);
1119
+ $start = $this->xcloner_sanitization->sanitize_input_as_int($_POST['start']);
1120
+ $return['part'] = $this->xcloner_sanitization->sanitize_input_as_int($_POST['part']);
1121
+
1122
+ $backup_file = $source_backup_file;
1123
+
1124
+ if ($this->xcloner_file_system->is_multipart($backup_file)) {
1125
+ $backup_parts = $this->xcloner_file_system->get_multipart_files($backup_file);
1126
+ $backup_file = $backup_parts[$return['part']];
1127
+ }
1128
+
1129
+ if ($this->xcloner_encryption->is_encrypted_file($backup_file)) {
1130
+ $return['error'] = true;
1131
+ $return['message'] = __("Backup archive is encrypted, please decrypt it first before you can list it's content.", "xcloner-backup-and-restore");
1132
+ $this->send_response($return, 0);
1133
+ }
1134
+
1135
+ try {
1136
+ $tar = new Tar();
1137
+ $tar->open($this->xcloner_settings->get_xcloner_store_path().DS.$backup_file, $start);
1138
+
1139
+ $data = $tar->contents(get_option('xcloner_files_to_process_per_request'));
1140
+ }catch (Exception $e) {
1141
+ $return['error'] = true;
1142
+ $return['message'] = $e->getMessage();
1143
+ $this->send_response($return, 0);
1144
+ }
1145
+
1146
+ $return['files'] = array();
1147
+ $return['finished'] = 1;
1148
+ $return['total_size'] = filesize($this->xcloner_settings->get_xcloner_store_path().DS.$backup_file);
1149
+ $i = 0;
1150
+
1151
+ if (isset($data['extracted_files']) and is_array($data['extracted_files'])) {
1152
+ foreach ($data['extracted_files'] as $file) {
1153
+ $return['files'][$i]['path'] = $file->getPath();
1154
+ $return['files'][$i]['size'] = $file->getSize();
1155
+ $return['files'][$i]['mtime'] = date(get_option('date_format')." ".get_option('time_format'),
1156
+ $file->getMtime());
1157
+
1158
+ $i++;
1159
+ }
1160
+ }
1161
+
1162
+ if (isset($data['start'])) {
1163
+ $return['start'] = $data['start'];
1164
+ $return['finished'] = 0;
1165
+ } else {
1166
+ if ($this->xcloner_file_system->is_multipart($source_backup_file)) {
1167
+ $return['start'] = 0;
1168
+
1169
+ ++$return['part'];
1170
+
1171
+ if ($return['part'] < sizeof($backup_parts)) {
1172
+ $return['finished'] = 0;
1173
+ }
1174
+
1175
+ }
1176
+ }
1177
+
1178
+ $this->send_response($return, 0);
1179
+ }
1180
+
1181
+ /*
1182
  * Copy remote backup to local storage
1183
  */
1184
+ public function copy_backup_remote_to_local()
1185
+ {
1186
 
1187
+ $this->check_access();
1188
 
1189
+ $backup_file = $this->xcloner_sanitization->sanitize_input_as_string($_POST['file']);
1190
+ $storage_type = $this->xcloner_sanitization->sanitize_input_as_string($_POST['storage_type']);
1191
 
1192
+ $xcloner_remote_storage = $this->get_xcloner_container()->get_xcloner_remote_storage();
1193
 
1194
+ $return = array();
1195
 
1196
+ try {
1197
+ if (method_exists($xcloner_remote_storage, "copy_backup_remote_to_local")) {
1198
+ $return = call_user_func_array(array(
1199
+ $xcloner_remote_storage,
1200
+ "copy_backup_remote_to_local"
1201
+ ), array($backup_file, $storage_type));
1202
+ }
1203
+ }catch (Exception $e) {
1204
 
1205
+ $return['error'] = 1;
1206
+ $return['message'] = $e->getMessage();
1207
+ }
1208
 
1209
+ if (!$return) {
1210
+ $return['error'] = 1;
1211
+ $return['message'] = "Upload failed, please check the error log for more information!";
1212
+ }
1213
 
1214
 
1215
+ $this->send_response($return, 0);
1216
 
1217
+ }
1218
 
1219
+ /*
1220
  *
1221
  * Upload backup to remote API
1222
  *
1223
  */
1224
+ public function upload_backup_to_remote()
1225
+ {
1226
+ $this->check_access();
1227
 
1228
+ $return = array();
 
1229
 
1230
+ $backup_file = $this->xcloner_sanitization->sanitize_input_as_string($_POST['file']);
1231
+ $storage_type = $this->xcloner_sanitization->sanitize_input_as_string($_POST['storage_type']);
1232
 
1233
+ $xcloner_remote_storage = $this->get_xcloner_container()->get_xcloner_remote_storage();
1234
 
1235
+ try {
1236
+ if (method_exists($xcloner_remote_storage, "upload_backup_to_storage")) {
1237
+ $return = call_user_func_array(array(
1238
+ $xcloner_remote_storage,
1239
+ "upload_backup_to_storage"
1240
+ ), array($backup_file, $storage_type));
1241
+ }
1242
+ }catch (Exception $e) {
1243
 
1244
+ $return['error'] = 1;
1245
+ $return['message'] = $e->getMessage();
1246
+ }
1247
 
1248
+ if (!$return) {
1249
+ $return['error'] = 1;
1250
+ $return['message'] = "Upload failed, please check the error log for more information!";
1251
+ }
1252
 
1253
 
1254
+ $this->send_response($return, 0);
1255
 
1256
+ }
1257
 
1258
+ /*
1259
  *
1260
  * Remote Storage Status Save
1261
  *
1262
  */
1263
+ public function remote_storage_save_status()
1264
+ {
1265
+ $this->check_access();
1266
+
1267
+ $return = array();
1268
 
1269
+ $xcloner_remote_storage = $this->get_xcloner_container()->get_xcloner_remote_storage();
1270
 
1271
+ $return['finished'] = $xcloner_remote_storage->change_storage_status($_POST['id'], $_POST['value']);
1272
 
1273
+ $this->send_response($return, 0);
1274
+ }
1275
 
1276
 
1277
+ public function download_restore_script()
1278
+ {
1279
+ $this->check_access();
1280
 
1281
+ ob_end_clean();
1282
 
1283
+ $adapter = new Local(dirname(__DIR__), LOCK_EX, '0001');
1284
+ $xcloner_plugin_filesystem = new Filesystem($adapter, new Config([
1285
+ 'disable_asserts' => true,
1286
+ ]));
1287
 
1288
+ /* Generate PHAR FILE
1289
  $file = 'restore/vendor.built';
1290
 
1291
  if(file_exists($file))
1301
  $phar2->setStub($phar2->createDefaultStub('vendor/autoload.php', 'vendor/autoload.php'));
1302
  * */
1303
 
1304
+ $tmp_file = $this->xcloner_settings->get_xcloner_tmp_path().DS."xcloner-restore.tgz";
1305
 
1306
+ $tar = new Tar();
1307
+ $tar->create($tmp_file);
1308
 
1309
+ $tar->addFile(dirname(__DIR__)."/restore/vendor.build.txt", "vendor.phar");
1310
+ //$tar->addFile(dirname(__DIR__)."/restore/vendor.tgz", "vendor.tgz");
1311
 
1312
+ $files = $xcloner_plugin_filesystem->listContents("vendor/", true);
1313
+ foreach ($files as $file) {
1314
+ $tar->addFile(dirname(__DIR__).DS.$file['path'], $file['path']);
1315
+ }
1316
 
1317
+ $content = file_get_contents(dirname(__DIR__)."/restore/xcloner_restore.php");
1318
+ $content = str_replace("define('AUTH_KEY', '');", "define('AUTH_KEY', '".md5(AUTH_KEY)."');", $content);
1319
 
1320
+ $tar->addData("xcloner_restore.php", $content);
1321
 
1322
+ $tar->close();
1323
 
1324
+ if (file_exists($tmp_file)) {
1325
+ header('Content-Description: File Transfer');
1326
+ header('Content-Type: application/octet-stream');
1327
+ header('Content-Disposition: attachment; filename="'.basename($tmp_file).'"');
1328
+ header('Expires: 0');
1329
+ header('Cache-Control: must-revalidate');
1330
+ header('Pragma: public');
1331
+ header('Content-Length: '.filesize($tmp_file));
1332
+ readfile($tmp_file);
1333
 
1334
+ }
1335
 
1336
+ try {
1337
+ unlink($tmp_file);
1338
+ }catch (Exception $e) {
1339
+ //We are not interested in the error here
1340
+ }
1341
 
1342
+ die();
1343
+ }
1344
+
1345
+ /*
1346
  *
1347
  * Download backup by Name from the Storage Path
1348
  *
1349
  */
1350
+ public function download_backup_by_name()
1351
+ {
1352
+ $this->check_access();
1353
+
1354
+ ob_end_clean();
1355
 
1356
+ $backup_name = $this->xcloner_sanitization->sanitize_input_as_string($_GET['name']);
1357
 
 
1358
 
1359
+ $metadata = $this->xcloner_file_system->get_storage_filesystem()->getMetadata($backup_name);
1360
+ $read_stream = $this->xcloner_file_system->get_storage_filesystem()->readStream($backup_name);
1361
 
 
 
1362
 
1363
+ header('Pragma: public');
1364
+ header('Expires: 0');
1365
+ header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
1366
+ header('Cache-Control: private', false);
1367
+ header('Content-Transfer-Encoding: binary');
1368
+ header('Content-Disposition: attachment; filename="'.$metadata['path'].'";');
1369
+ header('Content-Type: application/octet-stream');
1370
+ header('Content-Length: '.$metadata['size']);
1371
 
1372
+ ob_end_clean();
 
 
 
 
 
 
 
1373
 
1374
+ $chunkSize = 1024 * 1024;
1375
+ while (!feof($read_stream)) {
1376
+ $buffer = fread($read_stream, $chunkSize);
1377
+ echo $buffer;
1378
+ }
1379
+ fclose($read_stream);
1380
 
1381
+ wp_die();
 
 
 
 
 
 
1382
 
1383
+ }
1384
 
1385
+ /*
1386
  * Restore upload backup
1387
  */
1388
+ public function restore_upload_backup()
1389
+ {
1390
+ $this->check_access();
1391
+
1392
+ $return = array();
1393
 
1394
+ $return['part'] = 0;
1395
+ $return['total_parts'] = 0;
1396
+ $return['uploaded_size'] = 0;
1397
+ $is_multipart = 0;
1398
 
1399
+ $file = $this->xcloner_sanitization->sanitize_input_as_string($_POST['file']);
1400
+ $hash = $this->xcloner_sanitization->sanitize_input_as_string($_POST['hash']);
1401
 
1402
+ if (isset($_POST['part'])) {
1403
+ $return['part'] = $this->xcloner_sanitization->sanitize_input_as_int($_POST['part']);
1404
+ }
1405
 
1406
+ if (isset($_POST['uploaded_size'])) {
1407
+ $return['uploaded_size'] = $this->xcloner_sanitization->sanitize_input_as_int($_POST['uploaded_size']);
1408
+ }
1409
 
1410
+ $start = $this->xcloner_sanitization->sanitize_input_as_string($_POST['start']);
1411
+ $target_url = $this->xcloner_sanitization->sanitize_input_as_string($_POST['target_url']);
1412
 
1413
+ $return['total_size'] = $this->xcloner_file_system->get_backup_size($file);
1414
 
1415
+ if ($this->xcloner_file_system->is_multipart($file)) {
1416
+ $backup_parts = $this->xcloner_file_system->get_multipart_files($file);
1417
 
1418
+ $return['total_parts'] = sizeof($backup_parts) + 1;
1419
 
1420
+ if ($return['part'] and isset($backup_parts[$return['part'] - 1])) {
1421
+ $file = $backup_parts[$return['part'] - 1];
1422
+ }
1423
 
1424
+ $is_multipart = 1;
1425
+ }
1426
 
1427
+ try {
1428
 
1429
+ $xcloner_file_transfer = $this->get_xcloner_container()->get_xcloner_file_transfer();
1430
+ $xcloner_file_transfer->set_target($target_url);
1431
+ $return['start'] = $xcloner_file_transfer->transfer_file($file, $start, $hash);
1432
 
1433
+ }catch (Exception $e) {
1434
 
1435
+ $return = array();
1436
+ $return['error'] = true;
1437
+ $return['status'] = 500;
1438
+ $return['message'] = "CURL communication error with the restore host. ".$e->getMessage();
1439
+ $this->send_response($return, 0);
1440
 
1441
+ }
1442
 
1443
+ $return['status'] = 200;
1444
 
1445
+ //we have finished the upload
1446
+ if (!$return['start'] and $is_multipart) {
1447
+ $return['part']++;
1448
+ $return['uploaded_size'] += $this->xcloner_file_system->get_storage_filesystem()->getSize($file);
1449
+ }
1450
 
1451
+ $this->send_response($return, 0);
1452
+ }
1453
 
1454
+ /*
1455
  * Restore backup
1456
  */
1457
+ public function restore_backup()
1458
+ {
1459
+ $this->check_access();
1460
 
1461
+ define("XCLONER_PLUGIN_ACCESS", 1);
1462
+ include_once(dirname(__DIR__).DS."restore".DS."xcloner_restore.php");
1463
 
1464
+ return;
1465
+ }
1466
 
1467
+ /*
1468
  *
1469
  * Send the json response back
1470
  *
1471
  */
1472
+ private function send_response($data, $attach_hash = 1)
1473
+ {
1474
 
1475
+ if ($attach_hash and null !== $this->xcloner_settings->get_hash()) {
1476
+ $data['hash'] = $this->xcloner_settings->get_hash();
1477
+ }
1478
 
1479
+ if (ob_get_length()) {
1480
+ ob_clean();
1481
+ }
1482
+ wp_send_json($data);
1483
 
1484
+ }
 
1485
  }
includes/class-xcloner-archive.php CHANGED
@@ -36,171 +36,181 @@ use splitbrain\PHPArchive\FileInfo;
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
  *
@@ -213,31 +223,35 @@ class Xcloner_Archive extends Tar
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
  *
@@ -251,480 +265,490 @@ class Xcloner_Archive extends Tar
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
- *
722
- * If $file is empty, the tar file will be created in memory
723
- *
724
- * @param string $file
725
- * @throws ArchiveIOException
726
- */
727
- /*
 
 
 
728
  public function openForAppend($file = '')
729
  {
730
  $this->file = $file;
@@ -754,17 +778,17 @@ class Xcloner_Archive extends Tar
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);
@@ -820,15 +844,15 @@ class Xcloner_Archive extends Tar
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);
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
+ * The backup name encryption suffix
68
  * @var string
69
  */
70
+ private $encrypt_suffix = "-enc";
71
+
72
+ /**
73
+ * Archive name
74
+ * @var string
75
+ */
76
+ private $archive_name;
77
+ /**
78
+ * @var Tar
79
+ */
80
+ private $backup_archive;
81
+ /**
82
+ * @var Xcloner_File_System
83
+ */
84
+ private $filesystem;
85
+ /**
86
+ * @var Xcloner_Logger
87
+ */
88
+ private $logger;
89
+ /**
90
+ * @var Xcloner_Settings
91
+ */
92
+ private $xcloner_settings;
93
+
94
+ /**
95
+ * [__construct description]
96
+ * @param Xcloner $xcloner_container XCloner Container
97
+ * @param string $archive_name Achive Name
98
+ */
99
+ public function __construct(Xcloner $xcloner_container, $archive_name = "")
100
+ {
101
+ $this->filesystem = $xcloner_container->get_xcloner_filesystem();
102
+ $this->logger = $xcloner_container->get_xcloner_logger()->withName("xcloner_archive");
103
+ $this->xcloner_settings = $xcloner_container->get_xcloner_settings();
104
+
105
+ if ($value = $this->xcloner_settings->get_xcloner_option('xcloner_size_limit_per_request')) {
106
+ $this->file_size_per_request_limit = $value * 1024 * 1024;
107
+ } //MB
108
+
109
+ if ($value = $this->xcloner_settings->get_xcloner_option('xcloner_files_to_process_per_request')) {
110
+ $this->files_to_process_per_request = $value;
111
+ }
112
 
113
+ if ($value = get_option('xcloner_backup_compression_level')) {
114
+ $this->compression_level = $value;
115
+ }
116
 
117
+ if ($value = get_option('xcloner_split_backup_limit')) {
118
+ $this->xcloner_split_backup_limit = $value;
119
+ }
120
 
121
+ $this->xcloner_split_backup_limit = $this->xcloner_split_backup_limit * 1024 * 1024; //transform to bytes
122
 
123
+ if (isset($archive_name) && $archive_name) {
124
+ $this->set_archive_name($archive_name);
125
+ }
126
+ }
127
 
128
+ /*
129
  * Rename backup archive
130
  *
131
  * @param string $old_name
132
  * @param string $new_name
133
  *
134
  */
135
+ public function rename_archive($old_name, $new_name)
136
+ {
137
+ $this->logger->info(sprintf("Renaming backup archive %s to %s", $old_name, $new_name));
138
+ $storage_filesystem = $this->filesystem->get_storage_filesystem();
139
+ $storage_filesystem->rename($old_name, $new_name);
140
+ }
141
+
142
+ /*
143
  *
144
  * Set the backup archive name
145
  *
146
  */
147
+ public function set_archive_name($name = "", $part = 0, $encrypt_prefix = false)
148
+ {
149
 
150
+ $this->archive_name = $this->filesystem->process_backup_name($name);
151
 
152
+ if($encrypt_prefix) {
153
+ $this->archive_name .= $this->encrypt_suffix;
154
+ }
155
 
156
+ if ($diff_timestamp_start = $this->filesystem->get_diff_timestamp_start()) {
157
+ //$this->archive_name = $this->archive_name."-diff-".date("Y-m-d_H-i",$diff_timestamp_start);
158
+ $new_name = $this->archive_name;
159
 
160
+ if (!stristr($new_name, "-diff")) {
161
+ $new_name = $this->archive_name."-diff".date("Y-m-d_H-i", $diff_timestamp_start);
162
+ }
163
 
164
+ $this->archive_name = $new_name;
165
 
166
+ }
 
 
 
 
167
 
168
+ if (isset($part) and $part) {
169
+ $new_name = preg_replace('/-part(\d*)/', "-part".$part, $this->archive_name);
170
+ if (!stristr($new_name, "-part")) {
171
+ $new_name = $this->archive_name."-part".$part;
172
+ }
173
 
174
+ $this->archive_name = $new_name;
175
+ }
176
 
177
+ return $this;
178
+ }
179
+
180
+ /*
181
  *
182
  * Returns the backup archive name
183
  *
184
  * @return string archive name
185
  */
186
+ public function get_archive_name()
187
+ {
188
+ return $this->archive_name;
189
+ }
190
 
191
+ /*
192
  *
193
  * Returns the multipart naming for the backup archive
194
  *
195
  * @return string multi-part backup name
196
  */
197
+ public function get_archive_name_multipart()
198
+ {
199
+ $new_name = preg_replace('/-part(\d*)/', "", $this->archive_name);
200
+ return $new_name."-multipart".$this->xcloner_settings->get_backup_extension_name(".csv");
201
+ }
202
 
203
+ /*
204
  *
205
  * Returns the full backup name including extension
206
  *
207
  */
208
+ public function get_archive_name_with_extension()
209
+ {
210
+ return $this->archive_name.$this->xcloner_settings->get_backup_extension_name();
211
+ }
212
 
213
+ /*
214
  *
215
  * Send notification error by E-Mail
216
  *
223
  *
224
  * @return bool
225
  */
 
 
226
 
227
+ /**
228
+ * @param string $error_message
229
+ */
230
+ public function send_notification_error($to, $from, $subject, $backup_name, $params, $error_message)
231
+ {
232
 
233
+ $body = "";
234
+ $body .= sprintf(__("Backup Site Url: %s"), get_site_url());
235
+ $body .= "<br /><>";
236
 
237
+ $body .= sprintf(__("Error Message: %s"), $error_message);
238
 
239
+ $this->logger->info(sprintf("Sending backup error notification to %s", $to));
240
 
241
+ $admin_email = get_option("admin_email");
242
 
243
+ $headers = array('Content-Type: text/html; charset=UTF-8');
244
+
245
+ if ($admin_email and $from) {
246
+ $headers[] = 'From: '.$from.' <'.$admin_email.'>';
247
+ }
248
 
249
+ $return = wp_mail($to, $subject, $body, $headers);
250
 
251
+ return $return;
252
+ }
253
 
254
+ /*
255
  *
256
  * Send backup archive notfication by E-Mail
257
  *
265
  *
266
  * @return bool
267
  */
268
+ public function send_notification(
269
+ $to,
270
+ $from,
271
+ $subject,
272
+ $backup_name,
273
+ $params,
274
+ $error_message = "",
275
+ $additional = array()
276
+ ) {
277
+ if (!$from) {
278
+ $from = "XCloner Backup";
279
+ }
280
 
281
+ if (($error_message)) {
282
+ return $this->send_notification_error($to, $from, $subject, $backup_name, $params, $error_message);
283
+ }
284
 
285
+ $params = (array)$params;
286
 
287
+ if (!$subject) {
288
+ $subject = sprintf(__("New backup generated %s"), $backup_name);
289
+ }
290
 
291
+ $body = sprintf(__("Generated Backup Size: %s"), size_format($this->filesystem->get_backup_size($backup_name)));
292
+ $body .= "<br /><br />";
293
 
294
+ if (isset($additional['lines_total'])) {
295
+ $body .= sprintf(__("Total files added: %s"), $additional['lines_total']);
296
+ $body .= "<br /><br />";
297
+ }
298
 
299
+ $backup_parts = $this->filesystem->get_multipart_files($backup_name);
300
 
301
+ if (!$backups_counter = sizeof($backup_parts)) {
302
+ $backups_counter = 1;
303
+ }
304
 
305
+ $body .= sprintf(__("Backup Parts: %s"), $backups_counter);
306
+ $body .= "<br />";
307
 
308
+ if (sizeof($backup_parts)) {
309
+ $body .= implode("<br />", $backup_parts);
310
+ $body .= "<br />";
311
+ }
312
 
313
+ $body .= "<br />";
314
 
315
+ $body .= sprintf(__("Backup Site Url: %s"), get_site_url());
316
+ $body .= "<br />";
317
 
318
+ if (isset($params['backup_params']->backup_comments)) {
319
+ $body .= __("Backup Comments: ").$params['backup_params']->backup_comments;
320
+ $body .= "<br /><br />";
321
+ }
322
 
323
+ if ($this->xcloner_settings->get_xcloner_option('xcloner_enable_log')) {
324
+ $body .= __("Latest 50 Log Lines: ")."<br />".implode("<br />\n",
325
+ $this->logger->getLastDebugLines(50));
326
+ }
327
 
328
+ $attachments = $this->filesystem->get_backup_attachments();
329
 
330
+ $attachments_archive = $this->xcloner_settings->get_xcloner_tmp_path().DS."info.tgz";
331
 
332
+ $tar = new Tar();
333
+ $tar->create($attachments_archive);
334
 
335
+ foreach ($attachments as $key => $file) {
336
+ $tar->addFile($file, basename($file));
337
+ }
338
+ $tar->close();
339
 
340
+ $this->logger->info(sprintf("Sending backup notification to %s", $to));
341
 
342
+ $admin_email = get_option("admin_email");
343
 
344
+ $headers = array('Content-Type: text/html; charset=UTF-8', 'From: '.$from.' <'.$admin_email.'>');
345
 
346
+ $return = wp_mail($to, $subject, $body, $headers, array($attachments_archive));
347
 
348
+ return $return;
349
+ }
350
 
351
+ /*
352
  *
353
  * Incremental Backup method
354
  *
355
  */
356
+ public function start_incremental_backup($backup_params, $extra_params, $init)
357
+ {
358
+ $return = array();
359
 
360
+ if (!isset($extra_params['backup_part'])) {
361
+ $extra_params['backup_part'] = 0;
362
+ }
363
 
364
+ $return['extra']['backup_part'] = $extra_params['backup_part'];
365
 
366
+ if (isset($extra_params['backup_archive_name'])) {
367
+ $this->set_archive_name($extra_params['backup_archive_name'], $return['extra']['backup_part']);
368
+ } else {
369
+ $encrypt = false;
370
+ if(isset($backup_params['backup_encrypt']) && $backup_params['backup_encrypt']) {
371
+ $encrypt = true;
372
+ }
373
+ $this->set_archive_name($backup_params['backup_name'], 0, $encrypt);
374
+ }
375
 
376
+ if (!$this->get_archive_name()) {
377
+ $this->set_archive_name();
378
+ }
379
 
380
+ $this->backup_archive = new Tar();
381
+ $this->backup_archive->setCompression($this->compression_level);
382
 
383
+ $archive_info = $this->filesystem->get_storage_path_file_info($this->get_archive_name_with_extension());
384
 
385
+ if ($init) {
386
+ $this->logger->info(sprintf(__("Initializing the backup archive %s"), $this->get_archive_name()));
387
 
388
+ $this->backup_archive->create($archive_info->getPath().DS.$archive_info->getFilename());
389
 
390
+ $return['extra']['backup_init'] = 1;
391
 
392
+ } else {
393
+ $this->logger->info(sprintf(__("Opening for append the backup archive %s"), $this->get_archive_name()));
394
 
395
+ $this->backup_archive->openForAppend($archive_info->getPath().DS.$archive_info->getFilename());
396
 
397
+ $return['extra']['backup_init'] = 0;
398
 
399
+ }
400
 
401
+ $return['extra']['backup_archive_name'] = $this->get_archive_name();
402
+ $return['extra']['backup_archive_name_full'] = $this->get_archive_name_with_extension();
403
 
404
+ if (!isset($extra_params['start_at_line'])) {
405
+ $extra_params['start_at_line'] = 0;
406
+ }
407
 
408
+ if (!isset($extra_params['start_at_byte'])) {
409
+ $extra_params['start_at_byte'] = 0;
410
+ }
411
 
412
+ if (!$this->filesystem->get_tmp_filesystem()->has($this->filesystem->get_included_files_handler())) {
413
+ $this->logger->error(sprintf("Missing the includes file handler %s, aborting...",
414
+ $this->filesystem->get_included_files_handler()));
415
 
416
+ $return['finished'] = 1;
417
+ return $return;
418
+ }
419
 
420
+ $included_files_handler = $this->filesystem->get_included_files_handler(1);
421
 
422
+ $file = new SplFileObject($included_files_handler);
423
 
424
+ $file->seek(PHP_INT_MAX);
425
 
426
+ $return['extra']['lines_total'] = ($file->key() - 1);
427
 
428
+ //we skip the first CSV line with headers
429
+ if (!$extra_params['start_at_line']) {
430
+ $file->seek(1);
431
+ } else {
432
+ $file->seek($extra_params['start_at_line'] + 1);
433
+ }
434
 
435
+ $this->processed_size_bytes = 0;
436
 
437
+ $counter = 0;
438
 
439
+ $start_byte = $extra_params['start_at_byte'];
440
 
441
+ $byte_limit = 0;
442
 
443
+ while (!$file->eof() and $counter <= $this->files_to_process_per_request) {
444
+ $current_line_str = $file->current();
445
 
446
+ $line = str_getcsv($current_line_str);
447
 
448
+ $relative_path = stripslashes($line[0]);
449
 
450
+ $start_filesystem = "start_filesystem";
451
 
452
+ if (isset($line[4])) {
453
+ $start_filesystem = $line[4];
454
+ }
455
 
456
+ //$adapter = $this->filesystem->get_adapter($start_filesystem);
457
 
458
+ if (!$relative_path || !$this->filesystem->get_filesystem($start_filesystem)->has($relative_path)) {
459
+ if ($relative_path != "") {
460
+ $this->logger->error(sprintf("Could not add file %b to backup archive, file not found",
461
+ $relative_path));
462
+ }
463
 
464
+ $extra_params['start_at_line']++;
465
+ $file->next();
466
+ continue;
467
+ }
468
 
469
+ $file_info = $this->filesystem->get_filesystem($start_filesystem)->getMetadata($relative_path);
470
 
471
+ if (!isset($file_info['size'])) {
472
+ $file_info['size'] = 0;
473
+ }
474
 
475
+ if ($start_filesystem == "tmp_filesystem") {
476
+ $file_info['archive_prefix_path'] = $this->xcloner_settings->get_xcloner_tmp_path_suffix();
477
+ }
478
 
479
+ $byte_limit = (int)$this->file_size_per_request_limit / 512;
480
 
481
+ $append = 0;
482
 
483
+ if ($file_info['size'] > $byte_limit * 512 or $start_byte) {
484
+ $append = 1;
485
+ }
486
 
487
+ if (!isset($return['extra']['backup_size'])) {
488
+ $return['extra']['backup_size'] = 0;
489
+ }
490
 
491
+ $return['extra']['backup_size'] = $archive_info->getSize();
492
 
493
+ $estimated_new_size = $return['extra']['backup_size'] + $file_info['size'];
494
 
495
+ //we create a new backup part if we reach the Split Achive Limit
496
+ if ($this->xcloner_split_backup_limit and ($estimated_new_size > $this->xcloner_split_backup_limit) and (!$start_byte)) {
497
+ $this->logger->info(sprintf("Backup size limit %s bytes reached, file add estimate %s, attempt to create a new archive ",
498
+ $this->xcloner_split_backup_limit, $estimated_new_size));
499
+ list($archive_info, $return['extra']['backup_part']) = $this->create_new_backup_part($return['extra']['backup_part']);
500
 
501
+ if ($file_info['size'] > $this->xcloner_split_backup_limit) {
502
+ $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",
503
+ $file_info['path'], $file_info['size'], $this->xcloner_split_backup_limit));
504
+ $extra_params['start_at_line']++;
505
+ }
506
 
507
+ $return['extra']['start_at_line'] = $extra_params['start_at_line'];
508
+ $return['extra']['start_at_byte'] = 0;
509
 
510
+ $return['finished'] = 0;
511
 
512
+ return $return;
513
+ }
514
 
515
+ list($bytes_wrote, $last_position) = $this->add_file_to_archive($file_info, $start_byte, $byte_limit,
516
+ $append, $start_filesystem);
517
+ $this->processed_size_bytes += $bytes_wrote;
518
 
519
+ //echo" - processed ".$this->processed_size_bytes." bytes ".$this->file_size_per_request_limit." last_position:".$last_position." \n";
520
+ $return['extra']['processed_file'] = $file_info['path'];
521
+ $return['extra']['processed_file_size'] = $file_info['size'];
522
+ $return['extra']['backup_size'] = $archive_info->getSize();
523
 
524
+ if ($last_position > 0) {
525
+ $start_byte = $last_position;
526
+ } else {
527
+ $extra_params['start_at_line']++;
528
+ $file->next();
529
+ $start_byte = 0;
530
+ $counter++;
531
+ }
532
 
533
+ if ($this->processed_size_bytes >= $this->file_size_per_request_limit) {
534
+ clearstatcache();
535
+ $return['extra']['backup_size'] = $archive_info->getSize();
536
 
537
+ $return['finished'] = 0;
538
+ $return['extra']['start_at_line'] = $extra_params['start_at_line'];
539
+ $return['extra']['start_at_byte'] = $last_position;
540
+ $this->logger->info(sprintf("Reached the maximum %s request data limit, returning response",
541
+ $this->file_size_per_request_limit));
542
+ return $return;
543
+ }
544
+ }
545
 
546
+ if (!$file->eof()) {
547
+ clearstatcache();
548
+ $return['extra']['backup_size'] = $archive_info->getSize();
549
 
550
+ $return['finished'] = 0;
551
+ $return['extra']['start_at_line'] = $extra_params['start_at_line'];
552
+ $return['extra']['start_at_byte'] = $last_position;
553
+ $this->logger->info(sprintf("We have reached the maximum files to process per request limit of %s, returning response",
554
+ $this->files_to_process_per_request));
555
 
556
+ return $return;
557
+ }
558
 
559
+ //close the backup archive by adding 2*512 blocks of zero bytes
560
+ $this->logger->info(sprintf("Closing the backup archive %s with 2*512 zero bytes blocks.",
561
+ $this->get_archive_name_with_extension()));
562
+ $this->backup_archive->close();
563
 
564
+ /**
565
+ * XCloner HOOK backup_archive_finished.
566
+ *
567
+ * This will get triggered when a backup archive is finished writing.
568
+ */
569
+ //do_action('backup_archive_finished', $this->backup_archive, $this);
570
 
571
+ //updating archive_info
572
+ $archive_info = $this->filesystem->get_storage_path_file_info($this->get_archive_name_with_extension());
573
 
574
+ if ($return['extra']['backup_part']) {
575
+ $this->write_multipart_file($this->get_archive_name_with_extension());
576
+ }
577
 
578
+ $return['extra']['start_at_line'] = $extra_params['start_at_line'] - 1;
579
 
580
+ if (isset($file_info)) {
581
+ $return['extra']['processed_file'] = $file_info['path'];
582
+ $return['extra']['processed_file_size'] = $file_info['size'];
583
+ }
584
 
585
+ clearstatcache();
586
+ $return['extra']['backup_size'] = $archive_info->getSize();
587
 
588
+ $return['finished'] = 1;
589
+ return $return;
590
+ }
591
 
592
+ /*
593
  *
594
  * Write multipart file components
595
  *
596
  */
597
+ private function write_multipart_file($path = "")
598
+ {
599
+ if (!$path) {
600
+ $path = $this->get_archive_name_with_extension();
601
+ }
602
 
603
+ $file = $this->filesystem->get_filesystem("storage_filesystem_append")->getMetadata($path);
604
+ //print_r($file_info);
605
+ $line = '"'.$file['path'].'","'.$file['timestamp'].'","'.$file['size'].'"'.PHP_EOL;
606
 
607
 
608
+ $this->filesystem->get_filesystem("storage_filesystem_append")
609
+ ->write($this->get_archive_name_multipart(), $line);
610
+ }
611
 
612
+ /*
613
  *
614
  * Create a new backup part
615
  *
616
  */
617
+ private function create_new_backup_part($part = 0)
618
+ {
619
+ //close the backup archive by adding 2*512 blocks of zero bytes
620
+ $this->logger->info(sprintf("Closing the backup archive %s with 2*512 zero bytes blocks.",
621
+ $this->get_archive_name_with_extension()));
622
+ $this->backup_archive->close();
623
+
624
+ if (!$part) {
625
+ $old_name = $this->get_archive_name_with_extension();
626
+ $this->set_archive_name($this->get_archive_name(), ++$part);
627
+ $this->rename_archive($old_name, $this->get_archive_name_with_extension());
628
+
629
+ if ($this->filesystem->get_storage_filesystem()->has($this->get_archive_name_multipart())) {
630
+ $this->filesystem->get_storage_filesystem()->delete($this->get_archive_name_multipart());
631
+ }
632
+
633
+ $this->write_multipart_file($this->get_archive_name_with_extension());
634
+
635
+ } else {
636
+ $this->logger->info(sprintf("Creating new multipart info file %s",
637
+ $this->get_archive_name_with_extension()));
638
+ $this->write_multipart_file($this->get_archive_name_with_extension());
639
+ }
640
 
641
+ $this->set_archive_name($this->get_archive_name(), ++$part);
642
 
643
+ $this->logger->info(sprintf("Creating new backup archive part %s", $this->get_archive_name_with_extension()));
644
 
645
+ $this->backup_archive = new Tar();
646
+ $this->backup_archive->setCompression($this->compression_level);
647
+ $archive_info = $this->filesystem->get_storage_path_file_info($this->get_archive_name_with_extension());
648
+ $this->backup_archive->create($archive_info->getPath().DS.$archive_info->getFilename());
649
 
650
+ return array($archive_info, $part);
651
 
652
+ }
653
 
654
+ /*
655
  *
656
  * Add file to archive
657
  *
658
  */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
659
 
660
+ /**
661
+ * @param integer $append
662
+ */
663
+ public function add_file_to_archive($file_info, $start_at_byte, $byte_limit = 0, $append, $filesystem)
664
+ {
665
 
666
+ $start_adapter = $this->filesystem->get_adapter($filesystem);
667
+ $start_filesystem = $this->filesystem->get_adapter($filesystem);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
668
 
669
+ if (!$file_info['path']) {
670
+ return;
671
+ }
672
 
673
+ if (isset($file_info['archive_prefix_path'])) {
674
+ $file_info['target_path'] = $file_info['archive_prefix_path']."/".$file_info['path'];
675
+ } else {
676
+ $file_info['target_path'] = $file_info['path'];
677
+ }
 
 
 
 
 
 
 
 
 
 
678
 
679
+ $last_position = $start_at_byte;
680
+
681
+ //$start_adapter = $this->filesystem->get_start_adapter();
682
+
683
+ if (!$append) {
684
+ $bytes_wrote = $file_info['size'];
685
+ $this->logger->info(sprintf("Adding %s bytes of file %s to archive %s ", $bytes_wrote,
686
+ $file_info['target_path'], $this->get_archive_name_with_extension()));
687
+ $this->backup_archive->addFile($start_adapter->applyPathPrefix($file_info['path']),
688
+ $file_info['target_path']);
689
+ } else {
690
+ $tmp_file = md5($file_info['path']);
691
+
692
+ //we isolate file to tmp if we are at byte 0, the starting point of file reading
693
+ if (!$start_at_byte) {
694
+ $this->logger->info(sprintf("Copying %s file to tmp filesystem file %s to prevent reading changes",
695
+ $file_info['path'], $tmp_file));
696
+ $file_stream = $start_filesystem->readStream($file_info['path']);
697
+
698
+ if (is_resource($file_stream['stream'])) {
699
+ $this->filesystem->get_tmp_filesystem()->writeStream($tmp_file, $file_stream['stream']);
700
+ }
701
+ }
702
+
703
+ if ($this->filesystem->get_tmp_filesystem()->has($tmp_file)) {
704
+ $is_tmp = 1;
705
+ $last_position = $this->backup_archive->appendFileData($this->filesystem->get_tmp_filesystem_adapter()
706
+ ->applyPathPrefix($tmp_file),
707
+ $file_info['target_path'], $start_at_byte, $byte_limit);
708
+ } else {
709
+ $is_tmp = 0;
710
+ $last_position = $this->backup_archive->appendFileData($start_adapter->applyPathPrefix($file_info['path']),
711
+ $file_info['target_path'], $start_at_byte, $byte_limit);
712
+ }
713
+
714
+
715
+ if ($last_position == -1) {
716
+ $bytes_wrote = $file_info['size'] - $start_at_byte;
717
+ } else {
718
+ $bytes_wrote = $last_position - $start_at_byte;
719
+ }
720
+
721
+
722
+ if ($is_tmp) {
723
+ $this->logger->info(sprintf("Appended %s bytes, starting position %s, of tmp file %s (%s) to archive %s ",
724
+ $bytes_wrote, $start_at_byte, $tmp_file, $file_info['target_path'], $this->get_archive_name()));
725
+ } else {
726
+ $this->logger->info(sprintf("Appended %s bytes, starting position %s, of original file %s to archive %s ",
727
+ $bytes_wrote, $start_at_byte, $file_info['target_path'], $tmp_file, $this->get_archive_name()));
728
+ }
729
+
730
+ //we delete here the isolated tmp file
731
+ if ($last_position == -1) {
732
+ if ($this->filesystem->get_tmp_filesystem_adapter()->has($tmp_file)) {
733
+ $this->logger->info(sprintf("Deleting %s from the tmp filesystem", $tmp_file));
734
+ $this->filesystem->get_tmp_filesystem_adapter()->delete($tmp_file);
735
+ }
736
+ }
737
 
738
+ }
 
739
 
740
+ return array($bytes_wrote, $last_position);
741
+ }
742
+
743
+ /**
744
+ * Open a TAR archive and put the file cursor at the end for data appending
745
+ *
746
+ * If $file is empty, the tar file will be created in memory
747
+ *
748
+ * @param string $file
749
+ * @throws ArchiveIOException
750
+ */
751
+ /*
752
  public function openForAppend($file = '')
753
  {
754
  $this->file = $file;
778
  }
779
  */
780
 
781
+ /**
782
+ * Append data to a file to the current TAR archive using an existing file in the filesystem
783
+ *
784
+ * @param string $file path to the original file
785
+ * @param int $start starting reading position in file
786
+ * @param int $end end position in reading multiple with 512
787
+ * @param string|FileInfo $fileinfo either the name to us in archive (string) or a FileInfo oject with
788
+ * all meta data, empty to take from original
789
+ * @throws ArchiveIOException
790
+ */
791
+ /*
792
  * public function appendFileData($file, $fileinfo = '', $start = 0, $limit = 0)
793
  {
794
  $end = $start+($limit*512);
844
  return $last_position;
845
  }*/
846
 
847
+ /**
848
+ * Adds a file to a TAR archive by appending it's data
849
+ *
850
+ * @param string $archive name of the archive file
851
+ * @param string $file name of the file to read data from
852
+ * @param string $start start position from where to start reading data
853
+ * @throws ArchiveIOException
854
+ */
855
+ /*public function addFileToArchive($archive, $file, $start = 0)
856
  {
857
  $this->openForAppend($archive);
858
  return $start = $this->appendFileData($file, $start, $this->file_size_per_request_limit);
includes/class-xcloner-database.php CHANGED
@@ -21,41 +21,42 @@
21
  */
22
 
23
 
24
- class Xcloner_Database extends wpdb{
25
 
26
 
27
- public $debug = 0;
28
- public $recordsPerSession = 10000;
29
- public $dbCompatibility = "";
30
  public $dbDropSyntax = 1;
31
  public $countRecords = 0;
32
 
33
  private $link;
34
  private $db_selected;
35
  private $logger;
 
36
  private $fs;
37
 
38
  private $TEMP_DBPROCESS_FILE = ".database";
39
  private $TEMP_DUMP_FILE = "database-backup.sql";
40
 
41
- public function __construct(Xcloner $xcloner_container, $wp_user="", $wp_pass="", $wp_db="", $wp_host="")
42
  {
43
- $this->logger = $xcloner_container->get_xcloner_logger()->withName("xcloner_database");
44
- $this->xcloner_settings = $xcloner_container->get_xcloner_settings();
45
- $this->fs = $xcloner_container->get_xcloner_filesystem();
46
 
47
- if($this->xcloner_settings->get_xcloner_option('xcloner_database_records_per_request'))
48
- $this->recordsPerSession = $this->xcloner_settings->get_xcloner_option('xcloner_database_records_per_request');
49
 
50
- if(!$this->recordsPerSession)
51
  $this->recordsPerSession = 100;
52
 
53
- if(!$wp_user && !$wp_pass && !$wp_host && !$wp_db )
54
  {
55
  $wp_host = $this->xcloner_settings->get_db_hostname();
56
  $wp_user = $this->xcloner_settings->get_db_username();
57
  $wp_pass = $this->xcloner_settings->get_db_password();
58
- $wp_db = $this->xcloner_settings->get_db_database();
59
  }
60
 
61
  parent::__construct($wp_user, $wp_pass, $wp_db, $wp_host);
@@ -71,7 +72,7 @@ class Xcloner_Database extends wpdb{
71
  */
72
  public function init($data, $start = 0)
73
  {
74
- if($start and $this->fs->get_tmp_filesystem()->has($this->TEMP_DBPROCESS_FILE)){
75
  $this->fs->get_tmp_filesystem()->delete($this->TEMP_DBPROCESS_FILE);
76
  }
77
 
@@ -90,7 +91,7 @@ class Xcloner_Database extends wpdb{
90
  "database_count"=>0,
91
  );
92
 
93
- if(!$this->xcloner_settings->get_enable_mysql_backup())
94
  {
95
  $return['finished'] = 1;
96
  return $return;
@@ -100,44 +101,44 @@ class Xcloner_Database extends wpdb{
100
 
101
  $this->init($params, $init);
102
 
103
- if($init)
104
  {
105
  $db_count = 0;
106
 
107
- if(isset($params['#']))
108
  {
109
- foreach($params['#'] as $database)
110
  {
111
- if(!isset($params[$database]) or !is_array($params[$database]))
112
  $params[$database] = array();
113
  }
114
  $db_count = -1;
115
  }
116
 
117
- if(isset($params) and is_array($params))
118
- foreach($params as $database=>$tables)
119
  {
120
- if($database != "#")
121
  {
122
  $stats = $this->write_backup_process_list($database, $tables);
123
- $return['stats']['tables_count'] += $stats['tables_count'];
124
- $return['stats']['total_records'] += $stats['total_records'];
125
  }
126
  }
127
 
128
- if(sizeof($params))
129
- $return['stats']['database_count'] = sizeof($params)+$db_count;
130
  else
131
  $return['stats']['database_count'] = 0;
132
 
133
  return $return;
134
  }
135
 
136
- if(!isset($extra_params['startAtLine']))
137
  $extra_params['startAtLine'] = 0;
138
- if(!isset($extra_params['startAtRecord']))
139
  $extra_params['startAtRecord'] = 0;
140
- if(!isset($extra_params['dumpfile']))
141
  $extra_params['dumpfile'] = "";
142
 
143
  $return = $this->process_incremental($extra_params['startAtLine'], $extra_params['startAtRecord'], $extra_params['dumpfile']);
@@ -148,13 +149,13 @@ class Xcloner_Database extends wpdb{
148
  public function log($message = "")
149
  {
150
 
151
- if($message){
152
- $this->logger->info( $message, array(""));
153
- }else{
154
- if($this->last_query)
155
- $this->logger->debug( $this->last_query, array(""));
156
- if($this->last_error)
157
- $this->logger->error( $this->last_error, array(""));
158
  }
159
 
160
  return;
@@ -169,7 +170,7 @@ class Xcloner_Database extends wpdb{
169
  */
170
  public function error($message)
171
  {
172
- $this->logger->error( $message, array(""));
173
 
174
  return;
175
  }
@@ -179,7 +180,6 @@ class Xcloner_Database extends wpdb{
179
  *
180
  * name: headers
181
  * @param
182
- * @return
183
  */
184
  private function headers()
185
  {
@@ -202,7 +202,7 @@ class Xcloner_Database extends wpdb{
202
 
203
  $query = "show tables in `".$database."`";
204
 
205
- $res = $this->get_results($query);
206
  $this->log();
207
 
208
  return count($res);
@@ -225,9 +225,9 @@ class Xcloner_Database extends wpdb{
225
  $databases_list[$i]['num_tables'] = $this->get_database_num_tables($this->dbname);
226
  $i++;
227
 
228
- if(is_array($databases))
229
- foreach( $databases as $db){
230
- if($db->Database != $this->dbname)
231
  {
232
  $databases_list[$i]['name'] = $db->Database;
233
  $databases_list[$i]['num_tables'] = $this->get_database_num_tables($db->Database);
@@ -243,7 +243,7 @@ class Xcloner_Database extends wpdb{
243
  *
244
  * name: list_tables
245
  * @param string $database
246
- * @param array $include
247
  * @param int $get_num_records
248
  * @return array $tablesList
249
  */
@@ -252,7 +252,7 @@ class Xcloner_Database extends wpdb{
252
  $tablesList[0] = array( );
253
  $inc = 0;
254
 
255
- if(!$database)
256
  $database = $this->dbname;
257
 
258
  $this->logger->debug(sprintf(("Listing tables in %s database"), $database));
@@ -260,14 +260,14 @@ class Xcloner_Database extends wpdb{
260
  $tables = $this->get_results("SHOW TABLES in `".$database."`");
261
  $this->log();
262
 
263
- foreach ($tables as $table){
264
 
265
  $table = array_values((array)$table)[0];
266
 
267
  $tablesList[$inc]['name'] = $table;
268
  $tablesList[$inc]['database'] = $database;
269
 
270
- if($get_num_records)
271
  {
272
  $records_num_result = $this->get_var("SELECT count(*) FROM `".$database."`.`".$table."`");
273
  $this->log();
@@ -277,14 +277,14 @@ class Xcloner_Database extends wpdb{
277
 
278
  $tablesList[$inc]['excluded'] = 0;
279
 
280
- if(sizeof($included) and is_array($included))
281
- if(!in_array($table, $included) )
282
  {
283
  $tablesList[$inc]['excluded'] = 1;
284
  $this->log(sprintf(__("Excluding table %s.%s from backup"), $table, $database));
285
  }
286
  $inc++;
287
- }
288
 
289
  return $tablesList;
290
 
@@ -299,7 +299,7 @@ class Xcloner_Database extends wpdb{
299
 
300
  $tables = $this->list_tables($dbname, $incl_tables, 1);
301
 
302
- if($this->dbname != $dbname)
303
  $dumpfile = $dbname."-backup.sql";
304
  else
305
  $dumpfile = $this->TEMP_DUMP_FILE;
@@ -308,8 +308,8 @@ class Xcloner_Database extends wpdb{
308
  $this->fs->get_tmp_filesystem_append()->write($this->TEMP_DBPROCESS_FILE, $line);
309
 
310
  // write this to the class and write to $TEMP_DBPROCESS_FILE file as database.table records
311
- foreach($tables as $key=>$table)
312
- if($table!= "" and !$tables[$key]['excluded']){
313
 
314
  $line = sprintf("`%s`.`%s`\t%s\t%s\n", $dbname, $tables[$key]['name'], $tables[$key]['records'], $tables[$key]['excluded']);
315
  $this->fs->get_tmp_filesystem_append()->write($this->TEMP_DBPROCESS_FILE, $line);
@@ -353,25 +353,25 @@ class Xcloner_Database extends wpdb{
353
  * int $dbDropSyntax - check if the DROP TABLE syntax should be added
354
  * @return array $return
355
  */
356
- public function process_incremental($startAtLine= 0, $startAtRecord = 0, $dumpfile = "", $dbCompatibility= ""){
357
 
358
  $count = 0;
359
  $return['finished'] = 0;
360
  $lines = array();
361
 
362
- if($this->fs->get_tmp_filesystem()->has($this->TEMP_DBPROCESS_FILE))
363
- $lines = array_filter(explode("\n",$this->fs->get_tmp_filesystem()->read($this->TEMP_DBPROCESS_FILE)));
364
 
365
- foreach ($lines as $buffer){
366
 
367
- if($count == $startAtLine)
368
  {
369
 
370
- $tableInfo =explode("\t", $buffer);
371
 
372
- if($tableInfo[0] == "###newdump###"){
373
  // we create a new mysql dump file
374
- if($dumpfile != ""){
375
  // we finished a previous one and write the footers
376
  $return['dumpsize'] = $this->data_footers($dumpfile);
377
  }
@@ -385,13 +385,13 @@ class Xcloner_Database extends wpdb{
385
  $startAtLine++;
386
  $return['new_dump'] = 1;
387
  //break;
388
- }else{
389
  //we export the table
390
- if($tableInfo[0] == "###enddump###")
391
  $return['endDump'] = 1;
392
 
393
  //table is excluded
394
- if($tableInfo[2])
395
  continue;
396
 
397
  $next = $startAtRecord + $this->recordsPerSession;
@@ -403,28 +403,28 @@ class Xcloner_Database extends wpdb{
403
 
404
  //return something to the browser
405
  $return['databaseName'] = $databaseName;
406
- $return['tableName'] = $tableName;
407
  $return['totalRecords'] = $tableInfo[1];
408
 
409
  $processed_records = 0;
410
 
411
- if(trim($tableName) !="" and !$tableInfo[2])
412
  $processed_records = $this->export_table($databaseName, $tableName, $startAtRecord, $this->recordsPerSession, $dumpfile);
413
 
414
- $return['processedRecords'] = $startAtRecord+$processed_records;
415
 
416
- if($next >= $tableInfo[1]) //we finished loading the records for next sessions, will go to the new record
417
  {
418
- $startAtLine ++;
419
  $startAtRecord = 0;
420
- }else{
421
  $startAtRecord = $startAtRecord + $this->recordsPerSession;
422
  }
423
 
424
  //$return['dbCompatibility'] = self::$dbCompatibility;
425
 
426
- $return['startAtLine'] = $startAtLine;
427
- $return['startAtRecord'] = $startAtRecord;
428
  $return['dumpfile'] = $dumpfile;
429
  $return['dumpsize'] = $this->fs->get_tmp_filesystem_append()->getSize($dumpfile);
430
 
@@ -442,15 +442,15 @@ class Xcloner_Database extends wpdb{
442
  }
443
 
444
  //while is finished, lets go home...
445
- if($dumpfile != ""){
446
  // we finished a previous one and write the footers
447
  $return['dumpsize'] = $this->data_footers($dumpfile);
448
  $return['dumpfile'] = ($dumpfile);
449
  }
450
  $return['finished'] = 1;
451
- $return['startAtLine'] = $startAtLine;
452
 
453
- if($this->fs->get_tmp_filesystem()->has($this->TEMP_DBPROCESS_FILE))
454
  $this->fs->get_tmp_filesystem()->delete($this->TEMP_DBPROCESS_FILE);
455
 
456
  $this->logger->debug(sprintf(("Database backup finished!")));
@@ -473,13 +473,18 @@ class Xcloner_Database extends wpdb{
473
  * handler $fd - file handler where to write the records
474
  * @return
475
  */
 
 
 
 
 
476
  public function export_table($databaseName, $tableName, $start, $limit, $dumpfile)
477
  {
478
  $this->logger->debug(sprintf(("Exporting table %s.%s data"), $databaseName, $tableName));
479
 
480
  $records = 0;
481
 
482
- if($start == 0)
483
  $this->dump_structure($databaseName, $tableName, $dumpfile);
484
 
485
  $start = intval($start);
@@ -487,36 +492,36 @@ class Xcloner_Database extends wpdb{
487
  //exporting the table content now
488
 
489
  $query = "SELECT * from `$databaseName`.`$tableName` Limit $start, $limit ;";
490
- if($this->use_mysqli)
491
  {
492
  $result = mysqli_query($this->dbh, $query);
493
  $mysql_fetch_function = "mysqli_fetch_array";
494
 
495
- }else{
496
  $result = mysql_query($query, $this->dbh);
497
  $mysql_fetch_function = "mysqli_fetch_array";
498
  }
499
  //$result = $this->get_results($query, ARRAY_N);
500
  //print_r($result); exit;
501
 
502
- if($result){
503
- while($row = $mysql_fetch_function($result, MYSQLI_ASSOC)){
504
 
505
  $this->fs->get_tmp_filesystem_append()->write($dumpfile, "INSERT INTO `$tableName` VALUES (");
506
  $arr = $row;
507
  $buffer = "";
508
  $this->countRecords++;
509
 
510
- foreach ($arr as $key => $value) {
511
  $value = $this->_real_escape($value);
512
 
513
- if(method_exists($this, 'remove_placeholder_escape')){
514
  $value = $this->remove_placeholder_escape($value);
515
  }
516
 
517
  $buffer .= "'".$value."', ";
518
  }
519
- $buffer = rtrim($buffer, ', ') . ");\n";
520
  $this->fs->get_tmp_filesystem_append()->write($dumpfile, $buffer);
521
  unset($buffer);
522
 
@@ -531,29 +536,29 @@ class Xcloner_Database extends wpdb{
531
 
532
  }
533
 
534
- public function dump_structure($databaseName, $tableName ,$dumpfile)
535
  {
536
  $this->log(sprintf(__("Dumping the structure for %s.%s table"), $databaseName, $tableName));
537
 
538
  $line = ("\n#\n# Table structure for table `$tableName`\n#\n\n");
539
  $this->fs->get_tmp_filesystem_append()->write($dumpfile, $line);
540
 
541
- if ($this->dbDropSyntax)
542
- {
543
  $line = ("\nDROP table IF EXISTS `$tableName`;\n");
544
  $this->fs->get_tmp_filesystem_append()->write($dumpfile, $line);
545
  }
546
 
547
  //$result = mysqli_query($this->dbh,"SHOW CREATE table `$databaseName`.`$tableName`;");
548
  $result = $this->get_row("SHOW CREATE table `$databaseName`.`$tableName`;", ARRAY_N);
549
- if($result){
550
  //$row = mysqli_fetch_row( $result);
551
  $line = ($result[1].";\n");
552
  $this->fs->get_tmp_filesystem_append()->write($dumpfile, $line);
553
  }
554
 
555
- $line = ( "\n#\n# End Structure for table `$tableName`\n#\n\n");
556
- $line .=("#\n# Dumping data for table `$tableName`\n#\n\n");
557
  $this->fs->get_tmp_filesystem_append()->write($dumpfile, $line);
558
 
559
  return;
@@ -576,7 +581,7 @@ class Xcloner_Database extends wpdb{
576
 
577
  }
578
 
579
- public function resetcountRecords(){
580
 
581
  $this->countRecords = 0;
582
 
@@ -584,7 +589,7 @@ class Xcloner_Database extends wpdb{
584
 
585
  }
586
 
587
- public function getcountRecords(){
588
 
589
  return $this->countRecords;
590
 
@@ -601,14 +606,14 @@ class Xcloner_Database extends wpdb{
601
  $return .= "# Powered by XCloner Site Backup\n";
602
  $return .= "# http://www.xcloner.com\n";
603
  $return .= "#\n";
604
- $return .= "# Host: " . get_site_url() . "\n";
605
- $return .= "# Generation Time: " . date("M j, Y \a\\t H:i") . "\n";
606
- $return .= "# PHP Version: " . phpversion() . "\n";
607
- $return .= "# Database Charset: ". $this->charset . "\n";
608
 
609
  $results = $this->get_results("SHOW VARIABLES LIKE \"%version%\";", ARRAY_N);
610
- if(isset($results)){
611
- foreach($results as $result){
612
 
613
  $return .= "# MYSQL ".$result[0].": ".$result[1]."\n";
614
 
@@ -618,13 +623,13 @@ class Xcloner_Database extends wpdb{
618
  $results = $this->get_results("SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME
619
  FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = '".$database."';");
620
 
621
- if(isset($results[0])){
622
 
623
  $return .= "# MYSQL DEFAULT_CHARACTER_SET_NAME: ".$results[0]->DEFAULT_CHARACTER_SET_NAME."\n";
624
  $return .= "# MYSQL SCHEMA_NAME: ".$results[0]->DEFAULT_COLLATION_NAME."\n";
625
  }
626
 
627
- $return .= "#\n# Database : `" . $database . "`\n# --------------------------------------------------------\n\n";
628
 
629
  $this->log(sprintf(__("Writing %s database dump headers"), $database));
630
 
21
  */
22
 
23
 
24
+ class Xcloner_Database extends wpdb {
25
 
26
 
27
+ public $debug = 0;
28
+ public $recordsPerSession = 10000;
29
+ public $dbCompatibility = "";
30
  public $dbDropSyntax = 1;
31
  public $countRecords = 0;
32
 
33
  private $link;
34
  private $db_selected;
35
  private $logger;
36
+ private $xcloner_settings;
37
  private $fs;
38
 
39
  private $TEMP_DBPROCESS_FILE = ".database";
40
  private $TEMP_DUMP_FILE = "database-backup.sql";
41
 
42
+ public function __construct(Xcloner $xcloner_container, $wp_user = "", $wp_pass = "", $wp_db = "", $wp_host = "")
43
  {
44
+ $this->logger = $xcloner_container->get_xcloner_logger()->withName("xcloner_database");
45
+ $this->xcloner_settings = $xcloner_container->get_xcloner_settings();
46
+ $this->fs = $xcloner_container->get_xcloner_filesystem();
47
 
48
+ if ($this->xcloner_settings->get_xcloner_option('xcloner_database_records_per_request'))
49
+ $this->recordsPerSession = $this->xcloner_settings->get_xcloner_option('xcloner_database_records_per_request');
50
 
51
+ if (!$this->recordsPerSession)
52
  $this->recordsPerSession = 100;
53
 
54
+ if (!$wp_user && !$wp_pass && !$wp_host && !$wp_db)
55
  {
56
  $wp_host = $this->xcloner_settings->get_db_hostname();
57
  $wp_user = $this->xcloner_settings->get_db_username();
58
  $wp_pass = $this->xcloner_settings->get_db_password();
59
+ $wp_db = $this->xcloner_settings->get_db_database();
60
  }
61
 
62
  parent::__construct($wp_user, $wp_pass, $wp_db, $wp_host);
72
  */
73
  public function init($data, $start = 0)
74
  {
75
+ if ($start and $this->fs->get_tmp_filesystem()->has($this->TEMP_DBPROCESS_FILE)) {
76
  $this->fs->get_tmp_filesystem()->delete($this->TEMP_DBPROCESS_FILE);
77
  }
78
 
91
  "database_count"=>0,
92
  );
93
 
94
+ if (!$this->xcloner_settings->get_enable_mysql_backup())
95
  {
96
  $return['finished'] = 1;
97
  return $return;
101
 
102
  $this->init($params, $init);
103
 
104
+ if ($init)
105
  {
106
  $db_count = 0;
107
 
108
+ if (isset($params['#']))
109
  {
110
+ foreach ($params['#'] as $database)
111
  {
112
+ if (!isset($params[$database]) or !is_array($params[$database]))
113
  $params[$database] = array();
114
  }
115
  $db_count = -1;
116
  }
117
 
118
+ if (isset($params) and is_array($params))
119
+ foreach ($params as $database=>$tables)
120
  {
121
+ if ($database != "#")
122
  {
123
  $stats = $this->write_backup_process_list($database, $tables);
124
+ $return['stats']['tables_count'] += $stats['tables_count'];
125
+ $return['stats']['total_records'] += $stats['total_records'];
126
  }
127
  }
128
 
129
+ if (sizeof($params))
130
+ $return['stats']['database_count'] = sizeof($params) + $db_count;
131
  else
132
  $return['stats']['database_count'] = 0;
133
 
134
  return $return;
135
  }
136
 
137
+ if (!isset($extra_params['startAtLine']))
138
  $extra_params['startAtLine'] = 0;
139
+ if (!isset($extra_params['startAtRecord']))
140
  $extra_params['startAtRecord'] = 0;
141
+ if (!isset($extra_params['dumpfile']))
142
  $extra_params['dumpfile'] = "";
143
 
144
  $return = $this->process_incremental($extra_params['startAtLine'], $extra_params['startAtRecord'], $extra_params['dumpfile']);
149
  public function log($message = "")
150
  {
151
 
152
+ if ($message) {
153
+ $this->logger->info($message, array(""));
154
+ } else {
155
+ if ($this->last_query)
156
+ $this->logger->debug($this->last_query, array(""));
157
+ if ($this->last_error)
158
+ $this->logger->error($this->last_error, array(""));
159
  }
160
 
161
  return;
170
  */
171
  public function error($message)
172
  {
173
+ $this->logger->error($message, array(""));
174
 
175
  return;
176
  }
180
  *
181
  * name: headers
182
  * @param
 
183
  */
184
  private function headers()
185
  {
202
 
203
  $query = "show tables in `".$database."`";
204
 
205
+ $res = $this->get_results($query);
206
  $this->log();
207
 
208
  return count($res);
225
  $databases_list[$i]['num_tables'] = $this->get_database_num_tables($this->dbname);
226
  $i++;
227
 
228
+ if (is_array($databases))
229
+ foreach ($databases as $db) {
230
+ if ($db->Database != $this->dbname)
231
  {
232
  $databases_list[$i]['name'] = $db->Database;
233
  $databases_list[$i]['num_tables'] = $this->get_database_num_tables($db->Database);
243
  *
244
  * name: list_tables
245
  * @param string $database
246
+ * @param array $included
247
  * @param int $get_num_records
248
  * @return array $tablesList
249
  */
252
  $tablesList[0] = array( );
253
  $inc = 0;
254
 
255
+ if (!$database)
256
  $database = $this->dbname;
257
 
258
  $this->logger->debug(sprintf(("Listing tables in %s database"), $database));
260
  $tables = $this->get_results("SHOW TABLES in `".$database."`");
261
  $this->log();
262
 
263
+ foreach ($tables as $table) {
264
 
265
  $table = array_values((array)$table)[0];
266
 
267
  $tablesList[$inc]['name'] = $table;
268
  $tablesList[$inc]['database'] = $database;
269
 
270
+ if ($get_num_records)
271
  {
272
  $records_num_result = $this->get_var("SELECT count(*) FROM `".$database."`.`".$table."`");
273
  $this->log();
277
 
278
  $tablesList[$inc]['excluded'] = 0;
279
 
280
+ if (sizeof($included) and is_array($included))
281
+ if (!in_array($table, $included))
282
  {
283
  $tablesList[$inc]['excluded'] = 1;
284
  $this->log(sprintf(__("Excluding table %s.%s from backup"), $table, $database));
285
  }
286
  $inc++;
287
+ }
288
 
289
  return $tablesList;
290
 
299
 
300
  $tables = $this->list_tables($dbname, $incl_tables, 1);
301
 
302
+ if ($this->dbname != $dbname)
303
  $dumpfile = $dbname."-backup.sql";
304
  else
305
  $dumpfile = $this->TEMP_DUMP_FILE;
308
  $this->fs->get_tmp_filesystem_append()->write($this->TEMP_DBPROCESS_FILE, $line);
309
 
310
  // write this to the class and write to $TEMP_DBPROCESS_FILE file as database.table records
311
+ foreach ($tables as $key=>$table)
312
+ if ($table != "" and !$tables[$key]['excluded']) {
313
 
314
  $line = sprintf("`%s`.`%s`\t%s\t%s\n", $dbname, $tables[$key]['name'], $tables[$key]['records'], $tables[$key]['excluded']);
315
  $this->fs->get_tmp_filesystem_append()->write($this->TEMP_DBPROCESS_FILE, $line);
353
  * int $dbDropSyntax - check if the DROP TABLE syntax should be added
354
  * @return array $return
355
  */
356
+ public function process_incremental($startAtLine = 0, $startAtRecord = 0, $dumpfile = "", $dbCompatibility = "") {
357
 
358
  $count = 0;
359
  $return['finished'] = 0;
360
  $lines = array();
361
 
362
+ if ($this->fs->get_tmp_filesystem()->has($this->TEMP_DBPROCESS_FILE))
363
+ $lines = array_filter(explode("\n", $this->fs->get_tmp_filesystem()->read($this->TEMP_DBPROCESS_FILE)));
364
 
365
+ foreach ($lines as $buffer) {
366
 
367
+ if ($count == $startAtLine)
368
  {
369
 
370
+ $tableInfo = explode("\t", $buffer);
371
 
372
+ if ($tableInfo[0] == "###newdump###") {
373
  // we create a new mysql dump file
374
+ if ($dumpfile != "") {
375
  // we finished a previous one and write the footers
376
  $return['dumpsize'] = $this->data_footers($dumpfile);
377
  }
385
  $startAtLine++;
386
  $return['new_dump'] = 1;
387
  //break;
388
+ } else {
389
  //we export the table
390
+ if ($tableInfo[0] == "###enddump###")
391
  $return['endDump'] = 1;
392
 
393
  //table is excluded
394
+ if ($tableInfo[2])
395
  continue;
396
 
397
  $next = $startAtRecord + $this->recordsPerSession;
403
 
404
  //return something to the browser
405
  $return['databaseName'] = $databaseName;
406
+ $return['tableName'] = $tableName;
407
  $return['totalRecords'] = $tableInfo[1];
408
 
409
  $processed_records = 0;
410
 
411
+ if (trim($tableName) != "" and !$tableInfo[2])
412
  $processed_records = $this->export_table($databaseName, $tableName, $startAtRecord, $this->recordsPerSession, $dumpfile);
413
 
414
+ $return['processedRecords'] = $startAtRecord + $processed_records;
415
 
416
+ if ($next >= $tableInfo[1]) //we finished loading the records for next sessions, will go to the new record
417
  {
418
+ $startAtLine++;
419
  $startAtRecord = 0;
420
+ } else {
421
  $startAtRecord = $startAtRecord + $this->recordsPerSession;
422
  }
423
 
424
  //$return['dbCompatibility'] = self::$dbCompatibility;
425
 
426
+ $return['startAtLine'] = $startAtLine;
427
+ $return['startAtRecord'] = $startAtRecord;
428
  $return['dumpfile'] = $dumpfile;
429
  $return['dumpsize'] = $this->fs->get_tmp_filesystem_append()->getSize($dumpfile);
430
 
442
  }
443
 
444
  //while is finished, lets go home...
445
+ if ($dumpfile != "") {
446
  // we finished a previous one and write the footers
447
  $return['dumpsize'] = $this->data_footers($dumpfile);
448
  $return['dumpfile'] = ($dumpfile);
449
  }
450
  $return['finished'] = 1;
451
+ $return['startAtLine'] = $startAtLine;
452
 
453
+ if ($this->fs->get_tmp_filesystem()->has($this->TEMP_DBPROCESS_FILE))
454
  $this->fs->get_tmp_filesystem()->delete($this->TEMP_DBPROCESS_FILE);
455
 
456
  $this->logger->debug(sprintf(("Database backup finished!")));
473
  * handler $fd - file handler where to write the records
474
  * @return
475
  */
476
+
477
+ /**
478
+ * @param integer $start
479
+ * @param integer $limit
480
+ */
481
  public function export_table($databaseName, $tableName, $start, $limit, $dumpfile)
482
  {
483
  $this->logger->debug(sprintf(("Exporting table %s.%s data"), $databaseName, $tableName));
484
 
485
  $records = 0;
486
 
487
+ if ($start == 0)
488
  $this->dump_structure($databaseName, $tableName, $dumpfile);
489
 
490
  $start = intval($start);
492
  //exporting the table content now
493
 
494
  $query = "SELECT * from `$databaseName`.`$tableName` Limit $start, $limit ;";
495
+ if ($this->use_mysqli)
496
  {
497
  $result = mysqli_query($this->dbh, $query);
498
  $mysql_fetch_function = "mysqli_fetch_array";
499
 
500
+ } else {
501
  $result = mysql_query($query, $this->dbh);
502
  $mysql_fetch_function = "mysqli_fetch_array";
503
  }
504
  //$result = $this->get_results($query, ARRAY_N);
505
  //print_r($result); exit;
506
 
507
+ if ($result) {
508
+ while ($row = $mysql_fetch_function($result, MYSQLI_ASSOC)) {
509
 
510
  $this->fs->get_tmp_filesystem_append()->write($dumpfile, "INSERT INTO `$tableName` VALUES (");
511
  $arr = $row;
512
  $buffer = "";
513
  $this->countRecords++;
514
 
515
+ foreach ($arr as $key => $value) {
516
  $value = $this->_real_escape($value);
517
 
518
+ if (method_exists($this, 'remove_placeholder_escape')) {
519
  $value = $this->remove_placeholder_escape($value);
520
  }
521
 
522
  $buffer .= "'".$value."', ";
523
  }
524
+ $buffer = rtrim($buffer, ', ').");\n";
525
  $this->fs->get_tmp_filesystem_append()->write($dumpfile, $buffer);
526
  unset($buffer);
527
 
536
 
537
  }
538
 
539
+ public function dump_structure($databaseName, $tableName, $dumpfile)
540
  {
541
  $this->log(sprintf(__("Dumping the structure for %s.%s table"), $databaseName, $tableName));
542
 
543
  $line = ("\n#\n# Table structure for table `$tableName`\n#\n\n");
544
  $this->fs->get_tmp_filesystem_append()->write($dumpfile, $line);
545
 
546
+ if ($this->dbDropSyntax)
547
+ {
548
  $line = ("\nDROP table IF EXISTS `$tableName`;\n");
549
  $this->fs->get_tmp_filesystem_append()->write($dumpfile, $line);
550
  }
551
 
552
  //$result = mysqli_query($this->dbh,"SHOW CREATE table `$databaseName`.`$tableName`;");
553
  $result = $this->get_row("SHOW CREATE table `$databaseName`.`$tableName`;", ARRAY_N);
554
+ if ($result) {
555
  //$row = mysqli_fetch_row( $result);
556
  $line = ($result[1].";\n");
557
  $this->fs->get_tmp_filesystem_append()->write($dumpfile, $line);
558
  }
559
 
560
+ $line = ("\n#\n# End Structure for table `$tableName`\n#\n\n");
561
+ $line .= ("#\n# Dumping data for table `$tableName`\n#\n\n");
562
  $this->fs->get_tmp_filesystem_append()->write($dumpfile, $line);
563
 
564
  return;
581
 
582
  }
583
 
584
+ public function resetcountRecords() {
585
 
586
  $this->countRecords = 0;
587
 
589
 
590
  }
591
 
592
+ public function getcountRecords() {
593
 
594
  return $this->countRecords;
595
 
606
  $return .= "# Powered by XCloner Site Backup\n";
607
  $return .= "# http://www.xcloner.com\n";
608
  $return .= "#\n";
609
+ $return .= "# Host: ".get_site_url()."\n";
610
+ $return .= "# Generation Time: ".date("M j, Y \a\\t H:i")."\n";
611
+ $return .= "# PHP Version: ".phpversion()."\n";
612
+ $return .= "# Database Charset: ".$this->charset."\n";
613
 
614
  $results = $this->get_results("SHOW VARIABLES LIKE \"%version%\";", ARRAY_N);
615
+ if (isset($results)) {
616
+ foreach ($results as $result) {
617
 
618
  $return .= "# MYSQL ".$result[0].": ".$result[1]."\n";
619
 
623
  $results = $this->get_results("SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME
624
  FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = '".$database."';");
625
 
626
+ if (isset($results[0])) {
627
 
628
  $return .= "# MYSQL DEFAULT_CHARACTER_SET_NAME: ".$results[0]->DEFAULT_CHARACTER_SET_NAME."\n";
629
  $return .= "# MYSQL SCHEMA_NAME: ".$results[0]->DEFAULT_COLLATION_NAME."\n";
630
  }
631
 
632
+ $return .= "#\n# Database : `".$database."`\n# --------------------------------------------------------\n\n";
633
 
634
  $this->log(sprintf(__("Writing %s database dump headers"), $database));
635
 
includes/class-xcloner-deactivator.php CHANGED
@@ -51,11 +51,11 @@ class Xcloner_Deactivator {
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();
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();
includes/class-xcloner-encryption.php ADDED
@@ -0,0 +1,394 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Created by PhpStorm.
4
+ * User: thinkovi
5
+ * Date: 2018-11-27
6
+ * Time: 12:11
7
+ */
8
+
9
+ //namespace XCloner;
10
+
11
+ class Xcloner_Encryption
12
+ {
13
+ const FILE_ENCRYPTION_BLOCKS = 1024 * 1024;
14
+ const FILE_ENCRYPTION_SUFFIX = ".encrypted";
15
+ const FILE_DECRYPTION_SUFFIX = ".decrypted";
16
+
17
+ private $xcloner_settings;
18
+ private $logger;
19
+ private $xcloner_container;
20
+ private $verification = false;
21
+
22
+ /**
23
+ * Xcloner_Encryption constructor.
24
+ * @param Xcloner $xcloner_container
25
+ */
26
+ public function __construct(Xcloner $xcloner_container)
27
+ {
28
+ $this->xcloner_container = $xcloner_container;
29
+ if (property_exists($xcloner_container, 'xcloner_settings')) {
30
+ $this->xcloner_settings = $xcloner_container->get_xcloner_settings();
31
+ } else {
32
+ $this->xcloner_settings = "";
33
+ }
34
+
35
+ if (property_exists($xcloner_container, 'xcloner_logger')) {
36
+ $this->logger = $xcloner_container->get_xcloner_logger()->withName("xcloner_encryption");
37
+ } else {
38
+ $this->logger = "";
39
+ }
40
+ }
41
+
42
+ /**
43
+ * Returns the backup encryption key
44
+ *
45
+ * @return string|null
46
+ */
47
+ public function get_backup_encryption_key()
48
+ {
49
+ if (is_object($this->xcloner_settings)) {
50
+ return $this->xcloner_settings->get_xcloner_encryption_key();
51
+ }
52
+
53
+ return null;
54
+
55
+ }
56
+
57
+ /**
58
+ * Check if provided filename has encrypted suffix
59
+ *
60
+ * @param $filename
61
+ * @return bool
62
+ */
63
+ public function is_encrypted_file($filename) {
64
+ $fp = fopen($this->get_xcloner_path().$filename, 'r');
65
+ if (is_resource($fp)) {
66
+ $encryption_length = fread($fp, 16);
67
+ fclose($fp);
68
+ if (is_numeric($encryption_length)) {
69
+ return true;
70
+ }
71
+ }
72
+
73
+ return false;
74
+
75
+ }
76
+
77
+ /**
78
+ * Returns the filename with encrypted suffix
79
+ *
80
+ * @param string $filename
81
+ * @return string
82
+ */
83
+ public function get_encrypted_target_backup_file_name($filename) {
84
+
85
+ return str_replace(self::FILE_DECRYPTION_SUFFIX, "", $filename).self::FILE_ENCRYPTION_SUFFIX;
86
+ }
87
+
88
+ /**
89
+ * Returns the filename without encrypted suffix
90
+ *
91
+ * @param string $filename
92
+ * @return string
93
+ */
94
+ public function get_decrypted_target_backup_file_name($filename) {
95
+
96
+ return str_replace(self::FILE_ENCRYPTION_SUFFIX, "", $filename).self::FILE_DECRYPTION_SUFFIX;
97
+ }
98
+
99
+ /**
100
+ * Encrypt the passed file and saves the result in a new file with ".enc" as suffix.
101
+ *
102
+ * @param string $source Path to file that should be encrypted
103
+ * @param string $dest File name where the encryped file should be written to.
104
+ * @param string $key The key used for the encryption
105
+ * @param int $start Start position for reading when doing incremental mode.
106
+ * @param string $iv The IV key to use.
107
+ * @param bool $verification Weather we should we try to verify the decryption.
108
+ * @return array|false Returns array or FALSE if an error occured
109
+ * @throws Exception
110
+ */
111
+ public function encrypt_file($source, $dest = "", $key = "", $start = 0, $iv = 0, $verification = true, $recursive = false)
112
+ {
113
+ if (is_object($this->logger)) {
114
+ $this->logger->info(sprintf('Encrypting file %s at position %d IV %s', $source, $start, base64_encode($iv)));
115
+ }
116
+
117
+ //$key = substr(sha1($key, true), 0, 16);
118
+ if (!$key) {
119
+ $key = $this->get_backup_encryption_key();
120
+ }
121
+ $key_digest = openssl_digest($key, "md5", true);
122
+
123
+ $keep_local = 1;
124
+ if (!$dest) {
125
+ $dest = $this->get_encrypted_target_backup_file_name($source);
126
+ $keep_local = 0;
127
+ }
128
+
129
+ if (!$iv || !$start) {
130
+ //$iv = openssl_random_pseudo_bytes(16);
131
+ $iv = str_pad(self::FILE_ENCRYPTION_BLOCKS, 16, "0000000000000000", STR_PAD_LEFT);
132
+ }
133
+
134
+ if (!$start) {
135
+ $fpOut = fopen($this->get_xcloner_path().$dest, 'w');
136
+ } else {
137
+ $fpOut = fopen($this->get_xcloner_path().$dest, 'a');
138
+ }
139
+
140
+ if (is_resource($fpOut)) {
141
+
142
+ // Put the initialization vector to the beginning of the file
143
+ if (!$start) {
144
+ fwrite($fpOut, $iv);
145
+ }
146
+
147
+ if (file_exists($this->get_xcloner_path().$source) &&
148
+ $fpIn = fopen($this->get_xcloner_path().$source, 'rb')) {
149
+
150
+ fseek($fpIn, (int)$start);
151
+
152
+ if (!feof($fpIn)) {
153
+
154
+ $plaintext = fread($fpIn, 16 * self::FILE_ENCRYPTION_BLOCKS);
155
+ $ciphertext = openssl_encrypt($plaintext, 'AES-128-CBC', $key_digest, OPENSSL_RAW_DATA, $iv);
156
+
157
+ // Use the first 16 bytes of the ciphertext as the next initialization vector
158
+ $iv = substr($ciphertext, 0, 16);
159
+ //$iv = openssl_random_pseudo_bytes(16);
160
+
161
+ fwrite($fpOut, $ciphertext);
162
+
163
+ $start = ftell($fpIn);
164
+
165
+ fclose($fpOut);
166
+
167
+ if (!feof($fpIn)) {
168
+ fclose($fpIn);
169
+ //echo "\n NEW:".$key.md5($iv);
170
+ //self::encryptFile($source, $dest, $key, $start, $iv);
171
+ if ($recursive) {
172
+ $this->encrypt_file($source, $dest, $key, $start, ($iv), $verification, $recursive);
173
+ } else {
174
+
175
+ if (($iv) != base64_decode(base64_encode($iv)))
176
+ {
177
+ throw new \Exception('Could not encode IV for transport');
178
+ }
179
+
180
+ return array(
181
+ "start" => $start,
182
+ "iv" => base64_encode($iv),
183
+ "target_file" => $dest,
184
+ "finished" => 0
185
+ );
186
+ }
187
+ }
188
+
189
+ }
190
+ } else {
191
+ if (is_object($this->logger)) {
192
+ $this->logger->error('Unable to read source file for encryption.');
193
+ }
194
+ throw new \Exception("Unable to read source file for encryption.");
195
+ }
196
+ } else {
197
+ if (is_object($this->logger)) {
198
+ $this->logger->error('Unable to write destination file for encryption.');
199
+ }
200
+ throw new \Exception("Unable to write destination file for encryption.");
201
+ }
202
+
203
+ if ($verification) {
204
+ $this->verify_encrypted_file($dest);
205
+ }
206
+
207
+ //we replace the original backup with the encrypted one
208
+ if (!$keep_local && copy($this->get_xcloner_path().$dest,
209
+ $this->get_xcloner_path().$source)) {
210
+ unlink($this->get_xcloner_path().$dest);
211
+ }
212
+
213
+
214
+ return array("target_file" => $dest, "finished" => 1);
215
+ }
216
+
217
+ /**
218
+ * @param string $file
219
+ */
220
+ public function verify_encrypted_file($file) {
221
+ if (is_object($this->logger)) {
222
+ $this->logger->info(sprintf('Verifying encrypted file %s', $file));
223
+ }
224
+
225
+ $this->verification = true;
226
+ $this->decrypt_file($file);
227
+ $this->verification = false;
228
+ }
229
+
230
+ /**
231
+ * Dencrypt the passed file and saves the result in a new file, removing the
232
+ * last 4 characters from file name.
233
+ *
234
+ * @param string $source Path to file that should be decrypted
235
+ * @param string $dest File name where the decryped file should be written to.
236
+ * @param string $key The key used for the decryption (must be the same as for encryption)
237
+ * @param int $start Start position for reading when doing incremental mode.
238
+ * @param string $iv The IV key to use.
239
+ * @return array|false Returns array or FALSE if an error occured
240
+ * @throws Exception
241
+ */
242
+ public function decrypt_file($source, $dest = "", $key = "", $start = 0, $iv = 0, $recursive = false)
243
+ {
244
+ if (is_object($this->logger)) {
245
+ $this->logger->info(sprintf('Decrypting file %s at position %d with IV %s', $source, $start, base64_encode($iv)));
246
+ }
247
+
248
+ //$key = substr(sha1($key, true), 0, 16);
249
+ if (!$key) {
250
+ $key = $this->get_backup_encryption_key();
251
+ }
252
+
253
+ $key_digest = openssl_digest($key, "md5", true);
254
+
255
+ $keep_local = 1;
256
+ if (!$dest) {
257
+ $dest = $this->get_decrypted_target_backup_file_name($source);
258
+ $keep_local = 0;
259
+ }
260
+
261
+ if (!$start) {
262
+ if ($this->verification) {
263
+ $fpOut = fopen("php://stdout", 'w');
264
+ } else {
265
+ $fpOut = fopen($this->get_xcloner_path().$dest, 'w');
266
+ }
267
+ } else {
268
+ if ($this->verification) {
269
+ $fpOut = fopen("php://stdout", 'a');
270
+ } else {
271
+ $fpOut = fopen($this->get_xcloner_path().$dest, 'a');
272
+ }
273
+ }
274
+
275
+ if (is_resource($fpOut)) {
276
+ if (file_exists($this->get_xcloner_path().$source) &&
277
+ $fpIn = fopen($this->get_xcloner_path().$source, 'rb')) {
278
+
279
+ $encryption_length = (int)fread($fpIn, 16);
280
+ if (!$encryption_length) {
281
+ $encryption_length = self::FILE_ENCRYPTION_BLOCKS;
282
+ }
283
+
284
+ fseek($fpIn, (int)$start);
285
+
286
+ // Get the initialzation vector from the beginning of the file
287
+ if (!$iv) {
288
+ $iv = fread($fpIn, 16);
289
+ }
290
+
291
+ if (!feof($fpIn)) {
292
+
293
+ // we have to read one block more for decrypting than for encrypting
294
+ $ciphertext = fread($fpIn, 16 * ($encryption_length + 1));
295
+ $plaintext = openssl_decrypt($ciphertext, 'AES-128-CBC', $key_digest, OPENSSL_RAW_DATA, $iv);
296
+
297
+ if (!$plaintext) {
298
+ unlink($this->get_xcloner_path().$dest);
299
+ if (is_object($this->logger)) {
300
+ $this->logger->error('Backup decryption failed, please check your provided Encryption Key.');
301
+ }
302
+ throw new \Exception("Backup decryption failed, please check your provided Encryption Key.");
303
+ }
304
+
305
+ // Use the first 16 bytes of the ciphertext as the next initialization vector
306
+ $iv = substr($ciphertext, 0, 16);
307
+
308
+ if (!$this->verification) {
309
+ fwrite($fpOut, $plaintext);
310
+ }
311
+
312
+ $start = ftell($fpIn);
313
+
314
+ fclose($fpOut);
315
+
316
+ if (!feof($fpIn)) {
317
+ fclose($fpIn);
318
+ if ($this->verification || $recursive) {
319
+ unset($ciphertext);
320
+ unset($plaintext);
321
+ $this->decrypt_file($source, $dest, $key, $start, $iv, $recursive);
322
+ } else {
323
+ if (($iv) != base64_decode(base64_encode($iv)))
324
+ {
325
+ throw new \Exception('Could not encode IV for transport');
326
+ }
327
+
328
+ return array(
329
+ "start" => $start,
330
+ "encryption_length" => $encryption_length,
331
+ "iv" => base64_encode($iv),
332
+ "target_file" => $dest,
333
+ "finished" => 0
334
+ );
335
+ }
336
+ }
337
+
338
+ }
339
+ } else {
340
+ if (is_object($this->logger)) {
341
+ $this->logger->error('Unable to read source file for decryption');
342
+ }
343
+ throw new \Exception("Unable to read source file for decryption");
344
+ }
345
+ } else {
346
+ if (is_object($this->logger)) {
347
+ $this->logger->error('Unable to write destination file for decryption');
348
+ }
349
+ throw new \Exception("Unable to write destination file for decryption");
350
+ }
351
+
352
+ //we replace the original backup with the encrypted one
353
+ if (!$keep_local && !$this->verification && copy($this->get_xcloner_path().$dest,
354
+ $this->get_xcloner_path().$source)) {
355
+ unlink($this->get_xcloner_path().$dest);
356
+ }
357
+
358
+ return array("target_file" => $dest, "finished" => 1);
359
+ }
360
+
361
+ public function get_xcloner_path() {
362
+ if (is_object($this->xcloner_settings)) {
363
+ return $this->xcloner_settings->get_xcloner_store_path().DS;
364
+ }
365
+
366
+ return null;
367
+ }
368
+
369
+ }
370
+
371
+
372
+ try {
373
+
374
+ if (isset($argv[1])) {
375
+
376
+ class Xcloner {
377
+ /**
378
+ * Xcloner constructor.
379
+ */
380
+ public function __construct()
381
+ {
382
+ }
383
+ }
384
+ $xcloner_encryption = new Xcloner_Encryption(new Xcloner());
385
+
386
+ if ($argv[1] == "-e") {
387
+ $xcloner_encryption->encrypt_file($argv[2], $argv[2].".enc", $argv[4], 0, 0, false, true);
388
+ } elseif ($argv[1] == "-d") {
389
+ $xcloner_encryption->decrypt_file($argv[2], $argv[2].".dec", $argv[4], 0, 0, true);
390
+ }
391
+ }
392
+ }catch (\Exception $e) {
393
+ echo "CAUGHT: ".$e->getMessage();
394
+ }
includes/class-xcloner-file-system.php CHANGED
@@ -61,7 +61,7 @@ class Xcloner_File_System
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
  /**
@@ -102,8 +102,8 @@ class Xcloner_File_System
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
 
@@ -161,7 +161,7 @@ class Xcloner_File_System
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;
@@ -207,6 +207,9 @@ class Xcloner_File_System
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);
@@ -431,7 +434,7 @@ class Xcloner_File_System
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 {
@@ -472,15 +475,15 @@ class Xcloner_File_System
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)) {
@@ -505,7 +508,11 @@ class Xcloner_File_System
505
  }
506
  }
507
 
508
- @rmdir($this->xcloner_settings->get_xcloner_tmp_path());
 
 
 
 
509
 
510
  return;
511
  }
@@ -614,7 +621,7 @@ class Xcloner_File_System
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",
@@ -642,7 +649,7 @@ class Xcloner_File_System
642
  }
643
  }
644
 
645
- } catch (Exception $e) {
646
 
647
  $this->logger->error($e->getMessage());
648
 
@@ -652,7 +659,7 @@ class Xcloner_File_System
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
 
@@ -669,7 +676,7 @@ class Xcloner_File_System
669
 
670
  $this->tmp_filesystem->delete($tmp_file);
671
 
672
- } catch (Exception $e) {
673
 
674
  $this->logger->error($e->getMessage());
675
 
@@ -686,7 +693,7 @@ class Xcloner_File_System
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
 
@@ -711,18 +718,18 @@ class Xcloner_File_System
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
 
@@ -730,9 +737,9 @@ class Xcloner_File_System
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
 
@@ -741,6 +748,9 @@ class Xcloner_File_System
741
 
742
  }
743
 
 
 
 
744
  public function estimate_reading_time($tmp_file)
745
  {
746
  $this->logger->debug(sprintf(("Estimating file system reading time")));
@@ -781,6 +791,9 @@ class Xcloner_File_System
781
  return $name;
782
  }
783
 
 
 
 
784
  public function sort_by(&$array, $field, $direction = 'asc')
785
  {
786
  if (strtolower($direction) == "desc" || $direction == SORT_DESC) {
@@ -829,7 +842,7 @@ class Xcloner_File_System
829
  }
830
 
831
  if ($timestamp <= $this->get_diff_timestamp_start()) {
832
- return " file DIFF timestamp " . $timestamp . " < " . $this->diff_timestamp_start;
833
  }
834
  }
835
 
@@ -842,7 +855,7 @@ class Xcloner_File_System
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
 
@@ -855,10 +868,10 @@ class Xcloner_File_System
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
  }
@@ -910,163 +923,163 @@ class Xcloner_File_System
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
  }
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", "encrypted", "decrypted");
65
  private $backup_name_tags = array('[time]', '[hostname]', '[domain]');
66
 
67
  /**
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
 
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;
207
  return $this->start_filesystem->normalizeFileInfo($info);
208
  }
209
 
210
+ /**
211
+ * @param string $file
212
+ */
213
  public function get_storage_path_file_info($file)
214
  {
215
  return $this->getMetadataFull('storage_adapter', $file);
434
  $this->build_files_list($file);
435
  $counter++;
436
  } else {
437
+ $this->tmp_filesystem_append->write($this->get_temp_dir_handler(), $file."\n");
438
  }
439
  }
440
  } else {
475
  {
476
  $return = array();
477
 
478
+ $files_list_file = $this->xcloner_settings->get_xcloner_tmp_path().DS.$this->get_included_files_handler();
479
  if (file_exists($files_list_file)) {
480
  $return[] = $files_list_file;
481
  }
482
 
483
  if ($this->xcloner_settings->get_xcloner_option('xcloner_enable_log')) {
484
+ $log_file = $this->xcloner_settings->get_xcloner_tmp_path().DS.$this->xcloner_settings->get_logger_filename(1);
485
  if (!file_exists($log_file)) {
486
+ $log_file = $this->xcloner_settings->get_xcloner_store_path().DS.$this->xcloner_settings->get_logger_filename();
487
  }
488
 
489
  if (file_exists($log_file)) {
508
  }
509
  }
510
 
511
+ try {
512
+ rmdir($this->xcloner_settings->get_xcloner_tmp_path());
513
+ }catch (Exception $e) {
514
+ //silent continue
515
+ }
516
 
517
  return;
518
  }
621
 
622
  $files = $this->start_filesystem->listContents($folder);
623
  foreach ($files as $file) {
624
+ if (!is_readable($this->xcloner_settings->get_xcloner_start_path().DS.$file['path'])) {
625
  $this->logger->info(sprintf(__("Excluding %s from the filesystem list, file not readable"),
626
  $file['path']), array(
627
  "FILESYSTEM SCAN",
649
  }
650
  }
651
 
652
+ }catch (Exception $e) {
653
 
654
  $this->logger->error($e->getMessage());
655
 
659
 
660
  public function estimate_read_write_time()
661
  {
662
+ $tmp_file = ".xcloner".substr(md5(time()), 0, 5);
663
 
664
  $start_time = microtime(true);
665
 
676
 
677
  $this->tmp_filesystem->delete($tmp_file);
678
 
679
+ }catch (Exception $e) {
680
 
681
  $this->logger->error($e->getMessage());
682
 
693
  $_backup_files_list = array();
694
 
695
  //rule date limit
696
+ $current_timestamp = strtotime("-".$this->xcloner_settings->get_xcloner_option('xcloner_cleanup_retention_limit_days')." days");
697
 
698
  $files = $this->storage_filesystem->listContents();
699
 
718
  {
719
  $this->storage_filesystem->delete($file['path']);
720
  $_storage_size -= $file['size'];
721
+ $this->logger->info("Deleting backup ".$file['path']." matching rule", array(
722
  "STORAGE SIZE LIMIT",
723
+ $_storage_size." >= ".$set_storage_limit
724
  ));
725
  }
726
 
727
  //processing rule days limit
728
  if ($this->xcloner_settings->get_xcloner_option('xcloner_cleanup_retention_limit_days') && $current_timestamp >= $file['timestamp']) {
729
  $this->storage_filesystem->delete($file['path']);
730
+ $this->logger->info("Deleting backup ".$file['path']." matching rule", array(
731
  "RETENTION LIMIT TIMESTAMP",
732
+ $file['timestamp']." =< ".$this->xcloner_settings->get_xcloner_option('xcloner_cleanup_retention_limit_days')
733
  ));
734
  }
735
 
737
  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')) {
738
  $this->storage_filesystem->delete($file['path']);
739
  $_backups_counter--;
740
+ $this->logger->info("Deleting backup ".$file['path']." matching rule", array(
741
  "BACKUP QUANTITY LIMIT",
742
+ $_backups_counter." >= ".$this->xcloner_settings->get_xcloner_option('xcloner_cleanup_retention_limit_archives')
743
  ));
744
  }
745
 
748
 
749
  }
750
 
751
+ /**
752
+ * @param string $tmp_file
753
+ */
754
  public function estimate_reading_time($tmp_file)
755
  {
756
  $this->logger->debug(sprintf(("Estimating file system reading time")));
791
  return $name;
792
  }
793
 
794
+ /**
795
+ * @param string $field
796
+ */
797
  public function sort_by(&$array, $field, $direction = 'asc')
798
  {
799
  if (strtolower($direction) == "desc" || $direction == SORT_DESC) {
842
  }
843
 
844
  if ($timestamp <= $this->get_diff_timestamp_start()) {
845
+ return " file DIFF timestamp ".$timestamp." < ".$this->diff_timestamp_start;
846
  }
847
  }
848
 
855
 
856
  if ($xcloner_exclude_files_larger_than_mb = $this->xcloner_settings->get_xcloner_option('xcloner_exclude_files_larger_than_mb')) {
857
  if (isset($file['size']) && $file['size'] > $this->calc_to_bytes($xcloner_exclude_files_larger_than_mb)) {
858
+ return "> ".$xcloner_exclude_files_larger_than_mb."MB";
859
  }
860
  }
861
 
868
  if ($excluded_file_pattern == "/") {
869
  $needle = "$";
870
  } else {
871
+ $needle = "$".$excluded_file_pattern;
872
  }
873
 
874
+ if (strstr("$".$file['path'], $needle)) {
875
  return $excluded_file_pattern;
876
  }
877
  }
923
  * exclude the backup folders
924
  * PATTERN: (^|^\/)(wp-content\/backups|administrator\/backups)(.*)$";
925
  */
926
+ private function is_excluded_regex($file)
927
+ {
928
+ //$this->logger->debug(sprintf(("Checking if %s is excluded"), $file['path']));
929
+
930
+ $regex_patterns = explode(PHP_EOL, $this->xcloner_settings->get_xcloner_option('xcloner_regex_exclude'));
931
+
932
+ if (is_array($this->additional_regex_patterns)) {
933
+ $regex_patterns = array_merge($regex_patterns, $this->additional_regex_patterns);
934
+ }
935
+
936
+ //print_r($regex_patterns);exit;
937
+
938
+ if (is_array($regex_patterns)) {
939
+ //$this->excluded_files = array();
940
+ //$this->excluded_files[] ="(.*)\.(git)(.*)$";
941
+ //$this->excluded_files[] ="wp-content\/backups(.*)$";
942
+
943
+ foreach ($regex_patterns as $excluded_file_pattern) {
944
+
945
+ if (substr($excluded_file_pattern, strlen($excluded_file_pattern) - 1,
946
+ strlen($excluded_file_pattern)) == "\r") {
947
+ $excluded_file_pattern = substr($excluded_file_pattern, 0, strlen($excluded_file_pattern) - 1);
948
+ }
949
+
950
+ if ($file['path'] == "/") {
951
+ $needle = "/";
952
+ } else {
953
+ $needle = "/".$file['path'];
954
+ }
955
+ //echo $needle."---".$excluded_file_pattern."---\n";
956
+
957
+ if (@preg_match("/(^|^\/)".$excluded_file_pattern."/i", $needle)) {
958
+ return $excluded_file_pattern;
959
+ }
960
+ }
961
+ }
962
+
963
+ return false;
964
+ }
965
+
966
+ public function store_file($file, $storage = 'start_filesystem')
967
+ {
968
+ $this->logger->debug(sprintf("Storing %s in the backup list", $file['path']));
969
+
970
+ if (!isset($file['size'])) {
971
+ $file['size'] = 0;
972
+ }
973
+ if (!isset($file['visibility'])) {
974
+ $file['visibility'] = "private";
975
+ }
976
+
977
+ $csv_filename = str_replace('"', '""', $file['path']);
978
+
979
+ $line = '"'.($csv_filename).'","'.$file['timestamp'].'","'.$file['size'].'","'.$file['visibility'].'","'.$storage.'"'.PHP_EOL;
980
+
981
+ $this->last_logged_file = $file['path'];
982
+
983
+ if ($file['type'] == "dir") {
984
+ try {
985
+ $this->tmp_filesystem_append->write($this->get_temp_dir_handler(), $file['path']."\n");
986
+ }catch (Exception $e) {
987
+ $this->logger->error($e->getMessage());
988
+ }
989
+ }
990
+
991
+ if ($this->get_diff_timestamp_start()) {
992
+ if ($file['type'] != "file" && $response = $this->check_file_diff_time($file)) {
993
+ $this->logger->info(sprintf("Directory %s archiving skipped on differential backup %s", $file['path'],
994
+ $response), array(
995
+ "FILESYSTEM SCAN",
996
+ "DIR DIFF"
997
+ ));
998
+
999
+ return false;
1000
+ }
1001
+ }
1002
+
1003
+ try {
1004
+ if (!$this->tmp_filesystem_append->has($this->get_included_files_handler())) {
1005
+ //adding fix for UTF-8 CSV preview
1006
+ $start_line = "\xEF\xBB\xBF".'"Filename","Timestamp","Size","Visibility","Storage"'.PHP_EOL;
1007
+ $this->tmp_filesystem_append->write($this->get_included_files_handler(), $start_line);
1008
+ }
1009
+
1010
+ $this->tmp_filesystem_append->write($this->get_included_files_handler(), $line);
1011
+
1012
+ }catch (Exception $e) {
1013
+
1014
+ $this->logger->error($e->getMessage());
1015
+ }
1016
+
1017
+ return true;
1018
+ }
1019
+
1020
+ public function get_fileystem_handler()
1021
+ {
1022
+ return $this;
1023
+ }
1024
+
1025
+ public function get_filesystem($system = "")
1026
+ {
1027
+ if ($system == "storage_filesystem_append") {
1028
+ return $this->storage_filesystem_append;
1029
+ } elseif ($system == "tmp_filesystem_append") {
1030
+ return $this->tmp_filesystem_append;
1031
+ } elseif ($system == "tmp_filesystem") {
1032
+ return $this->tmp_filesystem;
1033
+ } elseif ($system == "storage_filesystem") {
1034
+ return $this->storage_filesystem;
1035
+ } else {
1036
+ return $this->start_filesystem;
1037
+ }
1038
+ }
1039
+
1040
+ public function get_adapter($system)
1041
+ {
1042
+ if ($system == "tmp_filesystem") {
1043
+ return $this->tmp_adapter;
1044
+ } elseif ($system == "storage_filesystem") {
1045
+ return $this->storage_adapter;
1046
+ } else {
1047
+ return $this->start_adapter;
1048
+ }
1049
+ }
1050
+
1051
+ /**
1052
+ * File scan finished
1053
+ * Method called when file scan is finished
1054
+ *
1055
+ * @return bool
1056
+ */
1057
+ private function scan_finished()
1058
+ {
1059
+ if ($this->tmp_filesystem_append->has($this->get_temp_dir_handler()) &&
1060
+ $this->tmp_filesystem_append->getSize($this->get_temp_dir_handler())) {
1061
+ return false;
1062
+ }
1063
+
1064
+ if ($this->tmp_filesystem->has($this->get_temp_dir_handler())) {
1065
+ $this->tmp_filesystem->delete($this->get_temp_dir_handler());
1066
+ }
1067
+
1068
+ $this->logger->debug(sprintf(("File scan finished")));
1069
+
1070
+ return true;
1071
+ }
1072
+
1073
+ /**
1074
+ * Calculate bytes from MB value
1075
+ *
1076
+ * @param int $mb_size
1077
+ *
1078
+ * @return float|int
1079
+ */
1080
+ private function calc_to_bytes($mb_size)
1081
+ {
1082
+ return $mb_size * (1024 * 1024);
1083
+ }
1084
 
1085
  }
includes/class-xcloner-file-transfer.php CHANGED
@@ -29,136 +29,137 @@
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
  }
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 string
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, 1);
110
+ //curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1);
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
 
121
+ $this->get_tmp_filesystem()->delete($tmp_filename);
122
 
123
+ $result = json_decode($original_result);
 
 
124
 
125
+ if (!$result) {
126
+ throw new Exception("We have received no valid response from the remote host, original message: ".$original_result);
127
+ }
128
 
129
+ if ($result->status != 200) {
130
+ throw new Exception($result->response);
131
+ }
 
132
 
133
+ if (ftell($fp) >= $this->get_storage_filesystem()->getSize($file)) {
134
+ $this->get_logger()->info(sprintf("Upload done for file %s to target url %s, transferred a total of %s bytes",
135
+ $file, $this->target_url, ftell($fp)));
136
+ $this->remove_tmp_filesystem();
137
 
138
+ return false;
139
+ }
140
 
141
+ return ftell($fp);
142
+ }
 
 
 
 
 
 
 
 
143
 
144
+ /**
145
+ * @param string $filename
146
+ * @param string $mimetype
147
+ * @param string $postname
148
+ *
149
+ * @return CURLFile|string
150
+ */
151
+ private function curl_file_create($filename, $mimetype = '', $postname = '')
152
+ {
153
+ if (!function_exists('curl_file_create')) {
154
 
155
+ return "@$filename;filename="
156
+ . ($postname ?: basename($filename))
157
+ . ($mimetype ? ";type=$mimetype" : '');
158
 
159
+ } else {
160
 
161
+ return curl_file_create($filename, $mimetype, $postname);
162
+
163
+ }
164
+ }
165
  }
includes/class-xcloner-i18n.php CHANGED
@@ -41,21 +41,21 @@
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
  }
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
@@ -41,154 +41,167 @@
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
  }
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
+ /**
63
+ * @var Xcloner
64
+ */
65
+ private $xcloner_plugin;
66
+
67
+ /**
68
+ * @var Xcloner
69
+ */
70
+ private $xcloner_container;
71
+
72
+
73
+ /**
74
+ * Initialize the collections used to maintain the actions and filters.
75
+ *
76
+ * Xcloner_Loader constructor.
77
+ * @param Xcloner $xcloner_container
78
+ */
79
+ public function __construct(Xcloner $xcloner_container)
80
+ {
81
+
82
+ $this->actions = array();
83
+ $this->filters = array();
84
+
85
+ $this->xcloner_container = $xcloner_container;
86
+
87
+ }
88
+
89
+ /**
90
+ * Add XCloner to Admin Menu
91
+ */
92
+ public function xcloner_backup_add_admin_menu()
93
+ {
94
+ if (function_exists('add_menu_page')) {
95
+ add_menu_page(__('Site Backup', 'xcloner-backup-and-restore'),
96
+ __('Site Backup', 'xcloner-backup-and-restore'), 'manage_options', 'xcloner_init_page',
97
+ array($this->xcloner_container, 'xcloner_display'), 'dashicons-backup');
98
+ }
99
+
100
+ if (function_exists('add_submenu_page')) {
101
+
102
+ add_submenu_page('xcloner_init_page', __('XCloner Dashboard', 'xcloner-backup-and-restore'),
103
+ __('Dashboard', 'xcloner-backup-and-restore'), 'manage_options', 'xcloner_init_page',
104
+ array($this->xcloner_container, 'xcloner_display'));
105
+ add_submenu_page('xcloner_init_page', __('XCloner Backup Settings', 'xcloner-backup-and-restore'),
106
+ __('Settings', 'xcloner-backup-and-restore'), 'manage_options', 'xcloner_settings_page',
107
+ array($this->xcloner_container, 'xcloner_display'));
108
+ add_submenu_page('xcloner_init_page', __('Remote Storage Settings', 'xcloner-backup-and-restore'),
109
+ __('Remote Storage', 'xcloner-backup-and-restore'), 'manage_options', 'xcloner_remote_storage_page',
110
+ array($this->xcloner_container, 'xcloner_display'));
111
+ add_submenu_page('xcloner_init_page', __('Manage Backups', 'xcloner-backup-and-restore'),
112
+ __('Manage Backups', 'xcloner-backup-and-restore'), 'manage_options', 'xcloner_manage_backups_page',
113
+ array($this->xcloner_container, 'xcloner_display'));
114
+ add_submenu_page('xcloner_init_page', __('Scheduled Backups', 'xcloner-backup-and-restore'),
115
+ __('Scheduled Backups', 'xcloner-backup-and-restore'), 'manage_options',
116
+ 'xcloner_scheduled_backups_page', array($this->xcloner_container, 'xcloner_display'));
117
+ add_submenu_page('xcloner_init_page', __('Generate Backups', 'xcloner-backup-and-restore'),
118
+ __('Generate Backups', 'xcloner-backup-and-restore'), 'manage_options', 'xcloner_generate_backups_page',
119
+ array($this->xcloner_container, 'xcloner_display'));
120
+ add_submenu_page('xcloner_init_page', __('Restore Backups', 'xcloner-backup-and-restore'),
121
+ __('Restore Backups', 'xcloner-backup-and-restore'), 'manage_options', 'xcloner_restore_page',
122
+ array($this->xcloner_container, 'xcloner_display'));
123
+ }
124
+
125
+ }
126
+
127
+
128
+ /**
129
+ * Add a new action to the collection to be registered with WordPress.
130
+ *
131
+ * @since 1.0.0
132
+ * @param string $hook The name of the WordPress action that is being registered.
133
+ * @param object $component A reference to the instance of the object on which the action is defined.
134
+ * @param string $callback The name of the function definition on the $component.
135
+ * @param int $priority Optional. he priority at which the function should be fired. Default is 10.
136
+ * @param int $accepted_args Optional. The number of arguments that should be passed to the $callback. Default is 1.
137
+ */
138
+ public function add_action($hook, $component, $callback, $priority = 10, $accepted_args = 1)
139
+ {
140
+ $this->actions = $this->add($this->actions, $hook, $component, $callback, $priority, $accepted_args);
141
+ }
142
+
143
+ /**
144
+ * Add a new filter to the collection to be registered with WordPress.
145
+ *
146
+ * @since 1.0.0
147
+ * @param string $hook The name of the WordPress filter that is being registered.
148
+ * @param object $component A reference to the instance of the object on which the filter is defined.
149
+ * @param string $callback The name of the function definition on the $component.
150
+ * @param int $priority Optional. he priority at which the function should be fired. Default is 10.
151
+ * @param int $accepted_args Optional. The number of arguments that should be passed to the $callback. Default is 1
152
+ */
153
+ public function add_filter($hook, $component, $callback, $priority = 10, $accepted_args = 1)
154
+ {
155
+ $this->filters = $this->add($this->filters, $hook, $component, $callback, $priority, $accepted_args);
156
+ }
157
+
158
+ /**
159
+ * A utility function that is used to register the actions and hooks into a single
160
+ * collection.
161
+ *
162
+ * @since 1.0.0
163
+ * @access private
164
+ * @param array $hooks The collection of hooks that is being registered (that is, actions or filters).
165
+ * @param string $hook The name of the WordPress filter that is being registered.
166
+ * @param object $component A reference to the instance of the object on which the filter is defined.
167
+ * @param string $callback The name of the function definition on the $component.
168
+ * @param int $priority The priority at which the function should be fired.
169
+ * @param int $accepted_args The number of arguments that should be passed to the $callback.
170
+ * @return array The collection of actions and filters registered with WordPress.
171
+ */
172
+ private function add($hooks, $hook, $component, $callback, $priority, $accepted_args)
173
+ {
174
+
175
+ $hooks[] = array(
176
+ 'hook' => $hook,
177
+ 'component' => $component,
178
+ 'callback' => $callback,
179
+ 'priority' => $priority,
180
+ 'accepted_args' => $accepted_args
181
+ );
182
+
183
+ return $hooks;
184
+
185
+ }
186
+
187
+ /**
188
+ * Register the filters and actions with WordPress.
189
+ *
190
+ * @since 1.0.0
191
+ */
192
+ public function run()
193
+ {
194
+
195
+ foreach ($this->filters as $hook) {
196
+ add_filter($hook['hook'], array($hook['component'], $hook['callback']), $hook['priority'],
197
+ $hook['accepted_args']);
198
+ }
199
+
200
+ foreach ($this->actions as $hook) {
201
+ add_action($hook['hook'], array($hook['component'], $hook['callback']), $hook['priority'],
202
+ $hook['accepted_args']);
203
+ }
204
+
205
+ }
206
 
207
  }
includes/class-xcloner-logger.php CHANGED
@@ -10,99 +10,112 @@ class Xcloner_Logger extends Logger {
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
  }
10
  private $max_logger_files = 7;
11
  private $main_logger_url;
12
 
13
+ /**
14
+ * Xcloner_Logger constructor.
15
+ * @param Xcloner $xcloner_container
16
+ * @param string $logger_name
17
+ * @throws Exception
18
+ */
19
+ public function __construct(Xcloner $xcloner_container, $logger_name = "xcloner_logger") {
20
+ if (!$xcloner_container->get_xcloner_settings()) {
21
+ $xcloner_settings = new Xcloner_Settings($xcloner_container);
22
  } else {
23
  $xcloner_settings = $xcloner_container->get_xcloner_settings();
24
  }
25
 
26
  $hash = $xcloner_settings->get_hash();
27
+ if ($hash == "-".$xcloner_settings->get_server_unique_hash(5)) {
28
  $hash = "";
29
  }
30
 
31
+ $logger_path = $xcloner_settings->get_xcloner_store_path().DS.$xcloner_settings->get_logger_filename();
32
  $logger_path_tmp = "";
33
 
34
+ if ($hash) {
35
+ $logger_path_tmp = $xcloner_settings->get_xcloner_tmp_path().DS.$xcloner_settings->get_logger_filename(1);
36
  }
37
 
38
  $this->logger_path = $logger_path;
39
 
40
+ if (!is_dir($xcloner_settings->get_xcloner_store_path()) or !is_writable($xcloner_settings->get_xcloner_store_path())) {
41
  $logger_path = 'php://stderr';
42
  $logger_path_tmp = "";
43
  }
44
 
45
+ if (!$xcloner_settings->get_xcloner_option('xcloner_enable_log')) {
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
  $debug_level = Logger::DEBUG;
57
  }
58
 
59
 
60
+ if ($logger_path) {
61
+ if (!$xcloner_settings->get_xcloner_option('xcloner_enable_log')) {
62
+ $stream = new StreamHandler($logger_path, $debug_level);
63
  } else {
64
+ $stream = new RotatingFileHandler($logger_path, $this->max_logger_files, $debug_level);
65
  }
66
 
67
+ $this->pushHandler($stream);
68
 
69
  $this->main_logger_url = $stream->getUrl();
70
  }
71
 
72
+ if ($hash and $logger_path_tmp) {
73
+ $this->pushHandler(new StreamHandler($logger_path_tmp, $debug_level));
74
  }
75
 
76
  //return $this;
77
  }
78
 
79
+ /**
80
+ * @return string|null
81
+ */
82
  function get_main_logger_url() {
83
  return $this->main_logger_url;
84
  }
85
 
86
+ /**
87
+ * @param int $totalLines
88
+ * @return array|bool
89
+ */
90
+ function getLastDebugLines($totalLines = 200) {
91
  $lines = array();
92
 
93
+ if (!file_exists($this->main_logger_url) or !is_readable($this->main_logger_url)) {
94
  return false;
95
  }
96
 
97
+ $fp = fopen($this->main_logger_url, 'r');
98
+ fseek($fp, - 1, SEEK_END);
99
+ $pos = ftell($fp);
100
  $lastLine = "";
101
 
102
  // Loop backword until we have our lines or we reach the start
103
+ while ($pos > 0 && count($lines) < $totalLines) {
104
 
105
+ $C = fgetc($fp);
106
+ if ($C == "\n") {
107
  // skip empty lines
108
+ if (trim($lastLine) != "") {
109
  $lines[] = $lastLine;
110
  }
111
  $lastLine = '';
112
  } else {
113
+ $lastLine = $C.$lastLine;
114
  }
115
+ fseek($fp, $pos--);
116
  }
117
 
118
+ $lines = array_reverse($lines);
119
 
120
  return $lines;
121
  }
includes/class-xcloner-remote-storage.php CHANGED
@@ -51,129 +51,135 @@ use League\Flysystem\WebDAV\WebDAVAdapter;
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
 
@@ -192,7 +198,7 @@ class Xcloner_Remote_Storage {
192
  }
193
  }
194
 
195
- }
196
 
197
  /**
198
  * Encrypts and Decrypt a string based on openssl lib
@@ -201,578 +207,622 @@ class Xcloner_Remote_Storage {
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
  }
51
  /**
52
  * Class Xcloner_Remote_Storage
53
  */
54
+ class Xcloner_Remote_Storage
55
+ {
56
+
57
+ private $gdrive_app_name = "XCloner Backup and Restore";
58
+
59
+ private $storage_fields = array(
60
+ "option_prefix" => "xcloner_",
61
+ "ftp" => array(
62
+ "text" => "FTP",
63
+ "ftp_enable" => "int",
64
+ "ftp_hostname" => "string",
65
+ "ftp_port" => "int",
66
+ "ftp_username" => "string",
67
+ "ftp_password" => "raw",
68
+ "ftp_path" => "path",
69
+ "ftp_transfer_mode" => "int",
70
+ "ftp_ssl_mode" => "int",
71
+ "ftp_timeout" => "int",
72
+ "ftp_cleanup_days" => "float",
73
+ ),
74
+ "sftp" => array(
75
+ "text" => "SFTP",
76
+ "sftp_enable" => "int",
77
+ "sftp_hostname" => "string",
78
+ "sftp_port" => "int",
79
+ "sftp_username" => "string",
80
+ "sftp_password" => "raw",
81
+ "sftp_path" => "path",
82
+ "sftp_private_key" => "raw",
83
+ "sftp_timeout" => "int",
84
+ "sftp_cleanup_days" => "float",
85
+ ),
86
+ "aws" => array(
87
+ "text" => "S3",
88
+ "aws_enable" => "int",
89
+ "aws_key" => "string",
90
+ "aws_secret" => "raw",
91
+ "aws_endpoint" => "string",
92
+ "aws_region" => "string",
93
+ "aws_bucket_name" => "string",
94
+ "aws_prefix" => "string",
95
+ "aws_cleanup_days" => "float",
96
+ ),
97
+ "dropbox" => array(
98
+ "text" => "Dropbox",
99
+ "dropbox_enable" => "int",
100
+ "dropbox_access_token" => "string",
101
+ "dropbox_app_secret" => "raw",
102
+ "dropbox_prefix" => "string",
103
+ "dropbox_cleanup_days" => "float",
104
+ ),
105
+ "azure" => array(
106
+ "text" => "Azure BLOB",
107
+ "azure_enable" => "int",
108
+ "azure_account_name" => "string",
109
+ "azure_api_key" => "string",
110
+ "azure_container" => "string",
111
+ "azure_cleanup_days" => "float",
112
+ ),
113
+ "backblaze" => array(
114
+ "text" => "Backblaze",
115
+ "backblaze_enable" => "int",
116
+ "backblaze_account_id" => "string",
117
+ "backblaze_application_key" => "string",
118
+ "backblaze_bucket_name" => "string",
119
+ "backblaze_cleanup_days" => "float",
120
+ ),
121
+
122
+ "webdav" => array(
123
+ "text" => "WebDAV",
124
+ "webdav_enable" => "int",
125
+ "webdav_url" => "string",
126
+ "webdav_username" => "string",
127
+ "webdav_password" => "raw",
128
+ "webdav_target_folder" => "string",
129
+ "webdav_cleanup_days" => "float",
130
+ ),
131
+
132
+ "gdrive" => array(
133
+ "text" => "Google Drive",
134
+ "gdrive_enable" => "int",
135
+ "gdrive_access_code" => "string",
136
+ "gdrive_client_id" => "string",
137
+ "gdrive_client_secret" => "raw",
138
+ "gdrive_target_folder" => "string",
139
+ "gdrive_cleanup_days" => "float",
140
+ "gdrive_empty_trash" => "int",
141
+ ),
142
+ );
143
+
144
+ private $aws_regions = array(
145
+ 'us-east-1' => 'US East (N. Virginia)',
146
+ 'us-east-2' => 'US East (Ohio)',
147
+ 'us-west-1' => 'US West (N. California)',
148
+ 'us-west-2' => 'US West (Oregon)',
149
+ 'ca-central-1' => 'Canada (Central)',
150
+ 'eu-west-1' => 'EU (Ireland)',
151
+ 'eu-central-1' => 'EU (Frankfurt)',
152
+ 'eu-west-2' => 'EU (London)',
153
+ 'ap-northeast-1' => 'Asia Pacific (Tokyo)',
154
+ 'ap-northeast-2' => 'Asia Pacific (Seoul)',
155
+ 'ap-southeast-1' => 'Asia Pacific (Singapore)',
156
+ 'ap-southeast-2' => 'Asia Pacific (Sydney)',
157
+ 'ap-south-1' => 'Asia Pacific (Mumbai)',
158
+ 'sa-east-1' => 'South America (São Paulo)'
159
+ );
160
+
161
+ private $xcloner_sanitization;
162
+ private $xcloner_file_system;
163
+ private $logger;
164
+ private $xcloner;
165
+
166
+ /**
167
+ * Xcloner_Remote_Storage constructor.
168
+ * @param Xcloner $xcloner_container
169
+ */
170
+ public function __construct(Xcloner $xcloner_container)
171
+ {
172
+ $this->xcloner_sanitization = $xcloner_container->get_xcloner_sanitization();
173
+ $this->xcloner_file_system = $xcloner_container->get_xcloner_filesystem();
174
+ $this->logger = $xcloner_container->get_xcloner_logger()->withName("xcloner_remote_storage");
175
+ $this->xcloner = $xcloner_container;
176
+
177
+ foreach ($this->storage_fields as $main_key => $array) {
178
+
179
+ if (is_array($array)) {
180
  foreach ($array as $key => $type) {
181
 
182
+ if ($type == "raw") {
183
  add_filter("pre_update_option_" . $this->storage_fields['option_prefix'] . $key,
184
  function ($value) {
185
 
198
  }
199
  }
200
 
201
+ }
202
 
203
  /**
204
  * Encrypts and Decrypt a string based on openssl lib
207
  * @param string $action
208
  * @return string
209
  */
210
+ private function simple_crypt($string, $action = 'e')
211
+ {
212
  // you may change these values to your own
213
  $secret_key = NONCE_KEY;
214
  $secret_iv = NONCE_SALT;
215
 
216
+ if (!$string) {
217
+ //we do no encryption for empty data
218
+ return $string;
219
+ }
220
+
221
  $output = $string;
222
  $encrypt_method = "AES-256-CBC";
223
+ $key = hash('sha256', $secret_key);
224
+ $iv = substr(hash('sha256', $secret_iv), 0, 16);
225
+
226
+ if ($action == 'e' && function_exists('openssl_encrypt')) {
227
+ $output = base64_encode(openssl_encrypt($string, $encrypt_method, $key, 0, $iv));
228
+ } else {
229
+ if ($action == 'd' && function_exists('openssl_decrypt') && base64_decode($string)) {
230
+ $decrypt = openssl_decrypt(base64_decode($string), $encrypt_method, $key, 0, $iv);
231
+ if ($decrypt) {
232
+ //we check if decrypt was succesful
233
+ $output = $decrypt;
234
+ }
235
  }
236
  }
237
 
238
  return $output;
239
  }
240
 
241
+ private function get_xcloner_container()
242
+ {
243
+ return $this->xcloner;
244
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
245
 
246
+ public function get_available_storages()
247
+ {
248
+ $return = array();
249
+ foreach ($this->storage_fields as $storage => $data) {
250
+ $check_field = $this->storage_fields["option_prefix"] . $storage . "_enable";
251
+ if (get_option($check_field)) {
252
+ $return[$storage] = $data['text'];
253
+ }
254
+ }
255
 
256
+ return $return;
257
+ }
 
258
 
259
+ public function save($action = "ftp")
260
+ {
261
+ if (!$action) {
262
+ return false;
263
+ }
264
 
265
+ $storage = $this->xcloner_sanitization->sanitize_input_as_string($action);
266
+ $this->logger->debug(sprintf("Saving the remote storage %s options", strtoupper($action)));
 
267
 
268
+ if (is_array($this->storage_fields[$storage])) {
269
+ foreach ($this->storage_fields[$storage] as $field => $validation) {
270
+ $check_field = $this->storage_fields["option_prefix"] . $field;
271
+ $sanitize_method = "sanitize_input_as_" . $validation;
272
 
273
+ if (!isset($_POST[$check_field])) {
274
+ $_POST[$check_field] = 0;
275
+ }
276
 
277
+ if (!method_exists($this->xcloner_sanitization, $sanitize_method)) {
278
+ $sanitize_method = "sanitize_input_as_string";
279
+ }
 
 
 
 
 
 
280
 
281
+ $sanitized_value = $this->xcloner_sanitization->$sanitize_method(stripslashes($_POST[$check_field]));
282
+ update_option($check_field, $sanitized_value);
283
+ }
284
 
285
+ $this->xcloner->trigger_message(__("%s storage settings saved.", 'xcloner-backup-and-restore'), "success",
286
+ $this->storage_fields[$action]['text']);
287
+ }
288
 
289
+ }
 
 
290
 
291
+ public function check($action = "ftp")
292
+ {
293
+ try {
294
+ $this->verify_filesystem($action);
295
+ $this->xcloner->trigger_message(__("%s connection is valid.", 'xcloner-backup-and-restore'), "success",
296
+ $this->storage_fields[$action]['text']);
297
+ $this->logger->debug(sprintf("Connection to remote storage %s is valid", strtoupper($action)));
298
+ } catch (Exception $e) {
299
+ $this->xcloner->trigger_message("%s connection error: " . $e->getMessage(), "error",
300
+ $this->storage_fields[$action]['text']);
301
+ }
302
+ }
303
 
304
+ /**
305
+ * @param string $storage_type
306
+ */
307
+ public function verify_filesystem($storage_type)
308
+ {
309
+ $method = "get_" . $storage_type . "_filesystem";
310
 
311
+ $this->logger->info(sprintf("Checking validity of the remote storage %s filesystem",
312
+ strtoupper($storage_type)));
 
 
 
313
 
314
+ if (!method_exists($this, $method)) {
315
+ return false;
316
+ }
317
 
318
+ list($adapter, $filesystem) = $this->$method();
 
 
 
 
319
 
320
+ $test_file = substr(".xcloner_" . md5(time()), 0, 15);
 
 
 
 
321
 
322
+ if ($storage_type == "gdrive") {
323
+ if (!is_array($filesystem->listContents())) {
324
+ throw new Exception(__("Could not read data", 'xcloner-backup-and-restore'));
325
+ }
326
+ $this->logger->debug(sprintf("I can list data from remote storage %s", strtoupper($storage_type)));
327
 
328
+ return true;
329
+ }
330
 
331
+ //testing write access
332
+ if (!$filesystem->write($test_file, "data")) {
333
+ throw new Exception(__("Could not write data", 'xcloner-backup-and-restore'));
334
+ }
335
+ $this->logger->debug(sprintf("I can write data to remote storage %s", strtoupper($storage_type)));
336
 
337
+ //testing read access
338
+ if (!$filesystem->has($test_file)) {
339
+ throw new Exception(__("Could not read data", 'xcloner-backup-and-restore'));
340
+ }
341
+ $this->logger->debug(sprintf("I can read data to remote storage %s", strtoupper($storage_type)));
342
 
343
+ //delete test file
344
+ if (!$filesystem->delete($test_file)) {
345
+ throw new Exception(__("Could not delete data", 'xcloner-backup-and-restore'));
346
+ }
347
+ $this->logger->debug(sprintf("I can delete data to remote storage %s", strtoupper($storage_type)));
348
 
349
+ return true;
350
+ }
 
351
 
352
+ public function upload_backup_to_storage($file, $storage)
353
+ {
354
+ if (!$this->xcloner_file_system->get_storage_filesystem()->has($file)) {
355
+ $this->logger->info(sprintf("File not found %s in local storage", $file));
356
 
357
+ return false;
358
+ }
359
 
360
+ $method = "get_" . $storage . "_filesystem";
361
 
362
+ if (!method_exists($this, $method)) {
363
+ return false;
364
+ }
 
 
365
 
366
+ list($remote_storage_adapter, $remote_storage_filesystem) = $this->$method();
367
 
368
+ //doing remote storage cleaning here
369
+ $this->clean_remote_storage($storage, $remote_storage_filesystem);
370
 
371
+ $this->logger->info(sprintf("Transferring backup %s to remote storage %s", $file, strtoupper($storage)),
372
+ array(""));
373
 
374
+ /*if(!$this->xcloner_file_system->get_storage_filesystem()->has($file))
375
+ {
376
+ $this->logger->info(sprintf("File not found %s in local storage", $file));
377
+ return false;
378
+ }*/
379
 
380
+ $backup_file_stream = $this->xcloner_file_system->get_storage_filesystem()->readStream($file);
 
 
 
 
 
 
381
 
382
+ if (!$remote_storage_filesystem->writeStream($file, $backup_file_stream)) {
383
+ $this->logger->info(sprintf("Could not transfer file %s", $file));
384
 
385
+ return false;
386
+ }
387
 
388
+ if ($this->xcloner_file_system->is_multipart($file)) {
389
+ $parts = $this->xcloner_file_system->get_multipart_files($file);
390
+ if (is_array($parts)) {
391
+ foreach ($parts as $part_file) {
392
+ $this->logger->info(sprintf("Transferring backup %s to remote storage %s", $part_file,
393
+ strtoupper($storage)), array(""));
394
 
395
+ $backup_file_stream = $this->xcloner_file_system->get_storage_filesystem()->readStream($part_file);
396
+ if (!$remote_storage_filesystem->writeStream($part_file, $backup_file_stream)) {
397
+ return false;
398
+ }
399
+ }
400
+ }
401
+ }
402
 
403
+ $this->logger->info(sprintf("Upload done, disconnecting from remote storage %s", strtoupper($storage)));
404
 
405
+ return true;
 
 
406
 
407
+ }
408
 
409
+ public function copy_backup_remote_to_local($file, $storage)
410
+ {
411
+ $method = "get_" . $storage . "_filesystem";
412
 
413
+ $target_filename = $file;
 
414
 
415
+ if (!method_exists($this, $method)) {
416
+ return false;
417
+ }
 
418
 
419
+ list($remote_storage_adapter, $remote_storage_filesystem) = $this->$method();
420
 
421
+ if (!$remote_storage_filesystem->has($file)) {
422
+ $this->logger->info(sprintf("File not found %s in remote storage %s", $file, strtoupper($storage)));
423
 
424
+ return false;
425
+ }
426
 
427
+ if ($storage == "gdrive") {
428
+ $metadata = $remote_storage_filesystem->getMetadata($file);
429
+ $target_filename = $metadata['filename'] . "." . $metadata['extension'];
430
+ }
431
 
432
+ $this->logger->info(sprintf("Transferring backup %s to local storage from %s storage", $file,
433
+ strtoupper($storage)), array(""));
 
 
 
434
 
435
+ $backup_file_stream = $remote_storage_filesystem->readStream($file);
 
 
 
 
 
 
436
 
437
+ if (!$this->xcloner_file_system->get_storage_filesystem()->writeStream($target_filename, $backup_file_stream)) {
438
+ $this->logger->info(sprintf("Could not transfer file %s", $file));
439
 
440
+ return false;
441
+ }
442
 
443
+ if ($this->xcloner_file_system->is_multipart($target_filename)) {
444
+ $parts = $this->xcloner_file_system->get_multipart_files($file, $storage);
445
+ if (is_array($parts)) {
446
+ foreach ($parts as $part_file) {
447
+ $this->logger->info(sprintf("Transferring backup %s to local storage from %s storage", $part_file,
448
+ strtoupper($storage)), array(""));
449
+
450
+ $backup_file_stream = $remote_storage_filesystem->readStream($part_file);
451
+ if (!$this->xcloner_file_system->get_storage_filesystem()->writeStream($part_file,
452
+ $backup_file_stream)) {
453
+ return false;
454
+ }
455
+ }
456
+ }
457
+ }
458
 
459
+ $this->logger->info(sprintf("Upload done, disconnecting from remote storage %s", strtoupper($storage)));
 
 
 
 
460
 
461
+ return true;
462
 
463
+ }
 
 
464
 
465
+ public function clean_remote_storage($storage, $remote_storage_filesystem)
466
+ {
467
+ $check_field = $this->storage_fields["option_prefix"] . $storage . "_cleanup_days";
468
+ if ($expire_days = get_option($check_field)) {
469
+ $this->logger->info(sprintf("Doing %s remote storage cleanup for %s days limit", strtoupper($storage),
470
+ $expire_days));
471
+ $files = $remote_storage_filesystem->listContents();
472
+
473
+ $current_timestamp = strtotime("-" . $expire_days . " days");
474
+
475
+ if (is_array($files)) {
476
+ foreach ($files as $file) {
477
+ $file['timestamp'] = $remote_storage_filesystem->getTimestamp($file['path']);
478
+
479
+ if ($current_timestamp >= $file['timestamp']) {
480
+ $remote_storage_filesystem->delete($file['path']);
481
+ $this->logger->info("Deleting remote file " . $file['path'] . " matching rule", array(
482
+ "RETENTION LIMIT TIMESTAMP",
483
+ $file['timestamp'] . " =< " . $expire_days
484
+ ));
485
+ }
486
 
487
+ }
488
+ }
489
+ }
490
+ }
491
 
492
+ public function get_azure_filesystem()
493
+ {
494
+ $this->logger->info(sprintf("Creating the AZURE BLOB remote storage connection"), array(""));
495
 
496
+ if (version_compare(phpversion(), '5.6.0', '<')) {
497
+ throw new Exception("AZURE BLOB requires PHP 5.6 to be installed!");
498
+ }
499
 
500
+ if (!class_exists('XmlWriter')) {
501
+ throw new Exception("AZURE BLOB requires libxml PHP module to be installed with XmlWriter class enabled!");
502
+ }
503
 
504
+ $endpoint = sprintf(
505
+ 'DefaultEndpointsProtocol=https;AccountName=%s;AccountKey=%s',
506
+ get_option("xcloner_azure_account_name"),
507
+ get_option("xcloner_azure_api_key")
508
+ );
509
 
510
+ $blobRestProxy = ServicesBuilder::getInstance()->createBlobService($endpoint);
511
 
512
+ $adapter = new AzureAdapter($blobRestProxy, get_option("xcloner_azure_container"));
513
 
514
+ $filesystem = new Filesystem($adapter, new Config([
515
+ 'disable_asserts' => true,
516
+ ]));
517
 
518
+ return array($adapter, $filesystem);
519
+ }
520
 
521
+ public function get_dropbox_filesystem()
522
+ {
523
+ $this->logger->info(sprintf("Creating the DROPBOX remote storage connection"), array(""));
524
 
525
+ if (version_compare(phpversion(), '5.6.0', '<')) {
526
+ throw new Exception("DROPBOX requires PHP 5.6 to be installed!");
527
+ }
528
 
529
+ $client = new DropboxClient(get_option("xcloner_dropbox_access_token"));
530
+ $adapter = new DropboxAdapter($client, get_option("xcloner_dropbox_prefix"));
531
 
532
+ $filesystem = new Filesystem($adapter, new Config([
533
+ 'disable_asserts' => true,
534
+ ]));
535
 
536
+ return array($adapter, $filesystem);
537
+ }
538
 
539
+ public function get_aws_filesystem()
540
+ {
541
+ $this->logger->info(sprintf("Creating the S3 remote storage connection"), array(""));
542
 
543
+ if (version_compare(phpversion(), '5.6.0', '<')) {
544
+ throw new Exception("S3 class requires PHP 5.6 to be installed!");
545
+ }
546
 
547
+ if (!class_exists('XmlWriter')) {
548
+ throw new Exception("AZURE BLOB requires libxml PHP module to be installed with XmlWriter class enabled!");
549
+ }
550
 
551
 
552
+ $credentials = array(
553
+ 'credentials' => array(
554
+ 'key' => get_option("xcloner_aws_key"),
555
+ 'secret' => get_option("xcloner_aws_secret")
556
+ ),
557
+ 'region' => get_option("xcloner_aws_region"),
558
+ 'version' => 'latest',
559
+ );
560
 
561
+ if (get_option('xcloner_aws_endpoint') != "" && !get_option("xcloner_aws_region")) {
562
 
563
+ $credentials['endpoint'] = get_option('xcloner_aws_endpoint');
564
+ #$credentials['use_path_style_endpoint'] = true;
565
+ #$credentials['bucket_endpoint'] = false;
566
 
567
 
568
+ }
569
 
570
+ $client = new S3Client($credentials);
571
 
572
+ $adapter = new AwsS3Adapter($client, get_option("xcloner_aws_bucket_name"), get_option("xcloner_aws_prefix"));
573
+ $filesystem = new Filesystem($adapter, new Config([
574
+ 'disable_asserts' => true,
575
+ ]));
576
 
577
+ return array($adapter, $filesystem);
578
+ }
579
 
580
+ public function get_backblaze_filesystem()
581
+ {
582
+ $this->logger->info(sprintf("Creating the BACKBLAZE remote storage connection"), array(""));
583
 
584
+ if (version_compare(phpversion(), '5.6.0', '<')) {
585
+ throw new Exception("BACKBLAZE API requires PHP 5.6 to be installed!");
586
+ }
587
 
588
 
589
+ $client = new B2Client(get_option("xcloner_backblaze_account_id"),
590
+ get_option("xcloner_backblaze_application_key"));
591
+ $adapter = new BackblazeAdapter($client, get_option("xcloner_backblaze_bucket_name"));
592
 
593
+ $filesystem = new Filesystem($adapter, new Config([
594
+ 'disable_asserts' => true,
595
+ ]));
596
 
597
+ return array($adapter, $filesystem);
598
+ }
599
 
600
+ public function get_webdav_filesystem()
601
+ {
602
+ $this->logger->info(sprintf("Creating the WEBDAV remote storage connection"), array(""));
603
 
604
+ if (version_compare(phpversion(), '5.6.0', '<')) {
605
+ throw new Exception("WEBDAV API requires PHP 5.6 to be installed!");
606
+ }
607
 
608
+ $settings = array(
609
+ 'baseUri' => get_option("xcloner_webdav_url"),
610
+ 'userName' => get_option("xcloner_webdav_username"),
611
+ 'password' => get_option("xcloner_webdav_password"),
612
+ //'proxy' => 'locahost:8888',
613
+ );
614
 
615
 
616
+ $client = new SabreClient($settings);
617
+ $adapter = new WebDAVAdapter($client, get_option("xcloner_webdav_target_folder"));
618
+ $filesystem = new Filesystem($adapter, new Config([
619
+ 'disable_asserts' => true,
620
+ ]));
621
 
622
+ return array($adapter, $filesystem);
623
+ }
624
 
625
 
626
+ public function gdrive_construct()
627
+ {
628
 
629
+ //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"))
630
+ if (!class_exists('Google_Client')) {
631
+ return false;
632
+ }
633
 
634
+ //require_once(__DIR__ . "/../../xcloner-google-drive/vendor/autoload.php");
635
 
636
+ $client = new \Google_Client();
637
+ $client->setApplicationName($this->gdrive_app_name);
638
+ $client->setClientId(get_option("xcloner_gdrive_client_id"));
639
+ $client->setClientSecret(get_option("xcloner_gdrive_client_secret"));
640
 
641
+ //$redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF']."?page=xcloner_remote_storage_page&action=set_gdrive_code";
642
+ $redirect_uri = "urn:ietf:wg:oauth:2.0:oob";
643
 
644
+ $client->setRedirectUri($redirect_uri); //urn:ietf:wg:oauth:2.0:oob
645
+ $client->addScope("https://www.googleapis.com/auth/drive");
646
+ $client->setAccessType('offline');
647
 
648
+ return $client;
649
+ }
650
 
651
+ public function get_gdrive_auth_url()
652
+ {
653
+ $client = $this->gdrive_construct();
654
 
655
+ if (!$client) {
656
+ return false;
657
+ }
658
 
659
+ return $authUrl = $client->createAuthUrl();
660
+ }
661
 
662
+ public function set_access_token($code)
663
+ {
664
+ $client = $this->gdrive_construct();
665
 
666
+ if (!$client) {
667
+ $error_msg = "Could not initialize the Google Drive Class, please check that the xcloner-google-drive plugin is enabled...";
668
+ $this->logger->error($error_msg);
669
 
670
+ return false;
671
+ }
672
 
673
+ $token = $client->fetchAccessTokenWithAuthCode($code);
674
+ $client->setAccessToken($token);
675
 
676
+ update_option("xcloner_gdrive_access_token", $token['access_token']);
677
+ update_option("xcloner_gdrive_refresh_token", $token['refresh_token']);
678
 
679
+ $redirect_url = ('http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'] . "?page=xcloner_remote_storage_page#gdrive");
680
 
681
+ ?>
682
  <script>
683
  window.location = '<?php echo $redirect_url?>';
684
  </script>
685
+ <?php
686
 
687
+ }
 
 
 
 
 
 
688
 
689
+ /*
690
+ * php composer.phar remove nao-pon/flysystem-google-drive
691
+ *
692
+ */
693
+ public function get_gdrive_filesystem()
694
+ {
695
 
696
+ if (version_compare(phpversion(), '5.6.0', '<')) {
697
+ throw new Exception("Google Drive API requires PHP 5.6 to be installed!");
698
+ }
699
 
700
+ $this->logger->info(sprintf("Creating the Google Drive remote storage connection"), array(""));
701
 
702
+ $client = $this->gdrive_construct();
 
 
 
 
703
 
704
+ if (!$client) {
705
+ $error_msg = "Could not initialize the Google Drive Class, please check that the xcloner-google-drive plugin is enabled...";
706
+ $this->logger->error($error_msg);
707
+ throw new Exception($error_msg);
708
+ }
709
 
710
+ $client->refreshToken(get_option("xcloner_gdrive_refresh_token"));
711
 
712
+ $service = new \Google_Service_Drive($client);
 
 
 
713
 
714
+ if (get_option("xcloner_gdrive_empty_trash", 0)) {
715
+ $this->logger->info(sprintf("Doing a Google Drive emptyTrash call"), array(""));
716
+ $service->files->emptyTrash();
717
+ }
718
 
719
+ $parent = 'root';
720
+ $dir = basename(get_option("xcloner_gdrive_target_folder"));
721
 
722
+ $folderID = get_option("xcloner_gdrive_target_folder");
723
 
724
+ $tmp = parse_url($folderID);
 
 
725
 
726
+ if (isset($tmp['query'])) {
727
+ $folderID = str_replace("id=", "", $tmp['query']);
728
+ }
 
 
 
729
 
730
+ if (stristr($folderID, "/")) {
731
+ $query = sprintf('mimeType = \'application/vnd.google-apps.folder\' and \'%s\' in parents and name contains \'%s\'',
732
+ $parent, $dir);
733
+ $response = $service->files->listFiles([
734
+ 'pageSize' => 1,
735
+ 'q' => $query
736
+ ]);
737
+
738
+ if (sizeof($response)) {
739
+ foreach ($response as $obj) {
740
+ $folderID = $obj->getId();
741
+ }
742
+ } else {
743
+ $this->xcloner->trigger_message(sprintf(__("Could not find folder ID by name %s",
744
+ 'xcloner-backup-and-restore'), $folderID), "error");
745
+ }
746
+ }
747
 
748
+ $this->logger->info(sprintf("Using target folder with ID %s on the remote storage", $folderID));
749
 
750
+ if (class_exists('XCloner_Google_Drive_Adapter')) {
751
+ $adapter = new XCloner_Google_Drive_Adapter($service, $folderID);
752
+ } else {
753
+ $adapter = new \Hypweb\Flysystem\GoogleDrive\GoogleDriveAdapter($service, $folderID);
754
+ }
755
 
756
+ $filesystem = new \League\Flysystem\Filesystem($adapter, new Config([
757
+ 'disable_asserts' => true,
758
+ ]));
759
 
760
 
761
+ return array($adapter, $filesystem);
762
+ }
763
 
764
+ public function get_ftp_filesystem()
765
+ {
766
+ $this->logger->info(sprintf("Creating the FTP remote storage connection"), array(""));
767
 
768
+ $adapter = new Adapter([
769
+ 'host' => get_option("xcloner_ftp_hostname"),
770
+ 'username' => get_option("xcloner_ftp_username"),
771
+ 'password' => get_option("xcloner_ftp_password"),
772
 
773
+ /** optional config settings */
774
+ 'port' => get_option("xcloner_ftp_port", 21),
775
+ 'root' => get_option("xcloner_ftp_path"),
776
+ 'passive' => get_option("xcloner_ftp_transfer_mode"),
777
+ 'ssl' => get_option("xcloner_ftp_ssl_mode"),
778
+ 'timeout' => get_option("xcloner_ftp_timeout", 30),
779
+ ]);
780
 
781
+ $adapter->connect();
782
 
783
+ $filesystem = new Filesystem($adapter, new Config([
784
+ 'disable_asserts' => true,
785
+ ]));
786
 
787
+ return array($adapter, $filesystem);
788
+ }
789
 
790
+ public function get_sftp_filesystem()
791
+ {
792
+ $this->logger->info(sprintf("Creating the SFTP remote storage connection"), array(""));
793
 
794
+ $adapter = new SftpAdapter([
795
+ 'host' => get_option("xcloner_sftp_hostname"),
796
+ 'username' => get_option("xcloner_sftp_username"),
797
+ 'password' => get_option("xcloner_sftp_password"),
798
 
799
+ /** optional config settings */
800
+ 'port' => get_option("xcloner_sftp_port", 22),
801
+ 'root' => (get_option("xcloner_sftp_path")?get_option("xcloner_sftp_path"):'./'),
802
+ 'privateKey' => get_option("xcloner_sftp_private_key"),
803
+ 'timeout' => get_option("xcloner_ftp_timeout", 30),
804
+ ]);
805
 
806
+ $adapter->connect();
807
 
808
+ $filesystem = new Filesystem($adapter, new Config([
809
+ 'disable_asserts' => true,
810
+ ]));
811
 
812
+ return array($adapter, $filesystem);
813
+ }
814
 
815
+ public function change_storage_status($field, $value)
816
+ {
817
+ $field = $this->xcloner_sanitization->sanitize_input_as_string($field);
818
+ $value = $this->xcloner_sanitization->sanitize_input_as_int($value);
819
 
820
+ return update_option($field, $value);
821
+ }
822
 
823
+ public function get_aws_regions()
824
+ {
825
+ return $this->aws_regions;
826
+ }
827
 
828
  }
includes/class-xcloner-requirements.php CHANGED
@@ -8,7 +8,7 @@ class Xcloner_Requirements {
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
  }
@@ -18,37 +18,37 @@ class Xcloner_Requirements {
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;
@@ -58,7 +58,7 @@ class Xcloner_Requirements {
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
 
@@ -77,68 +77,68 @@ class Xcloner_Requirements {
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
 
@@ -146,21 +146,21 @@ class Xcloner_Requirements {
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
  }
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
  }
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;
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
 
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
 
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
  }
includes/class-xcloner-sanitization.php CHANGED
@@ -7,29 +7,29 @@ class Xcloner_Sanitization {
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
  }
@@ -37,23 +37,23 @@ class Xcloner_Sanitization {
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
  }
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
  }
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
@@ -11,42 +11,44 @@ class Xcloner_Scheduler {
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
  }
@@ -56,42 +58,41 @@ class Xcloner_Scheduler {
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
  }
@@ -99,68 +100,74 @@ class Xcloner_Scheduler {
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'
@@ -170,13 +177,15 @@ class Xcloner_Scheduler {
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'
@@ -186,13 +195,17 @@ class Xcloner_Scheduler {
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'
@@ -202,150 +215,203 @@ class Xcloner_Scheduler {
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
  }
@@ -356,14 +422,14 @@ class Xcloner_Scheduler {
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
  }
11
  private $xcloner_settings;
12
  private $logger;
13
  private $xcloner_file_system;
14
+ private $xcloner_encryption;
15
+ private $xcloner_container;
16
 
17
+ private $allowed_schedules = array("hourly", "twicedaily", "daily", "weekly", "monthly");
18
 
19
  /*public function __call($method, $args) {
20
  echo "$method is not defined";
21
  }*/
22
 
23
+ public function __construct(Xcloner $xcloner_container) {
24
  global $wpdb;
25
 
26
  $this->db = $wpdb;
27
  $wpdb->show_errors = false;
28
 
29
  $this->xcloner_container = $xcloner_container;
30
+ $this->xcloner_settings = $this->xcloner_container->get_xcloner_settings();
31
 
32
+ $this->scheduler_table = $this->db->prefix.$this->scheduler_table;
33
  }
34
 
35
  private function get_xcloner_container() {
36
  return $this->xcloner_container;
37
  }
38
 
39
+ private function set_xcloner_container(Xcloner $container) {
40
  $this->xcloner_container = $container;
41
  }
42
 
43
+ public function get_scheduler_list($return_only_enabled = 0) {
44
+ $list = $this->db->get_results("SELECT * FROM ".$this->scheduler_table);
45
 
46
+ if ($return_only_enabled) {
47
  $new_list = array();
48
 
49
+ foreach ($list as $res) {
50
+ if ($res->status) {
51
+ $res->next_run_time = wp_next_scheduled('xcloner_scheduler_'.$res->id, array($res->id)) + (get_option('gmt_offset') * HOUR_IN_SECONDS);
52
  $new_list[] = $res;
53
  }
54
  }
58
  return $list;
59
  }
60
 
61
+ public function get_next_run_schedule( ) {
62
+ $list = $this->get_scheduler_list($return_only_enabled = 1);
63
 
64
  return $list;
65
  }
66
 
67
+ public function get_schedule_by_id_object($id) {
68
+ $data = $this->db->get_row("SELECT * FROM ".$this->scheduler_table." WHERE id=".$id);
69
 
70
  return $data;
71
  }
72
 
73
+ public function get_schedule_by_id($id) {
74
+ $data = $this->db->get_row("SELECT * FROM ".$this->scheduler_table." WHERE id=".$id, ARRAY_A);
75
 
76
+ if (!$data) {
77
  return false;
78
  }
79
 
80
+ $params = json_decode($data['params']);
81
 
82
  //print_r($params);
83
  $data['params'] = "";
84
  $data['backup_params'] = $params->backup_params;
85
+ $data['table_params'] = json_encode($params->database);
86
+ $data['excluded_files'] = json_encode($params->excluded_files);
 
87
 
88
  return $data;
89
  }
90
 
91
+ public function delete_schedule_by_id($id) {
92
+ $hook = 'xcloner_scheduler_'.$id;
93
+ wp_clear_scheduled_hook($hook, array($id));
94
 
95
+ $data = $this->db->delete($this->scheduler_table, array('id' => $id));
96
 
97
  return $data;
98
  }
100
  public function deactivate_wp_cron_hooks() {
101
  $list = $this->get_scheduler_list();
102
 
103
+ foreach ($list as $schedule) {
104
+ $hook = 'xcloner_scheduler_'.$schedule->id;
105
 
106
+ if ($timestamp = wp_next_scheduled($hook, array($schedule->id))) {
107
+ wp_unschedule_event($timestamp, $hook, array($schedule->id));
108
+ }
109
  }
110
  }
111
 
112
  public function update_wp_cron_hooks() {
113
  $list = $this->get_scheduler_list();
114
 
115
+ foreach ($list as $schedule) {
116
+ $hook = 'xcloner_scheduler_'.$schedule->id;
117
 
118
  //adding the xcloner_scheduler hook with xcloner_scheduler_callback callback
119
+ add_action($hook, array($this, 'xcloner_scheduler_callback'), 10, 1);
120
 
121
+ if (!wp_next_scheduled($hook, array($schedule->id)) and $schedule->status) {
122
 
123
+ if ($schedule->recurrence == "single") {
124
+ wp_schedule_single_event(strtotime($schedule->start_at), $hook, array($schedule->id));
125
  } else {
126
+ wp_schedule_event(strtotime($schedule->start_at), $schedule->recurrence, $hook, array($schedule->id));
127
  }
128
 
129
+ } elseif (!$schedule->status) {
130
+ if ($timestamp = wp_next_scheduled($hook, array($schedule->id))) {
131
+ wp_unschedule_event($timestamp, $hook, array($schedule->id));
132
+ }
133
  }
134
  }
135
 
136
  }
137
 
138
+ public function update_cron_hook($id) {
139
+ $schedule = $this->get_schedule_by_id_object($id);
140
+ $hook = 'xcloner_scheduler_'.$schedule->id;
141
 
142
+ if ($timestamp = wp_next_scheduled($hook, array($schedule->id))) {
143
+ wp_unschedule_event($timestamp, $hook, array($schedule->id));
144
+ }
145
 
146
+ if ($schedule->status) {
147
 
148
+ if ($schedule->recurrence == "single") {
149
+ wp_schedule_single_event(strtotime($schedule->start_at), $hook, array($schedule->id));
150
  } else {
151
+ wp_schedule_event(strtotime($schedule->start_at), $schedule->recurrence, $hook, array($schedule->id));
152
  }
153
 
154
  }
155
  }
156
 
157
+ public function disable_single_cron($schedule_id) {
158
+ $schedule = array();
159
+ $hook = 'xcloner_scheduler_'.$schedule_id;
160
+
161
+ if ($timestamp = wp_next_scheduled($hook, array($schedule_id))) {
162
+ wp_unschedule_event($timestamp, $hook, array($schedule_id));
163
+ }
164
 
165
  $schedule['status'] = 0;
166
 
167
  $update = $this->db->update(
168
  $this->scheduler_table,
169
  $schedule,
170
+ array('id' => $schedule_id),
171
  array(
172
  '%s',
173
  '%s'
177
  return $update;
178
  }
179
 
180
+ public function update_hash($schedule_id, $hash) {
181
+ $schedule = array();
182
+
183
  $schedule['hash'] = $hash;
184
 
185
  $update = $this->db->update(
186
  $this->scheduler_table,
187
  $schedule,
188
+ array('id' => $schedule_id),
189
  array(
190
  '%s',
191
  '%s'
195
  return $update;
196
  }
197
 
198
+ public function update_last_backup($schedule_id, $last_backup) {
199
+ $schedule = array();
200
+
201
+ $this->logger->info(sprintf('Updating last backup %s for schedule id #%s', $last_backup, $schedule_id));
202
+
203
  $schedule['last_backup'] = $last_backup;
204
 
205
  $update = $this->db->update(
206
  $this->scheduler_table,
207
  $schedule,
208
+ array('id' => $schedule_id),
209
  array(
210
  '%s',
211
  '%s'
215
  return $update;
216
  }
217
 
218
+ private function _xcloner_scheduler_callback($id, $schedule) {
219
+ set_time_limit(0);
220
+
221
 
222
  $xcloner = new XCloner();
223
  $xcloner->init();
224
+ $this->set_xcloner_container($xcloner);
225
+ $return_encrypted = array();
226
+ $return = array();
227
+ $additional = array();
228
 
229
  #$hash = $this->xcloner_settings->get_hash();
230
  #$this->get_xcloner_container()->get_xcloner_settings()->set_hash($hash);
231
 
232
  //$this->xcloner_settings = $this->get_xcloner_container()->get_xcloner_settings();
233
  $this->xcloner_file_system = $this->get_xcloner_container()->get_xcloner_filesystem();
234
+ $this->xcloner_encryption = $this->get_xcloner_container()->get_xcloner_encryption();
235
  $this->xcloner_database = $this->get_xcloner_container()->get_xcloner_database();
236
  $this->archive_system = $this->get_xcloner_container()->get_archive_system();
237
+ $this->logger = $this->get_xcloner_container()->get_xcloner_logger()->withName("xcloner_scheduler");
238
  $this->xcloner_remote_storage = $this->get_xcloner_container()->get_xcloner_remote_storage();
239
 
240
+ $this->logger->info(sprintf("New schedule hash is %s", $this->xcloner_settings->get_hash()));
241
 
242
+ if (isset($schedule['backup_params']->diff_start_date) && $schedule['backup_params']->diff_start_date) {
243
+ $this->xcloner_file_system->set_diff_timestamp_start($schedule['backup_params']->diff_start_date);
244
  }
245
 
246
+ if ($schedule['recurrence'] == "single") {
247
+ $this->disable_single_cron($schedule['id']);
248
  }
249
 
250
+ if (!$schedule) {
251
+ $this->logger->info(sprintf("Could not load schedule with id'%s'", $id), array("CRON"));
252
 
253
  return;
254
  }
255
 
256
  //echo $this->get_xcloner_container()->get_xcloner_settings()->get_hash(); exit;
257
 
258
+ $this->update_hash($schedule['id'], $this->xcloner_settings->get_hash());
259
 
260
+ $this->logger->info(sprintf("Starting cron schedule '%s'", $schedule['name']), array("CRON"));
261
 
262
+ $this->xcloner_file_system->set_excluded_files(json_decode($schedule['excluded_files']));
263
 
264
  $init = 1;
265
  $continue = 1;
266
 
267
+ while ($continue) {
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
+ $return = $this->xcloner_database->start_database_recursion((array)json_decode($schedule['table_params']), $return, $init);
282
  $init = 0;
283
  }
284
 
285
+ $this->logger->info(sprintf("Database backup done"), array("CRON"));
286
 
287
+ $this->logger->info(sprintf("Starting file archive process"), array("CRON"));
288
 
289
  $init = 0;
290
  $return['finished'] = 0;
291
  $return['extra'] = array();
292
 
293
+ while (!$return['finished']) {
294
+ $return = $this->archive_system->start_incremental_backup((array)$schedule['backup_params'], $return['extra'], $init);
295
  $init = 0;
296
  }
297
+ $this->logger->info(sprintf("File archive process FINISHED."), array("CRON"));
298
 
299
  //getting the last backup archive file
300
  $return['extra']['backup_parent'] = $this->archive_system->get_archive_name_with_extension();
301
+ if ($this->xcloner_file_system->is_part($this->archive_system->get_archive_name_with_extension())) {
302
  $return['extra']['backup_parent'] = $this->archive_system->get_archive_name_multipart();
303
  }
304
 
305
+ //Updating schedule last backup archive
306
+ $this->update_last_backup($schedule['id'], $return['extra']['backup_parent']);
307
+
308
+ //Encrypting the backup archive
309
+ $return_encrypted['finished'] = 0;
310
+ $return_encrypted['start'] = 0;
311
+ $return_encrypted['iv'] = '';
312
+ $return_encrypted['target_file'] = '';
313
+ $part = 0;
314
+ $backup_parts = array();
315
+
316
+ if ($schedule['backup_params']->backup_encrypt) {
317
+ $this->logger->info(sprintf("Encrypting backup archive %s.", $return['extra']['backup_parent']), array("CRON"));
318
 
 
319
  $backup_file = $return['extra']['backup_parent'];
320
 
321
+ if ($this->xcloner_file_system->is_multipart($return['extra']['backup_parent'])) {
322
+ $backup_parts = $this->xcloner_file_system->get_multipart_files($return['extra']['backup_parent']);
323
+ $backup_file = $backup_parts[$part];
324
+ }
325
+
326
+ while (!$return_encrypted['finished']) {
327
+ $return_encrypted = $this->xcloner_encryption->encrypt_file(
328
+ $backup_file,
329
+ "",
330
+ "",
331
+ "",
332
+ "",
333
+ true,
334
+ true
335
+ );
336
+
337
+ if ($return_encrypted['finished']) {
338
+ ++$part;
339
+
340
+ if ($part < sizeof($backup_parts)) {
341
+ $return_encrypted['finished'] = 0;
342
+ $backup_file = $backup_parts[$part];
343
+ }
344
+ }
345
+ }
346
+ }
347
 
348
+ //Sending backup to remote storage
349
+ if (isset($schedule['remote_storage']) && $schedule['remote_storage'] && array_key_exists($schedule['remote_storage'], $this->xcloner_remote_storage->get_available_storages())) {
350
+ $backup_file = $return['extra']['backup_parent'];
351
+
352
+ $this->logger->info(sprintf("Transferring backup to remote storage %s", strtoupper($schedule['remote_storage'])), array("CRON"));
353
+
354
+ if (method_exists($this->xcloner_remote_storage, "upload_backup_to_storage")) {
355
+ call_user_func_array(array(
356
  $this->xcloner_remote_storage,
357
  "upload_backup_to_storage"
358
+ ), array($backup_file, $schedule['remote_storage']));
359
  }
360
  }
361
 
362
+ //Sending email notification
363
+ if (isset($schedule['backup_params']->email_notification) and $to = $schedule['backup_params']->email_notification) {
364
  try {
365
  $from = "";
366
  $additional['lines_total'] = $return['extra']['lines_total'];
367
+ $subject = sprintf(__("%s - new backup generated %s"), $schedule['name'], $return['extra']['backup_parent']);
368
 
369
+ $this->archive_system->send_notification($to, $from, $subject, $return['extra']['backup_parent'], $schedule, "", $additional);
370
 
371
+ }catch (Exception $e) {
372
+ $this->logger->error($e->getMessage());
373
  }
374
  }
375
 
376
  //CHECK IF WE SHOULD DELETE BACKUP AFTER REMOTE TRANSFER IS DONE
377
+ if ($schedule['remote_storage'] && $this->xcloner_settings->get_xcloner_option('xcloner_cleanup_delete_after_remote_transfer')) {
378
+ $this->logger->info(sprintf("Deleting %s from local storage matching rule xcloner_cleanup_delete_after_remote_transfer", $return['extra']['backup_parent']));
379
+ $this->xcloner_file_system->delete_backup_by_name($return['extra']['backup_parent']);
380
 
381
  }
382
 
383
+ //Removing the tmp filesystem used for backup
384
  $this->xcloner_file_system->remove_tmp_filesystem();
385
 
386
+ //Backup Storage Cleanup
387
  $this->xcloner_file_system->backup_storage_cleanup();
388
 
389
+ //Filesystem Cleanup
390
  $this->xcloner_file_system->cleanup_tmp_directories();
391
  }
392
 
393
+ public function xcloner_scheduler_callback($id, $schedule = "") {
394
+ if ($id) {
395
+ $schedule = $this->get_schedule_by_id($id);
396
  }
397
 
398
  try {
399
+ if (get_option('xcloner_disable_email_notification')) {
400
+ //we disable email notifications
401
+ $schedule['backup_params']->email_notification = "";
402
+ }
403
+ $this->_xcloner_scheduler_callback($id, $schedule);
404
 
405
+ }catch (Exception $e) {
 
 
406
 
407
  //send email to site admin if email notification is not set in the scheduler
408
+ if (!isset($schedule['backup_params']->email_notification) || !$schedule['backup_params']->email_notification) {
409
+ $schedule['backup_params']->email_notification = get_option('admin_email');
410
  }
411
 
412
+ if (isset($schedule['backup_params']->email_notification) && $to = $schedule['backup_params']->email_notification) {
413
  $from = "";
414
+ $this->archive_system->send_notification($to, $from, $schedule['name']." - backup error", "", "", $e->getMessage());
415
  }
416
 
417
  }
422
  $schedules = wp_get_schedules();
423
  $new_schedules = array();
424
 
425
+ foreach ($schedules as $key => $row) {
426
+ if (in_array($key, $this->allowed_schedules)) {
427
+ $new_schedules[$key] = $row;
428
+ $intervals[$key] = $row['interval'];
429
  }
430
  }
431
 
432
+ array_multisort($intervals, SORT_ASC, $new_schedules);
433
 
434
  return $new_schedules;
435
  }
includes/class-xcloner-settings.php CHANGED
@@ -7,10 +7,10 @@ class Xcloner_Settings {
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
 
@@ -18,93 +18,125 @@ class Xcloner_Settings {
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;
@@ -112,27 +144,27 @@ class Xcloner_Settings {
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
  }
@@ -140,7 +172,7 @@ class Xcloner_Settings {
140
  public function get_db_hostname() {
141
  global $wpdb;
142
 
143
- if ( ! $data = get_option( 'xcloner_mysql_hostname' ) ) {
144
  $data = $wpdb->dbhost;
145
  }
146
 
@@ -150,7 +182,7 @@ class Xcloner_Settings {
150
  public function get_db_username() {
151
  global $wpdb;
152
 
153
- if ( ! $data = get_option( 'xcloner_mysql_username' ) ) {
154
  $data = $wpdb->dbuser;
155
  }
156
 
@@ -160,7 +192,7 @@ class Xcloner_Settings {
160
  public function get_db_password() {
161
  global $wpdb;
162
 
163
- if ( ! $data = get_option( 'xcloner_mysql_password' ) ) {
164
  $data = $wpdb->dbpassword;
165
  }
166
 
@@ -170,7 +202,7 @@ class Xcloner_Settings {
170
  public function get_db_database() {
171
  global $wpdb;
172
 
173
- if ( ! $data = get_option( 'xcloner_mysql_database' ) ) {
174
  $data = $wpdb->dbname;
175
  }
176
 
@@ -183,17 +215,20 @@ class Xcloner_Settings {
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;
@@ -204,20 +239,20 @@ class Xcloner_Settings {
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
 
@@ -225,31 +260,31 @@ class Xcloner_Settings {
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
 
@@ -257,269 +292,287 @@ class Xcloner_Settings {
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
  )
@@ -537,127 +590,140 @@ class Xcloner_Settings {
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
  }
@@ -675,26 +741,26 @@ class Xcloner_Settings {
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"
@@ -707,26 +773,26 @@ class Xcloner_Settings {
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"
@@ -735,39 +801,39 @@ class Xcloner_Settings {
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>
@@ -777,26 +843,26 @@ class Xcloner_Settings {
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"
@@ -808,22 +874,22 @@ class Xcloner_Settings {
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 ">
@@ -835,22 +901,22 @@ class Xcloner_Settings {
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
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
 
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(/** @scrutinizer ignore-type */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 = $this->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(/** @scrutinizer ignore-type */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_encryption_key() {
58
+
59
+ if (!get_option('xcloner_encryption_key'))
60
+ {
61
+ $key = $this->randomString(35);
62
+ update_option('xcloner_encryption_key', $key);
63
+ }
64
+
65
+ return get_option('xcloner_encryption_key');
66
+ }
67
+
68
+ /**
69
+ * Create a random string
70
+ * @author XEWeb <>
71
+ * @param $length the length of the string to create
72
+ * @return string
73
+ */
74
+ private function randomString($length = 6) {
75
+ $str = "";
76
+ $characters = array_merge(range('A', 'Z'), range('a', 'z'), range('0', '9'));
77
+ $max = count($characters) - 1;
78
+ for ($i = 0; $i < $length; $i++) {
79
+ $rand = mt_rand(0, $max);
80
+ $str .= $characters[$rand];
81
+ }
82
+ return $str;
83
+ }
84
+
85
  public function get_xcloner_tmp_path_suffix() {
86
+ return "xcloner".$this->get_hash();
87
  }
88
 
89
 
90
+ public function get_xcloner_tmp_path($suffix = true) {
91
+ if (get_option('xcloner_force_tmp_path_site_root')) {
92
  $path = $this->get_xcloner_store_path();
93
  } else {
94
 
95
  $path = sys_get_temp_dir();
96
+ if (!is_dir($path)) {
97
+ try {
98
+ mkdir($path);
99
+ chmod($path, 0777);
100
+ }catch(Exception $e){
101
+ //silent catch
102
+ }
103
  }
104
 
105
+ if (!is_dir($path) or !is_writeable($path)) {
106
  $path = $this->get_xcloner_store_path();
107
  }
108
  }
109
 
110
+ if ($suffix) {
111
+ $path = $path.DS.".".$this->get_xcloner_tmp_path_suffix();
112
  }
113
 
114
  return $path;
115
  }
116
 
117
  public function get_enable_mysql_backup() {
118
+ if (get_option('xcloner_enable_mysql_backup')) {
119
  return true;
120
  }
121
 
122
  return false;
123
  }
124
 
125
+ public function get_backup_extension_name($ext = "") {
126
+ if (!$ext) {
127
+ if (get_option('xcloner_backup_compression_level')) {
128
  $ext = ".tgz";
129
  } else {
130
  $ext = ".tar";
131
  }
132
  }
133
 
134
+ return ($this->get_hash()).$ext;
135
  }
136
 
137
  public function get_hash() {
138
+ if (!$this->hash) {
139
+ $this->set_hash("-".$this->get_server_unique_hash(5));
140
  }
141
 
142
  //echo $this->hash;
144
  }
145
 
146
  public function generate_new_hash() {
147
+ $hash = "-".md5(rand());
148
 
149
+ $this->set_hash(substr($hash, 0, 6));
150
 
151
  return $hash;
152
  }
153
 
154
+ public function set_hash($hash = "") {
155
+ if (substr($hash, 0, 1) != "-" and strlen($hash)) {
156
+ $hash = "-".$hash;
157
  }
158
 
159
+ $this->hash = substr($hash, 0, 6);
160
 
161
  return $this;
162
  }
163
 
164
  public function get_default_backup_name() {
165
+ $data = parse_url(get_site_url());
166
 
167
+ $backup_name = "backup_[domain]".(isset($data['port']) ? "_".$data['port'] : "")."-[time]-".($this->get_enable_mysql_backup() ? "sql" : "nosql");
168
 
169
  return $backup_name;
170
  }
172
  public function get_db_hostname() {
173
  global $wpdb;
174
 
175
+ if (!$data = get_option('xcloner_mysql_hostname')) {
176
  $data = $wpdb->dbhost;
177
  }
178
 
182
  public function get_db_username() {
183
  global $wpdb;
184
 
185
+ if (!$data = get_option('xcloner_mysql_username')) {
186
  $data = $wpdb->dbuser;
187
  }
188
 
192
  public function get_db_password() {
193
  global $wpdb;
194
 
195
+ if (!$data = get_option('xcloner_mysql_password')) {
196
  $data = $wpdb->dbpassword;
197
  }
198
 
202
  public function get_db_database() {
203
  global $wpdb;
204
 
205
+ if (!$data = get_option('xcloner_mysql_database')) {
206
  $data = $wpdb->dbname;
207
  }
208
 
215
  return $wpdb->prefix;
216
  }
217
 
218
+ /**
219
+ * @param string $option
220
+ */
221
+ public function get_xcloner_option($option) {
222
+ $data = get_option($option);
223
 
224
  return $data;
225
  }
226
 
227
+ public function get_server_unique_hash($strlen = 0) {
228
+ $hash = md5(get_home_url().__DIR__);
229
 
230
+ if ($strlen) {
231
+ $hash = substr($hash, 0, $strlen);
232
  }
233
 
234
  return $hash;
239
  $this->xcloner_sanitization = $this->get_xcloner_container()->get_xcloner_sanitization();
240
 
241
  //ADDING MISSING OPTIONS
242
+ if (false == get_option('xcloner_mysql_settings_page')) {
243
+ add_option('xcloner_mysql_settings_page');
244
  } // end if
245
 
246
+ if (false == get_option('xcloner_cron_settings_page')) {
247
+ add_option('xcloner_cron_settings_page');
248
  } // end if
249
 
250
+ if (false == get_option('xcloner_system_settings_page')) {
251
+ add_option('xcloner_system_settings_page');
252
  } // end if
253
 
254
+ if (false == get_option('xcloner_cleanup_settings_page')) {
255
+ add_option('xcloner_cleanup_settings_page');
256
  } // end if
257
 
258
 
260
  //GENERAL section
261
  add_settings_section(
262
  'xcloner_general_settings_group',
263
+ __(' '),
264
+ array($this, 'xcloner_settings_section_cb'),
265
  'xcloner_settings_page'
266
  );
267
  //MYSQL section
268
  add_settings_section(
269
  'xcloner_mysql_settings_group',
270
+ __(' '),
271
+ array($this, 'xcloner_settings_section_cb'),
272
  'xcloner_mysql_settings_page'
273
  );
274
 
275
  //SYSTEM section
276
  add_settings_section(
277
  'xcloner_system_settings_group',
278
+ __('These are advanced options recommended for developers!', 'xcloner-backup-and-restore'),
279
+ array($this, 'xcloner_settings_section_cb'),
280
  'xcloner_system_settings_page'
281
  );
282
 
283
  //CLEANUP section
284
  add_settings_section(
285
  'xcloner_cleanup_settings_group',
286
+ __(' '),
287
+ array($this, 'xcloner_settings_section_cb'),
288
  'xcloner_cleanup_settings_page'
289
  );
290
 
292
  //CRON section
293
  add_settings_section(
294
  'xcloner_cron_settings_group',
295
+ __(' '),
296
+ array($this, 'xcloner_settings_section_cb'),
297
  'xcloner_cron_settings_page'
298
  );
299
 
300
 
301
  //REGISTERING THE 'GENERAL SECTION' FIELDS
302
+ register_setting('xcloner_general_settings_group', 'xcloner_backup_compression_level', array(
303
  $this->xcloner_sanitization,
304
  "sanitize_input_as_int"
305
+ ));
306
  add_settings_field(
307
  'xcloner_backup_compression_level',
308
+ __('Backup Compression Level', 'xcloner-backup-and-restore'),
309
+ array($this, 'do_form_range_field'),
310
  'xcloner_settings_page',
311
  'xcloner_general_settings_group',
312
  array(
313
  'xcloner_backup_compression_level',
314
+ __('Options between [0-9]. Value 0 means no compression, while 9 is maximum compression affecting cpu load', 'xcloner-backup-and-restore'),
315
  0,
316
  9
317
  )
318
  );
319
 
320
+ register_setting('xcloner_general_settings_group', 'xcloner_start_path', array(
321
  $this->xcloner_sanitization,
322
  "sanitize_input_as_absolute_path"
323
+ ));
324
  add_settings_field(
325
  'xcloner_start_path',
326
+ __('Backup Start Location', 'xcloner-backup-and-restore'),
327
+ array($this, 'do_form_text_field'),
328
  'xcloner_settings_page',
329
  'xcloner_general_settings_group',
330
  array(
331
  'xcloner_start_path',
332
+ __('Base path location from where XCloner can start the Backup.', 'xcloner-backup-and-restore'),
333
  $this->get_xcloner_start_path(),
334
  //'disabled'
335
  )
336
  );
337
 
338
+ register_setting('xcloner_general_settings_group', 'xcloner_store_path', array(
339
  $this->xcloner_sanitization,
340
  "sanitize_input_as_absolute_path"
341
+ ));
342
  add_settings_field(
343
  'xcloner_store_path',
344
+ __('Backup Storage Location', 'xcloner-backup-and-restore'),
345
+ array($this, 'do_form_text_field'),
346
  'xcloner_settings_page',
347
  'xcloner_general_settings_group',
348
  array(
349
  'xcloner_store_path',
350
+ __('Location where XCloner will store the Backup archives.', 'xcloner-backup-and-restore'),
351
  $this->get_xcloner_store_path(),
352
  //'disabled'
353
  )
354
  );
355
 
356
+ register_setting('xcloner_general_settings_group', 'xcloner_encryption_key', array(
357
+ $this->xcloner_sanitization,
358
+ "sanitize_input_as_string"
359
+ ));
360
+ add_settings_field(
361
+ 'xcloner_encryption_key',
362
+ __('Backup Encryption Key', 'xcloner-backup-and-restore'),
363
+ array($this, 'do_form_text_field'),
364
+ 'xcloner_settings_page',
365
+ 'xcloner_general_settings_group',
366
+ array(
367
+ 'xcloner_encryption_key',
368
+ __('Backup Encryption Key used to Encrypt/Decrypt backups, you might want to save this somewhere else as well.', 'xcloner-backup-and-restore'),
369
+ $this->get_xcloner_encryption_key(),
370
+ //'disabled'
371
+ )
372
+ );
373
+
374
+ register_setting('xcloner_general_settings_group', 'xcloner_enable_log', array(
375
  $this->xcloner_sanitization,
376
  "sanitize_input_as_int"
377
+ ));
378
  add_settings_field(
379
  'xcloner_enable_log',
380
+ __('Enable XCloner Backup Log', 'xcloner-backup-and-restore'),
381
+ array($this, 'do_form_switch_field'),
382
  'xcloner_settings_page',
383
  'xcloner_general_settings_group',
384
  array(
385
  'xcloner_enable_log',
386
+ 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())
387
  )
388
  );
389
 
390
+ register_setting('xcloner_general_settings_group', 'xcloner_enable_pre_update_backup', array(
391
  $this->xcloner_sanitization,
392
  "sanitize_input_as_int"
393
+ ));
394
  add_settings_field(
395
  'xcloner_enable_pre_update_backup',
396
+ __('Generate Backups before Automatic WP Upgrades', 'xcloner-backup-and-restore'),
397
+ array($this, 'do_form_switch_field'),
398
  'xcloner_settings_page',
399
  'xcloner_general_settings_group',
400
  array(
401
  'xcloner_enable_pre_update_backup',
402
+ 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())
403
  )
404
  );
405
 
406
+ register_setting('xcloner_general_settings_group', 'xcloner_regex_exclude', array(
407
  $this->xcloner_sanitization,
408
  "sanitize_input_as_raw"
409
+ ));
410
  add_settings_field(
411
  'xcloner_regex_exclude',
412
+ __('Regex Exclude Files', 'xcloner-backup-and-restore'),
413
+ array($this, 'do_form_textarea_field'),
414
  'xcloner_settings_page',
415
  'xcloner_general_settings_group',
416
  array(
417
  'xcloner_regex_exclude',
418
+ __('Regular expression match to exclude files and folders, example patterns provided below, one pattern per line', 'xcloner-backup-and-restore'),
419
  //$this->get_xcloner_store_path(),
420
  //'disabled'
421
  )
422
  );
423
 
424
  //REGISTERING THE 'MYSQL SECTION' FIELDS
425
+ register_setting('xcloner_mysql_settings_group', 'xcloner_enable_mysql_backup', array(
426
  $this->xcloner_sanitization,
427
  "sanitize_input_as_int"
428
+ ));
429
  add_settings_field(
430
  'xcloner_enable_mysql_backup',
431
+ __('Enable Mysql Backup', 'xcloner-backup-and-restore'),
432
+ array($this, 'do_form_switch_field'),
433
  'xcloner_mysql_settings_page',
434
  'xcloner_mysql_settings_group',
435
  array(
436
  'xcloner_enable_mysql_backup',
437
+ __('Enable Mysql Backup Option. If you don\'t want to backup the database, you can disable this.', 'xcloner-backup-and-restore')
438
  )
439
  );
440
 
441
+ register_setting('xcloner_mysql_settings_group', 'xcloner_backup_only_wp_tables');
442
  add_settings_field(
443
  'xcloner_backup_only_wp_tables',
444
+ __('Backup only WP tables', 'xcloner-backup-and-restore'),
445
+ array($this, 'do_form_switch_field'),
446
  'xcloner_mysql_settings_page',
447
  'xcloner_mysql_settings_group',
448
  array(
449
  'xcloner_backup_only_wp_tables',
450
+ sprintf(__('Enable this if you only want to Backup only tables starting with \'%s\' prefix', 'xcloner-backup-and-restore'), $this->get_table_prefix())
451
  )
452
  );
453
 
454
+ register_setting('xcloner_mysql_settings_group', 'xcloner_mysql_hostname', array(
455
  $this->xcloner_sanitization,
456
  "sanitize_input_as_raw"
457
+ ));
458
  add_settings_field(
459
  'xcloner_mysql_hostname',
460
+ __('Mysql Hostname', 'xcloner-backup-and-restore'),
461
+ array($this, 'do_form_text_field'),
462
  'xcloner_mysql_settings_page',
463
  'xcloner_mysql_settings_group',
464
  array(
465
  'xcloner_mysql_hostname',
466
+ __('Wordpress mysql hostname', 'xcloner-backup-and-restore'),
467
  $this->get_db_hostname(),
468
  'disabled'
469
  )
470
  );
471
 
472
+ register_setting('xcloner_mysql_settings_group', 'xcloner_mysql_username', array(
473
  $this->xcloner_sanitization,
474
  "sanitize_input_as_raw"
475
+ ));
476
  add_settings_field(
477
  'xcloner_mysql_username',
478
+ __('Mysql Username', 'xcloner-backup-and-restore'),
479
+ array($this, 'do_form_text_field'),
480
  'xcloner_mysql_settings_page',
481
  'xcloner_mysql_settings_group',
482
  array(
483
  'xcloner_mysql_username',
484
+ __('Wordpress mysql username', 'xcloner-backup-and-restore'),
485
  $this->get_db_username(),
486
  'disabled'
487
  )
488
  );
489
 
490
+ register_setting('xcloner_mysql_settings_group', 'xcloner_mysql_database', array(
491
  $this->xcloner_sanitization,
492
  "sanitize_input_as_raw"
493
+ ));
494
  add_settings_field(
495
  'xcloner_mysql_database',
496
+ __('Mysql Database', 'xcloner-backup-and-restore'),
497
+ array($this, 'do_form_text_field'),
498
  'xcloner_mysql_settings_page',
499
  'xcloner_mysql_settings_group',
500
  array(
501
  'xcloner_mysql_database',
502
+ __('Wordpress mysql database', 'xcloner-backup-and-restore'),
503
  $this->get_db_database(),
504
  'disabled'
505
  )
506
  );
507
 
508
  //REGISTERING THE 'SYSTEM SECTION' FIELDS
509
+ register_setting('xcloner_system_settings_group', 'xcloner_size_limit_per_request', array(
510
  $this->xcloner_sanitization,
511
  "sanitize_input_as_int"
512
+ ));
513
  add_settings_field(
514
  'xcloner_size_limit_per_request',
515
+ __('Data Size Limit Per Request', 'xcloner-backup-and-restore'),
516
+ array($this, 'do_form_range_field'),
517
  'xcloner_system_settings_page',
518
  'xcloner_system_settings_group',
519
  array(
520
  'xcloner_size_limit_per_request',
521
+ __('Use this option to set how much file data can XCloner backup in one AJAX request. Range 0-1024 MB', 'xcloner-backup-and-restore'),
522
  0,
523
  1024
524
  )
525
  );
526
 
527
+ register_setting('xcloner_system_settings_group', 'xcloner_files_to_process_per_request', array(
528
  $this->xcloner_sanitization,
529
  "sanitize_input_as_int"
530
+ ));
531
  add_settings_field(
532
  'xcloner_files_to_process_per_request',
533
+ __('Files To Process Per Request', 'xcloner-backup-and-restore'),
534
+ array($this, 'do_form_range_field'),
535
  'xcloner_system_settings_page',
536
  'xcloner_system_settings_group',
537
  array(
538
  'xcloner_files_to_process_per_request',
539
+ __('Use this option to set how many files XCloner should process at one time before doing another AJAX call', 'xcloner-backup-and-restore'),
540
  0,
541
  1000
542
  )
543
  );
544
 
545
+ register_setting('xcloner_system_settings_group', 'xcloner_directories_to_scan_per_request', array(
546
  $this->xcloner_sanitization,
547
  "sanitize_input_as_int"
548
+ ));
549
  add_settings_field(
550
  'xcloner_directories_to_scan_per_request',
551
+ __('Directories To Scan Per Request', 'xcloner-backup-and-restore'),
552
+ array($this, 'do_form_range_field'),
553
  'xcloner_system_settings_page',
554
  'xcloner_system_settings_group',
555
  array(
556
  'xcloner_directories_to_scan_per_request',
557
+ __('Use this option to set how many directories XCloner should scan at one time before doing another AJAX call', 'xcloner-backup-and-restore'),
558
  0,
559
  1000
560
  )
561
  );
562
 
563
+ register_setting('xcloner_system_settings_group', 'xcloner_database_records_per_request', array(
564
  $this->xcloner_sanitization,
565
  "sanitize_input_as_int"
566
+ ));
567
  add_settings_field(
568
  'xcloner_database_records_per_request',
569
+ __('Database Records Per Request', 'xcloner-backup-and-restore'),
570
+ array($this, 'do_form_range_field'),
571
  'xcloner_system_settings_page',
572
  'xcloner_system_settings_group',
573
  array(
574
  'xcloner_database_records_per_request',
575
+ __('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'),
576
  0,
577
  100000
578
  )
590
  )
591
  );*/
592
 
593
+ register_setting('xcloner_system_settings_group', 'xcloner_exclude_files_larger_than_mb', array(
594
  $this->xcloner_sanitization,
595
  "sanitize_input_as_int"
596
+ ));
597
  add_settings_field(
598
  'xcloner_exclude_files_larger_than_mb',
599
+ __('Exclude files larger than (MB)', 'xcloner-backup-and-restore'),
600
+ array($this, 'do_form_number_field'),
601
  'xcloner_system_settings_page',
602
  'xcloner_system_settings_group',
603
  array(
604
  'xcloner_exclude_files_larger_than_mb',
605
+ __('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'),
606
  )
607
  );
608
 
609
+ register_setting('xcloner_system_settings_group', 'xcloner_split_backup_limit', array(
610
  $this->xcloner_sanitization,
611
  "sanitize_input_as_int"
612
+ ));
613
  add_settings_field(
614
  'xcloner_split_backup_limit',
615
+ __('Split Backup Archive Limit (MB)', 'xcloner-backup-and-restore'),
616
+ array($this, 'do_form_number_field'),
617
  'xcloner_system_settings_page',
618
  'xcloner_system_settings_group',
619
  array(
620
  'xcloner_split_backup_limit',
621
+ __('Use this option to automatically split the backup archive into smaller parts. Range 0-10000 MB', 'xcloner-backup-and-restore'),
622
  )
623
  );
624
 
625
+ register_setting('xcloner_system_settings_group', 'xcloner_force_tmp_path_site_root');
626
  add_settings_field(
627
  'xcloner_force_tmp_path_site_root',
628
+ __('Force Temporary Path Within XCloner Storage', 'xcloner-backup-and-restore'),
629
+ array($this, 'do_form_switch_field'),
630
  'xcloner_system_settings_page',
631
  'xcloner_system_settings_group',
632
  array(
633
  'xcloner_force_tmp_path_site_root',
634
+ 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())
635
+ )
636
+ );
637
+
638
+ register_setting('xcloner_system_settings_group', 'xcloner_disable_email_notification');
639
+ add_settings_field(
640
+ 'xcloner_disable_email_notification',
641
+ __('Disable Email Notifications', 'xcloner-backup-and-restore'),
642
+ array($this, 'do_form_switch_field'),
643
+ 'xcloner_system_settings_page',
644
+ 'xcloner_system_settings_group',
645
+ array(
646
+ 'xcloner_disable_email_notification',
647
+ sprintf(__('Enable this option if you want the XCloner to NOT send email notifications on successful backups', 'xcloner-backup-and-restore'), $this->get_table_prefix())
648
  )
649
  );
650
 
651
  //REGISTERING THE 'CLEANUP SECTION' FIELDS
652
+ register_setting('xcloner_cleanup_settings_group', 'xcloner_cleanup_retention_limit_days', array(
653
  $this->xcloner_sanitization,
654
  "sanitize_input_as_int"
655
+ ));
656
  add_settings_field(
657
  'xcloner_cleanup_retention_limit_days',
658
+ __('Cleanup by Date(days)', 'xcloner-backup-and-restore'),
659
+ array($this, 'do_form_number_field'),
660
  'xcloner_cleanup_settings_page',
661
  'xcloner_cleanup_settings_group',
662
  array(
663
  'xcloner_cleanup_retention_limit_days',
664
+ __('Specify the maximum number of days a backup archive can be kept on the server. 0 disables this option', 'xcloner-backup-and-restore')
665
  )
666
  );
667
 
668
+ register_setting('xcloner_cleanup_settings_group', 'xcloner_cleanup_retention_limit_archives', array(
669
  $this->xcloner_sanitization,
670
  "sanitize_input_as_int"
671
+ ));
672
  add_settings_field(
673
  'xcloner_cleanup_retention_limit_archives',
674
+ __('Cleanup by Quantity', 'xcloner-backup-and-restore'),
675
+ array($this, 'do_form_number_field'),
676
  'xcloner_cleanup_settings_page',
677
  'xcloner_cleanup_settings_group',
678
  array(
679
  'xcloner_cleanup_retention_limit_archives',
680
+ __('Specify the maximum number of backup archives to keep on the server. 0 disables this option', 'xcloner-backup-and-restore')
681
  )
682
  );
683
 
684
+ register_setting('xcloner_cleanup_settings_group', 'xcloner_cleanup_capacity_limit', array(
685
  $this->xcloner_sanitization,
686
  "sanitize_input_as_int"
687
+ ));
688
  add_settings_field(
689
  'xcloner_cleanup_capacity_limit',
690
+ __('Cleanup by Capacity(MB)', 'xcloner-backup-and-restore'),
691
+ array($this, 'do_form_number_field'),
692
  'xcloner_cleanup_settings_page',
693
  'xcloner_cleanup_settings_group',
694
  array(
695
  'xcloner_cleanup_capacity_limit',
696
+ __('Remove oldest backups if all created backups exceed the configured limit in Megabytes. 0 disables this option', 'xcloner-backup-and-restore')
697
  )
698
  );
699
 
700
+ register_setting('xcloner_cleanup_settings_group', 'xcloner_cleanup_delete_after_remote_transfer', array(
701
  $this->xcloner_sanitization,
702
  "sanitize_input_as_int"
703
+ ));
704
  add_settings_field(
705
  'xcloner_cleanup_delete_after_remote_transfer',
706
+ __('Delete Backup After Remote Storage Transfer', 'xcloner-backup-and-restore'),
707
+ array($this, 'do_form_switch_field'),
708
  'xcloner_cleanup_settings_page',
709
  'xcloner_cleanup_settings_group',
710
  array(
711
  'xcloner_cleanup_delete_after_remote_transfer',
712
+ __('Remove backup created automatically from local storage after sending the backup to Remote Storage', 'xcloner-backup-and-restore')
713
  )
714
  );
715
 
716
  //REGISTERING THE 'CRON SECTION' FIELDS
717
+ register_setting('xcloner_cron_settings_group', 'xcloner_cron_frequency');
718
  add_settings_field(
719
  'xcloner_cron_frequency',
720
+ __('Cron frequency', 'xcloner-backup-and-restore'),
721
+ array($this, 'do_form_text_field'),
722
  'xcloner_cron_settings_page',
723
  'xcloner_cron_settings_group',
724
  array(
725
  'xcloner_cron_frequency',
726
+ __('Cron frequency')
727
  )
728
  );
729
  }
741
  }
742
 
743
  // text field content cb
744
+ public function do_form_text_field($params) {
745
+ if (!isset($params['3'])) {
746
  $params[3] = 0;
747
  }
748
+ if (!isset($params['2'])) {
749
  $params[2] = 0;
750
  }
751
 
752
+ list($fieldname, $label, $value, $disabled) = $params;
753
 
754
+ if (!$value) {
755
+ $value = get_option($fieldname);
756
  }
757
  // output the field
758
  ?>
759
  <div class="row">
760
  <div class="input-field col s10 m10 l8">
761
+ <input class="validate" <?php echo ($disabled) ? "disabled" : "" ?> name="<?php echo $fieldname ?>"
762
  id="<?php echo $fieldname ?>" type="text" class="validate"
763
+ value="<?php echo isset($value) ? esc_attr($value) : ''; ?>">
764
  </div>
765
  <div class="col s2 m2 ">
766
  <a class="btn-floating tooltipped btn-small" data-position="left" data-delay="50"
773
  }
774
 
775
  // textarea field content cb
776
+ public function do_form_textarea_field($params) {
777
+ if (!isset($params['3'])) {
778
  $params[3] = 0;
779
  }
780
+ if (!isset($params['2'])) {
781
  $params[2] = 0;
782
  }
783
 
784
+ list($fieldname, $label, $value, $disabled) = $params;
785
 
786
+ if (!$value) {
787
+ $value = get_option($fieldname);
788
  }
789
  // output the field
790
  ?>
791
  <div class="row">
792
  <div class="input-field col s10 m10 l8">
793
+ <textarea class="validate" <?php echo ($disabled) ? "disabled" : "" ?> name="<?php echo $fieldname ?>"
794
  id="<?php echo $fieldname ?>" type="text" class="validate"
795
+ value=""><?php echo isset($value) ? esc_attr($value) : ''; ?></textarea>
796
  </div>
797
  <div class="col s2 m2 ">
798
  <a class="btn-floating tooltipped btn-small" data-position="center" data-html="true" data-delay="50"
801
  <div class="col s12">
802
  <ul class="xcloner_regex_exclude_limit">
803
  <li>Exclude all except .php file: <span
804
+ class="regex_pattern"><?php echo htmlentities('(.*)\.(.+)$(?<!(php))') ?></span></li>
805
  <li>Exclude all except .php and .txt: <span
806
+ class="regex_pattern"> <?php echo htmlentities('(.*)\.(.+)$(?<!(php|txt))') ?></span>
807
  </li>
808
  <li>Exclude all .avi files: <span
809
+ class="regex_pattern"> <?php echo htmlentities('(.*)\.(.+)$(?<=(avi))') ?></span></li>
810
  <li>Exclude all .jpg,.gif and .png files: <span
811
+ class="regex_pattern"> <?php echo htmlentities('(.*)\.(.+)$(?<=(gif|png|jpg))') ?></span>
812
  </li>
813
  <li>Exclude all .svn and .git: <span
814
+ class="regex_pattern"> <?php echo htmlentities('(.*)\.(svn|git)(.*)$') ?></span></li>
815
  <li>Exclude root directory /test: <span
816
+ class="regex_pattern"> <?php echo htmlentities('\/test(.*)$') ?></span> or <span
817
+ class="regex_pattern"> <?php echo htmlentities('test(.*)$') ?></span></li>
818
  <li>Exclude the wp-admin folder: <span
819
+ class="regex_pattern"> <?php echo htmlentities('(\/wp-admin)(.*)$') ?></span></li>
820
  <li>Exclude the wp-content/uploads folder: <span
821
+ class="regex_pattern"> <?php echo htmlentities('(\/wp-content\/uploads)(.*)$') ?></span>
822
  </li>
823
  <li>Exclude the wp-admin, wp-includes and wp-config.php: <span
824
+ class="regex_pattern"> <?php echo htmlentities('\/(wp-admin|wp-includes|wp-config.php)(.*)$') ?></span>
825
  </li>
826
  <li>Exclude wp-content/updraft and wp/content/uploads/wp_all_backup folder :<span
827
  class="regex_pattern">\/(wp-content\/updraft|\/wp-content\/uploads\/wp_all_backup)(.*)$</span>
828
  </li>
829
  <li>Exclude all cache folders from wp-content/ and it's subdirectories: <span
830
+ class="regex_pattern"> <?php echo htmlentities('\/wp-content(.*)\/cache($|\/)(.*)') ?></span>
831
  </li>
832
  <li>Exclude wp-content/cache/ folder: <span
833
+ class="regex_pattern"> <?php echo htmlentities('\/wp-content\/cache(.*)') ?></span>
834
  </li>
835
  <li>Exclude all error_log files: <span
836
+ class="regex_pattern"> <?php echo htmlentities('(.*)error_log$') ?></span></li>
837
  </ul>
838
  </div>
839
  </div>
843
  }
844
 
845
  // number field content cb
846
+ public function do_form_number_field($params) {
847
+ if (!isset($params['3'])) {
848
  $params[3] = 0;
849
  }
850
+ if (!isset($params['2'])) {
851
  $params[2] = 0;
852
  }
853
 
854
+ list($fieldname, $label, $value, $disabled) = $params;
855
 
856
+ if (!$value) {
857
+ $value = get_option($fieldname);
858
  }
859
  // output the field
860
  ?>
861
  <div class="row">
862
  <div class="input-field col s10 m5 l3">
863
+ <input class="validate" <?php echo ($disabled) ? "disabled" : "" ?> name="<?php echo $fieldname ?>"
864
  id="<?php echo $fieldname ?>" type="number" class="validate"
865
+ value="<?php echo isset($value) ? esc_attr($value) : ''; ?>">
866
  </div>
867
  <div class="col s2 m2 ">
868
  <a class="btn-floating tooltipped btn-small" data-html="true" data-position="center" data-delay="50"
874
  <?php
875
  }
876
 
877
+ public function do_form_range_field($params) {
878
+ if (!isset($params['4'])) {
879
  $params[4] = 0;
880
  }
881
 
882
+ list($fieldname, $label, $range_start, $range_end, $disabled) = $params;
883
+ $value = get_option($fieldname);
884
  ?>
885
  <div class="row">
886
  <div class="input-field col s10 m10 l8">
887
  <p class="range-field">
888
+ <input <?php echo ($disabled) ? "disabled" : "" ?> type="range" name="<?php echo $fieldname ?>"
889
  id="<?php echo $fieldname ?>"
890
  min="<?php echo $range_start ?>"
891
  max="<?php echo $range_end ?>"
892
+ value="<?php echo isset($value) ? esc_attr($value) : ''; ?>"/>
893
  </p>
894
  </div>
895
  <div class="col s2 m2 ">
901
  }
902
 
903
 
904
+ public function do_form_switch_field($params) {
905
+ if (!isset($params['2'])) {
906
  $params[2] = 0;
907
  }
908
+ list($fieldname, $label, $disabled) = $params;
909
+ $value = get_option($fieldname);
910
  ?>
911
  <div class="row">
912
  <div class="input-field col s10 m5 l3">
913
  <div class="switch">
914
  <label>
915
  Off
916
+ <input <?php echo ($disabled) ? "disabled" : "" ?> type="checkbox"
917
  name="<?php echo $fieldname ?>"
918
  id="<?php echo $fieldname ?>"
919
+ value="1" <?php echo ($value) ? 'checked="checked"' : ''; ?>
920
  ">
921
  <span class="lever"></span>
922
  On
includes/class-xcloner.php CHANGED
@@ -83,6 +83,8 @@ class Xcloner {
83
  private $xcloner_scheduler;
84
  private $xcloner_remote_storage;
85
  private $xcloner_file_transfer;
 
 
86
  /**
87
  * Define the core functionality of the plugin.
88
  *
@@ -112,7 +114,17 @@ class Xcloner {
112
 
113
  }
114
 
115
- public function get_xcloner_settings()
 
 
 
 
 
 
 
 
 
 
116
  {
117
  return $this->xcloner_settings;
118
  }
@@ -162,15 +174,29 @@ class Xcloner {
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))
172
  {
173
- if(!@mkdir($backup_storage_path))
174
  {
175
  $status = "error";
176
  $message = sprintf(__("Unable to create the Backup Storage Location Folder %s . Please fix this before starting the backup process."), $backup_storage_path);
@@ -178,7 +204,7 @@ class Xcloner {
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);
@@ -192,15 +218,15 @@ class Xcloner {
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
  ?>
202
  <div class="notice notice-<?php echo $status?> is-dismissible">
203
- <p><?php _e( $message, 'xcloner-backup-and-restore' ); ?></p>
204
  </div>
205
  <?php
206
  }
@@ -227,79 +253,84 @@ class Xcloner {
227
  * The class responsible for orchestrating the actions and filters of the
228
  * core plugin.
229
  */
230
- require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-xcloner-loader.php';
231
 
232
  /**
233
  * The class responsible for defining internationalization functionality
234
  * of the plugin.
235
  */
236
- require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-xcloner-i18n.php';
237
 
238
  /**
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
  */
296
- require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-xcloner-scheduler.php';
 
 
 
 
 
297
 
298
  /**
299
  * The class responsible for defining all actions that occur in the public-facing
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
 
@@ -318,10 +349,10 @@ class Xcloner {
318
 
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
 
326
  }
327
 
@@ -334,13 +365,13 @@ class Xcloner {
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
  /**
@@ -349,33 +380,33 @@ class Xcloner {
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(){
377
- $this->xcloner_file_system = new Xcloner_File_System($this);
378
- $this->xcloner_file_system->remove_tmp_filesystem();
379
  });
380
  }
381
 
@@ -392,23 +423,29 @@ class Xcloner {
392
  }
393
 
394
  /*
 
 
395
  * type = core|plugin|theme|translation
396
  */
397
  public function pre_auto_update($type, $item, $context)
398
  {
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(
414
  "^(?!(wp-admin|wp-includes|(?!.*\/.*.php)))(.*)$",
@@ -418,7 +455,7 @@ class Xcloner {
418
 
419
  $dir_array = explode(DS, $plugins_dir);
420
 
421
- foreach($dir_array as $dir)
422
  {
423
  $data .= "\/".$dir;
424
  $regex .= $data."$|";
@@ -434,7 +471,7 @@ class Xcloner {
434
 
435
  $dir_array = explode(DS, $themes_dir);
436
 
437
- foreach($dir_array as $dir)
438
  {
439
  $data .= "\/".$dir;
440
  $regex .= $data."$|";
@@ -450,7 +487,7 @@ class Xcloner {
450
 
451
  $dir_array = explode(DS, $langs_dir);
452
 
453
- foreach($dir_array as $dir)
454
  {
455
  $data .= "\/".$dir;
456
  $regex .= $data."$|";
@@ -476,9 +513,9 @@ class Xcloner {
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
 
@@ -493,10 +530,10 @@ class Xcloner {
493
  */
494
  private function define_public_hooks() {
495
 
496
- $plugin_public = new Xcloner_Public( $this );
497
 
498
- $this->loader->add_action( 'wp_enqueue_scripts', $plugin_public, 'enqueue_styles' );
499
- $this->loader->add_action( 'wp_enqueue_scripts', $plugin_public, 'enqueue_scripts' );
500
 
501
  }
502
 
@@ -505,91 +542,102 @@ class Xcloner {
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) {
518
- $levels=[];
519
- foreach (get_defined_constants() as $key=>$value) {
520
- if (strpos($key,'E_')!==0) {continue;}
521
- $levels[$value]= $key; //substr($key,2);
522
- }
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') );
547
- add_action( 'wp_ajax_get_file_system_action', array($xcloner_api,'get_file_system_action') );
548
- add_action( 'wp_ajax_scan_filesystem', array($xcloner_api,'scan_filesystem') );
549
- add_action( 'wp_ajax_backup_database', array($xcloner_api,'backup_database') );
550
- add_action( 'wp_ajax_backup_files' , array($xcloner_api,'backup_files') );
551
- add_action( 'wp_ajax_save_schedule' , array($xcloner_api,'save_schedule') );
552
- add_action( 'wp_ajax_get_schedule_by_id', array($xcloner_api,'get_schedule_by_id') );
553
- add_action( 'wp_ajax_get_scheduler_list', array($xcloner_api,'get_scheduler_list') );
554
- add_action( 'wp_ajax_delete_schedule_by_id' , array($xcloner_api,'delete_schedule_by_id') );
555
- add_action( 'wp_ajax_delete_backup_by_name' , array($xcloner_api,'delete_backup_by_name') );
556
- add_action( 'wp_ajax_download_backup_by_name', array($xcloner_api,'download_backup_by_name') );
557
- add_action( 'wp_ajax_remote_storage_save_status', array($xcloner_api,'remote_storage_save_status') );
558
- add_action( 'wp_ajax_upload_backup_to_remote', array($xcloner_api,'upload_backup_to_remote') );
559
- add_action( 'wp_ajax_list_backup_files' , array($xcloner_api,'list_backup_files') );
560
- add_action( 'wp_ajax_restore_upload_backup' , array($xcloner_api,'restore_upload_backup') );
561
- add_action( 'wp_ajax_download_restore_script', array($xcloner_api,'download_restore_script') );
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();
@@ -597,7 +645,11 @@ class Xcloner {
597
 
598
  }
599
 
600
- function add_new_intervals($schedules)
 
 
 
 
601
  {
602
  //weekly scheduler interval
603
  $schedules['weekly'] = array(
@@ -651,26 +703,16 @@ class Xcloner {
651
  return $this->loader;
652
  }
653
 
654
- /**
655
- * Retrieve the version number of the plugin.
656
- *
657
- * @since 1.0.0
658
- * @return string The version number of the plugin.
659
- */
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
  }
83
  private $xcloner_scheduler;
84
  private $xcloner_remote_storage;
85
  private $xcloner_file_transfer;
86
+ private $xcloner_encryption;
87
+
88
  /**
89
  * Define the core functionality of the plugin.
90
  *
114
 
115
  }
116
 
117
+ /**
118
+ * Retrieve the version number of the plugin.
119
+ *
120
+ * @since 1.0.0
121
+ * @return string The version number of the plugin.
122
+ */
123
+ /*public function get_version() {
124
+ return $this->version;
125
+ }
126
+
127
+ public function get_xcloner_settings()
128
  {
129
  return $this->xcloner_settings;
130
  }
174
  return $this->xcloner_file_transfer;
175
  }
176
 
177
+ public function get_xcloner_encryption()
178
+ {
179
+ return $this->xcloner_encryption;
180
+ }*/
181
+
182
+ public function __call($property, $args) {
183
+
184
+ $property = str_replace("get_", "", $property);
185
+
186
+ if(property_exists($this, $property)){
187
+ return $this->$property;
188
+ }
189
+ }
190
+
191
+ public function check_dependencies() {
192
 
193
  $backup_storage_path = realpath(__DIR__.DS."..".DS."..".DS."..").DS."backups".DS;
194
 
195
  define("XCLONER_STORAGE_PATH", realpath($backup_storage_path));
196
 
197
+ if (!is_dir($backup_storage_path))
198
  {
199
+ if (!@mkdir($backup_storage_path))
200
  {
201
  $status = "error";
202
  $message = sprintf(__("Unable to create the Backup Storage Location Folder %s . Please fix this before starting the backup process."), $backup_storage_path);
204
  return;
205
  }
206
  }
207
+ if (!is_writable($backup_storage_path))
208
  {
209
  $status = "error";
210
  $message = sprintf(__("Unable to write to the Backup Storage Location Folder %s . Please fix this before starting the backup process."), $backup_storage_path);
218
  public function trigger_message($message, $status = "error", $message_param1 = "", $message_param2 = "", $message_param3 = "")
219
  {
220
  $message = sprintf(__($message), $message_param1, $message_param2, $message_param3);
221
+ add_action('xcloner_admin_notices', array($this, "trigger_message_notice"), 10, 2);
222
+ do_action('xcloner_admin_notices', $message, $status);
223
  }
224
 
225
  public function trigger_message_notice($message, $status = "success")
226
  {
227
  ?>
228
  <div class="notice notice-<?php echo $status?> is-dismissible">
229
+ <p><?php _e($message, 'xcloner-backup-and-restore'); ?></p>
230
  </div>
231
  <?php
232
  }
253
  * The class responsible for orchestrating the actions and filters of the
254
  * core plugin.
255
  */
256
+ require_once plugin_dir_path(dirname(__FILE__)).'includes/class-xcloner-loader.php';
257
 
258
  /**
259
  * The class responsible for defining internationalization functionality
260
  * of the plugin.
261
  */
262
+ require_once plugin_dir_path(dirname(__FILE__)).'includes/class-xcloner-i18n.php';
263
 
264
  /**
265
  * The class responsible for defining all actions that occur in the admin area.
266
  */
267
+ require_once plugin_dir_path(dirname(__FILE__)).'admin/class-xcloner-admin.php';
268
 
269
  /**
270
  * The class responsible for debugging XCloner.
271
  */
272
+ require_once plugin_dir_path(dirname(__FILE__)).'includes/class-xcloner-logger.php';
273
 
274
  /**
275
  * The class responsible for defining the admin settings area.
276
  */
277
+ require_once plugin_dir_path(dirname(__FILE__)).'includes/class-xcloner-settings.php';
278
 
279
  /**
280
  * The class responsible for defining the Remote Storage settings area.
281
  */
282
+ require_once plugin_dir_path(dirname(__FILE__)).'includes/class-xcloner-remote-storage.php';
283
 
284
  /**
285
  * The class responsible for implementing the database backup methods.
286
  */
287
+ require_once plugin_dir_path(dirname(__FILE__)).'includes/class-xcloner-database.php';
288
 
289
  /**
290
  * The class responsible for sanitization of users input.
291
  */
292
+ require_once plugin_dir_path(dirname(__FILE__)).'includes/class-xcloner-sanitization.php';
293
 
294
  /**
295
  * The class responsible for XCloner system requirements validation.
296
  */
297
+ require_once plugin_dir_path(dirname(__FILE__)).'includes/class-xcloner-requirements.php';
298
 
299
  /**
300
  * The class responsible for XCloner backup archive creation.
301
  */
302
+ require_once plugin_dir_path(dirname(__FILE__)).'includes/class-xcloner-archive.php';
303
 
304
  /**
305
  * The class responsible for XCloner API requests.
306
  */
307
+ require_once plugin_dir_path(dirname(__FILE__)).'includes/class-xcloner-api.php';
308
 
309
  /**
310
  * The class responsible for the XCloner File System methods.
311
  */
312
+ require_once plugin_dir_path(dirname(__FILE__)).'includes/class-xcloner-file-system.php';
313
 
314
  /**
315
  * The class responsible for the XCloner File Transfer methods.
316
  */
317
+ require_once plugin_dir_path(dirname(__FILE__)).'includes/class-xcloner-file-transfer.php';
318
 
319
  /**
320
  * The class responsible for the XCloner Scheduler methods.
321
  */
322
+ require_once plugin_dir_path(dirname(__FILE__)).'includes/class-xcloner-scheduler.php';
323
+
324
+ /**
325
+ * The class responsible for the XCloner Encryption methods.
326
+ */
327
+ require_once plugin_dir_path(dirname(__FILE__)).'includes/class-xcloner-encryption.php';
328
 
329
  /**
330
  * The class responsible for defining all actions that occur in the public-facing
331
  * side of the site.
332
  */
333
+ require_once plugin_dir_path(dirname(__FILE__)).'public/class-xcloner-public.php';
334
 
335
  $this->loader = new Xcloner_Loader($this);
336
 
349
 
350
  $plugin_i18n = new Xcloner_i18n();
351
 
352
+ $this->loader->add_action('plugins_loaded', $plugin_i18n, 'load_plugin_textdomain');
353
 
354
  //wp_localize_script( 'ajax-script', 'my_ajax_object',
355
+ // array( 'ajax_url' => admin_url( 'admin-ajax.php' ) ) );
356
 
357
  }
358
 
365
  */
366
  private function define_admin_hooks() {
367
 
368
+ $plugin_admin = new Xcloner_Admin($this);
369
  $this->plugin_admin = $plugin_admin;
370
 
371
+ $this->loader->add_action('admin_enqueue_scripts', $plugin_admin, 'enqueue_styles');
372
+ $this->loader->add_action('admin_enqueue_scripts', $plugin_admin, 'enqueue_scripts');
373
 
374
+ add_action('backup_archive_finished', array($this, 'do_action_after_backup_finished'), 10, 2);
375
  }
376
 
377
  /**
380
  * @access private
381
  *
382
  */
383
+ private function define_admin_menu() {
384
 
385
  add_action('admin_menu', array($this->loader, 'xcloner_backup_add_admin_menu'));
386
 
387
  }
388
 
389
+ private function define_plugin_settings() {
390
  /**
391
+ * register wporg_settings_init to the admin_init action hook
392
+ */
393
 
394
  $this->xcloner_settings = new XCloner_Settings($this);
395
 
396
+ if (defined('DOING_CRON') || isset($_POST['hash'])) {
397
 
398
+ if (defined('DOING_CRON') || $_POST['hash'] == "generate_hash") {
399
  $this->xcloner_settings->generate_new_hash();
400
+ } else {
401
  $this->xcloner_settings->set_hash($_POST['hash']);
402
  }
403
  }
404
 
405
+ if (defined('DOING_CRON') || !isset($_POST['hash']))
406
  {
407
+ add_action('shutdown', function() {
408
+ $this->xcloner_filesystem = new Xcloner_File_System($this);
409
+ $this->xcloner_filesystem->remove_tmp_filesystem();
410
  });
411
  }
412
 
423
  }
424
 
425
  /*
426
+ * @method static $this get_xcloner_logger()
427
+ * @method static $this get_xcloner_settings()
428
  * type = core|plugin|theme|translation
429
  */
430
  public function pre_auto_update($type, $item, $context)
431
  {
432
+ if (!$type)
433
  {
434
  return false;
435
  }
436
 
437
+ $exclude_files = array();
438
+ $regex = "";
439
+ $data = "";
440
+
441
  $this->get_xcloner_logger()->info(sprintf("Doing automatic backup before %s upgrade, pre_auto_update hook.", $type));
442
 
443
  $content_dir = str_replace(ABSPATH, "", WP_CONTENT_DIR);
444
  $plugins_dir = str_replace(ABSPATH, "", WP_PLUGIN_DIR);
445
+ $langs_dir = $content_dir.DS."languages";
446
+ $themes_dir = $content_dir.DS."themes";
447
 
448
+ switch ($type) {
449
  case 'core':
450
  $exclude_files = array(
451
  "^(?!(wp-admin|wp-includes|(?!.*\/.*.php)))(.*)$",
455
 
456
  $dir_array = explode(DS, $plugins_dir);
457
 
458
+ foreach ($dir_array as $dir)
459
  {
460
  $data .= "\/".$dir;
461
  $regex .= $data."$|";
471
 
472
  $dir_array = explode(DS, $themes_dir);
473
 
474
+ foreach ($dir_array as $dir)
475
  {
476
  $data .= "\/".$dir;
477
  $regex .= $data."$|";
487
 
488
  $dir_array = explode(DS, $langs_dir);
489
 
490
+ foreach ($dir_array as $dir)
491
  {
492
  $data .= "\/".$dir;
493
  $regex .= $data."$|";
513
  $schedule['backup_params']->email_notification = get_option('admin_email');
514
  $schedule['backup_params']->backup_name = "backup_pre_auto_update_".$type."_[domain]-[time]-sql";
515
 
516
+ try {
517
  $this->xcloner_scheduler->xcloner_scheduler_callback(0, $schedule);
518
+ }catch (Exception $e) {
519
  $this->get_xcloner_logger()->error($e->getMessage());
520
  }
521
 
530
  */
531
  private function define_public_hooks() {
532
 
533
+ $plugin_public = new Xcloner_Public($this);
534
 
535
+ $this->loader->add_action('wp_enqueue_scripts', $plugin_public, 'enqueue_styles');
536
+ $this->loader->add_action('wp_enqueue_scripts', $plugin_public, 'enqueue_scripts');
537
 
538
  }
539
 
542
  $logger = new XCloner_Logger($this, "php_system");
543
  $error = error_get_last();
544
 
545
+ if ($error['type'] and $logger)
546
  {
547
+ $logger->info($this->friendly_error_type($error['type']).": ".var_export($error, true));
548
  }
549
 
550
  }
551
 
552
+ public function friendly_error_type($type) {
553
+ static $levels = null;
554
+ if ($levels === null) {
555
+ $levels = [];
556
+ foreach (get_defined_constants() as $key=>$value) {
557
+ if (strpos($key, 'E_') !== 0) {continue; }
558
+ $levels[$value] = $key; //substr($key,2);
559
+ }
560
+ }
561
+ return (isset($levels[$type]) ? $levels[$type] : "Error #{$type}");
562
  }
563
 
564
+ /**
565
+ * @method get_xcloner_settings()
566
+ * @throws Exception
567
+ */
568
  private function define_ajax_hooks()
569
  {
570
  //adding the pre-update hook
571
 
572
+ if (is_admin() || defined('DOING_CRON'))
573
  {
574
+ $this->xcloner_logger = new XCloner_Logger($this, "xcloner_api");
575
+ $this->xcloner_filesystem = new Xcloner_File_System($this);
576
 
577
  //$this->xcloner_filesystem->set_diff_timestamp_start (strtotime("-15 days"));
578
 
579
+ $this->archive_system = new Xcloner_Archive($this);
580
+ $this->xcloner_database = new Xcloner_Database($this);
581
+ $this->xcloner_scheduler = new Xcloner_Scheduler($this);
582
+ $this->xcloner_remote_storage = new Xcloner_Remote_Storage($this);
583
  $this->xcloner_file_transfer = new Xcloner_File_Transfer($this);
584
+ $this->xcloner_encryption = new Xcloner_Encryption($this);
585
+
586
+ $xcloner_api = new Xcloner_Api($this);
587
+
588
+ add_action('wp_ajax_get_database_tables_action', array($xcloner_api, 'get_database_tables_action'));
589
+ add_action('wp_ajax_get_file_system_action', array($xcloner_api, 'get_file_system_action'));
590
+ add_action('wp_ajax_scan_filesystem', array($xcloner_api, 'scan_filesystem'));
591
+ add_action('wp_ajax_backup_database', array($xcloner_api, 'backup_database'));
592
+ add_action('wp_ajax_backup_files', array($xcloner_api, 'backup_files'));
593
+ add_action('wp_ajax_save_schedule', array($xcloner_api, 'save_schedule'));
594
+ add_action('wp_ajax_get_schedule_by_id', array($xcloner_api, 'get_schedule_by_id'));
595
+ add_action('wp_ajax_get_scheduler_list', array($xcloner_api, 'get_scheduler_list'));
596
+ add_action('wp_ajax_delete_schedule_by_id', array($xcloner_api, 'delete_schedule_by_id'));
597
+ add_action('wp_ajax_delete_backup_by_name', array($xcloner_api, 'delete_backup_by_name'));
598
+ add_action('wp_ajax_download_backup_by_name', array($xcloner_api, 'download_backup_by_name'));
599
+ add_action('wp_ajax_remote_storage_save_status', array($xcloner_api, 'remote_storage_save_status'));
600
+ add_action('wp_ajax_upload_backup_to_remote', array($xcloner_api, 'upload_backup_to_remote'));
601
+ add_action('wp_ajax_list_backup_files', array($xcloner_api, 'list_backup_files'));
602
+ add_action('wp_ajax_restore_upload_backup', array($xcloner_api, 'restore_upload_backup'));
603
+ add_action('wp_ajax_download_restore_script', array($xcloner_api, 'download_restore_script'));
604
+ add_action('wp_ajax_copy_backup_remote_to_local', array($xcloner_api, 'copy_backup_remote_to_local'));
605
+ add_action('wp_ajax_restore_backup', array($xcloner_api, 'restore_backup'));
606
+ add_action('wp_ajax_backup_encryption', array($xcloner_api, 'backup_encryption'));
607
+ add_action('wp_ajax_backup_decryption', array($xcloner_api, 'backup_decryption'));
608
+ add_action('wp_ajax_get_manage_backups_list', array($xcloner_api, 'get_manage_backups_list'));
609
+ add_action('admin_notices', array($this, 'xcloner_error_admin_notices'));
610
 
611
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
612
 
613
+ //Do a pre-update backup of targeted files
614
+ if ($this->get_xcloner_settings()->get_xcloner_option('xcloner_enable_pre_update_backup'))
615
+ {
616
  add_action("pre_auto_update", array($this, "pre_auto_update"), 1, 3);
617
  }
618
  }
619
 
620
+ public function add_plugin_action_links($links, $file) {
621
+ if ($file == plugin_basename(dirname(dirname(__FILE__)).'/xcloner.php'))
622
  {
623
  $links[] = '<a href="admin.php?page=xcloner_settings_page">'.__('Settings', 'xcloner-backup-and-restore').'</a>';
624
  $links[] = '<a href="admin.php?page=xcloner_generate_backups_page">'.__('Generate Backup', 'xcloner-backup-and-restore').'</a>';
625
  }
626
 
627
+ return $links;
628
+ }
629
 
630
  public function xcloner_error_admin_notices() {
631
+ settings_errors('xcloner_error_message');
632
  }
633
 
634
+ /**
635
+ * @method get_xcloner_scheduler()
636
+ */
637
  public function define_cron_hooks()
638
  {
639
  //registering new schedule intervals
640
+ add_filter('cron_schedules', array($this, 'add_new_intervals'));
641
 
642
 
643
  $xcloner_scheduler = $this->get_xcloner_scheduler();
645
 
646
  }
647
 
648
+ /**
649
+ * @param $schedules
650
+ * @return mixed
651
+ */
652
+ public function add_new_intervals($schedules)
653
  {
654
  //weekly scheduler interval
655
  $schedules['weekly'] = array(
703
  return $this->loader;
704
  }
705
 
706
+ public function xcloner_display()
 
 
 
 
 
 
 
 
 
 
707
  {
708
  // check user capabilities
709
+ if (!current_user_can('manage_options')) {
710
+ return;
711
+ }
712
 
713
  $page = sanitize_key($_GET['page']);
714
 
715
+ if ($page)
716
  {
717
  $this->display($page);
718
  }
public/class-xcloner-public.php CHANGED
@@ -45,10 +45,8 @@ class Xcloner_Public {
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();
@@ -74,7 +72,7 @@ class Xcloner_Public {
74
  * class.
75
  */
76
 
77
- wp_enqueue_style( $this->plugin_name, plugin_dir_url( __FILE__ ) . 'css/xcloner-public.css', array(), $this->version, 'all' );
78
 
79
  }
80
 
@@ -97,7 +95,7 @@ class Xcloner_Public {
97
  * class.
98
  */
99
 
100
- wp_enqueue_script( $this->plugin_name, plugin_dir_url( __FILE__ ) . 'js/xcloner-public.js', array( 'jquery' ), $this->version, false );
101
 
102
  }
103
 
45
  *
46
  * @since 1.0.0
47
  *
 
 
48
  */
49
+ public function __construct(Xcloner $xcloner_container) {
50
 
51
  $this->plugin_name = $xcloner_container->get_plugin_name();
52
  $this->version = $xcloner_container->get_version();
72
  * class.
73
  */
74
 
75
+ wp_enqueue_style($this->plugin_name, plugin_dir_url(__FILE__).'css/xcloner-public.css', array(), $this->version, 'all');
76
 
77
  }
78
 
95
  * class.
96
  */
97
 
98
+ wp_enqueue_script($this->plugin_name, plugin_dir_url(__FILE__).'js/xcloner-public.js', array('jquery'), $this->version, false);
99
 
100
  }
101
 
restore/xcloner_restore.php CHANGED
@@ -1,30 +1,30 @@
1
  <?php
2
 
3
- if(!defined('AUTH_KEY'))
4
  {
5
  define('AUTH_KEY', '');
6
  }
7
 
8
- if(!defined("DS"))
9
  {
10
  define("DS", DIRECTORY_SEPARATOR);
11
  }
12
 
13
- if(!defined('XCLONER_PLUGIN_ACCESS') || XCLONER_PLUGIN_ACCESS != 1)
14
  {
15
- if(!AUTH_KEY)
16
  {
17
  Xcloner_Restore::send_response("404", "Could not run restore script, AUTH_KEY not set!");
18
  exit;
19
  }
20
 
21
- if(!isset($_REQUEST['hash']))
22
  {
23
  Xcloner_Restore::send_response("404", "Could not run restore script, sent HASH is empty!");
24
  exit;
25
  }
26
 
27
- if($_REQUEST['hash'] != AUTH_KEY)
28
  {
29
  Xcloner_Restore::send_response("404", "Could not run restore script, AUTH_KEY doesn't match the sent HASH!");
30
  exit;
@@ -32,28 +32,28 @@ if(!defined('XCLONER_PLUGIN_ACCESS') || XCLONER_PLUGIN_ACCESS != 1)
32
  }
33
 
34
  //check minimum PHP version
35
- if(version_compare(phpversion(), Xcloner_Restore::xcloner_minimum_version, '<'))
36
  {
37
- Xcloner_Restore::send_response(500, sprintf(("XCloner requires minimum PHP version %s in order to run correctly. We have detected your version as %s"),Xcloner_Restore::xcloner_minimum_version, phpversion()) );
38
  exit;
39
 
40
  }
41
 
42
- $file = dirname( __DIR__ ) . DS.'vendor'.DS.'autoload.php';
43
 
44
- if(file_exists($file))
45
  {
46
 
47
  require_once($file);
48
  }
49
- elseif(file_exists("vendor.phar") and extension_loaded('phar'))
50
  {
51
  require_once(__DIR__.DS."vendor.phar");
52
- }else{
53
 
54
- $file = dirname( __FILE__ ) . DS.'vendor'.DS.'autoload.php';
55
 
56
- if(!file_exists($file))
57
  {
58
  Xcloner_Restore::send_response("404", "File $file does not exists, please extract the vendor.tgz archive on the server or enable PHP Phar module!");
59
  exit;
@@ -78,16 +78,16 @@ use Monolog\Handler\StreamHandler;
78
 
79
  //do not modify below
80
  $that = "";
81
- if(defined('XCLONER_PLUGIN_ACCESS') && XCLONER_PLUGIN_ACCESS)
82
  {
83
  $that = $this;
84
  }
85
  $xcloner_restore = new Xcloner_Restore($that);
86
 
87
- try{
88
  $return = $xcloner_restore->init();
89
  $xcloner_restore->send_response(200, $return);
90
- }catch(Exception $e){
91
  $xcloner_restore->send_response(417, $e->getMessage());
92
  }
93
 
@@ -96,27 +96,34 @@ class Xcloner_Restore
96
 
97
  const xcloner_minimum_version = "5.4.0";
98
 
99
- private $backup_archive_extensions = array("zip", "tar", "tgz", "tar.gz", "gz", "csv");
100
- private $process_files_limit = 150;
101
- private $process_files_limit_list = 350;
102
- private $process_mysql_records_limit = 250;
103
  private $adapter;
104
  private $filesystem;
105
  private $logger;
106
  private $backup_storage_dir;
107
  private $parent_api;
108
-
109
-
 
 
 
 
 
 
 
110
  public function __construct($parent_api = "")
111
  {
112
  register_shutdown_function(array($this, 'exception_handler'));
113
 
114
- if(defined('XCLONER_PLUGIN_ACCESS') && XCLONER_PLUGIN_ACCESS)
115
  {
116
  $dir = $parent_api->get_xcloner_container()->get_xcloner_settings()->get_xcloner_store_path();
117
  }
118
 
119
- if(!isset($dir) || !$dir){
120
  $dir = dirname(__FILE__);
121
  }
122
 
@@ -124,7 +131,7 @@ class Xcloner_Restore
124
 
125
  $this->backup_storage_dir = $dir;
126
 
127
- $this->adapter = new Local($dir ,LOCK_EX, 'SKIP_LINKS');
128
  $this->filesystem = new Filesystem($this->adapter, new Config([
129
  'disable_asserts' => true,
130
  ]));
@@ -133,52 +140,65 @@ class Xcloner_Restore
133
 
134
  $logger_path = $this->get_logger_filename();
135
 
136
- if(!is_writeable($logger_path) and !touch($logger_path))
137
  {
138
  $logger_path = "php://stderr";
139
  }
140
 
141
  $this->logger->pushHandler(new StreamHandler($logger_path, Logger::DEBUG));
142
 
143
- if(isset($_POST['API_ID'])){
144
- $this->logger->info("Processing ajax request ID ".substr(filter_input(INPUT_POST, 'API_ID', FILTER_SANITIZE_STRING), 0 , 15));
145
  }
146
 
147
  }
148
-
 
 
 
149
  public function exception_handler() {
150
 
151
  $error = error_get_last();
152
 
153
- if($error['type'] and $this->logger)
154
  {
155
- $this->logger->info($this->friendly_error_type ($error['type']).": ".var_export($error, true));
156
  }
157
 
158
  }
159
-
 
 
 
 
160
  private function friendly_error_type($type) {
161
- static $levels=null;
162
- if ($levels===null) {
163
- $levels=[];
164
- foreach (get_defined_constants() as $key=>$value) {
165
- if (strpos($key,'E_')!==0) {continue;}
166
- $levels[$value]= $key; //substr($key,2);
167
- }
168
- }
169
- return (isset($levels[$type]) ? $levels[$type] : "Error #{$type}");
170
  }
171
 
172
  public function get_logger_filename()
173
  {
174
- $filename = $this->backup_storage_dir .DS. "xcloner_restore.log";
175
 
176
  return $filename;
177
  }
178
-
 
 
 
 
 
 
179
  public function init()
180
  {
181
- if(isset($_POST['xcloner_action']) and $_POST['xcloner_action'])
182
  {
183
  $method = filter_input(INPUT_POST, 'xcloner_action', FILTER_SANITIZE_STRING);
184
 
@@ -186,53 +206,64 @@ class Xcloner_Restore
186
 
187
  $method .= "_action";
188
 
189
- if(method_exists($this, $method))
190
  {
191
  $this->logger->debug(sprintf('Starting action %s', $method));
192
  return call_user_func(array($this, $method));
193
 
194
- }else{
195
- throw new Exception($method ." does not exists");
196
  }
197
  }
198
 
199
  return $this->check_system();
200
  }
201
-
 
 
 
 
 
 
202
  public function write_file_action()
203
  {
204
- if(isset($_POST['file']))
205
  {
206
  $target_file = filter_input(INPUT_POST, 'file', FILTER_SANITIZE_STRING);
207
 
208
- if(!$_POST['start'])
209
  $fp = fopen($target_file, "wb+");
210
  else
211
  $fp = fopen($target_file, "ab+");
212
 
213
- if(!$fp)
214
  throw new Exception("Unable to open $target_file file for writing");
215
 
216
  fseek($fp, $_POST['start']);
217
 
218
- if(isset($_FILES['blob']))
219
  {
220
  $this->logger->debug(sprintf('Writing %s bytes to file %s starting position %s using FILES blob', filesize($_FILES['blob']['tmp_name']), $target_file, $_POST['start']));
221
 
222
  $blob = file_get_contents($_FILES['blob']['tmp_name']);
223
 
224
- if(!$bytes_written = fwrite($fp, $blob))
225
  throw new Exception("Unable to write data to file $target_file");
226
-
227
- @unlink($_FILES['blob']['tmp_name']);
228
- }elseif(isset($_POST['blob'])){
 
 
 
 
 
229
  $this->logger->debug(sprintf('Writing %s bytes to file %s starting position %s using POST blob', strlen($_POST['blob']), $target_file, $_POST['start']));
230
 
231
  $blob = $_POST['blob'];
232
 
233
- if(!$bytes_written = fwrite($fp, $blob))
234
  throw new Exception("Unable to write data to file $target_file");
235
- }else{
236
  throw new Exception("Upload failed, did not receive any binary data");
237
  }
238
 
@@ -242,39 +273,54 @@ class Xcloner_Restore
242
  return $bytes_written;
243
 
244
  }
245
-
246
- public function mysql_connect($remote_mysql_host, $remote_mysql_user, $remote_mysql_pass, $remote_mysql_db )
 
 
 
 
 
 
 
 
 
 
247
  {
248
  $this->logger->info(sprintf('Connecting to mysql database %s with %s@%s', $remote_mysql_db, $remote_mysql_user, $remote_mysql_host));
249
 
250
  $mysqli = new mysqli($remote_mysql_host, $remote_mysql_user, $remote_mysql_pass, $remote_mysql_db);
251
 
252
  if ($mysqli->connect_error) {
253
- throw new Exception('Connect Error (' . $mysqli->connect_errno . ') '
254
  . $mysqli->connect_error);
255
  }
256
 
257
  $mysqli->query("SET sql_mode='';");
258
  $mysqli->query("SET foreign_key_checks = 0;");
259
- if(isset($_REQUEST['charset_of_file']) and $_REQUEST['charset_of_file'])
260
  $mysqli->query("SET NAMES ".$_REQUEST['charset_of_file']."");
261
  else
262
  $mysqli->query("SET NAMES utf8;");
263
 
264
  return $mysqli;
265
  }
266
-
 
 
 
 
 
267
  public function restore_mysql_backup_action()
268
  {
269
- $mysqldump_file = filter_input(INPUT_POST, 'mysqldump_file', FILTER_SANITIZE_STRING);
270
- $remote_path = filter_input(INPUT_POST, 'remote_path', FILTER_SANITIZE_STRING);
271
  $remote_mysql_user = filter_input(INPUT_POST, 'remote_mysql_user', FILTER_SANITIZE_STRING);
272
  $remote_mysql_pass = filter_input(INPUT_POST, 'remote_mysql_pass', FILTER_SANITIZE_STRING);
273
- $remote_mysql_db = filter_input(INPUT_POST, 'remote_mysql_db', FILTER_SANITIZE_STRING);
274
  $remote_mysql_host = filter_input(INPUT_POST, 'remote_mysql_host', FILTER_SANITIZE_STRING);
275
- $execute_query = trim(stripslashes($_POST['query']));
276
- $error_line = filter_input(INPUT_POST, 'error_line', FILTER_SANITIZE_NUMBER_INT);
277
- $start = filter_input(INPUT_POST, 'start', FILTER_SANITIZE_NUMBER_INT);
278
 
279
  $wp_home_url = filter_input(INPUT_POST, 'wp_home_url', FILTER_SANITIZE_STRING);
280
  $remote_restore_url = filter_input(INPUT_POST, 'remote_restore_url', FILTER_SANITIZE_STRING);
@@ -284,8 +330,8 @@ class Xcloner_Restore
284
 
285
  $mysql_backup_file = $remote_path.DS.$mysqldump_file;
286
 
287
- if(!file_exists($mysql_backup_file))
288
- throw new Exception(sprintf("Mysql backup file %s does not exists",$mysql_backup_file));
289
 
290
 
291
  /*if(defined('XCLONER_PLUGIN_ACCESS') && XCLONER_PLUGIN_ACCESS)
@@ -299,17 +345,18 @@ class Xcloner_Restore
299
  }*/
300
 
301
  {
302
- $mysqli = $this->mysql_connect($remote_mysql_host, $remote_mysql_user, $remote_mysql_pass, $remote_mysql_db );
303
  }
304
 
305
  $line_count = 0;
306
  $query = "";
 
307
  $return['finished'] = 1;
308
  $return['backup_file'] = $mysqldump_file;
309
  $return['backup_size'] = filesize($mysql_backup_file);
310
 
311
  $fp = fopen($mysql_backup_file, "r");
312
- if($fp)
313
  {
314
  $this->logger->info(sprintf("Opening mysql dump file %s at position %s.", $mysql_backup_file, $start));
315
  fseek($fp, $start);
@@ -317,49 +364,49 @@ class Xcloner_Restore
317
  // process the line read.
318
 
319
  //check if line is comment
320
- if(substr($line, 0, 1) == "#")
321
  continue;
322
 
323
  //check if line is empty
324
- if($line == "\n" or trim($line) == "")
325
  continue;
326
 
327
- if(substr($line, strlen($line)-2, strlen($line)) == ";\n")
328
  $query .= $line;
329
- else{
330
  $query .= $line;
331
  continue;
332
  }
333
 
334
- if($execute_query)
335
  {
336
- $query = (($execute_query));
337
  $execute_query = "";
338
  }
339
 
340
  //Doing serialized url replace here
341
 
342
- if($wp_site_url and $wp_home_url and strlen($wp_home_url) < strlen($wp_site_url))
343
  {
344
- list($wp_home_url,$wp_site_url) = array($wp_site_url,$wp_home_url);
345
- list($remote_restore_url,$restore_site_url) = array($restore_site_url,$remote_restore_url);
346
 
347
  }
348
 
349
- if($wp_home_url and $remote_restore_url and strpos($query, $wp_home_url) !== false)
350
  {
351
  $query = $this->url_replace($wp_home_url, $remote_restore_url, $query);
352
  }
353
 
354
- if($wp_site_url and $restore_site_url and strpos($query, $wp_site_url) !== false)
355
  {
356
  $query = $this->url_replace($wp_site_url, $restore_site_url, $query);
357
  }
358
 
359
- if(!$mysqli->query($query) && !stristr($mysqli->error,"Duplicate entry"))
360
  {
361
  //$return['error_line'] = $line_count;
362
- $return['start'] = ftell($fp)-strlen($line);
363
  $return['query_error'] = true;
364
  $return['query'] = $query;
365
  $return['message'] = sprintf("Mysql Error: %s\n", $mysqli->error);
@@ -376,36 +423,44 @@ class Xcloner_Restore
376
  $line_count++;
377
 
378
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
379
  }
380
 
381
- $return['start'] = ftell($fp);
382
-
383
- $this->logger->info(sprintf("Executed %s queries of size %s bytes", $line_count, ($return['start']-$start)));
384
-
385
- if(!feof($fp))
386
- {
387
- $return['finished'] = 0;
388
- }else{
389
- $this->logger->info(sprintf("Mysql Import Done."));
390
- }
391
-
392
- fclose($fp);
393
-
394
  $this->send_response(200, $return);
395
  }
396
-
 
 
 
 
 
 
 
 
397
  private function url_replace($search, $replace, $query)
398
  {
399
  $this->logger->info(sprintf("Doing url replace on query with length %s", strlen($query)), array("QUERY_REPLACE"));
400
  $query = str_replace($search, $replace, $query);
401
  $original_query = $query;
402
 
403
- if($this->has_serialized($query))
404
  {
405
  $this->logger->info(sprintf("Query contains serialized data, doing serialized size fix"), array("QUERY_REPLACE"));
406
  $query = $this->do_serialized_fix($query);
407
 
408
- if(!$query)
409
  {
410
  $this->logger->info(sprintf("Serialization probably failed here..."), array("QUERY_REPLACE"));
411
  $query = $original_query;
@@ -415,43 +470,48 @@ class Xcloner_Restore
415
 
416
  return $query;
417
  }
418
-
 
 
 
 
 
419
  public function list_backup_files_action()
420
  {
421
  $backup_parts = array();
422
 
423
  $source_backup_file = filter_input(INPUT_POST, 'file', FILTER_SANITIZE_STRING);
424
- $start = (int)filter_input(INPUT_POST, 'start', FILTER_SANITIZE_STRING);
425
- $return['part'] = (int)filter_input(INPUT_POST, 'part', FILTER_SANITIZE_STRING);
426
 
427
  $backup_file = $source_backup_file;
428
 
429
- if($this->is_multipart($backup_file))
430
  {
431
  $backup_parts = $this->get_multipart_files($backup_file);
432
  $backup_file = $backup_parts[$return['part']];
433
  }
434
 
435
- try{
436
  $tar = new Tar();
437
  $tar->open($this->backup_storage_dir.DS.$backup_file, $start);
438
 
439
  $data = $tar->contents($this->process_files_limit_list);
440
- }catch(Exception $e)
441
  {
442
  $return['error'] = true;
443
  $return['message'] = $e->getMessage();
444
  $this->send_response(200, $return);
445
  }
446
 
447
- $return['files'] = array();
448
- $return['finished'] = 1;
449
- $return['total_size'] = filesize($this->backup_storage_dir.DS.$backup_file);
450
  $i = 0;
451
 
452
- if(isset($data['extracted_files']) and is_array($data['extracted_files']))
453
  {
454
- foreach($data['extracted_files'] as $file)
455
  {
456
  $return['files'][$i]['path'] = $file->getPath();
457
  $return['files'][$i]['size'] = $file->getSize();
@@ -461,18 +521,18 @@ class Xcloner_Restore
461
  }
462
  }
463
 
464
- if(isset($data['start']))
465
  {
466
  $return['start'] = $data['start'];
467
  $return['finished'] = 0;
468
- }else{
469
- if($this->is_multipart($source_backup_file))
470
  {
471
  $return['start'] = 0;
472
 
473
  ++$return['part'];
474
 
475
- if($return['part'] < sizeof($backup_parts))
476
  $return['finished'] = 0;
477
 
478
  }
@@ -480,7 +540,12 @@ class Xcloner_Restore
480
 
481
  $this->send_response(200, $return);
482
  }
483
-
 
 
 
 
 
484
  public function restore_finish_action()
485
  {
486
  $remote_path = filter_input(INPUT_POST, 'remote_path', FILTER_SANITIZE_STRING);
@@ -490,28 +555,28 @@ class Xcloner_Restore
490
 
491
  $remote_mysql_user = filter_input(INPUT_POST, 'remote_mysql_user', FILTER_SANITIZE_STRING);
492
  $remote_mysql_pass = filter_input(INPUT_POST, 'remote_mysql_pass', FILTER_SANITIZE_STRING);
493
- $remote_mysql_db = filter_input(INPUT_POST, 'remote_mysql_db', FILTER_SANITIZE_STRING);
494
  $remote_mysql_host = filter_input(INPUT_POST, 'remote_mysql_host', FILTER_SANITIZE_STRING);
495
 
496
- $update_remote_site_url = filter_input(INPUT_POST, 'update_remote_site_url', FILTER_SANITIZE_NUMBER_INT);
497
- $delete_restore_script = filter_input(INPUT_POST, 'delete_restore_script', FILTER_SANITIZE_NUMBER_INT);
498
- $delete_backup_temporary_folder = filter_input(INPUT_POST, 'delete_backup_temporary_folder', FILTER_SANITIZE_NUMBER_INT);
499
 
500
- if($update_remote_site_url)
501
  {
502
- $mysqli = $this->mysql_connect($remote_mysql_host, $remote_mysql_user, $remote_mysql_pass, $remote_mysql_db );
503
  $this->update_wp_config($remote_path, $remote_mysql_host, $remote_mysql_user, $remote_mysql_pass, $remote_mysql_db);
504
  $this->update_wp_url($remote_path, $remote_restore_url, $mysqli);
505
  }
506
 
507
- if($delete_backup_temporary_folder)
508
  {
509
  $this->delete_backup_temporary_folder($remote_path);
510
  }
511
 
512
- if(!defined('XCLONER_PLUGIN_ACCESS') || XCLONER_PLUGIN_ACCESS != 1)
513
  {
514
- if($delete_restore_script)
515
  {
516
  $this->delete_self();
517
  }
@@ -520,10 +585,16 @@ class Xcloner_Restore
520
  $return = "Restore Process Finished.";
521
  $this->send_response(200, $return);
522
  }
523
-
 
 
 
 
 
 
524
  private function delete_backup_temporary_folder($remote_path)
525
  {
526
- $this->target_adapter = new Local($remote_path ,LOCK_EX, 'SKIP_LINKS');
527
  $this->target_filesystem = new Filesystem($this->target_adapter, new Config([
528
  'disable_asserts' => true,
529
  ]));
@@ -531,13 +602,13 @@ class Xcloner_Restore
531
  $mysqldump_list = array();
532
  $list = $this->target_filesystem->listContents();
533
 
534
- foreach($list as $file)
535
  {
536
  $matches = array();
537
 
538
- if($file['type'] == "dir")
539
  {
540
- if(preg_match("/xcloner-(\w*)/", $file['basename'], $matches)){
541
  $this->logger->info(sprintf('Deleting temporary folder %s', $file['path']));
542
  $this->target_filesystem->deleteDir($file['path']);
543
  }
@@ -547,50 +618,63 @@ class Xcloner_Restore
547
  return true;
548
 
549
  }
550
-
 
 
 
 
 
551
  private function delete_self()
552
  {
553
- if($this->filesystem->has("vendor.phar"))
554
  {
555
  $this->logger->info(sprintf('Deleting vendor.phar'));
556
  $this->filesystem->delete("vendor.phar");
557
  }
558
- if($this->filesystem->has("vendor"))
559
  {
560
  $this->logger->info(sprintf('Deleting vendor folder'));
561
  $this->filesystem->deleteDir("vendor");
562
  }
563
- if($this->filesystem->has("xcloner_restore.php"))
564
  {
565
  $this->logger->info(sprintf('Deleting xcloner_restore.php'));
566
  $this->filesystem->delete("xcloner_restore.php");
567
  }
568
 
569
- if($this->filesystem->has("xcloner_restore.log"))
570
  {
571
  $this->logger->info(sprintf('Deleting xcloner_restore.log'));
572
  $this->filesystem->delete("xcloner_restore.log");
573
  }
574
 
575
- if($this->filesystem->has($this->get_logger_filename()))
576
  {
577
  $this->logger->info(sprintf('Deleting logger file %s', $this->get_logger_filename()));
578
  $this->filesystem->delete($this->get_logger_filename());
579
  }
580
 
581
  }
582
-
 
 
 
 
 
 
 
 
583
  private function update_wp_url($wp_path, $url, $mysqli)
584
  {
585
  $wp_config = $wp_path.DS."wp-config.php";
586
 
587
  $this->logger->info(sprintf('Updating site url to %s', $url));
588
 
589
- if(file_exists($wp_config))
590
  {
591
  $config = file_get_contents($wp_config);
592
  preg_match("/.*table_prefix.*=.*'(.*)'/i", $config, $matches);
593
- if(isset($matches[1]))
594
  $table_prefix = $matches[1];
595
  else
596
  throw new Exception("Could not load wordpress table prefix from wp-config.php file.");
@@ -598,20 +682,31 @@ class Xcloner_Restore
598
  else
599
  throw new Exception("Could not update the SITEURL and HOME, wp-config.php file not found");
600
 
601
- if(!$mysqli->query("update ".$table_prefix."options set option_value='".($url)."' where option_name='home'"))
602
  throw new Exception(sprintf("Could not update the HOME option, error: %s\n", $mysqli->error));
603
 
604
- if(!$mysqli->query("update ".$table_prefix."options set option_value='".($url)."' where option_name='siteurl'"))
605
  throw new Exception(sprintf("Could not update the SITEURL option, error: %s\n", $mysqli->error));
606
 
607
  return true;
608
  }
609
-
 
 
 
 
 
 
 
 
 
 
 
610
  private function update_wp_config($remote_path, $remote_mysql_host, $remote_mysql_user, $remote_mysql_pass, $remote_mysql_db)
611
  {
612
  $wp_config = $remote_path.DS."wp-config.php";
613
 
614
- if(!file_exists($wp_config))
615
  {
616
  throw new Exception("Could not find the wp-config.php in ".$remote_path);
617
  }
@@ -629,7 +724,7 @@ class Xcloner_Restore
629
 
630
  $this->logger->info(sprintf('Updating wp-config.php file with the new mysql details'));
631
 
632
- if(!file_put_contents($wp_config, $content))
633
  throw new Exception("Could not write updated config data to ".$wp_config);
634
 
635
  chmod($wp_config, $file_perms);
@@ -637,7 +732,11 @@ class Xcloner_Restore
637
  return $wp_config;
638
 
639
  }
640
-
 
 
 
 
641
  public function list_mysqldump_backups_action()
642
  {
643
  $source_backup_file = filter_input(INPUT_POST, 'backup_file', FILTER_SANITIZE_STRING);
@@ -645,7 +744,7 @@ class Xcloner_Restore
645
 
646
  $hash = $this->get_hash_from_backup($source_backup_file);
647
 
648
- $this->target_adapter = new Local($remote_path ,LOCK_EX, 'SKIP_LINKS');
649
  $this->target_filesystem = new Filesystem($this->target_adapter, new Config([
650
  'disable_asserts' => true,
651
  ]));
@@ -653,25 +752,25 @@ class Xcloner_Restore
653
  $mysqldump_list = array();
654
  $list = $this->target_filesystem->listContents();
655
 
656
- foreach($list as $file)
657
  {
658
  $matches = array();
659
 
660
- if($file['type'] == "dir")
661
  {
662
- if(preg_match("/xcloner-(\w*)/", $file['basename'], $matches))
663
  {
664
  $files = $this->target_filesystem->listContents($file['basename']);
665
- foreach($files as $file)
666
  {
667
- if($file['extension'] == "sql")
668
  {
669
  $this->logger->info(sprintf('Found %s mysql backup file', $file['path']));
670
  $mysqldump_list[$file['path']]['path'] = $file['path'];
671
  $mysqldump_list[$file['path']]['size'] = $file['size'];
672
- $mysqldump_list[$file['path']]['timestamp'] = date("d M,Y H:i",$file['timestamp']);
673
 
674
- if($hash and $hash == $matches[1])
675
  $mysqldump_list[$file['path']]['selected'] = "selected";
676
  else
677
  $mysqldump_list[$file['path']]['selected'] = "";
@@ -681,25 +780,36 @@ class Xcloner_Restore
681
  }
682
  }
683
 
684
- $this->sort_by($mysqldump_list, 'timestamp','desc');
685
  $return['files'] = $mysqldump_list;
686
 
687
  $this->send_response(200, $return);
688
  }
689
-
 
 
 
 
 
 
690
  private function get_hash_from_backup($backup_file)
691
  {
692
- if(!$backup_file)
693
  return false;
694
 
695
- $result = preg_match("/-(\w*)./", substr($backup_file, strlen($backup_file)-10, strlen($backup_file)), $matches) ;
696
 
697
- if($result and isset($matches[1]))
698
  return ($matches[1]);
699
 
700
  return false;
701
  }
702
-
 
 
 
 
 
703
  public function list_backup_archives_action()
704
  {
705
  $local_backup_file = filter_input(INPUT_POST, 'local_backup_file', FILTER_SANITIZE_STRING);
@@ -708,18 +818,18 @@ class Xcloner_Restore
708
  $backup_files = array();
709
  $parents = array();
710
 
711
- foreach($list as $file_info)
712
  {
713
  $data = array();
714
 
715
- if(isset($file_info['extension']) and $file_info['extension'] == "csv")
716
  {
717
  $lines = explode(PHP_EOL, $this->filesystem->read($file_info['path']));
718
- foreach($lines as $line)
719
- if($line)
720
  {
721
  $data = str_getcsv($line);
722
- if(is_array($data)){
723
  $parents[$data[0]] = $file_info['path'];
724
  $file_info['childs'][] = $data;
725
  $file_info['size'] += $data[2];
@@ -728,19 +838,19 @@ class Xcloner_Restore
728
 
729
  }
730
 
731
- if($file_info['type'] == 'file' and isset($file_info['extension']) and in_array($file_info['extension'], $this->backup_archive_extensions))
732
  $backup_files[$file_info['path']] = $file_info;
733
  }
734
 
735
  $new_list = array();
736
 
737
- foreach($backup_files as $key=>$file_info)
738
  {
739
- if(isset($parents[$file_info['path']]))
740
  $backup_files[$key]['parent'] = $parents[$file_info['path']];
741
- else{
742
 
743
- if($local_backup_file and ($file_info['basename'] == $local_backup_file))
744
  $file_info['selected'] = 'selected';
745
 
746
  $this->logger->info(sprintf('Found %s backup file', $file_info['path']));
@@ -750,25 +860,31 @@ class Xcloner_Restore
750
 
751
  }
752
 
753
- $this->sort_by($new_list, "timestamp","desc");
754
 
755
  $return['files'] = $new_list;
756
 
757
  $this->send_response(200, $return);
758
 
759
  }
760
-
 
 
 
 
 
 
761
  public function restore_backup_to_path_action()
762
  {
763
- $source_backup_file = filter_input(INPUT_POST, 'backup_file', FILTER_SANITIZE_STRING);
764
- $remote_path = filter_input(INPUT_POST, 'remote_path', FILTER_SANITIZE_STRING);
765
  $include_filter_files = filter_input(INPUT_POST, 'filter_files', FILTER_SANITIZE_STRING);
766
  $exclude_filter_files = "";
767
- $start = filter_input(INPUT_POST, 'start', FILTER_SANITIZE_NUMBER_INT);
768
- $return['part'] = (int)filter_input(INPUT_POST, 'part', FILTER_SANITIZE_NUMBER_INT);
769
  $return['processed'] = (int)filter_input(INPUT_POST, 'processed', FILTER_SANITIZE_NUMBER_INT);
770
 
771
- $this->target_adapter = new Local($remote_path ,LOCK_EX, 'SKIP_LINKS');
772
  $this->target_filesystem = new Filesystem($this->target_adapter, new Config([
773
  'disable_asserts' => true,
774
  ]));
@@ -780,82 +896,112 @@ class Xcloner_Restore
780
  $return['total_size'] = $this->get_backup_size($backup_file);
781
 
782
  $backup_archive = new Tar();
783
- if($this->is_multipart($backup_file))
784
  {
785
- if(!$return['part'])
786
  $return['processed'] += $this->filesystem->getSize($backup_file);
787
 
788
  $backup_parts = $this->get_multipart_files($backup_file);
789
  $backup_file = $backup_parts[$return['part']];
790
- }
 
 
 
 
 
 
 
791
 
792
  $this->logger->info(sprintf('Opening backup archive %s at position %s', $backup_file, $start));
793
- $backup_archive->open($this->backup_storage_dir .DS. $backup_file, $start);
794
 
795
- $data = $backup_archive->extract($remote_path, '',$exclude_filter_files,$include_filter_files, $this->process_files_limit);
796
 
797
- if(isset($data['extracted_files']))
798
  {
799
- foreach($data['extracted_files'] as $spl_fileinfo)
800
  {
801
  $this->logger->info(sprintf('Extracted %s file', $spl_fileinfo->getPath()));
802
  $return['extracted_files'][] = $spl_fileinfo->getPath()." (".$spl_fileinfo->getSize()." bytes)";
803
  }
804
  }
805
 
806
- if(isset($data['start']))
807
  //if(isset($data['start']) and $data['start'] <= $this->filesystem->getSize($backup_file))
808
  {
809
  $return['finished'] = 0;
810
  $return['start'] = $data['start'];
811
- }else{
812
 
813
  $return['processed'] += $start;
814
 
815
- if($this->is_multipart($source_backup_file))
816
  {
817
  $return['start'] = 0;
818
 
819
  ++$return['part'];
820
 
821
- if($return['part'] < sizeof($backup_parts))
822
  $return['finished'] = 0;
823
 
824
  }
825
  }
826
 
827
- if($return['finished'])
828
  $this->logger->info(sprintf('Done extracting %s', $source_backup_file));
829
 
830
  $return['backup_file'] = $backup_file;
831
 
832
  $this->send_response(200, $return);
833
  }
834
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
835
  public function get_current_directory_action()
836
  {
837
  global $wpdb;
838
 
839
  $restore_script_url = filter_input(INPUT_POST, 'restore_script_url', FILTER_SANITIZE_STRING);
840
 
841
- $pathinfo = pathinfo( __FILE__);
842
 
843
  $suffix = "";
844
  $return['remote_mysql_host'] = "localhost";
845
  $return['remote_mysql_user'] = "";
846
  $return['remote_mysql_pass'] = "";
847
- $return['remote_mysql_db'] = "";
848
 
849
- if(defined('XCLONER_PLUGIN_ACCESS') && XCLONER_PLUGIN_ACCESS)
850
  {
851
  $return['dir'] = realpath(get_home_path().DS.$suffix);
852
- $return['restore_script_url'] = get_site_url();
853
  $return['remote_mysql_host'] = $wpdb->dbhost;
854
  $return['remote_mysql_user'] = $wpdb->dbuser;
855
  $return['remote_mysql_pass'] = $wpdb->dbpassword;
856
- $return['remote_mysql_db'] = $wpdb->dbname;
857
  }
858
- else{
859
  $return['dir'] = ($pathinfo['dirname']).DS.$suffix;
860
  $return['restore_script_url'] = str_replace($pathinfo['basename'], "", $restore_script_url).$suffix;
861
  }
@@ -864,75 +1010,109 @@ class Xcloner_Restore
864
 
865
  $this->send_response(200, $return);
866
  }
867
-
 
 
 
 
 
868
  public function check_system()
869
  {
870
  //check if i can write
871
  $tmp_file = md5(time());
872
- if(!file_put_contents($tmp_file, "++"))
873
  throw new Exception("Could not write to new host");
874
 
875
- if(!unlink($tmp_file))
876
  throw new Exception("Could not delete temporary file from new host");
877
 
878
  $max_upload = $this->return_bytes((ini_get('upload_max_filesize')));
879
  $max_post = $this->return_bytes((ini_get('post_max_size')));
880
 
881
  $return['max_upload_size'] = min($max_upload, $max_post); // bytes
882
- $return['status'] = true;
883
 
884
  $this->logger->info(sprintf('Current filesystem max upload size is %s bytes', $return['max_upload_size']));
885
 
886
  $this->send_response(200, $return);
887
  }
888
-
 
 
 
 
 
 
 
889
  private function return_bytes($val) {
890
- $val = trim($val);
891
- $last = strtolower($val[strlen($val)-1]);
892
- switch($last) {
893
- // The 'G' modifier is available since PHP 5.1.0
894
- case 'g':
895
- $val *= 1024;
896
- case 'm':
897
- $val *= 1024;
898
- case 'k':
899
- $val *= 1024;
900
- }
901
-
902
- return $val;
 
 
 
903
  }
904
-
 
 
 
 
 
 
905
  public function is_multipart($backup_name)
906
  {
907
- if(stristr($backup_name, "-multipart"))
908
  return true;
909
 
910
  return false;
911
  }
912
-
 
 
 
 
 
 
 
913
  public function get_backup_size($backup_name)
914
  {
915
  $backup_size = $this->filesystem->getSize($backup_name);
916
- if($this->is_multipart($backup_name))
917
  {
918
  $backup_parts = $this->get_multipart_files($backup_name);
919
- foreach($backup_parts as $part_file)
920
  $backup_size += $this->filesystem->getSize($part_file);
921
  }
922
 
923
  return $backup_size;
924
  }
925
-
 
 
 
 
 
 
926
  public function get_multipart_files($backup_name)
927
  {
928
  $files = array();
929
 
930
- if($this->is_multipart($backup_name))
931
  {
932
  $lines = explode(PHP_EOL, $this->filesystem->read($backup_name));
933
- foreach($lines as $line)
934
  {
935
- if($line)
936
  {
937
  $data = str_getcsv($line);
938
  $files[] = $data[0];
@@ -942,26 +1122,63 @@ class Xcloner_Restore
942
 
943
  return $files;
944
  }
945
-
946
- private function sort_by( &$array, $field, $direction = 'asc')
 
 
 
 
 
 
 
 
947
  {
948
  $direction = strtolower($direction);
949
-
950
- usort($array, create_function('$a, $b', '
951
- $a = $a["' . $field . '"];
952
- $b = $b["' . $field . '"];
953
-
954
- if ($a == $b)
955
- {
956
- return 0;
957
- }
958
-
959
- return ($a ' . ($direction == 'desc' ? '>' : '<') .' $b) ? -1 : 1;
960
- '));
961
-
962
- return true;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
963
  }
964
-
 
 
 
 
 
 
965
  public static function send_response($status = 200, $response)
966
  {
967
  header("Access-Control-Allow-Origin: *");
@@ -970,63 +1187,83 @@ class Xcloner_Restore
970
  $return['status'] = $status;
971
  $return['statusText'] = $response;
972
 
973
- if(isset($response['error']) && $response['error'])
974
  {
975
  $return['statusText'] = $response['message'];
976
  $return['error'] = true;
977
- }elseif($status != 200 and $status != 418)
978
  {
979
  $return['error'] = true;
980
  $return['message'] = $response;
981
  }
982
 
983
- echo json_encode($return);
984
- exit;
985
  }
986
-
987
- /*
988
  * Serialize fix methods below for mysql query lines
989
- */
 
 
 
990
 
991
  function do_serialized_fix($query)
992
  {
993
- $query = str_replace(array("\\n","\\r","\\'"), array("","","\""), ($query));
994
 
995
- return preg_replace_callback('!s:(\d+):([\\\\]?"[\\\\]?"|[\\\\]?"((.*?)[^\\\\])[\\\\]?");!', function ($m) {
996
  $data = "";
997
 
998
- if(!isset($m[3]))
999
  $m[3] = "";
1000
 
1001
  $data = 's:'.strlen(($m[3])).':\"'.($m[3]).'\";';
1002
- //return $this->unescape_quotes($data);
1003
 
1004
- return $data;
1005
- }, $query);
1006
  }
1007
-
 
 
 
 
 
 
1008
  private function unescape_quotes($value) {
1009
  return str_replace('\"', '"', $value);
1010
  }
1011
-
 
 
 
 
 
 
1012
  private function unescape_mysql($value) {
1013
- return str_replace(array("\\\\", "\\0", "\\n", "\\r", "\Z", "\'", '\"'),
1014
- array("\\", "\0", "\n", "\r", "\x1a", "'", '"'),
1015
  $value);
1016
- }
1017
-
1018
-
 
 
 
 
 
1019
  private function has_serialized($s)
1020
  {
1021
- if(
1022
- stristr($s, '{' ) != false &&
1023
- stristr($s, '}' ) != false &&
1024
- stristr($s, ';' ) != false &&
1025
- stristr($s, ':' ) != false
1026
- ){
1027
- return true;
1028
- }else{
1029
- return false;
1030
  }
1031
 
1032
  }
1
  <?php
2
 
3
+ if (!defined('AUTH_KEY'))
4
  {
5
  define('AUTH_KEY', '');
6
  }
7
 
8
+ if (!defined("DS"))
9
  {
10
  define("DS", DIRECTORY_SEPARATOR);
11
  }
12
 
13
+ if (!defined('XCLONER_PLUGIN_ACCESS') || XCLONER_PLUGIN_ACCESS != 1)
14
  {
15
+ if (!AUTH_KEY)
16
  {
17
  Xcloner_Restore::send_response("404", "Could not run restore script, AUTH_KEY not set!");
18
  exit;
19
  }
20
 
21
+ if (!isset($_REQUEST['hash']))
22
  {
23
  Xcloner_Restore::send_response("404", "Could not run restore script, sent HASH is empty!");
24
  exit;
25
  }
26
 
27
+ if ($_REQUEST['hash'] != AUTH_KEY)
28
  {
29
  Xcloner_Restore::send_response("404", "Could not run restore script, AUTH_KEY doesn't match the sent HASH!");
30
  exit;
32
  }
33
 
34
  //check minimum PHP version
35
+ if (version_compare(phpversion(), Xcloner_Restore::xcloner_minimum_version, '<'))
36
  {
37
+ Xcloner_Restore::send_response(500, sprintf(("XCloner requires minimum PHP version %s in order to run correctly. We have detected your version as %s"), Xcloner_Restore::xcloner_minimum_version, phpversion()));
38
  exit;
39
 
40
  }
41
 
42
+ $file = dirname(__DIR__).DS.'vendor'.DS.'autoload.php';
43
 
44
+ if (file_exists($file))
45
  {
46
 
47
  require_once($file);
48
  }
49
+ elseif (file_exists("vendor.phar") and extension_loaded('phar'))
50
  {
51
  require_once(__DIR__.DS."vendor.phar");
52
+ } else {
53
 
54
+ $file = dirname(__FILE__).DS.'vendor'.DS.'autoload.php';
55
 
56
+ if (!file_exists($file))
57
  {
58
  Xcloner_Restore::send_response("404", "File $file does not exists, please extract the vendor.tgz archive on the server or enable PHP Phar module!");
59
  exit;
78
 
79
  //do not modify below
80
  $that = "";
81
+ if (defined('XCLONER_PLUGIN_ACCESS') && XCLONER_PLUGIN_ACCESS)
82
  {
83
  $that = $this;
84
  }
85
  $xcloner_restore = new Xcloner_Restore($that);
86
 
87
+ try {
88
  $return = $xcloner_restore->init();
89
  $xcloner_restore->send_response(200, $return);
90
+ }catch (Exception $e) {
91
  $xcloner_restore->send_response(417, $e->getMessage());
92
  }
93
 
96
 
97
  const xcloner_minimum_version = "5.4.0";
98
 
99
+ private $backup_archive_extensions = array("zip", "tar", "tgz", "tar.gz", "gz", "csv");
100
+ private $process_files_limit = 150;
101
+ private $process_files_limit_list = 350;
102
+ private $process_mysql_records_limit = 250;
103
  private $adapter;
104
  private $filesystem;
105
  private $logger;
106
  private $backup_storage_dir;
107
  private $parent_api;
108
+
109
+ private $target_adapter;
110
+ private $target_filesystem;
111
+
112
+ /**
113
+ * Xcloner_Restore constructor.
114
+ * @param string $parent_api
115
+ * @throws Exception
116
+ */
117
  public function __construct($parent_api = "")
118
  {
119
  register_shutdown_function(array($this, 'exception_handler'));
120
 
121
+ if (defined('XCLONER_PLUGIN_ACCESS') && XCLONER_PLUGIN_ACCESS)
122
  {
123
  $dir = $parent_api->get_xcloner_container()->get_xcloner_settings()->get_xcloner_store_path();
124
  }
125
 
126
+ if (!isset($dir) || !$dir) {
127
  $dir = dirname(__FILE__);
128
  }
129
 
131
 
132
  $this->backup_storage_dir = $dir;
133
 
134
+ $this->adapter = new Local($dir, LOCK_EX, 'SKIP_LINKS');
135
  $this->filesystem = new Filesystem($this->adapter, new Config([
136
  'disable_asserts' => true,
137
  ]));
140
 
141
  $logger_path = $this->get_logger_filename();
142
 
143
+ if (!is_writeable($logger_path) and !touch($logger_path))
144
  {
145
  $logger_path = "php://stderr";
146
  }
147
 
148
  $this->logger->pushHandler(new StreamHandler($logger_path, Logger::DEBUG));
149
 
150
+ if (isset($_POST['API_ID'])) {
151
+ $this->logger->info("Processing ajax request ID ".substr(filter_input(INPUT_POST, 'API_ID', FILTER_SANITIZE_STRING), 0, 15));
152
  }
153
 
154
  }
155
+
156
+ /**
157
+ * Exception handler method
158
+ */
159
  public function exception_handler() {
160
 
161
  $error = error_get_last();
162
 
163
+ if ($error['type'] and $this->logger)
164
  {
165
+ $this->logger->info($this->friendly_error_type($error['type']).": ".var_export($error, true));
166
  }
167
 
168
  }
169
+
170
+ /**
171
+ * @param $type
172
+ * @return mixed|string
173
+ */
174
  private function friendly_error_type($type) {
175
+ static $levels = null;
176
+ if ($levels === null) {
177
+ $levels = [];
178
+ foreach (get_defined_constants() as $key=>$value) {
179
+ if (strpos($key, 'E_') !== 0) {continue; }
180
+ $levels[$value] = $key; //substr($key,2);
181
+ }
182
+ }
183
+ return (isset($levels[$type]) ? $levels[$type] : "Error #{$type}");
184
  }
185
 
186
  public function get_logger_filename()
187
  {
188
+ $filename = $this->backup_storage_dir.DS."xcloner_restore.log";
189
 
190
  return $filename;
191
  }
192
+
193
+ /**
194
+ * Init method
195
+ *
196
+ * @return mixed|void
197
+ * @throws Exception
198
+ */
199
  public function init()
200
  {
201
+ if (isset($_POST['xcloner_action']) and $_POST['xcloner_action'])
202
  {
203
  $method = filter_input(INPUT_POST, 'xcloner_action', FILTER_SANITIZE_STRING);
204
 
206
 
207
  $method .= "_action";
208
 
209
+ if (method_exists($this, $method))
210
  {
211
  $this->logger->debug(sprintf('Starting action %s', $method));
212
  return call_user_func(array($this, $method));
213
 
214
+ } else {
215
+ throw new Exception($method." does not exists");
216
  }
217
  }
218
 
219
  return $this->check_system();
220
  }
221
+
222
+ /**
223
+ * Write file method
224
+ *
225
+ * @return bool|int
226
+ * @throws Exception
227
+ */
228
  public function write_file_action()
229
  {
230
+ if (isset($_POST['file']))
231
  {
232
  $target_file = filter_input(INPUT_POST, 'file', FILTER_SANITIZE_STRING);
233
 
234
+ if (!$_POST['start'])
235
  $fp = fopen($target_file, "wb+");
236
  else
237
  $fp = fopen($target_file, "ab+");
238
 
239
+ if (!$fp)
240
  throw new Exception("Unable to open $target_file file for writing");
241
 
242
  fseek($fp, $_POST['start']);
243
 
244
+ if (isset($_FILES['blob']))
245
  {
246
  $this->logger->debug(sprintf('Writing %s bytes to file %s starting position %s using FILES blob', filesize($_FILES['blob']['tmp_name']), $target_file, $_POST['start']));
247
 
248
  $blob = file_get_contents($_FILES['blob']['tmp_name']);
249
 
250
+ if (!$bytes_written = fwrite($fp, $blob))
251
  throw new Exception("Unable to write data to file $target_file");
252
+
253
+ try {
254
+ unlink($_FILES['blob']['tmp_name']);
255
+ }catch (Exception $e) {
256
+ //silent message
257
+ }
258
+
259
+ }elseif (isset($_POST['blob'])) {
260
  $this->logger->debug(sprintf('Writing %s bytes to file %s starting position %s using POST blob', strlen($_POST['blob']), $target_file, $_POST['start']));
261
 
262
  $blob = $_POST['blob'];
263
 
264
+ if (!$bytes_written = fwrite($fp, $blob))
265
  throw new Exception("Unable to write data to file $target_file");
266
+ } else {
267
  throw new Exception("Upload failed, did not receive any binary data");
268
  }
269
 
273
  return $bytes_written;
274
 
275
  }
276
+
277
+ /**
278
+ * Connect to mysql server method
279
+ *
280
+ * @param $remote_mysql_host
281
+ * @param $remote_mysql_user
282
+ * @param $remote_mysql_pass
283
+ * @param $remote_mysql_db
284
+ * @return mysqli
285
+ * @throws Exception
286
+ */
287
+ public function mysql_connect($remote_mysql_host, $remote_mysql_user, $remote_mysql_pass, $remote_mysql_db)
288
  {
289
  $this->logger->info(sprintf('Connecting to mysql database %s with %s@%s', $remote_mysql_db, $remote_mysql_user, $remote_mysql_host));
290
 
291
  $mysqli = new mysqli($remote_mysql_host, $remote_mysql_user, $remote_mysql_pass, $remote_mysql_db);
292
 
293
  if ($mysqli->connect_error) {
294
+ throw new Exception('Connect Error ('.$mysqli->connect_errno.') '
295
  . $mysqli->connect_error);
296
  }
297
 
298
  $mysqli->query("SET sql_mode='';");
299
  $mysqli->query("SET foreign_key_checks = 0;");
300
+ if (isset($_REQUEST['charset_of_file']) and $_REQUEST['charset_of_file'])
301
  $mysqli->query("SET NAMES ".$_REQUEST['charset_of_file']."");
302
  else
303
  $mysqli->query("SET NAMES utf8;");
304
 
305
  return $mysqli;
306
  }
307
+
308
+ /**
309
+ * Restore mysql backup file
310
+ *
311
+ * @throws Exception
312
+ */
313
  public function restore_mysql_backup_action()
314
  {
315
+ $mysqldump_file = filter_input(INPUT_POST, 'mysqldump_file', FILTER_SANITIZE_STRING);
316
+ $remote_path = filter_input(INPUT_POST, 'remote_path', FILTER_SANITIZE_STRING);
317
  $remote_mysql_user = filter_input(INPUT_POST, 'remote_mysql_user', FILTER_SANITIZE_STRING);
318
  $remote_mysql_pass = filter_input(INPUT_POST, 'remote_mysql_pass', FILTER_SANITIZE_STRING);
319
+ $remote_mysql_db = filter_input(INPUT_POST, 'remote_mysql_db', FILTER_SANITIZE_STRING);
320
  $remote_mysql_host = filter_input(INPUT_POST, 'remote_mysql_host', FILTER_SANITIZE_STRING);
321
+ $execute_query = trim(stripslashes($_POST['query']));
322
+ $error_line = filter_input(INPUT_POST, 'error_line', FILTER_SANITIZE_NUMBER_INT);
323
+ $start = filter_input(INPUT_POST, 'start', FILTER_SANITIZE_NUMBER_INT);
324
 
325
  $wp_home_url = filter_input(INPUT_POST, 'wp_home_url', FILTER_SANITIZE_STRING);
326
  $remote_restore_url = filter_input(INPUT_POST, 'remote_restore_url', FILTER_SANITIZE_STRING);
330
 
331
  $mysql_backup_file = $remote_path.DS.$mysqldump_file;
332
 
333
+ if (!file_exists($mysql_backup_file))
334
+ throw new Exception(sprintf("Mysql backup file %s does not exists", $mysql_backup_file));
335
 
336
 
337
  /*if(defined('XCLONER_PLUGIN_ACCESS') && XCLONER_PLUGIN_ACCESS)
345
  }*/
346
 
347
  {
348
+ $mysqli = $this->mysql_connect($remote_mysql_host, $remote_mysql_user, $remote_mysql_pass, $remote_mysql_db);
349
  }
350
 
351
  $line_count = 0;
352
  $query = "";
353
+ $return = array();
354
  $return['finished'] = 1;
355
  $return['backup_file'] = $mysqldump_file;
356
  $return['backup_size'] = filesize($mysql_backup_file);
357
 
358
  $fp = fopen($mysql_backup_file, "r");
359
+ if ($fp)
360
  {
361
  $this->logger->info(sprintf("Opening mysql dump file %s at position %s.", $mysql_backup_file, $start));
362
  fseek($fp, $start);
364
  // process the line read.
365
 
366
  //check if line is comment
367
+ if (substr($line, 0, 1) == "#")
368
  continue;
369
 
370
  //check if line is empty
371
+ if ($line == "\n" or trim($line) == "")
372
  continue;
373
 
374
+ if (substr($line, strlen($line) - 2, strlen($line)) == ";\n")
375
  $query .= $line;
376
+ else {
377
  $query .= $line;
378
  continue;
379
  }
380
 
381
+ if ($execute_query)
382
  {
383
+ $query = (($execute_query));
384
  $execute_query = "";
385
  }
386
 
387
  //Doing serialized url replace here
388
 
389
+ if ($wp_site_url and $wp_home_url and strlen($wp_home_url) < strlen($wp_site_url))
390
  {
391
+ list($wp_home_url, $wp_site_url) = array($wp_site_url, $wp_home_url);
392
+ list($remote_restore_url, $restore_site_url) = array($restore_site_url, $remote_restore_url);
393
 
394
  }
395
 
396
+ if ($wp_home_url and $remote_restore_url and strpos($query, $wp_home_url) !== false)
397
  {
398
  $query = $this->url_replace($wp_home_url, $remote_restore_url, $query);
399
  }
400
 
401
+ if ($wp_site_url and $restore_site_url and strpos($query, $wp_site_url) !== false)
402
  {
403
  $query = $this->url_replace($wp_site_url, $restore_site_url, $query);
404
  }
405
 
406
+ if (!$mysqli->query($query) && !stristr($mysqli->error, "Duplicate entry"))
407
  {
408
  //$return['error_line'] = $line_count;
409
+ $return['start'] = ftell($fp) - strlen($line);
410
  $return['query_error'] = true;
411
  $return['query'] = $query;
412
  $return['message'] = sprintf("Mysql Error: %s\n", $mysqli->error);
423
  $line_count++;
424
 
425
  }
426
+
427
+ $return['start'] = ftell($fp);
428
+
429
+ $this->logger->info(sprintf("Executed %s queries of size %s bytes", $line_count, ($return['start'] - $start)));
430
+
431
+ if (!feof($fp))
432
+ {
433
+ $return['finished'] = 0;
434
+ } else {
435
+ $this->logger->info(sprintf("Mysql Import Done."));
436
+ }
437
+
438
+ fclose($fp);
439
  }
440
 
 
 
 
 
 
 
 
 
 
 
 
 
 
441
  $this->send_response(200, $return);
442
  }
443
+
444
+ /**
445
+ * Url replace method inside database backup file
446
+ *
447
+ * @param $search
448
+ * @param $replace
449
+ * @param $query
450
+ * @return mixed|string|string[]|null
451
+ */
452
  private function url_replace($search, $replace, $query)
453
  {
454
  $this->logger->info(sprintf("Doing url replace on query with length %s", strlen($query)), array("QUERY_REPLACE"));
455
  $query = str_replace($search, $replace, $query);
456
  $original_query = $query;
457
 
458
+ if ($this->has_serialized($query))
459
  {
460
  $this->logger->info(sprintf("Query contains serialized data, doing serialized size fix"), array("QUERY_REPLACE"));
461
  $query = $this->do_serialized_fix($query);
462
 
463
+ if (!$query)
464
  {
465
  $this->logger->info(sprintf("Serialization probably failed here..."), array("QUERY_REPLACE"));
466
  $query = $original_query;
470
 
471
  return $query;
472
  }
473
+
474
+ /**
475
+ * List backup files method
476
+ *
477
+ * @throws \League\Flysystem\FileNotFoundException
478
+ */
479
  public function list_backup_files_action()
480
  {
481
  $backup_parts = array();
482
 
483
  $source_backup_file = filter_input(INPUT_POST, 'file', FILTER_SANITIZE_STRING);
484
+ $start = (int)filter_input(INPUT_POST, 'start', FILTER_SANITIZE_STRING);
485
+ $return['part'] = (int)filter_input(INPUT_POST, 'part', FILTER_SANITIZE_STRING);
486
 
487
  $backup_file = $source_backup_file;
488
 
489
+ if ($this->is_multipart($backup_file))
490
  {
491
  $backup_parts = $this->get_multipart_files($backup_file);
492
  $backup_file = $backup_parts[$return['part']];
493
  }
494
 
495
+ try {
496
  $tar = new Tar();
497
  $tar->open($this->backup_storage_dir.DS.$backup_file, $start);
498
 
499
  $data = $tar->contents($this->process_files_limit_list);
500
+ }catch (Exception $e)
501
  {
502
  $return['error'] = true;
503
  $return['message'] = $e->getMessage();
504
  $this->send_response(200, $return);
505
  }
506
 
507
+ $return['files'] = array();
508
+ $return['finished'] = 1;
509
+ $return['total_size'] = filesize($this->backup_storage_dir.DS.$backup_file);
510
  $i = 0;
511
 
512
+ if (isset($data['extracted_files']) and is_array($data['extracted_files']))
513
  {
514
+ foreach ($data['extracted_files'] as $file)
515
  {
516
  $return['files'][$i]['path'] = $file->getPath();
517
  $return['files'][$i]['size'] = $file->getSize();
521
  }
522
  }
523
 
524
+ if (isset($data['start']))
525
  {
526
  $return['start'] = $data['start'];
527
  $return['finished'] = 0;
528
+ } else {
529
+ if ($this->is_multipart($source_backup_file))
530
  {
531
  $return['start'] = 0;
532
 
533
  ++$return['part'];
534
 
535
+ if ($return['part'] < sizeof($backup_parts))
536
  $return['finished'] = 0;
537
 
538
  }
540
 
541
  $this->send_response(200, $return);
542
  }
543
+
544
+ /**
545
+ * Finish backup restore method
546
+ *
547
+ * @throws \League\Flysystem\FileNotFoundException
548
+ */
549
  public function restore_finish_action()
550
  {
551
  $remote_path = filter_input(INPUT_POST, 'remote_path', FILTER_SANITIZE_STRING);
555
 
556
  $remote_mysql_user = filter_input(INPUT_POST, 'remote_mysql_user', FILTER_SANITIZE_STRING);
557
  $remote_mysql_pass = filter_input(INPUT_POST, 'remote_mysql_pass', FILTER_SANITIZE_STRING);
558
+ $remote_mysql_db = filter_input(INPUT_POST, 'remote_mysql_db', FILTER_SANITIZE_STRING);
559
  $remote_mysql_host = filter_input(INPUT_POST, 'remote_mysql_host', FILTER_SANITIZE_STRING);
560
 
561
+ $update_remote_site_url = filter_input(INPUT_POST, 'update_remote_site_url', FILTER_SANITIZE_NUMBER_INT);
562
+ $delete_restore_script = filter_input(INPUT_POST, 'delete_restore_script', FILTER_SANITIZE_NUMBER_INT);
563
+ $delete_backup_temporary_folder = filter_input(INPUT_POST, 'delete_backup_temporary_folder', FILTER_SANITIZE_NUMBER_INT);
564
 
565
+ if ($update_remote_site_url)
566
  {
567
+ $mysqli = $this->mysql_connect($remote_mysql_host, $remote_mysql_user, $remote_mysql_pass, $remote_mysql_db);
568
  $this->update_wp_config($remote_path, $remote_mysql_host, $remote_mysql_user, $remote_mysql_pass, $remote_mysql_db);
569
  $this->update_wp_url($remote_path, $remote_restore_url, $mysqli);
570
  }
571
 
572
+ if ($delete_backup_temporary_folder)
573
  {
574
  $this->delete_backup_temporary_folder($remote_path);
575
  }
576
 
577
+ if (!defined('XCLONER_PLUGIN_ACCESS') || XCLONER_PLUGIN_ACCESS != 1)
578
  {
579
+ if ($delete_restore_script)
580
  {
581
  $this->delete_self();
582
  }
585
  $return = "Restore Process Finished.";
586
  $this->send_response(200, $return);
587
  }
588
+
589
+ /**
590
+ * Delete backup temporary folder
591
+ *
592
+ * @param $remote_path
593
+ * @return bool
594
+ */
595
  private function delete_backup_temporary_folder($remote_path)
596
  {
597
+ $this->target_adapter = new Local($remote_path, LOCK_EX, 'SKIP_LINKS');
598
  $this->target_filesystem = new Filesystem($this->target_adapter, new Config([
599
  'disable_asserts' => true,
600
  ]));
602
  $mysqldump_list = array();
603
  $list = $this->target_filesystem->listContents();
604
 
605
+ foreach ($list as $file)
606
  {
607
  $matches = array();
608
 
609
+ if ($file['type'] == "dir")
610
  {
611
+ if (preg_match("/xcloner-(\w*)/", $file['basename'], $matches)) {
612
  $this->logger->info(sprintf('Deleting temporary folder %s', $file['path']));
613
  $this->target_filesystem->deleteDir($file['path']);
614
  }
618
  return true;
619
 
620
  }
621
+
622
+ /**
623
+ * Delete restore script method
624
+ *
625
+ * @throws \League\Flysystem\FileNotFoundException
626
+ */
627
  private function delete_self()
628
  {
629
+ if ($this->filesystem->has("vendor.phar"))
630
  {
631
  $this->logger->info(sprintf('Deleting vendor.phar'));
632
  $this->filesystem->delete("vendor.phar");
633
  }
634
+ if ($this->filesystem->has("vendor"))
635
  {
636
  $this->logger->info(sprintf('Deleting vendor folder'));
637
  $this->filesystem->deleteDir("vendor");
638
  }
639
+ if ($this->filesystem->has("xcloner_restore.php"))
640
  {
641
  $this->logger->info(sprintf('Deleting xcloner_restore.php'));
642
  $this->filesystem->delete("xcloner_restore.php");
643
  }
644
 
645
+ if ($this->filesystem->has("xcloner_restore.log"))
646
  {
647
  $this->logger->info(sprintf('Deleting xcloner_restore.log'));
648
  $this->filesystem->delete("xcloner_restore.log");
649
  }
650
 
651
+ if ($this->filesystem->has($this->get_logger_filename()))
652
  {
653
  $this->logger->info(sprintf('Deleting logger file %s', $this->get_logger_filename()));
654
  $this->filesystem->delete($this->get_logger_filename());
655
  }
656
 
657
  }
658
+
659
+ /**
660
+ * Update Wordpress url in wp-config.php method
661
+ * @param $wp_path
662
+ * @param $url
663
+ * @param mysqli $mysqli
664
+ * @return bool
665
+ * @throws Exception
666
+ */
667
  private function update_wp_url($wp_path, $url, $mysqli)
668
  {
669
  $wp_config = $wp_path.DS."wp-config.php";
670
 
671
  $this->logger->info(sprintf('Updating site url to %s', $url));
672
 
673
+ if (file_exists($wp_config))
674
  {
675
  $config = file_get_contents($wp_config);
676
  preg_match("/.*table_prefix.*=.*'(.*)'/i", $config, $matches);
677
+ if (isset($matches[1]))
678
  $table_prefix = $matches[1];
679
  else
680
  throw new Exception("Could not load wordpress table prefix from wp-config.php file.");
682
  else
683
  throw new Exception("Could not update the SITEURL and HOME, wp-config.php file not found");
684
 
685
+ if (!$mysqli->query("update ".$table_prefix."options set option_value='".($url)."' where option_name='home'"))
686
  throw new Exception(sprintf("Could not update the HOME option, error: %s\n", $mysqli->error));
687
 
688
+ if (!$mysqli->query("update ".$table_prefix."options set option_value='".($url)."' where option_name='siteurl'"))
689
  throw new Exception(sprintf("Could not update the SITEURL option, error: %s\n", $mysqli->error));
690
 
691
  return true;
692
  }
693
+
694
+ /**
695
+ * Update local wp-config.php file method
696
+ *
697
+ * @param $remote_path
698
+ * @param $remote_mysql_host
699
+ * @param $remote_mysql_user
700
+ * @param $remote_mysql_pass
701
+ * @param $remote_mysql_db
702
+ * @return string
703
+ * @throws Exception
704
+ */
705
  private function update_wp_config($remote_path, $remote_mysql_host, $remote_mysql_user, $remote_mysql_pass, $remote_mysql_db)
706
  {
707
  $wp_config = $remote_path.DS."wp-config.php";
708
 
709
+ if (!file_exists($wp_config))
710
  {
711
  throw new Exception("Could not find the wp-config.php in ".$remote_path);
712
  }
724
 
725
  $this->logger->info(sprintf('Updating wp-config.php file with the new mysql details'));
726
 
727
+ if (!file_put_contents($wp_config, $content))
728
  throw new Exception("Could not write updated config data to ".$wp_config);
729
 
730
  chmod($wp_config, $file_perms);
732
  return $wp_config;
733
 
734
  }
735
+
736
+ /**
737
+ * List mysqldump database backup files
738
+ *
739
+ */
740
  public function list_mysqldump_backups_action()
741
  {
742
  $source_backup_file = filter_input(INPUT_POST, 'backup_file', FILTER_SANITIZE_STRING);
744
 
745
  $hash = $this->get_hash_from_backup($source_backup_file);
746
 
747
+ $this->target_adapter = new Local($remote_path, LOCK_EX, 'SKIP_LINKS');
748
  $this->target_filesystem = new Filesystem($this->target_adapter, new Config([
749
  'disable_asserts' => true,
750
  ]));
752
  $mysqldump_list = array();
753
  $list = $this->target_filesystem->listContents();
754
 
755
+ foreach ($list as $file)
756
  {
757
  $matches = array();
758
 
759
+ if ($file['type'] == "dir")
760
  {
761
+ if (preg_match("/xcloner-(\w*)/", $file['basename'], $matches))
762
  {
763
  $files = $this->target_filesystem->listContents($file['basename']);
764
+ foreach ($files as $file)
765
  {
766
+ if ($file['extension'] == "sql")
767
  {
768
  $this->logger->info(sprintf('Found %s mysql backup file', $file['path']));
769
  $mysqldump_list[$file['path']]['path'] = $file['path'];
770
  $mysqldump_list[$file['path']]['size'] = $file['size'];
771
+ $mysqldump_list[$file['path']]['timestamp'] = date("d M,Y H:i", $file['timestamp']);
772
 
773
+ if ($hash and $hash == $matches[1])
774
  $mysqldump_list[$file['path']]['selected'] = "selected";
775
  else
776
  $mysqldump_list[$file['path']]['selected'] = "";
780
  }
781
  }
782
 
783
+ $this->sort_by($mysqldump_list, 'timestamp', 'desc');
784
  $return['files'] = $mysqldump_list;
785
 
786
  $this->send_response(200, $return);
787
  }
788
+
789
+ /**
790
+ * Get backup hash method
791
+ *
792
+ * @param $backup_file
793
+ * @return false|string
794
+ */
795
  private function get_hash_from_backup($backup_file)
796
  {
797
+ if (!$backup_file)
798
  return false;
799
 
800
+ $result = preg_match("/-(\w*)./", substr($backup_file, strlen($backup_file) - 10, strlen($backup_file)), $matches);
801
 
802
+ if ($result and isset($matches[1]))
803
  return ($matches[1]);
804
 
805
  return false;
806
  }
807
+
808
+ /**
809
+ * List backup archives found on local system
810
+ *
811
+ * @throws \League\Flysystem\FileNotFoundException
812
+ */
813
  public function list_backup_archives_action()
814
  {
815
  $local_backup_file = filter_input(INPUT_POST, 'local_backup_file', FILTER_SANITIZE_STRING);
818
  $backup_files = array();
819
  $parents = array();
820
 
821
+ foreach ($list as $file_info)
822
  {
823
  $data = array();
824
 
825
+ if (isset($file_info['extension']) and $file_info['extension'] == "csv")
826
  {
827
  $lines = explode(PHP_EOL, $this->filesystem->read($file_info['path']));
828
+ foreach ($lines as $line)
829
+ if ($line)
830
  {
831
  $data = str_getcsv($line);
832
+ if (is_array($data)) {
833
  $parents[$data[0]] = $file_info['path'];
834
  $file_info['childs'][] = $data;
835
  $file_info['size'] += $data[2];
838
 
839
  }
840
 
841
+ if ($file_info['type'] == 'file' and isset($file_info['extension']) and in_array($file_info['extension'], $this->backup_archive_extensions))
842
  $backup_files[$file_info['path']] = $file_info;
843
  }
844
 
845
  $new_list = array();
846
 
847
+ foreach ($backup_files as $key=>$file_info)
848
  {
849
+ if (isset($parents[$file_info['path']]))
850
  $backup_files[$key]['parent'] = $parents[$file_info['path']];
851
+ else {
852
 
853
+ if ($local_backup_file and ($file_info['basename'] == $local_backup_file))
854
  $file_info['selected'] = 'selected';
855
 
856
  $this->logger->info(sprintf('Found %s backup file', $file_info['path']));
860
 
861
  }
862
 
863
+ $this->sort_by($new_list, "timestamp", "desc");
864
 
865
  $return['files'] = $new_list;
866
 
867
  $this->send_response(200, $return);
868
 
869
  }
870
+
871
+ /**
872
+ * Restore backup archive to local path
873
+ *
874
+ * @throws \League\Flysystem\FileNotFoundException
875
+ * @throws \splitbrain\PHPArchive\ArchiveIOException
876
+ */
877
  public function restore_backup_to_path_action()
878
  {
879
+ $source_backup_file = filter_input(INPUT_POST, 'backup_file', FILTER_SANITIZE_STRING);
880
+ $remote_path = filter_input(INPUT_POST, 'remote_path', FILTER_SANITIZE_STRING);
881
  $include_filter_files = filter_input(INPUT_POST, 'filter_files', FILTER_SANITIZE_STRING);
882
  $exclude_filter_files = "";
883
+ $start = filter_input(INPUT_POST, 'start', FILTER_SANITIZE_NUMBER_INT);
884
+ $return['part'] = (int)filter_input(INPUT_POST, 'part', FILTER_SANITIZE_NUMBER_INT);
885
  $return['processed'] = (int)filter_input(INPUT_POST, 'processed', FILTER_SANITIZE_NUMBER_INT);
886
 
887
+ $this->target_adapter = new Local($remote_path, LOCK_EX, 'SKIP_LINKS');
888
  $this->target_filesystem = new Filesystem($this->target_adapter, new Config([
889
  'disable_asserts' => true,
890
  ]));
896
  $return['total_size'] = $this->get_backup_size($backup_file);
897
 
898
  $backup_archive = new Tar();
899
+ if ($this->is_multipart($backup_file))
900
  {
901
+ if (!$return['part'])
902
  $return['processed'] += $this->filesystem->getSize($backup_file);
903
 
904
  $backup_parts = $this->get_multipart_files($backup_file);
905
  $backup_file = $backup_parts[$return['part']];
906
+ }
907
+
908
+ if( $this->is_encrypted_file($backup_file) ) {
909
+ $message = sprintf('Backup file %s seems encrypted, please Decrypt it first from your Manage Backups panel.', $backup_file);
910
+ $this->logger->error($message);
911
+ $this->send_response(500, $message);
912
+ return;
913
+ }
914
 
915
  $this->logger->info(sprintf('Opening backup archive %s at position %s', $backup_file, $start));
916
+ $backup_archive->open($this->backup_storage_dir.DS.$backup_file, $start);
917
 
918
+ $data = $backup_archive->extract($remote_path, '', $exclude_filter_files, $include_filter_files, $this->process_files_limit);
919
 
920
+ if (isset($data['extracted_files']))
921
  {
922
+ foreach ($data['extracted_files'] as $spl_fileinfo)
923
  {
924
  $this->logger->info(sprintf('Extracted %s file', $spl_fileinfo->getPath()));
925
  $return['extracted_files'][] = $spl_fileinfo->getPath()." (".$spl_fileinfo->getSize()." bytes)";
926
  }
927
  }
928
 
929
+ if (isset($data['start']))
930
  //if(isset($data['start']) and $data['start'] <= $this->filesystem->getSize($backup_file))
931
  {
932
  $return['finished'] = 0;
933
  $return['start'] = $data['start'];
934
+ } else {
935
 
936
  $return['processed'] += $start;
937
 
938
+ if ($this->is_multipart($source_backup_file))
939
  {
940
  $return['start'] = 0;
941
 
942
  ++$return['part'];
943
 
944
+ if ($return['part'] < sizeof($backup_parts))
945
  $return['finished'] = 0;
946
 
947
  }
948
  }
949
 
950
+ if ($return['finished'])
951
  $this->logger->info(sprintf('Done extracting %s', $source_backup_file));
952
 
953
  $return['backup_file'] = $backup_file;
954
 
955
  $this->send_response(200, $return);
956
  }
957
+
958
+ /**
959
+ * Check if provided filename has encrypted suffix
960
+ *
961
+ * @param $filename
962
+ * @return bool
963
+ */
964
+ public function is_encrypted_file($filename) {
965
+ $fp = $this->filesystem->readStream( $filename );
966
+ if (is_resource($fp)) {
967
+ $encryption_length = fread($fp, 16);
968
+ fclose($fp);
969
+ if (is_numeric($encryption_length)) {
970
+ return true;
971
+ }
972
+ }
973
+
974
+ return false;
975
+
976
+ }
977
+
978
+ /**
979
+ * Get current directory method
980
+ */
981
  public function get_current_directory_action()
982
  {
983
  global $wpdb;
984
 
985
  $restore_script_url = filter_input(INPUT_POST, 'restore_script_url', FILTER_SANITIZE_STRING);
986
 
987
+ $pathinfo = pathinfo(__FILE__);
988
 
989
  $suffix = "";
990
  $return['remote_mysql_host'] = "localhost";
991
  $return['remote_mysql_user'] = "";
992
  $return['remote_mysql_pass'] = "";
993
+ $return['remote_mysql_db'] = "";
994
 
995
+ if (defined('XCLONER_PLUGIN_ACCESS') && XCLONER_PLUGIN_ACCESS)
996
  {
997
  $return['dir'] = realpath(get_home_path().DS.$suffix);
998
+ $return['restore_script_url'] = get_site_url();
999
  $return['remote_mysql_host'] = $wpdb->dbhost;
1000
  $return['remote_mysql_user'] = $wpdb->dbuser;
1001
  $return['remote_mysql_pass'] = $wpdb->dbpassword;
1002
+ $return['remote_mysql_db'] = $wpdb->dbname;
1003
  }
1004
+ else {
1005
  $return['dir'] = ($pathinfo['dirname']).DS.$suffix;
1006
  $return['restore_script_url'] = str_replace($pathinfo['basename'], "", $restore_script_url).$suffix;
1007
  }
1010
 
1011
  $this->send_response(200, $return);
1012
  }
1013
+
1014
+ /**
1015
+ * Check current filesystem
1016
+ *
1017
+ * @throws Exception
1018
+ */
1019
  public function check_system()
1020
  {
1021
  //check if i can write
1022
  $tmp_file = md5(time());
1023
+ if (!file_put_contents($tmp_file, "++"))
1024
  throw new Exception("Could not write to new host");
1025
 
1026
+ if (!unlink($tmp_file))
1027
  throw new Exception("Could not delete temporary file from new host");
1028
 
1029
  $max_upload = $this->return_bytes((ini_get('upload_max_filesize')));
1030
  $max_post = $this->return_bytes((ini_get('post_max_size')));
1031
 
1032
  $return['max_upload_size'] = min($max_upload, $max_post); // bytes
1033
+ $return['status'] = true;
1034
 
1035
  $this->logger->info(sprintf('Current filesystem max upload size is %s bytes', $return['max_upload_size']));
1036
 
1037
  $this->send_response(200, $return);
1038
  }
1039
+
1040
+ /**
1041
+ * Return bytes from human readable value
1042
+ *
1043
+ * @param string $val
1044
+ * @return int
1045
+ *
1046
+ */
1047
  private function return_bytes($val) {
1048
+ $numeric_val = (int)trim($val);
1049
+ $last = strtolower($val[strlen($val) - 1]);
1050
+ switch ($last) {
1051
+ // The 'G' modifier is available since PHP 5.1.0
1052
+ case 'g':
1053
+ //gigabytes
1054
+ $numeric_val *= 1024;
1055
+ case 'm':
1056
+ //megabytes
1057
+ $numeric_val *= 1024;
1058
+ case 'k':
1059
+ //kilobytes
1060
+ $numeric_val *= 1024;
1061
+ }
1062
+
1063
+ return $numeric_val;
1064
  }
1065
+
1066
+ /**
1067
+ * Check if backup archive os multipart
1068
+ *
1069
+ * @param $backup_name
1070
+ * @return bool
1071
+ */
1072
  public function is_multipart($backup_name)
1073
  {
1074
+ if (stristr($backup_name, "-multipart"))
1075
  return true;
1076
 
1077
  return false;
1078
  }
1079
+
1080
+ /**
1081
+ * Get backup archive size
1082
+ *
1083
+ * @param $backup_name
1084
+ * @return bool|false|int
1085
+ * @throws \League\Flysystem\FileNotFoundException
1086
+ */
1087
  public function get_backup_size($backup_name)
1088
  {
1089
  $backup_size = $this->filesystem->getSize($backup_name);
1090
+ if ($this->is_multipart($backup_name))
1091
  {
1092
  $backup_parts = $this->get_multipart_files($backup_name);
1093
+ foreach ($backup_parts as $part_file)
1094
  $backup_size += $this->filesystem->getSize($part_file);
1095
  }
1096
 
1097
  return $backup_size;
1098
  }
1099
+
1100
+ /**
1101
+ * Get multipart backup files list
1102
+ * @param $backup_name
1103
+ * @return array
1104
+ * @throws \League\Flysystem\FileNotFoundException
1105
+ */
1106
  public function get_multipart_files($backup_name)
1107
  {
1108
  $files = array();
1109
 
1110
+ if ($this->is_multipart($backup_name))
1111
  {
1112
  $lines = explode(PHP_EOL, $this->filesystem->read($backup_name));
1113
+ foreach ($lines as $line)
1114
  {
1115
+ if ($line)
1116
  {
1117
  $data = str_getcsv($line);
1118
  $files[] = $data[0];
1122
 
1123
  return $files;
1124
  }
1125
+
1126
+ /**
1127
+ * Sort_by method
1128
+ *
1129
+ * @param $array
1130
+ * @param string $field
1131
+ * @param string $direction
1132
+ * @return bool
1133
+ */
1134
+ private function sort_by(&$array, $field, $direction = 'asc')
1135
  {
1136
  $direction = strtolower($direction);
1137
+
1138
+ usort($array,
1139
+
1140
+ /**
1141
+ * @param string $b
1142
+ */
1143
+ function($a, $b) use($field, $direction){
1144
+
1145
+ $a = $a[$field];
1146
+ $b = $b[$field];
1147
+
1148
+ if ($a == $b)
1149
+ {
1150
+ return 0;
1151
+ }
1152
+
1153
+ if ($direction == 'desc') {
1154
+ if ($a > $b) {
1155
+ return -1;
1156
+ }
1157
+ else {
1158
+ return 1;
1159
+ }
1160
+ } else {
1161
+ if ($a < $b) {
1162
+ return -1;
1163
+ }
1164
+ else {
1165
+ return 1;
1166
+ }
1167
+ }
1168
+
1169
+ //return ($a.($direction == 'desc' ? '>' : '<').$b) ? -1 : 1;
1170
+ }
1171
+ );
1172
+
1173
+ return true;
1174
  }
1175
+
1176
+ /**
1177
+ * Send response method
1178
+ *
1179
+ * @param int $status
1180
+ * @param $response
1181
+ */
1182
  public static function send_response($status = 200, $response)
1183
  {
1184
  header("Access-Control-Allow-Origin: *");
1187
  $return['status'] = $status;
1188
  $return['statusText'] = $response;
1189
 
1190
+ if (isset($response['error']) && $response['error'])
1191
  {
1192
  $return['statusText'] = $response['message'];
1193
  $return['error'] = true;
1194
+ }elseif ($status != 200 and $status != 418)
1195
  {
1196
  $return['error'] = true;
1197
  $return['message'] = $response;
1198
  }
1199
 
1200
+ die (json_encode($return));
1201
+
1202
  }
1203
+
1204
+ /**
1205
  * Serialize fix methods below for mysql query lines
1206
+ *
1207
+ * @param $query
1208
+ * @return string
1209
+ */
1210
 
1211
  function do_serialized_fix($query)
1212
  {
1213
+ $query = str_replace(array("\\n", "\\r", "\\'"), array("", "", "\""), ($query));
1214
 
1215
+ return preg_replace_callback('!s:(\d+):([\\\\]?"[\\\\]?"|[\\\\]?"((.*?)[^\\\\])[\\\\]?");!', function($m) {
1216
  $data = "";
1217
 
1218
+ if (!isset($m[3]))
1219
  $m[3] = "";
1220
 
1221
  $data = 's:'.strlen(($m[3])).':\"'.($m[3]).'\";';
1222
+ //return $this->unescape_quotes($data);
1223
 
1224
+ return $data;
1225
+ }, $query);
1226
  }
1227
+
1228
+ /**
1229
+ * Unescape quotes method
1230
+ *
1231
+ * @param $value
1232
+ * @return mixed
1233
+ */
1234
  private function unescape_quotes($value) {
1235
  return str_replace('\"', '"', $value);
1236
  }
1237
+
1238
+ /**
1239
+ * Unescape mysql method
1240
+ *
1241
+ * @param $value
1242
+ * @return mixed
1243
+ */
1244
  private function unescape_mysql($value) {
1245
+ return str_replace(array("\\\\", "\\0", "\\n", "\\r", "\Z", "\'", '\"'),
1246
+ array("\\", "\0", "\n", "\r", "\x1a", "'", '"'),
1247
  $value);
1248
+ }
1249
+
1250
+ /**
1251
+ * Check if string is in serialized format
1252
+ *
1253
+ * @param $s
1254
+ * @return bool
1255
+ */
1256
  private function has_serialized($s)
1257
  {
1258
+ if (
1259
+ stristr($s, '{') !== false &&
1260
+ stristr($s, '}') !== false &&
1261
+ stristr($s, ';') !== false &&
1262
+ stristr($s, ':') !== false
1263
+ ) {
1264
+ return true;
1265
+ } else {
1266
+ return false;
1267
  }
1268
 
1269
  }
uninstall.php CHANGED
@@ -26,6 +26,6 @@
26
  */
27
 
28
  // If uninstall not called from WordPress, then exit.
29
- if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
30
  exit;
31
  }
26
  */
27
 
28
  // If uninstall not called from WordPress, then exit.
29
+ if (!defined('WP_UNINSTALL_PLUGIN')) {
30
  exit;
31
  }
vendor/composer/ClassLoader.php CHANGED
@@ -279,7 +279,7 @@ class ClassLoader
279
  */
280
  public function setApcuPrefix($apcuPrefix)
281
  {
282
- $this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null;
283
  }
284
 
285
  /**
@@ -377,7 +377,7 @@ class ClassLoader
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) {
279
  */
280
  public function setApcuPrefix($apcuPrefix)
281
  {
282
+ $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
283
  }
284
 
285
  /**
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) {
vendor/composer/autoload_files.php CHANGED
@@ -18,6 +18,5 @@ return array(
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
  );
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
  'decc78cc4436b1292c6c0d151b19445c' => $vendorDir . '/phpseclib/phpseclib/phpseclib/bootstrap.php',
22
  );
vendor/composer/autoload_psr4.php CHANGED
@@ -32,7 +32,6 @@ 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
- '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
  );
32
  'GuzzleHttp\\Psr7\\' => array($vendorDir . '/guzzlehttp/psr7/src'),
33
  'GuzzleHttp\\Promise\\' => array($vendorDir . '/guzzlehttp/promises/src'),
34
  'GuzzleHttp\\' => array($vendorDir . '/guzzlehttp/guzzle/src'),
 
35
  'BackblazeB2\\' => array($vendorDir . '/gliterd/backblaze-b2/src'),
36
  'Aws\\' => array($vendorDir . '/aws/aws-sdk-php/src'),
37
  );
vendor/composer/autoload_static.php CHANGED
@@ -19,7 +19,6 @@ class ComposerStaticInit571f9d19802717f7be61d57b40d60b28
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,10 +73,6 @@ class ComposerStaticInit571f9d19802717f7be61d57b40d60b28
74
  'GuzzleHttp\\Promise\\' => 19,
75
  'GuzzleHttp\\' => 11,
76
  ),
77
- 'D' =>
78
- array (
79
- 'Defuse\\Crypto\\' => 14,
80
- ),
81
  'B' =>
82
  array (
83
  'BackblazeB2\\' => 12,
@@ -193,10 +188,6 @@ class ComposerStaticInit571f9d19802717f7be61d57b40d60b28
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 (
202
  0 => __DIR__ . '/..' . '/gliterd/backblaze-b2/src',
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
  'decc78cc4436b1292c6c0d151b19445c' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/bootstrap.php',
23
  );
24
 
73
  'GuzzleHttp\\Promise\\' => 19,
74
  'GuzzleHttp\\' => 11,
75
  ),
 
 
 
 
76
  'B' =>
77
  array (
78
  'BackblazeB2\\' => 12,
188
  array (
189
  0 => __DIR__ . '/..' . '/guzzlehttp/guzzle/src',
190
  ),
 
 
 
 
191
  'BackblazeB2\\' =>
192
  array (
193
  0 => __DIR__ . '/..' . '/gliterd/backblaze-b2/src',
vendor/composer/installed.json CHANGED
@@ -125,71 +125,6 @@
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/",
164
- "license": [
165
- "MIT"
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",
@@ -435,29 +370,29 @@
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",
@@ -475,7 +410,7 @@
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": {
@@ -620,35 +555,30 @@
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": {
@@ -1019,57 +949,6 @@
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": [
1056
- "MIT"
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",
@@ -1793,17 +1672,17 @@
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": {
@@ -1812,7 +1691,7 @@
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": {
125
  "description": "jQuery JavaScript Library",
126
  "homepage": "http://jquery.com"
127
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
  {
129
  "name": "gliterd/backblaze-b2",
130
  "version": "1.0.4",
370
  },
371
  {
372
  "name": "league/flysystem",
373
+ "version": "1.0.49",
374
+ "version_normalized": "1.0.49.0",
375
  "source": {
376
  "type": "git",
377
  "url": "https://github.com/thephpleague/flysystem.git",
378
+ "reference": "a63cc83d8a931b271be45148fa39ba7156782ffd"
379
  },
380
  "dist": {
381
  "type": "zip",
382
+ "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/a63cc83d8a931b271be45148fa39ba7156782ffd",
383
+ "reference": "a63cc83d8a931b271be45148fa39ba7156782ffd",
384
  "shasum": ""
385
  },
386
  "require": {
387
+ "ext-fileinfo": "*",
388
  "php": ">=5.5.9"
389
  },
390
  "conflict": {
391
  "league/flysystem-sftp": "<1.0.6"
392
  },
393
  "require-dev": {
 
394
  "phpspec/phpspec": "^3.4",
395
+ "phpunit/phpunit": "^5.7.10"
396
  },
397
  "suggest": {
398
  "ext-fileinfo": "Required for MimeType",
410
  "spatie/flysystem-dropbox": "Allows you to use Dropbox storage",
411
  "srmklive/flysystem-dropbox-v2": "Allows you to use Dropbox storage for PHP 5 applications"
412
  },
413
+ "time": "2018-11-23T23:41:29+00:00",
414
  "type": "library",
415
  "extra": {
416
  "branch-alias": {
555
  },
556
  {
557
  "name": "league/flysystem-sftp",
558
+ "version": "1.0.18",
559
+ "version_normalized": "1.0.18.0",
560
  "source": {
561
  "type": "git",
562
  "url": "https://github.com/thephpleague/flysystem-sftp.git",
563
+ "reference": "61bc5a6ade892b5ac81e62b8c21be2c1798acc2a"
564
  },
565
  "dist": {
566
  "type": "zip",
567
+ "url": "https://api.github.com/repos/thephpleague/flysystem-sftp/zipball/61bc5a6ade892b5ac81e62b8c21be2c1798acc2a",
568
+ "reference": "61bc5a6ade892b5ac81e62b8c21be2c1798acc2a",
569
  "shasum": ""
570
  },
571
  "require": {
572
  "league/flysystem": "~1.0",
573
+ "php": ">=5.6.0",
574
  "phpseclib/phpseclib": "~2.0"
575
  },
576
  "require-dev": {
577
  "mockery/mockery": "0.9.*",
578
+ "phpunit/phpunit": "^5.7.25"
579
  },
580
+ "time": "2019-01-07T11:56:21+00:00",
581
  "type": "library",
 
 
 
 
 
582
  "installation-source": "source",
583
  "autoload": {
584
  "psr-4": {
949
  "jsonpath"
950
  ]
951
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
952
  {
953
  "name": "phpseclib/phpseclib",
954
  "version": "2.0.11",
1672
  },
1673
  {
1674
  "name": "vakata/jstree",
1675
+ "version": "3.3.7",
1676
+ "version_normalized": "3.3.7.0",
1677
  "source": {
1678
  "type": "git",
1679
  "url": "https://github.com/vakata/jstree.git",
1680
+ "reference": "bc5187e5826244dee5ebdc0e9db2e2652fefe928"
1681
  },
1682
  "dist": {
1683
  "type": "zip",
1684
+ "url": "https://api.github.com/repos/vakata/jstree/zipball/bc5187e5826244dee5ebdc0e9db2e2652fefe928",
1685
+ "reference": "bc5187e5826244dee5ebdc0e9db2e2652fefe928",
1686
  "shasum": ""
1687
  },
1688
  "require": {
1691
  "suggest": {
1692
  "robloach/component-installer": "Allows installation of Components via Composer"
1693
  },
1694
+ "time": "2018-11-06T21:15:47+00:00",
1695
  "type": "component",
1696
  "extra": {
1697
  "component": {
vendor/defuse/php-encryption/.gitignore DELETED
@@ -1,11 +0,0 @@
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 DELETED
@@ -1,60 +0,0 @@
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 DELETED
@@ -1,21 +0,0 @@
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 DELETED
@@ -1,102 +0,0 @@
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 DELETED
@@ -1,14 +0,0 @@
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 DELETED
@@ -1,35 +0,0 @@
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 DELETED
@@ -1,37 +0,0 @@
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 DELETED
@@ -1,25 +0,0 @@
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 DELETED
@@ -1,52 +0,0 @@
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 DELETED
@@ -1,64 +0,0 @@
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 DELETED
@@ -1,51 +0,0 @@
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 DELETED
@@ -1,53 +0,0 @@
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 DELETED
@@ -1,166 +0,0 @@
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 DELETED
@@ -1,314 +0,0 @@
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 DELETED
@@ -1,51 +0,0 @@
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 DELETED
@@ -1,280 +0,0 @@
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 DELETED
@@ -1,486 +0,0 @@
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 DELETED
@@ -1,117 +0,0 @@
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 DELETED
@@ -1,259 +0,0 @@
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 DELETED
@@ -1,12 +0,0 @@
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 DELETED
@@ -1,448 +0,0 @@
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 DELETED
@@ -1,445 +0,0 @@
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 DELETED
@@ -1,50 +0,0 @@
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 DELETED
@@ -1,268 +0,0 @@
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 DELETED
@@ -1,7 +0,0 @@
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 DELETED
@@ -1,7 +0,0 @@
1
- <?php
2
-
3
- namespace Defuse\Crypto\Exception;
4
-
5
- class CryptoException extends \Exception
6
- {
7
- }
 
 
 
 
 
 
 
vendor/defuse/php-encryption/src/Exception/EnvironmentIsBrokenException.php DELETED
@@ -1,7 +0,0 @@
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 DELETED
@@ -1,7 +0,0 @@
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 DELETED
@@ -1,7 +0,0 @@
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 DELETED
@@ -1,762 +0,0 @@
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 DELETED
@@ -1,94 +0,0 @@
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 DELETED
@@ -1,149 +0,0 @@
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 DELETED
@@ -1,145 +0,0 @@
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 DELETED
@@ -1,228 +0,0 @@
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/.gitignore ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ build
2
+ composer.lock
3
+ docs
4
+ vendor
5
+ coverage
6
+ coverage.xml
7
+ .idea/
vendor/gliterd/backblaze-b2/.scrutinizer.yml ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ filter:
2
+ paths: [src/*]
3
+ checks:
4
+ php:
5
+ code_rating: true
6
+ remove_extra_empty_lines: true
7
+ remove_php_closing_tag: true
8
+ remove_trailing_whitespace: true
9
+ fix_use_statements:
10
+ remove_unused: true
11
+ preserve_multiple: false
12
+ preserve_blanklines: true
13
+ order_alphabetically: true
14
+ fix_php_opening_tag: true
15
+ fix_linefeed: true
16
+ fix_line_ending: true
17
+ fix_identation_4spaces: true
18
+ fix_doc_comments: true
19
+ tools:
20
+ php_code_coverage: true
21
+ php_code_sniffer:
22
+ config:
23
+ standard: PSR2
24
+ filter:
25
+ paths: ['src']
26
+ php_loc:
27
+ enabled: true
28
+ php_cpd:
29
+ enabled: true
30
+ build:
31
+ environment:
32
+ php:
33
+ version: 7.1
vendor/gliterd/backblaze-b2/.travis.yml ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ language: php
2
+
3
+ php:
4
+ - '5.6'
5
+ - '7.0'
6
+ - '7.1'
7
+ - nightly
8
+
9
+ before_script: composer install
vendor/league/flysystem-sftp/.travis.yml CHANGED
@@ -12,14 +12,10 @@ env:
12
  - PREFER_LOWEST=""
13
 
14
  php:
15
- - 5.5
16
  - 5.6
17
  - 7.0
18
  - 7.1
19
-
20
- before_install:
21
- - composer self-up
22
- - composer config --global github-oauth.github.com $GITHUB_OAUTH_TOKEN
23
 
24
  install:
25
  - composer update --no-interaction --prefer-stable $PREFER_LOWEST
12
  - PREFER_LOWEST=""
13
 
14
  php:
 
15
  - 5.6
16
  - 7.0
17
  - 7.1
18
+ - 7.2
 
 
 
19
 
20
  install:
21
  - composer update --no-interaction --prefer-stable $PREFER_LOWEST
vendor/league/flysystem-sftp/changelog.md CHANGED
@@ -1,5 +1,26 @@
1
  # Changelog
2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  ## 1.0.14 - 2017-07-11
4
 
5
  ### Fixed
1
  # Changelog
2
 
3
+ ## 1.0.18 - 2019-01-07
4
+
5
+ * Throw an Exception if can't connect to check Host Fingerprint
6
+
7
+ ## 1.0.17 - 2018-10-14
8
+
9
+ * Don't return visibility when not in scope
10
+
11
+ ## 1.0.16 - 2018-07-08
12
+
13
+ ### Altered
14
+
15
+ * Stat cache is always disabled.
16
+
17
+ ## 1.0.15 - 2017-11-16
18
+
19
+ ### Fixed
20
+
21
+ * Added missing `path` to read and readStream response.
22
+ * Upgraded phpunit and lost support for php <=5.5
23
+
24
  ## 1.0.14 - 2017-07-11
25
 
26
  ### Fixed
vendor/league/flysystem-sftp/composer.json CHANGED
@@ -9,22 +9,17 @@
9
  }
10
  ],
11
  "require": {
12
- "php": ">=5.4.0",
13
  "league/flysystem": "~1.0",
14
  "phpseclib/phpseclib": "~2.0"
15
  },
16
  "require-dev": {
17
- "phpunit/phpunit": "~4.0",
18
- "mockery/mockery": "0.9.*"
19
  },
20
  "autoload": {
21
  "psr-4": {
22
  "League\\Flysystem\\Sftp\\": "src/"
23
  }
24
- },
25
- "extra": {
26
- "branch-alias": {
27
- "dev-master": "1.0-dev"
28
- }
29
  }
30
  }
9
  }
10
  ],
11
  "require": {
12
+ "php": ">=5.6.0",
13
  "league/flysystem": "~1.0",
14
  "phpseclib/phpseclib": "~2.0"
15
  },
16
  "require-dev": {
17
+ "mockery/mockery": "0.9.*",
18
+ "phpunit/phpunit": "^5.7.25"
19
  },
20
  "autoload": {
21
  "psr-4": {
22
  "League\\Flysystem\\Sftp\\": "src/"
23
  }
 
 
 
 
 
24
  }
25
  }
vendor/league/flysystem-sftp/phpunit.xml CHANGED
@@ -25,7 +25,6 @@
25
  </listeners>
26
  <logging>
27
  <log type="coverage-text" target="php://stdout" showUncoveredFiles="true"/>
28
- <log type="coverage-html" target="coverage" showUncoveredFiles="true"/>
29
  <log type="coverage-clover" target="coverage.xml" showUncoveredFiles="true"/>
30
  </logging>
31
  </phpunit>
25
  </listeners>
26
  <logging>
27
  <log type="coverage-text" target="php://stdout" showUncoveredFiles="true"/>
 
28
  <log type="coverage-clover" target="coverage.xml" showUncoveredFiles="true"/>
29
  </logging>
30
  </phpunit>
vendor/league/flysystem-sftp/readme.md CHANGED
@@ -7,6 +7,7 @@
7
  [![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE)
8
  [![Packagist Version](https://img.shields.io/packagist/v/league/flysystem-sftp.svg?style=flat-square)](https://packagist.org/packages/league/flysystem-sftp)
9
  [![Total Downloads](https://img.shields.io/packagist/dt/league/flysystem-sftp.svg?style=flat-square)](https://packagist.org/packages/league/flysystem-sftp)
 
10
 
11
  This adapter uses phpseclib to provide a SFTP adapter for Flysystem.
12
 
@@ -16,6 +17,10 @@ This adapter uses phpseclib to provide a SFTP adapter for Flysystem.
16
  composer require league/flysystem-sftp
17
  ```
18
 
 
 
 
 
19
  ## Usage
20
 
21
  ```php
7
  [![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE)
8
  [![Packagist Version](https://img.shields.io/packagist/v/league/flysystem-sftp.svg?style=flat-square)](https://packagist.org/packages/league/flysystem-sftp)
9
  [![Total Downloads](https://img.shields.io/packagist/dt/league/flysystem-sftp.svg?style=flat-square)](https://packagist.org/packages/league/flysystem-sftp)
10
+ [![Documentation](https://img.shields.io/badge/read-documentation-brightgreen.svg)](https://flysystem.thephpleague.com/adapter/sftp/)
11
 
12
  This adapter uses phpseclib to provide a SFTP adapter for Flysystem.
13
 
17
  composer require league/flysystem-sftp
18
  ```
19
 
20
+ ## Documentation
21
+
22
+ Full documentation of this adapter can be found [here](https://flysystem.thephpleague.com/adapter/sftp/): https://flysystem.thephpleague.com/adapter/sftp/
23
+
24
  ## Usage
25
 
26
  ```php
vendor/league/flysystem-sftp/src/SftpAdapter.php CHANGED
@@ -9,8 +9,8 @@ use League\Flysystem\AdapterInterface;
9
  use League\Flysystem\Config;
10
  use League\Flysystem\Util;
11
  use LogicException;
12
- use phpseclib\Net\SFTP;
13
  use phpseclib\Crypt\RSA;
 
14
  use phpseclib\System\SSH\Agent;
15
  use RuntimeException;
16
 
@@ -174,6 +174,7 @@ class SftpAdapter extends AbstractFtpAdapter
174
  public function connect()
175
  {
176
  $this->connection = $this->connection ?: new SFTP($this->host, $this->port, $this->timeout);
 
177
  $this->login();
178
  $this->setConnectionRoot();
179
  }
@@ -186,7 +187,13 @@ class SftpAdapter extends AbstractFtpAdapter
186
  protected function login()
187
  {
188
  if ($this->hostFingerprint) {
189
- $actualFingerprint = $this->getHexFingerprintFromSshPublicKey($this->connection->getServerPublicHostKey());
 
 
 
 
 
 
190
 
191
  if (0 !== strcasecmp($this->hostFingerprint, $actualFingerprint)) {
192
  throw new LogicException('The authenticity of host '.$this->host.' can\'t be established.');
@@ -362,7 +369,7 @@ class SftpAdapter extends AbstractFtpAdapter
362
  return false;
363
  }
364
 
365
- return compact('contents', 'visibility', 'path');
366
  }
367
 
368
  /**
@@ -374,7 +381,7 @@ class SftpAdapter extends AbstractFtpAdapter
374
  return false;
375
  }
376
 
377
- return compact('visibility', 'path');
378
  }
379
 
380
  /**
@@ -413,7 +420,7 @@ class SftpAdapter extends AbstractFtpAdapter
413
  return false;
414
  }
415
 
416
- return compact('contents');
417
  }
418
 
419
  /**
@@ -431,7 +438,7 @@ class SftpAdapter extends AbstractFtpAdapter
431
 
432
  rewind($stream);
433
 
434
- return compact('stream');
435
  }
436
 
437
  /**
9
  use League\Flysystem\Config;
10
  use League\Flysystem\Util;
11
  use LogicException;
 
12
  use phpseclib\Crypt\RSA;
13
+ use phpseclib\Net\SFTP;
14
  use phpseclib\System\SSH\Agent;
15
  use RuntimeException;
16
 
174
  public function connect()
175
  {
176
  $this->connection = $this->connection ?: new SFTP($this->host, $this->port, $this->timeout);
177
+ $this->connection->disableStatCache();
178
  $this->login();
179
  $this->setConnectionRoot();
180
  }
187
  protected function login()
188
  {
189
  if ($this->hostFingerprint) {
190
+ $publicKey = $this->connection->getServerPublicHostKey();
191
+
192
+ if ($publicKey === false) {
193
+ throw new LogicException('Could not connect to server to verify public key.');
194
+ }
195
+
196
+ $actualFingerprint = $this->getHexFingerprintFromSshPublicKey($publicKey);
197
 
198
  if (0 !== strcasecmp($this->hostFingerprint, $actualFingerprint)) {
199
  throw new LogicException('The authenticity of host '.$this->host.' can\'t be established.');
369
  return false;
370
  }
371
 
372
+ return compact('contents', 'path');
373
  }
374
 
375
  /**
381
  return false;
382
  }
383
 
384
+ return compact('path');
385
  }
386
 
387
  /**
420
  return false;
421
  }
422
 
423
+ return compact('contents', 'path');
424
  }
425
 
426
  /**
438
 
439
  rewind($stream);
440
 
441
+ return compact('stream', 'path');
442
  }
443
 
444
  /**
vendor/league/flysystem-sftp/tests/SftpAdapterTests.php CHANGED
@@ -5,12 +5,17 @@ use League\Flysystem\FilesystemInterface;
5
  use League\Flysystem\Sftp\SftpAdapter as Sftp;
6
  use League\Flysystem\Sftp\SftpAdapter;
7
  use phpseclib\System\SSH\Agent;
 
8
 
9
  /**
10
  * @covers \League\Flysystem\Sftp\SftpAdapter<extended>
11
  */
12
- class SftpTests extends PHPUnit_Framework_TestCase
13
  {
 
 
 
 
14
  protected function setup()
15
  {
16
  if (! defined('NET_SFTP_TYPE_DIRECTORY')) {
@@ -139,6 +144,12 @@ class SftpTests extends PHPUnit_Framework_TestCase
139
  */
140
  public function testSetVisibility($filesystem, $adapter, $mock)
141
  {
 
 
 
 
 
 
142
  $mock->shouldReceive('chmod')->twice()->andReturn(true, false);
143
  $this->assertTrue($filesystem->setVisibility('something', 'public'));
144
  $this->assertFalse($filesystem->setVisibility('something', 'public'));
@@ -150,6 +161,12 @@ class SftpTests extends PHPUnit_Framework_TestCase
150
  */
151
  public function testSetVisibilityInvalid($filesystem, $adapter, $mock)
152
  {
 
 
 
 
 
 
153
  $mock->shouldReceive('stat')->once()->andReturn(true);
154
  $filesystem->setVisibility('something', 'invalid');
155
  }
@@ -395,6 +412,7 @@ class SftpTests extends PHPUnit_Framework_TestCase
395
  {
396
  $adapter->setNetSftpConnection($mock);
397
  $mock->shouldReceive('login')->with('test', 'test')->andReturn(true);
 
398
  $adapter->connect();
399
  }
400
 
@@ -543,18 +561,16 @@ class SftpTests extends PHPUnit_Framework_TestCase
543
  'host' => 'example.org',
544
  'username' => 'user',
545
  'password' => '123456',
546
- 'hostFingerprint' => '88:76:75:96:c1:26:7c:dd:9f:87:50:db:ac:c4:a8:7c',
547
  ]);
548
 
549
  $connection = Mockery::mock('phpseclib\Net\SFTP');
550
-
551
  $connection->shouldReceive('getServerPublicHostKey')
552
- ->andReturn('ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQD05PZTxeH6GPDyxLNv7UV05jcK+Y9P8kQnpEZRHOurJVSOB4k6JBXLQtgbffuy8bFYh6mZVx40f5Za0I9mCfPel/xnCu4F1cndZBY3Ww/12rmjYOHie7k9B3h1trJ1mDhXHuiRO6vfy81jMJ9dzJyCwOK9aFGEueQ8WuPMRt9/1g3awi1O0+YZ8gTLtjKbUXLT50/GksiWDFA6DwxjLR7jFEcuPUm/WpBIKMcsbxpjKmTNaCeuoKs9TcpTwg5E311nQfk0oficgyHP/x8m6mNH5q/zOMwaRjyC6LYyBXVJgSKsh7YFf+pRyHFGpWTWKnRKXWG13NLiEKb47SydLe77');
553
-
554
  $connection->shouldReceive('login')
555
  ->with('user', '123456')
556
  ->andReturn(TRUE);
557
-
558
  $connection->shouldReceive('disconnect');
559
 
560
  $adapter->setNetSftpConnection($connection);
@@ -574,13 +590,11 @@ class SftpTests extends PHPUnit_Framework_TestCase
574
 
575
  $connection->shouldReceive('getServerPublicHostKey')
576
  ->never();
577
-
578
  $connection->shouldReceive('login')
579
  ->with('user', '123456')
580
  ->andReturn(TRUE);
581
-
582
  $connection->shouldReceive('disconnect');
583
-
584
  $adapter->setNetSftpConnection($connection);
585
 
586
  $adapter->connect();
@@ -602,11 +616,41 @@ class SftpTests extends PHPUnit_Framework_TestCase
602
  $connection = Mockery::mock('phpseclib\Net\SFTP');
603
 
604
  $connection->shouldReceive('getServerPublicHostKey')
605
- ->andReturn('ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQD05PZTxeH6GPDyxLNv7UV05jcK+Y9P8kQnpEZRHOurJVSOB4k6JBXLQtgbffuy8bFYh6mZVx40f5Za0I9mCfPel/xnCu4F1cndZBY3Ww/12rmjYOHie7k9B3h1trJ1mDhXHuiRO6vfy81jMJ9dzJyCwOK9aFGEueQ8WuPMRt9/1g3awi1O0+YZ8gTLtjKbUXLT50/GksiWDFA6DwxjLR7jFEcuPUm/WpBIKMcsbxpjKmTNaCeuoKs9TcpTwg5E311nQfk0oficgyHP/x8m6mNH5q/zOMwaRjyC6LYyBXVJgSKsh7YFf+pRyHFGpWTWKnRKXWG13NLiEKb47SydLe77');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
606
 
607
  $connection->shouldReceive('login')
608
  ->never();
609
 
 
610
  $connection->shouldReceive('disconnect');
611
 
612
  $adapter->setNetSftpConnection($connection);
5
  use League\Flysystem\Sftp\SftpAdapter as Sftp;
6
  use League\Flysystem\Sftp\SftpAdapter;
7
  use phpseclib\System\SSH\Agent;
8
+ use PHPUnit\Framework\TestCase;
9
 
10
  /**
11
  * @covers \League\Flysystem\Sftp\SftpAdapter<extended>
12
  */
13
+ class SftpTests extends TestCase
14
  {
15
+ const SSH_RSA = 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQD05PZTxeH6GPDyxLNv7UV05jcK+Y9P8kQnpEZRHOurJVSOB4k6JBXLQtgbffuy8bFYh6mZVx40f5Za0I9mCfPel/xnCu4F1cndZBY3Ww/12rmjYOHie7k9B3h1trJ1mDhXHuiRO6vfy81jMJ9dzJyCwOK9aFGEueQ8WuPMRt9/1g3awi1O0+YZ8gTLtjKbUXLT50/GksiWDFA6DwxjLR7jFEcuPUm/WpBIKMcsbxpjKmTNaCeuoKs9TcpTwg5E311nQfk0oficgyHP/x8m6mNH5q/zOMwaRjyC6LYyBXVJgSKsh7YFf+pRyHFGpWTWKnRKXWG13NLiEKb47SydLe77';
16
+
17
+ const SSH_RSA_FINGERPRINT = '88:76:75:96:c1:26:7c:dd:9f:87:50:db:ac:c4:a8:7c';
18
+
19
  protected function setup()
20
  {
21
  if (! defined('NET_SFTP_TYPE_DIRECTORY')) {
144
  */
145
  public function testSetVisibility($filesystem, $adapter, $mock)
146
  {
147
+ $mock->shouldReceive('stat')->andReturn([
148
+ 'type' => 1, // file
149
+ 'mtime' => time(),
150
+ 'size' => 20,
151
+ 'permissions' => 0777,
152
+ ]);
153
  $mock->shouldReceive('chmod')->twice()->andReturn(true, false);
154
  $this->assertTrue($filesystem->setVisibility('something', 'public'));
155
  $this->assertFalse($filesystem->setVisibility('something', 'public'));
161
  */
162
  public function testSetVisibilityInvalid($filesystem, $adapter, $mock)
163
  {
164
+ $mock->shouldReceive('stat')->andReturn([
165
+ 'type' => 1, // file
166
+ 'mtime' => time(),
167
+ 'size' => 20,
168
+ 'permissions' => 0777,
169
+ ]);
170
  $mock->shouldReceive('stat')->once()->andReturn(true);
171
  $filesystem->setVisibility('something', 'invalid');
172
  }
412
  {
413
  $adapter->setNetSftpConnection($mock);
414
  $mock->shouldReceive('login')->with('test', 'test')->andReturn(true);
415
+ $mock->shouldReceive('disableStatCache');
416
  $adapter->connect();
417
  }
418
 
561
  'host' => 'example.org',
562
  'username' => 'user',
563
  'password' => '123456',
564
+ 'hostFingerprint' => self::SSH_RSA_FINGERPRINT,
565
  ]);
566
 
567
  $connection = Mockery::mock('phpseclib\Net\SFTP');
 
568
  $connection->shouldReceive('getServerPublicHostKey')
569
+ ->andReturn(self::SSH_RSA);
 
570
  $connection->shouldReceive('login')
571
  ->with('user', '123456')
572
  ->andReturn(TRUE);
573
+ $connection->shouldReceive('disableStatCache');
574
  $connection->shouldReceive('disconnect');
575
 
576
  $adapter->setNetSftpConnection($connection);
590
 
591
  $connection->shouldReceive('getServerPublicHostKey')
592
  ->never();
 
593
  $connection->shouldReceive('login')
594
  ->with('user', '123456')
595
  ->andReturn(TRUE);
596
+ $connection->shouldReceive('disableStatCache');
597
  $connection->shouldReceive('disconnect');
 
598
  $adapter->setNetSftpConnection($connection);
599
 
600
  $adapter->connect();
616
  $connection = Mockery::mock('phpseclib\Net\SFTP');
617
 
618
  $connection->shouldReceive('getServerPublicHostKey')
619
+ ->andReturn(self::SSH_RSA);
620
+
621
+ $connection->shouldReceive('login')
622
+ ->never();
623
+
624
+ $connection->shouldReceive('disableStatCache');
625
+ $connection->shouldReceive('disconnect');
626
+
627
+ $adapter->setNetSftpConnection($connection);
628
+
629
+ $adapter->connect();
630
+ }
631
+
632
+ /**
633
+ * @expectedException LogicException
634
+ * @expectedExceptionMessage Could not connect to server to verify public key.
635
+ */
636
+ public function testCantConnectToCheckHostFingerprintAbortsLogin()
637
+ {
638
+ $adapter = new SftpAdapter([
639
+ 'host' => 'example.org',
640
+ 'username' => 'user',
641
+ 'password' => '123456',
642
+ 'hostFingerprint' => '00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00',
643
+ ]);
644
+
645
+ $connection = Mockery::mock('phpseclib\Net\SFTP');
646
+
647
+ $connection->shouldReceive('getServerPublicHostKey')
648
+ ->andReturn(false); // getServerPublicHostKey returns false if it cant connect.
649
 
650
  $connection->shouldReceive('login')
651
  ->never();
652
 
653
+ $connection->shouldReceive('disableStatCache');
654
  $connection->shouldReceive('disconnect');
655
 
656
  $adapter->setNetSftpConnection($connection);
vendor/league/flysystem/.travis.yml CHANGED
@@ -10,6 +10,7 @@ php:
10
  - 7.0
11
  - 7.1
12
  - 7.2
 
13
 
14
  matrix:
15
  allow_failures:
@@ -26,7 +27,6 @@ before_install:
26
 
27
  install:
28
  - if [[ "${TRAVIS_PHP_VERSION}" == "5.5" ]]; then composer require phpunit/phpunit:^4.8.36 phpspec/phpspec:^2 --prefer-dist --update-with-dependencies; fi
29
- - if [[ "${TRAVIS_PHP_VERSION}" == "7.2" ]]; then composer require phpunit/phpunit:^6.0 --prefer-dist --update-with-dependencies; fi
30
  - if [[ "${TRAVIS_PHP_VERSION}" == "7.2" ]]; then composer require --dev phpstan/phpstan:^0.9.2 --prefer-dist --update-with-dependencies; fi
31
  - travis_retry composer update --prefer-dist $COMPOSER_OPTS
32
 
10
  - 7.0
11
  - 7.1
12
  - 7.2
13
+ - 7.3
14
 
15
  matrix:
16
  allow_failures:
27
 
28
  install:
29
  - if [[ "${TRAVIS_PHP_VERSION}" == "5.5" ]]; then composer require phpunit/phpunit:^4.8.36 phpspec/phpspec:^2 --prefer-dist --update-with-dependencies; fi
 
30
  - if [[ "${TRAVIS_PHP_VERSION}" == "7.2" ]]; then composer require --dev phpstan/phpstan:^0.9.2 --prefer-dist --update-with-dependencies; fi
31
  - travis_retry composer update --prefer-dist $COMPOSER_OPTS
32
 
vendor/league/flysystem/README.md CHANGED
@@ -62,7 +62,7 @@ Want to get started quickly? Check out some of these integrations:
62
  ### Officially Supported
63
  * Amazon Web Services - S3 V2: https://github.com/thephpleague/flysystem-aws-s3-v2
64
  * Amazon Web Services - S3 V3: https://github.com/thephpleague/flysystem-aws-s3-v3
65
- * Azure Blob Storage: https://github.com/thephpleague/flysystem-azure
66
  * Memory: https://github.com/thephpleague/flysystem-memory
67
  * PHPCR: https://github.com/thephpleague/flysystem-phpcr
68
  * Rackspace Cloud Files: https://github.com/thephpleague/flysystem-rackspace
@@ -73,6 +73,7 @@ Want to get started quickly? Check out some of these integrations:
73
  ### Community Supported
74
  * AliYun OSS Storage: https://github.com/xxtime/flysystem-aliyun-oss
75
  * Amazon Cloud Drive - https://github.com/nikkiii/flysystem-acd
 
76
  * Backblaze: https://github.com/mhetreramesh/flysystem-backblaze
77
  * ClamAV Scanner Adapter: https://github.com/mgriego/flysystem-clamav
78
  * Citrix ShareFile: https://github.com/kapersoft/flysystem-sharefile
@@ -83,11 +84,13 @@ Want to get started quickly? Check out some of these integrations:
83
  * Gaufrette: https://github.com/jenkoian/flysystem-gaufrette
84
  * Google Cloud Storage: https://github.com/Superbalist/flysystem-google-storage
85
  * Google Drive: https://github.com/nao-pon/flysystem-google-drive
 
86
  * OneDrive: https://github.com/jacekbarecki/flysystem-onedrive
87
  * OpenStack Swift: https://github.com/nimbusoftltd/flysystem-openstack-swift
88
  * Redis (through Predis): https://github.com/danhunsaker/flysystem-redis
89
  * Selectel Cloud Storage: https://github.com/ArgentCrusade/flysystem-selectel
90
  * SinaAppEngine Storage: https://github.com/litp/flysystem-sae-storage
 
91
 
92
  ## Caching (https://github.com/thephpleague/flysystem-cached-adapter)
93
 
62
  ### Officially Supported
63
  * Amazon Web Services - S3 V2: https://github.com/thephpleague/flysystem-aws-s3-v2
64
  * Amazon Web Services - S3 V3: https://github.com/thephpleague/flysystem-aws-s3-v3
65
+ * Azure Blob Storage: https://github.com/thephpleague/flysystem-azure-blob-storage
66
  * Memory: https://github.com/thephpleague/flysystem-memory
67
  * PHPCR: https://github.com/thephpleague/flysystem-phpcr
68
  * Rackspace Cloud Files: https://github.com/thephpleague/flysystem-rackspace
73
  ### Community Supported
74
  * AliYun OSS Storage: https://github.com/xxtime/flysystem-aliyun-oss
75
  * Amazon Cloud Drive - https://github.com/nikkiii/flysystem-acd
76
+ * Azure File Storage: https://github.com/academe/flysystem-azure-file-storage
77
  * Backblaze: https://github.com/mhetreramesh/flysystem-backblaze
78
  * ClamAV Scanner Adapter: https://github.com/mgriego/flysystem-clamav
79
  * Citrix ShareFile: https://github.com/kapersoft/flysystem-sharefile
84
  * Gaufrette: https://github.com/jenkoian/flysystem-gaufrette
85
  * Google Cloud Storage: https://github.com/Superbalist/flysystem-google-storage
86
  * Google Drive: https://github.com/nao-pon/flysystem-google-drive
87
+ * Google Drive V2 (using regular paths): https://github.com/masbug/flysystem-google-drive-ext
88
  * OneDrive: https://github.com/jacekbarecki/flysystem-onedrive
89
  * OpenStack Swift: https://github.com/nimbusoftltd/flysystem-openstack-swift
90
  * Redis (through Predis): https://github.com/danhunsaker/flysystem-redis
91
  * Selectel Cloud Storage: https://github.com/ArgentCrusade/flysystem-selectel
92
  * SinaAppEngine Storage: https://github.com/litp/flysystem-sae-storage
93
+ * PDO Database: https://github.com/IntegralSoftware/flysystem-pdo-adapter
94
 
95
  ## Caching (https://github.com/thephpleague/flysystem-cached-adapter)
96
 
vendor/league/flysystem/changelog.md CHANGED
@@ -1,5 +1,26 @@
1
  # Changelog
2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  ## 1.0.44 - 2018-04-06
4
 
5
  * Added missing file presence checks on `Filesystem::setVisibility` and `Filesystem::getSize`.
1
  # Changelog
2
 
3
+ ## 1.0.49 - 2018-11-24
4
+
5
+ * It's my birthday today.
6
+ * Error message for directory creation in the Local adapter has a better description with more context.
7
+
8
+ ## 1.0.48 - 2018-10-15
9
+
10
+ * The MountManager now implements the FilesystemInterface.
11
+
12
+ ## 1.0.47 - 2018-09-14
13
+
14
+ * Specify mimetype for .epub files
15
+
16
+ ## 1.0.46 - 2018-08-22
17
+
18
+ * Return failure when copying a stream does not work instead of relying only on fclose.
19
+
20
+ ## 1.0.45 - 2018-05-07
21
+
22
+ * Fixed a regression in path-derived metadata fetching.
23
+
24
  ## 1.0.44 - 2018-04-06
25
 
26
  * Added missing file presence checks on `Filesystem::setVisibility` and `Filesystem::getSize`.
vendor/league/flysystem/composer.json CHANGED
@@ -14,12 +14,12 @@
14
  }
15
  ],
16
  "require": {
17
- "php": ">=5.5.9"
 
18
  },
19
  "require-dev": {
20
- "ext-fileinfo": "*",
21
  "phpspec/phpspec": "^3.4",
22
- "phpunit/phpunit": "^5.7"
23
  },
24
  "autoload": {
25
  "psr-4": {
14
  }
15
  ],
16
  "require": {
17
+ "php": ">=5.5.9",
18
+ "ext-fileinfo": "*"
19
  },
20
  "require-dev": {
 
21
  "phpspec/phpspec": "^3.4",
22
+ "phpunit/phpunit": "^5.7.10"
23
  },
24
  "autoload": {
25
  "psr-4": {
vendor/league/flysystem/docs/_data/menu.yml CHANGED
@@ -8,6 +8,7 @@ Usage:
8
  Filesystem API: '/docs/usage/filesystem-api/'
9
 
10
  Guides:
 
11
  Deterministic Code: '/docs/guides/deterministic-programming/'
12
  Handling Uploads: '/docs/guides/uploads/'
13
 
8
  Filesystem API: '/docs/usage/filesystem-api/'
9
 
10
  Guides:
11
+ Laravel Usage: '/docs/guides/laravel-usage/'
12
  Deterministic Code: '/docs/guides/deterministic-programming/'
13
  Handling Uploads: '/docs/guides/uploads/'
14
 
vendor/league/flysystem/docs/_data/project.yml CHANGED
@@ -1,5 +1,5 @@
1
  title: "Flysystem"
2
  tagline: "Many filesystems, one API."
3
  description: "Filesystem abstraction library for PHP."
4
- version: 1.0.44
5
  google_analytics_tracking_id: UA-114647967-1
1
  title: "Flysystem"
2
  tagline: "Many filesystems, one API."
3
  description: "Filesystem abstraction library for PHP."
4
+ version: 1.0.45
5
  google_analytics_tracking_id: UA-114647967-1
vendor/league/flysystem/docs/_includes/carbon.html CHANGED
@@ -1 +1 @@
1
- <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?zoneid=1673&serve=C6AILKT&placement=flysystemthephpleaguecom" id="_carbonads_js"></script>
1
+ <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CK7DT2JE&placement=flysystemthephpleaguecom" id="_carbonads_js"></script>
vendor/league/flysystem/docs/_layouts/default.html CHANGED
@@ -19,30 +19,30 @@
19
  gtag('config', '{{ site.data.project.google_analytics_tracking_id }}');
20
  </script>
21
  {% endif %}
22
- {% endunless %}
23
- <!--<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/docsearch.js@2/dist/cdn/docsearch.min.css" />-->
24
- <link rel="stylesheet" href="/dist/styles.css"/>
25
  <base href="https://flysystem.thephpleague.com/" />
 
 
 
26
  </head>
27
  <body class="min-h-screen text-base text-indigo-body-text min-w-full pt-12 leading-normal bg-indigo-lightest">
28
- <!--{% include size-helper.html %}-->
29
  <div class="pb-1 fixed z-10 pin-t w-screen bg-white border-indigo-lighter border-b">
30
  <div class="max-w-2xl mx-auto px-4 py-2">
31
  <div class="flex items-center flex-no-shrink pt-1">
32
  <a href="/" class="flex items-center h-10">
33
  <img class="h-10 w-10 mr-3" width="30" height="30" src="/img/flysystem.svg"/>
34
- <span class="pr-2 font-normal overflow-hidden font-heading text-3xl text-indigo-darkest">
35
  Flysystem
36
  <sup class="text-xs relative text-indigo" style="top: -20px;">{{ site.data.project.version }}</sup>
37
  </span>
38
  </a>
39
  <div class="flex-grow"></div>
40
- <!--<div class="flex-no-shrink flex-no-grow h-10 px-4 relative">-->
41
- <!--<input id="global-search" class="focus:outline-0 h-10 py-2 pl-8 pr-2 text-indigo-darker rounded bg-indigo-lightest focus:border-indigo-light focus:bg-white focus:placeholder-none max-w-xs w-full appearance-none" type="text" placeholder="Search the docs" />-->
42
- <!--<span class="pointer-events-none absolute pin-y pin-l pl-6 flex items-center">-->
43
- <!--<svg class="fill-current pointer-events-none text-indigo-light w-4 h-4 border-transparent border" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M12.9 14.32a8 8 0 1 1 1.41-1.41l5.35 5.33-1.42 1.42-5.33-5.34zM8 14A6 6 0 1 0 8 2a6 6 0 0 0 0 12z"/></svg>-->
44
- <!--</span>-->
45
- <!--</div>-->
46
  <a href="#" id="menu-toggle" class="block md:hidden h-8 w-8 border p-1 border-transparent text-grey hover:text-grey menu-closed">
47
  <svg class="menu-closed:shown fill-current h-full w-full" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
48
  <path d="M0 3h20v2H0V3zm0 6h20v2H0V9zm0 6h20v2H0v-2z"/>
@@ -87,13 +87,13 @@
87
 
88
  </footer>
89
  <script type="text/javascript" src="/dist/main.js"></script>
90
- <!--<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/docsearch.js@2/dist/cdn/docsearch.min.js"></script>-->
91
- <!--<script type="text/javascript"> docsearch({-->
92
- <!--apiKey: 'be7daf2d7afded0acb0589a0e304a423',-->
93
- <!--indexName: 'filesystem_thephpleague',-->
94
- <!--inputSelector: '#global-search',-->
95
- <!--debug: {% if site.data.dev.dev_mode %}true{% else %}false{% endif %}-->
96
- <!--});-->
97
- <!--</script>-->
98
  </body>
99
  </html>
19
  gtag('config', '{{ site.data.project.google_analytics_tracking_id }}');
20
  </script>
21
  {% endif %}
 
 
 
22
  <base href="https://flysystem.thephpleague.com/" />
23
+ {% endunless %}
24
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/docsearch.js@2/dist/cdn/docsearch.min.css" />
25
+ <link rel="stylesheet" href="/dist/styles.css?v=1.0"/>
26
  </head>
27
  <body class="min-h-screen text-base text-indigo-body-text min-w-full pt-12 leading-normal bg-indigo-lightest">
28
+ {% include size-helper.html %}
29
  <div class="pb-1 fixed z-10 pin-t w-screen bg-white border-indigo-lighter border-b">
30
  <div class="max-w-2xl mx-auto px-4 py-2">
31
  <div class="flex items-center flex-no-shrink pt-1">
32
  <a href="/" class="flex items-center h-10">
33
  <img class="h-10 w-10 mr-3" width="30" height="30" src="/img/flysystem.svg"/>
34
+ <span class="pr-2 font-normal overflow-hidden font-heading text-3xl text-indigo-darkest -sm:hidden">
35
  Flysystem
36
  <sup class="text-xs relative text-indigo" style="top: -20px;">{{ site.data.project.version }}</sup>
37
  </span>
38
  </a>
39
  <div class="flex-grow"></div>
40
+ <div class="flex-no-shrink flex-no-grow h-10 px-4 relative">
41
+ <input id="global-search" class="focus:outline-0 h-10 py-2 pl-8 pr-2 text-indigo-darker rounded bg-indigo-lightest focus:border-indigo-light focus:bg-white focus:placeholder-none max-w-xs w-full appearance-none" type="text" placeholder="Search the docs" />
42
+ <span class="pointer-events-none absolute pin-y pin-l pl-6 flex items-center">
43
+ <svg class="fill-current pointer-events-none text-indigo-light w-4 h-4 border-transparent border" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M12.9 14.32a8 8 0 1 1 1.41-1.41l5.35 5.33-1.42 1.42-5.33-5.34zM8 14A6 6 0 1 0 8 2a6 6 0 0 0 0 12z"/></svg>
44
+ </span>
45
+ </div>
46
  <a href="#" id="menu-toggle" class="block md:hidden h-8 w-8 border p-1 border-transparent text-grey hover:text-grey menu-closed">
47
  <svg class="menu-closed:shown fill-current h-full w-full" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
48
  <path d="M0 3h20v2H0V3zm0 6h20v2H0V9zm0 6h20v2H0v-2z"/>
87
 
88
  </footer>
89
  <script type="text/javascript" src="/dist/main.js"></script>
90
+ <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/docsearch.js@2/dist/cdn/docsearch.min.js"></script>
91
+ <script type="text/javascript"> docsearch({
92
+ apiKey: 'be7daf2d7afded0acb0589a0e304a423',
93
+ indexName: 'filesystem_thephpleague',
94
+ inputSelector: '#global-search',
95
+ debug: {% if site.data.dev.dev_mode %}true{% else %}false{% endif %}
96
+ });
97
+ </script>
98
  </body>
99
  </html>
vendor/league/flysystem/docs/adapter/azure.md CHANGED
@@ -8,23 +8,29 @@ title: Azure Blob Storage
8
  ## Installation
9
 
10
  ```bash
11
- composer require league/flysystem-azure
12
  ```
13
 
14
  ## Usage
15
 
16
  ```php
17
- use MicrosoftAzure\Storage\Common\ServicesBuilder;
18
  use League\Flysystem\Filesystem;
19
- use League\Flysystem\Azure\AzureAdapter;
20
 
21
- $endpoint = sprintf(
22
- 'DefaultEndpointsProtocol=https;AccountName=%s;AccountKey=%s',
23
- 'account-name',
24
- 'api-key'
25
- );
26
 
27
- $blobRestProxy = ServicesBuilder::getInstance()->createBlobService($endpoint);
28
-
29
- $filesystem = new Filesystem(new AzureAdapter($blobRestProxy, 'my-container'));
 
30
  ```
 
 
 
 
 
 
 
 
 
8
  ## Installation
9
 
10
  ```bash
11
+ composer require league/flysystem-azure-blob-storage
12
  ```
13
 
14
  ## Usage
15
 
16
  ```php
17
+ use League\Flysystem\AzureBlobStorage\AzureBlobStorageAdapter;
18
  use League\Flysystem\Filesystem;
19
+ use MicrosoftAzure\Storage\Blob\BlobRestProxy;
20
 
21
+ include __DIR__.'/vendor/autoload.php';
 
 
 
 
22
 
23
+ $client = BlobRestProxy::createBlobService('DefaultEndpointsProtocol=https;AccountName={YOUR_ACCOUNT_NAME};AccountKey={YOUR_ACCOUNT_KEY};');
24
+ $adapter = new AzureBlobStorageAdapter($client, 'container_name');
25
+ $filesystem = new Filesystem($adapter);
26
+ var_dump($filesystem->listContents());
27
  ```
28
+
29
+ ## Sponsored by:
30
+
31
+ <div class="flex my-6">
32
+ <a target="_blank" href="https://azure.microsoft.com/free/?utm_source=flysystem&utm_medium=banner&utm_campaign=flysystem_sponsorship" class="flex-no-grow w-1/3 bg-white rounded shadow-md mr-4 overflow-hidden">
33
+ <img src="/img/azure.svg" class="max-w-full m-6 sm:m-8" alt="Azure.com"/>
34
+ <span style="background-color: #00a1f1;" class="text-center text-xl hidden sm:block py-4 bg-indigo-dark text-white bg-grey-lightest">Azure.com</span>
35
+ </a>
36
+ </div>
vendor/league/flysystem/docs/adapter/phpcr.md CHANGED
@@ -40,9 +40,25 @@ $factory = new RepositoryFactoryDoctrineDBAL();
40
  $repository = $factory->getRepository([
41
  'jackalope.doctrine_dbal_connection' => $connection,
42
  ]);
43
- $session = $repository->login(new SimpleCredentials('', ''));
 
 
 
44
 
45
  // this part looks the same regardless of your phpcr implementation.
46
  $root = '/flysystem_tests';
47
  $filesystem = new Filesystem(new PhpcrAdapter($session, $root));
48
  ```
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  $repository = $factory->getRepository([
41
  'jackalope.doctrine_dbal_connection' => $connection,
42
  ]);
43
+ $session = $repository->login(new SimpleCredentials('username', 'password'));
44
+
45
+ //Or when no credentials are required
46
+ $session = $repository->login();
47
 
48
  // this part looks the same regardless of your phpcr implementation.
49
  $root = '/flysystem_tests';
50
  $filesystem = new Filesystem(new PhpcrAdapter($session, $root));
51
  ```
52
+
53
+ ### Indicate specific modification timestamp when writing content
54
+ By default PHPCR will use the current system time as the "last modified" timestamp of an entry when writing content. A specific timestamp can be provided by using the configuration array:
55
+
56
+ ```php
57
+ $path = '/path/to/file.ext';
58
+ $content = file_get_contents($path);
59
+ $config = ['timestamp' => filemtime($path)]; //Use the time when the content of the file was last changed.
60
+
61
+ $filesystem->write($path, $content, $config);
62
+ ```
63
+
64
+ This can be useful when the file timestamp needs to be preserved when copying a file structure to PHPCR.
vendor/league/flysystem/docs/adapter/sftp.md CHANGED
@@ -19,7 +19,7 @@ use League\Flysystem\Sftp\SftpAdapter;
19
 
20
  $filesystem = new Filesystem(new SftpAdapter([
21
  'host' => 'example.com',
22
- 'port' => 21,
23
  'username' => 'username',
24
  'password' => 'password',
25
  'privateKey' => 'path/to/or/contents/of/privatekey',
19
 
20
  $filesystem = new Filesystem(new SftpAdapter([
21
  'host' => 'example.com',
22
+ 'port' => 22,
23
  'username' => 'username',
24
  'password' => 'password',
25
  'privateKey' => 'path/to/or/contents/of/privatekey',
vendor/league/flysystem/docs/advanced/caching.md CHANGED
@@ -5,7 +5,7 @@ title: Caching
5
  ---
6
 
7
  File system I/O is slow, so Flysystem uses cached file system meta-data to boost performance. When your application needs to scale you can also choose to use a (shared) persistent caching solution for this.
8
- Or enable a per request caching (recommended).
9
 
10
  ## Installing the adapter cache decorator
11
 
5
  ---
6
 
7
  File system I/O is slow, so Flysystem uses cached file system meta-data to boost performance. When your application needs to scale you can also choose to use a (shared) persistent caching solution for this.
8
+ Or enable per request caching (recommended).
9
 
10
  ## Installing the adapter cache decorator
11
 
vendor/league/flysystem/docs/advanced/mount-manager.md CHANGED
@@ -60,7 +60,7 @@ foreach ($contents as $entry) {
60
  ### Copy
61
 
62
  The copy method provided by the Mount Manager takes the origin of the file into account.
63
- When it detects the source and destination are located on a different file systems it'll
64
  use a streamed upload instead, transparently.
65
 
66
  ```php
@@ -70,7 +70,7 @@ $mountManager->copy('local://some/file.ext', 'backup://storage/location.ext');
70
  ### Move
71
 
72
  The `move` call is the multi-file system counterpart to `rename`. Where rename must be used on
73
- the same file system, the `move` call provides the same conceptual behavior, but then on two
74
  different file systems.
75
 
76
  ```php
60
  ### Copy
61
 
62
  The copy method provided by the Mount Manager takes the origin of the file into account.
63
+ When it detects the source and destination are located on different file systems it'll
64
  use a streamed upload instead, transparently.
65
 
66
  ```php
70
  ### Move
71
 
72
  The `move` call is the multi-file system counterpart to `rename`. Where rename must be used on
73
+ the same file system, the `move` call provides the same conceptual behavior, but on two
74
  different file systems.
75
 
76
  ```php
vendor/league/flysystem/docs/advanced/performance.md CHANGED
@@ -5,7 +5,7 @@ title: Performance
5
  ---
6
 
7
  Flysystem aims to be as reliable as possible. In some cases this means doing extra
8
- checks to make sure the outcome will be as expected. For some adapter this means Flysystem
9
  will make extra calls to assert whether or not a file exists. This improves the reliability
10
  but also impacts performance. You can opt out of this behaviour.
11
 
5
  ---
6
 
7
  Flysystem aims to be as reliable as possible. In some cases this means doing extra
8
+ checks to make sure the outcome will be as expected. For some adapters this means Flysystem
9
  will make extra calls to assert whether or not a file exists. This improves the reliability
10
  but also impacts performance. You can opt out of this behaviour.
11
 
vendor/league/flysystem/docs/advanced/provided-plugins.md CHANGED
@@ -31,7 +31,7 @@ foreach ($listing as $object) {
31
  }
32
  ```
33
 
34
- ## Get file into with explicit metadata.
35
 
36
  This requires the `League\Flysystem\Plugin\GetWithMetadata` plugin.
37
 
31
  }
32
  ```
33
 
34
+ ## Get file info with explicit metadata.
35
 
36
  This requires the `League\Flysystem\Plugin\GetWithMetadata` plugin.
37
 
vendor/league/flysystem/docs/advanced/upgrade-to-1.0.0.md CHANGED
@@ -52,7 +52,7 @@ $filesystem = new Filesystem($decoratedAdapter);
52
 
53
  ## Helper Methods
54
 
55
- In order to clean up the Filsystem class, some helper functions have been moved to plugins.
56
 
57
  * ListWith
58
  * ListPaths
52
 
53
  ## Helper Methods
54
 
55
+ In order to clean up the Filesystem class, some helper functions have been moved to plugins.
56
 
57
  * ListWith
58
  * ListPaths
vendor/league/flysystem/docs/api.md CHANGED
@@ -182,7 +182,7 @@ foreach ($listing as $object) {
182
  }
183
  ~~~
184
 
185
- __Get file into with explicit metadata__
186
 
187
  ~~~ php
188
  $info = $filesystem->getWithMetadata('path/to/file.txt', ['timestamp', 'mimetype']);
@@ -200,10 +200,10 @@ Some SDK's close streams after consuming them, therefore, before calling fclose
200
 
201
  ~~~ php
202
  $stream = fopen('/path/to/database.backup', 'r+');
203
- $filesystem->writeStream('backups/'.strftime('%G-%m-%d').'.backup', $stream);
204
 
205
  // Using write you can also directly set the visibility
206
- $filesystem->writeStream('backups/'.strftime('%G-%m-%d').'.backup', $stream, [
207
  'visibility' => AdapterInterface::VISIBILITY_PRIVATE
208
  ]);
209
 
@@ -212,7 +212,7 @@ if (is_resource($stream)) {
212
  }
213
 
214
  // Or update a file with stream contents
215
- $filesystem->updateStream('backups/'.strftime('%G-%m-%d').'.backup', $stream);
216
 
217
  // Retrieve a read-stream
218
  $stream = $filesystem->readStream('something/is/here.ext');
182
  }
183
  ~~~
184
 
185
+ __Get file info with explicit metadata__
186
 
187
  ~~~ php
188
  $info = $filesystem->getWithMetadata('path/to/file.txt', ['timestamp', 'mimetype']);
200
 
201
  ~~~ php
202
  $stream = fopen('/path/to/database.backup', 'r+');
203
+ $filesystem->writeStream('backups/'.strftime('%Y-%m-%d').'.backup', $stream);
204
 
205
  // Using write you can also directly set the visibility
206
+ $filesystem->writeStream('backups/'.strftime('%Y-%m-%d').'.backup', $stream, [
207
  'visibility' => AdapterInterface::VISIBILITY_PRIVATE
208
  ]);
209
 
212
  }
213
 
214
  // Or update a file with stream contents
215
+ $filesystem->updateStream('backups/'.strftime('%Y-%m-%d').'.backup', $stream);
216
 
217
  // Retrieve a read-stream
218
  $stream = $filesystem->readStream('something/is/here.ext');
vendor/league/flysystem/docs/architecture.md CHANGED
@@ -30,4 +30,4 @@ timestamp | modified time | `integer`
30
  In order to make the most out of every (expensive) filesystem call adapters
31
  return as much information as they can when/if available. This makes it possible
32
  for caching mechanisms to store this information so subsequent calls can be
33
- returned from cache without the need for additional filesystems calls.
30
  In order to make the most out of every (expensive) filesystem call adapters
31
  return as much information as they can when/if available. This makes it possible
32
  for caching mechanisms to store this information so subsequent calls can be
33
+ returned from cache without the need for additional filesystem calls.
vendor/league/flysystem/docs/dist/styles.css CHANGED
@@ -1 +1 @@
1
- @import url(https://fonts.googleapis.com/css?family=Lato:300,400,700|Open+Sans:400,400i,600);/*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;box-sizing:border-box;font-family:Open Sans,sans-serif;font-weight:400;-webkit-font-smoothing:antialiased}body{margin:0}article,footer,main,menu,nav,section{display:block}h1{font-size:2em}hr{box-sizing:content-box;height:0;overflow:visible;border-bottom-width:1px;border-top-width:1px;opacity:.75;width:50%;margin:3.5rem auto 2rem;border-color:#d9dff1 #d9dff1 #fff}code,pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects;text-decoration:none;color:#4764bd}strong{font-weight:bolder}small{font-size:80%}sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline;top:-.5em}img{border-style:solid;max-width:100%}svg:not(:root){overflow:hidden}input,select{font-size:100%;line-height:1.15;margin:0}input{overflow:visible}select{text-transform:none}[type=reset],[type=submit],html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring{outline:1px dotted ButtonText}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}[hidden]{display:none}*,:after,:before{box-sizing:inherit;border:0 solid #dae1e7}blockquote,h1,h2,h3,p,pre,ul{margin:0}[tabindex="-1"]:focus{outline:0!important}[type=button],[type=reset],[type=submit]{border-radius:0}input,select{font-family:inherit}input::placeholder{color:inherit;opacity:.5}[role=button]{cursor:pointer}div.highlighter-rouge{font-family:Courier,monospace;background-color:#fff;padding:.5rem 1rem;margin-left:-1rem;margin-right:-1rem;margin-bottom:1rem;box-shadow:0 2px 4px 0 rgba(0,0,0,.1);display:block}div.highlighter-rouge>div{overflow-x:scroll;width:100%}@media (min-width:768px){div.highlighter-rouge{margin-left:0;margin-right:0}}code.highlighter-rouge{font-family:Courier,monospace;text-shadow:1px 1px 0 #fff,-1px 1px 0 #fff;font-size:1.125rem}@media (min-width:768px){.highlighter-rouge{margin-left:0;margin-right:0}}div.highlighter-rouge.language-bash{background-color:#4764bd;color:#fff;box-shadow:inset 0 4px 8px 0 rgba(0,0,0,.08),inset 0 2px 4px 0 rgba(0,0,0,.12);text-shadow:1px 1px 2px #253461,-1px 1px 2px #253461}.highlight .cp,.highlight .k,.highlight .o{font-weight:700}.highlight .cp{color:#999}.highlight .c1{color:#998;font-style:italic}.highlight .go{color:#888}.highlight .gt{color:#a00}.highlight .kc{font-weight:700}.highlight .s{color:#d14}.highlight .na{color:teal}.highlight .nb{color:#0086b3}.highlight .nc{color:#458;font-weight:700}.highlight .no{color:teal}.highlight .nf{color:#900;font-weight:700}.highlight .nv{color:teal}.highlight .w{color:#bbb}.highlight .mi,.highlight .mo{color:#099}.highlight .s1,.highlight .s2,.highlight .sd,.highlight .si{color:#d14}.algolia-autocomplete{width:100%!important}@media (max-width:768px){.algolia-autocomplete.algolia-autocomplete-right .ds-dropdown-menu{max-width:calc(100vw - 2rem)!important;width:calc(100vw - 2rem)!important;min-width:0!important;margin-left:16px!important;right:-3rem!important}.algolia-autocomplete.algolia-autocomplete-right .ds-dropdown-menu:before{right:58px}.algolia-autocomplete .algolia-docsearch-suggestion--content{width:100%!important;padding-left:0!important}.algolia-autocomplete .algolia-docsearch-suggestion--content:before,.algolia-autocomplete .algolia-docsearch-suggestion--subcategory-column{display:none!important}}.container{width:100%}@media (min-width:576px){.container{max-width:576px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:992px){.container{max-width:992px}}@media (min-width:1200px){.container{max-width:1200px}}.list-reset{list-style:none;padding:0}.appearance-none{appearance:none}.bg-black{background-color:#22292f}.bg-grey-lightest{background-color:#f8fafc}.bg-white{background-color:#fff}.bg-indigo-darkest{background-color:#253461}.bg-indigo-dark{background-color:#4764bd}.bg-indigo{background-color:#637fd6}.bg-indigo-light{background-color:#acbdf1}.bg-indigo-lightest{background-color:#f7f9fe}.border-transparent{border-color:transparent}.border-indigo-lighter{border-color:#d9dff1}.rounded{border-radius:.25rem}.rounded-t-none{border-top-left-radius:0;border-top-right-radius:0}.rounded-br{border-bottom-right-radius:.25rem}.border{border-width:1px}.border-b{border-bottom-width:1px}#carbonads>span,.block,.carbon-img img{display:block}.inline-block{display:inline-block}.table{display:table}.hidden{display:none}.flex{display:flex}.items-center{align-items:center}.flex-grow{flex-grow:1}.flex-no-grow{flex-grow:0}.flex-no-shrink{flex-shrink:0}.font-heading{font-family:Lato,sans-serif}.font-normal{font-weight:400}.h-4{height:1rem}.h-8{height:2rem}.h-10{height:2.5rem}.h-full{height:100%}.leading-normal{line-height:1.75}.leading-loose{line-height:2}.m-6{margin:1.5rem}.my-6{margin-top:1.5rem;margin-bottom:1.5rem}.mx-auto{margin-left:auto;margin-right:auto}.mt-0{margin-top:0}.mr-3{margin-right:.75rem}.mr-4{margin-right:1rem}.mb-4,p{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.max-w-xs{max-width:20rem}.max-w-sm{max-width:30rem}.max-w-2xl{max-width:66rem}.max-w-full{max-width:100%}.min-h-screen{min-height:100vh}.min-w-full{min-width:100%}.-ml-2{margin-left:-.5rem}.opacity-50{opacity:.5}.overflow-hidden{overflow:hidden}.p-1{padding:.25rem}.p-2{padding:.5rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.px-4{padding-left:1rem;padding-right:1rem}.pl-0{padding-left:0}.pt-1{padding-top:.25rem}.pb-1{padding-bottom:.25rem}.pt-2{padding-top:.5rem}.pr-2{padding-right:.5rem}.pl-2{padding-left:.5rem}.pr-6{padding-right:1.5rem}.pl-6{padding-left:1.5rem}.pl-8{padding-left:2rem}.pt-12{padding-top:4rem}.pointer-events-none{pointer-events:none}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.pin-y{top:0;bottom:0}.pin-t{top:0}.pin-l{left:0}.shadow-md{box-shadow:0 4px 8px 0 rgba(0,0,0,.12),0 2px 4px 0 rgba(0,0,0,.08)}.fill-current{fill:currentColor}.text-center{text-align:center}.hover\:text-grey:hover,.text-grey{color:#b8c2cc}.text-white{color:#fff}.text-indigo-darkest{color:#253461}.text-indigo-body-text{color:#535e7e}.text-indigo-darker{color:#2a3f7d}.text-indigo-dark{color:#4764bd}.text-indigo{color:#637fd6}.text-indigo-light{color:#acbdf1}.text-xs{font-size:.75rem}.text-base{font-size:1rem}.text-xl{font-size:1.25rem}.text-3xl{font-size:1.875rem}.uppercase{text-transform:uppercase}.tracking-wide{letter-spacing:.05em}.w-4{width:1rem}.w-8{width:2rem}.w-10{width:2.5rem}.w-1\/3{width:33.33333%}.w-1\/4{width:25%}.w-full{width:100%}.w-screen{width:100vw}.z-10{z-index:1}.z-50{z-index:2}:focus{outline:0}h1,h2,h3{font-family:Lato,sans-serif;line-height:1.25;color:#253461}.focus\:placeholder-none:focus::placeholder{opacity:0}article table{text-align:left;padding:1rem;background-color:#fff;box-shadow:0 4px 8px 0 rgba(0,0,0,.12),0 2px 4px 0 rgba(0,0,0,.08);margin-left:-1rem;margin-right:-1rem;border-spacing:0;border-collapse:collapse;margin-bottom:1.5rem;padding:0;width:calc(100% + 2rem);overflow:auto}@media (min-width:768px){article table{display:table;width:100%;margin-left:0;margin-right:0}}div.highlighter-rouge+table{margin-top:-1rem;border-top-width:4px;border-color:#4764bd}article table td{vertical-align:top;border-top-width:1px;border-color:#d9dff1;padding:.5rem 1rem}article table th{padding:.5rem 1rem;background-color:#637fd6;color:#fff;font-weight:700}div.highlighter-rouge+table th{color:#637fd6;background-color:#fff}.menu-closed .menu-closed\:shown{display:inline}.menu-closed .menu-closed\:hidden,.menu-closed\:shown{display:none}#carbonads{position:relative;text-shadow:1px 1px 0 hsla(0,0%,100%,.5);background:#fff;max-width:340px;line-height:1.75;font-size:.8rem;color:#3d4852;padding:.5rem;margin-bottom:1rem;background-color:#dae1e7;border-radius:.25rem;box-shadow:inset 0 2px 4px 0 rgba(0,0,0,.06);display:inline-block}.carbon-text{padding-left:.5rem;padding-bottom:1rem;line-height:1.75;color:#fff}#carbonads a{color:inherit}.carbon-wrap{display:flex;align-items:start}.carbon-img{flex-grow:0;flex-shrink:0}.carbon-poweredby{position:absolute;left:calc(130px + 1rem);bottom:0;opacity:.75;padding-bottom:.5rem}@media (min-width:576px){.sm\:block{display:block}.sm\:hidden{display:none}.sm\:m-8{margin:2rem}}@media (min-width:576px) and (max-width:768px){.sm-md\:block{display:block}}@media (min-width:768px){.md\:block{display:block}.md\:hidden{display:none}.md\:w-4\/14{width:28.57143%}.md\:w-10\/14{width:71.42857%}}@media (min-width:768px) and (max-width:992px){.md-lg\:block{display:block}}@media (min-width:992px){.lg\:relative{position:relative}}@media (min-width:992px) and (max-width:1200px){.lg-xl\:block{display:block}}@media (min-width:1200px){.xl\:block{display:block}}
1
+ @import url(https://fonts.googleapis.com/css?family=Lato:300,400,700|Open+Sans:400,400i,600);/*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;box-sizing:border-box;font-family:Open Sans,sans-serif;font-weight:400;-webkit-font-smoothing:antialiased}body{margin:0}article,footer,main,menu,nav,section{display:block}h1{font-size:2em}hr{box-sizing:content-box;height:0;overflow:visible;border-bottom-width:1px;border-top-width:1px;opacity:.75;width:50%;margin:3.5rem auto 2rem;border-color:#d9dff1 #d9dff1 #fff}code,pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects;text-decoration:none;color:#4764bd}strong{font-weight:bolder}small{font-size:80%}sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline;top:-.5em}img{border-style:solid;max-width:100%}svg:not(:root){overflow:hidden}input,select{font-size:100%;line-height:1.15;margin:0}input{overflow:visible}select{text-transform:none}[type=reset],[type=submit],html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring{outline:1px dotted ButtonText}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}[hidden]{display:none}*,:after,:before{box-sizing:inherit;border:0 solid #dae1e7}blockquote,h1,h2,h3,p,pre,ul{margin:0}[tabindex="-1"]:focus{outline:0!important}[type=button],[type=reset],[type=submit]{border-radius:0}input,select{font-family:inherit}input::placeholder{color:inherit;opacity:.5}[role=button]{cursor:pointer}div.highlighter-rouge{font-family:Courier,monospace;background-color:#fff;padding:.5rem 1rem;margin-left:-1rem;margin-right:-1rem;margin-bottom:1rem;box-shadow:0 2px 4px 0 rgba(0,0,0,.1);display:block}div.highlighter-rouge>div{overflow:auto;width:100%}@media (min-width:768px){div.highlighter-rouge{margin-left:0;margin-right:0}}code.highlighter-rouge{font-family:Courier,monospace;text-shadow:1px 1px 0 #fff,-1px 1px 0 #fff;font-size:1.125rem}@media (min-width:768px){.highlighter-rouge{margin-left:0;margin-right:0}}div.highlighter-rouge.language-bash{background-color:#4764bd;color:#fff;box-shadow:inset 0 4px 8px 0 rgba(0,0,0,.08),inset 0 2px 4px 0 rgba(0,0,0,.12);text-shadow:1px 1px 2px #253461,-1px 1px 2px #253461}.highlight .cp,.highlight .k,.highlight .o{font-weight:700}.highlight .cp{color:#999}.highlight .c1{color:#998;font-style:italic}.highlight .go{color:#888}.highlight .gt{color:#a00}.highlight .kc{font-weight:700}.highlight .s{color:#d14}.highlight .na{color:teal}.highlight .nb{color:#0086b3}.highlight .nc{color:#458;font-weight:700}.highlight .no{color:teal}.highlight .nf{color:#900;font-weight:700}.highlight .nv{color:teal}.highlight .w{color:#bbb}.highlight .mi,.highlight .mo{color:#099}.highlight .s1,.highlight .s2,.highlight .sd,.highlight .si{color:#d14}.algolia-autocomplete{width:100%!important}@media (max-width:768px){.algolia-autocomplete.algolia-autocomplete-right .ds-dropdown-menu{max-width:calc(100vw - 2rem)!important;width:calc(100vw - 2rem)!important;min-width:0!important;margin-left:16px!important;right:-3rem!important}.algolia-autocomplete.algolia-autocomplete-right .ds-dropdown-menu:before{right:58px}.algolia-autocomplete .algolia-docsearch-suggestion--content{width:100%!important;padding-left:0!important}.algolia-autocomplete .algolia-docsearch-suggestion--content:before,.algolia-autocomplete .algolia-docsearch-suggestion--subcategory-column{display:none!important}}.container{width:100%}@media (min-width:576px){.container{max-width:576px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:992px){.container{max-width:992px}}@media (min-width:1200px){.container{max-width:1200px}}.list-reset{list-style:none;padding:0}.appearance-none{appearance:none}.bg-black{background-color:#22292f}.bg-grey-lightest{background-color:#f8fafc}.bg-white{background-color:#fff}.bg-indigo-darkest{background-color:#253461}.bg-indigo-dark{background-color:#4764bd}.bg-indigo{background-color:#637fd6}.bg-indigo-light{background-color:#acbdf1}.bg-indigo-lightest{background-color:#f7f9fe}.border-transparent{border-color:transparent}.border-indigo-lighter{border-color:#d9dff1}.rounded{border-radius:.25rem}.rounded-t-none{border-top-left-radius:0;border-top-right-radius:0}.rounded-br{border-bottom-right-radius:.25rem}.border{border-width:1px}.border-b{border-bottom-width:1px}#carbonads>span,.block,.carbon-img img{display:block}.inline-block{display:inline-block}.table{display:table}.hidden{display:none}.flex{display:flex}.items-center{align-items:center}.flex-grow{flex-grow:1}.flex-no-grow{flex-grow:0}.flex-no-shrink{flex-shrink:0}.font-heading{font-family:Lato,sans-serif}.font-normal{font-weight:400}.h-4{height:1rem}.h-8{height:2rem}.h-10{height:2.5rem}.h-full{height:100%}.leading-normal{line-height:1.75}.leading-loose{line-height:2}.m-6{margin:1.5rem}.my-6{margin-top:1.5rem;margin-bottom:1.5rem}.mx-auto{margin-left:auto;margin-right:auto}.mt-0{margin-top:0}.mr-3{margin-right:.75rem}.mr-4{margin-right:1rem}.mb-4,p,ul{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.max-w-xs{max-width:20rem}.max-w-sm{max-width:30rem}.max-w-2xl{max-width:66rem}.max-w-full{max-width:100%}.min-h-screen{min-height:100vh}.min-w-full{min-width:100%}.-ml-2{margin-left:-.5rem}.opacity-50{opacity:.5}.overflow-hidden{overflow:hidden}.p-1{padding:.25rem}.p-2{padding:.5rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.px-4{padding-left:1rem;padding-right:1rem}.pl-0{padding-left:0}.pt-1{padding-top:.25rem}.pb-1{padding-bottom:.25rem}.pt-2{padding-top:.5rem}.pr-2{padding-right:.5rem}.pl-2{padding-left:.5rem}.pt-4{padding-top:1rem}.pr-6{padding-right:1.5rem}.pl-6{padding-left:1.5rem}.pl-8{padding-left:2rem}.pt-12{padding-top:4rem}.pointer-events-none{pointer-events:none}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.pin-y{top:0;bottom:0}.pin-t{top:0}.pin-l{left:0}.shadow-md{box-shadow:0 4px 8px 0 rgba(0,0,0,.12),0 2px 4px 0 rgba(0,0,0,.08)}.fill-current{fill:currentColor}.text-center{text-align:center}.hover\:text-grey:hover,.text-grey{color:#b8c2cc}.text-white{color:#fff}.text-indigo-darkest{color:#253461}.text-indigo-body-text{color:#535e7e}.text-indigo-darker{color:#2a3f7d}.text-indigo-dark{color:#4764bd}.text-indigo{color:#637fd6}.text-indigo-light{color:#acbdf1}.text-xs{font-size:.75rem}.text-base{font-size:1rem}.text-lg{font-size:1.125rem}.text-xl{font-size:1.25rem}.text-3xl{font-size:1.875rem}.uppercase{text-transform:uppercase}.tracking-wide{letter-spacing:.05em}.w-4{width:1rem}.w-8{width:2rem}.w-10{width:2.5rem}.w-1\/3{width:33.33333%}.w-1\/4{width:25%}.w-full{width:100%}.w-screen{width:100vw}.z-10{z-index:1}.z-50{z-index:2}:focus{outline:0}h1,h2,h3{font-family:Lato,sans-serif;line-height:1.25;color:#253461}.focus\:placeholder-none:focus::placeholder{opacity:0}article table{text-align:left;padding:1rem;background-color:#fff;box-shadow:0 4px 8px 0 rgba(0,0,0,.12),0 2px 4px 0 rgba(0,0,0,.08);margin-left:-1rem;margin-right:-1rem;border-spacing:0;border-collapse:collapse;margin-bottom:1.5rem;padding:0;width:calc(100% + 2rem);overflow:auto}@media (min-width:768px){article table{display:table;width:100%;margin-left:0;margin-right:0}}div.highlighter-rouge+table{margin-top:-1rem;border-top-width:4px;border-color:#4764bd}article table td{vertical-align:top;border-top-width:1px;border-color:#d9dff1;padding:.5rem 1rem}article table th{padding:.5rem 1rem;background-color:#637fd6;color:#fff;font-weight:700}div.highlighter-rouge+table th{color:#637fd6;background-color:#fff}.menu-closed .menu-closed\:shown{display:inline}.menu-closed .menu-closed\:hidden,.menu-closed\:shown{display:none}#carbonads{position:relative;text-shadow:1px 1px 0 hsla(0,0%,100%,.5);background:#fff;max-width:340px;line-height:1.75;font-size:.8rem;color:#3d4852;padding:.5rem;margin-bottom:1rem;background-color:#dae1e7;border-radius:.25rem;box-shadow:inset 0 2px 4px 0 rgba(0,0,0,.06);display:inline-block}.carbon-text{padding-left:.5rem;padding-bottom:1rem;line-height:1.75;color:#fff}#carbonads a{color:inherit}.carbon-wrap{display:flex;align-items:start}.carbon-img{flex-grow:0;flex-shrink:0}.carbon-poweredby{position:absolute;left:calc(130px + 1rem);bottom:0;opacity:.75;padding-bottom:.5rem}@media (max-width:576px){.-sm\:hidden{display:none}}@media (min-width:576px){.sm\:block{display:block}.sm\:hidden{display:none}.sm\:m-8{margin:2rem}}@media (min-width:576px) and (max-width:768px){.sm-md\:block{display:block}}@media (min-width:768px){.md\:block{display:block}.md\:hidden{display:none}.md\:w-4\/14{width:28.57143%}.md\:w-10\/14{width:71.42857%}}@media (min-width:768px) and (max-width:992px){.md-lg\:block{display:block}}@media (min-width:992px){.lg\:relative{position:relative}}@media (min-width:992px) and (max-width:1200px){.lg-xl\:block{display:block}}@media (min-width:1200px){.xl\:block{display:block}}
vendor/league/flysystem/docs/github.css CHANGED
@@ -9,7 +9,7 @@ div.highlighter-rouge {
9
  }
10
 
11
  div.highlighter-rouge > div {
12
- @apply overflow-x-scroll w-full;
13
  }
14
 
15
  @screen md {
@@ -96,4 +96,4 @@ div.highlighter-rouge.language-bash {
96
  .highlight .vg { color: teal; }
97
  .highlight .vi { color: teal; }
98
  .highlight .il { color: #009999; }
99
- .highlight .gc { color: #999; background-color: #EAF2F5; }
9
  }
10
 
11
  div.highlighter-rouge > div {
12
+ @apply overflow-auto w-full;
13
  }
14
 
15
  @screen md {
96
  .highlight .vg { color: teal; }
97
  .highlight .vi { color: teal; }
98
  .highlight .il { color: #009999; }
99
+ .highlight .gc { color: #999; background-color: #EAF2F5; }
vendor/league/flysystem/docs/guides/deterministic-programming.md CHANGED
@@ -12,7 +12,7 @@ problematic.
12
 
13
  ## Filesystems are slow.
14
 
15
- In general, filesystem interaction is slow. Every operation operation that
16
  hits the disc in one way or another is slow. While some operations absolutely
17
  require filesystem interaction, there's a number of cases where filesystem
18
  operations can be prevented in order to eliminate the associated penalties.
@@ -66,6 +66,6 @@ you can store all the paths in a persistent database. While this is
66
  not a conventional thing to do it certainly has a lot of benefits.
67
 
68
  File listings are just a select statement: `SELECT * FROM files WHERE path LIKE '/prefix/%'`.
69
- Listings can easily be sorted. File existence checks are in expensive.
70
  File migrations become really easy, even when your path generation
71
- strategy changes. Metadata can be stores alongside your path.
12
 
13
  ## Filesystems are slow.
14
 
15
+ In general, filesystem interaction is slow. Every operation that
16
  hits the disc in one way or another is slow. While some operations absolutely
17
  require filesystem interaction, there's a number of cases where filesystem
18
  operations can be prevented in order to eliminate the associated penalties.
66
  not a conventional thing to do it certainly has a lot of benefits.
67
 
68
  File listings are just a select statement: `SELECT * FROM files WHERE path LIKE '/prefix/%'`.
69
+ Listings can easily be sorted. File existence checks are inexpensive.
70
  File migrations become really easy, even when your path generation
71
+ strategy changes. Metadata can be stored alongside your path.
vendor/league/flysystem/docs/img/azure.svg CHANGED
@@ -1 +1,69 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="100%" height="100%"><polygon fill="#00a1f1" points="3.65 14.2 16 14.2 9.35 2.68 7.33 8.24 11.21 12.87 3.65 14.2"></polygon> <polygon fill="#00a1f1" points="8.82 1.8 4.07 5.79 0 12.84 3.67 12.84 3.67 12.85 8.82 1.8"></polygon> </svg>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <!-- Generator: Adobe Illustrator 22.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
3
+ <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
4
+ viewBox="0 0 283.5 283.5" style="enable-background:new 0 0 283.5 283.5;" xml:space="preserve">
5
+ <style type="text/css">
6
+ .st0{fill:#737373;}
7
+ .st1{fill:#F25022;}
8
+ .st2{fill:#7FBA00;}
9
+ .st3{fill:#00A4EF;}
10
+ .st4{fill:#FFB900;}
11
+ </style>
12
+ <g id="Azure_s">
13
+ <g>
14
+ <path class="st0" d="M118.8,147.7l11.4,30.3h-5.8l-2.7-7.5h-11.9l-2.6,7.5h-5.8l11.4-30.3H118.8z M115.6,153.3l-4.5,12.8h9.1
15
+ L115.6,153.3L115.6,153.3z"/>
16
+ <path class="st0" d="M132.7,156.3h17.4v2.1L138.7,174h11.5v4.1H132v-2.4l11.2-15.2h-10.4v-4.2L132.7,156.3L132.7,156.3z"/>
17
+ <path class="st0" d="M171.9,156.3V178h-5.2v-2.9h-0.1c-0.7,1-1.6,1.8-2.7,2.3c-1.1,0.6-2.4,0.8-3.8,0.8c-2.5,0-4.4-0.7-5.8-2.1
18
+ c-1.3-1.4-2-3.7-2-6.7v-13.2h5.2v12.6c0,1.8,0.4,3.2,1.1,4.1c0.7,0.9,1.8,1.4,3.3,1.4s2.6-0.5,3.5-1.5s1.3-2.4,1.3-4v-12.6
19
+ L171.9,156.3L171.9,156.3z"/>
20
+ <path class="st0" d="M187.3,155.9c0.4,0,0.8,0,1.1,0.1s0.6,0.1,0.8,0.2v5.2c-0.3-0.2-0.7-0.4-1.2-0.6c-0.5-0.2-1.1-0.3-1.9-0.3
21
+ c-1.3,0-2.3,0.5-3.2,1.6s-1.3,2.7-1.3,4.9v11h-5.1v-21.7h5.1v3.4h0.1c0.5-1.2,1.2-2.1,2.1-2.8C184.9,156.3,186,155.9,187.3,155.9z
22
+ "/>
23
+ <path class="st0" d="M207.7,172.5v4.2c-0.8,0.5-2,1-3.3,1.3c-1.4,0.3-2.8,0.5-4.4,0.5c-3.3,0-5.9-1-7.7-2.9s-2.8-4.7-2.8-8.2
24
+ c0-3.4,1-6.1,2.9-8.3s4.5-3.3,7.5-3.3s5.3,0.9,7,2.8c1.7,1.8,2.5,4.4,2.5,7.6v2.5h-14.9c0.2,2.2,0.9,3.7,2.1,4.6
25
+ c1.2,0.9,2.7,1.3,4.6,1.3c1.2,0,2.4-0.2,3.5-0.6C205.8,173.6,206.8,173.1,207.7,172.5z M204.4,164.9c0-1.7-0.4-3-1.2-3.9
26
+ s-1.9-1.3-3.3-1.3c-1.2,0-2.3,0.4-3.3,1.3s-1.6,2.2-1.9,3.9H204.4z"/>
27
+ </g>
28
+ </g>
29
+ <g id="MS-logotype">
30
+ <path class="st0" d="M136,106v30.3h-5.3v-23.8h-0.1l-9.4,23.8h-3.5l-9.6-23.8H108v23.8h-4.9V106h7.5l8.7,22.5h0.1l9.2-22.5H136z
31
+ M140.4,108.3c0-0.8,0.3-1.6,0.9-2.1c0.6-0.6,1.3-0.9,2.2-0.9s1.6,0.3,2.2,0.9c0.6,0.6,0.9,1.3,0.9,2.1c0,0.8-0.3,1.5-0.9,2.1
32
+ c-0.6,0.6-1.3,0.8-2.2,0.8s-1.6-0.3-2.2-0.9C140.7,109.8,140.4,109.1,140.4,108.3z M146.1,114.6v21.7H141v-21.7
33
+ C141,114.6,146.1,114.6,146.1,114.6z M161.6,132.6c0.8,0,1.6-0.2,2.5-0.5c0.9-0.4,1.8-0.8,2.5-1.4v4.8c-0.8,0.5-1.7,0.8-2.8,1.1
34
+ c-1,0.2-2.2,0.4-3.4,0.4c-3.2,0-5.8-1-7.8-3s-3-4.6-3-7.7c0-3.5,1-6.4,3.1-8.6c2-2.3,4.9-3.4,8.7-3.4c1,0,1.9,0.1,2.9,0.4
35
+ c1,0.2,1.8,0.5,2.3,0.9v4.9c-0.8-0.6-1.6-1-2.4-1.3c-0.8-0.3-1.7-0.5-2.5-0.5c-2,0-3.6,0.7-4.9,2c-1.2,1.3-1.9,3.1-1.9,5.3
36
+ s0.6,3.9,1.8,5.1C157.9,132,159.6,132.6,161.6,132.6z M181.2,114.2c0.4,0,0.8,0,1.1,0.1s0.6,0.1,0.8,0.2v5.2
37
+ c-0.3-0.2-0.7-0.4-1.2-0.6s-1.1-0.3-1.9-0.3c-1.3,0-2.3,0.5-3.2,1.6s-1.3,2.7-1.3,4.9v11h-5.1v-21.7h5.1v3.4h0.1
38
+ c0.5-1.2,1.2-2.1,2.1-2.8C178.8,114.6,179.9,114.2,181.2,114.2z M183.4,125.8c0-3.6,1-6.4,3-8.5s4.8-3.2,8.5-3.2c3.4,0,6.1,1,8,3
39
+ s2.9,4.8,2.9,8.2c0,3.5-1,6.3-3,8.4c-2,2.1-4.8,3.1-8.3,3.1c-3.4,0-6-1-8-3C184.4,131.9,183.4,129.2,183.4,125.8z M188.8,125.6
40
+ c0,2.3,0.5,4,1.5,5.2s2.5,1.8,4.4,1.8s3.3-0.6,4.2-1.8c1-1.2,1.5-3,1.5-5.3s-0.5-4.1-1.5-5.3c-1-1.2-2.4-1.8-4.2-1.8
41
+ c-1.9,0-3.3,0.6-4.4,1.9C189.3,121.5,188.8,123.3,188.8,125.6z M213.4,120.3c0,0.7,0.2,1.3,0.7,1.7c0.5,0.4,1.5,0.9,3.1,1.6
42
+ c2,0.8,3.5,1.7,4.3,2.8c0.8,1,1.2,2.3,1.2,3.7c0,2-0.8,3.7-2.4,4.9c-1.6,1.2-3.7,1.9-6.4,1.9c-0.9,0-1.9-0.1-3-0.3s-2-0.5-2.8-0.8
43
+ v-5c0.9,0.6,1.9,1.2,3,1.5c1.1,0.4,2,0.6,2.9,0.6c1.2,0,2-0.2,2.6-0.5s0.8-0.9,0.8-1.6c0-0.7-0.3-1.3-0.9-1.8s-1.7-1-3.2-1.7
44
+ c-1.9-0.8-3.2-1.7-4-2.7s-1.2-2.2-1.2-3.8c0-2,0.8-3.6,2.3-4.8c1.6-1.3,3.6-1.9,6.1-1.9c0.8,0,1.6,0.1,2.6,0.3
45
+ c0.9,0.2,1.7,0.4,2.4,0.7v4.9c-0.7-0.5-1.5-0.8-2.4-1.2c-0.9-0.3-1.8-0.5-2.7-0.5c-1,0-1.7,0.2-2.3,0.6
46
+ C213.6,119.1,213.4,119.6,213.4,120.3z M224.9,125.8c0-3.6,1-6.4,3-8.5s4.8-3.2,8.5-3.2c3.4,0,6.1,1,8,3s2.9,4.8,2.9,8.2
47
+ c0,3.5-1,6.3-3,8.4c-2,2.1-4.8,3.1-8.3,3.1c-3.4,0-6-1-8-3C225.9,131.9,224.9,129.2,224.9,125.8z M230.2,125.6c0,2.3,0.5,4,1.5,5.2
48
+ s2.5,1.8,4.4,1.8s3.3-0.6,4.2-1.8c1-1.2,1.5-3,1.5-5.3s-0.5-4.1-1.5-5.3c-1-1.2-2.4-1.8-4.2-1.8c-1.9,0-3.3,0.6-4.4,1.9
49
+ C230.7,121.5,230.2,123.3,230.2,125.6z M264.2,118.8h-7.6v17.5h-5.2v-17.5h-3.6v-4.2h3.6v-3c0-2.3,0.7-4.2,2.2-5.6
50
+ c1.5-1.5,3.4-2.2,5.7-2.2c0.6,0,1.2,0,1.6,0.1c0.5,0.1,0.9,0.2,1.3,0.3v4.4c-0.2-0.1-0.5-0.2-0.9-0.4c-0.4-0.1-0.9-0.2-1.5-0.2
51
+ c-1.1,0-1.9,0.3-2.5,1s-0.9,1.7-0.9,3v2.6h7.6v-4.9l5.1-1.6v6.4h5.2v4.2h-5.2V129c0,1.3,0.2,2.3,0.7,2.8s1.3,0.8,2.3,0.8
52
+ c0.3,0,0.7-0.1,1.1-0.2c0.4-0.1,0.8-0.3,1.1-0.5v4.2c-0.3,0.2-0.9,0.4-1.6,0.5s-1.5,0.2-2.2,0.2c-2.2,0-3.8-0.6-4.9-1.7
53
+ c-1.1-1.1-1.6-2.9-1.6-5.2v-11.1C264,118.8,264.2,118.8,264.2,118.8z"/>
54
+ </g>
55
+ <g id="MS-symbol">
56
+ <g>
57
+ <rect x="9.6" y="106" class="st1" width="34.2" height="34.2"/>
58
+ <rect x="47.4" y="106" class="st2" width="34.2" height="34.2"/>
59
+ <rect x="9.6" y="143.8" class="st3" width="34.2" height="34.2"/>
60
+ <rect x="47.4" y="143.8" class="st4" width="34.2" height="34.2"/>
61
+ </g>
62
+ <g>
63
+ <rect x="9.6" y="106" class="st1" width="34.2" height="34.2"/>
64
+ <rect x="47.4" y="106" class="st2" width="34.2" height="34.2"/>
65
+ <rect x="9.6" y="143.8" class="st3" width="34.2" height="34.2"/>
66
+ <rect x="47.4" y="143.8" class="st4" width="34.2" height="34.2"/>
67
+ </g>
68
+ </g>
69
+ </svg>
vendor/league/flysystem/docs/index.css CHANGED
@@ -32,7 +32,7 @@ h1, h2, h3, h4, h5 {
32
  opacity: 0;
33
  }
34
 
35
- p {
36
  @apply mb-4;
37
  }
38
 
32
  opacity: 0;
33
  }
34
 
35
+ p, ul {
36
  @apply mb-4;
37
  }
38
 
vendor/league/flysystem/docs/index.md CHANGED
@@ -30,11 +30,24 @@ of your code.
30
  <a target="_blank" href="https://laravel.com" class="flex-no-grow w-1/3 bg-white rounded shadow-md mr-4 overflow-hidden">
31
  <img src="/img/laravel.svg" class="w-full" alt="Laravel.com"/>
32
  </a>
33
- <!--
34
- <a target="_blank" href="https://azure.microsoft.com/" class="flex-no-grow w-1/3 bg-white rounded shadow-md mr-4 overflow-hidden">
35
  <img src="/img/azure.svg" class="max-w-full m-6" alt="Microsoft Azure"/>
36
  </a>
37
- -->
38
  </div>
39
 
40
- View all the <a href="/docs/sponsors/">sponsors</a>.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  <a target="_blank" href="https://laravel.com" class="flex-no-grow w-1/3 bg-white rounded shadow-md mr-4 overflow-hidden">
31
  <img src="/img/laravel.svg" class="w-full" alt="Laravel.com"/>
32
  </a>
33
+ <a target="_blank" href="https://azure.microsoft.com/free/?utm_source=flysystem&utm_medium=banner&utm_campaign=flysystem_sponsorship" class="flex-no-grow w-1/3 bg-white rounded shadow-md mr-4 overflow-hidden">
 
34
  <img src="/img/azure.svg" class="max-w-full m-6" alt="Microsoft Azure"/>
35
  </a>
 
36
  </div>
37
 
38
+ View all the <a href="/docs/sponsors/">sponsors</a>.
39
+
40
+ ## Getting Started
41
+
42
+ * **[Architecture](/docs/architecture/)**: Flysystem's internal architecture
43
+ * **[Setup/Bootstrap](/docs/usage/setup/)**: Load Flysystem and set up your first adapter
44
+ * **[Flysystem API](/docs/usage/filesystem-api/)**: How to interact with your Flysystem instance
45
+
46
+ ### Commonly-Used Adapters
47
+
48
+ * **[AWS S3](/docs/adapter/aws-s3/)**
49
+ * **[Azure](/docs/adapter/azure/)**
50
+ * **[Digital Ocean Spaces](/docs/adapter/digitalocean-spaces/)**
51
+ * **[Local](/docs/adapter/local/)**
52
+ * **[Memory](/docs/adapter/memory/)**
53
+ * **[Creating An Adapter](/docs/advanced/creating-an-adapter/)**
vendor/league/flysystem/docs/sponsors.md CHANGED
@@ -16,10 +16,10 @@ In order to free up time to keep everything up-to-date financial help is greatly
16
  <img src="/img/laravel.svg" class="w-full" alt="Laravel.com"/>
17
  <span style="background-color: #FB503B" class="text-center text-xl hidden sm:block py-4 bg-indigo-dark text-white bg-grey-lightest">Laravel.com</span>
18
  </a>
19
- <!--<a target="_blank" href="https://azure.microsoft.com/" class="flex-no-grow w-1/3 bg-white rounded shadow-md mr-4 overflow-hidden">
20
- <img src="/img/azure.svg" class="max-w-full m-6 sm:m-8" alt="Microsoft Azure"/>
21
- <span style="background-color: #00a1f1;" class="text-center text-xl hidden sm:block py-4 bg-indigo-dark text-white bg-grey-lightest">Microsoft Azure</span>
22
- </a>-->
23
  <a target="_blank" href="https://patreon.com/frankdejonge" class="flex-no-grow w-1/3 bg-white rounded shadow-md mr-4 overflow-hidden">
24
  <img src="/img/question.svg" class="max-w-full m-6 sm:m-8 opacity-50" alt="Become a sponsor"/>
25
  <span class="text-center text-xl hidden sm:block py-4 bg-indigo-light text-white bg-grey-lightest">Your company?</span>
@@ -37,8 +37,14 @@ In order to free up time to keep everything up-to-date financial help is greatly
37
 
38
  ## Bronze Sponsors
39
 
40
- <div class="flex my-6">
41
- <a target="_blank" href="https://patreon.com/frankdejonge" class="flex-no-grow w-1/4 bg-white rounded shadow-md mr-4 overflow-hidden">
42
- <img src="/img/question.svg" class="max-w-full m-6 opacity-50" alt="Become a sponsor"/>
43
- </a>
44
- </div>
 
 
 
 
 
 
16
  <img src="/img/laravel.svg" class="w-full" alt="Laravel.com"/>
17
  <span style="background-color: #FB503B" class="text-center text-xl hidden sm:block py-4 bg-indigo-dark text-white bg-grey-lightest">Laravel.com</span>
18
  </a>
19
+ <a target="_blank" href="https://azure.microsoft.com/free/?utm_source=flysystem&utm_medium=banner&utm_campaign=flysystem_sponsorship" class="flex-no-grow w-1/3 bg-white rounded shadow-md mr-4 overflow-hidden">
20
+ <img src="/img/azure.svg" class="max-w-full m-6 sm:m-8" alt="Azure.com"/>
21
+ <span style="background-color: #00a1f1;" class="text-center text-xl hidden sm:block py-4 bg-indigo-dark text-white bg-grey-lightest">Azure.com</span>
22
+ </a>
23
  <a target="_blank" href="https://patreon.com/frankdejonge" class="flex-no-grow w-1/3 bg-white rounded shadow-md mr-4 overflow-hidden">
24
  <img src="/img/question.svg" class="max-w-full m-6 sm:m-8 opacity-50" alt="Become a sponsor"/>
25
  <span class="text-center text-xl hidden sm:block py-4 bg-indigo-light text-white bg-grey-lightest">Your company?</span>
37
 
38
  ## Bronze Sponsors
39
 
40
+ <ul class="pt-4 text-lg">
41
+ <li><a target="_blank" href="http://isset.nl/">Isset Internet Professionals</a></li>
42
+ <li><a target="_blank" href="https://jwe.nl/">Jan-Willem Eshuis</a></li>
43
+ </ul>
44
+
45
+ ### Become a Sponsor
46
+
47
+ If you and your company believe that open source software is valuable and requires
48
+ financial sustainability, consider supporting:
49
+
50
+ <a href="https://www.patreon.com/bePatron?u=8623643"><img src="/img/become_a_patron_button.png" alt="Become a Patron!" title="Become a Patron!"/></a>
vendor/league/flysystem/docs/tailwind.js CHANGED
@@ -170,6 +170,7 @@ module.exports = {
170
  */
171
 
172
  screens: {
 
173
  'sm': '576px',
174
  '-md': {'max': '768px'},
175
  'sm-md': {'min': '576px', 'max': '768px'},
170
  */
171
 
172
  screens: {
173
+ '-sm': {'max': '576px'},
174
  'sm': '576px',
175
  '-md': {'max': '768px'},
176
  'sm-md': {'min': '576px', 'max': '768px'},
vendor/league/flysystem/docs/usage/filesystem-api.md CHANGED
@@ -23,6 +23,20 @@ param | description | type
23
 
24
  ---
25
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
  ## Update Files
27
 
28
  ```php
@@ -37,6 +51,20 @@ param | description | type
37
 
38
  ---
39
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  ## Write or Update Files
41
 
42
  ```php
@@ -51,6 +79,20 @@ param | description | type
51
 
52
  ---
53
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  ## Read Files
55
 
56
  ```php
@@ -64,16 +106,29 @@ param | description | type
64
 
65
  ---
66
 
67
- ## Check if a file exists
68
 
69
  ```php
70
- $exists = $filesystem->has($path);
71
  ```
72
 
73
  param | description | type
74
  ------------- | ------------------------ | -----------
75
  `$path` | location of a file | `string`
76
- `$exists` | wether the file exists | `bool`
 
 
 
 
 
 
 
 
 
 
 
 
 
77
 
78
  > This only has consistent behaviour for files, not directories. Directories
79
  > are less important in Flysystem, they're created implicitly and often ignored because
@@ -150,7 +205,7 @@ param | description | type
150
 
151
  ## Get Timestamps
152
 
153
- This function the last updated timestamp.
154
 
155
  ```php
156
  $response = $filesystem->getTimestamp($path);
23
 
24
  ---
25
 
26
+ ## Write Files using a stream
27
+
28
+ ```php
29
+ $response = $filesystem->writeStream($path, $resource);
30
+ ```
31
+
32
+ param | description | type
33
+ ------------- | ------------------------ | -----------
34
+ `$path` | location of a file | `string`
35
+ `$resource` | file stream | `resource`
36
+ `$response` | success boolean | `bool`
37
+
38
+ ---
39
+
40
  ## Update Files
41
 
42
  ```php
51
 
52
  ---
53
 
54
+ ## Update Files using a stream
55
+
56
+ ```php
57
+ $response = $filesystem->updateStream($path, $contents);
58
+ ```
59
+
60
+ param | description | type
61
+ ------------- | ------------------------ | -----------
62
+ `$path` | location of a file | `string`
63
+ `$resource` | file stream | `resource`
64
+ `$response` | success boolean | `bool`
65
+
66
+ ---
67
+
68
  ## Write or Update Files
69
 
70
  ```php
79
 
80
  ---
81
 
82
+ ## Write or Update Files using a stream
83
+
84
+ ```php
85
+ $response = $filesystem->putStream($path, $resource);
86
+ ```
87
+
88
+ param | description | type
89
+ ------------- | ------------------------ | -----------
90
+ `$path` | location of a file | `string`
91
+ `$resource` | file stream | `resource`
92
+ `$response` | success boolean | `bool`
93
+
94
+ ---
95
+
96
  ## Read Files
97
 
98
  ```php
106
 
107
  ---
108
 
109
+ ## Read Files as a stream
110
 
111
  ```php
112
+ $contents = $filesystem->readStream($path);
113
  ```
114
 
115
  param | description | type
116
  ------------- | ------------------------ | -----------
117
  `$path` | location of a file | `string`
118
+ `$resource` | file stream | `string`
119
+
120
+ ---
121
+
122
+ ## Check if a file exists
123
+
124
+ ```php
125
+ $exists = $filesystem->has($path);
126
+ ```
127
+
128
+ param | description | type
129
+ ------------- | ------------------------- | -----------
130
+ `$path` | location of a file | `string`
131
+ `$exists` | whether the file exists | `bool`
132
 
133
  > This only has consistent behaviour for files, not directories. Directories
134
  > are less important in Flysystem, they're created implicitly and often ignored because
205
 
206
  ## Get Timestamps
207
 
208
+ This function returns the last updated timestamp.
209
 
210
  ```php
211
  $response = $filesystem->getTimestamp($path);
vendor/league/flysystem/src/Adapter/AbstractFtpAdapter.php CHANGED
@@ -71,11 +71,6 @@ abstract class AbstractFtpAdapter extends AbstractAdapter
71
  */
72
  protected $systemType;
73
 
74
- /**
75
- * @var bool
76
- */
77
- protected $alternativeRecursion = false;
78
-
79
  /**
80
  * @var SafeStorage
81
  */
71
  */
72
  protected $systemType;
73
 
 
 
 
 
 
74
  /**
75
  * @var SafeStorage
76
  */
vendor/league/flysystem/src/Adapter/Local.php CHANGED
@@ -33,13 +33,13 @@ class Local extends AbstractAdapter
33
  */
34
  protected static $permissions = [
35
  'file' => [
36
- 'public' => 0644,
37
  'private' => 0600,
38
  ],
39
- 'dir' => [
40
- 'public' => 0755,
41
  'private' => 0700,
42
- ]
43
  ];
44
 
45
  /**
@@ -56,6 +56,7 @@ class Local extends AbstractAdapter
56
  * @var int
57
  */
58
  protected $writeFlags;
 
59
  /**
60
  * @var int
61
  */
@@ -99,11 +100,16 @@ class Local extends AbstractAdapter
99
  {
100
  if ( ! is_dir($root)) {
101
  $umask = umask(0);
102
- @mkdir($root, $this->permissionMap['dir']['public'], true);
 
 
 
 
103
  umask($umask);
104
 
105
  if ( ! is_dir($root)) {
106
- throw new Exception(sprintf('Impossible to create the root directory "%s".', $root));
 
107
  }
108
  }
109
  }
@@ -150,18 +156,11 @@ class Local extends AbstractAdapter
150
  $this->ensureDirectory(dirname($location));
151
  $stream = fopen($location, 'w+b');
152
 
153
- if ( ! $stream) {
154
- return false;
155
- }
156
-
157
- stream_copy_to_stream($resource, $stream);
158
-
159
- if ( ! fclose($stream)) {
160
  return false;
161
  }
162
 
163
  $type = 'file';
164
-
165
  $result = compact('type', 'path');
166
 
167
  if ($visibility = $config->get('visibility')) {
@@ -261,7 +260,7 @@ class Local extends AbstractAdapter
261
  {
262
  $location = $this->applyPathPrefix($path);
263
 
264
- return unlink($location);
265
  }
266
 
267
  /**
33
  */
34
  protected static $permissions = [
35
  'file' => [
36
+ 'public' => 0644,
37
  'private' => 0600,
38
  ],
39
+ 'dir' => [
40
+ 'public' => 0755,
41
  'private' => 0700,
42
+ ],
43
  ];
44
 
45
  /**
56
  * @var int
57
  */
58
  protected $writeFlags;
59
+
60
  /**
61
  * @var int
62
  */
100
  {
101
  if ( ! is_dir($root)) {
102
  $umask = umask(0);
103
+
104
+ if ( ! @mkdir($root, $this->permissionMap['dir']['public'], true)) {
105
+ $mkdirError = error_get_last();
106
+ }
107
+
108
  umask($umask);
109
 
110
  if ( ! is_dir($root)) {
111
+ $errorMessage = isset($mkdirError['message']) ? $mkdirError['message'] : '';
112
+ throw new Exception(sprintf('Impossible to create the root directory "%s". %s', $root, $errorMessage));
113
  }
114
  }
115
  }
156
  $this->ensureDirectory(dirname($location));
157
  $stream = fopen($location, 'w+b');
158
 
159
+ if ( ! $stream || stream_copy_to_stream($resource, $stream) === false || ! fclose($stream)) {
 
 
 
 
 
 
160
  return false;
161
  }
162
 
163
  $type = 'file';
 
164
  $result = compact('type', 'path');
165
 
166
  if ($visibility = $config->get('visibility')) {
260
  {
261
  $location = $this->applyPathPrefix($path);
262
 
263
+ return @unlink($location);
264
  }
265
 
266
  /**
vendor/league/flysystem/src/MountManager.php CHANGED
@@ -3,7 +3,6 @@
3
  namespace League\Flysystem;
4
 
5
  use InvalidArgumentException;
6
- use League\Flysystem\FilesystemNotFoundException;
7
  use League\Flysystem\Plugin\PluggableTrait;
8
  use League\Flysystem\Plugin\PluginNotFoundException;
9
 
@@ -14,36 +13,15 @@ use League\Flysystem\Plugin\PluginNotFoundException;
14
  *
15
  * @method AdapterInterface getAdapter($prefix)
16
  * @method Config getConfig($prefix)
17
- * @method bool has($path)
18
- * @method bool write($path, $contents, array $config = [])
19
- * @method bool writeStream($path, $resource, array $config = [])
20
- * @method bool put($path, $contents, $config = [])
21
- * @method bool putStream($path, $contents, $config = [])
22
- * @method string readAndDelete($path)
23
- * @method bool update($path, $contents, $config = [])
24
- * @method bool updateStream($path, $resource, $config = [])
25
- * @method string|false read($path)
26
- * @method resource|false readStream($path)
27
- * @method bool rename($path, $newpath)
28
- * @method bool delete($path)
29
- * @method bool deleteDir($dirname)
30
- * @method bool createDir($dirname, $config = [])
31
  * @method array listFiles($directory = '', $recursive = false)
32
  * @method array listPaths($directory = '', $recursive = false)
33
  * @method array getWithMetadata($path, array $metadata)
34
- * @method string|false getMimetype($path)
35
- * @method int|false getTimestamp($path)
36
- * @method string|false getVisibility($path)
37
- * @method int|false getSize($path);
38
- * @method bool setVisibility($path, $visibility)
39
- * @method array|false getMetadata($path)
40
- * @method Handler get($path, Handler $handler = null)
41
  * @method Filesystem flushCache()
42
  * @method void assertPresent($path)
43
  * @method void assertAbsent($path)
44
  * @method Filesystem addPlugin(PluginInterface $plugin)
45
  */
46
- class MountManager
47
  {
48
  use PluggableTrait;
49
 
@@ -195,6 +173,7 @@ class MountManager
195
  *
196
  * @throws InvalidArgumentException
197
  * @throws FilesystemNotFoundException
 
198
  *
199
  * @return bool
200
  */
@@ -317,4 +296,353 @@ class MountManager
317
 
318
  return explode('://', $path, 2);
319
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
320
  }
3
  namespace League\Flysystem;
4
 
5
  use InvalidArgumentException;
 
6
  use League\Flysystem\Plugin\PluggableTrait;
7
  use League\Flysystem\Plugin\PluginNotFoundException;
8
 
13
  *
14
  * @method AdapterInterface getAdapter($prefix)
15
  * @method Config getConfig($prefix)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  * @method array listFiles($directory = '', $recursive = false)
17
  * @method array listPaths($directory = '', $recursive = false)
18
  * @method array getWithMetadata($path, array $metadata)
 
 
 
 
 
 
 
19
  * @method Filesystem flushCache()
20
  * @method void assertPresent($path)
21
  * @method void assertAbsent($path)
22
  * @method Filesystem addPlugin(PluginInterface $plugin)
23
  */
24
+ class MountManager implements FilesystemInterface
25
  {
26
  use PluggableTrait;
27
 
173
  *
174
  * @throws InvalidArgumentException
175
  * @throws FilesystemNotFoundException
176
+ * @throws FileExistsException
177
  *
178
  * @return bool
179
  */
296
 
297
  return explode('://', $path, 2);
298
  }
299
+
300
+ /**
301
+ * Check whether a file exists.
302
+ *
303
+ * @param string $path
304
+ *
305
+ * @return bool
306
+ */
307
+ public function has($path)
308
+ {
309
+ list($prefix, $path) = $this->getPrefixAndPath($path);
310
+
311
+ return $this->getFilesystem($prefix)->has($path);
312
+ }
313
+
314
+ /**
315
+ * Read a file.
316
+ *
317
+ * @param string $path The path to the file.
318
+ *
319
+ * @throws FileNotFoundException
320
+ *
321
+ * @return string|false The file contents or false on failure.
322
+ */
323
+ public function read($path)
324
+ {
325
+ list($prefix, $path) = $this->getPrefixAndPath($path);
326
+
327
+ return $this->getFilesystem($prefix)->read($path);
328
+ }
329
+
330
+ /**
331
+ * Retrieves a read-stream for a path.
332
+ *
333
+ * @param string $path The path to the file.
334
+ *
335
+ * @throws FileNotFoundException
336
+ *
337
+ * @return resource|false The path resource or false on failure.
338
+ */
339
+ public function readStream($path)
340
+ {
341
+ list($prefix, $path) = $this->getPrefixAndPath($path);
342
+
343
+ return $this->getFilesystem($prefix)->readStream($path);
344
+ }
345
+
346
+ /**
347
+ * Get a file's metadata.
348
+ *
349
+ * @param string $path The path to the file.
350
+ *
351
+ * @throws FileNotFoundException
352
+ *
353
+ * @return array|false The file metadata or false on failure.
354
+ */
355
+ public function getMetadata($path)
356
+ {
357
+ list($prefix, $path) = $this->getPrefixAndPath($path);
358
+
359
+ return $this->getFilesystem($prefix)->getMetadata($path);
360
+ }
361
+
362
+ /**
363
+ * Get a file's size.
364
+ *
365
+ * @param string $path The path to the file.
366
+ *
367
+ * @throws FileNotFoundException
368
+ *
369
+ * @return int|false The file size or false on failure.
370
+ */
371
+ public function getSize($path)
372
+ {
373
+ list($prefix, $path) = $this->getPrefixAndPath($path);
374
+
375
+ return $this->getFilesystem($prefix)->getSize($path);
376
+ }
377
+
378
+ /**
379
+ * Get a file's mime-type.
380
+ *
381
+ * @param string $path The path to the file.
382
+ *
383
+ * @throws FileNotFoundException
384
+ *
385
+ * @return string|false The file mime-type or false on failure.
386
+ */
387
+ public function getMimetype($path)
388
+ {
389
+ list($prefix, $path) = $this->getPrefixAndPath($path);
390
+
391
+ return $this->getFilesystem($prefix)->getMimetype($path);
392
+ }
393
+
394
+ /**
395
+ * Get a file's timestamp.
396
+ *
397
+ * @param string $path The path to the file.
398
+ *
399
+ * @throws FileNotFoundException
400
+ *
401
+ * @return string|false The timestamp or false on failure.
402
+ */
403
+ public function getTimestamp($path)
404
+ {
405
+ list($prefix, $path) = $this->getPrefixAndPath($path);
406
+
407
+ return $this->getFilesystem($prefix)->getTimestamp($path);
408
+ }
409
+
410
+ /**
411
+ * Get a file's visibility.
412
+ *
413
+ * @param string $path The path to the file.
414
+ *
415
+ * @throws FileNotFoundException
416
+ *
417
+ * @return string|false The visibility (public|private) or false on failure.
418
+ */
419
+ public function getVisibility($path)
420
+ {
421
+ list($prefix, $path) = $this->getPrefixAndPath($path);
422
+
423
+ return $this->getFilesystem($prefix)->getVisibility($path);
424
+ }
425
+
426
+ /**
427
+ * Write a new file.
428
+ *
429
+ * @param string $path The path of the new file.
430
+ * @param string $contents The file contents.
431
+ * @param array $config An optional configuration array.
432
+ *
433
+ * @throws FileExistsException
434
+ *
435
+ * @return bool True on success, false on failure.
436
+ */
437
+ public function write($path, $contents, array $config = [])
438
+ {
439
+ list($prefix, $path) = $this->getPrefixAndPath($path);
440
+
441
+ return $this->getFilesystem($prefix)->write($path, $contents, $config);
442
+ }
443
+
444
+ /**
445
+ * Write a new file using a stream.
446
+ *
447
+ * @param string $path The path of the new file.
448
+ * @param resource $resource The file handle.
449
+ * @param array $config An optional configuration array.
450
+ *
451
+ * @throws InvalidArgumentException If $resource is not a file handle.
452
+ * @throws FileExistsException
453
+ *
454
+ * @return bool True on success, false on failure.
455
+ */
456
+ public function writeStream($path, $resource, array $config = [])
457
+ {
458
+ list($prefix, $path) = $this->getPrefixAndPath($path);
459
+
460
+ return $this->getFilesystem($prefix)->writeStream($path, $resource, $config);
461
+ }
462
+
463
+ /**
464
+ * Update an existing file.
465
+ *
466
+ * @param string $path The path of the existing file.
467
+ * @param string $contents The file contents.
468
+ * @param array $config An optional configuration array.
469
+ *
470
+ * @throws FileNotFoundException
471
+ *
472
+ * @return bool True on success, false on failure.
473
+ */
474
+ public function update($path, $contents, array $config = [])
475
+ {
476
+ list($prefix, $path) = $this->getPrefixAndPath($path);
477
+
478
+ return $this->getFilesystem($prefix)->update($path, $contents, $config);
479
+ }
480
+
481
+ /**
482
+ * Update an existing file using a stream.
483
+ *
484
+ * @param string $path The path of the existing file.
485
+ * @param resource $resource The file handle.
486
+ * @param array $config An optional configuration array.
487
+ *
488
+ * @throws InvalidArgumentException If $resource is not a file handle.
489
+ * @throws FileNotFoundException
490
+ *
491
+ * @return bool True on success, false on failure.
492
+ */
493
+ public function updateStream($path, $resource, array $config = [])
494
+ {
495
+ list($prefix, $path) = $this->getPrefixAndPath($path);
496
+
497
+ return $this->getFilesystem($prefix)->updateStream($path, $resource, $config);
498
+ }
499
+
500
+ /**
501
+ * Rename a file.
502
+ *
503
+ * @param string $path Path to the existing file.
504
+ * @param string $newpath The new path of the file.
505
+ *
506
+ * @throws FileExistsException Thrown if $newpath exists.
507
+ * @throws FileNotFoundException Thrown if $path does not exist.
508
+ *
509
+ * @return bool True on success, false on failure.
510
+ */
511
+ public function rename($path, $newpath)
512
+ {
513
+ list($prefix, $path) = $this->getPrefixAndPath($path);
514
+
515
+ return $this->getFilesystem($prefix)->rename($path, $newpath);
516
+ }
517
+
518
+ /**
519
+ * Delete a file.
520
+ *
521
+ * @param string $path
522
+ *
523
+ * @throws FileNotFoundException
524
+ *
525
+ * @return bool True on success, false on failure.
526
+ */
527
+ public function delete($path)
528
+ {
529
+ list($prefix, $path) = $this->getPrefixAndPath($path);
530
+
531
+ return $this->getFilesystem($prefix)->delete($path);
532
+ }
533
+
534
+ /**
535
+ * Delete a directory.
536
+ *
537
+ * @param string $dirname
538
+ *
539
+ * @throws RootViolationException Thrown if $dirname is empty.
540
+ *
541
+ * @return bool True on success, false on failure.
542
+ */
543
+ public function deleteDir($dirname)
544
+ {
545
+ list($prefix, $dirname) = $this->getPrefixAndPath($dirname);
546
+
547
+ return $this->getFilesystem($prefix)->deleteDir($dirname);
548
+ }
549
+
550
+ /**
551
+ * Create a directory.
552
+ *
553
+ * @param string $dirname The name of the new directory.
554
+ * @param array $config An optional configuration array.
555
+ *
556
+ * @return bool True on success, false on failure.
557
+ */
558
+ public function createDir($dirname, array $config = [])
559
+ {
560
+ list($prefix, $dirname) = $this->getPrefixAndPath($dirname);
561
+
562
+ return $this->getFilesystem($prefix)->createDir($dirname);
563
+ }
564
+
565
+ /**
566
+ * Set the visibility for a file.
567
+ *
568
+ * @param string $path The path to the file.
569
+ * @param string $visibility One of 'public' or 'private'.
570
+ *
571
+ * @throws FileNotFoundException
572
+ *
573
+ * @return bool True on success, false on failure.
574
+ */
575
+ public function setVisibility($path, $visibility)
576
+ {
577
+ list($prefix, $path) = $this->getPrefixAndPath($path);
578
+
579
+ return $this->getFilesystem($prefix)->setVisibility($path, $visibility);
580
+ }
581
+
582
+ /**
583
+ * Create a file or update if exists.
584
+ *
585
+ * @param string $path The path to the file.
586
+ * @param string $contents The file contents.
587
+ * @param array $config An optional configuration array.
588
+ *
589
+ * @return bool True on success, false on failure.
590
+ */
591
+ public function put($path, $contents, array $config = [])
592
+ {
593
+ list($prefix, $path) = $this->getPrefixAndPath($path);
594
+
595
+ return $this->getFilesystem($prefix)->put($path, $contents, $config);
596
+ }
597
+
598
+ /**
599
+ * Create a file or update if exists.
600
+ *
601
+ * @param string $path The path to the file.
602
+ * @param resource $resource The file handle.
603
+ * @param array $config An optional configuration array.
604
+ *
605
+ * @throws InvalidArgumentException Thrown if $resource is not a resource.
606
+ *
607
+ * @return bool True on success, false on failure.
608
+ */
609
+ public function putStream($path, $resource, array $config = [])
610
+ {
611
+ list($prefix, $path) = $this->getPrefixAndPath($path);
612
+
613
+ return $this->getFilesystem($prefix)->putStream($path, $resource, $config);
614
+ }
615
+
616
+ /**
617
+ * Read and delete a file.
618
+ *
619
+ * @param string $path The path to the file.
620
+ *
621
+ * @throws FileNotFoundException
622
+ *
623
+ * @return string|false The file contents, or false on failure.
624
+ */
625
+ public function readAndDelete($path)
626
+ {
627
+ list($prefix, $path) = $this->getPrefixAndPath($path);
628
+
629
+ return $this->getFilesystem($prefix)->readAndDelete($path);
630
+ }
631
+
632
+ /**
633
+ * Get a file/directory handler.
634
+ *
635
+ * @deprecated
636
+ *
637
+ * @param string $path The path to the file.
638
+ * @param Handler $handler An optional existing handler to populate.
639
+ *
640
+ * @return Handler Either a file or directory handler.
641
+ */
642
+ public function get($path, Handler $handler = null)
643
+ {
644
+ list($prefix, $path) = $this->getPrefixAndPath($path);
645
+
646
+ return $this->getFilesystem($prefix)->get($path);
647
+ }
648
  }
vendor/league/flysystem/src/Util/MimeType.php CHANGED
@@ -10,6 +10,166 @@ use ErrorException;
10
  */
11
  class MimeType
12
  {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  /**
14
  * Detects MIME Type based on given content.
15
  *
@@ -41,17 +201,9 @@ class MimeType
41
  */
42
  public static function detectByFileExtension($extension)
43
  {
44
- static $extensionToMimeTypeMap;
45
-
46
- if (! $extensionToMimeTypeMap) {
47
- $extensionToMimeTypeMap = static::getExtensionToMimeTypeMap();
48
- }
49
-
50
- if (isset($extensionToMimeTypeMap[$extension])) {
51
- return $extensionToMimeTypeMap[$extension];
52
- }
53
-
54
- return 'text/plain';
55
  }
56
 
57
  /**
@@ -71,162 +223,6 @@ class MimeType
71
  */
72
  public static function getExtensionToMimeTypeMap()
73
  {
74
- return [
75
- 'hqx' => 'application/mac-binhex40',
76
- 'cpt' => 'application/mac-compactpro',
77
- 'csv' => 'text/x-comma-separated-values',
78
- 'bin' => 'application/octet-stream',
79
- 'dms' => 'application/octet-stream',
80
- 'lha' => 'application/octet-stream',
81
- 'lzh' => 'application/octet-stream',
82
- 'exe' => 'application/octet-stream',
83
- 'class' => 'application/octet-stream',
84
- 'psd' => 'application/x-photoshop',
85
- 'so' => 'application/octet-stream',
86
- 'sea' => 'application/octet-stream',
87
- 'dll' => 'application/octet-stream',
88
- 'oda' => 'application/oda',
89
- 'pdf' => 'application/pdf',
90
- 'ai' => 'application/pdf',
91
- 'eps' => 'application/postscript',
92
- 'ps' => 'application/postscript',
93
- 'smi' => 'application/smil',
94
- 'smil' => 'application/smil',
95
- 'mif' => 'application/vnd.mif',
96
- 'xls' => 'application/vnd.ms-excel',
97
- 'ppt' => 'application/powerpoint',
98
- 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
99
- 'wbxml' => 'application/wbxml',
100
- 'wmlc' => 'application/wmlc',
101
- 'dcr' => 'application/x-director',
102
- 'dir' => 'application/x-director',
103
- 'dxr' => 'application/x-director',
104
- 'dvi' => 'application/x-dvi',
105
- 'gtar' => 'application/x-gtar',
106
- 'gz' => 'application/x-gzip',
107
- 'gzip' => 'application/x-gzip',
108
- 'php' => 'application/x-httpd-php',
109
- 'php4' => 'application/x-httpd-php',
110
- 'php3' => 'application/x-httpd-php',
111
- 'phtml' => 'application/x-httpd-php',
112
- 'phps' => 'application/x-httpd-php-source',
113
- 'js' => 'application/javascript',
114
- 'swf' => 'application/x-shockwave-flash',
115
- 'sit' => 'application/x-stuffit',
116
- 'tar' => 'application/x-tar',
117
- 'tgz' => 'application/x-tar',
118
- 'z' => 'application/x-compress',
119
- 'xhtml' => 'application/xhtml+xml',
120
- 'xht' => 'application/xhtml+xml',
121
- 'zip' => 'application/x-zip',
122
- 'rar' => 'application/x-rar',
123
- 'mid' => 'audio/midi',
124
- 'midi' => 'audio/midi',
125
- 'mpga' => 'audio/mpeg',
126
- 'mp2' => 'audio/mpeg',
127
- 'mp3' => 'audio/mpeg',
128
- 'aif' => 'audio/x-aiff',
129
- 'aiff' => 'audio/x-aiff',
130
- 'aifc' => 'audio/x-aiff',
131
- 'ram' => 'audio/x-pn-realaudio',
132
- 'rm' => 'audio/x-pn-realaudio',
133
- 'rpm' => 'audio/x-pn-realaudio-plugin',
134
- 'ra' => 'audio/x-realaudio',
135
- 'rv' => 'video/vnd.rn-realvideo',
136
- 'wav' => 'audio/x-wav',
137
- 'jpg' => 'image/jpeg',
138
- 'jpeg' => 'image/jpeg',
139
- 'jpe' => 'image/jpeg',
140
- 'png' => 'image/png',
141
- 'gif' => 'image/gif',
142
- 'bmp' => 'image/bmp',
143
- 'tiff' => 'image/tiff',
144
- 'tif' => 'image/tiff',
145
- 'svg' => 'image/svg+xml',
146
- 'css' => 'text/css',
147
- 'html' => 'text/html',
148
- 'htm' => 'text/html',
149
- 'shtml' => 'text/html',
150
- 'txt' => 'text/plain',
151
- 'text' => 'text/plain',
152
- 'log' => 'text/plain',
153
- 'rtx' => 'text/richtext',
154
- 'rtf' => 'text/rtf',
155
- 'xml' => 'application/xml',
156
- 'xsl' => 'application/xml',
157
- 'dmn' => 'application/octet-stream',
158
- 'bpmn' => 'application/octet-stream',
159
- 'mpeg' => 'video/mpeg',
160
- 'mpg' => 'video/mpeg',
161
- 'mpe' => 'video/mpeg',
162
- 'qt' => 'video/quicktime',
163
- 'mov' => 'video/quicktime',
164
- 'avi' => 'video/x-msvideo',
165
- 'movie' => 'video/x-sgi-movie',
166
- 'doc' => 'application/msword',
167
- 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
168
- 'docm' => 'application/vnd.ms-word.template.macroEnabled.12',
169
- 'dot' => 'application/msword',
170
- 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
171
- 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
172
- 'word' => 'application/msword',
173
- 'xl' => 'application/excel',
174
- 'eml' => 'message/rfc822',
175
- 'json' => 'application/json',
176
- 'pem' => 'application/x-x509-user-cert',
177
- 'p10' => 'application/x-pkcs10',
178
- 'p12' => 'application/x-pkcs12',
179
- 'p7a' => 'application/x-pkcs7-signature',
180
- 'p7c' => 'application/pkcs7-mime',
181
- 'p7m' => 'application/pkcs7-mime',
182
- 'p7r' => 'application/x-pkcs7-certreqresp',
183
- 'p7s' => 'application/pkcs7-signature',
184
- 'crt' => 'application/x-x509-ca-cert',
185
- 'crl' => 'application/pkix-crl',
186
- 'der' => 'application/x-x509-ca-cert',
187
- 'kdb' => 'application/octet-stream',
188
- 'pgp' => 'application/pgp',
189
- 'gpg' => 'application/gpg-keys',
190
- 'sst' => 'application/octet-stream',
191
- 'csr' => 'application/octet-stream',
192
- 'rsa' => 'application/x-pkcs7',
193
- 'cer' => 'application/pkix-cert',
194
- '3g2' => 'video/3gpp2',
195
- '3gp' => 'video/3gp',
196
- 'mp4' => 'video/mp4',
197
- 'm4a' => 'audio/x-m4a',
198
- 'f4v' => 'video/mp4',
199
- 'webm' => 'video/webm',
200
- 'aac' => 'audio/x-acc',
201
- 'm4u' => 'application/vnd.mpegurl',
202
- 'm3u' => 'text/plain',
203
- 'xspf' => 'application/xspf+xml',
204
- 'vlc' => 'application/videolan',
205
- 'wmv' => 'video/x-ms-wmv',
206
- 'au' => 'audio/x-au',
207
- 'ac3' => 'audio/ac3',
208
- 'flac' => 'audio/x-flac',
209
- 'ogg' => 'audio/ogg',
210
- 'kmz' => 'application/vnd.google-earth.kmz',
211
- 'kml' => 'application/vnd.google-earth.kml+xml',
212
- 'ics' => 'text/calendar',
213
- 'zsh' => 'text/x-scriptzsh',
214
- '7zip' => 'application/x-7z-compressed',
215
- 'cdr' => 'application/cdr',
216
- 'wma' => 'audio/x-ms-wma',
217
- 'jar' => 'application/java-archive',
218
- 'tex' => 'application/x-tex',
219
- 'latex' => 'application/x-latex',
220
- 'odt' => 'application/vnd.oasis.opendocument.text',
221
- 'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
222
- 'odp' => 'application/vnd.oasis.opendocument.presentation',
223
- 'odg' => 'application/vnd.oasis.opendocument.graphics',
224
- 'odc' => 'application/vnd.oasis.opendocument.chart',
225
- 'odf' => 'application/vnd.oasis.opendocument.formula',
226
- 'odi' => 'application/vnd.oasis.opendocument.image',
227
- 'odm' => 'application/vnd.oasis.opendocument.text-master',
228
- 'odb' => 'application/vnd.oasis.opendocument.database',
229
- 'ott' => 'application/vnd.oasis.opendocument.text-template',
230
- ];
231
  }
232
  }
10
  */
11
  class MimeType
12
  {
13
+ protected static $extensionToMimeTypeMap = [
14
+ 'hqx' => 'application/mac-binhex40',
15
+ 'cpt' => 'application/mac-compactpro',
16
+ 'csv' => 'text/x-comma-separated-values',
17
+ 'bin' => 'application/octet-stream',
18
+ 'dms' => 'application/octet-stream',
19
+ 'lha' => 'application/octet-stream',
20
+ 'lzh' => 'application/octet-stream',
21
+ 'exe' => 'application/octet-stream',
22
+ 'class' => 'application/octet-stream',
23
+ 'psd' => 'application/x-photoshop',
24
+ 'so' => 'application/octet-stream',
25
+ 'sea' => 'application/octet-stream',
26
+ 'dll' => 'application/octet-stream',
27
+ 'oda' => 'application/oda',
28
+ 'pdf' => 'application/pdf',
29
+ 'ai' => 'application/pdf',
30
+ 'eps' => 'application/postscript',
31
+ 'epub' => 'application/epub+zip',
32
+ 'ps' => 'application/postscript',
33
+ 'smi' => 'application/smil',
34
+ 'smil' => 'application/smil',
35
+ 'mif' => 'application/vnd.mif',
36
+ 'xls' => 'application/vnd.ms-excel',
37
+ 'ppt' => 'application/powerpoint',
38
+ 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
39
+ 'wbxml' => 'application/wbxml',
40
+ 'wmlc' => 'application/wmlc',
41
+ 'dcr' => 'application/x-director',
42
+ 'dir' => 'application/x-director',
43
+ 'dxr' => 'application/x-director',
44
+ 'dvi' => 'application/x-dvi',
45
+ 'gtar' => 'application/x-gtar',
46
+ 'gz' => 'application/x-gzip',
47
+ 'gzip' => 'application/x-gzip',
48
+ 'php' => 'application/x-httpd-php',
49
+ 'php4' => 'application/x-httpd-php',
50
+ 'php3' => 'application/x-httpd-php',
51
+ 'phtml' => 'application/x-httpd-php',
52
+ 'phps' => 'application/x-httpd-php-source',
53
+ 'js' => 'application/javascript',
54
+ 'swf' => 'application/x-shockwave-flash',
55
+ 'sit' => 'application/x-stuffit',
56
+ 'tar' => 'application/x-tar',
57
+ 'tgz' => 'application/x-tar',
58
+ 'z' => 'application/x-compress',
59
+ 'xhtml' => 'application/xhtml+xml',
60
+ 'xht' => 'application/xhtml+xml',
61
+ 'rdf' => 'application/rdf+xml',
62
+ 'zip' => 'application/x-zip',
63
+ 'rar' => 'application/x-rar',
64
+ 'mid' => 'audio/midi',
65
+ 'midi' => 'audio/midi',
66
+ 'mpga' => 'audio/mpeg',
67
+ 'mp2' => 'audio/mpeg',
68
+ 'mp3' => 'audio/mpeg',
69
+ 'aif' => 'audio/x-aiff',
70
+ 'aiff' => 'audio/x-aiff',
71
+ 'aifc' => 'audio/x-aiff',
72
+ 'ram' => 'audio/x-pn-realaudio',
73
+ 'rm' => 'audio/x-pn-realaudio',
74
+ 'rpm' => 'audio/x-pn-realaudio-plugin',
75
+ 'ra' => 'audio/x-realaudio',
76
+ 'rv' => 'video/vnd.rn-realvideo',
77
+ 'wav' => 'audio/x-wav',
78
+ 'jpg' => 'image/jpeg',
79
+ 'jpeg' => 'image/jpeg',
80
+ 'jpe' => 'image/jpeg',
81
+ 'png' => 'image/png',
82
+ 'gif' => 'image/gif',
83
+ 'bmp' => 'image/bmp',
84
+ 'tiff' => 'image/tiff',
85
+ 'tif' => 'image/tiff',
86
+ 'svg' => 'image/svg+xml',
87
+ 'css' => 'text/css',
88
+ 'html' => 'text/html',
89
+ 'htm' => 'text/html',
90
+ 'shtml' => 'text/html',
91
+ 'txt' => 'text/plain',
92
+ 'text' => 'text/plain',
93
+ 'log' => 'text/plain',
94
+ 'rtx' => 'text/richtext',
95
+ 'rtf' => 'text/rtf',
96
+ 'xml' => 'application/xml',
97
+ 'xsl' => 'application/xml',
98
+ 'dmn' => 'application/octet-stream',
99
+ 'bpmn' => 'application/octet-stream',
100
+ 'mpeg' => 'video/mpeg',
101
+ 'mpg' => 'video/mpeg',
102
+ 'mpe' => 'video/mpeg',
103
+ 'qt' => 'video/quicktime',
104
+ 'mov' => 'video/quicktime',
105
+ 'avi' => 'video/x-msvideo',
106
+ 'movie' => 'video/x-sgi-movie',
107
+ 'doc' => 'application/msword',
108
+ 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
109
+ 'docm' => 'application/vnd.ms-word.template.macroEnabled.12',
110
+ 'dot' => 'application/msword',
111
+ 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
112
+ 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
113
+ 'word' => 'application/msword',
114
+ 'xl' => 'application/excel',
115
+ 'eml' => 'message/rfc822',
116
+ 'json' => 'application/json',
117
+ 'pem' => 'application/x-x509-user-cert',
118
+ 'p10' => 'application/x-pkcs10',
119
+ 'p12' => 'application/x-pkcs12',
120
+ 'p7a' => 'application/x-pkcs7-signature',
121
+ 'p7c' => 'application/pkcs7-mime',
122
+ 'p7m' => 'application/pkcs7-mime',
123
+ 'p7r' => 'application/x-pkcs7-certreqresp',
124
+ 'p7s' => 'application/pkcs7-signature',
125
+ 'crt' => 'application/x-x509-ca-cert',
126
+ 'crl' => 'application/pkix-crl',
127
+ 'der' => 'application/x-x509-ca-cert',
128
+ 'kdb' => 'application/octet-stream',
129
+ 'pgp' => 'application/pgp',
130
+ 'gpg' => 'application/gpg-keys',
131
+ 'sst' => 'application/octet-stream',
132
+ 'csr' => 'application/octet-stream',
133
+ 'rsa' => 'application/x-pkcs7',
134
+ 'cer' => 'application/pkix-cert',
135
+ '3g2' => 'video/3gpp2',
136
+ '3gp' => 'video/3gp',
137
+ 'mp4' => 'video/mp4',
138
+ 'm4a' => 'audio/x-m4a',
139
+ 'f4v' => 'video/mp4',
140
+ 'webm' => 'video/webm',
141
+ 'aac' => 'audio/x-acc',
142
+ 'm4u' => 'application/vnd.mpegurl',
143
+ 'm3u' => 'text/plain',
144
+ 'xspf' => 'application/xspf+xml',
145
+ 'vlc' => 'application/videolan',
146
+ 'wmv' => 'video/x-ms-wmv',
147
+ 'au' => 'audio/x-au',
148
+ 'ac3' => 'audio/ac3',
149
+ 'flac' => 'audio/x-flac',
150
+ 'ogg' => 'audio/ogg',
151
+ 'kmz' => 'application/vnd.google-earth.kmz',
152
+ 'kml' => 'application/vnd.google-earth.kml+xml',
153
+ 'ics' => 'text/calendar',
154
+ 'zsh' => 'text/x-scriptzsh',
155
+ '7zip' => 'application/x-7z-compressed',
156
+ 'cdr' => 'application/cdr',
157
+ 'wma' => 'audio/x-ms-wma',
158
+ 'jar' => 'application/java-archive',
159
+ 'tex' => 'application/x-tex',
160
+ 'latex' => 'application/x-latex',
161
+ 'odt' => 'application/vnd.oasis.opendocument.text',
162
+ 'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
163
+ 'odp' => 'application/vnd.oasis.opendocument.presentation',
164
+ 'odg' => 'application/vnd.oasis.opendocument.graphics',
165
+ 'odc' => 'application/vnd.oasis.opendocument.chart',
166
+ 'odf' => 'application/vnd.oasis.opendocument.formula',
167
+ 'odi' => 'application/vnd.oasis.opendocument.image',
168
+ 'odm' => 'application/vnd.oasis.opendocument.text-master',
169
+ 'odb' => 'application/vnd.oasis.opendocument.database',
170
+ 'ott' => 'application/vnd.oasis.opendocument.text-template',
171
+ ];
172
+
173
  /**
174
  * Detects MIME Type based on given content.
175
  *
201
  */
202
  public static function detectByFileExtension($extension)
203
  {
204
+ return isset(static::$extensionToMimeTypeMap[$extension])
205
+ ? static::$extensionToMimeTypeMap[$extension]
206
+ : 'text/plain';
 
 
 
 
 
 
 
 
207
  }
208
 
209
  /**
223
  */
224
  public static function getExtensionToMimeTypeMap()
225
  {
226
+ return static::$extensionToMimeTypeMap;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
227
  }
228
  }
vendor/league/flysystem/stub/FilesystemSpy.php ADDED
@@ -0,0 +1,354 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace League\Flysystem\Stub;
4
+
5
+ use InvalidArgumentException;
6
+ use League\Flysystem\FileExistsException;
7
+ use League\Flysystem\FileNotFoundException;
8
+ use League\Flysystem\FilesystemInterface;
9
+ use League\Flysystem\Handler;
10
+ use League\Flysystem\Plugin\PluggableTrait;
11
+ use League\Flysystem\RootViolationException;
12
+
13
+ class FilesystemSpy implements FilesystemInterface
14
+ {
15
+ use PluggableTrait;
16
+
17
+ public $lastCall = [];
18
+
19
+ /**
20
+ * Check whether a file exists.
21
+ *
22
+ * @param string $path
23
+ *
24
+ * @return bool
25
+ */
26
+ public function has($path)
27
+ {
28
+ $this->lastCall = [__METHOD__, func_get_args()];
29
+ }
30
+
31
+ /**
32
+ * Read a file.
33
+ *
34
+ * @param string $path The path to the file.
35
+ *
36
+ * @throws FileNotFoundException
37
+ *
38
+ * @return string|false The file contents or false on failure.
39
+ */
40
+ public function read($path)
41
+ {
42
+ $this->lastCall = [__METHOD__, func_get_args()];
43
+ }
44
+
45
+ /**
46
+ * Retrieves a read-stream for a path.
47
+ *
48
+ * @param string $path The path to the file.
49
+ *
50
+ * @throws FileNotFoundException
51
+ *
52
+ * @return resource|false The path resource or false on failure.
53
+ */
54
+ public function readStream($path)
55
+ {
56
+ $this->lastCall = [__METHOD__, func_get_args()];
57
+ }
58
+
59
+ /**
60
+ * List contents of a directory.
61
+ *
62
+ * @param string $directory The directory to list.
63
+ * @param bool $recursive Whether to list recursively.
64
+ *
65
+ * @return array A list of file metadata.
66
+ */
67
+ public function listContents($directory = '', $recursive = false)
68
+ {
69
+ $this->lastCall = [__METHOD__, func_get_args()];
70
+ }
71
+
72
+ /**
73
+ * Get a file's metadata.
74
+ *
75
+ * @param string $path The path to the file.
76
+ *
77
+ * @throws FileNotFoundException
78
+ *
79
+ * @return array|false The file metadata or false on failure.
80
+ */
81
+ public function getMetadata($path)
82
+ {
83
+ $this->lastCall = [__METHOD__, func_get_args()];
84
+ }
85
+
86
+ /**
87
+ * Get a file's size.
88
+ *
89
+ * @param string $path The path to the file.
90
+ *
91
+ * @throws FileNotFoundException
92
+ *
93
+ * @return int|false The file size or false on failure.
94
+ */
95
+ public function getSize($path)
96
+ {
97
+ $this->lastCall = [__METHOD__, func_get_args()];
98
+ }
99
+
100
+ /**
101
+ * Get a file's mime-type.
102
+ *
103
+ * @param string $path The path to the file.
104
+ *
105
+ * @throws FileNotFoundException
106
+ *
107
+ * @return string|false The file mime-type or false on failure.
108
+ */
109
+ public function getMimetype($path)
110
+ {
111
+ $this->lastCall = [__METHOD__, func_get_args()];
112
+ }
113
+
114
+ /**
115
+ * Get a file's timestamp.
116
+ *
117
+ * @param string $path The path to the file.
118
+ *
119
+ * @throws FileNotFoundException
120
+ *
121
+ * @return string|false The timestamp or false on failure.
122
+ */
123
+ public function getTimestamp($path)
124
+ {
125
+ $this->lastCall = [__METHOD__, func_get_args()];
126
+ }
127
+
128
+ /**
129
+ * Get a file's visibility.
130
+ *
131
+ * @param string $path The path to the file.
132
+ *
133
+ * @throws FileNotFoundException
134
+ *
135
+ * @return string|false The visibility (public|private) or false on failure.
136
+ */
137
+ public function getVisibility($path)
138
+ {
139
+ $this->lastCall = [__METHOD__, func_get_args()];
140
+ }
141
+
142
+ /**
143
+ * Write a new file.
144
+ *
145
+ * @param string $path The path of the new file.
146
+ * @param string $contents The file contents.
147
+ * @param array $config An optional configuration array.
148
+ *
149
+ * @throws FileExistsException
150
+ *
151
+ * @return bool True on success, false on failure.
152
+ */
153
+ public function write($path, $contents, array $config = [])
154
+ {
155
+ $this->lastCall = [__METHOD__, func_get_args()];
156
+ }
157
+
158
+ /**
159
+ * Write a new file using a stream.
160
+ *
161
+ * @param string $path The path of the new file.
162
+ * @param resource $resource The file handle.
163
+ * @param array $config An optional configuration array.
164
+ *
165
+ * @throws InvalidArgumentException If $resource is not a file handle.
166
+ * @throws FileExistsException
167
+ *
168
+ * @return bool True on success, false on failure.
169
+ */
170
+ public function writeStream($path, $resource, array $config = [])
171
+ {
172
+ $this->lastCall = [__METHOD__, func_get_args()];
173
+ }
174
+
175
+ /**
176
+ * Update an existing file.
177
+ *
178
+ * @param string $path The path of the existing file.
179
+ * @param string $contents The file contents.
180
+ * @param array $config An optional configuration array.
181
+ *
182
+ * @throws FileNotFoundException
183
+ *
184
+ * @return bool True on success, false on failure.
185
+ */
186
+ public function update($path, $contents, array $config = [])
187
+ {
188
+ $this->lastCall = [__METHOD__, func_get_args()];
189
+ }
190
+
191
+ /**
192
+ * Update an existing file using a stream.
193
+ *
194
+ * @param string $path The path of the existing file.
195
+ * @param resource $resource The file handle.
196
+ * @param array $config An optional configuration array.
197
+ *
198
+ * @throws InvalidArgumentException If $resource is not a file handle.
199
+ * @throws FileNotFoundException
200
+ *
201
+ * @return bool True on success, false on failure.
202
+ */
203
+ public function updateStream($path, $resource, array $config = [])
204
+ {
205
+ $this->lastCall = [__METHOD__, func_get_args()];
206
+ }
207
+
208
+ /**
209
+ * Rename a file.
210
+ *
211
+ * @param string $path Path to the existing file.
212
+ * @param string $newpath The new path of the file.
213
+ *
214
+ * @throws FileExistsException Thrown if $newpath exists.
215
+ * @throws FileNotFoundException Thrown if $path does not exist.
216
+ *
217
+ * @return bool True on success, false on failure.
218
+ */
219
+ public function rename($path, $newpath)
220
+ {
221
+ $this->lastCall = [__METHOD__, func_get_args()];
222
+ }
223
+
224
+ /**
225
+ * Copy a file.
226
+ *
227
+ * @param string $path Path to the existing file.
228
+ * @param string $newpath The new path of the file.
229
+ *
230
+ * @throws FileExistsException Thrown if $newpath exists.
231
+ * @throws FileNotFoundException Thrown if $path does not exist.
232
+ *
233
+ * @return bool True on success, false on failure.
234
+ */
235
+ public function copy($path, $newpath)
236
+ {
237
+ $this->lastCall = [__METHOD__, func_get_args()];
238
+ }
239
+
240
+ /**
241
+ * Delete a file.
242
+ *
243
+ * @param string $path
244
+ *
245
+ * @throws FileNotFoundException
246
+ *
247
+ * @return bool True on success, false on failure.
248
+ */
249
+ public function delete($path)
250
+ {
251
+ $this->lastCall = [__METHOD__, func_get_args()];
252
+ }
253
+
254
+ /**
255
+ * Delete a directory.
256
+ *
257
+ * @param string $dirname
258
+ *
259
+ * @throws RootViolationException Thrown if $dirname is empty.
260
+ *
261
+ * @return bool True on success, false on failure.
262
+ */
263
+ public function deleteDir($dirname)
264
+ {
265
+ $this->lastCall = [__METHOD__, func_get_args()];
266
+ }
267
+
268
+ /**
269
+ * Create a directory.
270
+ *
271
+ * @param string $dirname The name of the new directory.
272
+ * @param array $config An optional configuration array.
273
+ *
274
+ * @return bool True on success, false on failure.
275
+ */
276
+ public function createDir($dirname, array $config = [])
277
+ {
278
+ $this->lastCall = [__METHOD__, func_get_args()];
279
+ }
280
+
281
+ /**
282
+ * Set the visibility for a file.
283
+ *
284
+ * @param string $path The path to the file.
285
+ * @param string $visibility One of 'public' or 'private'.
286
+ *
287
+ * @throws FileNotFoundException
288
+ *
289
+ * @return bool True on success, false on failure.
290
+ */
291
+ public function setVisibility($path, $visibility)
292
+ {
293
+ $this->lastCall = [__METHOD__, func_get_args()];
294
+ }
295
+
296
+ /**
297
+ * Create a file or update if exists.
298
+ *
299
+ * @param string $path The path to the file.
300
+ * @param string $contents The file contents.
301
+ * @param array $config An optional configuration array.
302
+ *
303
+ * @return bool True on success, false on failure.
304
+ */
305
+ public function put($path, $contents, array $config = [])
306
+ {
307
+ $this->lastCall = [__METHOD__, func_get_args()];
308
+ }
309
+
310
+ /**
311
+ * Create a file or update if exists.
312
+ *
313
+ * @param string $path The path to the file.
314
+ * @param resource $resource The file handle.
315
+ * @param array $config An optional configuration array.
316
+ *
317
+ * @throws InvalidArgumentException Thrown if $resource is not a resource.
318
+ *
319
+ * @return bool True on success, false on failure.
320
+ */
321
+ public function putStream($path, $resource, array $config = [])
322
+ {
323
+ $this->lastCall = [__METHOD__, func_get_args()];
324
+ }
325
+
326
+ /**
327
+ * Read and delete a file.
328
+ *
329
+ * @param string $path The path to the file.
330
+ *
331
+ * @throws FileNotFoundException
332
+ *
333
+ * @return string|false The file contents, or false on failure.
334
+ */
335
+ public function readAndDelete($path)
336
+ {
337
+ $this->lastCall = [__METHOD__, func_get_args()];
338
+ }
339
+
340
+ /**
341
+ * Get a file/directory handler.
342
+ *
343
+ * @deprecated
344
+ *
345
+ * @param string $path The path to the file.
346
+ * @param Handler $handler An optional existing handler to populate.
347
+ *
348
+ * @return Handler Either a file or directory handler.
349
+ */
350
+ public function get($path, Handler $handler = null)
351
+ {
352
+ $this->lastCall = [__METHOD__, func_get_args()];
353
+ }
354
+ }
vendor/league/flysystem/tests/FtpTests.php CHANGED
@@ -110,6 +110,10 @@ function ftp_pwd($connection)
110
 
111
  function ftp_raw($connection, $command)
112
  {
 
 
 
 
113
  if ($command === 'OPTS UTF8 ON') {
114
  return [0 => '200 UTF8 set to on'];
115
  }
@@ -762,6 +766,27 @@ class FtpTests extends TestCase
762
  $this->assertEquals('file1.txt', $metadata['path']);
763
  }
764
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
765
  /**
766
  * @param $adapter
767
  */
110
 
111
  function ftp_raw($connection, $command)
112
  {
113
+ if ($connection === 'utf8.fail') {
114
+ return [0 => '421 Service not available, closing control connection'];
115
+ }
116
+
117
  if ($command === 'OPTS UTF8 ON') {
118
  return [0 => '200 UTF8 set to on'];
119
  }
766
  $this->assertEquals('file1.txt', $metadata['path']);
767
  }
768
 
769
+ /**
770
+ * @depends testInstantiable
771
+ */
772
+ public function testItSetUtf8Mode()
773
+ {
774
+ $adapter = new Ftp($this->options + ['utf8' => true]);
775
+ $adapter->setUtf8(true);
776
+ $this->assertNull($adapter->connect());
777
+ }
778
+
779
+ /**
780
+ * @depends testInstantiable
781
+ * @expectedException \RuntimeException
782
+ */
783
+ public function testItThrowsAnExceptionWhenItCouldNotSetUtf8ModeForConnection()
784
+ {
785
+ $adapter = new Ftp(['host' => 'utf8.fail', 'utf8' => true]);
786
+ $adapter->setUtf8(true);
787
+ $adapter->connect();
788
+ }
789
+
790
  /**
791
  * @param $adapter
792
  */
vendor/league/flysystem/tests/LocalAdapterTests.php CHANGED
@@ -459,6 +459,17 @@ class LocalAdapterTests extends TestCase
459
  $this->assertEquals('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', $adapter->getMimetype('test.xlsx')['mimetype']);
460
  }
461
 
 
 
 
 
 
 
 
 
 
 
 
462
  /**
463
  * @expectedException \League\Flysystem\Exception
464
  */
459
  $this->assertEquals('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', $adapter->getMimetype('test.xlsx')['mimetype']);
460
  }
461
 
462
+ public function testDeleteFileShouldReturnTrue(){
463
+ $root = __DIR__ . '/files/';
464
+ $original = $root . 'delete.txt';
465
+ file_put_contents($original, 'something');
466
+ $this->assertTrue($this->adapter->delete('delete.txt'));
467
+ }
468
+
469
+ public function testDeleteMissingFileShouldReturnFalse(){
470
+ $this->assertFalse($this->adapter->delete('missing.txt'));
471
+ }
472
+
473
  /**
474
  * @expectedException \League\Flysystem\Exception
475
  */
vendor/league/flysystem/tests/MountManagerTests.php CHANGED
@@ -1,6 +1,9 @@
1
  <?php
2
 
 
 
3
  use League\Flysystem\MountManager;
 
4
  use PHPUnit\Framework\TestCase;
5
  use Prophecy\Argument;
6
 
@@ -59,18 +62,6 @@ class MountManagerTests extends TestCase
59
  $manager->filterPrefix($arguments);
60
  }
61
 
62
- public function testCallForwarder()
63
- {
64
- $manager = new MountManager();
65
- $mock = $this->getMockBuilder('League\Flysystem\Filesystem')->disableOriginalConstructor()->getMock();
66
- $mock->expects($this->once())
67
- ->method('__call')
68
- ->with('aMethodCall', ['file.ext'])
69
- ->willReturn('a result');
70
- $manager->mountFilesystem('prot', $mock);
71
- $this->assertEquals($manager->aMethodCall('prot://file.ext'), 'a result');
72
- }
73
-
74
  public function testCopyBetweenFilesystems()
75
  {
76
  $manager = new MountManager();
@@ -188,7 +179,12 @@ class MountManagerTests extends TestCase
188
 
189
  public function provideMountSchemas()
190
  {
191
- return [['with.dot'], ['with-dash'], ['with+plus'], ['with:colon']];
 
 
 
 
 
192
  }
193
 
194
  /**
@@ -198,8 +194,52 @@ class MountManagerTests extends TestCase
198
  {
199
  $manager = new MountManager();
200
  $mock = $this->getMockBuilder('League\Flysystem\Filesystem')->disableOriginalConstructor()->getMock();
201
- $mock->method('__call')->with('aMethodCall', ['file.ext'])->willReturn('a result');
202
  $manager->mountFilesystem($schema, $mock);
203
- $this->assertEquals($manager->aMethodCall($schema . '://file.ext'), 'a result');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
204
  }
205
  }
1
  <?php
2
 
3
+ use League\Flysystem\AdapterInterface;
4
+ use League\Flysystem\FilesystemInterface;
5
  use League\Flysystem\MountManager;
6
+ use League\Flysystem\Stub\FilesystemSpy;
7
  use PHPUnit\Framework\TestCase;
8
  use Prophecy\Argument;
9
 
62
  $manager->filterPrefix($arguments);
63
  }
64
 
 
 
 
 
 
 
 
 
 
 
 
 
65
  public function testCopyBetweenFilesystems()
66
  {
67
  $manager = new MountManager();
179
 
180
  public function provideMountSchemas()
181
  {
182
+ return [
183
+ ['with.dot'],
184
+ ['with-dash'],
185
+ ['with+plus'],
186
+ ['with:colon']
187
+ ];
188
  }
189
 
190
  /**
194
  {
195
  $manager = new MountManager();
196
  $mock = $this->getMockBuilder('League\Flysystem\Filesystem')->disableOriginalConstructor()->getMock();
197
+ $mock->method('read')->with('file.ext')->willReturn('a result');
198
  $manager->mountFilesystem($schema, $mock);
199
+ $this->assertEquals($manager->read($schema . '://file.ext'), 'a result');
200
+ }
201
+
202
+ /**
203
+ * @dataProvider methodForwardingProvider
204
+ */
205
+ public function testMethodForwarding($method, array $arguments)
206
+ {
207
+ $mountManager = new MountManager();
208
+ $filesystem = new FilesystemSpy();
209
+ $mountManager->mountFilesystem('local', $filesystem);
210
+ $expectedCall = FilesystemSpy::class . '::' . $method;
211
+ $callingArguments = $arguments;
212
+ $callingArguments[0] = "local://{$callingArguments[0]}";
213
+ call_user_func_array([$mountManager, $method], $callingArguments);
214
+
215
+ $this->assertEquals([$expectedCall, $arguments], $filesystem->lastCall);
216
+ }
217
+
218
+ public function methodForwardingProvider()
219
+ {
220
+
221
+ return [
222
+ ['write', ['path.txt', 'contents', []]],
223
+ ['writeStream', ['path.txt', 'contents', []]],
224
+ ['update', ['path.txt', 'contents', []]],
225
+ ['updateStream', ['path.txt', 'contents', []]],
226
+ ['put', ['path.txt', 'contents', []]],
227
+ ['putStream', ['path.txt', 'contents', []]],
228
+ ['read', ['path.txt']],
229
+ ['readStream', ['path.txt']],
230
+ ['readAndDelete', ['path.txt']],
231
+ ['get', ['path.txt']],
232
+ ['has', ['path.txt']],
233
+ ['getMetadata', ['path.txt']],
234
+ ['getMimetype', ['path.txt']],
235
+ ['getTimestamp', ['path.txt']],
236
+ ['getSize', ['path.txt']],
237
+ ['delete', ['path.txt']],
238
+ ['deleteDir', ['dirname']],
239
+ ['createDir', ['dirname']],
240
+ ['rename', ['name', 'other-name']],
241
+ ['setVisibility', ['name', AdapterInterface::VISIBILITY_PUBLIC]],
242
+ ['getVisibility', ['name']],
243
+ ];
244
  }
245
  }
vendor/league/flysystem/tests/UtilMimeTests.php CHANGED
@@ -29,6 +29,13 @@ class UtilMimeTests extends TestCase
29
  $passthru = true;
30
  }
31
 
 
 
 
 
 
 
 
32
  public function testNoExtension()
33
  {
34
  $this->assertEquals('text/plain', MimeType::detectByFileExtension('dir/file'));
29
  $passthru = true;
30
  }
31
 
32
+ public function testRetrievingAllMimetypes()
33
+ {
34
+ $map = MimeType::getExtensionToMimeTypeMap();
35
+ $this->assertInternalType('array', $map);
36
+ $this->assertEquals('application/epub+zip', $map['epub']);
37
+ }
38
+
39
  public function testNoExtension()
40
  {
41
  $this->assertEquals('text/plain', MimeType::detectByFileExtension('dir/file'));
vendor/paragonie/random_compat/LICENSE DELETED
@@ -1,22 +0,0 @@
1
- The MIT License (MIT)
2
-
3
- Copyright (c) 2015 Paragon Initiative Enterprises
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.
22
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/paragonie/random_compat/build-phar.sh DELETED
@@ -1,5 +0,0 @@
1
- #!/usr/bin/env bash
2
-
3
- basedir=$( dirname $( readlink -f ${BASH_SOURCE[0]} ) )
4
-
5
- php -dphar.readonly=0 "$basedir/other/build_phar.php" $*
 
 
 
 
 
vendor/paragonie/random_compat/composer.json DELETED
@@ -1,38 +0,0 @@
1
- {
2
- "name": "paragonie/random_compat",
3
- "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
4
- "keywords": [
5
- "csprng",
6
- "random",
7
- "polyfill",
8
- "pseudorandom"
9
- ],
10
- "license": "MIT",
11
- "type": "library",
12
- "authors": [
13
- {
14
- "name": "Paragon Initiative Enterprises",
15
- "email": "security@paragonie.com",
16
- "homepage": "https://paragonie.com"
17
- }
18
- ],
19
- "support": {
20
- "issues": "https://github.com/paragonie/random_compat/issues",
21
- "email": "info@paragonie.com",
22
- "source": "https://github.com/paragonie/random_compat"
23
- },
24
- "require": {
25
- "php": ">=5.2.0"
26
- },
27
- "require-dev": {
28
- "phpunit/phpunit": "4.*|5.*"
29
- },
30
- "suggest": {
31
- "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
32
- },
33
- "autoload": {
34
- "files": [
35
- "lib/random.php"
36
- ]
37
- }
38
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/paragonie/random_compat/dist/random_compat.phar.pubkey DELETED
@@ -1,5 +0,0 @@
1
- -----BEGIN PUBLIC KEY-----
2
- MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEEd+wCqJDrx5B4OldM0dQE0ZMX+lx1ZWm
3
- pui0SUqD4G29L3NGsz9UhJ/0HjBdbnkhIK5xviT0X5vtjacF6ajgcCArbTB+ds+p
4
- +h7Q084NuSuIpNb6YPfoUFgC/CL9kAoc
5
- -----END PUBLIC KEY-----
 
 
 
 
 
vendor/paragonie/random_compat/dist/random_compat.phar.pubkey.asc DELETED
@@ -1,11 +0,0 @@
1
- -----BEGIN PGP SIGNATURE-----
2
- Version: GnuPG v2.0.22 (MingW32)
3
-
4
- iQEcBAABAgAGBQJWtW1hAAoJEGuXocKCZATaJf0H+wbZGgskK1dcRTsuVJl9IWip
5
- QwGw/qIKI280SD6/ckoUMxKDCJiFuPR14zmqnS36k7N5UNPnpdTJTS8T11jttSpg
6
- 1LCmgpbEIpgaTah+cELDqFCav99fS+bEiAL5lWDAHBTE/XPjGVCqeehyPYref4IW
7
- NDBIEsvnHPHPLsn6X5jq4+Yj5oUixgxaMPiR+bcO4Sh+RzOVB6i2D0upWfRXBFXA
8
- NNnsg9/zjvoC7ZW73y9uSH+dPJTt/Vgfeiv52/v41XliyzbUyLalf02GNPY+9goV
9
- JHG1ulEEBJOCiUD9cE1PUIJwHA/HqyhHIvV350YoEFiHl8iSwm7SiZu5kPjaq74=
10
- =B6+8
11
- -----END PGP SIGNATURE-----
 
 
 
 
 
 
 
 
 
 
 
vendor/paragonie/random_compat/lib/byte_safe_strings.php DELETED
@@ -1,181 +0,0 @@
1
- <?php
2
- /**
3
- * Random_* Compatibility Library
4
- * for using the new PHP 7 random_* API in PHP 5 projects
5
- *
6
- * The MIT License (MIT)
7
- *
8
- * Copyright (c) 2015 - 2018 Paragon Initiative Enterprises
9
- *
10
- * Permission is hereby granted, free of charge, to any person obtaining a copy
11
- * of this software and associated documentation files (the "Software"), to deal
12
- * in the Software without restriction, including without limitation the rights
13
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
- * copies of the Software, and to permit persons to whom the Software is
15
- * furnished to do so, subject to the following conditions:
16
- *
17
- * The above copyright notice and this permission notice shall be included in
18
- * all copies or substantial portions of the Software.
19
- *
20
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
- * SOFTWARE.
27
- */
28
-
29
- if (!is_callable('RandomCompat_strlen')) {
30
- if (
31
- defined('MB_OVERLOAD_STRING') &&
32
- ini_get('mbstring.func_overload') & MB_OVERLOAD_STRING
33
- ) {
34
- /**
35
- * strlen() implementation that isn't brittle to mbstring.func_overload
36
- *
37
- * This version uses mb_strlen() in '8bit' mode to treat strings as raw
38
- * binary rather than UTF-8, ISO-8859-1, etc
39
- *
40
- * @param string $binary_string
41
- *
42
- * @throws TypeError
43
- *
44
- * @return int
45
- */
46
- function RandomCompat_strlen($binary_string)
47
- {
48
- if (!is_string($binary_string)) {
49
- throw new TypeError(
50
- 'RandomCompat_strlen() expects a string'
51
- );
52
- }
53
-
54
- return (int) mb_strlen($binary_string, '8bit');
55
- }
56
-
57
- } else {
58
- /**
59
- * strlen() implementation that isn't brittle to mbstring.func_overload
60
- *
61
- * This version just used the default strlen()
62
- *
63
- * @param string $binary_string
64
- *
65
- * @throws TypeError
66
- *
67
- * @return int
68
- */
69
- function RandomCompat_strlen($binary_string)
70
- {
71
- if (!is_string($binary_string)) {
72
- throw new TypeError(
73
- 'RandomCompat_strlen() expects a string'
74
- );
75
- }
76
- return (int) strlen($binary_string);
77
- }
78
- }
79
- }
80
-
81
- if (!is_callable('RandomCompat_substr')) {
82
-
83
- if (
84
- defined('MB_OVERLOAD_STRING')
85
- &&
86
- ini_get('mbstring.func_overload') & MB_OVERLOAD_STRING
87
- ) {
88
- /**
89
- * substr() implementation that isn't brittle to mbstring.func_overload
90
- *
91
- * This version uses mb_substr() in '8bit' mode to treat strings as raw
92
- * binary rather than UTF-8, ISO-8859-1, etc
93
- *
94
- * @param string $binary_string
95
- * @param int $start
96
- * @param int $length (optional)
97
- *
98
- * @throws TypeError
99
- *
100
- * @return string
101
- */
102
- function RandomCompat_substr($binary_string, $start, $length = null)
103
- {
104
- if (!is_string($binary_string)) {
105
- throw new TypeError(
106
- 'RandomCompat_substr(): First argument should be a string'
107
- );
108
- }
109
-
110
- if (!is_int($start)) {
111
- throw new TypeError(
112
- 'RandomCompat_substr(): Second argument should be an integer'
113
- );
114
- }
115
-
116
- if ($length === null) {
117
- /**
118
- * mb_substr($str, 0, NULL, '8bit') returns an empty string on
119
- * PHP 5.3, so we have to find the length ourselves.
120
- */
121
- $length = RandomCompat_strlen($binary_string) - $start;
122
- } elseif (!is_int($length)) {
123
- throw new TypeError(
124
- 'RandomCompat_substr(): Third argument should be an integer, or omitted'
125
- );
126
- }
127
-
128
- // Consistency with PHP's behavior
129
- if ($start === RandomCompat_strlen($binary_string) && $length === 0) {
130
- return '';
131
- }
132
- if ($start > RandomCompat_strlen($binary_string)) {
133
- return '';
134
- }
135
-
136
- return (string) mb_substr($binary_string, $start, $length, '8bit');
137
- }
138
-
139
- } else {
140
-
141
- /**
142
- * substr() implementation that isn't brittle to mbstring.func_overload
143
- *
144
- * This version just uses the default substr()
145
- *
146
- * @param string $binary_string
147
- * @param int $start
148
- * @param int $length (optional)
149
- *
150
- * @throws TypeError
151
- *
152
- * @return string
153
- */
154
- function RandomCompat_substr($binary_string, $start, $length = null)
155
- {
156
- if (!is_string($binary_string)) {
157
- throw new TypeError(
158
- 'RandomCompat_substr(): First argument should be a string'
159
- );
160
- }
161
-
162
- if (!is_int($start)) {
163
- throw new TypeError(
164
- 'RandomCompat_substr(): Second argument should be an integer'
165
- );
166
- }
167
-
168
- if ($length !== null) {
169
- if (!is_int($length)) {
170
- throw new TypeError(
171
- 'RandomCompat_substr(): Third argument should be an integer, or omitted'
172
- );
173
- }
174
-
175
- return (string) substr($binary_string, $start, $length);
176
- }
177
-
178
- return (string) substr($binary_string, $start);
179
- }
180
- }
181
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/paragonie/random_compat/lib/cast_to_int.php DELETED
@@ -1,75 +0,0 @@
1
- <?php
2
- /**
3
- * Random_* Compatibility Library
4
- * for using the new PHP 7 random_* API in PHP 5 projects
5
- *
6
- * The MIT License (MIT)
7
- *
8
- * Copyright (c) 2015 - 2018 Paragon Initiative Enterprises
9
- *
10
- * Permission is hereby granted, free of charge, to any person obtaining a copy
11
- * of this software and associated documentation files (the "Software"), to deal
12
- * in the Software without restriction, including without limitation the rights
13
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
- * copies of the Software, and to permit persons to whom the Software is
15
- * furnished to do so, subject to the following conditions:
16
- *
17
- * The above copyright notice and this permission notice shall be included in
18
- * all copies or substantial portions of the Software.
19
- *
20
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
- * SOFTWARE.
27
- */
28
-
29
- if (!is_callable('RandomCompat_intval')) {
30
-
31
- /**
32
- * Cast to an integer if we can, safely.
33
- *
34
- * If you pass it a float in the range (~PHP_INT_MAX, PHP_INT_MAX)
35
- * (non-inclusive), it will sanely cast it to an int. If you it's equal to
36
- * ~PHP_INT_MAX or PHP_INT_MAX, we let it fail as not an integer. Floats
37
- * lose precision, so the <= and => operators might accidentally let a float
38
- * through.
39
- *
40
- * @param int|float $number The number we want to convert to an int
41
- * @param bool $fail_open Set to true to not throw an exception
42
- *
43
- * @return float|int
44
- * @psalm-suppress InvalidReturnType
45
- *
46
- * @throws TypeError
47
- */
48
- function RandomCompat_intval($number, $fail_open = false)
49
- {
50
- if (is_int($number) || is_float($number)) {
51
- $number += 0;
52
- } elseif (is_numeric($number)) {
53
- $number += 0;
54
- }
55
-
56
- if (
57
- is_float($number)
58
- &&
59
- $number > ~PHP_INT_MAX
60
- &&
61
- $number < PHP_INT_MAX
62
- ) {
63
- $number = (int) $number;
64
- }
65
-
66
- if (is_int($number)) {
67
- return (int) $number;
68
- } elseif (!$fail_open) {
69
- throw new TypeError(
70
- 'Expected an integer.'
71
- );
72
- }
73
- return $number;
74
- }
75
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/paragonie/random_compat/lib/error_polyfill.php DELETED
@@ -1,49 +0,0 @@
1
- <?php
2
- /**
3
- * Random_* Compatibility Library
4
- * for using the new PHP 7 random_* API in PHP 5 projects
5
- *
6
- * The MIT License (MIT)
7
- *
8
- * Copyright (c) 2015 - 2018 Paragon Initiative Enterprises
9
- *
10
- * Permission is hereby granted, free of charge, to any person obtaining a copy
11
- * of this software and associated documentation files (the "Software"), to deal
12
- * in the Software without restriction, including without limitation the rights
13
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
- * copies of the Software, and to permit persons to whom the Software is
15
- * furnished to do so, subject to the following conditions:
16
- *
17
- * The above copyright notice and this permission notice shall be included in
18
- * all copies or substantial portions of the Software.
19
- *
20
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
- * SOFTWARE.
27
- */
28
-
29
- if (!class_exists('Error', false)) {
30
- // We can't really avoid making this extend Exception in PHP 5.
31
- class Error extends Exception
32
- {
33
-
34
- }
35
- }
36
-
37
- if (!class_exists('TypeError', false)) {
38
- if (is_subclass_of('Error', 'Exception')) {
39
- class TypeError extends Error
40
- {
41
-
42
- }
43
- } else {
44
- class TypeError extends Exception
45
- {
46
-
47
- }
48
- }
49
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/paragonie/random_compat/lib/random.php DELETED
@@ -1,226 +0,0 @@
1
- <?php
2
- /**
3
- * Random_* Compatibility Library
4
- * for using the new PHP 7 random_* API in PHP 5 projects
5
- *
6
- * @version 2.0.15
7
- * @released 2018-06-08
8
- *
9
- * The MIT License (MIT)
10
- *
11
- * Copyright (c) 2015 - 2018 Paragon Initiative Enterprises
12
- *
13
- * Permission is hereby granted, free of charge, to any person obtaining a copy
14
- * of this software and associated documentation files (the "Software"), to deal
15
- * in the Software without restriction, including without limitation the rights
16
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17
- * copies of the Software, and to permit persons to whom the Software is
18
- * furnished to do so, subject to the following conditions:
19
- *
20
- * The above copyright notice and this permission notice shall be included in
21
- * all copies or substantial portions of the Software.
22
- *
23
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29
- * SOFTWARE.
30
- */
31
-
32
- if (!defined('PHP_VERSION_ID')) {
33
- // This constant was introduced in PHP 5.2.7
34
- $RandomCompatversion = array_map('intval', explode('.', PHP_VERSION));
35
- define(
36
- 'PHP_VERSION_ID',
37
- $RandomCompatversion[0] * 10000
38
- + $RandomCompatversion[1] * 100
39
- + $RandomCompatversion[2]
40
- );
41
- $RandomCompatversion = null;
42
- }
43
-
44
- /**
45
- * PHP 7.0.0 and newer have these functions natively.
46
- */
47
- if (PHP_VERSION_ID >= 70000) {
48
- return;
49
- }
50
-
51
- if (!defined('RANDOM_COMPAT_READ_BUFFER')) {
52
- define('RANDOM_COMPAT_READ_BUFFER', 8);
53
- }
54
-
55
- $RandomCompatDIR = dirname(__FILE__);
56
-
57
- require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'byte_safe_strings.php';
58
- require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'cast_to_int.php';
59
- require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'error_polyfill.php';
60
-
61
- if (!is_callable('random_bytes')) {
62
- /**
63
- * PHP 5.2.0 - 5.6.x way to implement random_bytes()
64
- *
65
- * We use conditional statements here to define the function in accordance
66
- * to the operating environment. It's a micro-optimization.
67
- *
68
- * In order of preference:
69
- * 1. Use libsodium if available.
70
- * 2. fread() /dev/urandom if available (never on Windows)
71
- * 3. mcrypt_create_iv($bytes, MCRYPT_DEV_URANDOM)
72
- * 4. COM('CAPICOM.Utilities.1')->GetRandom()
73
- *
74
- * See RATIONALE.md for our reasoning behind this particular order
75
- */
76
- if (extension_loaded('libsodium')) {
77
- // See random_bytes_libsodium.php
78
- if (PHP_VERSION_ID >= 50300 && is_callable('\\Sodium\\randombytes_buf')) {
79
- require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_bytes_libsodium.php';
80
- } elseif (method_exists('Sodium', 'randombytes_buf')) {
81
- require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_bytes_libsodium_legacy.php';
82
- }
83
- }
84
-
85
- /**
86
- * Reading directly from /dev/urandom:
87
- */
88
- if (DIRECTORY_SEPARATOR === '/') {
89
- // DIRECTORY_SEPARATOR === '/' on Unix-like OSes -- this is a fast
90
- // way to exclude Windows.
91
- $RandomCompatUrandom = true;
92
- $RandomCompat_basedir = ini_get('open_basedir');
93
-
94
- if (!empty($RandomCompat_basedir)) {
95
- $RandomCompat_open_basedir = explode(
96
- PATH_SEPARATOR,
97
- strtolower($RandomCompat_basedir)
98
- );
99
- $RandomCompatUrandom = (array() !== array_intersect(
100
- array('/dev', '/dev/', '/dev/urandom'),
101
- $RandomCompat_open_basedir
102
- ));
103
- $RandomCompat_open_basedir = null;
104
- }
105
-
106
- if (
107
- !is_callable('random_bytes')
108
- &&
109
- $RandomCompatUrandom
110
- &&
111
- @is_readable('/dev/urandom')
112
- ) {
113
- // Error suppression on is_readable() in case of an open_basedir
114
- // or safe_mode failure. All we care about is whether or not we
115
- // can read it at this point. If the PHP environment is going to
116
- // panic over trying to see if the file can be read in the first
117
- // place, that is not helpful to us here.
118
-
119
- // See random_bytes_dev_urandom.php
120
- require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_bytes_dev_urandom.php';
121
- }
122
- // Unset variables after use
123
- $RandomCompat_basedir = null;
124
- } else {
125
- $RandomCompatUrandom = false;
126
- }
127
-
128
- /**
129
- * mcrypt_create_iv()
130
- *
131
- * We only want to use mcypt_create_iv() if:
132
- *
133
- * - random_bytes() hasn't already been defined
134
- * - the mcrypt extensions is loaded
135
- * - One of these two conditions is true:
136
- * - We're on Windows (DIRECTORY_SEPARATOR !== '/')
137
- * - We're not on Windows and /dev/urandom is readabale
138
- * (i.e. we're not in a chroot jail)
139
- * - Special case:
140
- * - If we're not on Windows, but the PHP version is between
141
- * 5.6.10 and 5.6.12, we don't want to use mcrypt. It will
142
- * hang indefinitely. This is bad.
143
- * - If we're on Windows, we want to use PHP >= 5.3.7 or else
144
- * we get insufficient entropy errors.
145
- */
146
- if (
147
- !is_callable('random_bytes')
148
- &&
149
- // Windows on PHP < 5.3.7 is broken, but non-Windows is not known to be.
150
- (DIRECTORY_SEPARATOR === '/' || PHP_VERSION_ID >= 50307)
151
- &&
152
- // Prevent this code from hanging indefinitely on non-Windows;
153
- // see https://bugs.php.net/bug.php?id=69833
154
- (
155
- DIRECTORY_SEPARATOR !== '/' ||
156
- (PHP_VERSION_ID <= 50609 || PHP_VERSION_ID >= 50613)
157
- )
158
- &&
159
- extension_loaded('mcrypt')
160
- ) {
161
- // See random_bytes_mcrypt.php
162
- require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_bytes_mcrypt.php';
163
- }
164
- $RandomCompatUrandom = null;
165
-
166
- /**
167
- * This is a Windows-specific fallback, for when the mcrypt extension
168
- * isn't loaded.
169
- */
170
- if (
171
- !is_callable('random_bytes')
172
- &&
173
- extension_loaded('com_dotnet')
174
- &&
175
- class_exists('COM')
176
- ) {
177
- $RandomCompat_disabled_classes = preg_split(
178
- '#\s*,\s*#',
179
- strtolower(ini_get('disable_classes'))
180
- );
181
-
182
- if (!in_array('com', $RandomCompat_disabled_classes)) {
183
- try {
184
- $RandomCompatCOMtest = new COM('CAPICOM.Utilities.1');
185
- if (method_exists($RandomCompatCOMtest, 'GetRandom')) {
186
- // See random_bytes_com_dotnet.php
187
- require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_bytes_com_dotnet.php';
188
- }
189
- } catch (com_exception $e) {
190
- // Don't try to use it.
191
- }
192
- }
193
- $RandomCompat_disabled_classes = null;
194
- $RandomCompatCOMtest = null;
195
- }
196
-
197
- /**
198
- * throw new Exception
199
- */
200
- if (!is_callable('random_bytes')) {
201
- /**
202
- * We don't have any more options, so let's throw an exception right now
203
- * and hope the developer won't let it fail silently.
204
- *
205
- * @param mixed $length
206
- * @psalm-suppress MissingReturnType
207
- * @psalm-suppress InvalidReturnType
208
- * @throws Exception
209
- * @return string
210
- */
211
- function random_bytes($length)
212
- {
213
- unset($length); // Suppress "variable not used" warnings.
214
- throw new Exception(
215
- 'There is no suitable CSPRNG installed on your system'
216
- );
217
- return '';
218
- }
219
- }
220
- }
221
-
222
- if (!is_callable('random_int')) {
223
- require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_int.php';
224
- }
225
-
226
- $RandomCompatDIR = null;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/paragonie/random_compat/lib/random_bytes_com_dotnet.php DELETED
@@ -1,88 +0,0 @@
1
- <?php
2
- /**
3
- * Random_* Compatibility Library
4
- * for using the new PHP 7 random_* API in PHP 5 projects
5
- *
6
- * The MIT License (MIT)
7
- *
8
- * Copyright (c) 2015 - 2018 Paragon Initiative Enterprises
9
- *
10
- * Permission is hereby granted, free of charge, to any person obtaining a copy
11
- * of this software and associated documentation files (the "Software"), to deal
12
- * in the Software without restriction, including without limitation the rights
13
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
- * copies of the Software, and to permit persons to whom the Software is
15
- * furnished to do so, subject to the following conditions:
16
- *
17
- * The above copyright notice and this permission notice shall be included in
18
- * all copies or substantial portions of the Software.
19
- *
20
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
- * SOFTWARE.
27
- */
28
-
29
- if (!is_callable('random_bytes')) {
30
- /**
31
- * Windows with PHP < 5.3.0 will not have the function
32
- * openssl_random_pseudo_bytes() available, so let's use
33
- * CAPICOM to work around this deficiency.
34
- *
35
- * @param int $bytes
36
- *
37
- * @throws Exception
38
- *
39
- * @return string
40
- */
41
- function random_bytes($bytes)
42
- {
43
- try {
44
- $bytes = RandomCompat_intval($bytes);
45
- } catch (TypeError $ex) {
46
- throw new TypeError(
47
- 'random_bytes(): $bytes must be an integer'
48
- );
49
- }
50
-
51
- if ($bytes < 1) {
52
- throw new Error(
53
- 'Length must be greater than 0'
54
- );
55
- }
56
-
57
- $buf = '';
58
- if (!class_exists('COM')) {
59
- throw new Error(
60
- 'COM does not exist'
61
- );
62
- }
63
- $util = new COM('CAPICOM.Utilities.1');
64
- $execCount = 0;
65
-
66
- /**
67
- * Let's not let it loop forever. If we run N times and fail to
68
- * get N bytes of random data, then CAPICOM has failed us.
69
- */
70
- do {
71
- $buf .= base64_decode($util->GetRandom($bytes, 0));
72
- if (RandomCompat_strlen($buf) >= $bytes) {
73
- /**
74
- * Return our random entropy buffer here:
75
- */
76
- return RandomCompat_substr($buf, 0, $bytes);
77
- }
78
- ++$execCount;
79
- } while ($execCount < $bytes);
80
-
81
- /**
82
- * If we reach here, PHP has failed us.
83
- */
84
- throw new Exception(
85
- 'Could not gather sufficient random data'
86
- );
87
- }
88
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/paragonie/random_compat/lib/random_bytes_dev_urandom.php DELETED
@@ -1,167 +0,0 @@
1
- <?php
2
- /**
3
- * Random_* Compatibility Library
4
- * for using the new PHP 7 random_* API in PHP 5 projects
5
- *
6
- * The MIT License (MIT)
7
- *
8
- * Copyright (c) 2015 - 2018 Paragon Initiative Enterprises
9
- *
10
- * Permission is hereby granted, free of charge, to any person obtaining a copy
11
- * of this software and associated documentation files (the "Software"), to deal
12
- * in the Software without restriction, including without limitation the rights
13
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
- * copies of the Software, and to permit persons to whom the Software is
15
- * furnished to do so, subject to the following conditions:
16
- *
17
- * The above copyright notice and this permission notice shall be included in
18
- * all copies or substantial portions of the Software.
19
- *
20
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
- * SOFTWARE.
27
- */
28
-
29
- if (!defined('RANDOM_COMPAT_READ_BUFFER')) {
30
- define('RANDOM_COMPAT_READ_BUFFER', 8);
31
- }
32
-
33
- if (!is_callable('random_bytes')) {
34
- /**
35
- * Unless open_basedir is enabled, use /dev/urandom for
36
- * random numbers in accordance with best practices
37
- *
38
- * Why we use /dev/urandom and not /dev/random
39
- * @ref http://sockpuppet.org/blog/2014/02/25/safely-generate-random-numbers
40
- *
41
- * @param int $bytes
42
- *
43
- * @throws Exception
44
- *
45
- * @return string
46
- */
47
- function random_bytes($bytes)
48
- {
49
- static $fp = null;
50
- /**
51
- * This block should only be run once
52
- */
53
- if (empty($fp)) {
54
- /**
55
- * We use /dev/urandom if it is a char device.
56
- * We never fall back to /dev/random
57
- */
58
- $fp = fopen('/dev/urandom', 'rb');
59
- if (!empty($fp)) {
60
- $st = fstat($fp);
61
- if (($st['mode'] & 0170000) !== 020000) {
62
- fclose($fp);
63
- $fp = false;
64
- }
65
- }
66
-
67
- if (!empty($fp)) {
68
- /**
69
- * stream_set_read_buffer() does not exist in HHVM
70
- *
71
- * If we don't set the stream's read buffer to 0, PHP will
72
- * internally buffer 8192 bytes, which can waste entropy
73
- *
74
- * stream_set_read_buffer returns 0 on success
75
- */
76
- if (is_callable('stream_set_read_buffer')) {
77
- stream_set_read_buffer($fp, RANDOM_COMPAT_READ_BUFFER);
78
- }
79
- if (is_callable('stream_set_chunk_size')) {
80
- stream_set_chunk_size($fp, RANDOM_COMPAT_READ_BUFFER);
81
- }
82
- }
83
- }
84
-
85
- try {
86
- $bytes = RandomCompat_intval($bytes);
87
- } catch (TypeError $ex) {
88
- throw new TypeError(
89
- 'random_bytes(): $bytes must be an integer'
90
- );
91
- }
92
-
93
- if ($bytes < 1) {
94
- throw new Error(
95
- 'Length must be greater than 0'
96
- );
97
- }
98
-
99
- /**
100
- * This if() block only runs if we managed to open a file handle
101
- *
102
- * It does not belong in an else {} block, because the above
103
- * if (empty($fp)) line is logic that should only be run once per
104
- * page load.
105
- */
106
- if (!empty($fp)) {
107
- /**
108
- * @var int
109
- */
110
- $remaining = $bytes;
111
-
112
- /**
113
- * @var string|bool
114
- */
115
- $buf = '';
116
-
117
- /**
118
- * We use fread() in a loop to protect against partial reads
119
- */
120
- do {
121
- /**
122
- * @var string|bool
123
- */
124
- $read = fread($fp, $remaining);
125
- if (!is_string($read)) {
126
- if ($read === false) {
127
- /**
128
- * We cannot safely read from the file. Exit the
129
- * do-while loop and trigger the exception condition
130
- *
131
- * @var string|bool
132
- */
133
- $buf = false;
134
- break;
135
- }
136
- }
137
- /**
138
- * Decrease the number of bytes returned from remaining
139
- */
140
- $remaining -= RandomCompat_strlen($read);
141
- /**
142
- * @var string|bool
143
- */
144
- $buf = $buf . $read;
145
- } while ($remaining > 0);
146
-
147
- /**
148
- * Is our result valid?
149
- */
150
- if (is_string($buf)) {
151
- if (RandomCompat_strlen($buf) === $bytes) {
152
- /**
153
- * Return our random entropy buffer here:
154
- */
155
- return $buf;
156
- }
157
- }
158
- }
159
-
160
- /**
161
- * If we reach here, PHP has failed us.
162
- */
163
- throw new Exception(
164
- 'Error reading from source device'
165
- );
166
- }
167
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/paragonie/random_compat/lib/random_bytes_libsodium.php DELETED
@@ -1,88 +0,0 @@
1
- <?php
2
- /**
3
- * Random_* Compatibility Library
4
- * for using the new PHP 7 random_* API in PHP 5 projects
5
- *
6
- * The MIT License (MIT)
7
- *
8
- * Copyright (c) 2015 - 2018 Paragon Initiative Enterprises
9
- *
10
- * Permission is hereby granted, free of charge, to any person obtaining a copy
11
- * of this software and associated documentation files (the "Software"), to deal
12
- * in the Software without restriction, including without limitation the rights
13
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
- * copies of the Software, and to permit persons to whom the Software is
15
- * furnished to do so, subject to the following conditions:
16
- *
17
- * The above copyright notice and this permission notice shall be included in
18
- * all copies or substantial portions of the Software.
19
- *
20
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
- * SOFTWARE.
27
- */
28
-
29
- if (!is_callable('random_bytes')) {
30
- /**
31
- * If the libsodium PHP extension is loaded, we'll use it above any other
32
- * solution.
33
- *
34
- * libsodium-php project:
35
- * @ref https://github.com/jedisct1/libsodium-php
36
- *
37
- * @param int $bytes
38
- *
39
- * @throws Exception
40
- *
41
- * @return string
42
- */
43
- function random_bytes($bytes)
44
- {
45
- try {
46
- $bytes = RandomCompat_intval($bytes);
47
- } catch (TypeError $ex) {
48
- throw new TypeError(
49
- 'random_bytes(): $bytes must be an integer'
50
- );
51
- }
52
-
53
- if ($bytes < 1) {
54
- throw new Error(
55
- 'Length must be greater than 0'
56
- );
57
- }
58
-
59
- /**
60
- * \Sodium\randombytes_buf() doesn't allow more than 2147483647 bytes to be
61
- * generated in one invocation.
62
- */
63
- if ($bytes > 2147483647) {
64
- $buf = '';
65
- for ($i = 0; $i < $bytes; $i += 1073741824) {
66
- $n = ($bytes - $i) > 1073741824
67
- ? 1073741824
68
- : $bytes - $i;
69
- $buf .= \Sodium\randombytes_buf($n);
70
- }
71
- } else {
72
- $buf = \Sodium\randombytes_buf($bytes);
73
- }
74
-
75
- if ($buf !== false) {
76
- if (RandomCompat_strlen($buf) === $bytes) {
77
- return $buf;
78
- }
79
- }
80
-
81
- /**
82
- * If we reach here, PHP has failed us.
83
- */
84
- throw new Exception(
85
- 'Could not gather sufficient random data'
86
- );
87
- }
88
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/paragonie/random_compat/lib/random_bytes_libsodium_legacy.php DELETED
@@ -1,92 +0,0 @@
1
- <?php
2
- /**
3
- * Random_* Compatibility Library
4
- * for using the new PHP 7 random_* API in PHP 5 projects
5
- *
6
- * The MIT License (MIT)
7
- *
8
- * Copyright (c) 2015 - 2018 Paragon Initiative Enterprises
9
- *
10
- * Permission is hereby granted, free of charge, to any person obtaining a copy
11
- * of this software and associated documentation files (the "Software"), to deal
12
- * in the Software without restriction, including without limitation the rights
13
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
- * copies of the Software, and to permit persons to whom the Software is
15
- * furnished to do so, subject to the following conditions:
16
- *
17
- * The above copyright notice and this permission notice shall be included in
18
- * all copies or substantial portions of the Software.
19
- *
20
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
- * SOFTWARE.
27
- */
28
-
29
- if (!is_callable('random_bytes')) {
30
- /**
31
- * If the libsodium PHP extension is loaded, we'll use it above any other
32
- * solution.
33
- *
34
- * libsodium-php project:
35
- * @ref https://github.com/jedisct1/libsodium-php
36
- *
37
- * @param int $bytes
38
- *
39
- * @throws Exception
40
- *
41
- * @return string
42
- */
43
- function random_bytes($bytes)
44
- {
45
- try {
46
- $bytes = RandomCompat_intval($bytes);
47
- } catch (TypeError $ex) {
48
- throw new TypeError(
49
- 'random_bytes(): $bytes must be an integer'
50
- );
51
- }
52
-
53
- if ($bytes < 1) {
54
- throw new Error(
55
- 'Length must be greater than 0'
56
- );
57
- }
58
-
59
- /**
60
- * @var string
61
- */
62
- $buf = '';
63
-
64
- /**
65
- * \Sodium\randombytes_buf() doesn't allow more than 2147483647 bytes to be
66
- * generated in one invocation.
67
- */
68
- if ($bytes > 2147483647) {
69
- for ($i = 0; $i < $bytes; $i += 1073741824) {
70
- $n = ($bytes - $i) > 1073741824
71
- ? 1073741824
72
- : $bytes - $i;
73
- $buf .= Sodium::randombytes_buf((int) $n);
74
- }
75
- } else {
76
- $buf .= Sodium::randombytes_buf((int) $bytes);
77
- }
78
-
79
- if (is_string($buf)) {
80
- if (RandomCompat_strlen($buf) === $bytes) {
81
- return $buf;
82
- }
83
- }
84
-
85
- /**
86
- * If we reach here, PHP has failed us.
87
- */
88
- throw new Exception(
89
- 'Could not gather sufficient random data'
90
- );
91
- }
92
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/paragonie/random_compat/lib/random_bytes_mcrypt.php DELETED
@@ -1,77 +0,0 @@
1
- <?php
2
- /**
3
- * Random_* Compatibility Library
4
- * for using the new PHP 7 random_* API in PHP 5 projects
5
- *
6
- * The MIT License (MIT)
7
- *
8
- * Copyright (c) 2015 - 2018 Paragon Initiative Enterprises
9
- *
10
- * Permission is hereby granted, free of charge, to any person obtaining a copy
11
- * of this software and associated documentation files (the "Software"), to deal
12
- * in the Software without restriction, including without limitation the rights
13
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
- * copies of the Software, and to permit persons to whom the Software is
15
- * furnished to do so, subject to the following conditions:
16
- *
17
- * The above copyright notice and this permission notice shall be included in
18
- * all copies or substantial portions of the Software.
19
- *
20
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
- * SOFTWARE.
27
- */
28
-
29
- if (!is_callable('random_bytes')) {
30
- /**
31
- * Powered by ext/mcrypt (and thankfully NOT libmcrypt)
32
- *
33
- * @ref https://bugs.php.net/bug.php?id=55169
34
- * @ref https://github.com/php/php-src/blob/c568ffe5171d942161fc8dda066bce844bdef676/ext/mcrypt/mcrypt.c#L1321-L1386
35
- *
36
- * @param int $bytes
37
- *
38
- * @throws Exception
39
- *
40
- * @return string
41
- */
42
- function random_bytes($bytes)
43
- {
44
- try {
45
- $bytes = RandomCompat_intval($bytes);
46
- } catch (TypeError $ex) {
47
- throw new TypeError(
48
- 'random_bytes(): $bytes must be an integer'
49
- );
50
- }
51
-
52
- if ($bytes < 1) {
53
- throw new Error(
54
- 'Length must be greater than 0'
55
- );
56
- }
57
-
58
- $buf = @mcrypt_create_iv($bytes, MCRYPT_DEV_URANDOM);
59
- if (
60
- $buf !== false
61
- &&
62
- RandomCompat_strlen($buf) === $bytes
63
- ) {
64
- /**
65
- * Return our random entropy buffer here:
66
- */
67
- return $buf;
68
- }
69
-
70
- /**
71
- * If we reach here, PHP has failed us.
72
- */
73
- throw new Exception(
74
- 'Could not gather sufficient random data'
75
- );
76
- }
77
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/paragonie/random_compat/lib/random_int.php DELETED
@@ -1,190 +0,0 @@
1
- <?php
2
-
3
- if (!is_callable('random_int')) {
4
- /**
5
- * Random_* Compatibility Library
6
- * for using the new PHP 7 random_* API in PHP 5 projects
7
- *
8
- * The MIT License (MIT)
9
- *
10
- * Copyright (c) 2015 - 2018 Paragon Initiative Enterprises
11
- *
12
- * Permission is hereby granted, free of charge, to any person obtaining a copy
13
- * of this software and associated documentation files (the "Software"), to deal
14
- * in the Software without restriction, including without limitation the rights
15
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16
- * copies of the Software, and to permit persons to whom the Software is
17
- * furnished to do so, subject to the following conditions:
18
- *
19
- * The above copyright notice and this permission notice shall be included in
20
- * all copies or substantial portions of the Software.
21
- *
22
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28
- * SOFTWARE.
29
- */
30
-
31
- /**
32
- * Fetch a random integer between $min and $max inclusive
33
- *
34
- * @param int $min
35
- * @param int $max
36
- *
37
- * @throws Exception
38
- *
39
- * @return int
40
- */
41
- function random_int($min, $max)
42
- {
43
- /**
44
- * Type and input logic checks
45
- *
46
- * If you pass it a float in the range (~PHP_INT_MAX, PHP_INT_MAX)
47
- * (non-inclusive), it will sanely cast it to an int. If you it's equal to
48
- * ~PHP_INT_MAX or PHP_INT_MAX, we let it fail as not an integer. Floats
49
- * lose precision, so the <= and => operators might accidentally let a float
50
- * through.
51
- */
52
-
53
- try {
54
- $min = RandomCompat_intval($min);
55
- } catch (TypeError $ex) {
56
- throw new TypeError(
57
- 'random_int(): $min must be an integer'
58
- );
59
- }
60
-
61
- try {
62
- $max = RandomCompat_intval($max);
63
- } catch (TypeError $ex) {
64
- throw new TypeError(
65
- 'random_int(): $max must be an integer'
66
- );
67
- }
68
-
69
- /**
70
- * Now that we've verified our weak typing system has given us an integer,
71
- * let's validate the logic then we can move forward with generating random
72
- * integers along a given range.
73
- */
74
- if ($min > $max) {
75
- throw new Error(
76
- 'Minimum value must be less than or equal to the maximum value'
77
- );
78
- }
79
-
80
- if ($max === $min) {
81
- return (int) $min;
82
- }
83
-
84
- /**
85
- * Initialize variables to 0
86
- *
87
- * We want to store:
88
- * $bytes => the number of random bytes we need
89
- * $mask => an integer bitmask (for use with the &) operator
90
- * so we can minimize the number of discards
91
- */
92
- $attempts = $bits = $bytes = $mask = $valueShift = 0;
93
-
94
- /**
95
- * At this point, $range is a positive number greater than 0. It might
96
- * overflow, however, if $max - $min > PHP_INT_MAX. PHP will cast it to
97
- * a float and we will lose some precision.
98
- */
99
- $range = $max - $min;
100
-
101
- /**
102
- * Test for integer overflow:
103
- */
104
- if (!is_int($range)) {
105
-
106
- /**
107
- * Still safely calculate wider ranges.
108
- * Provided by @CodesInChaos, @oittaa
109
- *
110
- * @ref https://gist.github.com/CodesInChaos/03f9ea0b58e8b2b8d435
111
- *
112
- * We use ~0 as a mask in this case because it generates all 1s
113
- *
114
- * @ref https://eval.in/400356 (32-bit)
115
- * @ref http://3v4l.org/XX9r5 (64-bit)
116
- */
117
- $bytes = PHP_INT_SIZE;
118
- $mask = ~0;
119
-
120
- } else {
121
-
122
- /**
123
- * $bits is effectively ceil(log($range, 2)) without dealing with
124
- * type juggling
125
- */
126
- while ($range > 0) {
127
- if ($bits % 8 === 0) {
128
- ++$bytes;
129
- }
130
- ++$bits;
131
- $range >>= 1;
132
- $mask = $mask << 1 | 1;
133
- }
134
- $valueShift = $min;
135
- }
136
-
137
- $val = 0;
138
- /**
139
- * Now that we have our parameters set up, let's begin generating
140
- * random integers until one falls between $min and $max
141
- */
142
- do {
143
- /**
144
- * The rejection probability is at most 0.5, so this corresponds
145
- * to a failure probability of 2^-128 for a working RNG
146
- */
147
- if ($attempts > 128) {
148
- throw new Exception(
149
- 'random_int: RNG is broken - too many rejections'
150
- );
151
- }
152
-
153
- /**
154
- * Let's grab the necessary number of random bytes
155
- */
156
- $randomByteString = random_bytes($bytes);
157
-
158
- /**
159
- * Let's turn $randomByteString into an integer
160
- *
161
- * This uses bitwise operators (<< and |) to build an integer
162
- * out of the values extracted from ord()
163
- *
164
- * Example: [9F] | [6D] | [32] | [0C] =>
165
- * 159 + 27904 + 3276800 + 201326592 =>
166
- * 204631455
167
- */
168
- $val &= 0;
169
- for ($i = 0; $i < $bytes; ++$i) {
170
- $val |= ord($randomByteString[$i]) << ($i * 8);
171
- }
172
-
173
- /**
174
- * Apply mask
175
- */
176
- $val &= $mask;
177
- $val += $valueShift;
178
-
179
- ++$attempts;
180
- /**
181
- * If $val overflows to a floating point number,
182
- * ... or is larger than $max,
183
- * ... or smaller than $min,
184
- * then try again.
185
- */
186
- } while (!is_int($val) || $val > $max || $val < $min);
187
-
188
- return (int) $val;
189
- }
190
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/paragonie/random_compat/other/build_phar.php DELETED
@@ -1,57 +0,0 @@
1
- <?php
2
- $dist = dirname(__DIR__).'/dist';
3
- if (!is_dir($dist)) {
4
- mkdir($dist, 0755);
5
- }
6
- if (file_exists($dist.'/random_compat.phar')) {
7
- unlink($dist.'/random_compat.phar');
8
- }
9
- $phar = new Phar(
10
- $dist.'/random_compat.phar',
11
- FilesystemIterator::CURRENT_AS_FILEINFO | \FilesystemIterator::KEY_AS_FILENAME,
12
- 'random_compat.phar'
13
- );
14
- rename(
15
- dirname(__DIR__).'/lib/random.php',
16
- dirname(__DIR__).'/lib/index.php'
17
- );
18
- $phar->buildFromDirectory(dirname(__DIR__).'/lib');
19
- rename(
20
- dirname(__DIR__).'/lib/index.php',
21
- dirname(__DIR__).'/lib/random.php'
22
- );
23
-
24
- /**
25
- * If we pass an (optional) path to a private key as a second argument, we will
26
- * sign the Phar with OpenSSL.
27
- *
28
- * If you leave this out, it will produce an unsigned .phar!
29
- */
30
- if ($argc > 1) {
31
- if (!@is_readable($argv[1])) {
32
- echo 'Could not read the private key file:', $argv[1], "\n";
33
- exit(255);
34
- }
35
- $pkeyFile = file_get_contents($argv[1]);
36
-
37
- $private = openssl_get_privatekey($pkeyFile);
38
- if ($private !== false) {
39
- $pkey = '';
40
- openssl_pkey_export($private, $pkey);
41
- $phar->setSignatureAlgorithm(Phar::OPENSSL, $pkey);
42
-
43
- /**
44
- * Save the corresponding public key to the file
45
- */
46
- if (!@is_readable($dist.'/random_compat.phar.pubkey')) {
47
- $details = openssl_pkey_get_details($private);
48
- file_put_contents(
49
- $dist.'/random_compat.phar.pubkey',
50
- $details['key']
51
- );
52
- }
53
- } else {
54
- echo 'An error occurred reading the private key from OpenSSL.', "\n";
55
- exit(255);
56
- }
57
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/paragonie/random_compat/psalm-autoload.php DELETED
@@ -1,9 +0,0 @@
1
- <?php
2
-
3
- require_once 'lib/byte_safe_strings.php';
4
- require_once 'lib/cast_to_int.php';
5
- require_once 'lib/error_polyfill.php';
6
- require_once 'other/ide_stubs/libsodium.php';
7
- require_once 'lib/random.php';
8
-
9
- $int = random_int(0, 65536);
 
 
 
 
 
 
 
 
 
vendor/paragonie/random_compat/psalm.xml DELETED
@@ -1,19 +0,0 @@
1
- <?xml version="1.0"?>
2
- <psalm
3
- autoloader="psalm-autoload.php"
4
- stopOnFirstError="false"
5
- useDocblockTypes="true"
6
- >
7
- <projectFiles>
8
- <directory name="lib" />
9
- </projectFiles>
10
- <issueHandlers>
11
- <RedundantConditionGivenDocblockType errorLevel="info" />
12
- <UnresolvableInclude errorLevel="info" />
13
- <DuplicateClass errorLevel="info" />
14
- <InvalidOperand errorLevel="info" />
15
- <UndefinedConstant errorLevel="info" />
16
- <MissingReturnType errorLevel="info" />
17
- <InvalidReturnType errorLevel="info" />
18
- </issueHandlers>
19
- </psalm>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/vakata/jstree/README.md CHANGED
@@ -62,8 +62,8 @@ To get started you need 3 things in your page:
62
  ```html
63
  <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
64
 
65
- <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/jstree/3.3.3/themes/default/style.min.css" />
66
- <script src="//cdnjs.cloudflare.com/ajax/libs/jstree/3.3.3/jstree.min.js"></script>
67
  ```
68
 
69
  _If you decide to host jstree yourself - the files are located in the `dist` folder. You can safely ignore the `dist/libs` folder._
62
  ```html
63
  <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
64
 
65
+ <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/jstree/3.3.5/themes/default/style.min.css" />
66
+ <script src="//cdnjs.cloudflare.com/ajax/libs/jstree/3.3.5/jstree.min.js"></script>
67
  ```
68
 
69
  _If you decide to host jstree yourself - the files are located in the `dist` folder. You can safely ignore the `dist/libs` folder._
vendor/vakata/jstree/bower.json CHANGED
@@ -1,7 +1,7 @@
1
  {
2
  "name": "jstree",
3
  "license": "MIT",
4
- "version": "3.3.5",
5
  "main" : [
6
  "./dist/jstree.js",
7
  "./dist/themes/default/style.css"
1
  {
2
  "name": "jstree",
3
  "license": "MIT",
4
+ "version": "3.3.7",
5
  "main" : [
6
  "./dist/jstree.js",
7
  "./dist/themes/default/style.css"
vendor/vakata/jstree/component.json CHANGED
@@ -2,7 +2,7 @@
2
  "name": "jstree",
3
  "repo": "vakata/jstree",
4
  "description": "jsTree is jquery plugin, that provides interactive trees.",
5
- "version": "3.3.5",
6
  "license": "MIT",
7
  "keywords": [
8
  "ui",
2
  "name": "jstree",
3
  "repo": "vakata/jstree",
4
  "description": "jsTree is jquery plugin, that provides interactive trees.",
5
+ "version": "3.3.7",
6
  "license": "MIT",
7
  "keywords": [
8
  "ui",
vendor/vakata/jstree/dist/jstree.js CHANGED
@@ -13,7 +13,7 @@
13
  }(function ($, undefined) {
14
  "use strict";
15
  /*!
16
- * jsTree 3.3.5
17
  * http://jstree.com/
18
  *
19
  * Copyright (c) 2014 Ivan Bozhanov (http://vakata.com)
@@ -54,7 +54,7 @@
54
  * specifies the jstree version in use
55
  * @name $.jstree.version
56
  */
57
- version : '3.3.5',
58
  /**
59
  * holds all the default options used when creating new instances
60
  * @name $.jstree.defaults
@@ -430,7 +430,7 @@
430
  */
431
  force_text : false,
432
  /**
433
- * Should the node should be toggled if the text is double clicked . Defaults to `true`
434
  * @name $.jstree.defaults.core.dblclick_toggle
435
  */
436
  dblclick_toggle : true,
@@ -1023,6 +1023,9 @@
1023
  if(obj && obj.id) {
1024
  obj = obj.id;
1025
  }
 
 
 
1026
  var dom;
1027
  try {
1028
  if(this._model.data[obj]) {
@@ -1034,10 +1037,10 @@
1034
  else if(typeof obj === "string" && (dom = $('#' + obj.replace($.jstree.idregex,'\\$&'), this.element)).length && this._model.data[dom.closest('.jstree-node').attr('id')]) {
1035
  obj = this._model.data[dom.closest('.jstree-node').attr('id')];
1036
  }
1037
- else if((dom = $(obj, this.element)).length && this._model.data[dom.closest('.jstree-node').attr('id')]) {
1038
  obj = this._model.data[dom.closest('.jstree-node').attr('id')];
1039
  }
1040
- else if((dom = $(obj, this.element)).length && dom.hasClass('jstree')) {
1041
  obj = this._model.data[$.jstree.root];
1042
  }
1043
  else {
@@ -1331,7 +1334,7 @@
1331
  return true;
1332
  },
1333
  /**
1334
- * load an array of nodes (will also load unavailable nodes as soon as the appear in the structure). Used internally.
1335
  * @private
1336
  * @name _load_nodes(nodes [, callback])
1337
  * @param {array} nodes
@@ -2325,7 +2328,7 @@
2325
  this.element.empty().append(f);
2326
  //this.get_container_ul()[0].appendChild(f);
2327
  }
2328
- if(fe !== null) {
2329
  tmp = this.get_node(fe, true);
2330
  if(tmp && tmp.length && tmp.children('.jstree-anchor')[0] !== document.activeElement) {
2331
  tmp.children('.jstree-anchor').focus();
@@ -2608,7 +2611,7 @@
2608
  return node;
2609
  },
2610
  /**
2611
- * opens a node, revaling its children. If the node is not loaded it will be loaded and opened once ready.
2612
  * @name open_node(obj [, callback, animation])
2613
  * @param {mixed} obj the node to open
2614
  * @param {Function} callback a function to execute once the node is opened
@@ -2812,7 +2815,7 @@
2812
  }
2813
  },
2814
  /**
2815
- * opens all nodes within a node (or the tree), revaling their children. If the node is not loaded it will be loaded and opened once ready.
2816
  * @name open_all([obj, animation, original_obj])
2817
  * @param {mixed} obj the node to open recursively, omit to open all nodes in the tree
2818
  * @param {Number} animation the animation duration in milliseconds when opening the nodes, the default is no animation
@@ -2853,7 +2856,7 @@
2853
  }
2854
  },
2855
  /**
2856
- * closes all nodes within a node (or the tree), revaling their children
2857
  * @name close_all([obj, animation])
2858
  * @param {mixed} obj the node to close recursively, omit to close all nodes in the tree
2859
  * @param {Number} animation the animation duration in milliseconds when closing the nodes, the default is no animation
@@ -4491,7 +4494,7 @@
4491
  w2 = ai.width() * ai.length,
4492
  */
4493
  t = default_text;
4494
- h1 = $("<"+"div />", { css : { "position" : "absolute", "top" : "-200px", "left" : (rtl ? "0px" : "-1000px"), "visibility" : "hidden" } }).appendTo("body");
4495
  h2 = $("<"+"input />", {
4496
  "value" : t,
4497
  "class" : "jstree-rename-input",
@@ -4517,6 +4520,7 @@
4517
  s.replaceWith(a);
4518
  s.remove();
4519
  t = f ? t : $('<div></div>').append($.parseHTML(t)).html();
 
4520
  this.set_text(obj, t);
4521
  nv = !!this.rename_node(obj, f ? $('<div></div>').text(v).text() : $('<div></div>').append($.parseHTML(v)).html()
13
  }(function ($, undefined) {
14
  "use strict";
15
  /*!
16
+ * jsTree 3.3.7
17
  * http://jstree.com/
18
  *
19
  * Copyright (c) 2014 Ivan Bozhanov (http://vakata.com)
54
  * specifies the jstree version in use
55
  * @name $.jstree.version
56
  */
57
+ version : '3.3.7',
58
  /**
59
  * holds all the default options used when creating new instances
60
  * @name $.jstree.defaults
430
  */
431
  force_text : false,
432
  /**
433
+ * Should the node be toggled if the text is double clicked. Defaults to `true`
434
  * @name $.jstree.defaults.core.dblclick_toggle
435
  */
436
  dblclick_toggle : true,
1023
  if(obj && obj.id) {
1024
  obj = obj.id;
1025
  }
1026
+ if (obj instanceof jQuery && obj.length && obj[0].id) {
1027
+ obj = obj[0].id;
1028
+ }
1029
  var dom;
1030
  try {
1031
  if(this._model.data[obj]) {
1037
  else if(typeof obj === "string" && (dom = $('#' + obj.replace($.jstree.idregex,'\\$&'), this.element)).length && this._model.data[dom.closest('.jstree-node').attr('id')]) {
1038
  obj = this._model.data[dom.closest('.jstree-node').attr('id')];
1039
  }
1040
+ else if((dom = this.element.find(obj)).length && this._model.data[dom.closest('.jstree-node').attr('id')]) {
1041
  obj = this._model.data[dom.closest('.jstree-node').attr('id')];
1042
  }
1043
+ else if((dom = this.element.find(obj)).length && dom.hasClass('jstree')) {
1044
  obj = this._model.data[$.jstree.root];
1045
  }
1046
  else {
1334
  return true;
1335
  },
1336
  /**
1337
+ * load an array of nodes (will also load unavailable nodes as soon as they appear in the structure). Used internally.
1338
  * @private
1339
  * @name _load_nodes(nodes [, callback])
1340
  * @param {array} nodes
2328
  this.element.empty().append(f);
2329
  //this.get_container_ul()[0].appendChild(f);
2330
  }
2331
+ if(fe !== null && this.settings.core.restore_focus) {
2332
  tmp = this.get_node(fe, true);
2333
  if(tmp && tmp.length && tmp.children('.jstree-anchor')[0] !== document.activeElement) {
2334
  tmp.children('.jstree-anchor').focus();
2611
  return node;
2612
  },
2613
  /**
2614
+ * opens a node, revealing its children. If the node is not loaded it will be loaded and opened once ready.
2615
  * @name open_node(obj [, callback, animation])
2616
  * @param {mixed} obj the node to open
2617
  * @param {Function} callback a function to execute once the node is opened
2815
  }
2816
  },
2817
  /**
2818
+ * opens all nodes within a node (or the tree), revealing their children. If the node is not loaded it will be loaded and opened once ready.
2819
  * @name open_all([obj, animation, original_obj])
2820
  * @param {mixed} obj the node to open recursively, omit to open all nodes in the tree
2821
  * @param {Number} animation the animation duration in milliseconds when opening the nodes, the default is no animation
2856
  }
2857
  },
2858
  /**
2859
+ * closes all nodes within a node (or the tree), revealing their children
2860
  * @name close_all([obj, animation])
2861
  * @param {mixed} obj the node to close recursively, omit to close all nodes in the tree
2862
  * @param {Number} animation the animation duration in milliseconds when closing the nodes, the default is no animation
4494
  w2 = ai.width() * ai.length,
4495
  */
4496
  t = default_text;
4497
+ h1 = $("<"+"div />", { css : { "position" : "absolute", "top" : "-200px", "left" : (rtl ? "0px" : "-1000px"), "visibility" : "hidden" } }).appendTo(document.body);
4498
  h2 = $("<"+"input />", {
4499
  "value" : t,
4500
  "class" : "jstree-rename-input",
4520
  s.replaceWith(a);
4521
  s.remove();
4522
  t = f ? t : $('<div></div>').append($.parseHTML(t)).html();
4523
+ obj = this.get_node(obj);
4524
  this.set_text(obj, t);
4525
  nv = !!this.rename_node(obj, f ? $('<div></div>').text(v).text() : $('<div></div>').append($.parseHTML(v)).html()