WP Mail SMTP by WPForms - Version 1.1.0

Version Description

  • 2017-12-18 =
  • Added: New option "Auto TLS" for SMTP mailer. Default is enabled. Migration routine for all sites.
  • Changed: Improve debug output - clear styles and context-aware content.
  • Changed: Better exceptions handling for Google authentication process.
  • Changed: Do not sanitize passwords, api keys etc - as they may contain special characters in certain order and sanitization will break those values.
  • Changed: Improve wording of some helpful texts inside plugin admin area.
  • Fixed: Do not include certain files in dependency libraries that are not used by Google mailer. This should stop flagging plugin by Wordfence and VaultPress.
  • Fixed: Constants usage is working now, to define the SMTP password, for example.
  • Fixed: Notice for default mailer.
Download this release

Release Info

Developer slaFFik
Plugin Icon 128x128 WP Mail SMTP by WPForms
Version 1.1.0
Comparing to
See all releases

Code changes from version 1.0.2 to 1.1.0

Files changed (57) hide show
  1. assets/js/smtp-admin.js +43 -36
  2. assets/js/smtp-admin.min.js +1 -1
  3. class-wpms-am-notification.php +450 -450
  4. languages/wp-mail-smtp.pot +25 -9
  5. readme.txt +10 -0
  6. src/AM_Notification.php +452 -452
  7. src/Admin/Area.php +457 -457
  8. src/Admin/PageAbstract.php +66 -66
  9. src/Admin/PageInterface.php +45 -45
  10. src/Admin/Pages/Auth.php +56 -56
  11. src/Admin/Pages/Misc.php +99 -99
  12. src/Admin/Pages/Settings.php +236 -236
  13. src/Admin/Pages/Test.php +235 -208
  14. src/Core.php +239 -213
  15. src/MailCatcher.php +66 -66
  16. src/Migration.php +245 -245
  17. src/Options.php +547 -469
  18. src/Processor.php +175 -170
  19. src/Providers/AuthAbstract.php +22 -22
  20. src/Providers/AuthInterface.php +19 -19
  21. src/Providers/Gmail/Auth.php +314 -299
  22. src/Providers/Gmail/Mailer.php +173 -173
  23. src/Providers/Gmail/Options.php +131 -131
  24. src/Providers/Loader.php +178 -178
  25. src/Providers/Mail/Options.php +42 -42
  26. src/Providers/MailerAbstract.php +346 -346
  27. src/Providers/MailerInterface.php +139 -139
  28. src/Providers/Mailgun/Mailer.php +299 -299
  29. src/Providers/Mailgun/Options.php +106 -106
  30. src/Providers/OptionAbstract.php +312 -291
  31. src/Providers/OptionInterface.php +64 -64
  32. src/Providers/Pepipost/Options.php +29 -29
  33. src/Providers/SMTP/Options.php +45 -45
  34. src/Providers/Sendgrid/Mailer.php +294 -294
  35. src/Providers/Sendgrid/Options.php +89 -89
  36. src/Upgrade.php +71 -0
  37. src/WP.php +140 -140
  38. vendor/autoload.php +2 -2
  39. vendor/composer/ClassLoader.php +45 -13
  40. vendor/composer/LICENSE +1 -1
  41. vendor/composer/autoload_classmap.php +228 -0
  42. vendor/composer/autoload_real.php +9 -18
  43. vendor/composer/autoload_static.php +233 -5
  44. vendor/phpseclib/phpseclib/phpseclib/Crypt/Base.php +0 -2558
  45. vendor/phpseclib/phpseclib/phpseclib/Crypt/Blowfish.php +0 -577
  46. vendor/phpseclib/phpseclib/phpseclib/Crypt/DES.php +0 -1443
  47. vendor/phpseclib/phpseclib/phpseclib/Crypt/Hash.php +0 -824
  48. vendor/phpseclib/phpseclib/phpseclib/Crypt/RC2.php +0 -688
  49. vendor/phpseclib/phpseclib/phpseclib/Crypt/RC4.php +0 -342
  50. vendor/phpseclib/phpseclib/phpseclib/Crypt/TripleDES.php +0 -460
  51. vendor/phpseclib/phpseclib/phpseclib/Crypt/Twofish.php +0 -808
  52. vendor/phpseclib/phpseclib/phpseclib/File/ANSI.php +0 -577
  53. vendor/phpseclib/phpseclib/phpseclib/File/ASN1.php +0 -1325
  54. vendor/phpseclib/phpseclib/phpseclib/File/ASN1/Element.php +0 -47
  55. vendor/phpseclib/phpseclib/phpseclib/File/X509.php +0 -4846
  56. vendor/phpseclib/phpseclib/phpseclib/Net/SCP.php +0 -337
  57. vendor/phpseclib/phpseclib/phpseclib/Net/SFTP.php +0 -1951
assets/js/smtp-admin.js CHANGED
@@ -1,36 +1,43 @@
1
- /* globals jQuery */
2
- jQuery( document ).ready( function ( $ ) {
3
-
4
- $( '.wp-mail-smtp-mailer input' ).click( function () {
5
- if ( $( this ).prop( 'disabled' ) ) {
6
- return false;
7
- }
8
-
9
- // Deselect the current mailer.
10
- $( '.wp-mail-smtp-mailer' ).removeClass( 'active' );
11
- // Select the correct one.
12
- $( this ).parents( '.wp-mail-smtp-mailer' ).addClass( 'active' );
13
-
14
- $( '.wp-mail-smtp-mailer-option' ).addClass( 'hidden' ).removeClass( 'active' );
15
- $( '.wp-mail-smtp-mailer-option-' + $( this ).val() ).addClass( 'active' ).removeClass( 'hidden' );
16
- } );
17
-
18
- $( '.wp-mail-smtp-mailer-image' ).click( function () {
19
- $( this ).parents( '.wp-mail-smtp-mailer' ).find( 'input' ).trigger( 'click' );
20
- } );
21
-
22
- $( '.wp-mail-smtp-setting-copy' ).click( function ( e ) {
23
- e.preventDefault();
24
-
25
- var target = $( '#' + $( this ).data( 'source_id' ) ).get(0);
26
-
27
- target.select();
28
-
29
- document.execCommand( 'Copy' );
30
- } );
31
-
32
- $( '#wp-mail-smtp-setting-smtp-auth' ).change(function() {
33
- $( '#wp-mail-smtp-setting-row-smtp-user, #wp-mail-smtp-setting-row-smtp-pass' ).toggleClass( 'inactive' );
34
- });
35
-
36
- } );
 
 
 
 
 
 
 
1
+ /* globals jQuery */
2
+ jQuery( document ).ready( function ( $ ) {
3
+
4
+ $( '.wp-mail-smtp-mailer input' ).click( function () {
5
+ if ( $( this ).prop( 'disabled' ) ) {
6
+ return false;
7
+ }
8
+
9
+ // Deselect the current mailer.
10
+ $( '.wp-mail-smtp-mailer' ).removeClass( 'active' );
11
+ // Select the correct one.
12
+ $( this ).parents( '.wp-mail-smtp-mailer' ).addClass( 'active' );
13
+
14
+ $( '.wp-mail-smtp-mailer-option' ).addClass( 'hidden' ).removeClass( 'active' );
15
+ $( '.wp-mail-smtp-mailer-option-' + $( this ).val() ).addClass( 'active' ).removeClass( 'hidden' );
16
+ } );
17
+
18
+ $( '.wp-mail-smtp-mailer-image' ).click( function () {
19
+ $( this ).parents( '.wp-mail-smtp-mailer' ).find( 'input' ).trigger( 'click' );
20
+ } );
21
+
22
+ $( '.wp-mail-smtp-setting-copy' ).click( function ( e ) {
23
+ e.preventDefault();
24
+
25
+ var target = $( '#' + $( this ).data( 'source_id' ) ).get(0);
26
+
27
+ target.select();
28
+
29
+ document.execCommand( 'Copy' );
30
+ } );
31
+
32
+ $( '#wp-mail-smtp-setting-smtp-auth' ).change( function() {
33
+ $( '#wp-mail-smtp-setting-row-smtp-user, #wp-mail-smtp-setting-row-smtp-pass' ).toggleClass( 'inactive' );
34
+ });
35
+
36
+ $( '#wp-mail-smtp-setting-row-smtp-encryption input').change( function() {
37
+ if ( 'tls' === $(this).val() ) {
38
+ $(' #wp-mail-smtp-setting-row-smtp-autotls' ).addClass( 'inactive' );
39
+ } else {
40
+ $( '#wp-mail-smtp-setting-row-smtp-autotls' ).removeClass( 'inactive' );
41
+ }
42
+ } );
43
+ } );
assets/js/smtp-admin.min.js CHANGED
@@ -1 +1 @@
1
- jQuery(document).ready(function(i){i(".wp-mail-smtp-mailer input").click(function(){if(i(this).prop("disabled"))return!1;i(".wp-mail-smtp-mailer").removeClass("active"),i(this).parents(".wp-mail-smtp-mailer").addClass("active"),i(".wp-mail-smtp-mailer-option").addClass("hidden").removeClass("active"),i(".wp-mail-smtp-mailer-option-"+i(this).val()).addClass("active").removeClass("hidden")}),i(".wp-mail-smtp-mailer-image").click(function(){i(this).parents(".wp-mail-smtp-mailer").find("input").trigger("click")}),i(".wp-mail-smtp-setting-copy").click(function(t){t.preventDefault();i("#"+i(this).data("source_id")).get(0).select(),document.execCommand("Copy")}),i("#wp-mail-smtp-setting-smtp-auth").change(function(){i("#wp-mail-smtp-setting-row-smtp-user, #wp-mail-smtp-setting-row-smtp-pass").toggleClass("inactive")})});
1
+ jQuery(document).ready(function(t){t(".wp-mail-smtp-mailer input").click(function(){if(t(this).prop("disabled"))return!1;t(".wp-mail-smtp-mailer").removeClass("active"),t(this).parents(".wp-mail-smtp-mailer").addClass("active"),t(".wp-mail-smtp-mailer-option").addClass("hidden").removeClass("active"),t(".wp-mail-smtp-mailer-option-"+t(this).val()).addClass("active").removeClass("hidden")}),t(".wp-mail-smtp-mailer-image").click(function(){t(this).parents(".wp-mail-smtp-mailer").find("input").trigger("click")}),t(".wp-mail-smtp-setting-copy").click(function(i){i.preventDefault(),t("#"+t(this).data("source_id")).get(0).select(),document.execCommand("Copy")}),t("#wp-mail-smtp-setting-smtp-auth").change(function(){t("#wp-mail-smtp-setting-row-smtp-user, #wp-mail-smtp-setting-row-smtp-pass").toggleClass("inactive")}),t("#wp-mail-smtp-setting-row-smtp-encryption input").change(function(){"tls"===t(this).val()?t(" #wp-mail-smtp-setting-row-smtp-autotls").addClass("inactive"):t("#wp-mail-smtp-setting-row-smtp-autotls").removeClass("inactive")})});
class-wpms-am-notification.php CHANGED
@@ -1,450 +1,450 @@
1
- <?php
2
-
3
- /**
4
- * Awesome Motive Notifications
5
- *
6
- * This creates a custom post type (if it doesn't exist) and calls the API to
7
- * retrieve notifications for this product.
8
- *
9
- * @package AwesomeMotive
10
- * @author Benjamin Rojas
11
- * @license GPL-2.0+
12
- * @copyright Copyright (c) 2017, Retyp LLC
13
- * @version 1.0.2
14
- */
15
- class WPMS_AM_Notification {
16
- /**
17
- * The api url we are calling.
18
- *
19
- * @since 1.0.0
20
- *
21
- * @var string
22
- */
23
- public $api_url = 'https://api.awesomemotive.com/v1/notification/';
24
-
25
- /**
26
- * A unique slug for this plugin.
27
- * (Not the WordPress plugin slug)
28
- *
29
- * @since 1.0.0
30
- *
31
- * @var string
32
- */
33
- public $plugin;
34
-
35
- /**
36
- * The current plugin version.
37
- *
38
- * @since 1.0.0
39
- *
40
- * @var string
41
- */
42
- public $plugin_version;
43
-
44
- /**
45
- * Flag if a notice has been registered.
46
- *
47
- * @since 1.0.0
48
- *
49
- * @var bool
50
- */
51
- public static $registered = false;
52
-
53
- /**
54
- * Construct.
55
- *
56
- * @since 1.0.0
57
- *
58
- * @param string $plugin The plugin slug.
59
- * @param mixed $version The version of the plugin.
60
- */
61
- public function __construct( $plugin = '', $version = 0 ) {
62
- $this->plugin = $plugin;
63
- $this->plugin_version = $version;
64
-
65
- add_action( 'init', array( $this, 'custom_post_type' ) );
66
- add_action( 'admin_init', array( $this, 'get_remote_notifications' ), 100 );
67
- add_action( 'admin_notices', array( $this, 'display_notifications' ) );
68
- add_action( 'wp_ajax_am_notification_dismiss', array( $this, 'dismiss_notification' ) );
69
- }
70
-
71
- /**
72
- * Registers a custom post type.
73
- *
74
- * @since 1.0.0
75
- */
76
- public function custom_post_type() {
77
- register_post_type( 'amn_' . $this->plugin, array(
78
- 'label' => $this->plugin . ' Announcements',
79
- 'can_export' => false,
80
- 'supports' => false,
81
- ) );
82
- }
83
-
84
- /**
85
- * Retrieve the remote notifications if the time has expired.
86
- *
87
- * @since 1.0.0
88
- */
89
- public function get_remote_notifications() {
90
- if ( ! current_user_can( apply_filters( 'am_notifications_display', 'manage_options' ) ) ) {
91
- return;
92
- }
93
-
94
- $last_checked = get_option( '_amn_' . $this->plugin . '_last_checked', strtotime( '-1 week' ) );
95
-
96
- if ( $last_checked < strtotime( 'today midnight' ) ) {
97
- $plugin_notifications = $this->get_plugin_notifications( 1 );
98
- $notification_id = null;
99
-
100
- if ( ! empty( $plugin_notifications ) ) {
101
- // Unset it from the array.
102
- $notification = $plugin_notifications[0];
103
- $notification_id = get_post_meta( $notification->ID, 'notification_id', true );
104
- }
105
-
106
- $response = wp_remote_retrieve_body( wp_remote_post( $this->api_url, array(
107
- 'body' => array(
108
- 'slug' => $this->plugin,
109
- 'version' => $this->plugin_version,
110
- 'last_notification' => $notification_id,
111
- ),
112
- ) ) );
113
-
114
- $data = json_decode( $response );
115
-
116
- if ( ! empty( $data->id ) ) {
117
- $notifications = array();
118
-
119
- foreach ( (array) $data->slugs as $slug ) {
120
- $notifications = array_merge(
121
- $notifications,
122
- (array) get_posts(
123
- array(
124
- 'post_type' => 'amn_' . $slug,
125
- 'post_status' => 'all',
126
- 'meta_key' => 'notification_id',
127
- 'meta_value' => $data->id,
128
- )
129
- )
130
- );
131
- }
132
-
133
- if ( empty( $notifications ) ) {
134
- $new_notification_id = wp_insert_post( array(
135
- 'post_content' => wp_kses_post( $data->content ),
136
- 'post_type' => 'amn_' . $this->plugin,
137
- ) );
138
-
139
- update_post_meta( $new_notification_id, 'notification_id', absint( $data->id ) );
140
- update_post_meta( $new_notification_id, 'type', sanitize_text_field( trim( $data->type ) ) );
141
- update_post_meta( $new_notification_id, 'dismissable', (bool) $data->dismissible ? 1 : 0 );
142
- update_post_meta( $new_notification_id, 'location', function_exists( 'wp_json_encode' ) ? wp_json_encode( $data->location ) : json_encode( $data->location ) );
143
- update_post_meta( $new_notification_id, 'version', sanitize_text_field( trim( $data->version ) ) );
144
- update_post_meta( $new_notification_id, 'viewed', 0 );
145
- update_post_meta( $new_notification_id, 'expiration', $data->expiration ? absint( $data->expiration ) : false );
146
- update_post_meta( $new_notification_id, 'plans', function_exists( 'wp_json_encode' ) ? wp_json_encode( $data->plans ) : json_encode( $data->plans ) );
147
- }
148
- }
149
-
150
- // Possibly revoke notifications.
151
- if ( ! empty( $data->revoked ) ) {
152
- $this->revoke_notifications( $data->revoked );
153
- }
154
-
155
- // Set the option now so we can't run this again until after 24 hours.
156
- update_option( '_amn_' . $this->plugin . '_last_checked', strtotime( 'today midnight' ) );
157
- }
158
- }
159
-
160
- /**
161
- * Get local plugin notifications that have already been set.
162
- *
163
- * @since 1.0.0
164
- *
165
- * @param integer $limit Set the limit for how many posts to retrieve.
166
- * @param array $args Any top-level arguments to add to the array.
167
- *
168
- * @return WP_Post[] WP_Post that match the query.
169
- */
170
- public function get_plugin_notifications( $limit = -1, $args = array() ) {
171
- return get_posts(
172
- array(
173
- 'posts_per_page' => $limit,
174
- 'post_type' => 'amn_' . $this->plugin,
175
- ) + $args
176
- );
177
- }
178
-
179
- /**
180
- * Display any notifications that should be displayed.
181
- *
182
- * @since 1.0.0
183
- */
184
- public function display_notifications() {
185
- if ( ! current_user_can( apply_filters( 'am_notifications_display', 'manage_options' ) ) ) {
186
- return;
187
- }
188
-
189
- $plugin_notifications = $this->get_plugin_notifications( -1, array(
190
- 'post_status' => 'all',
191
- 'meta_key' => 'viewed',
192
- 'meta_value' => '0',
193
- ) );
194
-
195
- $plugin_notifications = $this->validate_notifications( $plugin_notifications );
196
-
197
- if ( ! empty( $plugin_notifications ) && ! self::$registered ) {
198
- foreach ( $plugin_notifications as $notification ) {
199
- $dismissable = get_post_meta( $notification->ID, 'dismissable', true );
200
- $type = get_post_meta( $notification->ID, 'type', true );
201
- ?>
202
- <div class="am-notification am-notification-<?php echo $notification->ID; ?> notice notice-<?php echo $type; ?><?php echo $dismissable ? ' is-dismissible' : ''; ?>">
203
- <?php echo $notification->post_content; ?>
204
- </div>
205
- <script type="text/javascript">
206
- jQuery(document).ready(function ($) {
207
- $(document).on('click', '.am-notification-<?php echo $notification->ID; ?> button.notice-dismiss', function (event) {
208
- $.post(ajaxurl, {
209
- action: 'am_notification_dismiss',
210
- notification_id: '<?php echo $notification->ID; ?>'
211
- });
212
- });
213
- });
214
- </script>
215
- <?php
216
- }
217
-
218
- self::$registered = true;
219
- }
220
- }
221
-
222
- /**
223
- * Validate the notifications before displaying them.
224
- *
225
- * @since 1.0.0
226
- *
227
- * @param array $plugin_notifications An array of plugin notifications.
228
- *
229
- * @return array A filtered array of plugin notifications.
230
- */
231
- public function validate_notifications( $plugin_notifications ) {
232
- global $pagenow;
233
-
234
- foreach ( $plugin_notifications as $key => $notification ) {
235
- // Location validation.
236
- $location = (array) json_decode( get_post_meta( $notification->ID, 'location', true ) );
237
- $continue = false;
238
- if ( ! in_array( 'everywhere', $location, true ) ) {
239
- if ( in_array( 'index.php', $location, true ) && 'index.php' === $pagenow ) {
240
- $continue = true;
241
- }
242
-
243
- if ( in_array( 'plugins.php', $location, true ) && 'plugins.php' === $pagenow ) {
244
- $continue = true;
245
- }
246
-
247
- if ( ! $continue ) {
248
- unset( $plugin_notifications[ $key ] );
249
- }
250
- }
251
-
252
- // Plugin validation (OR conditional).
253
- $plugins = (array) json_decode( get_post_meta( $notification->ID, 'plugins', true ) );
254
- $continue = false;
255
- if ( ! empty( $plugins ) ) {
256
- foreach ( $plugins as $plugin ) {
257
- if ( is_plugin_active( $plugin ) ) {
258
- $continue = true;
259
- }
260
- }
261
-
262
- if ( ! $continue ) {
263
- unset( $plugin_notifications[ $key ] );
264
- }
265
- }
266
-
267
- // Theme validation.
268
- $theme = get_post_meta( $notification->ID, 'theme', true );
269
- $continue = (string) wp_get_theme() === $theme;
270
-
271
- if ( ! empty( $theme ) && ! $continue ) {
272
- unset( $plugin_notifications[ $key ] );
273
- }
274
-
275
- // Version validation.
276
- $version = get_post_meta( $notification->ID, 'version', true );
277
- $continue = false;
278
- if ( ! empty( $version ) ) {
279
- if ( version_compare( $this->plugin_version, $version, '<=' ) ) {
280
- $continue = true;
281
- }
282
-
283
- if ( ! $continue ) {
284
- unset( $plugin_notifications[ $key ] );
285
- }
286
- }
287
-
288
- // Expiration validation.
289
- $expiration = get_post_meta( $notification->ID, 'expiration', true );
290
- $continue = false;
291
- if ( ! empty( $expiration ) ) {
292
- if ( $expiration > time() ) {
293
- $continue = true;
294
- }
295
-
296
- if ( ! $continue ) {
297
- unset( $plugin_notifications[ $key ] );
298
- }
299
- }
300
-
301
- // Plan validation.
302
- $plans = (array) json_decode( get_post_meta( $notification->ID, 'plans', true ) );
303
- $continue = false;
304
- if ( ! empty( $plans ) ) {
305
- $level = $this->get_plan_level();
306
- if ( in_array( $level, $plans, true ) ) {
307
- $continue = true;
308
- }
309
-
310
- if ( ! $continue ) {
311
- unset( $plugin_notifications[ $key ] );
312
- }
313
- }
314
- }
315
-
316
- return $plugin_notifications;
317
- }
318
-
319
- /**
320
- * Grab the current plan level.
321
- *
322
- * @since 1.0.0
323
- *
324
- * @return string The current plan level.
325
- */
326
- public function get_plan_level() {
327
- // Prepare variables.
328
- $key = '';
329
- $level = '';
330
- $option = false;
331
- switch ( $this->plugin ) {
332
- case 'wpforms' :
333
- $option = get_option( 'wpforms_license' );
334
- $key = is_array( $option ) && isset( $option['key'] ) ? $option['key'] : '';
335
- $level = is_array( $option ) && isset( $option['type'] ) ? $option['type'] : '';
336
-
337
- // Possibly check for a constant.
338
- if ( empty( $key ) && defined( 'WPFORMS_LICENSE_KEY' ) ) {
339
- $key = WPFORMS_LICENSE_KEY;
340
- }
341
- break;
342
- case 'mi' :
343
- $option = get_option( 'monsterinsights_license' );
344
- $key = is_array( $option ) && isset( $option['key'] ) ? $option['key'] : '';
345
- $level = is_array( $option ) && isset( $option['type'] ) ? $option['type'] : '';
346
-
347
- // Possibly check for a constant.
348
- if ( empty( $key ) && defined( 'MONSTERINSIGHTS_LICENSE_KEY' ) && is_string( MONSTERINSIGHTS_LICENSE_KEY ) && strlen( MONSTERINSIGHTS_LICENSE_KEY ) > 10 ) {
349
- $key = MONSTERINSIGHTS_LICENSE_KEY;
350
- }
351
- break;
352
- case 'sol' :
353
- $option = get_option( 'soliloquy' );
354
- $key = is_array( $option ) && isset( $option['key'] ) ? $option['key'] : '';
355
- $level = is_array( $option ) && isset( $option['type'] ) ? $option['type'] : '';
356
-
357
- // Possibly check for a constant.
358
- if ( empty( $key ) && defined( 'SOLILOQUY_LICENSE_KEY' ) ) {
359
- $key = SOLILOQUY_LICENSE_KEY;
360
- }
361
- break;
362
- case 'envira' :
363
- $option = get_option( 'envira_gallery' );
364
- $key = is_array( $option ) && isset( $option['key'] ) ? $option['key'] : '';
365
- $level = is_array( $option ) && isset( $option['type'] ) ? $option['type'] : '';
366
-
367
- // Possibly check for a constant.
368
- if ( empty( $key ) && defined( 'ENVIRA_LICENSE_KEY' ) ) {
369
- $key = ENVIRA_LICENSE_KEY;
370
- }
371
- break;
372
- case 'om' :
373
- $option = get_option( 'optin_monster_api' );
374
- $key = is_array( $option ) && isset( $option['api']['apikey'] ) ? $option['api']['apikey'] : '';
375
-
376
- // Possibly check for a constant.
377
- if ( empty( $key ) && defined( 'OPTINMONSTER_REST_API_LICENSE_KEY' ) ) {
378
- $key = OPTINMONSTER_REST_API_LICENSE_KEY;
379
- }
380
-
381
- // If the key is still empty, check for the old legacy key.
382
- if ( empty( $key ) ) {
383
- $key = is_array( $option ) && isset( $option['api']['key'] ) ? $option['api']['key'] : '';
384
- }
385
- break;
386
- }
387
-
388
- // Possibly set the level to 'none' if the key is empty and no level has been set.
389
- if ( empty( $key ) && empty( $level ) ) {
390
- $level = 'none';
391
- }
392
-
393
- // Normalize the level.
394
- switch ( $level ) {
395
- case 'bronze' :
396
- case 'personal' :
397
- $level = 'basic';
398
- break;
399
- case 'silver' :
400
- case 'multi' :
401
- $level = 'plus';
402
- break;
403
- case 'gold' :
404
- case 'developer' :
405
- $level = 'pro';
406
- break;
407
- case 'platinum' :
408
- case 'master' :
409
- $level = 'ultimate';
410
- break;
411
- }
412
-
413
- // Return the plan level.
414
- return $level;
415
- }
416
-
417
- /**
418
- * Dismiss the notification via AJAX.
419
- *
420
- * @since 1.0.0
421
- */
422
- public function dismiss_notification() {
423
- if ( ! current_user_can( apply_filters( 'am_notifications_display', 'manage_options' ) ) ) {
424
- die;
425
- }
426
-
427
- $notification_id = intval( $_POST['notification_id'] );
428
- update_post_meta( $notification_id, 'viewed', 1 );
429
- die;
430
- }
431
-
432
- /**
433
- * Revokes notifications.
434
- *
435
- * @since 1.0.0
436
- *
437
- * @param array $ids An array of notification IDs to revoke.
438
- */
439
- public function revoke_notifications( $ids ) {
440
- // Loop through each of the IDs and find the post that has it as meta.
441
- foreach ( (array) $ids as $id ) {
442
- $notifications = $this->get_plugin_notifications( -1, array( 'post_status' => 'all', 'meta_key' => 'notification_id', 'meta_value' => $id ) );
443
- if ( $notifications ) {
444
- foreach ( $notifications as $notification ) {
445
- update_post_meta( $notification->ID, 'viewed', 1 );
446
- }
447
- }
448
- }
449
- }
450
- }
1
+ <?php
2
+
3
+ /**
4
+ * Awesome Motive Notifications
5
+ *
6
+ * This creates a custom post type (if it doesn't exist) and calls the API to
7
+ * retrieve notifications for this product.
8
+ *
9
+ * @package AwesomeMotive
10
+ * @author Benjamin Rojas
11
+ * @license GPL-2.0+
12
+ * @copyright Copyright (c) 2017, Retyp LLC
13
+ * @version 1.0.2
14
+ */
15
+ class WPMS_AM_Notification {
16
+ /**
17
+ * The api url we are calling.
18
+ *
19
+ * @since 1.0.0
20
+ *
21
+ * @var string
22
+ */
23
+ public $api_url = 'https://api.awesomemotive.com/v1/notification/';
24
+
25
+ /**
26
+ * A unique slug for this plugin.
27
+ * (Not the WordPress plugin slug)
28
+ *
29
+ * @since 1.0.0
30
+ *
31
+ * @var string
32
+ */
33
+ public $plugin;
34
+
35
+ /**
36
+ * The current plugin version.
37
+ *
38
+ * @since 1.0.0
39
+ *
40
+ * @var string
41
+ */
42
+ public $plugin_version;
43
+
44
+ /**
45
+ * Flag if a notice has been registered.
46
+ *
47
+ * @since 1.0.0
48
+ *
49
+ * @var bool
50
+ */
51
+ public static $registered = false;
52
+
53
+ /**
54
+ * Construct.
55
+ *
56
+ * @since 1.0.0
57
+ *
58
+ * @param string $plugin The plugin slug.
59
+ * @param mixed $version The version of the plugin.
60
+ */
61
+ public function __construct( $plugin = '', $version = 0 ) {
62
+ $this->plugin = $plugin;
63
+ $this->plugin_version = $version;
64
+
65
+ add_action( 'init', array( $this, 'custom_post_type' ) );
66
+ add_action( 'admin_init', array( $this, 'get_remote_notifications' ), 100 );
67
+ add_action( 'admin_notices', array( $this, 'display_notifications' ) );
68
+ add_action( 'wp_ajax_am_notification_dismiss', array( $this, 'dismiss_notification' ) );
69
+ }
70
+
71
+ /**
72
+ * Registers a custom post type.
73
+ *
74
+ * @since 1.0.0
75
+ */
76
+ public function custom_post_type() {
77
+ register_post_type( 'amn_' . $this->plugin, array(
78
+ 'label' => $this->plugin . ' Announcements',
79
+ 'can_export' => false,
80
+ 'supports' => false,
81
+ ) );
82
+ }
83
+
84
+ /**
85
+ * Retrieve the remote notifications if the time has expired.
86
+ *
87
+ * @since 1.0.0
88
+ */
89
+ public function get_remote_notifications() {
90
+ if ( ! current_user_can( apply_filters( 'am_notifications_display', 'manage_options' ) ) ) {
91
+ return;
92
+ }
93
+
94
+ $last_checked = get_option( '_amn_' . $this->plugin . '_last_checked', strtotime( '-1 week' ) );
95
+
96
+ if ( $last_checked < strtotime( 'today midnight' ) ) {
97
+ $plugin_notifications = $this->get_plugin_notifications( 1 );
98
+ $notification_id = null;
99
+
100
+ if ( ! empty( $plugin_notifications ) ) {
101
+ // Unset it from the array.
102
+ $notification = $plugin_notifications[0];
103
+ $notification_id = get_post_meta( $notification->ID, 'notification_id', true );
104
+ }
105
+
106
+ $response = wp_remote_retrieve_body( wp_remote_post( $this->api_url, array(
107
+ 'body' => array(
108
+ 'slug' => $this->plugin,
109
+ 'version' => $this->plugin_version,
110
+ 'last_notification' => $notification_id,
111
+ ),
112
+ ) ) );
113
+
114
+ $data = json_decode( $response );
115
+
116
+ if ( ! empty( $data->id ) ) {
117
+ $notifications = array();
118
+
119
+ foreach ( (array) $data->slugs as $slug ) {
120
+ $notifications = array_merge(
121
+ $notifications,
122
+ (array) get_posts(
123
+ array(
124
+ 'post_type' => 'amn_' . $slug,
125
+ 'post_status' => 'all',
126
+ 'meta_key' => 'notification_id',
127
+ 'meta_value' => $data->id,
128
+ )
129
+ )
130
+ );
131
+ }
132
+
133
+ if ( empty( $notifications ) ) {
134
+ $new_notification_id = wp_insert_post( array(
135
+ 'post_content' => wp_kses_post( $data->content ),
136
+ 'post_type' => 'amn_' . $this->plugin,
137
+ ) );
138
+
139
+ update_post_meta( $new_notification_id, 'notification_id', absint( $data->id ) );
140
+ update_post_meta( $new_notification_id, 'type', sanitize_text_field( trim( $data->type ) ) );
141
+ update_post_meta( $new_notification_id, 'dismissable', (bool) $data->dismissible ? 1 : 0 );
142
+ update_post_meta( $new_notification_id, 'location', function_exists( 'wp_json_encode' ) ? wp_json_encode( $data->location ) : json_encode( $data->location ) );
143
+ update_post_meta( $new_notification_id, 'version', sanitize_text_field( trim( $data->version ) ) );
144
+ update_post_meta( $new_notification_id, 'viewed', 0 );
145
+ update_post_meta( $new_notification_id, 'expiration', $data->expiration ? absint( $data->expiration ) : false );
146
+ update_post_meta( $new_notification_id, 'plans', function_exists( 'wp_json_encode' ) ? wp_json_encode( $data->plans ) : json_encode( $data->plans ) );
147
+ }
148
+ }
149
+
150
+ // Possibly revoke notifications.
151
+ if ( ! empty( $data->revoked ) ) {
152
+ $this->revoke_notifications( $data->revoked );
153
+ }
154
+
155
+ // Set the option now so we can't run this again until after 24 hours.
156
+ update_option( '_amn_' . $this->plugin . '_last_checked', strtotime( 'today midnight' ) );
157
+ }
158
+ }
159
+
160
+ /**
161
+ * Get local plugin notifications that have already been set.
162
+ *
163
+ * @since 1.0.0
164
+ *
165
+ * @param integer $limit Set the limit for how many posts to retrieve.
166
+ * @param array $args Any top-level arguments to add to the array.
167
+ *
168
+ * @return WP_Post[] WP_Post that match the query.
169
+ */
170
+ public function get_plugin_notifications( $limit = -1, $args = array() ) {
171
+ return get_posts(
172
+ array(
173
+ 'posts_per_page' => $limit,
174
+ 'post_type' => 'amn_' . $this->plugin,
175
+ ) + $args
176
+ );
177
+ }
178
+
179
+ /**
180
+ * Display any notifications that should be displayed.
181
+ *
182
+ * @since 1.0.0
183
+ */
184
+ public function display_notifications() {
185
+ if ( ! current_user_can( apply_filters( 'am_notifications_display', 'manage_options' ) ) ) {
186
+ return;
187
+ }
188
+
189
+ $plugin_notifications = $this->get_plugin_notifications( -1, array(
190
+ 'post_status' => 'all',
191
+ 'meta_key' => 'viewed',
192
+ 'meta_value' => '0',
193
+ ) );
194
+
195
+ $plugin_notifications = $this->validate_notifications( $plugin_notifications );
196
+
197
+ if ( ! empty( $plugin_notifications ) && ! self::$registered ) {
198
+ foreach ( $plugin_notifications as $notification ) {
199
+ $dismissable = get_post_meta( $notification->ID, 'dismissable', true );
200
+ $type = get_post_meta( $notification->ID, 'type', true );
201
+ ?>
202
+ <div class="am-notification am-notification-<?php echo $notification->ID; ?> notice notice-<?php echo $type; ?><?php echo $dismissable ? ' is-dismissible' : ''; ?>">
203
+ <?php echo $notification->post_content; ?>
204
+ </div>
205
+ <script type="text/javascript">
206
+ jQuery(document).ready(function ($) {
207
+ $(document).on('click', '.am-notification-<?php echo $notification->ID; ?> button.notice-dismiss', function (event) {
208
+ $.post(ajaxurl, {
209
+ action: 'am_notification_dismiss',
210
+ notification_id: '<?php echo $notification->ID; ?>'
211
+ });
212
+ });
213
+ });
214
+ </script>
215
+ <?php
216
+ }
217
+
218
+ self::$registered = true;
219
+ }
220
+ }
221
+
222
+ /**
223
+ * Validate the notifications before displaying them.
224
+ *
225
+ * @since 1.0.0
226
+ *
227
+ * @param array $plugin_notifications An array of plugin notifications.
228
+ *
229
+ * @return array A filtered array of plugin notifications.
230
+ */
231
+ public function validate_notifications( $plugin_notifications ) {
232
+ global $pagenow;
233
+
234
+ foreach ( $plugin_notifications as $key => $notification ) {
235
+ // Location validation.
236
+ $location = (array) json_decode( get_post_meta( $notification->ID, 'location', true ) );
237
+ $continue = false;
238
+ if ( ! in_array( 'everywhere', $location, true ) ) {
239
+ if ( in_array( 'index.php', $location, true ) && 'index.php' === $pagenow ) {
240
+ $continue = true;
241
+ }
242
+
243
+ if ( in_array( 'plugins.php', $location, true ) && 'plugins.php' === $pagenow ) {
244
+ $continue = true;
245
+ }
246
+
247
+ if ( ! $continue ) {
248
+ unset( $plugin_notifications[ $key ] );
249
+ }
250
+ }
251
+
252
+ // Plugin validation (OR conditional).
253
+ $plugins = (array) json_decode( get_post_meta( $notification->ID, 'plugins', true ) );
254
+ $continue = false;
255
+ if ( ! empty( $plugins ) ) {
256
+ foreach ( $plugins as $plugin ) {
257
+ if ( is_plugin_active( $plugin ) ) {
258
+ $continue = true;
259
+ }
260
+ }
261
+
262
+ if ( ! $continue ) {
263
+ unset( $plugin_notifications[ $key ] );
264
+ }
265
+ }
266
+
267
+ // Theme validation.
268
+ $theme = get_post_meta( $notification->ID, 'theme', true );
269
+ $continue = (string) wp_get_theme() === $theme;
270
+
271
+ if ( ! empty( $theme ) && ! $continue ) {
272
+ unset( $plugin_notifications[ $key ] );
273
+ }
274
+
275
+ // Version validation.
276
+ $version = get_post_meta( $notification->ID, 'version', true );
277
+ $continue = false;
278
+ if ( ! empty( $version ) ) {
279
+ if ( version_compare( $this->plugin_version, $version, '<=' ) ) {
280
+ $continue = true;
281
+ }
282
+
283
+ if ( ! $continue ) {
284
+ unset( $plugin_notifications[ $key ] );
285
+ }
286
+ }
287
+
288
+ // Expiration validation.
289
+ $expiration = get_post_meta( $notification->ID, 'expiration', true );
290
+ $continue = false;
291
+ if ( ! empty( $expiration ) ) {
292
+ if ( $expiration > time() ) {
293
+ $continue = true;
294
+ }
295
+
296
+ if ( ! $continue ) {
297
+ unset( $plugin_notifications[ $key ] );
298
+ }
299
+ }
300
+
301
+ // Plan validation.
302
+ $plans = (array) json_decode( get_post_meta( $notification->ID, 'plans', true ) );
303
+ $continue = false;
304
+ if ( ! empty( $plans ) ) {
305
+ $level = $this->get_plan_level();
306
+ if ( in_array( $level, $plans, true ) ) {
307
+ $continue = true;
308
+ }
309
+
310
+ if ( ! $continue ) {
311
+ unset( $plugin_notifications[ $key ] );
312
+ }
313
+ }
314
+ }
315
+
316
+ return $plugin_notifications;
317
+ }
318
+
319
+ /**
320
+ * Grab the current plan level.
321
+ *
322
+ * @since 1.0.0
323
+ *
324
+ * @return string The current plan level.
325
+ */
326
+ public function get_plan_level() {
327
+ // Prepare variables.
328
+ $key = '';
329
+ $level = '';
330
+ $option = false;
331
+ switch ( $this->plugin ) {
332
+ case 'wpforms' :
333
+ $option = get_option( 'wpforms_license' );
334
+ $key = is_array( $option ) && isset( $option['key'] ) ? $option['key'] : '';
335
+ $level = is_array( $option ) && isset( $option['type'] ) ? $option['type'] : '';
336
+
337
+ // Possibly check for a constant.
338
+ if ( empty( $key ) && defined( 'WPFORMS_LICENSE_KEY' ) ) {
339
+ $key = WPFORMS_LICENSE_KEY;
340
+ }
341
+ break;
342
+ case 'mi' :
343
+ $option = get_option( 'monsterinsights_license' );
344
+ $key = is_array( $option ) && isset( $option['key'] ) ? $option['key'] : '';
345
+ $level = is_array( $option ) && isset( $option['type'] ) ? $option['type'] : '';
346
+
347
+ // Possibly check for a constant.
348
+ if ( empty( $key ) && defined( 'MONSTERINSIGHTS_LICENSE_KEY' ) && is_string( MONSTERINSIGHTS_LICENSE_KEY ) && strlen( MONSTERINSIGHTS_LICENSE_KEY ) > 10 ) {
349
+ $key = MONSTERINSIGHTS_LICENSE_KEY;
350
+ }
351
+ break;
352
+ case 'sol' :
353
+ $option = get_option( 'soliloquy' );
354
+ $key = is_array( $option ) && isset( $option['key'] ) ? $option['key'] : '';
355
+ $level = is_array( $option ) && isset( $option['type'] ) ? $option['type'] : '';
356
+
357
+ // Possibly check for a constant.
358
+ if ( empty( $key ) && defined( 'SOLILOQUY_LICENSE_KEY' ) ) {
359
+ $key = SOLILOQUY_LICENSE_KEY;
360
+ }
361
+ break;
362
+ case 'envira' :
363
+ $option = get_option( 'envira_gallery' );
364
+ $key = is_array( $option ) && isset( $option['key'] ) ? $option['key'] : '';
365
+ $level = is_array( $option ) && isset( $option['type'] ) ? $option['type'] : '';
366
+
367
+ // Possibly check for a constant.
368
+ if ( empty( $key ) && defined( 'ENVIRA_LICENSE_KEY' ) ) {
369
+ $key = ENVIRA_LICENSE_KEY;
370
+ }
371
+ break;
372
+ case 'om' :
373
+ $option = get_option( 'optin_monster_api' );
374
+ $key = is_array( $option ) && isset( $option['api']['apikey'] ) ? $option['api']['apikey'] : '';
375
+
376
+ // Possibly check for a constant.
377
+ if ( empty( $key ) && defined( 'OPTINMONSTER_REST_API_LICENSE_KEY' ) ) {
378
+ $key = OPTINMONSTER_REST_API_LICENSE_KEY;
379
+ }
380
+
381
+ // If the key is still empty, check for the old legacy key.
382
+ if ( empty( $key ) ) {
383
+ $key = is_array( $option ) && isset( $option['api']['key'] ) ? $option['api']['key'] : '';
384
+ }
385
+ break;
386
+ }
387
+
388
+ // Possibly set the level to 'none' if the key is empty and no level has been set.
389
+ if ( empty( $key ) && empty( $level ) ) {
390
+ $level = 'none';
391
+ }
392
+
393
+ // Normalize the level.
394
+ switch ( $level ) {
395
+ case 'bronze' :
396
+ case 'personal' :
397
+ $level = 'basic';
398
+ break;
399
+ case 'silver' :
400
+ case 'multi' :
401
+ $level = 'plus';
402
+ break;
403
+ case 'gold' :
404
+ case 'developer' :
405
+ $level = 'pro';
406
+ break;
407
+ case 'platinum' :
408
+ case 'master' :
409
+ $level = 'ultimate';
410
+ break;
411
+ }
412
+
413
+ // Return the plan level.
414
+ return $level;
415
+ }
416
+
417
+ /**
418
+ * Dismiss the notification via AJAX.
419
+ *
420
+ * @since 1.0.0
421
+ */
422
+ public function dismiss_notification() {
423
+ if ( ! current_user_can( apply_filters( 'am_notifications_display', 'manage_options' ) ) ) {
424
+ die;
425
+ }
426
+
427
+ $notification_id = intval( $_POST['notification_id'] );
428
+ update_post_meta( $notification_id, 'viewed', 1 );
429
+ die;
430
+ }
431
+
432
+ /**
433
+ * Revokes notifications.
434
+ *
435
+ * @since 1.0.0
436
+ *
437
+ * @param array $ids An array of notification IDs to revoke.
438
+ */
439
+ public function revoke_notifications( $ids ) {
440
+ // Loop through each of the IDs and find the post that has it as meta.
441
+ foreach ( (array) $ids as $id ) {
442
+ $notifications = $this->get_plugin_notifications( -1, array( 'post_status' => 'all', 'meta_key' => 'notification_id', 'meta_value' => $id ) );
443
+ if ( $notifications ) {
444
+ foreach ( $notifications as $notification ) {
445
+ update_post_meta( $notification->ID, 'viewed', 1 );
446
+ }
447
+ }
448
+ }
449
+ }
450
+ }
languages/wp-mail-smtp.pot CHANGED
@@ -142,11 +142,11 @@ msgstr ""
142
  msgid "Use TLS encryption."
143
  msgstr ""
144
 
145
- #: wp_mail_smtp.php:462, src/Providers/OptionAbstract.php:186
146
  msgid "TLS is not the same as STARTTLS. For most servers SSL is the recommended option."
147
  msgstr ""
148
 
149
- #: wp_mail_smtp.php:467, wp_mail_smtp.php:471, src/Providers/OptionAbstract.php:195
150
  msgid "Authentication"
151
  msgstr ""
152
 
@@ -238,31 +238,43 @@ msgstr ""
238
  msgid "TLS"
239
  msgstr ""
240
 
241
- #: src/Providers/OptionAbstract.php:205
 
 
 
 
 
 
 
 
242
  msgid "On"
243
  msgstr ""
244
 
245
- #: src/Providers/OptionAbstract.php:206
246
  msgid "Off"
247
  msgstr ""
248
 
249
- #: src/Providers/OptionAbstract.php:214
 
 
 
 
250
  msgid "SMTP Username"
251
  msgstr ""
252
 
253
- #: src/Providers/OptionAbstract.php:228
254
  msgid "SMTP Password"
255
  msgstr ""
256
 
257
- #: src/Providers/OptionAbstract.php:242
258
  msgid "The password is stored in plain text. We highly recommend you setup your password in your WordPress configuration file for improved security; to do this add the lines below to your %s file."
259
  msgstr ""
260
 
261
- #: src/Providers/OptionAbstract.php:279
262
  msgid "%1$s requires PHP %2$s to work and does not support your current PHP version %3$s. Please contact your host and request a PHP upgrade to the latest one."
263
  msgstr ""
264
 
265
- #: src/Providers/OptionAbstract.php:286
266
  msgid "Meanwhile you can switch to the \"Other SMTP\" Mailer option."
267
  msgstr ""
268
 
@@ -350,6 +362,10 @@ msgstr ""
350
  msgid "The related debugging output is shown below:"
351
  msgstr ""
352
 
 
 
 
 
353
  #: src/Providers/Gmail/Options.php:25
354
  msgid "Gmail"
355
  msgstr ""
142
  msgid "Use TLS encryption."
143
  msgstr ""
144
 
145
+ #: wp_mail_smtp.php:462
146
  msgid "TLS is not the same as STARTTLS. For most servers SSL is the recommended option."
147
  msgstr ""
148
 
149
+ #: wp_mail_smtp.php:467, wp_mail_smtp.php:471, src/Providers/OptionAbstract.php:216
150
  msgid "Authentication"
151
  msgstr ""
152
 
238
  msgid "TLS"
239
  msgstr ""
240
 
241
+ #: src/Providers/OptionAbstract.php:186
242
+ msgid "For most servers TLS is the recommended option. If your SMTP provider offers both SSL and TLS options, we recommend using TLS."
243
+ msgstr ""
244
+
245
+ #: src/Providers/OptionAbstract.php:194
246
+ msgid "Auto TLS"
247
+ msgstr ""
248
+
249
+ #: src/Providers/OptionAbstract.php:204, src/Providers/OptionAbstract.php:226
250
  msgid "On"
251
  msgstr ""
252
 
253
+ #: src/Providers/OptionAbstract.php:205, src/Providers/OptionAbstract.php:227
254
  msgid "Off"
255
  msgstr ""
256
 
257
+ #: src/Providers/OptionAbstract.php:208
258
+ msgid "By default TLS encryption is automatically used if the server supports it, which is recommended. In some cases, due to server misconfigurations, this can cause issues and may need to be disabled."
259
+ msgstr ""
260
+
261
+ #: src/Providers/OptionAbstract.php:235
262
  msgid "SMTP Username"
263
  msgstr ""
264
 
265
+ #: src/Providers/OptionAbstract.php:249
266
  msgid "SMTP Password"
267
  msgstr ""
268
 
269
+ #: src/Providers/OptionAbstract.php:263
270
  msgid "The password is stored in plain text. We highly recommend you setup your password in your WordPress configuration file for improved security; to do this add the lines below to your %s file."
271
  msgstr ""
272
 
273
+ #: src/Providers/OptionAbstract.php:300
274
  msgid "%1$s requires PHP %2$s to work and does not support your current PHP version %3$s. Please contact your host and request a PHP upgrade to the latest one."
275
  msgstr ""
276
 
277
+ #: src/Providers/OptionAbstract.php:307
278
  msgid "Meanwhile you can switch to the \"Other SMTP\" Mailer option."
279
  msgstr ""
280
 
362
  msgid "The related debugging output is shown below:"
363
  msgstr ""
364
 
365
+ #: src/Admin/Pages/Test.php:136
366
+ msgid "Please copy only the content of the error debug message above, identified with an orange left border, into the support forum topic if you experience any issues."
367
+ msgstr ""
368
+
369
  #: src/Providers/Gmail/Options.php:25
370
  msgid "Gmail"
371
  msgstr ""
readme.txt CHANGED
@@ -146,6 +146,16 @@ By all means please contact us to discuss features or options you'd like to see
146
 
147
  == Changelog ==
148
 
 
 
 
 
 
 
 
 
 
 
149
  = 1.0.2 - 2017-12-12 =
150
  * Fixed: PHPMailer using incorrect SMTPSecure value.
151
 
146
 
147
  == Changelog ==
148
 
149
+ = 1.1.0 - 2017-12-18 =
150
+ * Added: New option "Auto TLS" for SMTP mailer. Default is enabled. Migration routine for all sites.
151
+ * Changed: Improve debug output - clear styles and context-aware content.
152
+ * Changed: Better exceptions handling for Google authentication process.
153
+ * Changed: Do not sanitize passwords, api keys etc - as they may contain special characters in certain order and sanitization will break those values.
154
+ * Changed: Improve wording of some helpful texts inside plugin admin area.
155
+ * Fixed: Do not include certain files in dependency libraries that are not used by Google mailer. This should stop flagging plugin by Wordfence and VaultPress.
156
+ * Fixed: Constants usage is working now, to define the SMTP password, for example.
157
+ * Fixed: Notice for default mailer.
158
+
159
  = 1.0.2 - 2017-12-12 =
160
  * Fixed: PHPMailer using incorrect SMTPSecure value.
161
 
src/AM_Notification.php CHANGED
@@ -1,452 +1,452 @@
1
- <?php
2
-
3
- namespace WPMailSMTP;
4
-
5
- /**
6
- * Awesome Motive Notifications
7
- *
8
- * This creates a custom post type (if it doesn't exist) and calls the API to
9
- * retrieve notifications for this product.
10
- *
11
- * @package AwesomeMotive
12
- * @author Benjamin Rojas
13
- * @license GPL-2.0+
14
- * @copyright Copyright (c) 2017, Retyp LLC
15
- * @version 1.0.2
16
- */
17
- class AM_Notification {
18
- /**
19
- * The api url we are calling.
20
- *
21
- * @since 1.0.0
22
- *
23
- * @var string
24
- */
25
- public $api_url = 'https://api.awesomemotive.com/v1/notification/';
26
-
27
- /**
28
- * A unique slug for this plugin.
29
- * (Not the WordPress plugin slug)
30
- *
31
- * @since 1.0.0
32
- *
33
- * @var string
34
- */
35
- public $plugin;
36
-
37
- /**
38
- * The current plugin version.
39
- *
40
- * @since 1.0.0
41
- *
42
- * @var string
43
- */
44
- public $plugin_version;
45
-
46
- /**
47
- * Flag if a notice has been registered.
48
- *
49
- * @since 1.0.0
50
- *
51
- * @var bool
52
- */
53
- public static $registered = false;
54
-
55
- /**
56
- * Construct.
57
- *
58
- * @since 1.0.0
59
- *
60
- * @param string $plugin The plugin slug.
61
- * @param mixed $version The version of the plugin.
62
- */
63
- public function __construct( $plugin = '', $version = 0 ) {
64
- $this->plugin = $plugin;
65
- $this->plugin_version = $version;
66
-
67
- add_action( 'init', array( $this, 'custom_post_type' ) );
68
- add_action( 'admin_init', array( $this, 'get_remote_notifications' ), 100 );
69
- add_action( 'admin_notices', array( $this, 'display_notifications' ) );
70
- add_action( 'wp_ajax_am_notification_dismiss', array( $this, 'dismiss_notification' ) );
71
- }
72
-
73
- /**
74
- * Registers a custom post type.
75
- *
76
- * @since 1.0.0
77
- */
78
- public function custom_post_type() {
79
- register_post_type( 'amn_' . $this->plugin, array(
80
- 'label' => $this->plugin . ' Announcements',
81
- 'can_export' => false,
82
- 'supports' => false,
83
- ) );
84
- }
85
-
86
- /**
87
- * Retrieve the remote notifications if the time has expired.
88
- *
89
- * @since 1.0.0
90
- */
91
- public function get_remote_notifications() {
92
- if ( ! current_user_can( apply_filters( 'am_notifications_display', 'manage_options' ) ) ) {
93
- return;
94
- }
95
-
96
- $last_checked = get_option( '_amn_' . $this->plugin . '_last_checked', strtotime( '-1 week' ) );
97
-
98
- if ( $last_checked < strtotime( 'today midnight' ) ) {
99
- $plugin_notifications = $this->get_plugin_notifications( 1 );
100
- $notification_id = null;
101
-
102
- if ( ! empty( $plugin_notifications ) ) {
103
- // Unset it from the array.
104
- $notification = $plugin_notifications[0];
105
- $notification_id = get_post_meta( $notification->ID, 'notification_id', true );
106
- }
107
-
108
- $response = wp_remote_retrieve_body( wp_remote_post( $this->api_url, array(
109
- 'body' => array(
110
- 'slug' => $this->plugin,
111
- 'version' => $this->plugin_version,
112
- 'last_notification' => $notification_id,
113
- ),
114
- ) ) );
115
-
116
- $data = json_decode( $response );
117
-
118
- if ( ! empty( $data->id ) ) {
119
- $notifications = array();
120
-
121
- foreach ( (array) $data->slugs as $slug ) {
122
- $notifications = array_merge(
123
- $notifications,
124
- (array) get_posts(
125
- array(
126
- 'post_type' => 'amn_' . $slug,
127
- 'post_status' => 'all',
128
- 'meta_key' => 'notification_id',
129
- 'meta_value' => $data->id,
130
- )
131
- )
132
- );
133
- }
134
-
135
- if ( empty( $notifications ) ) {
136
- $new_notification_id = wp_insert_post( array(
137
- 'post_content' => wp_kses_post( $data->content ),
138
- 'post_type' => 'amn_' . $this->plugin,
139
- ) );
140
-
141
- update_post_meta( $new_notification_id, 'notification_id', absint( $data->id ) );
142
- update_post_meta( $new_notification_id, 'type', sanitize_text_field( trim( $data->type ) ) );
143
- update_post_meta( $new_notification_id, 'dismissable', (bool) $data->dismissible ? 1 : 0 );
144
- update_post_meta( $new_notification_id, 'location', function_exists( 'wp_json_encode' ) ? wp_json_encode( $data->location ) : json_encode( $data->location ) );
145
- update_post_meta( $new_notification_id, 'version', sanitize_text_field( trim( $data->version ) ) );
146
- update_post_meta( $new_notification_id, 'viewed', 0 );
147
- update_post_meta( $new_notification_id, 'expiration', $data->expiration ? absint( $data->expiration ) : false );
148
- update_post_meta( $new_notification_id, 'plans', function_exists( 'wp_json_encode' ) ? wp_json_encode( $data->plans ) : json_encode( $data->plans ) );
149
- }
150
- }
151
-
152
- // Possibly revoke notifications.
153
- if ( ! empty( $data->revoked ) ) {
154
- $this->revoke_notifications( $data->revoked );
155
- }
156
-
157
- // Set the option now so we can't run this again until after 24 hours.
158
- update_option( '_amn_' . $this->plugin . '_last_checked', strtotime( 'today midnight' ) );
159
- }
160
- }
161
-
162
- /**
163
- * Get local plugin notifications that have already been set.
164
- *
165
- * @since 1.0.0
166
- *
167
- * @param integer $limit Set the limit for how many posts to retrieve.
168
- * @param array $args Any top-level arguments to add to the array.
169
- *
170
- * @return WP_Post[] WP_Post that match the query.
171
- */
172
- public function get_plugin_notifications( $limit = -1, $args = array() ) {
173
- return get_posts(
174
- array(
175
- 'posts_per_page' => $limit,
176
- 'post_type' => 'amn_' . $this->plugin,
177
- ) + $args
178
- );
179
- }
180
-
181
- /**
182
- * Display any notifications that should be displayed.
183
- *
184
- * @since 1.0.0
185
- */
186
- public function display_notifications() {
187
- if ( ! current_user_can( apply_filters( 'am_notifications_display', 'manage_options' ) ) ) {
188
- return;
189
- }
190
-
191
- $plugin_notifications = $this->get_plugin_notifications( -1, array(
192
- 'post_status' => 'all',
193
- 'meta_key' => 'viewed',
194
- 'meta_value' => '0',
195
- ) );
196
-
197
- $plugin_notifications = $this->validate_notifications( $plugin_notifications );
198
-
199
- if ( ! empty( $plugin_notifications ) && ! self::$registered ) {
200
- foreach ( $plugin_notifications as $notification ) {
201
- $dismissable = get_post_meta( $notification->ID, 'dismissable', true );
202
- $type = get_post_meta( $notification->ID, 'type', true );
203
- ?>
204
- <div class="am-notification am-notification-<?php echo $notification->ID; ?> notice notice-<?php echo $type; ?><?php echo $dismissable ? ' is-dismissible' : ''; ?>">
205
- <?php echo $notification->post_content; ?>
206
- </div>
207
- <script type="text/javascript">
208
- jQuery(document).ready(function ($) {
209
- $(document).on('click', '.am-notification-<?php echo $notification->ID; ?> button.notice-dismiss', function (event) {
210
- $.post(ajaxurl, {
211
- action: 'am_notification_dismiss',
212
- notification_id: '<?php echo $notification->ID; ?>'
213
- });
214
- });
215
- });
216
- </script>
217
- <?php
218
- }
219
-
220
- self::$registered = true;
221
- }
222
- }
223
-
224
- /**
225
- * Validate the notifications before displaying them.
226
- *
227
- * @since 1.0.0
228
- *
229
- * @param array $plugin_notifications An array of plugin notifications.
230
- *
231
- * @return array A filtered array of plugin notifications.
232
- */
233
- public function validate_notifications( $plugin_notifications ) {
234
- global $pagenow;
235
-
236
- foreach ( $plugin_notifications as $key => $notification ) {
237
- // Location validation.
238
- $location = (array) json_decode( get_post_meta( $notification->ID, 'location', true ) );
239
- $continue = false;
240
- if ( ! in_array( 'everywhere', $location, true ) ) {
241
- if ( in_array( 'index.php', $location, true ) && 'index.php' === $pagenow ) {
242
- $continue = true;
243
- }
244
-
245
- if ( in_array( 'plugins.php', $location, true ) && 'plugins.php' === $pagenow ) {
246
- $continue = true;
247
- }
248
-
249
- if ( ! $continue ) {
250
- unset( $plugin_notifications[ $key ] );
251
- }
252
- }
253
-
254
- // Plugin validation (OR conditional).
255
- $plugins = (array) json_decode( get_post_meta( $notification->ID, 'plugins', true ) );
256
- $continue = false;
257
- if ( ! empty( $plugins ) ) {
258
- foreach ( $plugins as $plugin ) {
259
- if ( is_plugin_active( $plugin ) ) {
260
- $continue = true;
261
- }
262
- }
263
-
264
- if ( ! $continue ) {
265
- unset( $plugin_notifications[ $key ] );
266
- }
267
- }
268
-
269
- // Theme validation.
270
- $theme = get_post_meta( $notification->ID, 'theme', true );
271
- $continue = (string) wp_get_theme() === $theme;
272
-
273
- if ( ! empty( $theme ) && ! $continue ) {
274
- unset( $plugin_notifications[ $key ] );
275
- }
276
-
277
- // Version validation.
278
- $version = get_post_meta( $notification->ID, 'version', true );
279
- $continue = false;
280
- if ( ! empty( $version ) ) {
281
- if ( version_compare( $this->plugin_version, $version, '<=' ) ) {
282
- $continue = true;
283
- }
284
-
285
- if ( ! $continue ) {
286
- unset( $plugin_notifications[ $key ] );
287
- }
288
- }
289
-
290
- // Expiration validation.
291
- $expiration = get_post_meta( $notification->ID, 'expiration', true );
292
- $continue = false;
293
- if ( ! empty( $expiration ) ) {
294
- if ( $expiration > time() ) {
295
- $continue = true;
296
- }
297
-
298
- if ( ! $continue ) {
299
- unset( $plugin_notifications[ $key ] );
300
- }
301
- }
302
-
303
- // Plan validation.
304
- $plans = (array) json_decode( get_post_meta( $notification->ID, 'plans', true ) );
305
- $continue = false;
306
- if ( ! empty( $plans ) ) {
307
- $level = $this->get_plan_level();
308
- if ( in_array( $level, $plans, true ) ) {
309
- $continue = true;
310
- }
311
-
312
- if ( ! $continue ) {
313
- unset( $plugin_notifications[ $key ] );
314
- }
315
- }
316
- }
317
-
318
- return $plugin_notifications;
319
- }
320
-
321
- /**
322
- * Grab the current plan level.
323
- *
324
- * @since 1.0.0
325
- *
326
- * @return string The current plan level.
327
- */
328
- public function get_plan_level() {
329
- // Prepare variables.
330
- $key = '';
331
- $level = '';
332
- $option = false;
333
- switch ( $this->plugin ) {
334
- case 'wpforms' :
335
- $option = get_option( 'wpforms_license' );
336
- $key = is_array( $option ) && isset( $option['key'] ) ? $option['key'] : '';
337
- $level = is_array( $option ) && isset( $option['type'] ) ? $option['type'] : '';
338
-
339
- // Possibly check for a constant.
340
- if ( empty( $key ) && defined( 'WPFORMS_LICENSE_KEY' ) ) {
341
- $key = WPFORMS_LICENSE_KEY;
342
- }
343
- break;
344
- case 'mi' :
345
- $option = get_option( 'monsterinsights_license' );
346
- $key = is_array( $option ) && isset( $option['key'] ) ? $option['key'] : '';
347
- $level = is_array( $option ) && isset( $option['type'] ) ? $option['type'] : '';
348
-
349
- // Possibly check for a constant.
350
- if ( empty( $key ) && defined( 'MONSTERINSIGHTS_LICENSE_KEY' ) && is_string( MONSTERINSIGHTS_LICENSE_KEY ) && strlen( MONSTERINSIGHTS_LICENSE_KEY ) > 10 ) {
351
- $key = MONSTERINSIGHTS_LICENSE_KEY;
352
- }
353
- break;
354
- case 'sol' :
355
- $option = get_option( 'soliloquy' );
356
- $key = is_array( $option ) && isset( $option['key'] ) ? $option['key'] : '';
357
- $level = is_array( $option ) && isset( $option['type'] ) ? $option['type'] : '';
358
-
359
- // Possibly check for a constant.
360
- if ( empty( $key ) && defined( 'SOLILOQUY_LICENSE_KEY' ) ) {
361
- $key = SOLILOQUY_LICENSE_KEY;
362
- }
363
- break;
364
- case 'envira' :
365
- $option = get_option( 'envira_gallery' );
366
- $key = is_array( $option ) && isset( $option['key'] ) ? $option['key'] : '';
367
- $level = is_array( $option ) && isset( $option['type'] ) ? $option['type'] : '';
368
-
369
- // Possibly check for a constant.
370
- if ( empty( $key ) && defined( 'ENVIRA_LICENSE_KEY' ) ) {
371
- $key = ENVIRA_LICENSE_KEY;
372
- }
373
- break;
374
- case 'om' :
375
- $option = get_option( 'optin_monster_api' );
376
- $key = is_array( $option ) && isset( $option['api']['apikey'] ) ? $option['api']['apikey'] : '';
377
-
378
- // Possibly check for a constant.
379
- if ( empty( $key ) && defined( 'OPTINMONSTER_REST_API_LICENSE_KEY' ) ) {
380
- $key = OPTINMONSTER_REST_API_LICENSE_KEY;
381
- }
382
-
383
- // If the key is still empty, check for the old legacy key.
384
- if ( empty( $key ) ) {
385
- $key = is_array( $option ) && isset( $option['api']['key'] ) ? $option['api']['key'] : '';
386
- }
387
- break;
388
- }
389
-
390
- // Possibly set the level to 'none' if the key is empty and no level has been set.
391
- if ( empty( $key ) && empty( $level ) ) {
392
- $level = 'none';
393
- }
394
-
395
- // Normalize the level.
396
- switch ( $level ) {
397
- case 'bronze' :
398
- case 'personal' :
399
- $level = 'basic';
400
- break;
401
- case 'silver' :
402
- case 'multi' :
403
- $level = 'plus';
404
- break;
405
- case 'gold' :
406
- case 'developer' :
407
- $level = 'pro';
408
- break;
409
- case 'platinum' :
410
- case 'master' :
411
- $level = 'ultimate';
412
- break;
413
- }
414
-
415
- // Return the plan level.
416
- return $level;
417
- }
418
-
419
- /**
420
- * Dismiss the notification via AJAX.
421
- *
422
- * @since 1.0.0
423
- */
424
- public function dismiss_notification() {
425
- if ( ! current_user_can( apply_filters( 'am_notifications_display', 'manage_options' ) ) ) {
426
- die;
427
- }
428
-
429
- $notification_id = intval( $_POST['notification_id'] );
430
- update_post_meta( $notification_id, 'viewed', 1 );
431
- die;
432
- }
433
-
434
- /**
435
- * Revokes notifications.
436
- *
437
- * @since 1.0.0
438
- *
439
- * @param array $ids An array of notification IDs to revoke.
440
- */
441
- public function revoke_notifications( $ids ) {
442
- // Loop through each of the IDs and find the post that has it as meta.
443
- foreach ( (array) $ids as $id ) {
444
- $notifications = $this->get_plugin_notifications( -1, array( 'post_status' => 'all', 'meta_key' => 'notification_id', 'meta_value' => $id ) );
445
- if ( $notifications ) {
446
- foreach ( $notifications as $notification ) {
447
- update_post_meta( $notification->ID, 'viewed', 1 );
448
- }
449
- }
450
- }
451
- }
452
- }
1
+ <?php
2
+
3
+ namespace WPMailSMTP;
4
+
5
+ /**
6
+ * Awesome Motive Notifications
7
+ *
8
+ * This creates a custom post type (if it doesn't exist) and calls the API to
9
+ * retrieve notifications for this product.
10
+ *
11
+ * @package AwesomeMotive
12
+ * @author Benjamin Rojas
13
+ * @license GPL-2.0+
14
+ * @copyright Copyright (c) 2017, Retyp LLC
15
+ * @version 1.0.2
16
+ */
17
+ class AM_Notification {
18
+ /**
19
+ * The api url we are calling.
20
+ *
21
+ * @since 1.0.0
22
+ *
23
+ * @var string
24
+ */
25
+ public $api_url = 'https://api.awesomemotive.com/v1/notification/';
26
+
27
+ /**
28
+ * A unique slug for this plugin.
29
+ * (Not the WordPress plugin slug)
30
+ *
31
+ * @since 1.0.0
32
+ *
33
+ * @var string
34
+ */
35
+ public $plugin;
36
+
37
+ /**
38
+ * The current plugin version.
39
+ *
40
+ * @since 1.0.0
41
+ *
42
+ * @var string
43
+ */
44
+ public $plugin_version;
45
+
46
+ /**
47
+ * Flag if a notice has been registered.
48
+ *
49
+ * @since 1.0.0
50
+ *
51
+ * @var bool
52
+ */
53
+ public static $registered = false;
54
+
55
+ /**
56
+ * Construct.
57
+ *
58
+ * @since 1.0.0
59
+ *
60
+ * @param string $plugin The plugin slug.
61
+ * @param mixed $version The version of the plugin.
62
+ */
63
+ public function __construct( $plugin = '', $version = 0 ) {
64
+ $this->plugin = $plugin;
65
+ $this->plugin_version = $version;
66
+
67
+ add_action( 'init', array( $this, 'custom_post_type' ) );
68
+ add_action( 'admin_init', array( $this, 'get_remote_notifications' ), 100 );
69
+ add_action( 'admin_notices', array( $this, 'display_notifications' ) );
70
+ add_action( 'wp_ajax_am_notification_dismiss', array( $this, 'dismiss_notification' ) );
71
+ }
72
+
73
+ /**
74
+ * Registers a custom post type.
75
+ *
76
+ * @since 1.0.0
77
+ */
78
+ public function custom_post_type() {
79
+ register_post_type( 'amn_' . $this->plugin, array(
80
+ 'label' => $this->plugin . ' Announcements',
81
+ 'can_export' => false,
82
+ 'supports' => false,
83
+ ) );
84
+ }
85
+
86
+ /**
87
+ * Retrieve the remote notifications if the time has expired.
88
+ *
89
+ * @since 1.0.0
90
+ */
91
+ public function get_remote_notifications() {
92
+ if ( ! current_user_can( apply_filters( 'am_notifications_display', 'manage_options' ) ) ) {
93
+ return;
94
+ }
95
+
96
+ $last_checked = get_option( '_amn_' . $this->plugin . '_last_checked', strtotime( '-1 week' ) );
97
+
98
+ if ( $last_checked < strtotime( 'today midnight' ) ) {
99
+ $plugin_notifications = $this->get_plugin_notifications( 1 );
100
+ $notification_id = null;
101
+
102
+ if ( ! empty( $plugin_notifications ) ) {
103
+ // Unset it from the array.
104
+ $notification = $plugin_notifications[0];
105
+ $notification_id = get_post_meta( $notification->ID, 'notification_id', true );
106
+ }
107
+
108
+ $response = wp_remote_retrieve_body( wp_remote_post( $this->api_url, array(
109
+ 'body' => array(
110
+ 'slug' => $this->plugin,
111
+ 'version' => $this->plugin_version,
112
+ 'last_notification' => $notification_id,
113
+ ),
114
+ ) ) );
115
+
116
+ $data = json_decode( $response );
117
+
118
+ if ( ! empty( $data->id ) ) {
119
+ $notifications = array();
120
+
121
+ foreach ( (array) $data->slugs as $slug ) {
122
+ $notifications = array_merge(
123
+ $notifications,
124
+ (array) get_posts(
125
+ array(
126
+ 'post_type' => 'amn_' . $slug,
127
+ 'post_status' => 'all',
128
+ 'meta_key' => 'notification_id',
129
+ 'meta_value' => $data->id,
130
+ )
131
+ )
132
+ );
133
+ }
134
+
135
+ if ( empty( $notifications ) ) {
136
+ $new_notification_id = wp_insert_post( array(
137
+ 'post_content' => wp_kses_post( $data->content ),
138
+ 'post_type' => 'amn_' . $this->plugin,
139
+ ) );
140
+
141
+ update_post_meta( $new_notification_id, 'notification_id', absint( $data->id ) );
142
+ update_post_meta( $new_notification_id, 'type', sanitize_text_field( trim( $data->type ) ) );
143
+ update_post_meta( $new_notification_id, 'dismissable', (bool) $data->dismissible ? 1 : 0 );
144
+ update_post_meta( $new_notification_id, 'location', function_exists( 'wp_json_encode' ) ? wp_json_encode( $data->location ) : json_encode( $data->location ) );
145
+ update_post_meta( $new_notification_id, 'version', sanitize_text_field( trim( $data->version ) ) );
146
+ update_post_meta( $new_notification_id, 'viewed', 0 );
147
+ update_post_meta( $new_notification_id, 'expiration', $data->expiration ? absint( $data->expiration ) : false );
148
+ update_post_meta( $new_notification_id, 'plans', function_exists( 'wp_json_encode' ) ? wp_json_encode( $data->plans ) : json_encode( $data->plans ) );
149
+ }
150
+ }
151
+
152
+ // Possibly revoke notifications.
153
+ if ( ! empty( $data->revoked ) ) {
154
+ $this->revoke_notifications( $data->revoked );
155
+ }
156
+
157
+ // Set the option now so we can't run this again until after 24 hours.
158
+ update_option( '_amn_' . $this->plugin . '_last_checked', strtotime( 'today midnight' ) );
159
+ }
160
+ }
161
+
162
+ /**
163
+ * Get local plugin notifications that have already been set.
164
+ *
165
+ * @since 1.0.0
166
+ *
167
+ * @param integer $limit Set the limit for how many posts to retrieve.
168
+ * @param array $args Any top-level arguments to add to the array.
169
+ *
170
+ * @return WP_Post[] WP_Post that match the query.
171
+ */
172
+ public function get_plugin_notifications( $limit = -1, $args = array() ) {
173
+ return get_posts(
174
+ array(
175
+ 'posts_per_page' => $limit,
176
+ 'post_type' => 'amn_' . $this->plugin,
177
+ ) + $args
178
+ );
179
+ }
180
+
181
+ /**
182
+ * Display any notifications that should be displayed.
183
+ *
184
+ * @since 1.0.0
185
+ */
186
+ public function display_notifications() {
187
+ if ( ! current_user_can( apply_filters( 'am_notifications_display', 'manage_options' ) ) ) {
188
+ return;
189
+ }
190
+
191
+ $plugin_notifications = $this->get_plugin_notifications( -1, array(
192
+ 'post_status' => 'all',
193
+ 'meta_key' => 'viewed',
194
+ 'meta_value' => '0',
195
+ ) );
196
+
197
+ $plugin_notifications = $this->validate_notifications( $plugin_notifications );
198
+
199
+ if ( ! empty( $plugin_notifications ) && ! self::$registered ) {
200
+ foreach ( $plugin_notifications as $notification ) {
201
+ $dismissable = get_post_meta( $notification->ID, 'dismissable', true );
202
+ $type = get_post_meta( $notification->ID, 'type', true );
203
+ ?>
204
+ <div class="am-notification am-notification-<?php echo $notification->ID; ?> notice notice-<?php echo $type; ?><?php echo $dismissable ? ' is-dismissible' : ''; ?>">
205
+ <?php echo $notification->post_content; ?>
206
+ </div>
207
+ <script type="text/javascript">
208
+ jQuery(document).ready(function ($) {
209
+ $(document).on('click', '.am-notification-<?php echo $notification->ID; ?> button.notice-dismiss', function (event) {
210
+ $.post(ajaxurl, {
211
+ action: 'am_notification_dismiss',
212
+ notification_id: '<?php echo $notification->ID; ?>'
213
+ });
214
+ });
215
+ });
216
+ </script>
217
+ <?php
218
+ }
219
+
220
+ self::$registered = true;
221
+ }
222
+ }
223
+
224
+ /**
225
+ * Validate the notifications before displaying them.
226
+ *
227
+ * @since 1.0.0
228
+ *
229
+ * @param array $plugin_notifications An array of plugin notifications.
230
+ *
231
+ * @return array A filtered array of plugin notifications.
232
+ */
233
+ public function validate_notifications( $plugin_notifications ) {
234
+ global $pagenow;
235
+
236
+ foreach ( $plugin_notifications as $key => $notification ) {
237
+ // Location validation.
238
+ $location = (array) json_decode( get_post_meta( $notification->ID, 'location', true ) );
239
+ $continue = false;
240
+ if ( ! in_array( 'everywhere', $location, true ) ) {
241
+ if ( in_array( 'index.php', $location, true ) && 'index.php' === $pagenow ) {
242
+ $continue = true;
243
+ }
244
+
245
+ if ( in_array( 'plugins.php', $location, true ) && 'plugins.php' === $pagenow ) {
246
+ $continue = true;
247
+ }
248
+
249
+ if ( ! $continue ) {
250
+ unset( $plugin_notifications[ $key ] );
251
+ }
252
+ }
253
+
254
+ // Plugin validation (OR conditional).
255
+ $plugins = (array) json_decode( get_post_meta( $notification->ID, 'plugins', true ) );
256
+ $continue = false;
257
+ if ( ! empty( $plugins ) ) {
258
+ foreach ( $plugins as $plugin ) {
259
+ if ( is_plugin_active( $plugin ) ) {
260
+ $continue = true;
261
+ }
262
+ }
263
+
264
+ if ( ! $continue ) {
265
+ unset( $plugin_notifications[ $key ] );
266
+ }
267
+ }
268
+
269
+ // Theme validation.
270
+ $theme = get_post_meta( $notification->ID, 'theme', true );
271
+ $continue = (string) wp_get_theme() === $theme;
272
+
273
+ if ( ! empty( $theme ) && ! $continue ) {
274
+ unset( $plugin_notifications[ $key ] );
275
+ }
276
+
277
+ // Version validation.
278
+ $version = get_post_meta( $notification->ID, 'version', true );
279
+ $continue = false;
280
+ if ( ! empty( $version ) ) {
281
+ if ( version_compare( $this->plugin_version, $version, '<=' ) ) {
282
+ $continue = true;
283
+ }
284
+
285
+ if ( ! $continue ) {
286
+ unset( $plugin_notifications[ $key ] );
287
+ }
288
+ }
289
+
290
+ // Expiration validation.
291
+ $expiration = get_post_meta( $notification->ID, 'expiration', true );
292
+ $continue = false;
293
+ if ( ! empty( $expiration ) ) {
294
+ if ( $expiration > time() ) {
295
+ $continue = true;
296
+ }
297
+
298
+ if ( ! $continue ) {
299
+ unset( $plugin_notifications[ $key ] );
300
+ }
301
+ }
302
+
303
+ // Plan validation.
304
+ $plans = (array) json_decode( get_post_meta( $notification->ID, 'plans', true ) );
305
+ $continue = false;
306
+ if ( ! empty( $plans ) ) {
307
+ $level = $this->get_plan_level();
308
+ if ( in_array( $level, $plans, true ) ) {
309
+ $continue = true;
310
+ }
311
+
312
+ if ( ! $continue ) {
313
+ unset( $plugin_notifications[ $key ] );
314
+ }
315
+ }
316
+ }
317
+
318
+ return $plugin_notifications;
319
+ }
320
+
321
+ /**
322
+ * Grab the current plan level.
323
+ *
324
+ * @since 1.0.0
325
+ *
326
+ * @return string The current plan level.
327
+ */
328
+ public function get_plan_level() {
329
+ // Prepare variables.
330
+ $key = '';
331
+ $level = '';
332
+ $option = false;
333
+ switch ( $this->plugin ) {
334
+ case 'wpforms' :
335
+ $option = get_option( 'wpforms_license' );
336
+ $key = is_array( $option ) && isset( $option['key'] ) ? $option['key'] : '';
337
+ $level = is_array( $option ) && isset( $option['type'] ) ? $option['type'] : '';
338
+
339
+ // Possibly check for a constant.
340
+ if ( empty( $key ) && defined( 'WPFORMS_LICENSE_KEY' ) ) {
341
+ $key = WPFORMS_LICENSE_KEY;
342
+ }
343
+ break;
344
+ case 'mi' :
345
+ $option = get_option( 'monsterinsights_license' );
346
+ $key = is_array( $option ) && isset( $option['key'] ) ? $option['key'] : '';
347
+ $level = is_array( $option ) && isset( $option['type'] ) ? $option['type'] : '';
348
+
349
+ // Possibly check for a constant.
350
+ if ( empty( $key ) && defined( 'MONSTERINSIGHTS_LICENSE_KEY' ) && is_string( MONSTERINSIGHTS_LICENSE_KEY ) && strlen( MONSTERINSIGHTS_LICENSE_KEY ) > 10 ) {
351
+ $key = MONSTERINSIGHTS_LICENSE_KEY;
352
+ }
353
+ break;
354
+ case 'sol' :
355
+ $option = get_option( 'soliloquy' );
356
+ $key = is_array( $option ) && isset( $option['key'] ) ? $option['key'] : '';
357
+ $level = is_array( $option ) && isset( $option['type'] ) ? $option['type'] : '';
358
+
359
+ // Possibly check for a constant.
360
+ if ( empty( $key ) && defined( 'SOLILOQUY_LICENSE_KEY' ) ) {
361
+ $key = SOLILOQUY_LICENSE_KEY;
362
+ }
363
+ break;
364
+ case 'envira' :
365
+ $option = get_option( 'envira_gallery' );
366
+ $key = is_array( $option ) && isset( $option['key'] ) ? $option['key'] : '';
367
+ $level = is_array( $option ) && isset( $option['type'] ) ? $option['type'] : '';
368
+
369
+ // Possibly check for a constant.
370
+ if ( empty( $key ) && defined( 'ENVIRA_LICENSE_KEY' ) ) {
371
+ $key = ENVIRA_LICENSE_KEY;
372
+ }
373
+ break;
374
+ case 'om' :
375
+ $option = get_option( 'optin_monster_api' );
376
+ $key = is_array( $option ) && isset( $option['api']['apikey'] ) ? $option['api']['apikey'] : '';
377
+
378
+ // Possibly check for a constant.
379
+ if ( empty( $key ) && defined( 'OPTINMONSTER_REST_API_LICENSE_KEY' ) ) {
380
+ $key = OPTINMONSTER_REST_API_LICENSE_KEY;
381
+ }
382
+
383
+ // If the key is still empty, check for the old legacy key.
384
+ if ( empty( $key ) ) {
385
+ $key = is_array( $option ) && isset( $option['api']['key'] ) ? $option['api']['key'] : '';
386
+ }
387
+ break;
388
+ }
389
+
390
+ // Possibly set the level to 'none' if the key is empty and no level has been set.
391
+ if ( empty( $key ) && empty( $level ) ) {
392
+ $level = 'none';
393
+ }
394
+
395
+ // Normalize the level.
396
+ switch ( $level ) {
397
+ case 'bronze' :
398
+ case 'personal' :
399
+ $level = 'basic';
400
+ break;
401
+ case 'silver' :
402
+ case 'multi' :
403
+ $level = 'plus';
404
+ break;
405
+ case 'gold' :
406
+ case 'developer' :
407
+ $level = 'pro';
408
+ break;
409
+ case 'platinum' :
410
+ case 'master' :
411
+ $level = 'ultimate';
412
+ break;
413
+ }
414
+
415
+ // Return the plan level.
416
+ return $level;
417
+ }
418
+
419
+ /**
420
+ * Dismiss the notification via AJAX.
421
+ *
422
+ * @since 1.0.0
423
+ */
424
+ public function dismiss_notification() {
425
+ if ( ! current_user_can( apply_filters( 'am_notifications_display', 'manage_options' ) ) ) {
426
+ die;
427
+ }
428
+
429
+ $notification_id = intval( $_POST['notification_id'] );
430
+ update_post_meta( $notification_id, 'viewed', 1 );
431
+ die;
432
+ }
433
+
434
+ /**
435
+ * Revokes notifications.
436
+ *
437
+ * @since 1.0.0
438
+ *
439
+ * @param array $ids An array of notification IDs to revoke.
440
+ */
441
+ public function revoke_notifications( $ids ) {
442
+ // Loop through each of the IDs and find the post that has it as meta.
443
+ foreach ( (array) $ids as $id ) {
444
+ $notifications = $this->get_plugin_notifications( -1, array( 'post_status' => 'all', 'meta_key' => 'notification_id', 'meta_value' => $id ) );
445
+ if ( $notifications ) {
446
+ foreach ( $notifications as $notification ) {
447
+ update_post_meta( $notification->ID, 'viewed', 1 );
448
+ }
449
+ }
450
+ }
451
+ }
452
+ }
src/Admin/Area.php CHANGED
@@ -1,457 +1,457 @@
1
- <?php
2
-
3
- namespace WPMailSMTP\Admin;
4
-
5
- use WPMailSMTP\WP;
6
-
7
- /**
8
- * Class Area registers and process all wp-admin display functionality.
9
- *
10
- * @since 1.0.0
11
- */
12
- class Area {
13
-
14
- /**
15
- * @var string Slug of the admin area page.
16
- */
17
- const SLUG = 'wp-mail-smtp';
18
-
19
- /**
20
- * @var string Admin page unique hook.
21
- */
22
- public $hook;
23
-
24
- /**
25
- * @var PageAbstract[]
26
- */
27
- private $pages;
28
-
29
- /**
30
- * Area constructor.
31
- *
32
- * @since 1.0.0
33
- */
34
- public function __construct() {
35
- $this->hooks();
36
- }
37
-
38
- /**
39
- * Assign all hooks to proper places.
40
- *
41
- * @since 1.0.0
42
- */
43
- protected function hooks() {
44
-
45
- // Add the Settings link to a plugin on Plugins page.
46
- add_filter( 'plugin_action_links', array( $this, 'add_plugin_action_link' ), 10, 2 );
47
-
48
- // Add the options page.
49
- add_action( 'admin_menu', array( $this, 'add_admin_options_page' ) );
50
-
51
- // Admin footer text.
52
- add_filter( 'admin_footer_text', array( $this, 'get_admin_footer' ), 1, 2 );
53
-
54
- // Enqueue admin area scripts and styles.
55
- add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_assets' ) );
56
-
57
- // Process the admin page forms actions.
58
- add_action( 'admin_init', array( $this, 'process_actions' ) );
59
-
60
- // Display custom notices based on the error/success codes.
61
- add_action( 'admin_init', array( $this, 'display_custom_auth_notices' ) );
62
-
63
- // Outputs the plugin admin header.
64
- add_action( 'in_admin_header', array( $this, 'display_admin_header' ), 100 );
65
-
66
- // Hide all unrelated to the plugin notices on the plugin admin pages.
67
- add_action( 'admin_print_scripts', array( $this, 'hide_unrelated_notices' ) );
68
- }
69
-
70
- /**
71
- * Display custom notices based on the error/success codes.
72
- *
73
- * @since 1.0.0
74
- */
75
- public function display_custom_auth_notices() {
76
-
77
- $error = isset( $_GET['error'] ) ? $_GET['error'] : '';
78
- $success = isset( $_GET['success'] ) ? $_GET['success'] : '';
79
-
80
- if ( empty( $error ) && empty( $success ) ) {
81
- return;
82
- }
83
-
84
- switch ( $error ) {
85
- case 'google_access_denied':
86
- WP::add_admin_notice(
87
- /* translators: %s - error code, returned by Google API. */
88
- sprintf( esc_html__( 'There was an error while processing the authentication request: %s. Please try again.', 'wp-mail-smtp' ), '<code>' . $error . '</code>' ),
89
- WP::ADMIN_NOTICE_ERROR
90
- );
91
- break;
92
-
93
- case 'google_no_code_scope':
94
- WP::add_admin_notice(
95
- esc_html__( 'There was an error while processing the authentication request. Please try again.', 'wp-mail-smtp' ),
96
- WP::ADMIN_NOTICE_ERROR
97
- );
98
- break;
99
-
100
- case 'google_no_clients':
101
- WP::add_admin_notice(
102
- esc_html__( 'There was an error while processing the authentication request. Please make sure that you have Client ID and Client Secret both valid and saved.', 'wp-mail-smtp' ),
103
- WP::ADMIN_NOTICE_ERROR
104
- );
105
- break;
106
- }
107
-
108
- switch ( $success ) {
109
- case 'google_site_linked':
110
- WP::add_admin_notice(
111
- esc_html__( 'You have successfully linked the current site with you Google API project. Now you can start sending emails through Google.', 'wp-mail-smtp' ),
112
- WP::ADMIN_NOTICE_SUCCESS
113
- );
114
- break;
115
- }
116
- }
117
-
118
- /**
119
- * Add admin area menu item.
120
- *
121
- * @since 1.0.0
122
- */
123
- public function add_admin_options_page() {
124
-
125
- $this->hook = add_options_page(
126
- esc_html__( 'WP Mail SMTP Options', 'wp-mail-smtp' ),
127
- esc_html__( 'WP Mail SMTP', 'wp-mail-smtp' ),
128
- 'manage_options',
129
- self::SLUG,
130
- array( $this, 'display' )
131
- );
132
- }
133
-
134
- /**
135
- * Enqueue admin area scripts and styles.
136
- *
137
- * @since 1.0.0
138
- *
139
- * @param string $hook
140
- */
141
- public function enqueue_assets( $hook ) {
142
-
143
- if ( $hook !== $this->hook ) {
144
- return;
145
- }
146
-
147
- wp_enqueue_style(
148
- 'wp-mail-smtp-admin',
149
- wp_mail_smtp()->plugin_url . '/assets/css/smtp-admin.min.css',
150
- false,
151
- WPMS_PLUGIN_VER
152
- );
153
-
154
- wp_enqueue_script(
155
- 'wp-mail-smtp-admin',
156
- wp_mail_smtp()->plugin_url . '/assets/js/smtp-admin' . WP::asset_min() . '.js',
157
- array( 'jquery' ),
158
- WPMS_PLUGIN_VER
159
- );
160
- }
161
-
162
- /**
163
- * Outputs the plugin admin header.
164
- *
165
- * @since 1.0.0
166
- */
167
- public function display_admin_header() {
168
-
169
- // Bail if we're not on a plugin page.
170
- if ( ! $this->is_admin_page() ) {
171
- return;
172
- }
173
- ?>
174
-
175
- <div id="wp-mail-smtp-header">
176
- <!--suppress HtmlUnknownTarget -->
177
- <img class="wp-mail-smtp-header-logo" src="<?php echo wp_mail_smtp()->plugin_url; ?>/assets/images/logo.png" alt="WP Mail SMTP"/>
178
- </div>
179
-
180
- <?php
181
- }
182
-
183
- /**
184
- * Display a text to ask users to review the plugin on WP.org.
185
- *
186
- * @since 1.0.0
187
- *
188
- * @param string $text
189
- *
190
- * @return string
191
- */
192
- public function get_admin_footer( $text ) {
193
-
194
- if ( $this->is_admin_page() ) {
195
- $url = 'https://wordpress.org/support/plugin/wp-mail-smtp/reviews/?filter=5#new-post';
196
-
197
- $text = sprintf(
198
- /* translators: %1$s - WP.org link; %2$s - same WP.org link. */
199
- __( 'Please rate <strong>WP Mail SMTP</strong> <a href="%1$s" target="_blank" rel="noopener noreferrer">&#9733;&#9733;&#9733;&#9733;&#9733;</a> on <a href="%2$s" target="_blank">WordPress.org</a> to help us spread the word. Thank you from the WP Mail SMTP team!', 'wp-mail-smtp' ),
200
- $url,
201
- $url
202
- );
203
- }
204
-
205
- return $text;
206
- }
207
-
208
- /**
209
- * Display content of the admin area page.
210
- *
211
- * @since 1.0.0
212
- */
213
- public function display() {
214
- ?>
215
-
216
- <div class="wrap" id="wp-mail-smtp">
217
-
218
- <div class="wp-mail-smtp-page-title">
219
- <?php
220
- foreach ( $this->get_pages() as $page_slug => $page ) :
221
- $label = $page->get_label();
222
- if ( empty( $label ) ) {
223
- continue;
224
- }
225
- $class = $page_slug === $this->get_current_tab() ? 'class="active"' : '';
226
- ?>
227
-
228
- <a href="<?php echo $page->get_link(); ?>" <?php echo $class; ?>><?php echo $label; ?></a>
229
-
230
- <?php endforeach; ?>
231
- </div>
232
-
233
- <div class="wp-mail-smtp-page wp-mail-smtp-tab-<?php echo $this->get_current_tab(); ?>">
234
- <h1 class="screen-reader-text"><?php echo $this->get_current_tab_title(); ?></h1>
235
-
236
- <?php $this->display_current_tab_content(); ?>
237
- </div>
238
-
239
- </div>
240
-
241
- <?php
242
- }
243
-
244
- /**
245
- * Get the current tab title.
246
- *
247
- * @since 1.0.0
248
- */
249
- public function display_current_tab_content() {
250
-
251
- if ( ! array_key_exists( $this->get_current_tab(), $this->get_pages() ) ) {
252
- return;
253
- }
254
-
255
- $this->pages[ $this->get_current_tab() ]->display();
256
- }
257
-
258
- /**
259
- * Get the current admin area tab.
260
- *
261
- * @since 1.0.0
262
- *
263
- * @return string
264
- */
265
- protected function get_current_tab() {
266
-
267
- $current = '';
268
-
269
- if ( $this->is_admin_page() ) {
270
- $current = ! empty( $_GET['tab'] ) ? sanitize_key( $_GET['tab'] ) : 'settings';
271
- }
272
-
273
- return $current;
274
- }
275
-
276
- /**
277
- * Get the array of default registered tabs for plugin admin area.
278
- *
279
- * @since 1.0.0
280
- *
281
- * @return \WPMailSMTP\Admin\PageAbstract[]
282
- */
283
- public function get_pages() {
284
-
285
- if ( empty( $this->pages ) ) {
286
- $this->pages = array(
287
- 'settings' => new Pages\Settings(),
288
- 'test' => new Pages\Test(),
289
- 'misc' => new Pages\Misc(),
290
- 'auth' => new Pages\Auth(),
291
- );
292
- }
293
-
294
- return apply_filters( 'wp_mail_smtp_admin_get_pages', $this->pages );
295
- }
296
-
297
- /**
298
- * Get the current tab title.
299
- *
300
- * @since 1.0.0
301
- *
302
- * @return string
303
- */
304
- public function get_current_tab_title() {
305
-
306
- if ( ! array_key_exists( $this->get_current_tab(), $this->get_pages() ) ) {
307
- return '';
308
- }
309
-
310
- return $this->pages[ $this->get_current_tab() ]->get_title();
311
- }
312
-
313
- /**
314
- * Check whether we are on an admin page.
315
- *
316
- * @since 1.0.0
317
- *
318
- * @return bool
319
- */
320
- public function is_admin_page() {
321
-
322
- $page = isset( $_GET['page'] ) ? $_GET['page'] : '';
323
-
324
- return self::SLUG === $page;
325
- }
326
-
327
- /**
328
- * All possible plugin forms manipulation will be done here.
329
- *
330
- * @since 1.0.0
331
- */
332
- public function process_actions() {
333
-
334
- // Allow to process only own tabs.
335
- if ( ! array_key_exists( $this->get_current_tab(), $this->get_pages() ) ) {
336
- return;
337
- }
338
-
339
- // Process POST only if it exists.
340
- if ( ! empty( $_POST ) ) {
341
- if ( ! empty( $_POST['wp-mail-smtp'] ) ) {
342
- $post = $_POST['wp-mail-smtp'];
343
- } else {
344
- $post = array();
345
- }
346
-
347
- $this->pages[ $this->get_current_tab() ]->process_post( $post );
348
- }
349
-
350
- // This won't do anything for most pages.
351
- $this->pages[ $this->get_current_tab() ]->process_auth();
352
- }
353
-
354
- /**
355
- * Add a link to Settings page of a plugin on Plugins page.
356
- *
357
- * @since 1.0.0
358
- *
359
- * @param array $links
360
- * @param string $file
361
- *
362
- * @return mixed
363
- */
364
- public function add_plugin_action_link( $links, $file ) {
365
-
366
- if ( strpos( $file, 'wp-mail-smtp' ) === false ) {
367
- return $links;
368
- }
369
-
370
- $settings_link = '<a href="' . $this->get_admin_page_url() . '">' . esc_html__( 'Settings', 'wp-mail-smtp' ) . '</a>';
371
-
372
- array_unshift( $links, $settings_link );
373
-
374
- return $links;
375
- }
376
-
377
- /**
378
- * Get plugin admin area page URL.
379
- *
380
- * @since 1.0.0
381
- *
382
- * @return string
383
- */
384
- public function get_admin_page_url() {
385
- return add_query_arg(
386
- 'page',
387
- self::SLUG,
388
- admin_url( 'options-general.php' )
389
- );
390
- }
391
-
392
- /**
393
- * Remove all non-WP Mail SMTP plugin notices from plugin pages.
394
- *
395
- * @since 1.0.0
396
- */
397
- public function hide_unrelated_notices() {
398
-
399
- // Bail if we're not on a our screen or page.
400
- if ( empty( $_REQUEST['page'] ) || strpos( $_REQUEST['page'], self::SLUG ) === false ) {
401
- return;
402
- }
403
-
404
- global $wp_filter;
405
-
406
- if ( ! empty( $wp_filter['user_admin_notices']->callbacks ) && is_array( $wp_filter['user_admin_notices']->callbacks ) ) {
407
- foreach ( $wp_filter['user_admin_notices']->callbacks as $priority => $hooks ) {
408
- foreach ( $hooks as $name => $arr ) {
409
- if ( is_object( $arr['function'] ) && $arr['function'] instanceof \Closure ) {
410
- unset( $wp_filter['user_admin_notices']->callbacks[ $priority ][ $name ] );
411
- continue;
412
- }
413
- if ( ! empty( $arr['function'][0] ) && is_object( $arr['function'][0] ) && strpos( strtolower( get_class( $arr['function'][0] ) ), 'wpmailsmtp' ) !== false ) {
414
- continue;
415
- }
416
- if ( ! empty( $name ) && strpos( strtolower( $name ), 'wpmailsmtp' ) === false ) {
417
- unset( $wp_filter['user_admin_notices']->callbacks[ $priority ][ $name ] );
418
- }
419
- }
420
- }
421
- }
422
-
423
- if ( ! empty( $wp_filter['admin_notices']->callbacks ) && is_array( $wp_filter['admin_notices']->callbacks ) ) {
424
- foreach ( $wp_filter['admin_notices']->callbacks as $priority => $hooks ) {
425
- foreach ( $hooks as $name => $arr ) {
426
- if ( is_object( $arr['function'] ) && $arr['function'] instanceof \Closure ) {
427
- unset( $wp_filter['admin_notices']->callbacks[ $priority ][ $name ] );
428
- continue;
429
- }
430
- if ( ! empty( $arr['function'][0] ) && is_object( $arr['function'][0] ) && strpos( strtolower( get_class( $arr['function'][0] ) ), 'wpmailsmtp' ) !== false ) {
431
- continue;
432
- }
433
- if ( ! empty( $name ) && strpos( strtolower( $name ), 'wpmailsmtp' ) === false ) {
434
- unset( $wp_filter['admin_notices']->callbacks[ $priority ][ $name ] );
435
- }
436
- }
437
- }
438
- }
439
-
440
- if ( ! empty( $wp_filter['all_admin_notices']->callbacks ) && is_array( $wp_filter['all_admin_notices']->callbacks ) ) {
441
- foreach ( $wp_filter['all_admin_notices']->callbacks as $priority => $hooks ) {
442
- foreach ( $hooks as $name => $arr ) {
443
- if ( is_object( $arr['function'] ) && $arr['function'] instanceof \Closure ) {
444
- unset( $wp_filter['all_admin_notices']->callbacks[ $priority ][ $name ] );
445
- continue;
446
- }
447
- if ( ! empty( $arr['function'][0] ) && is_object( $arr['function'][0] ) && strpos( strtolower( get_class( $arr['function'][0] ) ), 'wpmailsmtp' ) !== false ) {
448
- continue;
449
- }
450
- if ( ! empty( $name ) && strpos( strtolower( $name ), 'wpmailsmtp' ) === false ) {
451
- unset( $wp_filter['all_admin_notices']->callbacks[ $priority ][ $name ] );
452
- }
453
- }
454
- }
455
- }
456
- }
457
- }
1
+ <?php
2
+
3
+ namespace WPMailSMTP\Admin;
4
+
5
+ use WPMailSMTP\WP;
6
+
7
+ /**
8
+ * Class Area registers and process all wp-admin display functionality.
9
+ *
10
+ * @since 1.0.0
11
+ */
12
+ class Area {
13
+
14
+ /**
15
+ * @var string Slug of the admin area page.
16
+ */
17
+ const SLUG = 'wp-mail-smtp';
18
+
19
+ /**
20
+ * @var string Admin page unique hook.
21
+ */
22
+ public $hook;
23
+
24
+ /**
25
+ * @var PageAbstract[]
26
+ */
27
+ private $pages;
28
+
29
+ /**
30
+ * Area constructor.
31
+ *
32
+ * @since 1.0.0
33
+ */
34
+ public function __construct() {
35
+ $this->hooks();
36
+ }
37
+
38
+ /**
39
+ * Assign all hooks to proper places.
40
+ *
41
+ * @since 1.0.0
42
+ */
43
+ protected function hooks() {
44
+
45
+ // Add the Settings link to a plugin on Plugins page.
46
+ add_filter( 'plugin_action_links', array( $this, 'add_plugin_action_link' ), 10, 2 );
47
+
48
+ // Add the options page.
49
+ add_action( 'admin_menu', array( $this, 'add_admin_options_page' ) );
50
+
51
+ // Admin footer text.
52
+ add_filter( 'admin_footer_text', array( $this, 'get_admin_footer' ), 1, 2 );
53
+
54
+ // Enqueue admin area scripts and styles.
55
+ add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_assets' ) );
56
+
57
+ // Process the admin page forms actions.
58
+ add_action( 'admin_init', array( $this, 'process_actions' ) );
59
+
60
+ // Display custom notices based on the error/success codes.
61
+ add_action( 'admin_init', array( $this, 'display_custom_auth_notices' ) );
62
+
63
+ // Outputs the plugin admin header.
64
+ add_action( 'in_admin_header', array( $this, 'display_admin_header' ), 100 );
65
+
66
+ // Hide all unrelated to the plugin notices on the plugin admin pages.
67
+ add_action( 'admin_print_scripts', array( $this, 'hide_unrelated_notices' ) );
68
+ }
69
+
70
+ /**
71
+ * Display custom notices based on the error/success codes.
72
+ *
73
+ * @since 1.0.0
74
+ */
75
+ public function display_custom_auth_notices() {
76
+
77
+ $error = isset( $_GET['error'] ) ? $_GET['error'] : '';
78
+ $success = isset( $_GET['success'] ) ? $_GET['success'] : '';
79
+
80
+ if ( empty( $error ) && empty( $success ) ) {
81
+ return;
82
+ }
83
+
84
+ switch ( $error ) {
85
+ case 'google_access_denied':
86
+ WP::add_admin_notice(
87
+ /* translators: %s - error code, returned by Google API. */
88
+ sprintf( esc_html__( 'There was an error while processing the authentication request: %s. Please try again.', 'wp-mail-smtp' ), '<code>' . $error . '</code>' ),
89
+ WP::ADMIN_NOTICE_ERROR
90
+ );
91
+ break;
92
+
93
+ case 'google_no_code_scope':
94
+ WP::add_admin_notice(
95
+ esc_html__( 'There was an error while processing the authentication request. Please try again.', 'wp-mail-smtp' ),
96
+ WP::ADMIN_NOTICE_ERROR
97
+ );
98
+ break;
99
+
100
+ case 'google_no_clients':
101
+ WP::add_admin_notice(
102
+ esc_html__( 'There was an error while processing the authentication request. Please make sure that you have Client ID and Client Secret both valid and saved.', 'wp-mail-smtp' ),
103
+ WP::ADMIN_NOTICE_ERROR
104
+ );
105
+ break;
106
+ }
107
+
108
+ switch ( $success ) {
109
+ case 'google_site_linked':
110
+ WP::add_admin_notice(
111
+ esc_html__( 'You have successfully linked the current site with you Google API project. Now you can start sending emails through Google.', 'wp-mail-smtp' ),
112
+ WP::ADMIN_NOTICE_SUCCESS
113
+ );
114
+ break;
115
+ }
116
+ }
117
+
118
+ /**
119
+ * Add admin area menu item.
120
+ *
121
+ * @since 1.0.0
122
+ */
123
+ public function add_admin_options_page() {
124
+
125
+ $this->hook = add_options_page(
126
+ esc_html__( 'WP Mail SMTP Options', 'wp-mail-smtp' ),
127
+ esc_html__( 'WP Mail SMTP', 'wp-mail-smtp' ),
128
+ 'manage_options',
129
+ self::SLUG,
130
+ array( $this, 'display' )
131
+ );
132
+ }
133
+
134
+ /**
135
+ * Enqueue admin area scripts and styles.
136
+ *
137
+ * @since 1.0.0
138
+ *
139
+ * @param string $hook
140
+ */
141
+ public function enqueue_assets( $hook ) {
142
+
143
+ if ( $hook !== $this->hook ) {
144
+ return;
145
+ }
146
+
147
+ wp_enqueue_style(
148
+ 'wp-mail-smtp-admin',
149
+ wp_mail_smtp()->plugin_url . '/assets/css/smtp-admin.min.css',
150
+ false,
151
+ WPMS_PLUGIN_VER
152
+ );
153
+
154
+ wp_enqueue_script(
155
+ 'wp-mail-smtp-admin',
156
+ wp_mail_smtp()->plugin_url . '/assets/js/smtp-admin' . WP::asset_min() . '.js',
157
+ array( 'jquery' ),
158
+ WPMS_PLUGIN_VER
159
+ );
160
+ }
161
+
162
+ /**
163
+ * Outputs the plugin admin header.
164
+ *
165
+ * @since 1.0.0
166
+ */
167
+ public function display_admin_header() {
168
+
169
+ // Bail if we're not on a plugin page.
170
+ if ( ! $this->is_admin_page() ) {
171
+ return;
172
+ }
173
+ ?>
174
+
175
+ <div id="wp-mail-smtp-header">
176
+ <!--suppress HtmlUnknownTarget -->
177
+ <img class="wp-mail-smtp-header-logo" src="<?php echo wp_mail_smtp()->plugin_url; ?>/assets/images/logo.png" alt="WP Mail SMTP"/>
178
+ </div>
179
+
180
+ <?php
181
+ }
182
+
183
+ /**
184
+ * Display a text to ask users to review the plugin on WP.org.
185
+ *
186
+ * @since 1.0.0
187
+ *
188
+ * @param string $text
189
+ *
190
+ * @return string
191
+ */
192
+ public function get_admin_footer( $text ) {
193
+
194
+ if ( $this->is_admin_page() ) {
195
+ $url = 'https://wordpress.org/support/plugin/wp-mail-smtp/reviews/?filter=5#new-post';
196
+
197
+ $text = sprintf(
198
+ /* translators: %1$s - WP.org link; %2$s - same WP.org link. */
199
+ __( 'Please rate <strong>WP Mail SMTP</strong> <a href="%1$s" target="_blank" rel="noopener noreferrer">&#9733;&#9733;&#9733;&#9733;&#9733;</a> on <a href="%2$s" target="_blank">WordPress.org</a> to help us spread the word. Thank you from the WP Mail SMTP team!', 'wp-mail-smtp' ),
200
+ $url,
201
+ $url
202
+ );
203
+ }
204
+
205
+ return $text;
206
+ }
207
+
208
+ /**
209
+ * Display content of the admin area page.
210
+ *
211
+ * @since 1.0.0
212
+ */
213
+ public function display() {
214
+ ?>
215
+
216
+ <div class="wrap" id="wp-mail-smtp">
217
+
218
+ <div class="wp-mail-smtp-page-title">
219
+ <?php
220
+ foreach ( $this->get_pages() as $page_slug => $page ) :
221
+ $label = $page->get_label();
222
+ if ( empty( $label ) ) {
223
+ continue;
224
+ }
225
+ $class = $page_slug === $this->get_current_tab() ? 'class="active"' : '';
226
+ ?>
227
+
228
+ <a href="<?php echo $page->get_link(); ?>" <?php echo $class; ?>><?php echo $label; ?></a>
229
+
230
+ <?php endforeach; ?>
231
+ </div>
232
+
233
+ <div class="wp-mail-smtp-page wp-mail-smtp-tab-<?php echo $this->get_current_tab(); ?>">
234
+ <h1 class="screen-reader-text"><?php echo $this->get_current_tab_title(); ?></h1>
235
+
236
+ <?php $this->display_current_tab_content(); ?>
237
+ </div>
238
+
239
+ </div>
240
+
241
+ <?php
242
+ }
243
+
244
+ /**
245
+ * Get the current tab title.
246
+ *
247
+ * @since 1.0.0
248
+ */
249
+ public function display_current_tab_content() {
250
+
251
+ if ( ! array_key_exists( $this->get_current_tab(), $this->get_pages() ) ) {
252
+ return;
253
+ }
254
+
255
+ $this->pages[ $this->get_current_tab() ]->display();
256
+ }
257
+
258
+ /**
259
+ * Get the current admin area tab.
260
+ *
261
+ * @since 1.0.0
262
+ *
263
+ * @return string
264
+ */
265
+ protected function get_current_tab() {
266
+
267
+ $current = '';
268
+
269
+ if ( $this->is_admin_page() ) {
270
+ $current = ! empty( $_GET['tab'] ) ? sanitize_key( $_GET['tab'] ) : 'settings';
271
+ }
272
+
273
+ return $current;
274
+ }
275
+
276
+ /**
277
+ * Get the array of default registered tabs for plugin admin area.
278
+ *
279
+ * @since 1.0.0
280
+ *
281
+ * @return \WPMailSMTP\Admin\PageAbstract[]
282
+ */
283
+ public function get_pages() {
284
+
285
+ if ( empty( $this->pages ) ) {
286
+ $this->pages = array(
287
+ 'settings' => new Pages\Settings(),
288
+ 'test' => new Pages\Test(),
289
+ 'misc' => new Pages\Misc(),
290
+ 'auth' => new Pages\Auth(),
291
+ );
292
+ }
293
+
294
+ return apply_filters( 'wp_mail_smtp_admin_get_pages', $this->pages );
295
+ }
296
+
297
+ /**
298
+ * Get the current tab title.
299
+ *
300
+ * @since 1.0.0
301
+ *
302
+ * @return string
303
+ */
304
+ public function get_current_tab_title() {
305
+
306
+ if ( ! array_key_exists( $this->get_current_tab(), $this->get_pages() ) ) {
307
+ return '';
308
+ }
309
+
310
+ return $this->pages[ $this->get_current_tab() ]->get_title();
311
+ }
312
+
313
+ /**
314
+ * Check whether we are on an admin page.
315
+ *
316
+ * @since 1.0.0
317
+ *
318
+ * @return bool
319
+ */
320
+ public function is_admin_page() {
321
+
322
+ $page = isset( $_GET['page'] ) ? $_GET['page'] : '';
323
+
324
+ return self::SLUG === $page;
325
+ }
326
+
327
+ /**
328
+ * All possible plugin forms manipulation will be done here.
329
+ *
330
+ * @since 1.0.0
331
+ */
332
+ public function process_actions() {
333
+
334
+ // Allow to process only own tabs.
335
+ if ( ! array_key_exists( $this->get_current_tab(), $this->get_pages() ) ) {
336
+ return;
337
+ }
338
+
339
+ // Process POST only if it exists.
340
+ if ( ! empty( $_POST ) ) {
341
+ if ( ! empty( $_POST['wp-mail-smtp'] ) ) {
342
+ $post = $_POST['wp-mail-smtp'];
343
+ } else {
344
+ $post = array();
345
+ }
346
+
347
+ $this->pages[ $this->get_current_tab() ]->process_post( $post );
348
+ }
349
+
350
+ // This won't do anything for most pages.
351
+ $this->pages[ $this->get_current_tab() ]->process_auth();
352
+ }
353
+
354
+ /**
355
+ * Add a link to Settings page of a plugin on Plugins page.
356
+ *
357
+ * @since 1.0.0
358
+ *
359
+ * @param array $links
360
+ * @param string $file
361
+ *
362
+ * @return mixed
363
+ */
364
+ public function add_plugin_action_link( $links, $file ) {
365
+
366
+ if ( strpos( $file, 'wp-mail-smtp' ) === false ) {
367
+ return $links;
368
+ }
369
+
370
+ $settings_link = '<a href="' . $this->get_admin_page_url() . '">' . esc_html__( 'Settings', 'wp-mail-smtp' ) . '</a>';
371
+
372
+ array_unshift( $links, $settings_link );
373
+
374
+ return $links;
375
+ }
376
+
377
+ /**
378
+ * Get plugin admin area page URL.
379
+ *
380
+ * @since 1.0.0
381
+ *
382
+ * @return string
383
+ */
384
+ public function get_admin_page_url() {
385
+ return add_query_arg(
386
+ 'page',
387
+ self::SLUG,
388
+ admin_url( 'options-general.php' )
389
+ );
390
+ }
391
+
392
+ /**
393
+ * Remove all non-WP Mail SMTP plugin notices from plugin pages.
394
+ *
395
+ * @since 1.0.0
396
+ */
397
+ public function hide_unrelated_notices() {
398
+
399
+ // Bail if we're not on a our screen or page.
400
+ if ( empty( $_REQUEST['page'] ) || strpos( $_REQUEST['page'], self::SLUG ) === false ) {
401
+ return;
402
+ }
403
+
404
+ global $wp_filter;
405
+
406
+ if ( ! empty( $wp_filter['user_admin_notices']->callbacks ) && is_array( $wp_filter['user_admin_notices']->callbacks ) ) {
407
+ foreach ( $wp_filter['user_admin_notices']->callbacks as $priority => $hooks ) {
408
+ foreach ( $hooks as $name => $arr ) {
409
+ if ( is_object( $arr['function'] ) && $arr['function'] instanceof \Closure ) {
410
+ unset( $wp_filter['user_admin_notices']->callbacks[ $priority ][ $name ] );
411
+ continue;
412
+ }
413
+ if ( ! empty( $arr['function'][0] ) && is_object( $arr['function'][0] ) && strpos( strtolower( get_class( $arr['function'][0] ) ), 'wpmailsmtp' ) !== false ) {
414
+ continue;
415
+ }
416
+ if ( ! empty( $name ) && strpos( strtolower( $name ), 'wpmailsmtp' ) === false ) {
417
+ unset( $wp_filter['user_admin_notices']->callbacks[ $priority ][ $name ] );
418
+ }
419
+ }
420
+ }
421
+ }
422
+
423
+ if ( ! empty( $wp_filter['admin_notices']->callbacks ) && is_array( $wp_filter['admin_notices']->callbacks ) ) {
424
+ foreach ( $wp_filter['admin_notices']->callbacks as $priority => $hooks ) {
425
+ foreach ( $hooks as $name => $arr ) {
426
+ if ( is_object( $arr['function'] ) && $arr['function'] instanceof \Closure ) {
427
+ unset( $wp_filter['admin_notices']->callbacks[ $priority ][ $name ] );
428
+ continue;
429
+ }
430
+ if ( ! empty( $arr['function'][0] ) && is_object( $arr['function'][0] ) && strpos( strtolower( get_class( $arr['function'][0] ) ), 'wpmailsmtp' ) !== false ) {
431
+ continue;
432
+ }
433
+ if ( ! empty( $name ) && strpos( strtolower( $name ), 'wpmailsmtp' ) === false ) {
434
+ unset( $wp_filter['admin_notices']->callbacks[ $priority ][ $name ] );
435
+ }
436
+ }
437
+ }
438
+ }
439
+
440
+ if ( ! empty( $wp_filter['all_admin_notices']->callbacks ) && is_array( $wp_filter['all_admin_notices']->callbacks ) ) {
441
+ foreach ( $wp_filter['all_admin_notices']->callbacks as $priority => $hooks ) {
442
+ foreach ( $hooks as $name => $arr ) {
443
+ if ( is_object( $arr['function'] ) && $arr['function'] instanceof \Closure ) {
444
+ unset( $wp_filter['all_admin_notices']->callbacks[ $priority ][ $name ] );
445
+ continue;
446
+ }
447
+ if ( ! empty( $arr['function'][0] ) && is_object( $arr['function'][0] ) && strpos( strtolower( get_class( $arr['function'][0] ) ), 'wpmailsmtp' ) !== false ) {
448
+ continue;
449
+ }
450
+ if ( ! empty( $name ) && strpos( strtolower( $name ), 'wpmailsmtp' ) === false ) {
451
+ unset( $wp_filter['all_admin_notices']->callbacks[ $priority ][ $name ] );
452
+ }
453
+ }
454
+ }
455
+ }
456
+ }
457
+ }
src/Admin/PageAbstract.php CHANGED
@@ -1,66 +1,66 @@
1
- <?php
2
-
3
- namespace WPMailSMTP\Admin;
4
-
5
- /**
6
- * Class PageAbstract.
7
- *
8
- * @since 1.0.0
9
- */
10
- abstract class PageAbstract implements PageInterface {
11
-
12
- /**
13
- * @var string Slug of a tab.
14
- */
15
- protected $slug;
16
-
17
- /**
18
- * @inheritdoc
19
- */
20
- public function get_link() {
21
- return esc_url(
22
- add_query_arg(
23
- 'tab',
24
- $this->slug,
25
- admin_url( 'options-general.php?page=' . Area::SLUG )
26
- )
27
- );
28
- }
29
-
30
- /**
31
- * Process tab form submission ($_POST ).
32
- *
33
- * @since 1.0.0
34
- *
35
- * @param array $data $_POST data specific for the plugin.
36
- */
37
- public function process_post( $data ) {
38
- }
39
-
40
- /**
41
- * Process tab & mailer specific Auth actions.
42
- *
43
- * @since 1.0.0
44
- */
45
- public function process_auth() {
46
- }
47
-
48
- /**
49
- * Print the nonce field for a specific tab.
50
- *
51
- * @since 1.0.0
52
- */
53
- public function wp_nonce_field() {
54
- wp_nonce_field( Area::SLUG . '-' . $this->slug );
55
- }
56
-
57
- /**
58
- * Make sure that a user was referred from plugin admin page.
59
- * To avoid security problems.
60
- *
61
- * @since 1.0.0
62
- */
63
- public function check_admin_referer() {
64
- check_admin_referer( Area::SLUG . '-' . $this->slug );
65
- }
66
- }
1
+ <?php
2
+
3
+ namespace WPMailSMTP\Admin;
4
+
5
+ /**
6
+ * Class PageAbstract.
7
+ *
8
+ * @since 1.0.0
9
+ */
10
+ abstract class PageAbstract implements PageInterface {
11
+
12
+ /**
13
+ * @var string Slug of a tab.
14
+ */
15
+ protected $slug;
16
+
17
+ /**
18
+ * @inheritdoc
19
+ */
20
+ public function get_link() {
21
+ return esc_url(
22
+ add_query_arg(
23
+ 'tab',
24
+ $this->slug,
25
+ admin_url( 'options-general.php?page=' . Area::SLUG )
26
+ )
27
+ );
28
+ }
29
+
30
+ /**
31
+ * Process tab form submission ($_POST ).
32
+ *
33
+ * @since 1.0.0
34
+ *
35
+ * @param array $data $_POST data specific for the plugin.
36
+ */
37
+ public function process_post( $data ) {
38
+ }
39
+
40
+ /**
41
+ * Process tab & mailer specific Auth actions.
42
+ *
43
+ * @since 1.0.0
44
+ */
45
+ public function process_auth() {
46
+ }
47
+
48
+ /**
49
+ * Print the nonce field for a specific tab.
50
+ *
51
+ * @since 1.0.0
52
+ */
53
+ public function wp_nonce_field() {
54
+ wp_nonce_field( Area::SLUG . '-' . $this->slug );
55
+ }
56
+
57
+ /**
58
+ * Make sure that a user was referred from plugin admin page.
59
+ * To avoid security problems.
60
+ *
61
+ * @since 1.0.0
62
+ */
63
+ public function check_admin_referer() {
64
+ check_admin_referer( Area::SLUG . '-' . $this->slug );
65
+ }
66
+ }
src/Admin/PageInterface.php CHANGED
@@ -1,45 +1,45 @@
1
- <?php
2
-
3
- namespace WPMailSMTP\Admin;
4
-
5
- /**
6
- * Class PageInterface defines what should be in each page class.
7
- *
8
- * @since 1.0.0
9
- */
10
- interface PageInterface {
11
-
12
- /**
13
- * URL to a tab.
14
- *
15
- * @since 1.0.0
16
- *
17
- * @return string
18
- */
19
- public function get_link();
20
-
21
- /**
22
- * Title of a tab.
23
- *
24
- * @since 1.0.0
25
- *
26
- * @return string
27
- */
28
- public function get_title();
29
-
30
- /**
31
- * Link label of a tab.
32
- *
33
- * @since 1.0.0
34
- *
35
- * @return string
36
- */
37
- public function get_label();
38
-
39
- /**
40
- * Tab content.
41
- *
42
- * @since 1.0.0
43
- */
44
- public function display();
45
- }
1
+ <?php
2
+
3
+ namespace WPMailSMTP\Admin;
4
+
5
+ /**
6
+ * Class PageInterface defines what should be in each page class.
7
+ *
8
+ * @since 1.0.0
9
+ */
10
+ interface PageInterface {
11
+
12
+ /**
13
+ * URL to a tab.
14
+ *
15
+ * @since 1.0.0
16
+ *
17
+ * @return string
18
+ */
19
+ public function get_link();
20
+
21
+ /**
22
+ * Title of a tab.
23
+ *
24
+ * @since 1.0.0
25
+ *
26
+ * @return string
27
+ */
28
+ public function get_title();
29
+
30
+ /**
31
+ * Link label of a tab.
32
+ *
33
+ * @since 1.0.0
34
+ *
35
+ * @return string
36
+ */
37
+ public function get_label();
38
+
39
+ /**
40
+ * Tab content.
41
+ *
42
+ * @since 1.0.0
43
+ */
44
+ public function display();
45
+ }
src/Admin/Pages/Auth.php CHANGED
@@ -1,56 +1,56 @@
1
- <?php
2
-
3
- namespace WPMailSMTP\Admin\Pages;
4
-
5
- use WPMailSMTP\Options;
6
-
7
- /**
8
- * Class Auth.
9
- *
10
- * @since 1.0.0
11
- */
12
- class Auth {
13
-
14
- /**
15
- * @var string Slug of a tab.
16
- */
17
- protected $slug = 'auth';
18
-
19
- /**
20
- * Launch mailer specific Auth logic.
21
- *
22
- * @since 1.0.0
23
- */
24
- public function process_auth() {
25
-
26
- $auth = wp_mail_smtp()->get_providers()->get_auth( Options::init()->get( 'mail', 'mailer' ) );
27
-
28
- $auth->process();
29
- }
30
-
31
- /**
32
- * Return nothing, as we don't need this functionality.
33
- *
34
- * @since 1.0.0
35
- */
36
- public function get_label() {
37
- return '';
38
- }
39
-
40
- /**
41
- * Return nothing, as we don't need this functionality.
42
- *
43
- * @since 1.0.0
44
- */
45
- public function get_title() {
46
- return '';
47
- }
48
-
49
- /**
50
- * Do nothing, as we don't need this functionality.
51
- *
52
- * @since 1.0.0
53
- */
54
- public function display() {
55
- }
56
- }
1
+ <?php
2
+
3
+ namespace WPMailSMTP\Admin\Pages;
4
+
5
+ use WPMailSMTP\Options;
6
+
7
+ /**
8
+ * Class Auth.
9
+ *
10
+ * @since 1.0.0
11
+ */
12
+ class Auth {
13
+
14
+ /**
15
+ * @var string Slug of a tab.
16
+ */
17
+ protected $slug = 'auth';
18
+
19
+ /**
20
+ * Launch mailer specific Auth logic.
21
+ *
22
+ * @since 1.0.0
23
+ */
24
+ public function process_auth() {
25
+
26
+ $auth = wp_mail_smtp()->get_providers()->get_auth( Options::init()->get( 'mail', 'mailer' ) );
27
+
28
+ $auth->process();
29
+ }
30
+
31
+ /**
32
+ * Return nothing, as we don't need this functionality.
33
+ *
34
+ * @since 1.0.0
35
+ */
36
+ public function get_label() {
37
+ return '';
38
+ }
39
+
40
+ /**
41
+ * Return nothing, as we don't need this functionality.
42
+ *
43
+ * @since 1.0.0
44
+ */
45
+ public function get_title() {
46
+ return '';
47
+ }
48
+
49
+ /**
50
+ * Do nothing, as we don't need this functionality.
51
+ *
52
+ * @since 1.0.0
53
+ */
54
+ public function display() {
55
+ }
56
+ }
src/Admin/Pages/Misc.php CHANGED
@@ -1,99 +1,99 @@
1
- <?php
2
-
3
- namespace WPMailSMTP\Admin\Pages;
4
-
5
- use WPMailSMTP\Admin\PageAbstract;
6
- use WPMailSMTP\Options;
7
- use WPMailSMTP\WP;
8
-
9
- /**
10
- * Class Misc is part of Area, displays different plugin-related settings of the plugin (not related to emails).
11
- *
12
- * @since 1.0.0
13
- */
14
- class Misc extends PageAbstract {
15
- /**
16
- * @var string Slug of a tab.
17
- */
18
- protected $slug = 'misc';
19
-
20
- /**
21
- * @inheritdoc
22
- */
23
- public function get_label() {
24
- return esc_html__( 'Misc', 'wp-mail-smtp' );
25
- }
26
-
27
- /**
28
- * @inheritdoc
29
- */
30
- public function get_title() {
31
- return $this->get_label();
32
- }
33
-
34
- /**
35
- * @inheritdoc
36
- */
37
- public function display() {
38
-
39
- $options = new Options();
40
- ?>
41
-
42
- <form method="POST" action="">
43
- <?php $this->wp_nonce_field(); ?>
44
-
45
- <!-- General Section Title -->
46
- <div class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-content wp-mail-smtp-clear section-heading no-desc" id="wp-mail-smtp-setting-row-email-heading">
47
- <div class="wp-mail-smtp-setting-field">
48
- <h2><?php esc_html_e( 'General', 'wp-mail-smtp' ); ?></h2>
49
- </div>
50
- </div>
51
-
52
- <!-- Hide Announcements -->
53
- <div id="wp-mail-smtp-setting-row-am_notifications_hidden" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-checkbox wp-mail-smtp-clear">
54
- <div class="wp-mail-smtp-setting-label">
55
- <label for="wp-mail-smtp-setting-am_notifications_hidden"><?php esc_html_e( 'Hide Announcements', 'wp-mail-smtp' ); ?></label>
56
- </div>
57
- <div class="wp-mail-smtp-setting-field">
58
- <input name="wp-mail-smtp[general][am_notifications_hidden]" type="checkbox"
59
- value="true" <?php checked( true, $options->get( 'general', 'am_notifications_hidden' ) ); ?>
60
- id="wp-mail-smtp-setting-am_notifications_hidden"
61
- />
62
- <label for="wp-mail-smtp-setting-am_notifications_hidden"><?php esc_html_e( 'Check this if you would like to hide plugin announcements and update details.', 'wp-mail-smtp' ); ?></label>
63
- </div>
64
- </div>
65
-
66
- <p class="wp-mail-smtp-submit">
67
- <button type="submit" class="wp-mail-smtp-btn wp-mail-smtp-btn-md wp-mail-smtp-btn-orange"><?php esc_html_e( 'Save Settings', 'wp-mail-smtp' ); ?></button>
68
- </p>
69
-
70
- </form>
71
-
72
- <?php
73
- }
74
-
75
- /**
76
- * @inheritdoc
77
- */
78
- public function process_post( $data ) {
79
-
80
- $this->check_admin_referer();
81
-
82
- $options = new Options();
83
-
84
- // Unchecked checkbox doesn't exist in $_POST, so we need to ensure we actually have it.
85
- if ( empty( $data['general']['am_notifications_hidden'] ) ) {
86
- $data['general']['am_notifications_hidden'] = false;
87
- }
88
-
89
- $to_save = array_merge( $options->get_all(), $data );
90
-
91
- // All the sanitization is done there.
92
- $options->set( $to_save );
93
-
94
- WP::add_admin_notice(
95
- esc_html__( 'Settings were successfully saved.', 'wp-mail-smtp' ),
96
- WP::ADMIN_NOTICE_SUCCESS
97
- );
98
- }
99
- }
1
+ <?php
2
+
3
+ namespace WPMailSMTP\Admin\Pages;
4
+
5
+ use WPMailSMTP\Admin\PageAbstract;
6
+ use WPMailSMTP\Options;
7
+ use WPMailSMTP\WP;
8
+
9
+ /**
10
+ * Class Misc is part of Area, displays different plugin-related settings of the plugin (not related to emails).
11
+ *
12
+ * @since 1.0.0
13
+ */
14
+ class Misc extends PageAbstract {
15
+ /**
16
+ * @var string Slug of a tab.
17
+ */
18
+ protected $slug = 'misc';
19
+
20
+ /**
21
+ * @inheritdoc
22
+ */
23
+ public function get_label() {
24
+ return esc_html__( 'Misc', 'wp-mail-smtp' );
25
+ }
26
+
27
+ /**
28
+ * @inheritdoc
29
+ */
30
+ public function get_title() {
31
+ return $this->get_label();
32
+ }
33
+
34
+ /**
35
+ * @inheritdoc
36
+ */
37
+ public function display() {
38
+
39
+ $options = new Options();
40
+ ?>
41
+
42
+ <form method="POST" action="">
43
+ <?php $this->wp_nonce_field(); ?>
44
+
45
+ <!-- General Section Title -->
46
+ <div class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-content wp-mail-smtp-clear section-heading no-desc" id="wp-mail-smtp-setting-row-email-heading">
47
+ <div class="wp-mail-smtp-setting-field">
48
+ <h2><?php esc_html_e( 'General', 'wp-mail-smtp' ); ?></h2>
49
+ </div>
50
+ </div>
51
+
52
+ <!-- Hide Announcements -->
53
+ <div id="wp-mail-smtp-setting-row-am_notifications_hidden" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-checkbox wp-mail-smtp-clear">
54
+ <div class="wp-mail-smtp-setting-label">
55
+ <label for="wp-mail-smtp-setting-am_notifications_hidden"><?php esc_html_e( 'Hide Announcements', 'wp-mail-smtp' ); ?></label>
56
+ </div>
57
+ <div class="wp-mail-smtp-setting-field">
58
+ <input name="wp-mail-smtp[general][am_notifications_hidden]" type="checkbox"
59
+ value="true" <?php checked( true, $options->get( 'general', 'am_notifications_hidden' ) ); ?>
60
+ id="wp-mail-smtp-setting-am_notifications_hidden"
61
+ />
62
+ <label for="wp-mail-smtp-setting-am_notifications_hidden"><?php esc_html_e( 'Check this if you would like to hide plugin announcements and update details.', 'wp-mail-smtp' ); ?></label>
63
+ </div>
64
+ </div>
65
+
66
+ <p class="wp-mail-smtp-submit">
67
+ <button type="submit" class="wp-mail-smtp-btn wp-mail-smtp-btn-md wp-mail-smtp-btn-orange"><?php esc_html_e( 'Save Settings', 'wp-mail-smtp' ); ?></button>
68
+ </p>
69
+
70
+ </form>
71
+
72
+ <?php
73
+ }
74
+
75
+ /**
76
+ * @inheritdoc
77
+ */
78
+ public function process_post( $data ) {
79
+
80
+ $this->check_admin_referer();
81
+
82
+ $options = new Options();
83
+
84
+ // Unchecked checkbox doesn't exist in $_POST, so we need to ensure we actually have it.
85
+ if ( empty( $data['general']['am_notifications_hidden'] ) ) {
86
+ $data['general']['am_notifications_hidden'] = false;
87
+ }
88
+
89
+ $to_save = array_merge( $options->get_all(), $data );
90
+
91
+ // All the sanitization is done there.
92
+ $options->set( $to_save );
93
+
94
+ WP::add_admin_notice(
95
+ esc_html__( 'Settings were successfully saved.', 'wp-mail-smtp' ),
96
+ WP::ADMIN_NOTICE_SUCCESS
97
+ );
98
+ }
99
+ }
src/Admin/Pages/Settings.php CHANGED
@@ -1,236 +1,236 @@
1
- <?php
2
-
3
- namespace WPMailSMTP\Admin\Pages;
4
-
5
- use WPMailSMTP\Admin\PageAbstract;
6
- use WPMailSMTP\Options;
7
- use WPMailSMTP\WP;
8
-
9
- /**
10
- * Class Settings is part of Area, displays general settings of the plugin.
11
- *
12
- * @since 1.0.0
13
- */
14
- class Settings extends PageAbstract {
15
-
16
- /**
17
- * @var string Slug of a tab.
18
- */
19
- protected $slug = 'settings';
20
-
21
- /**
22
- * @inheritdoc
23
- */
24
- public function get_label() {
25
- return esc_html__( 'Settings', 'wp-mail-smtp' );
26
- }
27
-
28
- /**
29
- * @inheritdoc
30
- */
31
- public function get_title() {
32
- return $this->get_label();
33
- }
34
-
35
- /**
36
- * @inheritdoc
37
- */
38
- public function display() {
39
-
40
- $options = new Options();
41
- $mailer = $options->get( 'mail', 'mailer' );
42
- ?>
43
-
44
- <form method="POST" action="">
45
- <?php $this->wp_nonce_field(); ?>
46
-
47
- <!-- Mail Section Title -->
48
- <div class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-content wp-mail-smtp-clear section-heading no-desc" id="wp-mail-smtp-setting-row-email-heading">
49
- <div class="wp-mail-smtp-setting-field">
50
- <h2><?php esc_html_e( 'Mail', 'wp-mail-smtp' ); ?></h2>
51
- </div>
52
- </div>
53
-
54
- <!-- From Email -->
55
- <div id="wp-mail-smtp-setting-row-from_email" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-email wp-mail-smtp-clear">
56
- <div class="wp-mail-smtp-setting-label">
57
- <label for="wp-mail-smtp-setting-from_email"><?php esc_html_e( 'From Email', 'wp-mail-smtp' ); ?></label>
58
- </div>
59
- <div class="wp-mail-smtp-setting-field">
60
- <input name="wp-mail-smtp[mail][from_email]" type="email"
61
- value="<?php echo esc_attr( $options->get( 'mail', 'from_email' ) ); ?>"
62
- <?php echo $options->is_const_defined( 'mail', 'from_email' ) ? 'disabled' : ''; ?>
63
- id="wp-mail-smtp-setting-from_email" spellcheck="false"
64
- />
65
- <p class="desc">
66
- <?php esc_html_e( 'You can specify the email address that emails should be sent from.', 'wp-mail-smtp' ); ?><br/>
67
- <?php
68
- printf(
69
- /* translators: %s - default email address. */
70
- esc_html__( 'If you leave this blank, the default one will be used: %s.', 'wp-mail-smtp' ),
71
- '<code>' . wp_mail_smtp()->get_processor()->get_default_email() . '</code>'
72
- );
73
- ?>
74
- </p>
75
- <p class="desc">
76
- <?php esc_html_e( 'Please note if you are sending using an email provider (Gmail, Yahoo, Hotmail, Outlook.com, etc) this setting should be your email address for that account.', 'wp-mail-smtp' ); ?>
77
- </p>
78
- </div>
79
- </div>
80
-
81
- <!-- From Name -->
82
- <div id="wp-mail-smtp-setting-row-from_name" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-text wp-mail-smtp-clear">
83
- <div class="wp-mail-smtp-setting-label">
84
- <label for="wp-mail-smtp-setting-from_name"><?php esc_html_e( 'From Name', 'wp-mail-smtp' ); ?></label>
85
- </div>
86
- <div class="wp-mail-smtp-setting-field">
87
- <input name="wp-mail-smtp[mail][from_name]" type="text"
88
- value="<?php echo esc_attr( $options->get( 'mail', 'from_name' ) ); ?>"
89
- <?php echo $options->is_const_defined( 'mail', 'from_name' ) ? 'disabled' : ''; ?>
90
- id="wp-mail-smtp-setting-from-name" spellcheck="false"
91
- />
92
- <p class="desc">
93
- <?php esc_html_e( 'You can specify the name that emails should be sent from.', 'wp-mail-smtp' ); ?><br/>
94
- <?php
95
- printf(
96
- /* translators: %s - WordPress. */
97
- esc_html__( 'If you leave this blank, the emails will be sent from %s.', 'wp-mail-smtp' ),
98
- '<code>WordPress</code>'
99
- );
100
- ?>
101
- </p>
102
- </div>
103
- </div>
104
-
105
- <!-- Mailer -->
106
- <div id="wp-mail-smtp-setting-row-mailer" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-mailer wp-mail-smtp-clear">
107
- <div class="wp-mail-smtp-setting-label">
108
- <label for="wp-mail-smtp-setting-mailer"><?php esc_html_e( 'Mailer', 'wp-mail-smtp' ); ?></label>
109
- </div>
110
- <div class="wp-mail-smtp-setting-field">
111
- <div class="wp-mail-smtp-mailers">
112
-
113
- <?php foreach ( wp_mail_smtp()->get_providers()->get_options_all() as $provider ) : ?>
114
-
115
- <div class="wp-mail-smtp-mailer <?php echo $mailer === $provider->get_slug() ? 'active' : ''; ?>">
116
- <div class="wp-mail-smtp-mailer-image">
117
- <img src="<?php echo esc_url( $provider->get_logo_url() ); ?>"
118
- alt="<?php echo esc_attr( $provider->get_title() ); ?>">
119
- </div>
120
-
121
- <div class="wp-mail-smtp-mailer-text">
122
- <input id="wp-mail-smtp-setting-mailer-<?php echo esc_attr( $provider->get_slug() ); ?>"
123
- type="radio" name="wp-mail-smtp[mail][mailer]"
124
- value="<?php echo esc_attr( $provider->get_slug() ); ?>"
125
- <?php checked( $provider->get_slug(), $mailer ); ?>
126
- <?php echo $options->is_const_defined( 'mail', 'mailer' ) ? 'disabled' : ''; ?>
127
- />
128
- <label for="wp-mail-smtp-setting-mailer-<?php echo esc_attr( $provider->get_slug() ); ?>"><?php echo $provider->get_title(); ?></label>
129
- </div>
130
- </div>
131
-
132
- <?php endforeach; ?>
133
-
134
- </div>
135
- </div>
136
- </div>
137
-
138
- <!-- Return Path -->
139
- <div id="wp-mail-smtp-setting-row-return_path" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-checkbox wp-mail-smtp-clear">
140
- <div class="wp-mail-smtp-setting-label">
141
- <label for="wp-mail-smtp-setting-return_path"><?php esc_html_e( 'Return Path', 'wp-mail-smtp' ); ?></label>
142
- </div>
143
- <div class="wp-mail-smtp-setting-field">
144
- <input name="wp-mail-smtp[mail][return_path]" type="checkbox"
145
- value="true" <?php checked( true, $options->get( 'mail', 'return_path' ) ); ?>
146
- <?php echo $options->is_const_defined( 'mail', 'return_path' ) ? 'disabled' : ''; ?>
147
- id="wp-mail-smtp-setting-return_path"
148
- />
149
- <label for="wp-mail-smtp-setting-return_path"><?php esc_html_e( 'Set the return-path to match the From Email', 'wp-mail-smtp' ); ?></label></label>
150
- <p class="desc">
151
- <?php esc_html_e( 'Return Path indicates where non-delivery receipts - or bounce messages - are to be sent.', 'wp-mail-smtp' ); ?><br/>
152
- <?php esc_html_e( 'If unchecked bounce messages may be lost.', 'wp-mail-smtp' ); ?>
153
- </p>
154
- </div>
155
- </div>
156
-
157
- <!-- Mailer Options -->
158
- <div class="wp-mail-smtp-mailer-options">
159
- <?php foreach ( wp_mail_smtp()->get_providers()->get_options_all() as $provider ) : ?>
160
-
161
- <div class="wp-mail-smtp-mailer-option wp-mail-smtp-mailer-option-<?php echo esc_attr( $provider->get_slug() ); ?> <?php echo $mailer === $provider->get_slug() ? 'active' : 'hidden'; ?>">
162
-
163
- <!-- Mailer Option Title -->
164
- <?php $provider_desc = $provider->get_description(); ?>
165
- <div class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-content wp-mail-smtp-clear section-heading <?php empty( $provider_desc ) ? 'no-desc' : ''; ?>" id="wp-mail-smtp-setting-row-email-heading">
166
- <div class="wp-mail-smtp-setting-field">
167
- <h2><?php echo $provider->get_title(); ?></h2>
168
- <?php if ( ! empty( $provider_desc ) ) : ?>
169
- <p class="desc"><?php echo $provider_desc; ?></p>
170
- <?php endif; ?>
171
- </div>
172
- </div>
173
-
174
- <?php $provider->display_options(); ?>
175
- </div>
176
-
177
- <?php endforeach; ?>
178
-
179
- </div>
180
-
181
- <p class="wp-mail-smtp-submit">
182
- <button type="submit" class="wp-mail-smtp-btn wp-mail-smtp-btn-md wp-mail-smtp-btn-orange"><?php esc_html_e( 'Save Settings', 'wp-mail-smtp' ); ?></button>
183
- </p>
184
-
185
- </form>
186
-
187
- <?php
188
- }
189
-
190
- /**
191
- * @inheritdoc
192
- */
193
- public function process_post( $data ) {
194
-
195
- $this->check_admin_referer();
196
-
197
- $options = new Options();
198
- $old_opt = $options->get_all();
199
-
200
- $to_redirect = false;
201
-
202
- // Old and new Gmail client id/secret values are different - we need to invalidate tokens and scroll to Auth button.
203
- if (
204
- $options->get( 'mail', 'mailer' ) === 'gmail' &&
205
- (
206
- $options->get( 'gmail', 'client_id' ) !== $data['gmail']['client_id'] ||
207
- $options->get( 'gmail', 'client_secret' ) !== $data['gmail']['client_secret']
208
- )
209
- ) {
210
- unset( $old_opt['gmail'] );
211
-
212
- if (
213
- ! empty( $data['gmail']['client_id'] ) &&
214
- ! empty( $data['gmail']['client_secret'] )
215
- ) {
216
- $to_redirect = true;
217
- }
218
- }
219
-
220
- // New gmail clients data will be added from new $data, except the old access/refresh_token.
221
- $to_save = array_merge( $old_opt, $data );
222
-
223
- // All the sanitization is done there.
224
- $options->set( $to_save );
225
-
226
- if ( $to_redirect ) {
227
- wp_redirect( $_POST['_wp_http_referer'] . '#wp-mail-smtp-setting-row-gmail-authorize' );
228
- exit;
229
- }
230
-
231
- WP::add_admin_notice(
232
- esc_html__( 'Settings were successfully saved.', 'wp-mail-smtp' ),
233
- WP::ADMIN_NOTICE_SUCCESS
234
- );
235
- }
236
- }
1
+ <?php
2
+
3
+ namespace WPMailSMTP\Admin\Pages;
4
+
5
+ use WPMailSMTP\Admin\PageAbstract;
6
+ use WPMailSMTP\Options;
7
+ use WPMailSMTP\WP;
8
+
9
+ /**
10
+ * Class Settings is part of Area, displays general settings of the plugin.
11
+ *
12
+ * @since 1.0.0
13
+ */
14
+ class Settings extends PageAbstract {
15
+
16
+ /**
17
+ * @var string Slug of a tab.
18
+ */
19
+ protected $slug = 'settings';
20
+
21
+ /**
22
+ * @inheritdoc
23
+ */
24
+ public function get_label() {
25
+ return esc_html__( 'Settings', 'wp-mail-smtp' );
26
+ }
27
+
28
+ /**
29
+ * @inheritdoc
30
+ */
31
+ public function get_title() {
32
+ return $this->get_label();
33
+ }
34
+
35
+ /**
36
+ * @inheritdoc
37
+ */
38
+ public function display() {
39
+
40
+ $options = new Options();
41
+ $mailer = $options->get( 'mail', 'mailer' );
42
+ ?>
43
+
44
+ <form method="POST" action="">
45
+ <?php $this->wp_nonce_field(); ?>
46
+
47
+ <!-- Mail Section Title -->
48
+ <div class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-content wp-mail-smtp-clear section-heading no-desc" id="wp-mail-smtp-setting-row-email-heading">
49
+ <div class="wp-mail-smtp-setting-field">
50
+ <h2><?php esc_html_e( 'Mail', 'wp-mail-smtp' ); ?></h2>
51
+ </div>
52
+ </div>
53
+
54
+ <!-- From Email -->
55
+ <div id="wp-mail-smtp-setting-row-from_email" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-email wp-mail-smtp-clear">
56
+ <div class="wp-mail-smtp-setting-label">
57
+ <label for="wp-mail-smtp-setting-from_email"><?php esc_html_e( 'From Email', 'wp-mail-smtp' ); ?></label>
58
+ </div>
59
+ <div class="wp-mail-smtp-setting-field">
60
+ <input name="wp-mail-smtp[mail][from_email]" type="email"
61
+ value="<?php echo esc_attr( $options->get( 'mail', 'from_email' ) ); ?>"
62
+ <?php echo $options->is_const_defined( 'mail', 'from_email' ) ? 'disabled' : ''; ?>
63
+ id="wp-mail-smtp-setting-from_email" spellcheck="false"
64
+ />
65
+ <p class="desc">
66
+ <?php esc_html_e( 'You can specify the email address that emails should be sent from.', 'wp-mail-smtp' ); ?><br/>
67
+ <?php
68
+ printf(
69
+ /* translators: %s - default email address. */
70
+ esc_html__( 'If you leave this blank, the default one will be used: %s.', 'wp-mail-smtp' ),
71
+ '<code>' . wp_mail_smtp()->get_processor()->get_default_email() . '</code>'
72
+ );
73
+ ?>
74
+ </p>
75
+ <p class="desc">
76
+ <?php esc_html_e( 'Please note if you are sending using an email provider (Gmail, Yahoo, Hotmail, Outlook.com, etc) this setting should be your email address for that account.', 'wp-mail-smtp' ); ?>
77
+ </p>
78
+ </div>
79
+ </div>
80
+
81
+ <!-- From Name -->
82
+ <div id="wp-mail-smtp-setting-row-from_name" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-text wp-mail-smtp-clear">
83
+ <div class="wp-mail-smtp-setting-label">
84
+ <label for="wp-mail-smtp-setting-from_name"><?php esc_html_e( 'From Name', 'wp-mail-smtp' ); ?></label>
85
+ </div>
86
+ <div class="wp-mail-smtp-setting-field">
87
+ <input name="wp-mail-smtp[mail][from_name]" type="text"
88
+ value="<?php echo esc_attr( $options->get( 'mail', 'from_name' ) ); ?>"
89
+ <?php echo $options->is_const_defined( 'mail', 'from_name' ) ? 'disabled' : ''; ?>
90
+ id="wp-mail-smtp-setting-from-name" spellcheck="false"
91
+ />
92
+ <p class="desc">
93
+ <?php esc_html_e( 'You can specify the name that emails should be sent from.', 'wp-mail-smtp' ); ?><br/>
94
+ <?php
95
+ printf(
96
+ /* translators: %s - WordPress. */
97
+ esc_html__( 'If you leave this blank, the emails will be sent from %s.', 'wp-mail-smtp' ),
98
+ '<code>WordPress</code>'
99
+ );
100
+ ?>
101
+ </p>
102
+ </div>
103
+ </div>
104
+
105
+ <!-- Mailer -->
106
+ <div id="wp-mail-smtp-setting-row-mailer" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-mailer wp-mail-smtp-clear">
107
+ <div class="wp-mail-smtp-setting-label">
108
+ <label for="wp-mail-smtp-setting-mailer"><?php esc_html_e( 'Mailer', 'wp-mail-smtp' ); ?></label>
109
+ </div>
110
+ <div class="wp-mail-smtp-setting-field">
111
+ <div class="wp-mail-smtp-mailers">
112
+
113
+ <?php foreach ( wp_mail_smtp()->get_providers()->get_options_all() as $provider ) : ?>
114
+
115
+ <div class="wp-mail-smtp-mailer <?php echo $mailer === $provider->get_slug() ? 'active' : ''; ?>">
116
+ <div class="wp-mail-smtp-mailer-image">
117
+ <img src="<?php echo esc_url( $provider->get_logo_url() ); ?>"
118
+ alt="<?php echo esc_attr( $provider->get_title() ); ?>">
119
+ </div>
120
+
121
+ <div class="wp-mail-smtp-mailer-text">
122
+ <input id="wp-mail-smtp-setting-mailer-<?php echo esc_attr( $provider->get_slug() ); ?>"
123
+ type="radio" name="wp-mail-smtp[mail][mailer]"
124
+ value="<?php echo esc_attr( $provider->get_slug() ); ?>"
125
+ <?php checked( $provider->get_slug(), $mailer ); ?>
126
+ <?php echo $options->is_const_defined( 'mail', 'mailer' ) ? 'disabled' : ''; ?>
127
+ />
128
+ <label for="wp-mail-smtp-setting-mailer-<?php echo esc_attr( $provider->get_slug() ); ?>"><?php echo $provider->get_title(); ?></label>
129
+ </div>
130
+ </div>
131
+
132
+ <?php endforeach; ?>
133
+
134
+ </div>
135
+ </div>
136
+ </div>
137
+
138
+ <!-- Return Path -->
139
+ <div id="wp-mail-smtp-setting-row-return_path" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-checkbox wp-mail-smtp-clear">
140
+ <div class="wp-mail-smtp-setting-label">
141
+ <label for="wp-mail-smtp-setting-return_path"><?php esc_html_e( 'Return Path', 'wp-mail-smtp' ); ?></label>
142
+ </div>
143
+ <div class="wp-mail-smtp-setting-field">
144
+ <input name="wp-mail-smtp[mail][return_path]" type="checkbox"
145
+ value="true" <?php checked( true, $options->get( 'mail', 'return_path' ) ); ?>
146
+ <?php echo $options->is_const_defined( 'mail', 'return_path' ) ? 'disabled' : ''; ?>
147
+ id="wp-mail-smtp-setting-return_path"
148
+ />
149
+ <label for="wp-mail-smtp-setting-return_path"><?php esc_html_e( 'Set the return-path to match the From Email', 'wp-mail-smtp' ); ?></label></label>
150
+ <p class="desc">
151
+ <?php esc_html_e( 'Return Path indicates where non-delivery receipts - or bounce messages - are to be sent.', 'wp-mail-smtp' ); ?><br/>
152
+ <?php esc_html_e( 'If unchecked bounce messages may be lost.', 'wp-mail-smtp' ); ?>
153
+ </p>
154
+ </div>
155
+ </div>
156
+
157
+ <!-- Mailer Options -->
158
+ <div class="wp-mail-smtp-mailer-options">
159
+ <?php foreach ( wp_mail_smtp()->get_providers()->get_options_all() as $provider ) : ?>
160
+
161
+ <div class="wp-mail-smtp-mailer-option wp-mail-smtp-mailer-option-<?php echo esc_attr( $provider->get_slug() ); ?> <?php echo $mailer === $provider->get_slug() ? 'active' : 'hidden'; ?>">
162
+
163
+ <!-- Mailer Option Title -->
164
+ <?php $provider_desc = $provider->get_description(); ?>
165
+ <div class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-content wp-mail-smtp-clear section-heading <?php empty( $provider_desc ) ? 'no-desc' : ''; ?>" id="wp-mail-smtp-setting-row-email-heading">
166
+ <div class="wp-mail-smtp-setting-field">
167
+ <h2><?php echo $provider->get_title(); ?></h2>
168
+ <?php if ( ! empty( $provider_desc ) ) : ?>
169
+ <p class="desc"><?php echo $provider_desc; ?></p>
170
+ <?php endif; ?>
171
+ </div>
172
+ </div>
173
+
174
+ <?php $provider->display_options(); ?>
175
+ </div>
176
+
177
+ <?php endforeach; ?>
178
+
179
+ </div>
180
+
181
+ <p class="wp-mail-smtp-submit">
182
+ <button type="submit" class="wp-mail-smtp-btn wp-mail-smtp-btn-md wp-mail-smtp-btn-orange"><?php esc_html_e( 'Save Settings', 'wp-mail-smtp' ); ?></button>
183
+ </p>
184
+
185
+ </form>
186
+
187
+ <?php
188
+ }
189
+
190
+ /**
191
+ * @inheritdoc
192
+ */
193
+ public function process_post( $data ) {
194
+
195
+ $this->check_admin_referer();
196
+
197
+ $options = new Options();
198
+ $old_opt = $options->get_all();
199
+
200
+ $to_redirect = false;
201
+
202
+ // Old and new Gmail client id/secret values are different - we need to invalidate tokens and scroll to Auth button.
203
+ if (
204
+ $options->get( 'mail', 'mailer' ) === 'gmail' &&
205
+ (
206
+ $options->get( 'gmail', 'client_id' ) !== $data['gmail']['client_id'] ||
207
+ $options->get( 'gmail', 'client_secret' ) !== $data['gmail']['client_secret']
208
+ )
209
+ ) {
210
+ unset( $old_opt['gmail'] );
211
+
212
+ if (
213
+ ! empty( $data['gmail']['client_id'] ) &&
214
+ ! empty( $data['gmail']['client_secret'] )
215
+ ) {
216
+ $to_redirect = true;
217
+ }
218
+ }
219
+
220
+ // New gmail clients data will be added from new $data, except the old access/refresh_token.
221
+ $to_save = array_merge( $old_opt, $data );
222
+
223
+ // All the sanitization is done there.
224
+ $options->set( $to_save );
225
+
226
+ if ( $to_redirect ) {
227
+ wp_redirect( $_POST['_wp_http_referer'] . '#wp-mail-smtp-setting-row-gmail-authorize' );
228
+ exit;
229
+ }
230
+
231
+ WP::add_admin_notice(
232
+ esc_html__( 'Settings were successfully saved.', 'wp-mail-smtp' ),
233
+ WP::ADMIN_NOTICE_SUCCESS
234
+ );
235
+ }
236
+ }
src/Admin/Pages/Test.php CHANGED
@@ -1,208 +1,235 @@
1
- <?php
2
-
3
- namespace WPMailSMTP\Admin\Pages;
4
-
5
- use WPMailSMTP\MailCatcher;
6
- use WPMailSMTP\Options;
7
- use WPMailSMTP\WP;
8
- use WPMailSMTP\Admin\PageAbstract;
9
-
10
- /**
11
- * Class Test is part of Area, displays email testing page of the plugin.
12
- *
13
- * @since 1.0.0
14
- */
15
- class Test extends PageAbstract {
16
-
17
- /**
18
- * @var string Slug of a tab.
19
- */
20
- protected $slug = 'test';
21
-
22
- /**
23
- * @inheritdoc
24
- */
25
- public function get_label() {
26
- return esc_html__( 'Email Test', 'wp-mail-smtp' );
27
- }
28
-
29
- /**
30
- * @inheritdoc
31
- */
32
- public function get_title() {
33
- return $this->get_label();
34
- }
35
-
36
- /**
37
- * @inheritdoc
38
- */
39
- public function display() {
40
- ?>
41
-
42
- <form method="POST" action="">
43
- <?php $this->wp_nonce_field(); ?>
44
-
45
- <!-- Test Email Section Title -->
46
- <div class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-content wp-mail-smtp-clear section-heading no-desc" id="wp-mail-smtp-setting-row-email-heading">
47
- <div class="wp-mail-smtp-setting-field">
48
- <h2><?php esc_html_e( 'Send a Test Email', 'wp-mail-smtp' ); ?></h2>
49
- </div>
50
- </div>
51
-
52
- <!-- Test Email -->
53
- <div id="wp-mail-smtp-setting-row-test_email" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-email wp-mail-smtp-clear">
54
- <div class="wp-mail-smtp-setting-label">
55
- <label for="wp-mail-smtp-setting-test_email"><?php esc_html_e( 'Send To', 'wp-mail-smtp' ); ?></label>
56
- </div>
57
- <div class="wp-mail-smtp-setting-field">
58
- <input name="wp-mail-smtp[test_email]" type="email" id="wp-mail-smtp-setting-test_email" spellcheck="false" required />
59
- <p class="desc">
60
- <?php esc_html_e( 'Type an email address here and then click a button below to generate a test email.', 'wp-mail-smtp' ); ?>
61
- </p>
62
- </div>
63
- </div>
64
-
65
- <p class="wp-mail-smtp-submit">
66
- <button type="submit" class="wp-mail-smtp-btn wp-mail-smtp-btn-md wp-mail-smtp-btn-orange"><?php esc_html_e( 'Send Email', 'wp-mail-smtp' ); ?></button>
67
- </p>
68
- </form>
69
-
70
- <?php
71
- }
72
-
73
- /**
74
- * @inheritdoc
75
- */
76
- public function process_post( $data ) {
77
-
78
- $this->check_admin_referer();
79
-
80
- if ( isset( $data['test_email'] ) ) {
81
- $data['test_email'] = filter_var( $data['test_email'], FILTER_VALIDATE_EMAIL );
82
- }
83
-
84
- if ( empty( $data['test_email'] ) ) {
85
- WP::add_admin_notice(
86
- esc_html__( 'Test failed. Please use a valid email address and try to resend the test email.', 'wp-mail-smtp' ),
87
- WP::ADMIN_NOTICE_WARNING
88
- );
89
- return;
90
- }
91
-
92
- global $phpmailer;
93
-
94
- // Make sure the PHPMailer class has been instantiated.
95
- if ( ! is_object( $phpmailer ) || ! is_a( $phpmailer, 'PHPMailer' ) ) {
96
- require_once ABSPATH . WPINC . '/class-phpmailer.php';
97
- $phpmailer = new MailCatcher( true );
98
- }
99
-
100
- // Set SMTPDebug level, default is 2 (commands + data + connection status).
101
- $phpmailer->SMTPDebug = apply_filters( 'wp_mail_smtp_admin_test_email_smtp_debug', 2 );
102
-
103
- // Start output buffering to grab smtp debugging output.
104
- ob_start();
105
-
106
- // Send the test mail.
107
- $result = wp_mail(
108
- $data['test_email'],
109
- /* translators: %s - email address a test email will be sent to. */
110
- 'WP Mail SMTP: ' . sprintf( esc_html__( 'Test email to %s', 'wp-mail-smtp' ), $data['test_email'] ),
111
- sprintf(
112
- /* translators: %s - mailer name. */
113
- esc_html__( 'This email was sent by %s mailer, and generated by the WP Mail SMTP WordPress plugin.', 'wp-mail-smtp' ),
114
- wp_mail_smtp()->get_providers()->get_options( Options::init()->get( 'mail', 'mailer' ) )->get_title()
115
- )
116
- );
117
-
118
- // Grab the smtp debugging output.
119
- $smtp_debug = ob_get_clean();
120
-
121
- /*
122
- * Do the actual sending.
123
- */
124
- if ( $result ) {
125
- WP::add_admin_notice(
126
- esc_html__( 'Your email was sent successfully!', 'wp-mail-smtp' ),
127
- WP::ADMIN_NOTICE_SUCCESS
128
- );
129
- } else {
130
- $error = $this->get_debug_messages( $phpmailer, $smtp_debug );
131
-
132
- WP::add_admin_notice(
133
- '<p><strong>' . esc_html__( 'There was a problem while sending a test email.', 'wp-mail-smtp' ) . '</strong></p>' .
134
- '<p>' . esc_html__( 'The related debugging output is shown below:', 'wp-mail-smtp' ) . '</p>' .
135
- '<blockquote>' . $error . '</blockquote>',
136
- WP::ADMIN_NOTICE_ERROR
137
- );
138
- }
139
- }
140
-
141
- /**
142
- * Prepare debug information, that will help users to identify the error.
143
- *
144
- * @param \PHPMailer $phpmailer
145
- * @param string $smtp_debug
146
- *
147
- * @return string
148
- */
149
- protected function get_debug_messages( $phpmailer, $smtp_debug ) {
150
-
151
- global $wp_version;
152
-
153
- $errors = array();
154
-
155
- $versions_text = '<h3>Versions</h3>';
156
-
157
- $versions_text .= '<strong>WordPress:</strong> ' . $wp_version . '<br>';
158
- $versions_text .= '<strong>PHP:</strong> ' . PHP_VERSION . '<br>';
159
- $versions_text .= '<strong>WP Mail SMTP:</strong> ' . WPMS_PLUGIN_VER;
160
-
161
- $errors[] = $versions_text;
162
-
163
- $phpmailer_text = '<h3>PHPMailer</h3>';
164
-
165
- $phpmailer_text .= '<strong>ErrorInfo:</strong> ' . make_clickable( $phpmailer->ErrorInfo ) . '<br>';
166
- $phpmailer_text .= '<strong>Mailer:</strong> ' . $phpmailer->Mailer . '<br>';
167
- $phpmailer_text .= '<strong>Host:</strong> ' . $phpmailer->Host . '<br>';
168
- $phpmailer_text .= '<strong>Port:</strong> ' . $phpmailer->Port . '<br>';
169
- $phpmailer_text .= '<strong>SMTPSecure:</strong> ' . $this->pvar( $phpmailer->SMTPSecure ) . '<br>';
170
- $phpmailer_text .= '<strong>SMTPAutoTLS:</strong> ' . $this->pvar( $phpmailer->SMTPAutoTLS ) . '<br>';
171
- $phpmailer_text .= '<strong>SMTPAuth:</strong> ' . $this->pvar( $phpmailer->SMTPAuth );
172
- if ( ! empty( $phpmailer->SMTPOptions ) ) {
173
- $phpmailer_text .= '<br><strong>SMTPOptions:</strong> ' . $this->pvar( $phpmailer->SMTPOptions );
174
- }
175
-
176
- $errors[] = $phpmailer_text;
177
-
178
- if ( ! empty( $smtp_debug ) ) {
179
- $errors[] = '<h3>SMTP Debug</h3>' . nl2br( $smtp_debug );
180
- }
181
-
182
- return implode( '</p><p>', $errors );
183
- }
184
-
185
- /**
186
- * Get the proper variable content output to debug.
187
- *
188
- * @param mixed $var
189
- *
190
- * @return string
191
- */
192
- protected function pvar( $var = '' ) {
193
-
194
- ob_start();
195
-
196
- echo '<code>';
197
-
198
- if ( is_bool( $var ) || empty( $var ) ) {
199
- var_dump( $var );
200
- } else {
201
- print_r( $var );
202
- }
203
-
204
- echo '</code>';
205
-
206
- return ob_get_clean();
207
- }
208
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WPMailSMTP\Admin\Pages;
4
+
5
+ use WPMailSMTP\MailCatcher;
6
+ use WPMailSMTP\Options;
7
+ use WPMailSMTP\WP;
8
+ use WPMailSMTP\Admin\PageAbstract;
9
+
10
+ /**
11
+ * Class Test is part of Area, displays email testing page of the plugin.
12
+ *
13
+ * @since 1.0.0
14
+ */
15
+ class Test extends PageAbstract {
16
+
17
+ /**
18
+ * @var string Slug of a tab.
19
+ */
20
+ protected $slug = 'test';
21
+
22
+ /**
23
+ * @inheritdoc
24
+ */
25
+ public function get_label() {
26
+ return esc_html__( 'Email Test', 'wp-mail-smtp' );
27
+ }
28
+
29
+ /**
30
+ * @inheritdoc
31
+ */
32
+ public function get_title() {
33
+ return $this->get_label();
34
+ }
35
+
36
+ /**
37
+ * @inheritdoc
38
+ */
39
+ public function display() {
40
+ ?>
41
+
42
+ <form method="POST" action="">
43
+ <?php $this->wp_nonce_field(); ?>
44
+
45
+ <!-- Test Email Section Title -->
46
+ <div class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-content wp-mail-smtp-clear section-heading no-desc" id="wp-mail-smtp-setting-row-email-heading">
47
+ <div class="wp-mail-smtp-setting-field">
48
+ <h2><?php esc_html_e( 'Send a Test Email', 'wp-mail-smtp' ); ?></h2>
49
+ </div>
50
+ </div>
51
+
52
+ <!-- Test Email -->
53
+ <div id="wp-mail-smtp-setting-row-test_email" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-email wp-mail-smtp-clear">
54
+ <div class="wp-mail-smtp-setting-label">
55
+ <label for="wp-mail-smtp-setting-test_email"><?php esc_html_e( 'Send To', 'wp-mail-smtp' ); ?></label>
56
+ </div>
57
+ <div class="wp-mail-smtp-setting-field">
58
+ <input name="wp-mail-smtp[test_email]" type="email" id="wp-mail-smtp-setting-test_email" spellcheck="false" required />
59
+ <p class="desc">
60
+ <?php esc_html_e( 'Type an email address here and then click a button below to generate a test email.', 'wp-mail-smtp' ); ?>
61
+ </p>
62
+ </div>
63
+ </div>
64
+
65
+ <p class="wp-mail-smtp-submit">
66
+ <button type="submit" class="wp-mail-smtp-btn wp-mail-smtp-btn-md wp-mail-smtp-btn-orange"><?php esc_html_e( 'Send Email', 'wp-mail-smtp' ); ?></button>
67
+ </p>
68
+ </form>
69
+
70
+ <?php
71
+ }
72
+
73
+ /**
74
+ * @inheritdoc
75
+ */
76
+ public function process_post( $data ) {
77
+
78
+ $this->check_admin_referer();
79
+
80
+ if ( isset( $data['test_email'] ) ) {
81
+ $data['test_email'] = filter_var( $data['test_email'], FILTER_VALIDATE_EMAIL );
82
+ }
83
+
84
+ if ( empty( $data['test_email'] ) ) {
85
+ WP::add_admin_notice(
86
+ esc_html__( 'Test failed. Please use a valid email address and try to resend the test email.', 'wp-mail-smtp' ),
87
+ WP::ADMIN_NOTICE_WARNING
88
+ );
89
+ return;
90
+ }
91
+
92
+ global $phpmailer;
93
+
94
+ // Make sure the PHPMailer class has been instantiated.
95
+ if ( ! is_object( $phpmailer ) || ! is_a( $phpmailer, 'PHPMailer' ) ) {
96
+ require_once ABSPATH . WPINC . '/class-phpmailer.php';
97
+ $phpmailer = new MailCatcher( true );
98
+ }
99
+
100
+ // Set SMTPDebug level, default is 3 (commands + data + connection status).
101
+ $phpmailer->SMTPDebug = apply_filters( 'wp_mail_smtp_admin_test_email_smtp_debug', 3 );
102
+
103
+ // Start output buffering to grab smtp debugging output.
104
+ ob_start();
105
+
106
+ // Send the test mail.
107
+ $result = wp_mail(
108
+ $data['test_email'],
109
+ /* translators: %s - email address a test email will be sent to. */
110
+ 'WP Mail SMTP: ' . sprintf( esc_html__( 'Test email to %s', 'wp-mail-smtp' ), $data['test_email'] ),
111
+ sprintf(
112
+ /* translators: %s - mailer name. */
113
+ esc_html__( 'This email was sent by %s mailer, and generated by the WP Mail SMTP WordPress plugin.', 'wp-mail-smtp' ),
114
+ wp_mail_smtp()->get_providers()->get_options( Options::init()->get( 'mail', 'mailer' ) )->get_title()
115
+ )
116
+ );
117
+
118
+ // Grab the smtp debugging output.
119
+ $smtp_debug = ob_get_clean();
120
+
121
+ /*
122
+ * Do the actual sending.
123
+ */
124
+ if ( $result ) {
125
+ WP::add_admin_notice(
126
+ esc_html__( 'Your email was sent successfully!', 'wp-mail-smtp' ),
127
+ WP::ADMIN_NOTICE_SUCCESS
128
+ );
129
+ } else {
130
+ $error = $this->get_debug_messages( $phpmailer, $smtp_debug );
131
+
132
+ WP::add_admin_notice(
133
+ '<p><strong>' . esc_html__( 'There was a problem while sending a test email.', 'wp-mail-smtp' ) . '</strong></p>' .
134
+ '<p>' . esc_html__( 'The related debugging output is shown below:', 'wp-mail-smtp' ) . '</p>' .
135
+ '<blockquote style="border-left:1px solid orange;padding-left:10px">' . $error . '</blockquote>' .
136
+ '<p class="description">' . esc_html__( 'Please copy only the content of the error debug message above, identified with an orange left border, into the support forum topic if you experience any issues.', 'wp-mail-smtp' ) . '</p>',
137
+ WP::ADMIN_NOTICE_ERROR
138
+ );
139
+ }
140
+ }
141
+
142
+ /**
143
+ * Prepare debug information, that will help users to identify the error.
144
+ *
145
+ * @since 1.0.0
146
+ *
147
+ * @param \PHPMailer $phpmailer
148
+ * @param string $smtp_debug
149
+ *
150
+ * @return string
151
+ */
152
+ protected function get_debug_messages( $phpmailer, $smtp_debug ) {
153
+
154
+ $options = new Options();
155
+
156
+ /*
157
+ * Versions Debug.
158
+ */
159
+
160
+ $versions_text = '<strong>Versions:</strong><br>';
161
+
162
+ $versions_text .= '<strong>WordPress:</strong> ' . get_bloginfo( 'version' ) . '<br>';
163
+ $versions_text .= '<strong>WordPress MS:</strong> ' . ( is_multisite() ? 'Yes' : 'No' ) . '<br>';
164
+ $versions_text .= '<strong>PHP:</strong> ' . PHP_VERSION . '<br>';
165
+ $versions_text .= '<strong>WP Mail SMTP:</strong> ' . WPMS_PLUGIN_VER . '<br>';
166
+
167
+ /*
168
+ * Mailer Debug.
169
+ */
170
+
171
+ $mailer_text = '<strong>PHPMailer:</strong><br>';
172
+
173
+ $mailer_text .= '<strong>Mailer:</strong> ' . $phpmailer->Mailer . '<br>';
174
+
175
+ // Display different debug info based on the mailer.
176
+ if ( $options->is_mailer_smtp() ) {
177
+ $mailer_text .= '<strong>ErrorInfo:</strong> ' . make_clickable( $phpmailer->ErrorInfo ) . '<br>';
178
+ $mailer_text .= '<strong>Host:</strong> ' . $phpmailer->Host . '<br>';
179
+ $mailer_text .= '<strong>Port:</strong> ' . $phpmailer->Port . '<br>';
180
+ $mailer_text .= '<strong>SMTPSecure:</strong> ' . $this->pvar( $phpmailer->SMTPSecure ) . '<br>';
181
+ $mailer_text .= '<strong>SMTPAutoTLS:</strong> ' . $this->pvar( $phpmailer->SMTPAutoTLS ) . '<br>';
182
+ $mailer_text .= '<strong>SMTPAuth:</strong> ' . $this->pvar( $phpmailer->SMTPAuth );
183
+ if ( ! empty( $phpmailer->SMTPOptions ) ) {
184
+ $mailer_text .= '<br><strong>SMTPOptions:</strong> <code>' . json_encode( $phpmailer->SMTPOptions ) . '</code>';
185
+ }
186
+ }
187
+
188
+ /*
189
+ * SMTP Debug.
190
+ */
191
+
192
+ $smtp_text = '<br><strong>SMTP Debug:</strong><br>';
193
+ if ( ! empty( $smtp_debug ) ) {
194
+ $smtp_text .= $smtp_debug;
195
+ } else {
196
+ $smtp_text .= '[empty]';
197
+ }
198
+
199
+ $errors = apply_filters( 'wp_mail_smtp_admin_test_get_debug_messages', array(
200
+ $versions_text,
201
+ $mailer_text,
202
+ $smtp_text,
203
+ ) );
204
+
205
+ return '<pre>' . implode( '<br>', $errors ) . '</pre>';
206
+ }
207
+
208
+ /**
209
+ * Get the proper variable content output to debug.
210
+ *
211
+ * @since 1.0.0
212
+ *
213
+ * @param mixed $var
214
+ *
215
+ * @return string
216
+ */
217
+ protected function pvar( $var = '' ) {
218
+
219
+ ob_start();
220
+
221
+ echo '<code>';
222
+
223
+ if ( is_bool( $var ) || empty( $var ) ) {
224
+ var_dump( $var );
225
+ } else {
226
+ print_r( $var );
227
+ }
228
+
229
+ echo '</code>';
230
+
231
+ $output = ob_get_clean();
232
+
233
+ return str_replace( array( "\r\n", "\r", "\n" ), '', $output );
234
+ }
235
+ }
src/Core.php CHANGED
@@ -1,213 +1,239 @@
1
- <?php
2
-
3
- namespace WPMailSMTP;
4
-
5
- /**
6
- * Class Core to handle all plugin initialization.
7
- *
8
- * @since 1.0.0
9
- */
10
- class Core {
11
-
12
- /**
13
- * Without trailing slash.
14
- *
15
- * @var string
16
- */
17
- public $plugin_url;
18
- /**
19
- * Without trailing slash.
20
- *
21
- * @var string
22
- */
23
- public $plugin_path;
24
-
25
- /**
26
- * Core constructor.
27
- *
28
- * @since 1.0.0
29
- */
30
- public function __construct() {
31
-
32
- $this->plugin_url = rtrim( plugin_dir_url( __DIR__ ), '/\\' );
33
- $this->plugin_path = rtrim( plugin_dir_path( __DIR__ ), '/\\' );
34
-
35
- $this->hooks();
36
- }
37
-
38
- /**
39
- * Assign all hooks to proper places.
40
- *
41
- * @since 1.0.0
42
- */
43
- public function hooks() {
44
-
45
- // Activation hook.
46
- add_action( 'activate_wp-mail-smtp/wp_mail_smtp.php', array( $this, 'activate' ) );
47
-
48
- add_action( 'plugins_loaded', array( $this, 'get_processor' ) );
49
- add_action( 'plugins_loaded', array( $this, 'replace_phpmailer' ) );
50
- add_action( 'plugins_loaded', array( $this, 'init_notifications' ) );
51
-
52
- add_action( 'admin_notices', array( '\WPMailSMTP\WP', 'display_admin_notices' ) );
53
-
54
- add_action( 'init', array( $this, 'init' ) );
55
- }
56
-
57
- /**
58
- * Initial plugin actions.
59
- *
60
- * @since 1.0.0
61
- */
62
- public function init() {
63
-
64
- // Load translations just in case.
65
- load_plugin_textdomain( 'wp-mail-smtp', false, wp_mail_smtp()->plugin_path . '/languages' );
66
-
67
- /*
68
- * Constantly check in admin area, that we don't need to upgrade DB.
69
- * Do not wait for the `admin_init` hook, because some actions are already done
70
- * on `plugins_loaded`, so migration has to be done before.
71
- */
72
- if ( WP::in_wp_admin() ) {
73
- $this->get_migration();
74
- $this->get_admin();
75
- }
76
- }
77
-
78
- /**
79
- * Load the plugin core processor.
80
- *
81
- * @since 1.0.0
82
- *
83
- * @return Processor
84
- */
85
- public function get_processor() {
86
-
87
- static $processor;
88
-
89
- if ( ! isset( $processor ) ) {
90
- $processor = apply_filters( 'wp_mail_smtp_core_get_processor', new Processor() );
91
- }
92
-
93
- return $processor;
94
- }
95
-
96
- /**
97
- * Load the plugin admin area.
98
- *
99
- * @since 1.0.0
100
- *
101
- * @return Admin\Area
102
- */
103
- public function get_admin() {
104
-
105
- static $admin;
106
-
107
- if ( ! isset( $admin ) ) {
108
- $admin = apply_filters( 'wp_mail_smtp_core_get_admin', new Admin\Area() );
109
- }
110
-
111
- return $admin;
112
- }
113
-
114
- /**
115
- * Load the plugin providers loader.
116
- *
117
- * @since 1.0.0
118
- *
119
- * @return Providers\Loader
120
- */
121
- public function get_providers() {
122
-
123
- static $providers;
124
-
125
- if ( ! isset( $providers ) ) {
126
- $providers = apply_filters( 'wp_mail_smtp_core_get_providers', new Providers\Loader() );
127
- }
128
-
129
- return $providers;
130
- }
131
-
132
- /**
133
- * Load the plugin option migrator.
134
- *
135
- * @since 1.0.0
136
- *
137
- * @return Migration
138
- */
139
- public function get_migration() {
140
-
141
- static $migration;
142
-
143
- if ( ! isset( $migration ) ) {
144
- $migration = apply_filters( 'wp_mail_smtp_core_get_migration', new Migration() );
145
- }
146
-
147
- return $migration;
148
- }
149
-
150
- /**
151
- * Awesome Motive Notifications.
152
- *
153
- * @since 1.0.0
154
- */
155
- public function init_notifications() {
156
-
157
- if ( Options::init()->get( 'general', 'am_notifications_hidden' ) ) {
158
- return;
159
- }
160
-
161
- static $notification;
162
-
163
- if ( ! isset( $notification ) ) {
164
- $notification = new AM_Notification( 'smtp', WPMS_PLUGIN_VER );
165
- }
166
- }
167
-
168
- /**
169
- * Init the \PHPMailer replacement.
170
- *
171
- * @since 1.0.0
172
- *
173
- * @return \WPMailSMTP\MailCatcher
174
- */
175
- public function replace_phpmailer() {
176
- global $phpmailer;
177
-
178
- return $this->replace_w_fake_phpmailer( $phpmailer );
179
- }
180
-
181
- /**
182
- * Overwrite default PhpMailer with out MailCatcher.
183
- *
184
- * @since 1.0.0
185
- *
186
- * @param null $obj
187
- *
188
- * @return \WPMailSMTP\MailCatcher
189
- */
190
- protected function replace_w_fake_phpmailer( &$obj = null ) {
191
-
192
- $obj = new MailCatcher();
193
-
194
- return $obj;
195
- }
196
-
197
- /**
198
- * What to do on plugin activation.
199
- *
200
- * @since 1.0.0
201
- */
202
- public function activate() {
203
-
204
- $options['mail'] = array(
205
- 'from_email' => get_option( 'admin_email' ),
206
- 'from_name' => get_bloginfo( 'name' ),
207
- 'mailer' => 'mail',
208
- 'return_path' => false,
209
- );
210
-
211
- Options::init()->set( $options );
212
- }
213
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WPMailSMTP;
4
+
5
+ /**
6
+ * Class Core to handle all plugin initialization.
7
+ *
8
+ * @since 1.0.0
9
+ */
10
+ class Core {
11
+
12
+ /**
13
+ * Without trailing slash.
14
+ *
15
+ * @var string
16
+ */
17
+ public $plugin_url;
18
+ /**
19
+ * Without trailing slash.
20
+ *
21
+ * @var string
22
+ */
23
+ public $plugin_path;
24
+
25
+ /**
26
+ * Core constructor.
27
+ *
28
+ * @since 1.0.0
29
+ */
30
+ public function __construct() {
31
+
32
+ $this->plugin_url = rtrim( plugin_dir_url( __DIR__ ), '/\\' );
33
+ $this->plugin_path = rtrim( plugin_dir_path( __DIR__ ), '/\\' );
34
+
35
+ $this->hooks();
36
+ }
37
+
38
+ /**
39
+ * Assign all hooks to proper places.
40
+ *
41
+ * @since 1.0.0
42
+ */
43
+ public function hooks() {
44
+
45
+ // Activation hook.
46
+ add_action( 'activate_wp-mail-smtp/wp_mail_smtp.php', array( $this, 'activate' ) );
47
+
48
+ add_action( 'plugins_loaded', array( $this, 'get_processor' ) );
49
+ add_action( 'plugins_loaded', array( $this, 'replace_phpmailer' ) );
50
+ add_action( 'plugins_loaded', array( $this, 'init_notifications' ) );
51
+
52
+ add_action( 'admin_notices', array( '\WPMailSMTP\WP', 'display_admin_notices' ) );
53
+
54
+ add_action( 'init', array( $this, 'init' ) );
55
+ }
56
+
57
+ /**
58
+ * Initial plugin actions.
59
+ *
60
+ * @since 1.0.0
61
+ */
62
+ public function init() {
63
+
64
+ // Load translations just in case.
65
+ load_plugin_textdomain( 'wp-mail-smtp', false, wp_mail_smtp()->plugin_path . '/languages' );
66
+
67
+ /*
68
+ * Constantly check in admin area, that we don't need to upgrade DB.
69
+ * Do not wait for the `admin_init` hook, because some actions are already done
70
+ * on `plugins_loaded`, so migration has to be done before.
71
+ */
72
+ if ( WP::in_wp_admin() ) {
73
+ $this->get_migration();
74
+ $this->get_upgrade();
75
+ $this->get_admin();
76
+ }
77
+ }
78
+
79
+ /**
80
+ * Load the plugin core processor.
81
+ *
82
+ * @since 1.0.0
83
+ *
84
+ * @return Processor
85
+ */
86
+ public function get_processor() {
87
+
88
+ static $processor;
89
+
90
+ if ( ! isset( $processor ) ) {
91
+ $processor = apply_filters( 'wp_mail_smtp_core_get_processor', new Processor() );
92
+ }
93
+
94
+ return $processor;
95
+ }
96
+
97
+ /**
98
+ * Load the plugin admin area.
99
+ *
100
+ * @since 1.0.0
101
+ *
102
+ * @return Admin\Area
103
+ */
104
+ public function get_admin() {
105
+
106
+ static $admin;
107
+
108
+ if ( ! isset( $admin ) ) {
109
+ $admin = apply_filters( 'wp_mail_smtp_core_get_admin', new Admin\Area() );
110
+ }
111
+
112
+ return $admin;
113
+ }
114
+
115
+ /**
116
+ * Load the plugin providers loader.
117
+ *
118
+ * @since 1.0.0
119
+ *
120
+ * @return Providers\Loader
121
+ */
122
+ public function get_providers() {
123
+
124
+ static $providers;
125
+
126
+ if ( ! isset( $providers ) ) {
127
+ $providers = apply_filters( 'wp_mail_smtp_core_get_providers', new Providers\Loader() );
128
+ }
129
+
130
+ return $providers;
131
+ }
132
+
133
+ /**
134
+ * Load the plugin option migrator.
135
+ *
136
+ * @since 1.0.0
137
+ *
138
+ * @return Migration
139
+ */
140
+ public function get_migration() {
141
+
142
+ static $migration;
143
+
144
+ if ( ! isset( $migration ) ) {
145
+ $migration = apply_filters( 'wp_mail_smtp_core_get_migration', new Migration() );
146
+ }
147
+
148
+ return $migration;
149
+ }
150
+
151
+ /**
152
+ * Load the plugin upgrader.
153
+ *
154
+ * @since 1.1.0
155
+ *
156
+ * @return Upgrade
157
+ */
158
+ public function get_upgrade() {
159
+
160
+ static $upgrade;
161
+
162
+ if ( ! isset( $upgrade ) ) {
163
+ $upgrade = apply_filters( 'wp_mail_smtp_core_get_upgrade', new Upgrade() );
164
+ }
165
+
166
+ return $upgrade;
167
+ }
168
+
169
+ /**
170
+ * Awesome Motive Notifications.
171
+ *
172
+ * @since 1.0.0
173
+ */
174
+ public function init_notifications() {
175
+
176
+ if ( Options::init()->get( 'general', 'am_notifications_hidden' ) ) {
177
+ return;
178
+ }
179
+
180
+ static $notification;
181
+
182
+ if ( ! isset( $notification ) ) {
183
+ $notification = new AM_Notification( 'smtp', WPMS_PLUGIN_VER );
184
+ }
185
+ }
186
+
187
+ /**
188
+ * Init the \PHPMailer replacement.
189
+ *
190
+ * @since 1.0.0
191
+ *
192
+ * @return \WPMailSMTP\MailCatcher
193
+ */
194
+ public function replace_phpmailer() {
195
+ global $phpmailer;
196
+
197
+ return $this->replace_w_fake_phpmailer( $phpmailer );
198
+ }
199
+
200
+ /**
201
+ * Overwrite default PhpMailer with out MailCatcher.
202
+ *
203
+ * @since 1.0.0
204
+ *
205
+ * @param null $obj
206
+ *
207
+ * @return \WPMailSMTP\MailCatcher
208
+ */
209
+ protected function replace_w_fake_phpmailer( &$obj = null ) {
210
+
211
+ $obj = new MailCatcher();
212
+
213
+ return $obj;
214
+ }
215
+
216
+ /**
217
+ * What to do on plugin activation.
218
+ *
219
+ * @since 1.0.0
220
+ */
221
+ public function activate() {
222
+
223
+ // Store the plugin version activated to reference with upgrades.
224
+ update_option( 'wp_mail_smtp_version', WPMS_PLUGIN_VER );
225
+
226
+ // Create and store inital plugin settings.
227
+ $options['mail'] = array(
228
+ 'from_email' => get_option( 'admin_email' ),
229
+ 'from_name' => get_bloginfo( 'name' ),
230
+ 'mailer' => 'mail',
231
+ 'return_path' => false,
232
+ 'smtp' => array(
233
+ 'autotls' => true,
234
+ ),
235
+ );
236
+
237
+ Options::init()->set( $options );
238
+ }
239
+ }
src/MailCatcher.php CHANGED
@@ -1,66 +1,66 @@
1
- <?php
2
-
3
- namespace WPMailSMTP;
4
-
5
- // Load PHPMailer class, so we can subclass it.
6
- if ( ! class_exists( 'PHPMailer', false ) ) {
7
- require_once ABSPATH . WPINC . '/class-phpmailer.php';
8
- }
9
-
10
- /**
11
- * Class MailCatcher replaces the \PHPMailer and modifies the email sending logic.
12
- * Thus, we can use other mailers API to do what we need, or stop emails completely.
13
- *
14
- * @since 1.0.0
15
- */
16
- class MailCatcher extends \PHPMailer {
17
-
18
- /**
19
- * Modify the default send() behaviour.
20
- * For those mailers, that relies on PHPMailer class - call it directly.
21
- * For others - init the correct provider and process it.
22
- *
23
- * @since 1.0.0
24
- *
25
- * @throws \phpmailerException Throws when sending via PhpMailer fails for some reason.
26
- *
27
- * @return bool
28
- */
29
- public function send() {
30
-
31
- $options = new Options();
32
- $mailer = $options->get( 'mail', 'mailer' );
33
-
34
- // Use the default PHPMailer, as we inject our settings there for certain providers.
35
- if (
36
- $mailer === 'mail' ||
37
- $mailer === 'smtp' ||
38
- $mailer === 'pepipost'
39
- ) {
40
- return parent::send();
41
- }
42
-
43
- // Prepare everything (including the message) for sending.
44
- if ( ! $this->preSend() ) {
45
- return false;
46
- }
47
-
48
- $mailer = wp_mail_smtp()->get_providers()->get_mailer( $mailer, $this );
49
-
50
- if ( ! $mailer ) {
51
- return false;
52
- }
53
-
54
- if ( ! $mailer->is_php_compatible() ) {
55
- return false;
56
- }
57
-
58
- /*
59
- * Send the actual email.
60
- * We reuse everything, that was preprocessed for usage in \PHPMailer.
61
- */
62
- $mailer->send();
63
-
64
- return $mailer->is_email_sent();
65
- }
66
- }
1
+ <?php
2
+
3
+ namespace WPMailSMTP;
4
+
5
+ // Load PHPMailer class, so we can subclass it.
6
+ if ( ! class_exists( 'PHPMailer', false ) ) {
7
+ require_once ABSPATH . WPINC . '/class-phpmailer.php';
8
+ }
9
+
10
+ /**
11
+ * Class MailCatcher replaces the \PHPMailer and modifies the email sending logic.
12
+ * Thus, we can use other mailers API to do what we need, or stop emails completely.
13
+ *
14
+ * @since 1.0.0
15
+ */
16
+ class MailCatcher extends \PHPMailer {
17
+
18
+ /**
19
+ * Modify the default send() behaviour.
20
+ * For those mailers, that relies on PHPMailer class - call it directly.
21
+ * For others - init the correct provider and process it.
22
+ *
23
+ * @since 1.0.0
24
+ *
25
+ * @throws \phpmailerException Throws when sending via PhpMailer fails for some reason.
26
+ *
27
+ * @return bool
28
+ */
29
+ public function send() {
30
+
31
+ $options = new Options();
32
+ $mailer = $options->get( 'mail', 'mailer' );
33
+
34
+ // Use the default PHPMailer, as we inject our settings there for certain providers.
35
+ if (
36
+ $mailer === 'mail' ||
37
+ $mailer === 'smtp' ||
38
+ $mailer === 'pepipost'
39
+ ) {
40
+ return parent::send();
41
+ }
42
+
43
+ // Prepare everything (including the message) for sending.
44
+ if ( ! $this->preSend() ) {
45
+ return false;
46
+ }
47
+
48
+ $mailer = wp_mail_smtp()->get_providers()->get_mailer( $mailer, $this );
49
+
50
+ if ( ! $mailer ) {
51
+ return false;
52
+ }
53
+
54
+ if ( ! $mailer->is_php_compatible() ) {
55
+ return false;
56
+ }
57
+
58
+ /*
59
+ * Send the actual email.
60
+ * We reuse everything, that was preprocessed for usage in \PHPMailer.
61
+ */
62
+ $mailer->send();
63
+
64
+ return $mailer->is_email_sent();
65
+ }
66
+ }
src/Migration.php CHANGED
@@ -1,245 +1,245 @@
1
- <?php
2
-
3
- namespace WPMailSMTP;
4
-
5
- /**
6
- * Class Migration helps migrate all plugin options saved into DB to a new storage location.
7
- *
8
- * @since 1.0.0
9
- */
10
- class Migration {
11
-
12
- /**
13
- * All old values for pre 1.0 version of a plugin.
14
- *
15
- * @var array
16
- */
17
- protected $old_keys = array(
18
- 'pepipost_ssl',
19
- 'pepipost_port',
20
- 'pepipost_pass',
21
- 'pepipost_user',
22
- 'smtp_pass',
23
- 'smtp_user',
24
- 'smtp_auth',
25
- 'smtp_ssl',
26
- 'smtp_port',
27
- 'smtp_host',
28
- 'mail_set_return_path',
29
- 'mailer',
30
- 'mail_from_name',
31
- 'mail_from',
32
- 'wp_mail_smtp_am_notifications_hidden',
33
- );
34
-
35
- /**
36
- * Old values, taken from $old_keys options.
37
- *
38
- * @var array
39
- */
40
- protected $old_values = array();
41
-
42
- /**
43
- * Converted array of data from previous option values.
44
- *
45
- * @var array
46
- */
47
- protected $new_values = array();
48
-
49
- /**
50
- * Migration constructor.
51
- *
52
- * @since 1.0.0
53
- */
54
- public function __construct() {
55
-
56
- if ( $this->is_migrated() ) {
57
- return;
58
- }
59
-
60
- $this->old_values = $this->get_old_values();
61
- $this->new_values = $this->get_converted_options();
62
-
63
- Options::init()->set( $this->new_values );
64
-
65
- // Removing all options will be enabled some time in the future.
66
- // $this->clean_deprecated_data();
67
- }
68
-
69
- /**
70
- * Whether we already migrated or not.
71
- *
72
- * @since 1.0.0
73
- *
74
- * @return bool
75
- */
76
- protected function is_migrated() {
77
-
78
- $is_migrated = false;
79
- $new_values = get_option( Options::META_KEY, array() );
80
-
81
- if ( ! empty( $new_values ) ) {
82
- $is_migrated = true;
83
- }
84
-
85
- return $is_migrated;
86
- }
87
-
88
- /**
89
- * Get all old values from DB.
90
- *
91
- * @since 1.0.0
92
- *
93
- * @return array
94
- */
95
- protected function get_old_values() {
96
-
97
- $old_values = array();
98
-
99
- foreach ( $this->old_keys as $old_key ) {
100
- $old_values[ $old_key ] = get_option( $old_key, '' );
101
- }
102
-
103
- return $old_values;
104
- }
105
-
106
- /**
107
- * Convert old values from key=>value to a multidimensional array of data.
108
- *
109
- * @since 1.0.0
110
- */
111
- protected function get_converted_options() {
112
-
113
- $converted = array();
114
-
115
- foreach ( $this->old_keys as $old_key ) {
116
-
117
- switch ( $old_key ) {
118
- case 'pepipost_user':
119
- case 'pepipost_pass':
120
- case 'pepipost_port':
121
- case 'pepipost_ssl':
122
- // Do not migrate pepipost options if it's not activated at the moment.
123
- if ( 'pepipost' === $this->old_values['mailer'] ) {
124
- $shortcut = explode( '_', $old_key );
125
-
126
- if ( $old_key === 'pepipost_ssl' ) {
127
- $converted[ $shortcut[0] ]['encryption'] = $this->old_values[ $old_key ];
128
- } else {
129
- $converted[ $shortcut[0] ][ $shortcut[1] ] = $this->old_values[ $old_key ];
130
- }
131
- }
132
- break;
133
-
134
- case 'smtp_host':
135
- case 'smtp_port':
136
- case 'smtp_ssl':
137
- case 'smtp_auth':
138
- case 'smtp_user':
139
- case 'smtp_pass':
140
- $shortcut = explode( '_', $old_key );
141
-
142
- if ( $old_key === 'smtp_ssl' ) {
143
- $converted[ $shortcut[0] ]['encryption'] = $this->old_values[ $old_key ];
144
- } elseif ( $old_key === 'smtp_auth' ) {
145
- $converted[ $shortcut[0] ][ $shortcut[1] ] = ( $this->old_values[ $old_key ] === 'true' ? 'yes' : 'no' );
146
- } else {
147
- $converted[ $shortcut[0] ][ $shortcut[1] ] = $this->old_values[ $old_key ];
148
- }
149
-
150
- break;
151
-
152
- case 'mail_from':
153
- $converted['mail']['from_email'] = $this->old_values[ $old_key ];
154
- break;
155
- case 'mail_from_name':
156
- $converted['mail']['from_name'] = $this->old_values[ $old_key ];
157
- break;
158
- case 'mail_set_return_path':
159
- $converted['mail']['return_path'] = ( $this->old_values[ $old_key ] === 'true' );
160
- break;
161
- case 'mailer':
162
- $converted['mail']['mailer'] = $this->old_values[ $old_key ];
163
- break;
164
- case 'wp_mail_smtp_am_notifications_hidden':
165
- $converted['general']['am_notifications_hidden'] = ( $this->old_values[ $old_key ] === 'true' );
166
- break;
167
- }
168
- }
169
-
170
- $converted = $this->get_converted_constants_options( $converted );
171
-
172
- return $converted;
173
- }
174
-
175
- /**
176
- * Some users use constants in wp-config.php to define values.
177
- * We need to prioritize them and reapply data to options.
178
- * Use only those that are actually defined.
179
- *
180
- * @since 1.0.0
181
- *
182
- * @param array $converted
183
- *
184
- * @return array
185
- */
186
- protected function get_converted_constants_options( $converted ) {
187
-
188
- // Are we configured via constants?
189
- if ( ! defined( 'WPMS_ON' ) || ! WPMS_ON ) {
190
- return $converted;
191
- }
192
-
193
- /*
194
- * Mail settings.
195
- */
196
- if ( defined( 'WPMS_MAIL_FROM' ) ) {
197
- $converted['mail']['from_email'] = WPMS_MAIL_FROM;
198
- }
199
- if ( defined( 'WPMS_MAIL_FROM_NAME' ) ) {
200
- $converted['mail']['from_name'] = WPMS_MAIL_FROM_NAME;
201
- }
202
- if ( defined( 'WPMS_MAILER' ) ) {
203
- $converted['mail']['return_path'] = WPMS_MAILER;
204
- }
205
- if ( defined( 'WPMS_SET_RETURN_PATH' ) ) {
206
- $converted['mail']['mailer'] = WPMS_SET_RETURN_PATH;
207
- }
208
-
209
- /*
210
- * SMTP settings.
211
- */
212
- if ( defined( 'WPMS_SMTP_HOST' ) ) {
213
- $converted['smtp']['host'] = WPMS_SMTP_HOST;
214
- }
215
- if ( defined( 'WPMS_SMTP_PORT' ) ) {
216
- $converted['smtp']['port'] = WPMS_SMTP_PORT;
217
- }
218
- if ( defined( 'WPMS_SSL' ) ) {
219
- $converted['smtp']['ssl'] = WPMS_SSL;
220
- }
221
- if ( defined( 'WPMS_SMTP_AUTH' ) ) {
222
- $converted['smtp']['auth'] = WPMS_SMTP_AUTH;
223
- }
224
- if ( defined( 'WPMS_SMTP_USER' ) ) {
225
- $converted['smtp']['user'] = WPMS_SMTP_USER;
226
- }
227
- if ( defined( 'WPMS_SMTP_PASS' ) ) {
228
- $converted['smtp']['pass'] = WPMS_SMTP_PASS;
229
- }
230
-
231
- return $converted;
232
- }
233
-
234
- /**
235
- * Delete all old values that are stored separately each.
236
- *
237
- * @since 1.0.0
238
- */
239
- protected function clean_deprecated_data() {
240
-
241
- foreach ( $this->old_keys as $old_key ) {
242
- delete_option( $old_key );
243
- }
244
- }
245
- }
1
+ <?php
2
+
3
+ namespace WPMailSMTP;
4
+
5
+ /**
6
+ * Class Migration helps migrate all plugin options saved into DB to a new storage location.
7
+ *
8
+ * @since 1.0.0
9
+ */
10
+ class Migration {
11
+
12
+ /**
13
+ * All old values for pre 1.0 version of a plugin.
14
+ *
15
+ * @var array
16
+ */
17
+ protected $old_keys = array(
18
+ 'pepipost_ssl',
19
+ 'pepipost_port',
20
+ 'pepipost_pass',
21
+ 'pepipost_user',
22
+ 'smtp_pass',
23
+ 'smtp_user',
24
+ 'smtp_auth',
25
+ 'smtp_ssl',
26
+ 'smtp_port',
27
+ 'smtp_host',
28
+ 'mail_set_return_path',
29
+ 'mailer',
30
+ 'mail_from_name',
31
+ 'mail_from',
32
+ 'wp_mail_smtp_am_notifications_hidden',
33
+ );
34
+
35
+ /**
36
+ * Old values, taken from $old_keys options.
37
+ *
38
+ * @var array
39
+ */
40
+ protected $old_values = array();
41
+
42
+ /**
43
+ * Converted array of data from previous option values.
44
+ *
45
+ * @var array
46
+ */
47
+ protected $new_values = array();
48
+
49
+ /**
50
+ * Migration constructor.
51
+ *
52
+ * @since 1.0.0
53
+ */
54
+ public function __construct() {
55
+
56
+ if ( $this->is_migrated() ) {
57
+ return;
58
+ }
59
+
60
+ $this->old_values = $this->get_old_values();
61
+ $this->new_values = $this->get_converted_options();
62
+
63
+ Options::init()->set( $this->new_values );
64
+
65
+ // Removing all options will be enabled some time in the future.
66
+ // $this->clean_deprecated_data();
67
+ }
68
+
69
+ /**
70
+ * Whether we already migrated or not.
71
+ *
72
+ * @since 1.0.0
73
+ *
74
+ * @return bool
75
+ */
76
+ protected function is_migrated() {
77
+
78
+ $is_migrated = false;
79
+ $new_values = get_option( Options::META_KEY, array() );
80
+
81
+ if ( ! empty( $new_values ) ) {
82
+ $is_migrated = true;
83
+ }
84
+
85
+ return $is_migrated;
86
+ }
87
+
88
+ /**
89
+ * Get all old values from DB.
90
+ *
91
+ * @since 1.0.0
92
+ *
93
+ * @return array
94
+ */
95
+ protected function get_old_values() {
96
+
97
+ $old_values = array();
98
+
99
+ foreach ( $this->old_keys as $old_key ) {
100
+ $old_values[ $old_key ] = get_option( $old_key, '' );
101
+ }
102
+
103
+ return $old_values;
104
+ }
105
+
106
+ /**
107
+ * Convert old values from key=>value to a multidimensional array of data.
108
+ *
109
+ * @since 1.0.0
110
+ */
111
+ protected function get_converted_options() {
112
+
113
+ $converted = array();
114
+
115
+ foreach ( $this->old_keys as $old_key ) {
116
+
117
+ switch ( $old_key ) {
118
+ case 'pepipost_user':
119
+ case 'pepipost_pass':
120
+ case 'pepipost_port':
121
+ case 'pepipost_ssl':
122
+ // Do not migrate pepipost options if it's not activated at the moment.
123
+ if ( 'pepipost' === $this->old_values['mailer'] ) {
124
+ $shortcut = explode( '_', $old_key );
125
+
126
+ if ( $old_key === 'pepipost_ssl' ) {
127
+ $converted[ $shortcut[0] ]['encryption'] = $this->old_values[ $old_key ];
128
+ } else {
129
+ $converted[ $shortcut[0] ][ $shortcut[1] ] = $this->old_values[ $old_key ];
130
+ }
131
+ }
132
+ break;
133
+
134
+ case 'smtp_host':
135
+ case 'smtp_port':
136
+ case 'smtp_ssl':
137
+ case 'smtp_auth':
138
+ case 'smtp_user':
139
+ case 'smtp_pass':
140
+ $shortcut = explode( '_', $old_key );
141
+
142
+ if ( $old_key === 'smtp_ssl' ) {
143
+ $converted[ $shortcut[0] ]['encryption'] = $this->old_values[ $old_key ];
144
+ } elseif ( $old_key === 'smtp_auth' ) {
145
+ $converted[ $shortcut[0] ][ $shortcut[1] ] = ( $this->old_values[ $old_key ] === 'true' ? 'yes' : 'no' );
146
+ } else {
147
+ $converted[ $shortcut[0] ][ $shortcut[1] ] = $this->old_values[ $old_key ];
148
+ }
149
+
150
+ break;
151
+
152
+ case 'mail_from':
153
+ $converted['mail']['from_email'] = $this->old_values[ $old_key ];
154
+ break;
155
+ case 'mail_from_name':
156
+ $converted['mail']['from_name'] = $this->old_values[ $old_key ];
157
+ break;
158
+ case 'mail_set_return_path':
159
+ $converted['mail']['return_path'] = ( $this->old_values[ $old_key ] === 'true' );
160
+ break;
161
+ case 'mailer':
162
+ $converted['mail']['mailer'] = $this->old_values[ $old_key ];
163
+ break;
164
+ case 'wp_mail_smtp_am_notifications_hidden':
165
+ $converted['general']['am_notifications_hidden'] = ( $this->old_values[ $old_key ] === 'true' );
166
+ break;
167
+ }
168
+ }
169
+
170
+ $converted = $this->get_converted_constants_options( $converted );
171
+
172
+ return $converted;
173
+ }
174
+
175
+ /**
176
+ * Some users use constants in wp-config.php to define values.
177
+ * We need to prioritize them and reapply data to options.
178
+ * Use only those that are actually defined.
179
+ *
180
+ * @since 1.0.0
181
+ *
182
+ * @param array $converted
183
+ *
184
+ * @return array
185
+ */
186
+ protected function get_converted_constants_options( $converted ) {
187
+
188
+ // Are we configured via constants?
189
+ if ( ! defined( 'WPMS_ON' ) || ! WPMS_ON ) {
190
+ return $converted;
191
+ }
192
+
193
+ /*
194
+ * Mail settings.
195
+ */
196
+ if ( defined( 'WPMS_MAIL_FROM' ) ) {
197
+ $converted['mail']['from_email'] = WPMS_MAIL_FROM;
198
+ }
199
+ if ( defined( 'WPMS_MAIL_FROM_NAME' ) ) {
200
+ $converted['mail']['from_name'] = WPMS_MAIL_FROM_NAME;
201
+ }
202
+ if ( defined( 'WPMS_MAILER' ) ) {
203
+ $converted['mail']['return_path'] = WPMS_MAILER;
204
+ }
205
+ if ( defined( 'WPMS_SET_RETURN_PATH' ) ) {
206
+ $converted['mail']['mailer'] = WPMS_SET_RETURN_PATH;
207
+ }
208
+
209
+ /*
210
+ * SMTP settings.
211
+ */
212
+ if ( defined( 'WPMS_SMTP_HOST' ) ) {
213
+ $converted['smtp']['host'] = WPMS_SMTP_HOST;
214
+ }
215
+ if ( defined( 'WPMS_SMTP_PORT' ) ) {
216
+ $converted['smtp']['port'] = WPMS_SMTP_PORT;
217
+ }
218
+ if ( defined( 'WPMS_SSL' ) ) {
219
+ $converted['smtp']['ssl'] = WPMS_SSL;
220
+ }
221
+ if ( defined( 'WPMS_SMTP_AUTH' ) ) {
222
+ $converted['smtp']['auth'] = WPMS_SMTP_AUTH;
223
+ }
224
+ if ( defined( 'WPMS_SMTP_USER' ) ) {
225
+ $converted['smtp']['user'] = WPMS_SMTP_USER;
226
+ }
227
+ if ( defined( 'WPMS_SMTP_PASS' ) ) {
228
+ $converted['smtp']['pass'] = WPMS_SMTP_PASS;
229
+ }
230
+
231
+ return $converted;
232
+ }
233
+
234
+ /**
235
+ * Delete all old values that are stored separately each.
236
+ *
237
+ * @since 1.0.0
238
+ */
239
+ protected function clean_deprecated_data() {
240
+
241
+ foreach ( $this->old_keys as $old_key ) {
242
+ delete_option( $old_key );
243
+ }
244
+ }
245
+ }
src/Options.php CHANGED
@@ -1,469 +1,547 @@
1
- <?php
2
-
3
- namespace WPMailSMTP;
4
-
5
- /**
6
- * Class Options to handle all options management.
7
- * WordPress does all the heavy work for caching get_option() data,
8
- * so we don't have to do that. But we want to minimize cyclomatic complexity
9
- * of calling a bunch of WP functions, thus we will cache them in a class as well.
10
- *
11
- * @since 1.0.0
12
- */
13
- class Options {
14
-
15
- /**
16
- * That's where plugin options are saved in wp_options table.
17
- *
18
- * @var string
19
- */
20
- const META_KEY = 'wp_mail_smtp';
21
-
22
- /**
23
- * All the plugin options.
24
- *
25
- * @var array
26
- */
27
- private $_options = array();
28
-
29
- /**
30
- * Init the Options class.
31
- *
32
- * @since 1.0.0
33
- */
34
- public function __construct() {
35
- $this->populate_options();
36
- }
37
-
38
- /**
39
- * Initialize all the options, used for chaining.
40
- *
41
- * One-liner:
42
- * Options::init()->get('smtp', 'host');
43
- * Options::init()->is_pepipost_active();
44
- *
45
- * Or multiple-usage:
46
- * $options = new Options();
47
- * $options->get('smtp', 'host');
48
- *
49
- * @since 1.0.0
50
- *
51
- * @return Options
52
- */
53
- public static function init() {
54
-
55
- static $instance;
56
-
57
- if ( ! $instance ) {
58
- $instance = new self();
59
- }
60
-
61
- return $instance;
62
- }
63
-
64
- /**
65
- * Retrieve all options of the plugin.
66
- *
67
- * @since 1.0.0
68
- */
69
- protected function populate_options() {
70
- $this->_options = get_option( self::META_KEY, array() );
71
- }
72
-
73
- /**
74
- * Get all the options.
75
- *
76
- * Options::init()->get_all();
77
- *
78
- * @since 1.0.0
79
- *
80
- * @return array
81
- */
82
- public function get_all() {
83
- return apply_filters( 'wp_mail_smtp_options_get_all', $this->_options );
84
- }
85
-
86
-
87
- /**
88
- * Get all the options for a group.
89
- *
90
- * Options::init()->get_group('smtp') - will return only array of options (or empty array if no key doesn't exist).
91
- *
92
- * @since 1.0.0
93
- *
94
- * @param string $group
95
- *
96
- * @return mixed
97
- */
98
- public function get_group( $group ) {
99
-
100
- // Just to feel safe.
101
- $group = sanitize_key( $group );
102
-
103
- if ( isset( $this->_options[ $group ] ) ) {
104
- return apply_filters( 'wp_mail_smtp_options_get_group', $this->_options[ $group ], $group );
105
- }
106
-
107
- return array();
108
- }
109
-
110
- /**
111
- * Get options by a group and a key.
112
- *
113
- * Options::init()->get('smtp', 'host') - will return only SMTP 'host' option.
114
- *
115
- * @since 1.0.0
116
- *
117
- * @param string $group
118
- * @param string $key
119
- *
120
- * @return mixed
121
- */
122
- public function get( $group, $key ) {
123
-
124
- // Just to feel safe.
125
- $group = sanitize_key( $group );
126
- $key = sanitize_key( $key );
127
-
128
- // Get the options group.
129
- if ( isset( $this->_options[ $group ] ) ) {
130
-
131
- // Get the options key of a group.
132
- if ( isset( $this->_options[ $group ][ $key ] ) ) {
133
- $value = $this->get_const_value( $group, $key, $this->_options[ $group ][ $key ] );
134
- } else {
135
- $value = $this->postprocess_key_defaults( $group, $key, '' );
136
- }
137
- } else {
138
- $value = $this->postprocess_key_defaults( $group, $key, '' );
139
- }
140
-
141
- return apply_filters( 'wp_mail_smtp_options_get', $value, $group, $key );
142
- }
143
-
144
- /**
145
- * Some options may be non-empty by default,
146
- * so we need to postprocess them to convert.
147
- *
148
- * @since 1.0.0
149
- *
150
- * @param string $group
151
- * @param string $key
152
- * @param mixed $value Default value, it's '' (empty string).
153
- *
154
- * @return mixed
155
- */
156
- protected function postprocess_key_defaults( $group, $key, $value ) {
157
-
158
- switch ( $key ) {
159
- case 'return_path':
160
- $value = $group === 'mail' && empty( $value ) ? false : true;
161
- break;
162
-
163
- case 'encryption':
164
- $value = $group === 'smtp' && empty( $value ) ? 'none' : $value;
165
- break;
166
-
167
- case 'auth':
168
- $value = $group === 'smtp' && empty( $value ) ? false : true;
169
- break;
170
- }
171
-
172
- return $value;
173
- }
174
-
175
- /**
176
- * Process the options values through the constants check.
177
- * If we have defined associated constant - use it instead of a DB value.
178
- * Backward compatibility is hard.
179
- * General section of options won't have constants, so we are omitting those checks and just return default value.
180
- *
181
- * @since 1.0.0
182
- *
183
- * @param string $group
184
- * @param string $key
185
- * @param mixed $value
186
- *
187
- * @return mixed
188
- */
189
- protected function get_const_value( $group, $key, $value ) {
190
-
191
- if ( ! $this->is_const_enabled() ) {
192
- return $value;
193
- }
194
-
195
- switch ( $group ) {
196
- case 'mail':
197
- switch ( $key ) {
198
- case 'from_name':
199
- /** @noinspection PhpUndefinedConstantInspection */
200
- return $this->is_const_defined( $group, $key ) ? WPMS_MAIL_FROM_NAME : $value;
201
- case 'from_email':
202
- /** @noinspection PhpUndefinedConstantInspection */
203
- return $this->is_const_defined( $group, $key ) ? WPMS_MAIL_FROM : $value;
204
- case 'mailer':
205
- /** @noinspection PhpUndefinedConstantInspection */
206
- return $this->is_const_defined( $group, $key ) ? WPMS_MAILER : $value;
207
- case 'return_path':
208
- return $this->is_const_defined( $group, $key ) ? true : $value;
209
- }
210
-
211
- break;
212
-
213
- case 'smtp':
214
- switch ( $key ) {
215
- case 'host':
216
- /** @noinspection PhpUndefinedConstantInspection */
217
- return $this->is_const_defined( $group, $key ) ? WPMS_SMTP_HOST : $value;
218
- case 'port':
219
- /** @noinspection PhpUndefinedConstantInspection */
220
- return $this->is_const_defined( $group, $key ) ? WPMS_SMTP_PORT : $value;
221
- case 'encryption':
222
- /** @noinspection PhpUndefinedConstantInspection */
223
- return $this->is_const_defined( $group, $key )
224
- ? ( WPMS_SSL === '' ? 'none' : WPMS_SSL )
225
- : $value;
226
- case 'auth':
227
- /** @noinspection PhpUndefinedConstantInspection */
228
- return $this->is_const_defined( $group, $key ) ? WPMS_SMTP_AUTH : $value;
229
- case 'user':
230
- /** @noinspection PhpUndefinedConstantInspection */
231
- return $this->is_const_defined( $group, $key ) ? WPMS_SMTP_USER : $value;
232
- case 'pass':
233
- /** @noinspection PhpUndefinedConstantInspection */
234
- return $this->is_const_defined( $group, $key ) ? WPMS_SMTP_PASS : $value;
235
- }
236
-
237
- break;
238
-
239
- case 'gmail':
240
- switch ( $key ) {
241
- case 'client_id':
242
- /** @noinspection PhpUndefinedConstantInspection */
243
- return $this->is_const_defined( $group, $key ) ? WPMS_GMAIL_CLIENT_ID : $value;
244
- case 'client_secret':
245
- /** @noinspection PhpUndefinedConstantInspection */
246
- return $this->is_const_defined( $group, $key ) ? WPMS_GMAIL_CLIENT_SECRET : $value;
247
- }
248
-
249
- break;
250
-
251
- case 'mailgun':
252
- switch ( $key ) {
253
- case 'api_key':
254
- /** @noinspection PhpUndefinedConstantInspection */
255
- return $this->is_const_defined( $group, $key ) ? WPMS_MAILGUN_API_KEY : $value;
256
- case 'domain':
257
- /** @noinspection PhpUndefinedConstantInspection */
258
- return $this->is_const_defined( $group, $key ) ? WPMS_MAILGUN_DOMAIN : $value;
259
- }
260
-
261
- break;
262
-
263
- case 'sendgrid':
264
- switch ( $key ) {
265
- case 'api_key':
266
- /** @noinspection PhpUndefinedConstantInspection */
267
- return $this->is_const_defined( $group, $key ) ? WPMS_SENDGRID_API_KEY : $value;
268
- }
269
-
270
- break;
271
- }
272
-
273
- // Always return the default value if nothing from above matches the request.
274
- return $value;
275
- }
276
-
277
- /**
278
- * Whether constants redefinition is enabled or not.
279
- *
280
- * @since 1.0.0
281
- *
282
- * @return bool
283
- */
284
- public function is_const_enabled() {
285
- return defined( 'WPMS_ON' ) && WPMS_ON === true;
286
- }
287
-
288
- /**
289
- * We need this check to reuse later in admin area,
290
- * to distinguish settings fields that were redefined,
291
- * and display them differently.
292
- *
293
- * @since 1.0.0
294
- *
295
- * @param string $group
296
- * @param string $key
297
- *
298
- * @return bool
299
- */
300
- public function is_const_defined( $group, $key ) {
301
-
302
- if ( ! $this->is_const_enabled() ) {
303
- return false;
304
- }
305
-
306
- // Just to feel safe.
307
- $group = sanitize_key( $group );
308
- $key = sanitize_key( $key );
309
-
310
- switch ( $group ) {
311
- case 'mail':
312
- switch ( $key ) {
313
- case 'from_name':
314
- return defined( 'WPMS_MAIL_FROM_NAME' ) && WPMS_MAIL_FROM_NAME;
315
- case 'from_email':
316
- return defined( 'WPMS_MAIL_FROM' ) && WPMS_MAIL_FROM;
317
- case 'mailer':
318
- return defined( 'WPMS_MAILER' ) && WPMS_MAILER;
319
- case 'return_path':
320
- return defined( 'WPMS_SET_RETURN_PATH' ) && ( WPMS_SET_RETURN_PATH === 'true' || WPMS_SET_RETURN_PATH === true );
321
- }
322
-
323
- break;
324
-
325
- case 'smtp':
326
- switch ( $key ) {
327
- case 'host':
328
- return defined( 'WPMS_SMTP_HOST' ) && WPMS_SMTP_HOST;
329
- case 'port':
330
- return defined( 'WPMS_SMTP_PORT' ) && WPMS_SMTP_PORT;
331
- case 'encryption':
332
- return defined( 'WPMS_SSL' );
333
- case 'auth':
334
- return defined( 'WPMS_SMTP_AUTH' ) && WPMS_SMTP_AUTH;
335
- case 'user':
336
- return defined( 'WPMS_SMTP_USER' ) && WPMS_SMTP_USER;
337
- case 'pass':
338
- return defined( 'WPMS_SMTP_PASS' ) && WPMS_SMTP_PASS;
339
- }
340
-
341
- break;
342
-
343
- case 'gmail':
344
- switch ( $key ) {
345
- case 'client_id':
346
- return defined( 'WPMS_GMAIL_CLIENT_ID' ) && WPMS_GMAIL_CLIENT_ID;
347
- case 'client_secret':
348
- return defined( 'WPMS_GMAIL_CLIENT_SECRET' ) && WPMS_GMAIL_CLIENT_SECRET;
349
- }
350
-
351
- break;
352
-
353
- case 'mailgun':
354
- switch ( $key ) {
355
- case 'api_key':
356
- return defined( 'WPMS_MAILGUN_API_KEY' ) && WPMS_MAILGUN_API_KEY;
357
- case 'domain':
358
- return defined( 'WPMS_MAILGUN_DOMAIN' ) && WPMS_MAILGUN_DOMAIN;
359
- }
360
-
361
- break;
362
-
363
- case 'sendgrid':
364
- switch ( $key ) {
365
- case 'api_key':
366
- return defined( 'WPMS_SENDGRID_API_KEY' ) && WPMS_SENDGRID_API_KEY;
367
- }
368
-
369
- break;
370
- }
371
-
372
- return false;
373
- }
374
-
375
- /**
376
- * Set plugin options, all at once.
377
- *
378
- * @since 1.0.0
379
- *
380
- * @param array $options Data to save.
381
- */
382
- public function set( $options ) {
383
-
384
- foreach ( (array) $options as $group => $keys ) {
385
- foreach ( $keys as $key_name => $key_value ) {
386
- switch ( $group ) {
387
- case 'mail':
388
- switch ( $key_name ) {
389
- case 'from_name':
390
- case 'mailer':
391
- $options[ $group ][ $key_name ] = $this->get_const_value( $group, $key_name, sanitize_text_field( $options[ $group ][ $key_name ] ) );
392
- break;
393
- case 'from_email':
394
- if ( filter_var( $options[ $group ][ $key_name ], FILTER_VALIDATE_EMAIL ) ) {
395
- $options[ $group ][ $key_name ] = $this->get_const_value( $group, $key_name, sanitize_email( $options[ $group ][ $key_name ] ) );
396
- }
397
- break;
398
- case 'return_path':
399
- $options[ $group ][ $key_name ] = $this->get_const_value( $group, $key_name, (bool) $options[ $group ][ $key_name ] );
400
- break;
401
- }
402
- break;
403
-
404
- case 'general':
405
- switch ( $key_name ) {
406
- case 'am_notifications_hidden':
407
- $options[ $group ][ $key_name ] = (bool) $options[ $group ][ $key_name ];
408
- break;
409
- }
410
- }
411
- }
412
- }
413
-
414
- if (
415
- isset( $options[ $options['mail']['mailer'] ] ) &&
416
- in_array( $options['mail']['mailer'], array( 'pepipost', 'smtp', 'sendgrid', 'mailgun', 'gmail' ), true )
417
- ) {
418
-
419
- $mailer = $options['mail']['mailer'];
420
-
421
- foreach ( $options[ $mailer ] as $key_name => $key_value ) {
422
- switch ( $key_name ) {
423
- case 'host':
424
- case 'user':
425
- case 'pass':
426
- case 'api_key':
427
- case 'domain':
428
- case 'client_id':
429
- case 'client_secret':
430
- $options[ $mailer ][ $key_name ] = $this->get_const_value( $mailer, $key_name, sanitize_text_field( $options[ $mailer ][ $key_name ] ) );
431
- break;
432
- case 'port':
433
- $options[ $mailer ][ $key_name ] = $this->get_const_value( $mailer, $key_name, intval( $options[ $mailer ][ $key_name ] ) );
434
- break;
435
- case 'encryption':
436
- $options[ $mailer ][ $key_name ] = $this->get_const_value( $mailer, $key_name, sanitize_text_field( $options[ $mailer ][ $key_name ] ) );
437
- break;
438
- case 'auth':
439
- $value = $options[ $mailer ][ $key_name ] === 'yes' || $options[ $mailer ][ $key_name ] === true ? true : false;
440
-
441
- $options[ $mailer ][ $key_name ] = $this->get_const_value( $mailer, $key_name, $value );
442
- break;
443
-
444
- case 'auth_code':
445
- case 'access_token':
446
- // Do nothing for them.
447
- }
448
- }
449
- }
450
-
451
- $options = apply_filters( 'wp_mail_smtp_options_set', $options );
452
-
453
- update_option( self::META_KEY, $options );
454
-
455
- // Now we need to re-cache values.
456
- $this->populate_options();
457
- }
458
-
459
- /**
460
- * Check whether the site is using Pepipost or not.
461
- *
462
- * @since 1.0.0
463
- *
464
- * @return bool
465
- */
466
- public function is_pepipost_active() {
467
- return apply_filters( 'wp_mail_smtp_options_is_pepipost_active', 'pepipost' === $this->get( 'mail', 'mailer' ) );
468
- }
469
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WPMailSMTP;
4
+
5
+ /**
6
+ * Class Options to handle all options management.
7
+ * WordPress does all the heavy work for caching get_option() data,
8
+ * so we don't have to do that. But we want to minimize cyclomatic complexity
9
+ * of calling a bunch of WP functions, thus we will cache them in a class as well.
10
+ *
11
+ * @since 1.0.0
12
+ */
13
+ class Options {
14
+
15
+ /**
16
+ * @var array Map of all the default options of the plugin.
17
+ */
18
+ private static $map = array(
19
+ 'mail' => array(
20
+ 'from_name',
21
+ 'from_email',
22
+ 'mailer',
23
+ 'return_path',
24
+ ),
25
+ 'smtp' => array(
26
+ 'host',
27
+ 'port',
28
+ 'encryption',
29
+ 'autotls',
30
+ 'auth',
31
+ 'user',
32
+ 'pass',
33
+ ),
34
+ 'gmail' => array(
35
+ 'client_id',
36
+ 'client_secret',
37
+ ),
38
+ 'mailgun' => array(
39
+ 'api_key',
40
+ 'domain',
41
+ ),
42
+ 'sendgrid' => array(
43
+ 'api_key',
44
+ ),
45
+ 'pepipost' => array(
46
+ 'host',
47
+ 'port',
48
+ 'encryption',
49
+ 'auth',
50
+ 'user',
51
+ 'pass',
52
+ ),
53
+ );
54
+
55
+ /**
56
+ * That's where plugin options are saved in wp_options table.
57
+ *
58
+ * @var string
59
+ */
60
+ const META_KEY = 'wp_mail_smtp';
61
+
62
+ /**
63
+ * All the plugin options.
64
+ *
65
+ * @var array
66
+ */
67
+ private $_options = array();
68
+
69
+ /**
70
+ * Init the Options class.
71
+ *
72
+ * @since 1.0.0
73
+ */
74
+ public function __construct() {
75
+ $this->populate_options();
76
+ }
77
+
78
+ /**
79
+ * Initialize all the options, used for chaining.
80
+ *
81
+ * One-liner:
82
+ * Options::init()->get('smtp', 'host');
83
+ * Options::init()->is_pepipost_active();
84
+ *
85
+ * Or multiple-usage:
86
+ * $options = new Options();
87
+ * $options->get('smtp', 'host');
88
+ *
89
+ * @since 1.0.0
90
+ *
91
+ * @return Options
92
+ */
93
+ public static function init() {
94
+
95
+ static $instance;
96
+
97
+ if ( ! $instance ) {
98
+ $instance = new self();
99
+ }
100
+
101
+ return $instance;
102
+ }
103
+
104
+ /**
105
+ * Retrieve all options of the plugin.
106
+ *
107
+ * @since 1.0.0
108
+ */
109
+ protected function populate_options() {
110
+ $this->_options = get_option( self::META_KEY, array() );
111
+ }
112
+
113
+ /**
114
+ * Get all the options.
115
+ *
116
+ * Options::init()->get_all();
117
+ *
118
+ * @since 1.0.0
119
+ *
120
+ * @return array
121
+ */
122
+ public function get_all() {
123
+
124
+ $options = $this->_options;
125
+
126
+ foreach ( $options as $group => $g_value ) {
127
+ foreach ( $g_value as $key => $value ) {
128
+ $options[ $group ][ $key ] = $this->get( $group, $key );
129
+ }
130
+ }
131
+
132
+ return apply_filters( 'wp_mail_smtp_options_get_all', $options );
133
+ }
134
+
135
+ /**
136
+ * Get all the options for a group.
137
+ *
138
+ * Options::init()->get_group('smtp') - will return only array of options (or empty array if a key doesn't exist).
139
+ *
140
+ * @since 1.0.0
141
+ *
142
+ * @param string $group
143
+ *
144
+ * @return mixed
145
+ */
146
+ public function get_group( $group ) {
147
+
148
+ // Just to feel safe.
149
+ $group = sanitize_key( $group );
150
+
151
+ if ( isset( $this->_options[ $group ] ) ) {
152
+
153
+ foreach ( $this->_options[ $group ] as $g_key => $g_value ) {
154
+ $options[ $group ][ $g_key ] = $this->get( $group, $g_key );
155
+ }
156
+
157
+ return apply_filters( 'wp_mail_smtp_options_get_group', $this->_options[ $group ], $group );
158
+ }
159
+
160
+ return array();
161
+ }
162
+
163
+ /**
164
+ * Get options by a group and a key.
165
+ *
166
+ * Options::init()->get( 'smtp', 'host' ) - will return only SMTP 'host' option.
167
+ *
168
+ * @since 1.0.0
169
+ *
170
+ * @param string $group
171
+ * @param string $key
172
+ *
173
+ * @return mixed
174
+ */
175
+ public function get( $group, $key ) {
176
+
177
+ // Just to feel safe.
178
+ $group = sanitize_key( $group );
179
+ $key = sanitize_key( $key );
180
+
181
+ // Get the options group.
182
+ if ( isset( $this->_options[ $group ] ) ) {
183
+
184
+ // Get the options key of a group.
185
+ if ( isset( $this->_options[ $group ][ $key ] ) ) {
186
+ $value = $this->get_const_value( $group, $key, $this->_options[ $group ][ $key ] );
187
+ } else {
188
+ $value = $this->postprocess_key_defaults( $group, $key );
189
+ }
190
+ } else {
191
+ $value = $this->postprocess_key_defaults( $group, $key );
192
+ }
193
+
194
+ return apply_filters( 'wp_mail_smtp_options_get', $value, $group, $key );
195
+ }
196
+
197
+ /**
198
+ * Some options may be non-empty by default,
199
+ * so we need to postprocess them to convert.
200
+ *
201
+ * @since 1.0.0
202
+ *
203
+ * @param string $group
204
+ * @param string $key
205
+ *
206
+ * @return mixed
207
+ */
208
+ protected function postprocess_key_defaults( $group, $key ) {
209
+
210
+ $value = '';
211
+
212
+ switch ( $key ) {
213
+ case 'return_path':
214
+ $value = $group === 'mail' ? false : true;
215
+ break;
216
+
217
+ case 'encryption':
218
+ $value = in_array( $group, array( 'smtp', 'pepipost' ), true ) ? 'none' : $value;
219
+ break;
220
+
221
+ case 'auth':
222
+ case 'autotls':
223
+ $value = in_array( $group, array( 'smtp', 'pepipost' ), true ) ? false : true;
224
+ break;
225
+
226
+ case 'pass':
227
+ $value = $this->get_const_value( $group, $key, $value );
228
+ break;
229
+ }
230
+
231
+ return apply_filters( 'wp_mail_smtp_options_postprocess_key_defaults', $value, $group, $key );
232
+ }
233
+
234
+ /**
235
+ * Process the options values through the constants check.
236
+ * If we have defined associated constant - use it instead of a DB value.
237
+ * Backward compatibility is hard.
238
+ * General section of options won't have constants, so we are omitting those checks and just return default value.
239
+ *
240
+ * @since 1.0.0
241
+ *
242
+ * @param string $group
243
+ * @param string $key
244
+ * @param mixed $value
245
+ *
246
+ * @return mixed
247
+ */
248
+ protected function get_const_value( $group, $key, $value ) {
249
+
250
+ if ( ! $this->is_const_enabled() ) {
251
+ return $value;
252
+ }
253
+
254
+ switch ( $group ) {
255
+ case 'mail':
256
+ switch ( $key ) {
257
+ case 'from_name':
258
+ /** @noinspection PhpUndefinedConstantInspection */
259
+ return $this->is_const_defined( $group, $key ) ? WPMS_MAIL_FROM_NAME : $value;
260
+ case 'from_email':
261
+ /** @noinspection PhpUndefinedConstantInspection */
262
+ return $this->is_const_defined( $group, $key ) ? WPMS_MAIL_FROM : $value;
263
+ case 'mailer':
264
+ /** @noinspection PhpUndefinedConstantInspection */
265
+ return $this->is_const_defined( $group, $key ) ? WPMS_MAILER : $value;
266
+ case 'return_path':
267
+ return $this->is_const_defined( $group, $key ) ? true : $value;
268
+ }
269
+
270
+ break;
271
+
272
+ case 'smtp':
273
+ switch ( $key ) {
274
+ case 'host':
275
+ /** @noinspection PhpUndefinedConstantInspection */
276
+ return $this->is_const_defined( $group, $key ) ? WPMS_SMTP_HOST : $value;
277
+ case 'port':
278
+ /** @noinspection PhpUndefinedConstantInspection */
279
+ return $this->is_const_defined( $group, $key ) ? WPMS_SMTP_PORT : $value;
280
+ case 'encryption':
281
+ /** @noinspection PhpUndefinedConstantInspection */
282
+ return $this->is_const_defined( $group, $key )
283
+ ? ( WPMS_SSL === '' ? 'none' : WPMS_SSL )
284
+ : $value;
285
+ case 'auth':
286
+ /** @noinspection PhpUndefinedConstantInspection */
287
+ return $this->is_const_defined( $group, $key ) ? WPMS_SMTP_AUTH : $value;
288
+ case 'autotls':
289
+ /** @noinspection PhpUndefinedConstantInspection */
290
+ return $this->is_const_defined( $group, $key ) ? WPMS_SMTP_AUTOTLS : $value;
291
+ case 'user':
292
+ /** @noinspection PhpUndefinedConstantInspection */
293
+ return $this->is_const_defined( $group, $key ) ? WPMS_SMTP_USER : $value;
294
+ case 'pass':
295
+ /** @noinspection PhpUndefinedConstantInspection */
296
+ return $this->is_const_defined( $group, $key ) ? WPMS_SMTP_PASS : $value;
297
+ }
298
+
299
+ break;
300
+
301
+ case 'gmail':
302
+ switch ( $key ) {
303
+ case 'client_id':
304
+ /** @noinspection PhpUndefinedConstantInspection */
305
+ return $this->is_const_defined( $group, $key ) ? WPMS_GMAIL_CLIENT_ID : $value;
306
+ case 'client_secret':
307
+ /** @noinspection PhpUndefinedConstantInspection */
308
+ return $this->is_const_defined( $group, $key ) ? WPMS_GMAIL_CLIENT_SECRET : $value;
309
+ }
310
+
311
+ break;
312
+
313
+ case 'mailgun':
314
+ switch ( $key ) {
315
+ case 'api_key':
316
+ /** @noinspection PhpUndefinedConstantInspection */
317
+ return $this->is_const_defined( $group, $key ) ? WPMS_MAILGUN_API_KEY : $value;
318
+ case 'domain':
319
+ /** @noinspection PhpUndefinedConstantInspection */
320
+ return $this->is_const_defined( $group, $key ) ? WPMS_MAILGUN_DOMAIN : $value;
321
+ }
322
+
323
+ break;
324
+
325
+ case 'sendgrid':
326
+ switch ( $key ) {
327
+ case 'api_key':
328
+ /** @noinspection PhpUndefinedConstantInspection */
329
+ return $this->is_const_defined( $group, $key ) ? WPMS_SENDGRID_API_KEY : $value;
330
+ }
331
+
332
+ break;
333
+ }
334
+
335
+ // Always return the default value if nothing from above matches the request.
336
+ return $value;
337
+ }
338
+
339
+ /**
340
+ * Whether constants redefinition is enabled or not.
341
+ *
342
+ * @since 1.0.0
343
+ *
344
+ * @return bool
345
+ */
346
+ public function is_const_enabled() {
347
+ return defined( 'WPMS_ON' ) && WPMS_ON === true;
348
+ }
349
+
350
+ /**
351
+ * We need this check to reuse later in admin area,
352
+ * to distinguish settings fields that were redefined,
353
+ * and display them differently.
354
+ *
355
+ * @since 1.0.0
356
+ *
357
+ * @param string $group
358
+ * @param string $key
359
+ *
360
+ * @return bool
361
+ */
362
+ public function is_const_defined( $group, $key ) {
363
+
364
+ if ( ! $this->is_const_enabled() ) {
365
+ return false;
366
+ }
367
+
368
+ // Just to feel safe.
369
+ $group = sanitize_key( $group );
370
+ $key = sanitize_key( $key );
371
+
372
+ switch ( $group ) {
373
+ case 'mail':
374
+ switch ( $key ) {
375
+ case 'from_name':
376
+ return defined( 'WPMS_MAIL_FROM_NAME' ) && WPMS_MAIL_FROM_NAME;
377
+ case 'from_email':
378
+ return defined( 'WPMS_MAIL_FROM' ) && WPMS_MAIL_FROM;
379
+ case 'mailer':
380
+ return defined( 'WPMS_MAILER' ) && WPMS_MAILER;
381
+ case 'return_path':
382
+ return defined( 'WPMS_SET_RETURN_PATH' ) && ( WPMS_SET_RETURN_PATH === 'true' || WPMS_SET_RETURN_PATH === true );
383
+ }
384
+
385
+ break;
386
+
387
+ case 'smtp':
388
+ switch ( $key ) {
389
+ case 'host':
390
+ return defined( 'WPMS_SMTP_HOST' ) && WPMS_SMTP_HOST;
391
+ case 'port':
392
+ return defined( 'WPMS_SMTP_PORT' ) && WPMS_SMTP_PORT;
393
+ case 'encryption':
394
+ return defined( 'WPMS_SSL' );
395
+ case 'auth':
396
+ return defined( 'WPMS_SMTP_AUTH' ) && WPMS_SMTP_AUTH;
397
+ case 'autotls':
398
+ return defined( 'WPMS_SMTP_AUTOTLS' ) && WPMS_SMTP_AUTOTLS;
399
+ case 'user':
400
+ return defined( 'WPMS_SMTP_USER' ) && WPMS_SMTP_USER;
401
+ case 'pass':
402
+ return defined( 'WPMS_SMTP_PASS' ) && WPMS_SMTP_PASS;
403
+ }
404
+
405
+ break;
406
+
407
+ case 'gmail':
408
+ switch ( $key ) {
409
+ case 'client_id':
410
+ return defined( 'WPMS_GMAIL_CLIENT_ID' ) && WPMS_GMAIL_CLIENT_ID;
411
+ case 'client_secret':
412
+ return defined( 'WPMS_GMAIL_CLIENT_SECRET' ) && WPMS_GMAIL_CLIENT_SECRET;
413
+ }
414
+
415
+ break;
416
+
417
+ case 'mailgun':
418
+ switch ( $key ) {
419
+ case 'api_key':
420
+ return defined( 'WPMS_MAILGUN_API_KEY' ) && WPMS_MAILGUN_API_KEY;
421
+ case 'domain':
422
+ return defined( 'WPMS_MAILGUN_DOMAIN' ) && WPMS_MAILGUN_DOMAIN;
423
+ }
424
+
425
+ break;
426
+
427
+ case 'sendgrid':
428
+ switch ( $key ) {
429
+ case 'api_key':
430
+ return defined( 'WPMS_SENDGRID_API_KEY' ) && WPMS_SENDGRID_API_KEY;
431
+ }
432
+
433
+ break;
434
+ }
435
+
436
+ return false;
437
+ }
438
+
439
+ /**
440
+ * Set plugin options, all at once.
441
+ *
442
+ * @since 1.0.0
443
+ *
444
+ * @param array $options Data to save.
445
+ */
446
+ public function set( $options ) {
447
+
448
+ foreach ( (array) $options as $group => $keys ) {
449
+ foreach ( $keys as $key_name => $key_value ) {
450
+ switch ( $group ) {
451
+ case 'mail':
452
+ switch ( $key_name ) {
453
+ case 'from_name':
454
+ case 'mailer':
455
+ $options[ $group ][ $key_name ] = $this->get_const_value( $group, $key_name, sanitize_text_field( $options[ $group ][ $key_name ] ) );
456
+ break;
457
+ case 'from_email':
458
+ if ( filter_var( $options[ $group ][ $key_name ], FILTER_VALIDATE_EMAIL ) ) {
459
+ $options[ $group ][ $key_name ] = $this->get_const_value( $group, $key_name, sanitize_email( $options[ $group ][ $key_name ] ) );
460
+ }
461
+ break;
462
+ case 'return_path':
463
+ $options[ $group ][ $key_name ] = $this->get_const_value( $group, $key_name, (bool) $options[ $group ][ $key_name ] );
464
+ break;
465
+ }
466
+ break;
467
+
468
+ case 'general':
469
+ switch ( $key_name ) {
470
+ case 'am_notifications_hidden':
471
+ $options[ $group ][ $key_name ] = (bool) $options[ $group ][ $key_name ];
472
+ break;
473
+ }
474
+ }
475
+ }
476
+ }
477
+
478
+ if (
479
+ isset( $options[ $options['mail']['mailer'] ] ) &&
480
+ in_array( $options['mail']['mailer'], array( 'pepipost', 'smtp', 'sendgrid', 'mailgun', 'gmail' ), true )
481
+ ) {
482
+
483
+ $mailer = $options['mail']['mailer'];
484
+
485
+ foreach ( $options[ $mailer ] as $key_name => $key_value ) {
486
+ switch ( $key_name ) {
487
+ case 'host':
488
+ case 'user':
489
+ $options[ $mailer ][ $key_name ] = $this->get_const_value( $mailer, $key_name, sanitize_text_field( $options[ $mailer ][ $key_name ] ) );
490
+ break;
491
+ case 'port':
492
+ $options[ $mailer ][ $key_name ] = $this->get_const_value( $mailer, $key_name, intval( $options[ $mailer ][ $key_name ] ) );
493
+ break;
494
+ case 'encryption':
495
+ $options[ $mailer ][ $key_name ] = $this->get_const_value( $mailer, $key_name, sanitize_text_field( $options[ $mailer ][ $key_name ] ) );
496
+ break;
497
+ case 'auth':
498
+ case 'autotls':
499
+ $value = $options[ $mailer ][ $key_name ] === 'yes' || $options[ $mailer ][ $key_name ] === true ? true : false;
500
+
501
+ $options[ $mailer ][ $key_name ] = $this->get_const_value( $mailer, $key_name, $value );
502
+ break;
503
+
504
+ case 'pass':
505
+ case 'api_key':
506
+ case 'domain':
507
+ case 'client_id':
508
+ case 'client_secret':
509
+ case 'auth_code':
510
+ case 'access_token':
511
+ // Do not process as they may contain certain special characters, but allow to be overwritten using constants.
512
+ $options[ $mailer ][ $key_name ] = $this->get_const_value( $mailer, $key_name, $options[ $mailer ][ $key_name ] );
513
+ break;
514
+ }
515
+ }
516
+ }
517
+
518
+ $options = apply_filters( 'wp_mail_smtp_options_set', $options );
519
+
520
+ update_option( self::META_KEY, $options );
521
+
522
+ // Now we need to re-cache values.
523
+ $this->populate_options();
524
+ }
525
+
526
+ /**
527
+ * Check whether the site is using Pepipost or not.
528
+ *
529
+ * @since 1.0.0
530
+ *
531
+ * @return bool
532
+ */
533
+ public function is_pepipost_active() {
534
+ return apply_filters( 'wp_mail_smtp_options_is_pepipost_active', $this->get( 'mail', 'mailer' ) === 'pepipost' );
535
+ }
536
+
537
+ /**
538
+ * Check whether the site is using Pepipost/SMTP as a mailer or not.
539
+ *
540
+ * @since 1.1.0
541
+ *
542
+ * @return bool
543
+ */
544
+ public function is_mailer_smtp() {
545
+ return apply_filters( 'wp_mail_smtp_options_is_mailer_smtp', in_array( $this->get( 'mail', 'mailer' ), array( 'pepipost', 'smtp' ), true ) );
546
+ }
547
+ }
src/Processor.php CHANGED
@@ -1,170 +1,175 @@
1
- <?php
2
-
3
- namespace WPMailSMTP;
4
-
5
- /**
6
- * Class Processor modifies the behaviour of wp_mail() function.
7
- *
8
- * @since 1.0.0
9
- */
10
- class Processor {
11
-
12
- /**
13
- * Processor constructor.
14
- *
15
- * @since 1.0.0
16
- */
17
- public function __construct() {
18
- $this->hooks();
19
- }
20
-
21
- /**
22
- * Assign all hooks to proper places.
23
- *
24
- * @since 1.0.0
25
- */
26
- public function hooks() {
27
-
28
- add_action( 'phpmailer_init', array( $this, 'phpmailer_init' ) );
29
-
30
- add_filter( 'wp_mail_from', array( $this, 'filter_mail_from_email' ) );
31
- add_filter( 'wp_mail_from_name', array( $this, 'filter_mail_from_name' ), 11 );
32
- }
33
-
34
- /**
35
- * Redefine certain PHPMailer options with our custom ones.
36
- *
37
- * @since 1.0.0
38
- *
39
- * @param \PHPMailer $phpmailer It's passed by reference, so no need to return anything.
40
- */
41
- public function phpmailer_init( $phpmailer ) {
42
-
43
- $options = Options::init()->get_all();
44
- $mailer = $options['mail']['mailer'];
45
-
46
- // Check that mailer is not blank, and if mailer=smtp, host is not blank.
47
- if (
48
- ! $mailer ||
49
- ( 'smtp' === $mailer && ! $options['smtp']['host'] )
50
- ) {
51
- return;
52
- }
53
-
54
- // If the mailer is pepipost, make sure we have a username and password.
55
- if (
56
- 'pepipost' === $mailer &&
57
- ( ! $options['pepipost']['user'] && ! $options['pepipost']['pass'] )
58
- ) {
59
- return;
60
- }
61
-
62
- // Set the mailer type as per config above, this overrides the already called isMail method.
63
- // It's basically always 'smtp'.
64
- $phpmailer->Mailer = $mailer;
65
-
66
- // Set the Sender (return-path) if required.
67
- if ( isset( $options['mail']['return_path'] ) && $options['mail']['return_path'] ) {
68
- $phpmailer->Sender = $phpmailer->From;
69
- }
70
-
71
- // Set the SMTPSecure value, if set to none, leave this blank.
72
- $phpmailer->SMTPSecure = $options[ $mailer ]['encryption'];
73
- if ( isset( $options[ $mailer ]['encryption'] ) && 'none' === $options[ $mailer ]['encryption'] ) {
74
- $phpmailer->SMTPSecure = '';
75
- $phpmailer->SMTPAutoTLS = false;
76
- }
77
-
78
- // If we're sending via SMTP, set the host.
79
- if ( 'smtp' === $mailer ) {
80
- // Set the other options.
81
- $phpmailer->Host = $options[ $mailer ]['host'];
82
- $phpmailer->Port = $options[ $mailer ]['port'];
83
-
84
- // If we're using smtp auth, set the username & password.
85
- if ( $options[ $mailer ]['auth'] ) {
86
- $phpmailer->SMTPAuth = true;
87
- $phpmailer->Username = $options[ $mailer ]['user'];
88
- $phpmailer->Password = $options[ $mailer ]['pass'];
89
- }
90
- } elseif ( 'pepipost' === $mailer ) {
91
- // Set the Pepipost settings for BC.
92
- $phpmailer->Mailer = 'smtp';
93
- $phpmailer->Host = 'smtp.pepipost.com';
94
- $phpmailer->Port = $options[ $mailer ]['port'];
95
- $phpmailer->SMTPSecure = $options[ $mailer ]['encryption'] === 'none' ? '' : $options[ $mailer ]['encryption'];
96
- $phpmailer->SMTPAuth = true;
97
- $phpmailer->Username = $options[ $mailer ]['user'];
98
- $phpmailer->Password = $options[ $mailer ]['pass'];
99
- }
100
-
101
- // You can add your own options here.
102
- // See the phpmailer documentation for more info: https://github.com/PHPMailer/PHPMailer/tree/5.2-stable.
103
- /** @noinspection PhpUnusedLocalVariableInspection It's passed by reference. */
104
- $phpmailer = apply_filters( 'wp_mail_smtp_custom_options', $phpmailer );
105
- }
106
-
107
- /**
108
- * Modify the email address that is used for sending emails.
109
- *
110
- * @since 1.0.0
111
- *
112
- * @param string $email
113
- *
114
- * @return string
115
- */
116
- public function filter_mail_from_email( $email ) {
117
-
118
- // If the from email is not the default, return it unchanged.
119
- if ( $email !== $this->get_default_email() ) {
120
- return $email;
121
- }
122
-
123
- $from_email = Options::init()->get( 'mail', 'from_email' );
124
-
125
- if ( ! empty( $from_email ) ) {
126
- return $from_email;
127
- }
128
-
129
- return $email;
130
- }
131
-
132
- /**
133
- * Modify the sender name that is used for sending emails.
134
- *
135
- * @since 1.0.0
136
- *
137
- * @param string $name
138
- *
139
- * @return string
140
- */
141
- public function filter_mail_from_name( $name ) {
142
-
143
- if ( 'WordPress' === $name ) {
144
- $name = Options::init()->get( 'mail', 'from_name' );
145
- }
146
-
147
- return $name;
148
- }
149
-
150
- /**
151
- * Get the default email address based on domain name.
152
- *
153
- * @since 1.0.0
154
- *
155
- * @return string
156
- */
157
- public function get_default_email() {
158
-
159
- // In case of CLI we don't have SERVER_NAME, so use host name instead, may be not a domain name.
160
- $server_name = ! empty( $_SERVER['SERVER_NAME'] ) ? $_SERVER['SERVER_NAME'] : wp_parse_url( get_home_url( get_current_blog_id() ), PHP_URL_HOST );
161
-
162
- // Get the site domain and get rid of www.
163
- $sitename = strtolower( $server_name );
164
- if ( substr( $sitename, 0, 4 ) === 'www.' ) {
165
- $sitename = substr( $sitename, 4 );
166
- }
167
-
168
- return 'wordpress@' . $sitename;
169
- }
170
- }
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WPMailSMTP;
4
+
5
+ /**
6
+ * Class Processor modifies the behaviour of wp_mail() function.
7
+ *
8
+ * @since 1.0.0
9
+ */
10
+ class Processor {
11
+
12
+ /**
13
+ * Processor constructor.
14
+ *
15
+ * @since 1.0.0
16
+ */
17
+ public function __construct() {
18
+ $this->hooks();
19
+ }
20
+
21
+ /**
22
+ * Assign all hooks to proper places.
23
+ *
24
+ * @since 1.0.0
25
+ */
26
+ public function hooks() {
27
+
28
+ add_action( 'phpmailer_init', array( $this, 'phpmailer_init' ) );
29
+
30
+ add_filter( 'wp_mail_from', array( $this, 'filter_mail_from_email' ) );
31
+ add_filter( 'wp_mail_from_name', array( $this, 'filter_mail_from_name' ), 11 );
32
+ }
33
+
34
+ /**
35
+ * Redefine certain PHPMailer options with our custom ones.
36
+ *
37
+ * @since 1.0.0
38
+ *
39
+ * @param \PHPMailer $phpmailer It's passed by reference, so no need to return anything.
40
+ */
41
+ public function phpmailer_init( $phpmailer ) {
42
+
43
+ $options = new Options();
44
+ $mailer = $options->get( 'mail', 'mailer' );
45
+
46
+ // Check that mailer is not blank, and if mailer=smtp, host is not blank.
47
+ if (
48
+ ! $mailer ||
49
+ ( 'smtp' === $mailer && ! $options->get( 'smtp', 'host' ) )
50
+ ) {
51
+ return;
52
+ }
53
+
54
+ // If the mailer is pepipost, make sure we have a username and password.
55
+ if (
56
+ 'pepipost' === $mailer &&
57
+ ( ! $options->get( 'pepipost', 'user' ) && ! $options->get( 'pepipost', 'pass' ) )
58
+ ) {
59
+ return;
60
+ }
61
+
62
+ // Set the mailer type as per config above, this overrides the already called isMail method.
63
+ // It's basically always 'smtp'.
64
+ $phpmailer->Mailer = $mailer;
65
+
66
+ // Set the Sender (return-path) if required.
67
+ if ( $options->get( 'mail', 'return_path' ) ) {
68
+ $phpmailer->Sender = $phpmailer->From;
69
+ }
70
+
71
+ // Set the SMTPSecure value, if set to none, leave this blank. Possible values: 'ssl', 'tls', ''.
72
+ if ( 'none' === $options->get( $mailer, 'encryption' ) ) {
73
+ $phpmailer->SMTPSecure = '';
74
+ } else {
75
+ $phpmailer->SMTPSecure = $options->get( $mailer, 'encryption' );
76
+ }
77
+
78
+ // Check if user has disabled SMTPAutoTLS.
79
+ if ( $options->get( $mailer, 'encryption' ) !== 'tls' && ! $options->get( $mailer, 'autotls' ) ) {
80
+ $phpmailer->SMTPAutoTLS = false;
81
+ }
82
+
83
+ // If we're sending via SMTP, set the host.
84
+ if ( 'smtp' === $mailer ) {
85
+ // Set the other options.
86
+ $phpmailer->Host = $options->get( $mailer, 'host' );
87
+ $phpmailer->Port = $options->get( $mailer, 'port' );
88
+
89
+ // If we're using smtp auth, set the username & password.
90
+ if ( $options->get( $mailer, 'auth' ) ) {
91
+ $phpmailer->SMTPAuth = true;
92
+ $phpmailer->Username = $options->get( $mailer, 'user' );
93
+ $phpmailer->Password = $options->get( $mailer, 'pass' );
94
+ }
95
+ } elseif ( 'pepipost' === $mailer ) {
96
+ // Set the Pepipost settings for BC.
97
+ $phpmailer->Mailer = 'smtp';
98
+ $phpmailer->Host = 'smtp.pepipost.com';
99
+ $phpmailer->Port = $options->get( $mailer, 'port' );
100
+ $phpmailer->SMTPSecure = $options->get( $mailer, 'encryption' ) === 'none' ? '' : $options->get( $mailer, 'encryption' );
101
+ $phpmailer->SMTPAuth = true;
102
+ $phpmailer->Username = $options->get( $mailer, 'user' );
103
+ $phpmailer->Password = $options->get( $mailer, 'pass' );
104
+ }
105
+
106
+ // You can add your own options here.
107
+ // See the phpmailer documentation for more info: https://github.com/PHPMailer/PHPMailer/tree/5.2-stable.
108
+ /** @noinspection PhpUnusedLocalVariableInspection It's passed by reference. */
109
+ $phpmailer = apply_filters( 'wp_mail_smtp_custom_options', $phpmailer );
110
+ }
111
+
112
+ /**
113
+ * Modify the email address that is used for sending emails.
114
+ *
115
+ * @since 1.0.0
116
+ *
117
+ * @param string $email
118
+ *
119
+ * @return string
120
+ */
121
+ public function filter_mail_from_email( $email ) {
122
+
123
+ // If the from email is not the default, return it unchanged.
124
+ if ( $email !== $this->get_default_email() ) {
125
+ return $email;
126
+ }
127
+
128
+ $from_email = Options::init()->get( 'mail', 'from_email' );
129
+
130
+ if ( ! empty( $from_email ) ) {
131
+ return $from_email;
132
+ }
133
+
134
+ return $email;
135
+ }
136
+
137
+ /**
138
+ * Modify the sender name that is used for sending emails.
139
+ *
140
+ * @since 1.0.0
141
+ *
142
+ * @param string $name
143
+ *
144
+ * @return string
145
+ */
146
+ public function filter_mail_from_name( $name ) {
147
+
148
+ if ( 'WordPress' === $name ) {
149
+ $name = Options::init()->get( 'mail', 'from_name' );
150
+ }
151
+
152
+ return $name;
153
+ }
154
+
155
+ /**
156
+ * Get the default email address based on domain name.
157
+ *
158
+ * @since 1.0.0
159
+ *
160
+ * @return string
161
+ */
162
+ public function get_default_email() {
163
+
164
+ // In case of CLI we don't have SERVER_NAME, so use host name instead, may be not a domain name.
165
+ $server_name = ! empty( $_SERVER['SERVER_NAME'] ) ? $_SERVER['SERVER_NAME'] : wp_parse_url( get_home_url( get_current_blog_id() ), PHP_URL_HOST );
166
+
167
+ // Get the site domain and get rid of www.
168
+ $sitename = strtolower( $server_name );
169
+ if ( substr( $sitename, 0, 4 ) === 'www.' ) {
170
+ $sitename = substr( $sitename, 4 );
171
+ }
172
+
173
+ return 'wordpress@' . $sitename;
174
+ }
175
+ }
src/Providers/AuthAbstract.php CHANGED
@@ -1,22 +1,22 @@
1
- <?php
2
-
3
- namespace WPMailSMTP\Providers;
4
-
5
- /**
6
- * Class AuthAbstract.
7
- *
8
- * @since 1.0.0
9
- */
10
- abstract class AuthAbstract implements AuthInterface {
11
-
12
- /**
13
- * Get the url, that users will be redirected back to finish the OAuth process.
14
- *
15
- * @since 1.0.0
16
- *
17
- * @return string
18
- */
19
- public static function get_plugin_auth_url() {
20
- return add_query_arg( 'tab', 'auth', wp_mail_smtp()->get_admin()->get_admin_page_url() );
21
- }
22
- }
1
+ <?php
2
+
3
+ namespace WPMailSMTP\Providers;
4
+
5
+ /**
6
+ * Class AuthAbstract.
7
+ *
8
+ * @since 1.0.0
9
+ */
10
+ abstract class AuthAbstract implements AuthInterface {
11
+
12
+ /**
13
+ * Get the url, that users will be redirected back to finish the OAuth process.
14
+ *
15
+ * @since 1.0.0
16
+ *
17
+ * @return string
18
+ */
19
+ public static function get_plugin_auth_url() {
20
+ return add_query_arg( 'tab', 'auth', wp_mail_smtp()->get_admin()->get_admin_page_url() );
21
+ }
22
+ }
src/Providers/AuthInterface.php CHANGED
@@ -1,19 +1,19 @@
1
- <?php
2
-
3
- namespace WPMailSMTP\Providers;
4
-
5
- /**
6
- * Interface AuthInterface.
7
- *
8
- * @since 1.0.0
9
- */
10
- interface AuthInterface {
11
-
12
- /**
13
- * Do something for this Auth implementation.
14
- *
15
- * @since 1.0.0
16
- */
17
- public function process();
18
-
19
- }
1
+ <?php
2
+
3
+ namespace WPMailSMTP\Providers;
4
+
5
+ /**
6
+ * Interface AuthInterface.
7
+ *
8
+ * @since 1.0.0
9
+ */
10
+ interface AuthInterface {
11
+
12
+ /**
13
+ * Do something for this Auth implementation.
14
+ *
15
+ * @since 1.0.0
16
+ */
17
+ public function process();
18
+
19
+ }
src/Providers/Gmail/Auth.php CHANGED
@@ -1,299 +1,314 @@
1
- <?php
2
-
3
- namespace WPMailSMTP\Providers\Gmail;
4
-
5
- use WPMailSMTP\Options as PluginOptions;
6
- use WPMailSMTP\Providers\AuthAbstract;
7
-
8
- /**
9
- * Class Auth to request access and refresh tokens.
10
- *
11
- * @since 1.0.0
12
- */
13
- class Auth extends AuthAbstract {
14
-
15
- /**
16
- * Gmail options.
17
- *
18
- * @var array
19
- */
20
- private $gmail;
21
-
22
- /**
23
- * @var \Google_Client
24
- */
25
- private $client;
26
-
27
- /**
28
- * @var string
29
- */
30
- private $mailer;
31
-
32
- /**
33
- * Auth constructor.
34
- *
35
- * @since 1.0.0
36
- */
37
- public function __construct() {
38
-
39
- $options = new PluginOptions();
40
- $this->mailer = $options->get( 'mail', 'mailer' );
41
- $this->gmail = $options->get_group( $this->mailer );
42
-
43
- if ( $this->is_clients_saved() ) {
44
-
45
- $this->include_google_lib();
46
-
47
- $this->client = $this->get_client();
48
- }
49
- }
50
-
51
- /**
52
- * Use the composer autoloader to include the Google Library and all its dependencies.
53
- *
54
- * @since 1.0.0
55
- */
56
- protected function include_google_lib() {
57
- require wp_mail_smtp()->plugin_path . '/vendor/autoload.php';
58
- }
59
-
60
- /**
61
- * Init and get the Google Client object.
62
- *
63
- * @since 1.0.0
64
- */
65
- public function get_client() {
66
-
67
- // Doesn't load client twice + gives ability to overwrite.
68
- if ( ! empty( $this->client ) ) {
69
- return $this->client;
70
- }
71
-
72
- $client = new \Google_Client(
73
- array(
74
- 'client_id' => $this->gmail['client_id'],
75
- 'client_secret' => $this->gmail['client_secret'],
76
- 'redirect_uris' => array(
77
- Auth::get_plugin_auth_url(),
78
- ),
79
- )
80
- );
81
- $client->setAccessType( 'offline' );
82
- $client->setApprovalPrompt( 'force' );
83
- $client->setIncludeGrantedScopes( true );
84
- // We request only the sending capability, as it's what we only need to do.
85
- $client->setScopes( array( \Google_Service_Gmail::GMAIL_SEND ) );
86
- $client->setRedirectUri( self::get_plugin_auth_url() );
87
-
88
- if (
89
- empty( $this->gmail['access_token'] ) &&
90
- ! empty( $this->gmail['auth_code'] )
91
- ) {
92
- $client->fetchAccessTokenWithAuthCode( $this->gmail['auth_code'] );
93
-
94
- // Bail if we have an error.
95
- if ( ! empty( $creds['error'] ) ) {
96
- // TODO: save this error to display to a user later.
97
- return $client;
98
- }
99
-
100
- $this->update_access_token( $client->getAccessToken() );
101
- $this->update_refresh_token( $client->getRefreshToken() );
102
- }
103
-
104
- if ( ! empty( $this->gmail['access_token'] ) ) {
105
- $client->setAccessToken( $this->gmail['access_token'] );
106
- }
107
-
108
- // Refresh the token if it's expired.
109
- if ( $client->isAccessTokenExpired() ) {
110
- $refresh = $client->getRefreshToken();
111
- if ( empty( $refresh ) && isset( $this->gmail['refresh_token'] ) ) {
112
- $refresh = $this->gmail['refresh_token'];
113
- }
114
-
115
- if ( ! empty( $refresh ) ) {
116
- $client->fetchAccessTokenWithRefreshToken( $refresh );
117
- $this->update_access_token( $client->getAccessToken() );
118
- $this->update_refresh_token( $client->getRefreshToken() );
119
- }
120
- }
121
-
122
- return $client;
123
- }
124
-
125
- /**
126
- * Get the auth code from the $_GET and save it.
127
- * Redirect user back to settings with an error message, if failed.
128
- *
129
- * @since 1.0.0
130
- */
131
- public function process() {
132
-
133
- // We can't process without saved client_id/secret.
134
- if ( ! $this->is_clients_saved() ) {
135
- wp_redirect(
136
- add_query_arg(
137
- 'error',
138
- 'google_no_clients',
139
- wp_mail_smtp()->get_admin()->get_admin_page_url()
140
- )
141
- );
142
- exit;
143
- }
144
-
145
- $code = '';
146
- $scope = '';
147
- $error = '';
148
-
149
- if ( isset( $_GET['error'] ) ) {
150
- $error = sanitize_key( $_GET['error'] );
151
- }
152
-
153
- // In case of any error: display a message to a user.
154
- if ( ! empty( $error ) ) {
155
- wp_redirect(
156
- add_query_arg(
157
- 'error',
158
- 'google_' . $error,
159
- wp_mail_smtp()->get_admin()->get_admin_page_url()
160
- )
161
- );
162
- exit;
163
- }
164
-
165
- if ( isset( $_GET['code'] ) ) {
166
- $code = $_GET['code'];
167
- }
168
- if ( isset( $_GET['scope'] ) ) {
169
- $scope = urldecode( $_GET['scope'] );
170
- }
171
-
172
- // Let's try to get the access token.
173
- if (
174
- ! empty( $code ) &&
175
- (
176
- $scope === ( \Google_Service_Gmail::GMAIL_SEND . ' ' . \Google_Service_Gmail::MAIL_GOOGLE_COM ) ||
177
- $scope === \Google_Service_Gmail::GMAIL_SEND
178
- )
179
- ) {
180
- // Save the auth code. So \Google_Client can reuse it to retrieve the access token.
181
- $this->update_auth_code( $code );
182
- } else {
183
- wp_redirect(
184
- add_query_arg(
185
- 'error',
186
- 'google_no_code_scope',
187
- wp_mail_smtp()->get_admin()->get_admin_page_url()
188
- )
189
- );
190
- exit;
191
- }
192
-
193
- wp_redirect(
194
- add_query_arg(
195
- 'success',
196
- 'google_site_linked',
197
- wp_mail_smtp()->get_admin()->get_admin_page_url()
198
- )
199
- );
200
- exit;
201
- }
202
-
203
- /**
204
- * Update access token in our DB.
205
- *
206
- * @since 1.0.0
207
- *
208
- * @param array $token
209
- */
210
- protected function update_access_token( $token ) {
211
-
212
- $options = new PluginOptions();
213
- $all = $options->get_all();
214
-
215
- $all[ $this->mailer ]['access_token'] = $token;
216
- $this->gmail['access_token'] = $token;
217
-
218
- $options->set( $all );
219
- }
220
-
221
- /**
222
- * Update refresh token in our DB.
223
- *
224
- * @since 1.0.0
225
- *
226
- * @param array $token
227
- */
228
- protected function update_refresh_token( $token ) {
229
-
230
- $options = new PluginOptions();
231
- $all = $options->get_all();
232
-
233
- $all[ $this->mailer ]['refresh_token'] = $token;
234
- $this->gmail['refresh_token'] = $token;
235
-
236
- $options->set( $all );
237
- }
238
-
239
- /**
240
- * Update auth code in our DB.
241
- *
242
- * @since 1.0.0
243
- *
244
- * @param string $code
245
- */
246
- protected function update_auth_code( $code ) {
247
-
248
- $options = new PluginOptions();
249
- $all = $options->get_all();
250
-
251
- $all[ $this->mailer ]['auth_code'] = $code;
252
- $this->gmail['auth_code'] = $code;
253
-
254
-
255
- $options->set( $all );
256
- }
257
-
258
- /**
259
- * Get the auth URL used to proceed to Google to request access to send emails.
260
- *
261
- * @since 1.0.0
262
- *
263
- * @return string
264
- */
265
- public function get_google_auth_url() {
266
- if (
267
- ! empty( $this->client ) &&
268
- class_exists( 'Google_Client', false ) &&
269
- $this->client instanceof \Google_Client
270
- ) {
271
- return filter_var( $this->client->createAuthUrl(), FILTER_SANITIZE_URL );
272
- }
273
-
274
- return '';
275
- }
276
-
277
- /**
278
- * Whether user saved Client ID and Client Secret or not.
279
- * Both options are required.
280
- *
281
- * @since 1.0.0
282
- *
283
- * @return bool
284
- */
285
- public function is_clients_saved() {
286
- return ! empty( $this->gmail['client_id'] ) && ! empty( $this->gmail['client_secret'] );
287
- }
288
-
289
- /**
290
- * Whether we have an access and refresh tokens or not.
291
- *
292
- * @since 1.0.0
293
- *
294
- * @return bool
295
- */
296
- public function is_auth_required() {
297
- return empty( $this->gmail['access_token'] ) || empty( $this->gmail['refresh_token'] );
298
- }
299
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WPMailSMTP\Providers\Gmail;
4
+
5
+ use WPMailSMTP\Options as PluginOptions;
6
+ use WPMailSMTP\Providers\AuthAbstract;
7
+
8
+ /**
9
+ * Class Auth to request access and refresh tokens.
10
+ *
11
+ * @since 1.0.0
12
+ */
13
+ class Auth extends AuthAbstract {
14
+
15
+ /**
16
+ * Gmail options.
17
+ *
18
+ * @var array
19
+ */
20
+ private $gmail;
21
+
22
+ /**
23
+ * @var \Google_Client
24
+ */
25
+ private $client;
26
+
27
+ /**
28
+ * @var string
29
+ */
30
+ private $mailer;
31
+
32
+ /**
33
+ * Auth constructor.
34
+ *
35
+ * @since 1.0.0
36
+ */
37
+ public function __construct() {
38
+
39
+ $options = new PluginOptions();
40
+ $this->mailer = $options->get( 'mail', 'mailer' );
41
+ $this->gmail = $options->get_group( $this->mailer );
42
+
43
+ if ( $this->is_clients_saved() ) {
44
+
45
+ $this->include_google_lib();
46
+
47
+ $this->client = $this->get_client();
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Use the composer autoloader to include the Google Library and all its dependencies.
53
+ *
54
+ * @since 1.0.0
55
+ */
56
+ protected function include_google_lib() {
57
+ require wp_mail_smtp()->plugin_path . '/vendor/autoload.php';
58
+ }
59
+
60
+ /**
61
+ * Init and get the Google Client object.
62
+ *
63
+ * @since 1.0.0
64
+ */
65
+ public function get_client() {
66
+
67
+ // Doesn't load client twice + gives ability to overwrite.
68
+ if ( ! empty( $this->client ) ) {
69
+ return $this->client;
70
+ }
71
+
72
+ $client = new \Google_Client(
73
+ array(
74
+ 'client_id' => $this->gmail['client_id'],
75
+ 'client_secret' => $this->gmail['client_secret'],
76
+ 'redirect_uris' => array(
77
+ Auth::get_plugin_auth_url(),
78
+ ),
79
+ )
80
+ );
81
+ $client->setAccessType( 'offline' );
82
+ $client->setApprovalPrompt( 'force' );
83
+ $client->setIncludeGrantedScopes( true );
84
+ // We request only the sending capability, as it's what we only need to do.
85
+ $client->setScopes( array( \Google_Service_Gmail::GMAIL_SEND ) );
86
+ $client->setRedirectUri( self::get_plugin_auth_url() );
87
+
88
+ if (
89
+ empty( $this->gmail['access_token'] ) &&
90
+ ! empty( $this->gmail['auth_code'] )
91
+ ) {
92
+ try {
93
+ $creds = $client->fetchAccessTokenWithAuthCode( $this->gmail['auth_code'] );
94
+ } catch ( \Exception $e ) {
95
+ $creds['error'] = $e->getMessage();
96
+ }
97
+
98
+ // Bail if we have an error.
99
+ if ( ! empty( $creds['error'] ) ) {
100
+ // TODO: save this error to display to a user later.
101
+ return $client;
102
+ }
103
+
104
+ $this->update_access_token( $client->getAccessToken() );
105
+ $this->update_refresh_token( $client->getRefreshToken() );
106
+ }
107
+
108
+ if ( ! empty( $this->gmail['access_token'] ) ) {
109
+ $client->setAccessToken( $this->gmail['access_token'] );
110
+ }
111
+
112
+ // Refresh the token if it's expired.
113
+ if ( $client->isAccessTokenExpired() ) {
114
+ $refresh = $client->getRefreshToken();
115
+ if ( empty( $refresh ) && isset( $this->gmail['refresh_token'] ) ) {
116
+ $refresh = $this->gmail['refresh_token'];
117
+ }
118
+
119
+ if ( ! empty( $refresh ) ) {
120
+ try {
121
+ $creds = $client->fetchAccessTokenWithRefreshToken( $refresh );
122
+ } catch ( \Exception $e ) {
123
+ $creds['error'] = $e->getMessage();
124
+ }
125
+
126
+ // Bail if we have an error.
127
+ if ( ! empty( $creds['error'] ) ) {
128
+ // TODO: save this error to display to a user later.
129
+ return $client;
130
+ }
131
+
132
+ $this->update_access_token( $client->getAccessToken() );
133
+ $this->update_refresh_token( $client->getRefreshToken() );
134
+ }
135
+ }
136
+
137
+ return $client;
138
+ }
139
+
140
+ /**
141
+ * Get the auth code from the $_GET and save it.
142
+ * Redirect user back to settings with an error message, if failed.
143
+ *
144
+ * @since 1.0.0
145
+ */
146
+ public function process() {
147
+
148
+ // We can't process without saved client_id/secret.
149
+ if ( ! $this->is_clients_saved() ) {
150
+ wp_redirect(
151
+ add_query_arg(
152
+ 'error',
153
+ 'google_no_clients',
154
+ wp_mail_smtp()->get_admin()->get_admin_page_url()
155
+ )
156
+ );
157
+ exit;
158
+ }
159
+
160
+ $code = '';
161
+ $scope = '';
162
+ $error = '';
163
+
164
+ if ( isset( $_GET['error'] ) ) {
165
+ $error = sanitize_key( $_GET['error'] );
166
+ }
167
+
168
+ // In case of any error: display a message to a user.
169
+ if ( ! empty( $error ) ) {
170
+ wp_redirect(
171
+ add_query_arg(
172
+ 'error',
173
+ 'google_' . $error,
174
+ wp_mail_smtp()->get_admin()->get_admin_page_url()
175
+ )
176
+ );
177
+ exit;
178
+ }
179
+
180
+ if ( isset( $_GET['code'] ) ) {
181
+ $code = $_GET['code'];
182
+ }
183
+ if ( isset( $_GET['scope'] ) ) {
184
+ $scope = urldecode( $_GET['scope'] );
185
+ }
186
+
187
+ // Let's try to get the access token.
188
+ if (
189
+ ! empty( $code ) &&
190
+ (
191
+ $scope === ( \Google_Service_Gmail::GMAIL_SEND . ' ' . \Google_Service_Gmail::MAIL_GOOGLE_COM ) ||
192
+ $scope === \Google_Service_Gmail::GMAIL_SEND
193
+ )
194
+ ) {
195
+ // Save the auth code. So \Google_Client can reuse it to retrieve the access token.
196
+ $this->update_auth_code( $code );
197
+ } else {
198
+ wp_redirect(
199
+ add_query_arg(
200
+ 'error',
201
+ 'google_no_code_scope',
202
+ wp_mail_smtp()->get_admin()->get_admin_page_url()
203
+ )
204
+ );
205
+ exit;
206
+ }
207
+
208
+ wp_redirect(
209
+ add_query_arg(
210
+ 'success',
211
+ 'google_site_linked',
212
+ wp_mail_smtp()->get_admin()->get_admin_page_url()
213
+ )
214
+ );
215
+ exit;
216
+ }
217
+
218
+ /**
219
+ * Update access token in our DB.
220
+ *
221
+ * @since 1.0.0
222
+ *
223
+ * @param array $token
224
+ */
225
+ protected function update_access_token( $token ) {
226
+
227
+ $options = new PluginOptions();
228
+ $all = $options->get_all();
229
+
230
+ $all[ $this->mailer ]['access_token'] = $token;
231
+ $this->gmail['access_token'] = $token;
232
+
233
+ $options->set( $all );
234
+ }
235
+
236
+ /**
237
+ * Update refresh token in our DB.
238
+ *
239
+ * @since 1.0.0
240
+ *
241
+ * @param array $token
242
+ */
243
+ protected function update_refresh_token( $token ) {
244
+
245
+ $options = new PluginOptions();
246
+ $all = $options->get_all();
247
+
248
+ $all[ $this->mailer ]['refresh_token'] = $token;
249
+ $this->gmail['refresh_token'] = $token;
250
+
251
+ $options->set( $all );
252
+ }
253
+
254
+ /**
255
+ * Update auth code in our DB.
256
+ *
257
+ * @since 1.0.0
258
+ *
259
+ * @param string $code
260
+ */
261
+ protected function update_auth_code( $code ) {
262
+
263
+ $options = new PluginOptions();
264
+ $all = $options->get_all();
265
+
266
+ $all[ $this->mailer ]['auth_code'] = $code;
267
+ $this->gmail['auth_code'] = $code;
268
+
269
+
270
+ $options->set( $all );
271
+ }
272
+
273
+ /**
274
+ * Get the auth URL used to proceed to Google to request access to send emails.
275
+ *
276
+ * @since 1.0.0
277
+ *
278
+ * @return string
279
+ */
280
+ public function get_google_auth_url() {
281
+ if (
282
+ ! empty( $this->client ) &&
283
+ class_exists( 'Google_Client', false ) &&
284
+ $this->client instanceof \Google_Client
285
+ ) {
286
+ return filter_var( $this->client->createAuthUrl(), FILTER_SANITIZE_URL );
287
+ }
288
+
289
+ return '';
290
+ }
291
+
292
+ /**
293
+ * Whether user saved Client ID and Client Secret or not.
294
+ * Both options are required.
295
+ *
296
+ * @since 1.0.0
297
+ *
298
+ * @return bool
299
+ */
300
+ public function is_clients_saved() {
301
+ return ! empty( $this->gmail['client_id'] ) && ! empty( $this->gmail['client_secret'] );
302
+ }
303
+
304
+ /**
305
+ * Whether we have an access and refresh tokens or not.
306
+ *
307
+ * @since 1.0.0
308
+ *
309
+ * @return bool
310
+ */
311
+ public function is_auth_required() {
312
+ return empty( $this->gmail['access_token'] ) || empty( $this->gmail['refresh_token'] );
313
+ }
314
+ }
src/Providers/Gmail/Mailer.php CHANGED
@@ -1,173 +1,173 @@
1
- <?php
2
-
3
- namespace WPMailSMTP\Providers\Gmail;
4
-
5
- use WPMailSMTP\Providers\MailerAbstract;
6
-
7
- /**
8
- * Class Mailer.
9
- *
10
- * @since 1.0.0
11
- */
12
- class Mailer extends MailerAbstract {
13
-
14
- /**
15
- * URL to make an API request to.
16
- * Not used for Gmail, as we are using its API.
17
- *
18
- * @var string
19
- */
20
- protected $url = 'https://www.googleapis.com/upload/gmail/v1/users/userId/messages/send';
21
-
22
- /**
23
- * Gmail custom Auth library.
24
- *
25
- * @var Auth
26
- */
27
- protected $auth;
28
-
29
- /**
30
- * Gmail message.
31
- *
32
- * @var \Google_Service_Gmail_Message
33
- */
34
- protected $message;
35
-
36
- /**
37
- * Mailer constructor.
38
- *
39
- * @since 1.0.0
40
- *
41
- * @param \WPMailSMTP\MailCatcher $phpmailer
42
- */
43
- public function __construct( $phpmailer ) {
44
- parent::__construct( $phpmailer );
45
-
46
- if ( ! $this->is_php_compatible() ) {
47
- return;
48
- }
49
-
50
- // Include the Google library.
51
- require wp_mail_smtp()->plugin_path . '/vendor/autoload.php';
52
-
53
- $this->auth = new Auth();
54
- $this->message = new \Google_Service_Gmail_Message();
55
- }
56
-
57
- /**
58
- * Set email FROM.
59
- *
60
- * @since 1.0.0
61
- *
62
- * @param string $email
63
- * @param string $name
64
- */
65
- public function set_from( $email, $name ) {
66
- }
67
-
68
- /**
69
- * Set a bunch of email recipients: to, cc, bcc.
70
- *
71
- * @since 1.0.0
72
- *
73
- * @param array $recipients
74
- */
75
- public function set_recipients( $recipients ) {
76
- }
77
-
78
- /**
79
- * Set the email content.
80
- *
81
- * @since 1.0.0
82
- *
83
- * @param string|array $content
84
- */
85
- public function set_content( $content ) {
86
- }
87
-
88
- /**
89
- * Set the email attachments.
90
- *
91
- * @since 1.0.0
92
- *
93
- * @param array $attachments
94
- */
95
- public function set_attachments( $attachments ) {
96
- }
97
-
98
- /**
99
- * Set the email reply_to option.
100
- *
101
- * @since 1.0.0
102
- *
103
- * @param array $reply_to
104
- */
105
- public function set_reply_to( $reply_to ) {
106
- }
107
-
108
- /**
109
- * Set the email return_path (when supported).
110
- *
111
- * @since 1.0.0
112
- *
113
- * @param string $email
114
- */
115
- public function set_return_path( $email ) {
116
- }
117
-
118
- /**
119
- * Use Google API Services to send emails.
120
- *
121
- * @since 1.0.0
122
- */
123
- public function send() {
124
-
125
- // Get the raw MIME email using \PHPMailer data.
126
- $mime = $this->phpmailer->getSentMIMEMessage();
127
- $data = base64_encode( $mime );
128
- $data = str_replace( array( '+', '/', '=' ), array( '-', '_', '' ), $data ); // url safe.
129
- $this->message->setRaw( $data );
130
-
131
- $service = new \Google_Service_Gmail( $this->auth->get_client() );
132
-
133
- try {
134
- $response = $service->users_messages->send( 'me', $this->message );
135
-
136
- $this->process_response( $response );
137
- } catch ( \Exception $e ) {
138
- // TODO: save here the error message to display to a user later.
139
- return;
140
- }
141
- }
142
-
143
- /**
144
- * Save response from the API to use it later.
145
- *
146
- * @since 1.0.0
147
- *
148
- * @param \Google_Service_Gmail_Message $response
149
- */
150
- protected function process_response( $response ) {
151
- $this->response = $response;
152
- }
153
-
154
- /**
155
- * Check whether the email was sent.
156
- *
157
- * @since 1.0.0
158
- *
159
- * @return bool
160
- */
161
- public function is_email_sent() {
162
- $is_sent = false;
163
-
164
- if ( method_exists( $this->response, 'getId' ) ) {
165
- $message_id = $this->response->getId();
166
- if ( ! empty( $message_id ) ) {
167
- return true;
168
- }
169
- }
170
-
171
- return $is_sent;
172
- }
173
- }
1
+ <?php
2
+
3
+ namespace WPMailSMTP\Providers\Gmail;
4
+
5
+ use WPMailSMTP\Providers\MailerAbstract;
6
+
7
+ /**
8
+ * Class Mailer.
9
+ *
10
+ * @since 1.0.0
11
+ */
12
+ class Mailer extends MailerAbstract {
13
+
14
+ /**
15
+ * URL to make an API request to.
16
+ * Not used for Gmail, as we are using its API.
17
+ *
18
+ * @var string
19
+ */
20
+ protected $url = 'https://www.googleapis.com/upload/gmail/v1/users/userId/messages/send';
21
+
22
+ /**
23
+ * Gmail custom Auth library.
24
+ *
25
+ * @var Auth
26
+ */
27
+ protected $auth;
28
+
29
+ /**
30
+ * Gmail message.
31
+ *
32
+ * @var \Google_Service_Gmail_Message
33
+ */
34
+ protected $message;
35
+
36
+ /**
37
+ * Mailer constructor.
38
+ *
39
+ * @since 1.0.0
40
+ *
41
+ * @param \WPMailSMTP\MailCatcher $phpmailer
42
+ */
43
+ public function __construct( $phpmailer ) {
44
+ parent::__construct( $phpmailer );
45
+
46
+ if ( ! $this->is_php_compatible() ) {
47
+ return;
48
+ }
49
+
50
+ // Include the Google library.
51
+ require wp_mail_smtp()->plugin_path . '/vendor/autoload.php';
52
+
53
+ $this->auth = new Auth();
54
+ $this->message = new \Google_Service_Gmail_Message();
55
+ }
56
+
57
+ /**
58
+ * Set email FROM.
59
+ *
60
+ * @since 1.0.0
61
+ *
62
+ * @param string $email
63
+ * @param string $name
64
+ */
65
+ public function set_from( $email, $name ) {
66
+ }
67
+
68
+ /**
69
+ * Set a bunch of email recipients: to, cc, bcc.
70
+ *
71
+ * @since 1.0.0
72
+ *
73
+ * @param array $recipients
74
+ */
75
+ public function set_recipients( $recipients ) {
76
+ }
77
+
78
+ /**
79
+ * Set the email content.
80
+ *
81
+ * @since 1.0.0
82
+ *
83
+ * @param string|array $content
84
+ */
85
+ public function set_content( $content ) {
86
+ }
87
+
88
+ /**
89
+ * Set the email attachments.
90
+ *
91
+ * @since 1.0.0
92
+ *
93
+ * @param array $attachments
94
+ */
95
+ public function set_attachments( $attachments ) {
96
+ }
97
+
98
+ /**
99
+ * Set the email reply_to option.
100
+ *
101
+ * @since 1.0.0
102
+ *
103
+ * @param array $reply_to
104
+ */
105
+ public function set_reply_to( $reply_to ) {
106
+ }
107
+
108
+ /**
109
+ * Set the email return_path (when supported).
110
+ *
111
+ * @since 1.0.0
112
+ *
113
+ * @param string $email
114
+ */
115
+ public function set_return_path( $email ) {
116
+ }
117
+
118
+ /**
119
+ * Use Google API Services to send emails.
120
+ *
121
+ * @since 1.0.0
122
+ */
123
+ public function send() {
124
+
125
+ // Get the raw MIME email using \PHPMailer data.
126
+ $mime = $this->phpmailer->getSentMIMEMessage();
127
+ $data = base64_encode( $mime );
128
+ $data = str_replace( array( '+', '/', '=' ), array( '-', '_', '' ), $data ); // url safe.
129
+ $this->message->setRaw( $data );
130
+
131
+ $service = new \Google_Service_Gmail( $this->auth->get_client() );
132
+
133
+ try {
134
+ $response = $service->users_messages->send( 'me', $this->message );
135
+
136
+ $this->process_response( $response );
137
+ } catch ( \Exception $e ) {
138
+ // TODO: save here the error message to display to a user later.
139
+ return;
140
+ }
141
+ }
142
+
143
+ /**
144
+ * Save response from the API to use it later.
145
+ *
146
+ * @since 1.0.0
147
+ *
148
+ * @param \Google_Service_Gmail_Message $response
149
+ */
150
+ protected function process_response( $response ) {
151
+ $this->response = $response;
152
+ }
153
+
154
+ /**
155
+ * Check whether the email was sent.
156
+ *
157
+ * @since 1.0.0
158
+ *
159
+ * @return bool
160
+ */
161
+ public function is_email_sent() {
162
+ $is_sent = false;
163
+
164
+ if ( method_exists( $this->response, 'getId' ) ) {
165
+ $message_id = $this->response->getId();
166
+ if ( ! empty( $message_id ) ) {
167
+ return true;
168
+ }
169
+ }
170
+
171
+ return $is_sent;
172
+ }
173
+ }
src/Providers/Gmail/Options.php CHANGED
@@ -1,131 +1,131 @@
1
- <?php
2
-
3
- namespace WPMailSMTP\Providers\Gmail;
4
-
5
- use WPMailSMTP\Providers\OptionAbstract;
6
-
7
- /**
8
- * Class Option.
9
- *
10
- * @since 1.0.0
11
- */
12
- class Options extends OptionAbstract {
13
-
14
- /**
15
- * Mailgun constructor.
16
- *
17
- * @since 1.0.0
18
- */
19
- public function __construct() {
20
-
21
- parent::__construct(
22
- array(
23
- 'logo_url' => wp_mail_smtp()->plugin_url . '/assets/images/gmail.png',
24
- 'slug' => 'gmail',
25
- 'title' => esc_html__( 'Gmail', 'wp-mail-smtp' ),
26
- 'description' => sprintf(
27
- wp_kses(
28
- /* translators: %1$s - opening link tag; %2$s - closing link tag. */
29
- __( 'Send emails using your Gmail or G Suite (formerly Google Apps) account, all while keeping your login credentials safe. Other Google SMTP methods require enabling less secure apps in your account and entering your password. However, this integration uses the Google API to improve email delivery issues while keeping your site secure.<br><br>Read our %1$sGmail documentation%2$s to learn how to configure Gmail or G Suite.', 'wp-mail-smtp' ),
30
- array(
31
- 'br' => array(),
32
- 'a' => array(
33
- 'href' => array(),
34
- 'rel' => array(),
35
- 'target' => array(),
36
- ),
37
- )
38
- ),
39
- '<a href="https://wpforms.com/how-to-securely-send-wordpress-emails-using-gmail-smtp/" target="_blank" rel="noopener noreferrer">',
40
- '</a>'
41
- ),
42
- 'php' => '5.5',
43
- )
44
- );
45
- }
46
-
47
- /**
48
- * @inheritdoc
49
- */
50
- public function display_options() {
51
-
52
- // Do not display options if PHP version is not correct.
53
- if ( ! $this->is_php_correct() ) {
54
- $this->display_php_warning();
55
-
56
- return;
57
- }
58
- ?>
59
-
60
- <!-- Client ID -->
61
- <div id="wp-mail-smtp-setting-row-<?php echo esc_attr( $this->get_slug() ); ?>-client_id" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-text wp-mail-smtp-clear">
62
- <div class="wp-mail-smtp-setting-label">
63
- <label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-client_id"><?php esc_html_e( 'Client ID', 'wp-mail-smtp' ); ?></label>
64
- </div>
65
- <div class="wp-mail-smtp-setting-field">
66
- <input name="wp-mail-smtp[<?php echo esc_attr( $this->get_slug() ); ?>][client_id]" type="text"
67
- value="<?php echo esc_attr( $this->options->get( $this->get_slug(), 'client_id' ) ); ?>"
68
- <?php echo $this->options->is_const_defined( $this->get_slug(), 'client_id' ) ? 'disabled' : ''; ?>
69
- id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-client_id" spellcheck="false"
70
- />
71
- </div>
72
- </div>
73
-
74
- <!-- Client Secret -->
75
- <div id="wp-mail-smtp-setting-row-<?php echo esc_attr( $this->get_slug() ); ?>-client_secret" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-text wp-mail-smtp-clear">
76
- <div class="wp-mail-smtp-setting-label">
77
- <label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-client_secret"><?php esc_html_e( 'Client Secret', 'wp-mail-smtp' ); ?></label>
78
- </div>
79
- <div class="wp-mail-smtp-setting-field">
80
- <input name="wp-mail-smtp[<?php echo esc_attr( $this->get_slug() ); ?>][client_secret]" type="text"
81
- value="<?php echo esc_attr( $this->options->get( $this->get_slug(), 'client_secret' ) ); ?>"
82
- <?php echo $this->options->is_const_defined( $this->get_slug(), 'client_secret' ) ? 'disabled' : ''; ?>
83
- id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-client_secret" spellcheck="false"
84
- />
85
- </div>
86
- </div>
87
-
88
- <!-- Authorized redirect URI -->
89
- <div id="wp-mail-smtp-setting-row-<?php echo esc_attr( $this->get_slug() ); ?>-client_redirect" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-text wp-mail-smtp-clear">
90
- <div class="wp-mail-smtp-setting-label">
91
- <label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-client_redirect"><?php esc_html_e( 'Authorized redirect URI', 'wp-mail-smtp' ); ?></label>
92
- </div>
93
- <div class="wp-mail-smtp-setting-field">
94
- <input type="text" readonly="readonly"
95
- value="<?php echo esc_attr( Auth::get_plugin_auth_url() ); ?>"
96
- id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-client_redirect"
97
- />
98
- <button type="button" class="wp-mail-smtp-btn wp-mail-smtp-btn-md wp-mail-smtp-btn-light-grey wp-mail-smtp-setting-copy"
99
- title="<?php esc_attr_e( 'Copy URL to clipboard', 'wp-mail-smtp' ); ?>"
100
- data-source_id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-client_redirect">
101
- <span class="dashicons dashicons-admin-page"></span>
102
- </button>
103
- <p class="desc">
104
- <?php esc_html_e( 'This is the path on your site that you will be redirected to after you have authenticated with Google.', 'wp-mail-smtp' ); ?>
105
- <br>
106
- <?php esc_html_e( 'You need to copy this URL into "Authorized redirect URIs" field for you web application on Google APIs site for your project there.', 'wp-mail-smtp' ); ?>
107
- </p>
108
- </div>
109
- </div>
110
-
111
- <!-- Auth users button -->
112
- <?php $auth = new Auth(); ?>
113
- <?php if ( $auth->is_clients_saved() && $auth->is_auth_required() ) : ?>
114
- <div id="wp-mail-smtp-setting-row-<?php echo esc_attr( $this->get_slug() ); ?>-authorize" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-text wp-mail-smtp-clear">
115
- <div class="wp-mail-smtp-setting-label">
116
- <label><?php esc_html_e( 'Authorize', 'wp-mail-smtp' ); ?></label>
117
- </div>
118
- <div class="wp-mail-smtp-setting-field">
119
- <a href="<?php echo esc_url( $auth->get_google_auth_url() ); ?>" class="wp-mail-smtp-btn wp-mail-smtp-btn-md wp-mail-smtp-btn-orange">
120
- <?php esc_html_e( 'Allow plugin to send emails using your Google account', 'wp-mail-smtp' ); ?>
121
- </a>
122
- <p class="desc">
123
- <?php esc_html_e( 'Click the button above to confirm authorization.', 'wp-mail-smtp' ); ?>
124
- </p>
125
- </div>
126
- </div>
127
- <?php endif; ?>
128
-
129
- <?php
130
- }
131
- }
1
+ <?php
2
+
3
+ namespace WPMailSMTP\Providers\Gmail;
4
+
5
+ use WPMailSMTP\Providers\OptionAbstract;
6
+
7
+ /**
8
+ * Class Option.
9
+ *
10
+ * @since 1.0.0
11
+ */
12
+ class Options extends OptionAbstract {
13
+
14
+ /**
15
+ * Mailgun constructor.
16
+ *
17
+ * @since 1.0.0
18
+ */
19
+ public function __construct() {
20
+
21
+ parent::__construct(
22
+ array(
23
+ 'logo_url' => wp_mail_smtp()->plugin_url . '/assets/images/gmail.png',
24
+ 'slug' => 'gmail',
25
+ 'title' => esc_html__( 'Gmail', 'wp-mail-smtp' ),
26
+ 'description' => sprintf(
27
+ wp_kses(
28
+ /* translators: %1$s - opening link tag; %2$s - closing link tag. */
29
+ __( 'Send emails using your Gmail or G Suite (formerly Google Apps) account, all while keeping your login credentials safe. Other Google SMTP methods require enabling less secure apps in your account and entering your password. However, this integration uses the Google API to improve email delivery issues while keeping your site secure.<br><br>Read our %1$sGmail documentation%2$s to learn how to configure Gmail or G Suite.', 'wp-mail-smtp' ),
30
+ array(
31
+ 'br' => array(),
32
+ 'a' => array(
33
+ 'href' => array(),
34
+ 'rel' => array(),
35
+ 'target' => array(),
36
+ ),
37
+ )
38
+ ),
39
+ '<a href="https://wpforms.com/how-to-securely-send-wordpress-emails-using-gmail-smtp/" target="_blank" rel="noopener noreferrer">',
40
+ '</a>'
41
+ ),
42
+ 'php' => '5.5',
43
+ )
44
+ );
45
+ }
46
+
47
+ /**
48
+ * @inheritdoc
49
+ */
50
+ public function display_options() {
51
+
52
+ // Do not display options if PHP version is not correct.
53
+ if ( ! $this->is_php_correct() ) {
54
+ $this->display_php_warning();
55
+
56
+ return;
57
+ }
58
+ ?>
59
+
60
+ <!-- Client ID -->
61
+ <div id="wp-mail-smtp-setting-row-<?php echo esc_attr( $this->get_slug() ); ?>-client_id" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-text wp-mail-smtp-clear">
62
+ <div class="wp-mail-smtp-setting-label">
63
+ <label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-client_id"><?php esc_html_e( 'Client ID', 'wp-mail-smtp' ); ?></label>
64
+ </div>
65
+ <div class="wp-mail-smtp-setting-field">
66
+ <input name="wp-mail-smtp[<?php echo esc_attr( $this->get_slug() ); ?>][client_id]" type="text"
67
+ value="<?php echo esc_attr( $this->options->get( $this->get_slug(), 'client_id' ) ); ?>"
68
+ <?php echo $this->options->is_const_defined( $this->get_slug(), 'client_id' ) ? 'disabled' : ''; ?>
69
+ id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-client_id" spellcheck="false"
70
+ />
71
+ </div>
72
+ </div>
73
+
74
+ <!-- Client Secret -->
75
+ <div id="wp-mail-smtp-setting-row-<?php echo esc_attr( $this->get_slug() ); ?>-client_secret" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-text wp-mail-smtp-clear">
76
+ <div class="wp-mail-smtp-setting-label">
77
+ <label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-client_secret"><?php esc_html_e( 'Client Secret', 'wp-mail-smtp' ); ?></label>
78
+ </div>
79
+ <div class="wp-mail-smtp-setting-field">
80
+ <input name="wp-mail-smtp[<?php echo esc_attr( $this->get_slug() ); ?>][client_secret]" type="text"
81
+ value="<?php echo esc_attr( $this->options->get( $this->get_slug(), 'client_secret' ) ); ?>"
82
+ <?php echo $this->options->is_const_defined( $this->get_slug(), 'client_secret' ) ? 'disabled' : ''; ?>
83
+ id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-client_secret" spellcheck="false"
84
+ />
85
+ </div>
86
+ </div>
87
+
88
+ <!-- Authorized redirect URI -->
89
+ <div id="wp-mail-smtp-setting-row-<?php echo esc_attr( $this->get_slug() ); ?>-client_redirect" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-text wp-mail-smtp-clear">
90
+ <div class="wp-mail-smtp-setting-label">
91
+ <label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-client_redirect"><?php esc_html_e( 'Authorized redirect URI', 'wp-mail-smtp' ); ?></label>
92
+ </div>
93
+ <div class="wp-mail-smtp-setting-field">
94
+ <input type="text" readonly="readonly"
95
+ value="<?php echo esc_attr( Auth::get_plugin_auth_url() ); ?>"
96
+ id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-client_redirect"
97
+ />
98
+ <button type="button" class="wp-mail-smtp-btn wp-mail-smtp-btn-md wp-mail-smtp-btn-light-grey wp-mail-smtp-setting-copy"
99
+ title="<?php esc_attr_e( 'Copy URL to clipboard', 'wp-mail-smtp' ); ?>"
100
+ data-source_id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-client_redirect">
101
+ <span class="dashicons dashicons-admin-page"></span>
102
+ </button>
103
+ <p class="desc">
104
+ <?php esc_html_e( 'This is the path on your site that you will be redirected to after you have authenticated with Google.', 'wp-mail-smtp' ); ?>
105
+ <br>
106
+ <?php esc_html_e( 'You need to copy this URL into "Authorized redirect URIs" field for you web application on Google APIs site for your project there.', 'wp-mail-smtp' ); ?>
107
+ </p>
108
+ </div>
109
+ </div>
110
+
111
+ <!-- Auth users button -->
112
+ <?php $auth = new Auth(); ?>
113
+ <?php if ( $auth->is_clients_saved() && $auth->is_auth_required() ) : ?>
114
+ <div id="wp-mail-smtp-setting-row-<?php echo esc_attr( $this->get_slug() ); ?>-authorize" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-text wp-mail-smtp-clear">
115
+ <div class="wp-mail-smtp-setting-label">
116
+ <label><?php esc_html_e( 'Authorize', 'wp-mail-smtp' ); ?></label>
117
+ </div>
118
+ <div class="wp-mail-smtp-setting-field">
119
+ <a href="<?php echo esc_url( $auth->get_google_auth_url() ); ?>" class="wp-mail-smtp-btn wp-mail-smtp-btn-md wp-mail-smtp-btn-orange">
120
+ <?php esc_html_e( 'Allow plugin to send emails using your Google account', 'wp-mail-smtp' ); ?>
121
+ </a>
122
+ <p class="desc">
123
+ <?php esc_html_e( 'Click the button above to confirm authorization.', 'wp-mail-smtp' ); ?>
124
+ </p>
125
+ </div>
126
+ </div>
127
+ <?php endif; ?>
128
+
129
+ <?php
130
+ }
131
+ }
src/Providers/Loader.php CHANGED
@@ -1,178 +1,178 @@
1
- <?php
2
-
3
- namespace WPMailSMTP\Providers;
4
-
5
- use WPMailSMTP\MailCatcher;
6
-
7
- /**
8
- * Class Loader.
9
- *
10
- * @since 1.0.0
11
- */
12
- class Loader {
13
-
14
- /**
15
- * Key is the mailer option, value is the path to its classes.
16
- *
17
- * @var array
18
- */
19
- protected $providers = array(
20
- 'mail' => '\WPMailSMTP\Providers\Mail\\',
21
- 'gmail' => '\WPMailSMTP\Providers\Gmail\\',
22
- 'mailgun' => '\WPMailSMTP\Providers\Mailgun\\',
23
- 'sendgrid' => '\WPMailSMTP\Providers\Sendgrid\\',
24
- 'pepipost' => '\WPMailSMTP\Providers\Pepipost\\',
25
- 'smtp' => '\WPMailSMTP\Providers\SMTP\\',
26
- );
27
-
28
- /**
29
- * @var \WPMailSMTP\MailCatcher
30
- */
31
- private $phpmailer;
32
-
33
- /**
34
- * Get all the supported providers.
35
- *
36
- * @since 1.0.0
37
- *
38
- * @return array
39
- */
40
- public function get_providers() {
41
- return apply_filters( 'wp_mail_smtp_providers_loader_get_providers', $this->providers );
42
- }
43
-
44
- /**
45
- * Get a single provider FQN-path based on its name.
46
- *
47
- * @since 1.0.0
48
- *
49
- * @param string $provider
50
- *
51
- * @return array
52
- */
53
- public function get_provider_path( $provider ) {
54
- $provider = sanitize_key( $provider );
55
-
56
- return apply_filters(
57
- 'wp_mail_smtp_providers_loader_get_provider_path',
58
- isset( $this->providers[ $provider ] ) ? $this->providers[ $provider ] : null,
59
- $provider
60
- );
61
- }
62
-
63
- /**
64
- * Get the provider options, if exists.
65
- *
66
- * @since 1.0.0
67
- *
68
- * @param string $provider
69
- *
70
- * @return \WPMailSMTP\Providers\OptionAbstract|null
71
- */
72
- public function get_options( $provider ) {
73
- return $this->get_entity( $provider, 'Options' );
74
- }
75
-
76
- /**
77
- * Get all options of all providers.
78
- *
79
- * @since 1.0.0
80
- *
81
- * @return \WPMailSMTP\Providers\OptionAbstract[]
82
- */
83
- public function get_options_all() {
84
- $options = array();
85
-
86
- foreach ( $this->get_providers() as $provider => $path ) {
87
-
88
- $option = $this->get_options( $provider );
89
-
90
- if ( ! $option instanceof OptionAbstract ) {
91
- continue;
92
- }
93
-
94
- $slug = $option->get_slug();
95
- $title = $option->get_title();
96
-
97
- if ( empty( $title ) || empty( $slug ) ) {
98
- continue;
99
- }
100
-
101
- $options[] = $option;
102
- }
103
-
104
- return apply_filters( 'wp_mail_smtp_providers_loader_get_providers_all', $options );
105
- }
106
-
107
- /**
108
- * Get the provider mailer, if exists.
109
- *
110
- * @since 1.0.0
111
- *
112
- * @param string $provider
113
- * @param MailCatcher $phpmailer
114
- *
115
- * @return \WPMailSMTP\Providers\MailerAbstract|null
116
- */
117
- public function get_mailer( $provider, $phpmailer ) {
118
-
119
- if ( $phpmailer instanceof MailCatcher ) {
120
- $this->phpmailer = $phpmailer;
121
- }
122
-
123
- return $this->get_entity( $provider, 'Mailer' );
124
- }
125
-
126
- /**
127
- * Get the provider auth, if exists.
128
- *
129
- * @param string $provider
130
- *
131
- * @return \WPMailSMTP\Providers\AuthAbstract|null
132
- */
133
- public function get_auth( $provider ) {
134
- return $this->get_entity( $provider, 'Auth' );
135
- }
136
-
137
- /**
138
- * Get a generic entity based on the request.
139
- *
140
- * @uses ReflectionClass
141
- *
142
- * @since 1.0.0
143
- *
144
- * @param string $provider
145
- * @param string $request
146
- *
147
- * @return null
148
- */
149
- protected function get_entity( $provider, $request ) {
150
-
151
- $provider = sanitize_key( $provider );
152
- $request = sanitize_text_field( $request );
153
- $path = $this->get_provider_path( $provider );
154
- $entity = null;
155
-
156
- if ( empty( $path ) ) {
157
- return $entity;
158
- }
159
-
160
- try {
161
- $reflection = new \ReflectionClass( $path . $request );
162
-
163
- if ( file_exists( $reflection->getFileName() ) ) {
164
- $class = $path . $request;
165
- if ( $this->phpmailer ) {
166
- $entity = new $class( $this->phpmailer );
167
- } else {
168
- $entity = new $class();
169
- }
170
- }
171
- } catch ( \Exception $e ) {
172
- // TODO: save error message later to display a user.
173
- $entity = null;
174
- }
175
-
176
- return apply_filters( 'wp_mail_smtp_providers_loader_get_entity', $entity, $provider, $request );
177
- }
178
- }
1
+ <?php
2
+
3
+ namespace WPMailSMTP\Providers;
4
+
5
+ use WPMailSMTP\MailCatcher;
6
+
7
+ /**
8
+ * Class Loader.
9
+ *
10
+ * @since 1.0.0
11
+ */
12
+ class Loader {
13
+
14
+ /**
15
+ * Key is the mailer option, value is the path to its classes.
16
+ *
17
+ * @var array
18
+ */
19
+ protected $providers = array(
20
+ 'mail' => '\WPMailSMTP\Providers\Mail\\',
21
+ 'gmail' => '\WPMailSMTP\Providers\Gmail\\',
22
+ 'mailgun' => '\WPMailSMTP\Providers\Mailgun\\',
23
+ 'sendgrid' => '\WPMailSMTP\Providers\Sendgrid\\',
24
+ 'pepipost' => '\WPMailSMTP\Providers\Pepipost\\',
25
+ 'smtp' => '\WPMailSMTP\Providers\SMTP\\',
26
+ );
27
+
28
+ /**
29
+ * @var \WPMailSMTP\MailCatcher
30
+ */
31
+ private $phpmailer;
32
+
33
+ /**
34
+ * Get all the supported providers.
35
+ *
36
+ * @since 1.0.0
37
+ *
38
+ * @return array
39
+ */
40
+ public function get_providers() {
41
+ return apply_filters( 'wp_mail_smtp_providers_loader_get_providers', $this->providers );
42
+ }
43
+
44
+ /**
45
+ * Get a single provider FQN-path based on its name.
46
+ *
47
+ * @since 1.0.0
48
+ *
49
+ * @param string $provider
50
+ *
51
+ * @return array
52
+ */
53
+ public function get_provider_path( $provider ) {
54
+ $provider = sanitize_key( $provider );
55
+
56
+ return apply_filters(
57
+ 'wp_mail_smtp_providers_loader_get_provider_path',
58
+ isset( $this->providers[ $provider ] ) ? $this->providers[ $provider ] : null,
59
+ $provider
60
+ );
61
+ }
62
+
63
+ /**
64
+ * Get the provider options, if exists.
65
+ *
66
+ * @since 1.0.0
67
+ *
68
+ * @param string $provider
69
+ *
70
+ * @return \WPMailSMTP\Providers\OptionAbstract|null
71
+ */
72
+ public function get_options( $provider ) {
73
+ return $this->get_entity( $provider, 'Options' );
74
+ }
75
+
76
+ /**
77
+ * Get all options of all providers.
78
+ *
79
+ * @since 1.0.0
80
+ *
81
+ * @return \WPMailSMTP\Providers\OptionAbstract[]
82
+ */
83
+ public function get_options_all() {
84
+ $options = array();
85
+
86
+ foreach ( $this->get_providers() as $provider => $path ) {
87
+
88
+ $option = $this->get_options( $provider );
89
+
90
+ if ( ! $option instanceof OptionAbstract ) {
91
+ continue;
92
+ }
93
+
94
+ $slug = $option->get_slug();
95
+ $title = $option->get_title();
96
+
97
+ if ( empty( $title ) || empty( $slug ) ) {
98
+ continue;
99
+ }
100
+
101
+ $options[] = $option;
102
+ }
103
+
104
+ return apply_filters( 'wp_mail_smtp_providers_loader_get_providers_all', $options );
105
+ }
106
+
107
+ /**
108
+ * Get the provider mailer, if exists.
109
+ *
110
+ * @since 1.0.0
111
+ *
112
+ * @param string $provider
113
+ * @param MailCatcher $phpmailer
114
+ *
115
+ * @return \WPMailSMTP\Providers\MailerAbstract|null
116
+ */
117
+ public function get_mailer( $provider, $phpmailer ) {
118
+
119
+ if ( $phpmailer instanceof MailCatcher ) {
120
+ $this->phpmailer = $phpmailer;
121
+ }
122
+
123
+ return $this->get_entity( $provider, 'Mailer' );
124
+ }
125
+
126
+ /**
127
+ * Get the provider auth, if exists.
128
+ *
129
+ * @param string $provider
130
+ *
131
+ * @return \WPMailSMTP\Providers\AuthAbstract|null
132
+ */
133
+ public function get_auth( $provider ) {
134
+ return $this->get_entity( $provider, 'Auth' );
135
+ }
136
+
137
+ /**
138
+ * Get a generic entity based on the request.
139
+ *
140
+ * @uses ReflectionClass
141
+ *
142
+ * @since 1.0.0
143
+ *
144
+ * @param string $provider
145
+ * @param string $request
146
+ *
147
+ * @return null
148
+ */
149
+ protected function get_entity( $provider, $request ) {
150
+
151
+ $provider = sanitize_key( $provider );
152
+ $request = sanitize_text_field( $request );
153
+ $path = $this->get_provider_path( $provider );
154
+ $entity = null;
155
+
156
+ if ( empty( $path ) ) {
157
+ return $entity;
158
+ }
159
+
160
+ try {
161
+ $reflection = new \ReflectionClass( $path . $request );
162
+
163
+ if ( file_exists( $reflection->getFileName() ) ) {
164
+ $class = $path . $request;
165
+ if ( $this->phpmailer ) {
166
+ $entity = new $class( $this->phpmailer );
167
+ } else {
168
+ $entity = new $class();
169
+ }
170
+ }
171
+ } catch ( \Exception $e ) {
172
+ // TODO: save error message later to display a user.
173
+ $entity = null;
174
+ }
175
+
176
+ return apply_filters( 'wp_mail_smtp_providers_loader_get_entity', $entity, $provider, $request );
177
+ }
178
+ }
src/Providers/Mail/Options.php CHANGED
@@ -1,42 +1,42 @@
1
- <?php
2
-
3
- namespace WPMailSMTP\Providers\Mail;
4
-
5
- use WPMailSMTP\Providers\OptionAbstract;
6
-
7
- /**
8
- * Class Option.
9
- *
10
- * @since 1.0.0
11
- */
12
- class Options extends OptionAbstract {
13
-
14
- /**
15
- * Mail constructor.
16
- *
17
- * @since 1.0.0
18
- */
19
- public function __construct() {
20
-
21
- parent::__construct(
22
- array(
23
- 'logo_url' => wp_mail_smtp()->plugin_url . '/assets/images/php.png',
24
- 'slug' => 'mail',
25
- 'title' => esc_html__( 'Default (none)', 'wp-mail-smtp' ),
26
- )
27
- );
28
- }
29
-
30
- /**
31
- * @inheritdoc
32
- */
33
- public function display_options() {
34
- ?>
35
-
36
- <blockquote>
37
- <?php esc_html_e( 'You currently have the native WordPress option selected. Please select any other Mailer option above to continue the setup.', 'wp-mail-smtp' ); ?>
38
- </blockquote>
39
-
40
- <?php
41
- }
42
- }
1
+ <?php
2
+
3
+ namespace WPMailSMTP\Providers\Mail;
4
+
5
+ use WPMailSMTP\Providers\OptionAbstract;
6
+
7
+ /**
8
+ * Class Option.
9
+ *
10
+ * @since 1.0.0
11
+ */
12
+ class Options extends OptionAbstract {
13
+
14
+ /**
15
+ * Mail constructor.
16
+ *
17
+ * @since 1.0.0
18
+ */
19
+ public function __construct() {
20
+
21
+ parent::__construct(
22
+ array(
23
+ 'logo_url' => wp_mail_smtp()->plugin_url . '/assets/images/php.png',
24
+ 'slug' => 'mail',
25
+ 'title' => esc_html__( 'Default (none)', 'wp-mail-smtp' ),
26
+ )
27
+ );
28
+ }
29
+
30
+ /**
31
+ * @inheritdoc
32
+ */
33
+ public function display_options() {
34
+ ?>
35
+
36
+ <blockquote>
37
+ <?php esc_html_e( 'You currently have the native WordPress option selected. Please select any other Mailer option above to continue the setup.', 'wp-mail-smtp' ); ?>
38
+ </blockquote>
39
+
40
+ <?php
41
+ }
42
+ }
src/Providers/MailerAbstract.php CHANGED
@@ -1,346 +1,346 @@
1
- <?php
2
-
3
- namespace WPMailSMTP\Providers;
4
-
5
- use WPMailSMTP\MailCatcher;
6
- use WPMailSMTP\Options;
7
-
8
- /**
9
- * Class MailerAbstract.
10
- *
11
- * @since 1.0.0
12
- */
13
- abstract class MailerAbstract implements MailerInterface {
14
-
15
- /**
16
- * Which response code from HTTP provider is considered to be successful?
17
- *
18
- * @var int
19
- */
20
- protected $email_sent_code = 200;
21
- /**
22
- * @var Options
23
- */
24
- protected $options;
25
- /**
26
- * @var MailCatcher
27
- */
28
- protected $phpmailer;
29
- /**
30
- * @var string
31
- */
32
- protected $mailer = '';
33
-
34
- /**
35
- * URL to make an API request to.
36
- *
37
- * @var string
38
- */
39
- protected $url = '';
40
- /**
41
- * @var array
42
- */
43
- protected $headers = array();
44
- /**
45
- * @var array
46
- */
47
- protected $body = array();
48
- /**
49
- * @var mixed
50
- */
51
- protected $response = array();
52
-
53
- /**
54
- * Mailer constructor.
55
- *
56
- * @since 1.0.0
57
- *
58
- * @param MailCatcher $phpmailer
59
- */
60
- public function __construct( MailCatcher $phpmailer ) {
61
-
62
- if ( empty( $this->url ) ) {
63
- return;
64
- }
65
-
66
- $this->options = new Options();
67
- $this->mailer = $this->options->get( 'mail', 'mailer' );
68
-
69
- $this->process_phpmailer( $phpmailer );
70
- }
71
-
72
- /**
73
- * Re-use the MailCatcher class methods and properties.
74
- *
75
- * @since 1.0.0
76
- *
77
- * @param MailCatcher $phpmailer
78
- */
79
- protected function process_phpmailer( $phpmailer ) {
80
-
81
- // Make sure that we have access to PHPMailer class methods.
82
- if ( ! $phpmailer instanceof MailCatcher ) {
83
- return;
84
- }
85
-
86
- $this->phpmailer = $phpmailer;
87
-
88
- $this->set_headers( $this->phpmailer->getCustomHeaders() );
89
- $this->set_from( $this->phpmailer->From, $this->phpmailer->FromName );
90
- $this->set_recipients(
91
- array(
92
- 'to' => $this->phpmailer->getToAddresses(),
93
- 'cc' => $this->phpmailer->getCcAddresses(),
94
- 'bcc' => $this->phpmailer->getBccAddresses(),
95
- )
96
- );
97
- $this->set_subject( $this->phpmailer->Subject );
98
- $this->set_content(
99
- array(
100
- 'html' => $this->phpmailer->Body,
101
- 'text' => $this->phpmailer->AltBody,
102
- )
103
- );
104
- $this->set_return_path( $this->phpmailer->From );
105
- $this->set_reply_to( $this->phpmailer->getReplyToAddresses() );
106
-
107
- /*
108
- * In some cases we will need to modify the internal structure
109
- * of the body content, if attachments are present.
110
- * So lets make this call the last one.
111
- */
112
- $this->set_attachments( $this->phpmailer->getAttachments() );
113
- }
114
-
115
- /**
116
- * @inheritdoc
117
- */
118
- public function set_subject( $subject ) {
119
-
120
- $this->set_body_param(
121
- array(
122
- 'subject' => $subject,
123
- )
124
- );
125
- }
126
-
127
- /**
128
- * Set the request params, that goes to the body of the HTTP request.
129
- *
130
- * @since 1.0.0
131
- *
132
- * @param array $param Key=>value of what should be sent to a 3rd party API.
133
- *
134
- * @internal param array $params
135
- */
136
- protected function set_body_param( $param ) {
137
- $this->body = $this->array_merge_recursive( $this->body, $param );
138
- }
139
-
140
- /**
141
- * @inheritdoc
142
- */
143
- public function set_headers( $headers ) {
144
-
145
- foreach ( $headers as $header ) {
146
- $name = isset( $header[0] ) ? $header[0] : false;
147
- $value = isset( $header[1] ) ? $header[1] : false;
148
-
149
- if ( empty( $name ) || empty( $value ) ) {
150
- continue;
151
- }
152
-
153
- $this->set_header( $name, $value );
154
- }
155
- }
156
-
157
- /**
158
- * @inheritdoc
159
- */
160
- public function set_header( $name, $value ) {
161
-
162
- $process_value = function ( $value ) {
163
- // Remove HTML tags.
164
- $filtered = wp_strip_all_tags( $value, false );
165
- // Remove multi-lines/tabs.
166
- $filtered = preg_replace( '/[\r\n\t ]+/', ' ', $filtered );
167
- // Remove whitespaces.
168
- $filtered = trim( $filtered );
169
-
170
- // Remove octets.
171
- $found = false;
172
- while ( preg_match( '/%[a-f0-9]{2}/i', $filtered, $match ) ) {
173
- $filtered = str_replace( $match[0], '', $filtered );
174
- $found = true;
175
- }
176
-
177
- if ( $found ) {
178
- // Strip out the whitespace that may now exist after removing the octets.
179
- $filtered = trim( preg_replace( '/ +/', ' ', $filtered ) );
180
- }
181
-
182
- return $filtered;
183
- };
184
-
185
- $name = sanitize_text_field( $name );
186
- if ( empty( $name ) ) {
187
- return;
188
- }
189
-
190
- $value = $process_value( $value );
191
-
192
- $this->headers[ $name ] = $value;
193
- }
194
-
195
- /**
196
- * @inheritdoc
197
- */
198
- public function get_body() {
199
- return apply_filters( 'wp_mail_smtp_providers_mailer_get_body', $this->body );
200
- }
201
-
202
- /**
203
- * @inheritdoc
204
- */
205
- public function get_headers() {
206
- return apply_filters( 'wp_mail_smtp_providers_mailer_get_headers', $this->headers );
207
- }
208
-
209
- /**
210
- * @inheritdoc
211
- */
212
- public function send() {
213
-
214
- $params = $this->array_merge_recursive( $this->get_default_params(), array(
215
- 'headers' => $this->get_headers(),
216
- 'body' => $this->get_body(),
217
- ) );
218
-
219
- $response = wp_safe_remote_post( $this->url, $params );
220
-
221
- $this->process_response( $response );
222
- }
223
-
224
- /**
225
- * We might need to do something after the email was sent to the API.
226
- * In this method we preprocess the response from the API.
227
- *
228
- * @since 1.0.0
229
- *
230
- * @param array|\WP_Error $response
231
- */
232
- protected function process_response( $response ) {
233
-
234
- if ( is_wp_error( $response ) ) {
235
- return;
236
- }
237
-
238
- if ( isset( $response['body'] ) && $this->is_json( $response['body'] ) ) {
239
- $response['body'] = json_decode( $response['body'] );
240
- }
241
-
242
- $this->response = $response;
243
- }
244
-
245
- /**
246
- * Get the default params, required for wp_safe_remote_post().
247
- *
248
- * @since 1.0.0
249
- *
250
- * @return array
251
- */
252
- protected function get_default_params() {
253
-
254
- return apply_filters( 'wp_mail_smtp_providers_mailer_get_default_params', array(
255
- 'timeout' => 15,
256
- 'httpversion' => '1.1',
257
- 'blocking' => true,
258
- ) );
259
- }
260
-
261
- /**
262
- * @inheritdoc
263
- */
264
- public function is_email_sent() {
265
-
266
- $is_sent = false;
267
-
268
- if ( wp_remote_retrieve_response_code( $this->response ) === $this->email_sent_code ) {
269
- $is_sent = true;
270
- }
271
-
272
- return apply_filters( 'wp_mail_smtp_providers_mailer_is_email_sent', $is_sent );
273
- }
274
-
275
- /**
276
- * @inheritdoc
277
- */
278
- public function is_php_compatible() {
279
-
280
- $options = wp_mail_smtp()->get_providers()->get_options( $this->mailer );
281
-
282
- return version_compare( phpversion(), $options->get_php_version(), '>=' );
283
- }
284
-
285
- /**
286
- * Check whether the string is a JSON or not.
287
- *
288
- * @since 1.0.0
289
- *
290
- * @param string $string
291
- *
292
- * @return bool
293
- */
294
- protected function is_json( $string ) {
295
- return is_string( $string ) && is_array( json_decode( $string, true ) ) && ( json_last_error() === JSON_ERROR_NONE ) ? true : false;
296
- }
297
-
298
- /**
299
- * Merge recursively, including a proper substitution of values in sub-arrays when keys are the same.
300
- * It's more like array_merge() and array_merge_recursive() combined.
301
- *
302
- * @since 1.0.0
303
- *
304
- * @return array
305
- */
306
- protected function array_merge_recursive() {
307
-
308
- $arrays = func_get_args();
309
-
310
- if ( count( $arrays ) < 2 ) {
311
- return isset( $arrays[0] ) ? $arrays[0] : array();
312
- }
313
-
314
- $merged = array();
315
-
316
- while ( $arrays ) {
317
- $array = array_shift( $arrays );
318
-
319
- if ( ! is_array( $array ) ) {
320
- return array();
321
- }
322
-
323
- if ( empty( $array ) ) {
324
- continue;
325
- }
326
-
327
- foreach ( $array as $key => $value ) {
328
- if ( is_string( $key ) ) {
329
- if (
330
- is_array( $value ) &&
331
- array_key_exists( $key, $merged ) &&
332
- is_array( $merged[ $key ] )
333
- ) {
334
- $merged[ $key ] = call_user_func( __FUNCTION__, $merged[ $key ], $value );
335
- } else {
336
- $merged[ $key ] = $value;
337
- }
338
- } else {
339
- $merged[] = $value;
340
- }
341
- }
342
- }
343
-
344
- return $merged;
345
- }
346
- }
1
+ <?php
2
+
3
+ namespace WPMailSMTP\Providers;
4
+
5
+ use WPMailSMTP\MailCatcher;
6
+ use WPMailSMTP\Options;
7
+
8
+ /**
9
+ * Class MailerAbstract.
10
+ *
11
+ * @since 1.0.0
12
+ */
13
+ abstract class MailerAbstract implements MailerInterface {
14
+
15
+ /**
16
+ * Which response code from HTTP provider is considered to be successful?
17
+ *
18
+ * @var int
19
+ */
20
+ protected $email_sent_code = 200;
21
+ /**
22
+ * @var Options
23
+ */
24
+ protected $options;
25
+ /**
26
+ * @var MailCatcher
27
+ */
28
+ protected $phpmailer;
29
+ /**
30
+ * @var string
31
+ */
32
+ protected $mailer = '';
33
+
34
+ /**
35
+ * URL to make an API request to.
36
+ *
37
+ * @var string
38
+ */
39
+ protected $url = '';
40
+ /**
41
+ * @var array
42
+ */
43
+ protected $headers = array();
44
+ /**
45
+ * @var array
46
+ */
47
+ protected $body = array();
48
+ /**
49
+ * @var mixed
50
+ */
51
+ protected $response = array();
52
+
53
+ /**
54
+ * Mailer constructor.
55
+ *
56
+ * @since 1.0.0
57
+ *
58
+ * @param MailCatcher $phpmailer
59
+ */
60
+ public function __construct( MailCatcher $phpmailer ) {
61
+
62
+ if ( empty( $this->url ) ) {
63
+ return;
64
+ }
65
+
66
+ $this->options = new Options();
67
+ $this->mailer = $this->options->get( 'mail', 'mailer' );
68
+
69
+ $this->process_phpmailer( $phpmailer );
70
+ }
71
+
72
+ /**
73
+ * Re-use the MailCatcher class methods and properties.
74
+ *
75
+ * @since 1.0.0
76
+ *
77
+ * @param MailCatcher $phpmailer
78
+ */
79
+ protected function process_phpmailer( $phpmailer ) {
80
+
81
+ // Make sure that we have access to PHPMailer class methods.
82
+ if ( ! $phpmailer instanceof MailCatcher ) {
83
+ return;
84
+ }
85
+
86
+ $this->phpmailer = $phpmailer;
87
+
88
+ $this->set_headers( $this->phpmailer->getCustomHeaders() );
89
+ $this->set_from( $this->phpmailer->From, $this->phpmailer->FromName );
90
+ $this->set_recipients(
91
+ array(
92
+ 'to' => $this->phpmailer->getToAddresses(),
93
+ 'cc' => $this->phpmailer->getCcAddresses(),
94
+ 'bcc' => $this->phpmailer->getBccAddresses(),
95
+ )
96
+ );
97
+ $this->set_subject( $this->phpmailer->Subject );
98
+ $this->set_content(
99
+ array(
100
+ 'html' => $this->phpmailer->Body,
101
+ 'text' => $this->phpmailer->AltBody,
102
+ )
103
+ );
104
+ $this->set_return_path( $this->phpmailer->From );
105
+ $this->set_reply_to( $this->phpmailer->getReplyToAddresses() );
106
+
107
+ /*
108
+ * In some cases we will need to modify the internal structure
109
+ * of the body content, if attachments are present.
110
+ * So lets make this call the last one.
111
+ */
112
+ $this->set_attachments( $this->phpmailer->getAttachments() );
113
+ }
114
+
115
+ /**
116
+ * @inheritdoc
117
+ */
118
+ public function set_subject( $subject ) {
119
+
120
+ $this->set_body_param(
121
+ array(
122
+ 'subject' => $subject,
123
+ )
124
+ );
125
+ }
126
+
127
+ /**
128
+ * Set the request params, that goes to the body of the HTTP request.
129
+ *
130
+ * @since 1.0.0
131
+ *
132
+ * @param array $param Key=>value of what should be sent to a 3rd party API.
133
+ *
134
+ * @internal param array $params
135
+ */
136
+ protected function set_body_param( $param ) {
137
+ $this->body = $this->array_merge_recursive( $this->body, $param );
138
+ }
139
+
140
+ /**
141
+ * @inheritdoc
142
+ */
143
+ public function set_headers( $headers ) {
144
+
145
+ foreach ( $headers as $header ) {
146
+ $name = isset( $header[0] ) ? $header[0] : false;
147
+ $value = isset( $header[1] ) ? $header[1] : false;
148
+
149
+ if ( empty( $name ) || empty( $value ) ) {
150
+ continue;
151
+ }
152
+
153
+ $this->set_header( $name, $value );
154
+ }
155
+ }
156
+
157
+ /**
158
+ * @inheritdoc
159
+ */
160
+ public function set_header( $name, $value ) {
161
+
162
+ $process_value = function ( $value ) {
163
+ // Remove HTML tags.
164
+ $filtered = wp_strip_all_tags( $value, false );
165
+ // Remove multi-lines/tabs.
166
+ $filtered = preg_replace( '/[\r\n\t ]+/', ' ', $filtered );
167
+ // Remove whitespaces.
168
+ $filtered = trim( $filtered );
169
+
170
+ // Remove octets.
171
+ $found = false;
172
+ while ( preg_match( '/%[a-f0-9]{2}/i', $filtered, $match ) ) {
173
+ $filtered = str_replace( $match[0], '', $filtered );
174
+ $found = true;
175
+ }
176
+
177
+ if ( $found ) {
178
+ // Strip out the whitespace that may now exist after removing the octets.
179
+ $filtered = trim( preg_replace( '/ +/', ' ', $filtered ) );
180
+ }
181
+
182
+ return $filtered;
183
+ };
184
+
185
+ $name = sanitize_text_field( $name );
186
+ if ( empty( $name ) ) {
187
+ return;
188
+ }
189
+
190
+ $value = $process_value( $value );
191
+
192
+ $this->headers[ $name ] = $value;
193
+ }
194
+
195
+ /**
196
+ * @inheritdoc
197
+ */
198
+ public function get_body() {
199
+ return apply_filters( 'wp_mail_smtp_providers_mailer_get_body', $this->body );
200
+ }
201
+
202
+ /**
203
+ * @inheritdoc
204
+ */
205
+ public function get_headers() {
206
+ return apply_filters( 'wp_mail_smtp_providers_mailer_get_headers', $this->headers );
207
+ }
208
+
209
+ /**
210
+ * @inheritdoc
211
+ */
212
+ public function send() {
213
+
214
+ $params = $this->array_merge_recursive( $this->get_default_params(), array(
215
+ 'headers' => $this->get_headers(),
216
+ 'body' => $this->get_body(),
217
+ ) );
218
+
219
+ $response = wp_safe_remote_post( $this->url, $params );
220
+
221
+ $this->process_response( $response );
222
+ }
223
+
224
+ /**
225
+ * We might need to do something after the email was sent to the API.
226
+ * In this method we preprocess the response from the API.
227
+ *
228
+ * @since 1.0.0
229
+ *
230
+ * @param array|\WP_Error $response
231
+ */
232
+ protected function process_response( $response ) {
233
+
234
+ if ( is_wp_error( $response ) ) {
235
+ return;
236
+ }
237
+
238
+ if ( isset( $response['body'] ) && $this->is_json( $response['body'] ) ) {
239
+ $response['body'] = json_decode( $response['body'] );
240
+ }
241
+
242
+ $this->response = $response;
243
+ }
244
+
245
+ /**
246
+ * Get the default params, required for wp_safe_remote_post().
247
+ *
248
+ * @since 1.0.0
249
+ *
250
+ * @return array
251
+ */
252
+ protected function get_default_params() {
253
+
254
+ return apply_filters( 'wp_mail_smtp_providers_mailer_get_default_params', array(
255
+ 'timeout' => 15,
256
+ 'httpversion' => '1.1',
257
+ 'blocking' => true,
258
+ ) );
259
+ }
260
+
261
+ /**
262
+ * @inheritdoc
263
+ */
264
+ public function is_email_sent() {
265
+
266
+ $is_sent = false;
267
+
268
+ if ( wp_remote_retrieve_response_code( $this->response ) === $this->email_sent_code ) {
269
+ $is_sent = true;
270
+ }
271
+
272
+ return apply_filters( 'wp_mail_smtp_providers_mailer_is_email_sent', $is_sent );
273
+ }
274
+
275
+ /**
276
+ * @inheritdoc
277
+ */
278
+ public function is_php_compatible() {
279
+
280
+ $options = wp_mail_smtp()->get_providers()->get_options( $this->mailer );
281
+
282
+ return version_compare( phpversion(), $options->get_php_version(), '>=' );
283
+ }
284
+
285
+ /**
286
+ * Check whether the string is a JSON or not.
287
+ *
288
+ * @since 1.0.0
289
+ *
290
+ * @param string $string
291
+ *
292
+ * @return bool
293
+ */
294
+ protected function is_json( $string ) {
295
+ return is_string( $string ) && is_array( json_decode( $string, true ) ) && ( json_last_error() === JSON_ERROR_NONE ) ? true : false;
296
+ }
297
+
298
+ /**
299
+ * Merge recursively, including a proper substitution of values in sub-arrays when keys are the same.
300
+ * It's more like array_merge() and array_merge_recursive() combined.
301
+ *
302
+ * @since 1.0.0
303
+ *
304
+ * @return array
305
+ */
306
+ protected function array_merge_recursive() {
307
+
308
+ $arrays = func_get_args();
309
+
310
+ if ( count( $arrays ) < 2 ) {
311
+ return isset( $arrays[0] ) ? $arrays[0] : array();
312
+ }
313
+
314
+ $merged = array();
315
+
316
+ while ( $arrays ) {
317
+ $array = array_shift( $arrays );
318
+
319
+ if ( ! is_array( $array ) ) {
320
+ return array();
321
+ }
322
+
323
+ if ( empty( $array ) ) {
324
+ continue;
325
+ }
326
+
327
+ foreach ( $array as $key => $value ) {
328
+ if ( is_string( $key ) ) {
329
+ if (
330
+ is_array( $value ) &&
331
+ array_key_exists( $key, $merged ) &&
332
+ is_array( $merged[ $key ] )
333
+ ) {
334
+ $merged[ $key ] = call_user_func( __FUNCTION__, $merged[ $key ], $value );
335
+ } else {
336
+ $merged[ $key ] = $value;
337
+ }
338
+ } else {
339
+ $merged[] = $value;
340
+ }
341
+ }
342
+ }
343
+
344
+ return $merged;
345
+ }
346
+ }
src/Providers/MailerInterface.php CHANGED
@@ -1,139 +1,139 @@
1
- <?php
2
-
3
- namespace WPMailSMTP\Providers;
4
-
5
- /**
6
- * Interface MailerInterface.
7
- *
8
- * @since 1.0.0
9
- */
10
- interface MailerInterface {
11
-
12
- /**
13
- * Send the email.
14
- *
15
- * @since 1.0.0
16
- */
17
- public function send();
18
-
19
- /**
20
- * Whether the email is sent or not.
21
- * We basically check the response code from a request to provider.
22
- * Might not be 100% correct, not guarantees that email is delivered.
23
- *
24
- * @since 1.0.0
25
- *
26
- * @return bool
27
- */
28
- public function is_email_sent();
29
-
30
- /**
31
- * Whether the mailer supports the current PHP version or not.
32
- *
33
- * @since 1.0.0
34
- *
35
- * @return bool
36
- */
37
- public function is_php_compatible();
38
-
39
- /**
40
- * Set the email headers in bulk.
41
- *
42
- * @since 1.0.0
43
- *
44
- * @param array $headers
45
- */
46
- public function set_headers( $headers );
47
-
48
- /**
49
- * Set the email single header.
50
- *
51
- * @since 1.0.0
52
- *
53
- * @param string $name
54
- * @param string $value
55
- */
56
- public function set_header( $name, $value );
57
-
58
- /**
59
- * Set email FROM.
60
- *
61
- * @since 1.0.0
62
- *
63
- * @param string $email
64
- * @param string $name
65
- */
66
- public function set_from( $email, $name );
67
-
68
- /**
69
- * Set a bunch of email recipients: to, cc, bcc.
70
- *
71
- * @since 1.0.0
72
- *
73
- * @param array $recipients
74
- */
75
- public function set_recipients( $recipients );
76
-
77
- /**
78
- * Set the email subject.
79
- *
80
- * @since 1.0.0
81
- *
82
- * @param string $subject
83
- */
84
- public function set_subject( $subject );
85
-
86
- /**
87
- * Set the email content.
88
- *
89
- * @since 1.0.0
90
- *
91
- * @param string|array $content
92
- */
93
- public function set_content( $content );
94
-
95
- /**
96
- * Set the email attachments.
97
- *
98
- * @since 1.0.0
99
- *
100
- * @param array $attachments
101
- */
102
- public function set_attachments( $attachments );
103
-
104
- /**
105
- * Set the email reply_to option.
106
- *
107
- * @since 1.0.0
108
- *
109
- * @param array $reply_to
110
- */
111
- public function set_reply_to( $reply_to );
112
-
113
- /**
114
- * Set the email return_path (when supported).
115
- *
116
- * @since 1.0.0
117
- *
118
- * @param string $email
119
- */
120
- public function set_return_path( $email );
121
-
122
- /**
123
- * Get the email body.
124
- *
125
- * @since 1.0.0
126
- *
127
- * @return string|array
128
- */
129
- public function get_body();
130
-
131
- /**
132
- * Get the email headers.
133
- *
134
- * @since 1.0.0
135
- *
136
- * @return array
137
- */
138
- public function get_headers();
139
- }
1
+ <?php
2
+
3
+ namespace WPMailSMTP\Providers;
4
+
5
+ /**
6
+ * Interface MailerInterface.
7
+ *
8
+ * @since 1.0.0
9
+ */
10
+ interface MailerInterface {
11
+
12
+ /**
13
+ * Send the email.
14
+ *
15
+ * @since 1.0.0
16
+ */
17
+ public function send();
18
+
19
+ /**
20
+ * Whether the email is sent or not.
21
+ * We basically check the response code from a request to provider.
22
+ * Might not be 100% correct, not guarantees that email is delivered.
23
+ *
24
+ * @since 1.0.0
25
+ *
26
+ * @return bool
27
+ */
28
+ public function is_email_sent();
29
+
30
+ /**
31
+ * Whether the mailer supports the current PHP version or not.
32
+ *
33
+ * @since 1.0.0
34
+ *
35
+ * @return bool
36
+ */
37
+ public function is_php_compatible();
38
+
39
+ /**
40
+ * Set the email headers in bulk.
41
+ *
42
+ * @since 1.0.0
43
+ *
44
+ * @param array $headers
45
+ */
46
+ public function set_headers( $headers );
47
+
48
+ /**
49
+ * Set the email single header.
50
+ *
51
+ * @since 1.0.0
52
+ *
53
+ * @param string $name
54
+ * @param string $value
55
+ */
56
+ public function set_header( $name, $value );
57
+
58
+ /**
59
+ * Set email FROM.
60
+ *
61
+ * @since 1.0.0
62
+ *
63
+ * @param string $email
64
+ * @param string $name
65
+ */
66
+ public function set_from( $email, $name );
67
+
68
+ /**
69
+ * Set a bunch of email recipients: to, cc, bcc.
70
+ *
71
+ * @since 1.0.0
72
+ *
73
+ * @param array $recipients
74
+ */
75
+ public function set_recipients( $recipients );
76
+
77
+ /**
78
+ * Set the email subject.
79
+ *
80
+ * @since 1.0.0
81
+ *
82
+ * @param string $subject
83
+ */
84
+ public function set_subject( $subject );
85
+
86
+ /**
87
+ * Set the email content.
88
+ *
89
+ * @since 1.0.0
90
+ *
91
+ * @param string|array $content
92
+ */
93
+ public function set_content( $content );
94
+
95
+ /**
96
+ * Set the email attachments.
97
+ *
98
+ * @since 1.0.0
99
+ *
100
+ * @param array $attachments
101
+ */
102
+ public function set_attachments( $attachments );
103
+
104
+ /**
105
+ * Set the email reply_to option.
106
+ *
107
+ * @since 1.0.0
108
+ *
109
+ * @param array $reply_to
110
+ */
111
+ public function set_reply_to( $reply_to );
112
+
113
+ /**
114
+ * Set the email return_path (when supported).
115
+ *
116
+ * @since 1.0.0
117
+ *
118
+ * @param string $email
119
+ */
120
+ public function set_return_path( $email );
121
+
122
+ /**
123
+ * Get the email body.
124
+ *
125
+ * @since 1.0.0
126
+ *
127
+ * @return string|array
128
+ */
129
+ public function get_body();
130
+
131
+ /**
132
+ * Get the email headers.
133
+ *
134
+ * @since 1.0.0
135
+ *
136
+ * @return array
137
+ */
138
+ public function get_headers();
139
+ }
src/Providers/Mailgun/Mailer.php CHANGED
@@ -1,299 +1,299 @@
1
- <?php
2
-
3
- namespace WPMailSMTP\Providers\Mailgun;
4
-
5
- use WPMailSMTP\Providers\MailerAbstract;
6
-
7
- /**
8
- * Class Mailer.
9
- *
10
- * @since 1.0.0
11
- */
12
- class Mailer extends MailerAbstract {
13
-
14
- /**
15
- * Which response code from HTTP provider is considered to be successful?
16
- *
17
- * @var int
18
- */
19
- protected $email_sent_code = 200;
20
-
21
- /**
22
- * URL to make an API request to.
23
- *
24
- * @var string
25
- */
26
- protected $url = 'https://api.mailgun.net/v3/';
27
-
28
- /**
29
- * @inheritdoc
30
- */
31
- public function __construct( $phpmailer ) {
32
-
33
- // We want to prefill everything from \PHPMailer class.
34
- parent::__construct( $phpmailer );
35
-
36
- /*
37
- * Append the url with a domain,
38
- * to avoid passing the domain name as a query parameter with all requests.
39
- */
40
- $this->url .= sanitize_text_field( $this->options->get( $this->mailer, 'domain' ) . '/messages' );
41
-
42
- $this->set_header( 'Authorization', 'Basic ' . base64_encode( 'api:' . $this->options->get( $this->mailer, 'api_key' ) ) );
43
- }
44
-
45
- /**
46
- * @inheritdoc
47
- */
48
- public function set_from( $email, $name = '' ) {
49
-
50
- if ( ! filter_var( $email, FILTER_VALIDATE_EMAIL ) ) {
51
- return;
52
- }
53
-
54
- if ( ! empty( $name ) ) {
55
- $this->set_body_param(
56
- array(
57
- 'from' => $name . ' <' . $email . '>',
58
- )
59
- );
60
- } else {
61
- $this->set_body_param(
62
- array(
63
- 'from' => $email,
64
- )
65
- );
66
- }
67
- }
68
-
69
- /**
70
- * @inheritdoc
71
- */
72
- public function set_recipients( $recipients ) {
73
-
74
- if ( empty( $recipients ) ) {
75
- return;
76
- }
77
-
78
- $default = array( 'to', 'cc', 'bcc' );
79
-
80
- foreach ( $recipients as $kind => $emails ) {
81
- if (
82
- ! in_array( $kind, $default, true ) ||
83
- empty( $emails ) ||
84
- ! is_array( $emails )
85
- ) {
86
- continue;
87
- }
88
-
89
- $data = array();
90
-
91
- foreach ( $emails as $email ) {
92
- $addr = isset( $email[0] ) ? $email[0] : false;
93
- $name = isset( $email[1] ) ? $email[1] : false;
94
-
95
- if ( ! filter_var( $addr, FILTER_VALIDATE_EMAIL ) ) {
96
- continue;
97
- }
98
-
99
- if ( ! empty( $name ) ) {
100
- $data[] = $name . ' <' . $addr . '>';
101
- } else {
102
- $data[] = $addr;
103
- }
104
- }
105
-
106
- if ( ! empty( $data ) ) {
107
- $this->set_body_param(
108
- array(
109
- $kind => implode( ', ', $data ),
110
- )
111
- );
112
- }
113
- }
114
- }
115
-
116
- /**
117
- * @inheritdoc
118
- */
119
- public function set_content( $content ) {
120
-
121
- if ( is_array( $content ) ) {
122
-
123
- $default = array( 'text', 'html' );
124
-
125
- foreach ( $content as $type => $mail ) {
126
- if (
127
- ! in_array( $type, $default, true ) ||
128
- empty( $mail )
129
- ) {
130
- continue;
131
- }
132
-
133
- $this->set_body_param(
134
- array(
135
- $type => $mail,
136
- )
137
- );
138
- }
139
- } else {
140
- $type = 'text';
141
-
142
- if ( $this->phpmailer->ContentType === 'text/html' ) {
143
- $type = 'html';
144
- }
145
-
146
- if ( ! empty( $content ) ) {
147
- $this->set_body_param(
148
- array(
149
- $type => $content,
150
- )
151
- );
152
- }
153
- }
154
- }
155
-
156
- /**
157
- * It's the last one, so we can modify the whole body.
158
- *
159
- * @since 1.0.0
160
- *
161
- * @param array $attachments
162
- */
163
- public function set_attachments( $attachments ) {
164
-
165
- if ( empty( $attachments ) ) {
166
- return;
167
- }
168
-
169
- $payload = '';
170
- $data = array();
171
-
172
- foreach ( $attachments as $attachment ) {
173
- $file = false;
174
-
175
- /*
176
- * We are not using WP_Filesystem API as we can't reliably work with it.
177
- * It is not always available, same as credentials for FTP.
178
- */
179
- try {
180
- if ( is_file( $attachment[0] ) && is_readable( $attachment[0] ) ) {
181
- $file = file_get_contents( $attachment[0] );
182
- }
183
- } catch ( \Exception $e ) {
184
- $file = false;
185
- }
186
-
187
- if ( $file === false ) {
188
- continue;
189
- }
190
-
191
- $data[] = array(
192
- 'content' => $file,
193
- 'name' => $attachment[1],
194
- );
195
- }
196
-
197
- if ( ! empty( $data ) ) {
198
-
199
- // First, generate a boundary for the multipart message.
200
- $boundary = base_convert( uniqid( 'boundary', true ), 10, 36 );
201
-
202
- // Iterate through pre-built params and build a payload.
203
- foreach ( $this->body as $key => $value ) {
204
- if ( is_array( $value ) ) {
205
- foreach ( $value as $child_key => $child_value ) {
206
- $payload .= '--' . $boundary;
207
- $payload .= "\r\n";
208
- $payload .= 'Content-Disposition: form-data; name="' . $key . "\"\r\n\r\n";
209
- $payload .= $child_value;
210
- $payload .= "\r\n";
211
- }
212
- } else {
213
- $payload .= '--' . $boundary;
214
- $payload .= "\r\n";
215
- $payload .= 'Content-Disposition: form-data; name="' . $key . '"' . "\r\n\r\n";
216
- $payload .= $value;
217
- $payload .= "\r\n";
218
- }
219
- }
220
-
221
- // Now iterate through our attachments, and add them too.
222
- foreach ( $data as $key => $attachment ) {
223
- $payload .= '--' . $boundary;
224
- $payload .= "\r\n";
225
- $payload .= 'Content-Disposition: form-data; name="attachment[' . $key . ']"; filename="' . $attachment['name'] . '"' . "\r\n\r\n";
226
- $payload .= $attachment['content'];
227
- $payload .= "\r\n";
228
- }
229
-
230
- $payload .= '--' . $boundary . '--';
231
-
232
- // Redefine the body the "dirty way".
233
- $this->body = $payload;
234
-
235
- $this->set_header( 'Content-Type', 'multipart/form-data; boundary=' . $boundary );
236
- }
237
- }
238
-
239
- /**
240
- * @inheritdoc
241
- */
242
- public function set_reply_to( $reply_to ) {
243
-
244
- if ( empty( $reply_to ) ) {
245
- return;
246
- }
247
-
248
- $data = array();
249
-
250
- foreach ( $reply_to as $key => $emails ) {
251
- if (
252
- empty( $emails ) ||
253
- ! is_array( $emails )
254
- ) {
255
- continue;
256
- }
257
-
258
- $addr = isset( $emails[0] ) ? $emails[0] : false;
259
- $name = isset( $emails[1] ) ? $emails[1] : false;
260
-
261
- if ( ! filter_var( $addr, FILTER_VALIDATE_EMAIL ) ) {
262
- continue;
263
- }
264
-
265
- if ( ! empty( $name ) ) {
266
- $data[] = $name . ' <' . $addr . '>';
267
- } else {
268
- $data[] = $addr;
269
- }
270
- }
271
-
272
- if ( ! empty( $data ) ) {
273
- $this->set_body_param(
274
- array(
275
- 'h:Reply-To' => implode( ',', $data ),
276
- )
277
- );
278
- }
279
- }
280
-
281
- /**
282
- * @inheritdoc
283
- */
284
- public function set_return_path( $email ) {
285
-
286
- if (
287
- $this->options->get( 'mail', 'return_path' ) !== true ||
288
- ! filter_var( $email, FILTER_VALIDATE_EMAIL )
289
- ) {
290
- return;
291
- }
292
-
293
- $this->set_body_param(
294
- array(
295
- 'sender' => $email,
296
- )
297
- );
298
- }
299
- }
1
+ <?php
2
+
3
+ namespace WPMailSMTP\Providers\Mailgun;
4
+
5
+ use WPMailSMTP\Providers\MailerAbstract;
6
+
7
+ /**
8
+ * Class Mailer.
9
+ *
10
+ * @since 1.0.0
11
+ */
12
+ class Mailer extends MailerAbstract {
13
+
14
+ /**
15
+ * Which response code from HTTP provider is considered to be successful?
16
+ *
17
+ * @var int
18
+ */
19
+ protected $email_sent_code = 200;
20
+
21
+ /**
22
+ * URL to make an API request to.
23
+ *
24
+ * @var string
25
+ */
26
+ protected $url = 'https://api.mailgun.net/v3/';
27
+
28
+ /**
29
+ * @inheritdoc
30
+ */
31
+ public function __construct( $phpmailer ) {
32
+
33
+ // We want to prefill everything from \PHPMailer class.
34
+ parent::__construct( $phpmailer );
35
+
36
+ /*
37
+ * Append the url with a domain,
38
+ * to avoid passing the domain name as a query parameter with all requests.
39
+ */
40
+ $this->url .= sanitize_text_field( $this->options->get( $this->mailer, 'domain' ) . '/messages' );
41
+
42
+ $this->set_header( 'Authorization', 'Basic ' . base64_encode( 'api:' . $this->options->get( $this->mailer, 'api_key' ) ) );
43
+ }
44
+
45
+ /**
46
+ * @inheritdoc
47
+ */
48
+ public function set_from( $email, $name = '' ) {
49
+
50
+ if ( ! filter_var( $email, FILTER_VALIDATE_EMAIL ) ) {
51
+ return;
52
+ }
53
+
54
+ if ( ! empty( $name ) ) {
55
+ $this->set_body_param(
56
+ array(
57
+ 'from' => $name . ' <' . $email . '>',
58
+ )
59
+ );
60
+ } else {
61
+ $this->set_body_param(
62
+ array(
63
+ 'from' => $email,
64
+ )
65
+ );
66
+ }
67
+ }
68
+
69
+ /**
70
+ * @inheritdoc
71
+ */
72
+ public function set_recipients( $recipients ) {
73
+
74
+ if ( empty( $recipients ) ) {
75
+ return;
76
+ }
77
+
78
+ $default = array( 'to', 'cc', 'bcc' );
79
+
80
+ foreach ( $recipients as $kind => $emails ) {
81
+ if (
82
+ ! in_array( $kind, $default, true ) ||
83
+ empty( $emails ) ||
84
+ ! is_array( $emails )
85
+ ) {
86
+ continue;
87
+ }
88
+
89
+ $data = array();
90
+
91
+ foreach ( $emails as $email ) {
92
+ $addr = isset( $email[0] ) ? $email[0] : false;
93
+ $name = isset( $email[1] ) ? $email[1] : false;
94
+
95
+ if ( ! filter_var( $addr, FILTER_VALIDATE_EMAIL ) ) {
96
+ continue;
97
+ }
98
+
99
+ if ( ! empty( $name ) ) {
100
+ $data[] = $name . ' <' . $addr . '>';
101
+ } else {
102
+ $data[] = $addr;
103
+ }
104
+ }
105
+
106
+ if ( ! empty( $data ) ) {
107
+ $this->set_body_param(
108
+ array(
109
+ $kind => implode( ', ', $data ),
110
+ )
111
+ );
112
+ }
113
+ }
114
+ }
115
+
116
+ /**
117
+ * @inheritdoc
118
+ */
119
+ public function set_content( $content ) {
120
+
121
+ if ( is_array( $content ) ) {
122
+
123
+ $default = array( 'text', 'html' );
124
+
125
+ foreach ( $content as $type => $mail ) {
126
+ if (
127
+ ! in_array( $type, $default, true ) ||
128
+ empty( $mail )
129
+ ) {
130
+ continue;
131
+ }
132
+
133
+ $this->set_body_param(
134
+ array(
135
+ $type => $mail,
136
+ )
137
+ );
138
+ }
139
+ } else {
140
+ $type = 'text';
141
+
142
+ if ( $this->phpmailer->ContentType === 'text/html' ) {
143
+ $type = 'html';
144
+ }
145
+
146
+ if ( ! empty( $content ) ) {
147
+ $this->set_body_param(
148
+ array(
149
+ $type => $content,
150
+ )
151
+ );
152
+ }
153
+ }
154
+ }
155
+
156
+ /**
157
+ * It's the last one, so we can modify the whole body.
158
+ *
159
+ * @since 1.0.0
160
+ *
161
+ * @param array $attachments
162
+ */
163
+ public function set_attachments( $attachments ) {
164
+
165
+ if ( empty( $attachments ) ) {
166
+ return;
167
+ }
168
+
169
+ $payload = '';
170
+ $data = array();
171
+
172
+ foreach ( $attachments as $attachment ) {
173
+ $file = false;
174
+
175
+ /*
176
+ * We are not using WP_Filesystem API as we can't reliably work with it.
177
+ * It is not always available, same as credentials for FTP.
178
+ */
179
+ try {
180
+ if ( is_file( $attachment[0] ) && is_readable( $attachment[0] ) ) {
181
+ $file = file_get_contents( $attachment[0] );
182
+ }
183
+ } catch ( \Exception $e ) {
184
+ $file = false;
185
+ }
186
+
187
+ if ( $file === false ) {
188
+ continue;
189
+ }
190
+
191
+ $data[] = array(
192
+ 'content' => $file,
193
+ 'name' => $attachment[1],
194
+ );
195
+ }
196
+
197
+ if ( ! empty( $data ) ) {
198
+
199
+ // First, generate a boundary for the multipart message.
200
+ $boundary = base_convert( uniqid( 'boundary', true ), 10, 36 );
201
+
202
+ // Iterate through pre-built params and build a payload.
203
+ foreach ( $this->body as $key => $value ) {
204
+ if ( is_array( $value ) ) {
205
+ foreach ( $value as $child_key => $child_value ) {
206
+ $payload .= '--' . $boundary;
207
+ $payload .= "\r\n";
208
+ $payload .= 'Content-Disposition: form-data; name="' . $key . "\"\r\n\r\n";
209
+ $payload .= $child_value;
210
+ $payload .= "\r\n";
211
+ }
212
+ } else {
213
+ $payload .= '--' . $boundary;
214
+ $payload .= "\r\n";
215
+ $payload .= 'Content-Disposition: form-data; name="' . $key . '"' . "\r\n\r\n";
216
+ $payload .= $value;
217
+ $payload .= "\r\n";
218
+ }
219
+ }
220
+
221
+ // Now iterate through our attachments, and add them too.
222
+ foreach ( $data as $key => $attachment ) {
223
+ $payload .= '--' . $boundary;
224
+ $payload .= "\r\n";
225
+ $payload .= 'Content-Disposition: form-data; name="attachment[' . $key . ']"; filename="' . $attachment['name'] . '"' . "\r\n\r\n";
226
+ $payload .= $attachment['content'];
227
+ $payload .= "\r\n";
228
+ }
229
+
230
+ $payload .= '--' . $boundary . '--';
231
+
232
+ // Redefine the body the "dirty way".
233
+ $this->body = $payload;
234
+
235
+ $this->set_header( 'Content-Type', 'multipart/form-data; boundary=' . $boundary );
236
+ }
237
+ }
238
+
239
+ /**
240
+ * @inheritdoc
241
+ */
242
+ public function set_reply_to( $reply_to ) {
243
+
244
+ if ( empty( $reply_to ) ) {
245
+ return;
246
+ }
247
+
248
+ $data = array();
249
+
250
+ foreach ( $reply_to as $key => $emails ) {
251
+ if (
252
+ empty( $emails ) ||
253
+ ! is_array( $emails )
254
+ ) {
255
+ continue;
256
+ }
257
+
258
+ $addr = isset( $emails[0] ) ? $emails[0] : false;
259
+ $name = isset( $emails[1] ) ? $emails[1] : false;
260
+
261
+ if ( ! filter_var( $addr, FILTER_VALIDATE_EMAIL ) ) {
262
+ continue;
263
+ }
264
+
265
+ if ( ! empty( $name ) ) {
266
+ $data[] = $name . ' <' . $addr . '>';
267
+ } else {
268
+ $data[] = $addr;
269
+ }
270
+ }
271
+
272
+ if ( ! empty( $data ) ) {
273
+ $this->set_body_param(
274
+ array(
275
+ 'h:Reply-To' => implode( ',', $data ),
276
+ )
277
+ );
278
+ }
279
+ }
280
+
281
+ /**
282
+ * @inheritdoc
283
+ */
284
+ public function set_return_path( $email ) {
285
+
286
+ if (
287
+ $this->options->get( 'mail', 'return_path' ) !== true ||
288
+ ! filter_var( $email, FILTER_VALIDATE_EMAIL )
289
+ ) {
290
+ return;
291
+ }
292
+
293
+ $this->set_body_param(
294
+ array(
295
+ 'sender' => $email,
296
+ )
297
+ );
298
+ }
299
+ }
src/Providers/Mailgun/Options.php CHANGED
@@ -1,106 +1,106 @@
1
- <?php
2
-
3
- namespace WPMailSMTP\Providers\Mailgun;
4
-
5
- use WPMailSMTP\Providers\OptionAbstract;
6
-
7
- /**
8
- * Class Option.
9
- *
10
- * @since 1.0.0
11
- */
12
- class Options extends OptionAbstract {
13
-
14
- /**
15
- * Mailgun constructor.
16
- *
17
- * @since 1.0.0
18
- */
19
- public function __construct() {
20
-
21
- parent::__construct(
22
- array(
23
- 'logo_url' => wp_mail_smtp()->plugin_url . '/assets/images/mailgun.png',
24
- 'slug' => 'mailgun',
25
- 'title' => esc_html__( 'Mailgun', 'wp-mail-smtp' ),
26
- 'description' => sprintf(
27
- wp_kses(
28
- /* translators: %1$s - opening link tag; %2$s - closing link tag; %3$s - opening link tag; %4$s - closing link tag. */
29
- __( '%1$sMailgun%2$s is one of the leading transactional email services trusted by over 10,000 website and application developers. They provide users 10,000 free emails per month.<br><br>Read our %3$sMailgun documentation%4$s to learn how to configure Mailgun and improve your email deliverability.', 'wp-mail-smtp' ),
30
- array(
31
- 'br' => array(),
32
- 'a' => array(
33
- 'href' => array(),
34
- 'rel' => array(),
35
- 'target' => array(),
36
- ),
37
- )
38
- ),
39
- '<a href="https://www.mailgun.com" target="_blank" rel="noopener noreferrer">',
40
- '</a>',
41
- '<a href="https://wpforms.com/how-to-send-wordpress-emails-with-mailgun/" target="_blank" rel="noopener noreferrer">',
42
- '</a>'
43
- ),
44
- )
45
- );
46
- }
47
-
48
- /**
49
- * @inheritdoc
50
- */
51
- public function display_options() {
52
- ?>
53
-
54
- <!-- API Key -->
55
- <div id="wp-mail-smtp-setting-row-<?php echo esc_attr( $this->get_slug() ); ?>-api_key" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-text wp-mail-smtp-clear">
56
- <div class="wp-mail-smtp-setting-label">
57
- <label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-api_key"><?php esc_html_e( 'Private API Key', 'wp-mail-smtp' ); ?></label>
58
- </div>
59
- <div class="wp-mail-smtp-setting-field">
60
- <input name="wp-mail-smtp[<?php echo esc_attr( $this->get_slug() ); ?>][api_key]" type="text"
61
- value="<?php echo esc_attr( $this->options->get( $this->get_slug(), 'api_key' ) ); ?>"
62
- <?php echo $this->options->is_const_defined( $this->get_slug(), 'api_key' ) ? 'disabled' : ''; ?>
63
- id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-api_key" spellcheck="false"
64
- />
65
- <p class="desc">
66
- <?php
67
- printf(
68
- /* translators: %s - API key link. */
69
- esc_html__( 'Follow this link to get an API Key from Mailgun: %s.', 'wp-mail-smtp' ),
70
- '<a href="https://app.mailgun.com/app/account/security" target="_blank" rel="noopener noreferrer">' .
71
- esc_html__( 'Get a Private API Key', 'wp-mail-smtp' ) .
72
- '</a>'
73
- );
74
- ?>
75
- </p>
76
- </div>
77
- </div>
78
-
79
- <!-- Domain -->
80
- <div id="wp-mail-smtp-setting-row-<?php echo esc_attr( $this->get_slug() ); ?>-domain" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-text wp-mail-smtp-clear">
81
- <div class="wp-mail-smtp-setting-label">
82
- <label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-domain"><?php esc_html_e( 'Domain Name', 'wp-mail-smtp' ); ?></label>
83
- </div>
84
- <div class="wp-mail-smtp-setting-field">
85
- <input name="wp-mail-smtp[<?php echo esc_attr( $this->get_slug() ); ?>][domain]" type="text"
86
- value="<?php echo esc_attr( $this->options->get( $this->get_slug(), 'domain' ) ); ?>"
87
- <?php echo $this->options->is_const_defined( $this->get_slug(), 'domain' ) ? 'disabled' : ''; ?>
88
- id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-domain" spellcheck="false"
89
- />
90
- <p class="desc">
91
- <?php
92
- printf(
93
- /* translators: %s - Domain Name link. */
94
- esc_html__( 'Follow this link to get a Domain Name from Mailgun: %s.', 'wp-mail-smtp' ),
95
- '<a href="https://app.mailgun.com/app/domains" target="_blank" rel="noopener noreferrer">' .
96
- esc_html__( 'Get a Domain Name', 'wp-mail-smtp' ) .
97
- '</a>'
98
- );
99
- ?>
100
- </p>
101
- </div>
102
- </div>
103
-
104
- <?php
105
- }
106
- }
1
+ <?php
2
+
3
+ namespace WPMailSMTP\Providers\Mailgun;
4
+
5
+ use WPMailSMTP\Providers\OptionAbstract;
6
+
7
+ /**
8
+ * Class Option.
9
+ *
10
+ * @since 1.0.0
11
+ */
12
+ class Options extends OptionAbstract {
13
+
14
+ /**
15
+ * Mailgun constructor.
16
+ *
17
+ * @since 1.0.0
18
+ */
19
+ public function __construct() {
20
+
21
+ parent::__construct(
22
+ array(
23
+ 'logo_url' => wp_mail_smtp()->plugin_url . '/assets/images/mailgun.png',
24
+ 'slug' => 'mailgun',
25
+ 'title' => esc_html__( 'Mailgun', 'wp-mail-smtp' ),
26
+ 'description' => sprintf(
27
+ wp_kses(
28
+ /* translators: %1$s - opening link tag; %2$s - closing link tag; %3$s - opening link tag; %4$s - closing link tag. */
29
+ __( '%1$sMailgun%2$s is one of the leading transactional email services trusted by over 10,000 website and application developers. They provide users 10,000 free emails per month.<br><br>Read our %3$sMailgun documentation%4$s to learn how to configure Mailgun and improve your email deliverability.', 'wp-mail-smtp' ),
30
+ array(
31
+ 'br' => array(),
32
+ 'a' => array(
33
+ 'href' => array(),
34
+ 'rel' => array(),
35
+ 'target' => array(),
36
+ ),
37
+ )
38
+ ),
39
+ '<a href="https://www.mailgun.com" target="_blank" rel="noopener noreferrer">',
40
+ '</a>',
41
+ '<a href="https://wpforms.com/how-to-send-wordpress-emails-with-mailgun/" target="_blank" rel="noopener noreferrer">',
42
+ '</a>'
43
+ ),
44
+ )
45
+ );
46
+ }
47
+
48
+ /**
49
+ * @inheritdoc
50
+ */
51
+ public function display_options() {
52
+ ?>
53
+
54
+ <!-- API Key -->
55
+ <div id="wp-mail-smtp-setting-row-<?php echo esc_attr( $this->get_slug() ); ?>-api_key" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-text wp-mail-smtp-clear">
56
+ <div class="wp-mail-smtp-setting-label">
57
+ <label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-api_key"><?php esc_html_e( 'Private API Key', 'wp-mail-smtp' ); ?></label>
58
+ </div>
59
+ <div class="wp-mail-smtp-setting-field">
60
+ <input name="wp-mail-smtp[<?php echo esc_attr( $this->get_slug() ); ?>][api_key]" type="text"
61
+ value="<?php echo esc_attr( $this->options->get( $this->get_slug(), 'api_key' ) ); ?>"
62
+ <?php echo $this->options->is_const_defined( $this->get_slug(), 'api_key' ) ? 'disabled' : ''; ?>
63
+ id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-api_key" spellcheck="false"
64
+ />
65
+ <p class="desc">
66
+ <?php
67
+ printf(
68
+ /* translators: %s - API key link. */
69
+ esc_html__( 'Follow this link to get an API Key from Mailgun: %s.', 'wp-mail-smtp' ),
70
+ '<a href="https://app.mailgun.com/app/account/security" target="_blank" rel="noopener noreferrer">' .
71
+ esc_html__( 'Get a Private API Key', 'wp-mail-smtp' ) .
72
+ '</a>'
73
+ );
74
+ ?>
75
+ </p>
76
+ </div>
77
+ </div>
78
+
79
+ <!-- Domain -->
80
+ <div id="wp-mail-smtp-setting-row-<?php echo esc_attr( $this->get_slug() ); ?>-domain" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-text wp-mail-smtp-clear">
81
+ <div class="wp-mail-smtp-setting-label">
82
+ <label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-domain"><?php esc_html_e( 'Domain Name', 'wp-mail-smtp' ); ?></label>
83
+ </div>
84
+ <div class="wp-mail-smtp-setting-field">
85
+ <input name="wp-mail-smtp[<?php echo esc_attr( $this->get_slug() ); ?>][domain]" type="text"
86
+ value="<?php echo esc_attr( $this->options->get( $this->get_slug(), 'domain' ) ); ?>"
87
+ <?php echo $this->options->is_const_defined( $this->get_slug(), 'domain' ) ? 'disabled' : ''; ?>
88
+ id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-domain" spellcheck="false"
89
+ />
90
+ <p class="desc">
91
+ <?php
92
+ printf(
93
+ /* translators: %s - Domain Name link. */
94
+ esc_html__( 'Follow this link to get a Domain Name from Mailgun: %s.', 'wp-mail-smtp' ),
95
+ '<a href="https://app.mailgun.com/app/domains" target="_blank" rel="noopener noreferrer">' .
96
+ esc_html__( 'Get a Domain Name', 'wp-mail-smtp' ) .
97
+ '</a>'
98
+ );
99
+ ?>
100
+ </p>
101
+ </div>
102
+ </div>
103
+
104
+ <?php
105
+ }
106
+ }
src/Providers/OptionAbstract.php CHANGED
@@ -1,291 +1,312 @@
1
- <?php
2
-
3
- namespace WPMailSMTP\Providers;
4
-
5
- use WPMailSMTP\Options;
6
-
7
- /**
8
- * Abstract Class ProviderAbstract to contain common providers functionality.
9
- *
10
- * @since 1.0.0
11
- */
12
- abstract class OptionAbstract implements OptionInterface {
13
-
14
- /**
15
- * @var string
16
- */
17
- private $logo_url = '';
18
- /**
19
- * @var string
20
- */
21
- private $slug = '';
22
- /**
23
- * @var string
24
- */
25
- private $title = '';
26
- /**
27
- * @var string
28
- */
29
- private $description = '';
30
- /**
31
- * @var string
32
- */
33
- private $php = WPMS_PHP_VER;
34
- /**
35
- * @var Options
36
- */
37
- protected $options;
38
-
39
- /**
40
- * ProviderAbstract constructor.
41
- *
42
- * @since 1.0.0
43
- *
44
- * @param array $params
45
- */
46
- public function __construct( $params ) {
47
-
48
- if (
49
- empty( $params['slug'] ) ||
50
- empty( $params['title'] )
51
- ) {
52
- return;
53
- }
54
-
55
- $this->slug = sanitize_key( $params['slug'] );
56
- $this->title = sanitize_text_field( $params['title'] );
57
-
58
- if ( ! empty( $params['description'] ) ) {
59
- $this->description = wp_kses( $params['description'],
60
- array(
61
- 'br' => array(),
62
- 'a' => array(
63
- 'href' => array(),
64
- 'rel' => array(),
65
- 'target' => array(),
66
- ),
67
- )
68
- );
69
- }
70
-
71
- if ( ! empty( $params['php'] ) ) {
72
- $this->php = sanitize_text_field( $params['php'] );
73
- }
74
-
75
- if ( ! empty( $params['logo_url'] ) ) {
76
- $this->logo_url = esc_url_raw( $params['logo_url'] );
77
- }
78
-
79
- $this->options = new Options();
80
- }
81
-
82
- /**
83
- * @inheritdoc
84
- */
85
- public function get_logo_url() {
86
- return apply_filters( 'wp_mail_smtp_providers_provider_get_logo_url', $this->logo_url, $this );
87
- }
88
-
89
- /**
90
- * @inheritdoc
91
- */
92
- public function get_slug() {
93
- return apply_filters( 'wp_mail_smtp_providers_provider_get_slug', $this->slug, $this );
94
- }
95
-
96
- /**
97
- * @inheritdoc
98
- */
99
- public function get_title() {
100
- return apply_filters( 'wp_mail_smtp_providers_provider_get_title', $this->title, $this );
101
- }
102
-
103
- /**
104
- * @inheritdoc
105
- */
106
- public function get_description() {
107
- return apply_filters( 'wp_mail_smtp_providers_provider_get_description', $this->description, $this );
108
- }
109
-
110
- /**
111
- * @inheritdoc
112
- */
113
- public function get_php_version() {
114
- return apply_filters( 'wp_mail_smtp_providers_provider_get_php_version', $this->php, $this );
115
- }
116
-
117
- /**
118
- * @inheritdoc
119
- */
120
- public function display_options() {
121
- ?>
122
-
123
- <!-- SMTP Host -->
124
- <div id="wp-mail-smtp-setting-row-<?php echo esc_attr( $this->get_slug() ); ?>-host" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-text wp-mail-smtp-clear">
125
- <div class="wp-mail-smtp-setting-label">
126
- <label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-host"><?php esc_html_e( 'SMTP Host', 'wp-mail-smtp' ); ?></label>
127
- </div>
128
- <div class="wp-mail-smtp-setting-field">
129
- <input name="wp-mail-smtp[<?php echo esc_attr( $this->get_slug() ); ?>][host]" type="text"
130
- value="<?php echo esc_attr( $this->options->get( $this->get_slug(), 'host' ) ); ?>"
131
- <?php echo $this->options->is_const_defined( $this->get_slug(), 'host' ) ? 'disabled' : ''; ?>
132
- id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-host" spellcheck="false"
133
- />
134
- </div>
135
- </div>
136
-
137
- <!-- SMTP Port -->
138
- <div id="wp-mail-smtp-setting-row-<?php echo esc_attr( $this->get_slug() ); ?>-port" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-number wp-mail-smtp-clear">
139
- <div class="wp-mail-smtp-setting-label">
140
- <label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-port"><?php esc_html_e( 'SMTP Port', 'wp-mail-smtp' ); ?></label>
141
- </div>
142
- <div class="wp-mail-smtp-setting-field">
143
- <input name="wp-mail-smtp[<?php echo esc_attr( $this->get_slug() ); ?>][port]" type="number"
144
- value="<?php echo esc_attr( $this->options->get( $this->get_slug(), 'port' ) ); ?>"
145
- <?php echo $this->options->is_const_defined( $this->get_slug(), 'port' ) ? 'disabled' : ''; ?>
146
- id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-port" class="small-text" spellcheck="false"
147
- />
148
- </div>
149
- </div>
150
-
151
- <!-- SMTP Encryption -->
152
- <div id="wp-mail-smtp-setting-row-<?php echo esc_attr( $this->get_slug() ); ?>-encryption" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-radio wp-mail-smtp-clear">
153
- <div class="wp-mail-smtp-setting-label">
154
- <label><?php esc_html_e( 'Encryption', 'wp-mail-smtp' ); ?></label>
155
- </div>
156
- <div class="wp-mail-smtp-setting-field">
157
-
158
- <label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-enc-none">
159
- <input type="radio" id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-enc-none"
160
- name="wp-mail-smtp[<?php echo esc_attr( $this->get_slug() ); ?>][encryption]" value="none"
161
- <?php echo $this->options->is_const_defined( $this->get_slug(), 'encryption' ) ? 'disabled' : ''; ?>
162
- <?php checked( 'none', $this->options->get( $this->get_slug(), 'encryption' ) ); ?>
163
- />
164
- <?php esc_html_e( 'None', 'wp-mail-smtp' ); ?>
165
- </label>
166
-
167
- <label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-enc-ssl">
168
- <input type="radio" id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-enc-ssl"
169
- name="wp-mail-smtp[<?php echo esc_attr( $this->get_slug() ); ?>][encryption]" value="ssl"
170
- <?php echo $this->options->is_const_defined( $this->get_slug(), 'encryption' ) ? 'disabled' : ''; ?>
171
- <?php checked( 'ssl', $this->options->get( $this->get_slug(), 'encryption' ) ); ?>
172
- />
173
- <?php esc_html_e( 'SSL', 'wp-mail-smtp' ); ?>
174
- </label>
175
-
176
- <label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-enc-tls">
177
- <input type="radio" id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-enc-tls"
178
- name="wp-mail-smtp[<?php echo esc_attr( $this->get_slug() ); ?>][encryption]" value="tls"
179
- <?php echo $this->options->is_const_defined( $this->get_slug(), 'encryption' ) ? 'disabled' : ''; ?>
180
- <?php checked( 'tls', $this->options->get( $this->get_slug(), 'encryption' ) ); ?>
181
- />
182
- <?php esc_html_e( 'TLS', 'wp-mail-smtp' ); ?>
183
- </label>
184
-
185
- <p class="desc">
186
- <?php esc_html_e( 'TLS is not the same as STARTTLS. For most servers SSL is the recommended option.', 'wp-mail-smtp' ); ?>
187
- </p>
188
- </div>
189
- </div>
190
-
191
-
192
- <!-- SMTP Authentication -->
193
- <div id="wp-mail-smtp-setting-row-<?php echo esc_attr( $this->get_slug() ); ?>-auth" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-checkbox-toggle wp-mail-smtp-clear">
194
- <div class="wp-mail-smtp-setting-label">
195
- <label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-auth"><?php esc_html_e( 'Authentication', 'wp-mail-smtp' ); ?></label>
196
- </div>
197
- <div class="wp-mail-smtp-setting-field">
198
- <label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-auth">
199
- <input type="checkbox" id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-auth"
200
- name="wp-mail-smtp[<?php echo esc_attr( $this->get_slug() ); ?>][auth]" value="yes"
201
- <?php echo $this->options->is_const_defined( $this->get_slug(), 'auth' ) ? 'disabled' : ''; ?>
202
- <?php checked( true, $this->options->get( $this->get_slug(), 'auth' ) ); ?>
203
- />
204
- <span class="wp-mail-smtp-setting-toggle-switch"></span>
205
- <span class="wp-mail-smtp-setting-toggle-checked-label"><?php esc_html_e( 'On', 'wp-mail-smtp' ); ?></span>
206
- <span class="wp-mail-smtp-setting-toggle-unchecked-label"><?php esc_html_e( 'Off', 'wp-mail-smtp' ); ?></span>
207
- </label>
208
- </div>
209
- </div>
210
-
211
- <!-- SMTP Username -->
212
- <div id="wp-mail-smtp-setting-row-<?php echo esc_attr( $this->get_slug() ); ?>-user" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-text wp-mail-smtp-clear <?php echo ! $this->options->is_const_defined( $this->get_slug(), 'auth' ) && ! $this->options->get( $this->get_slug(), 'auth' ) ? 'inactive' : ''; ?>">
213
- <div class="wp-mail-smtp-setting-label">
214
- <label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-user"><?php esc_html_e( 'SMTP Username', 'wp-mail-smtp' ); ?></label>
215
- </div>
216
- <div class="wp-mail-smtp-setting-field">
217
- <input name="wp-mail-smtp[<?php echo esc_attr( $this->get_slug() ); ?>][user]" type="text"
218
- value="<?php echo esc_attr( $this->options->get( $this->get_slug(), 'user' ) ); ?>"
219
- <?php echo $this->options->is_const_defined( $this->get_slug(), 'user' ) ? 'disabled' : ''; ?>
220
- id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-user" spellcheck="false" autocomplete="off"
221
- />
222
- </div>
223
- </div>
224
-
225
- <!-- SMTP Password -->
226
- <div id="wp-mail-smtp-setting-row-<?php echo esc_attr( $this->get_slug() ); ?>-pass" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-password wp-mail-smtp-clear <?php echo ! $this->options->is_const_defined( $this->get_slug(), 'auth' ) && ! $this->options->get( $this->get_slug(), 'auth' ) ? 'inactive' : ''; ?>">
227
- <div class="wp-mail-smtp-setting-label">
228
- <label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-pass"><?php esc_html_e( 'SMTP Password', 'wp-mail-smtp' ); ?></label>
229
- </div>
230
- <div class="wp-mail-smtp-setting-field">
231
- <?php if ( $this->options->is_const_defined( $this->get_slug(), 'pass' ) ) : ?>
232
- <input type="text" value="*************" disabled id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-pass"/>
233
- <?php else : ?>
234
- <input name="wp-mail-smtp[<?php echo esc_attr( $this->get_slug() ); ?>][pass]" type="password"
235
- value="<?php echo esc_attr( $this->options->get( $this->get_slug(), 'pass' ) ); ?>"
236
- id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-pass" spellcheck="false" autocomplete="off"
237
- />
238
- <p class="desc">
239
- <?php
240
- printf(
241
- /* translators: %s - wp-config.php. */
242
- esc_html__( 'The password is stored in plain text. We highly recommend you setup your password in your WordPress configuration file for improved security; to do this add the lines below to your %s file.', 'wp-mail-smtp' ),
243
- '<code>wp-config.php</code>'
244
- );
245
- ?>
246
- </p>
247
- <pre>
248
- define( 'WPMS_ON', true );
249
- define( 'WPMS_SMTP_PASS', 'your_password' );
250
- </pre>
251
- <?php endif; ?>
252
- </div>
253
- </div>
254
-
255
- <?php
256
- }
257
-
258
- /**
259
- * Check whether we can use this provider based on the PHP version.
260
- * Valid for those, that use SDK.
261
- *
262
- * @return bool
263
- */
264
- protected function is_php_correct() {
265
- return version_compare( phpversion(), $this->php, '>=' );
266
- }
267
-
268
- /**
269
- * Display a helpful message to those users, that are using an outdated version of PHP,
270
- * which is not supported by the currently selected Provider.
271
- */
272
- protected function display_php_warning() {
273
- ?>
274
-
275
- <blockquote>
276
- <?php
277
- printf(
278
- /* translators: %1$s - Provider name; %2$s - PHP version required by Provider; %3$s - current PHP version. */
279
- esc_html__( '%1$s requires PHP %2$s to work and does not support your current PHP version %3$s. Please contact your host and request a PHP upgrade to the latest one.', 'wp-mail-smtp' ),
280
- $this->title,
281
- $this->php,
282
- phpversion()
283
- )
284
- ?>
285
- <br>
286
- <?php esc_html_e( 'Meanwhile you can switch to the "Other SMTP" Mailer option.', 'wp-mail-smtp' ); ?>
287
- </blockquote>
288
-
289
- <?php
290
- }
291
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WPMailSMTP\Providers;
4
+
5
+ use WPMailSMTP\Options;
6
+
7
+ /**
8
+ * Abstract Class ProviderAbstract to contain common providers functionality.
9
+ *
10
+ * @since 1.0.0
11
+ */
12
+ abstract class OptionAbstract implements OptionInterface {
13
+
14
+ /**
15
+ * @var string
16
+ */
17
+ private $logo_url = '';
18
+ /**
19
+ * @var string
20
+ */
21
+ private $slug = '';
22
+ /**
23
+ * @var string
24
+ */
25
+ private $title = '';
26
+ /**
27
+ * @var string
28
+ */
29
+ private $description = '';
30
+ /**
31
+ * @var string
32
+ */
33
+ private $php = WPMS_PHP_VER;
34
+ /**
35
+ * @var Options
36
+ */
37
+ protected $options;
38
+
39
+ /**
40
+ * ProviderAbstract constructor.
41
+ *
42
+ * @since 1.0.0
43
+ *
44
+ * @param array $params
45
+ */
46
+ public function __construct( $params ) {
47
+
48
+ if (
49
+ empty( $params['slug'] ) ||
50
+ empty( $params['title'] )
51
+ ) {
52
+ return;
53
+ }
54
+
55
+ $this->slug = sanitize_key( $params['slug'] );
56
+ $this->title = sanitize_text_field( $params['title'] );
57
+
58
+ if ( ! empty( $params['description'] ) ) {
59
+ $this->description = wp_kses( $params['description'],
60
+ array(
61
+ 'br' => array(),
62
+ 'a' => array(
63
+ 'href' => array(),
64
+ 'rel' => array(),
65
+ 'target' => array(),
66
+ ),
67
+ )
68
+ );
69
+ }
70
+
71
+ if ( ! empty( $params['php'] ) ) {
72
+ $this->php = sanitize_text_field( $params['php'] );
73
+ }
74
+
75
+ if ( ! empty( $params['logo_url'] ) ) {
76
+ $this->logo_url = esc_url_raw( $params['logo_url'] );
77
+ }
78
+
79
+ $this->options = new Options();
80
+ }
81
+
82
+ /**
83
+ * @inheritdoc
84
+ */
85
+ public function get_logo_url() {
86
+ return apply_filters( 'wp_mail_smtp_providers_provider_get_logo_url', $this->logo_url, $this );
87
+ }
88
+
89
+ /**
90
+ * @inheritdoc
91
+ */
92
+ public function get_slug() {
93
+ return apply_filters( 'wp_mail_smtp_providers_provider_get_slug', $this->slug, $this );
94
+ }
95
+
96
+ /**
97
+ * @inheritdoc
98
+ */
99
+ public function get_title() {
100
+ return apply_filters( 'wp_mail_smtp_providers_provider_get_title', $this->title, $this );
101
+ }
102
+
103
+ /**
104
+ * @inheritdoc
105
+ */
106
+ public function get_description() {
107
+ return apply_filters( 'wp_mail_smtp_providers_provider_get_description', $this->description, $this );
108
+ }
109
+
110
+ /**
111
+ * @inheritdoc
112
+ */
113
+ public function get_php_version() {
114
+ return apply_filters( 'wp_mail_smtp_providers_provider_get_php_version', $this->php, $this );
115
+ }
116
+
117
+ /**
118
+ * @inheritdoc
119
+ */
120
+ public function display_options() {
121
+ ?>
122
+
123
+ <!-- SMTP Host -->
124
+ <div id="wp-mail-smtp-setting-row-<?php echo esc_attr( $this->get_slug() ); ?>-host" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-text wp-mail-smtp-clear">
125
+ <div class="wp-mail-smtp-setting-label">
126
+ <label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-host"><?php esc_html_e( 'SMTP Host', 'wp-mail-smtp' ); ?></label>
127
+ </div>
128
+ <div class="wp-mail-smtp-setting-field">
129
+ <input name="wp-mail-smtp[<?php echo esc_attr( $this->get_slug() ); ?>][host]" type="text"
130
+ value="<?php echo esc_attr( $this->options->get( $this->get_slug(), 'host' ) ); ?>"
131
+ <?php echo $this->options->is_const_defined( $this->get_slug(), 'host' ) ? 'disabled' : ''; ?>
132
+ id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-host" spellcheck="false"
133
+ />
134
+ </div>
135
+ </div>
136
+
137
+ <!-- SMTP Port -->
138
+ <div id="wp-mail-smtp-setting-row-<?php echo esc_attr( $this->get_slug() ); ?>-port" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-number wp-mail-smtp-clear">
139
+ <div class="wp-mail-smtp-setting-label">
140
+ <label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-port"><?php esc_html_e( 'SMTP Port', 'wp-mail-smtp' ); ?></label>
141
+ </div>
142
+ <div class="wp-mail-smtp-setting-field">
143
+ <input name="wp-mail-smtp[<?php echo esc_attr( $this->get_slug() ); ?>][port]" type="number"
144
+ value="<?php echo esc_attr( $this->options->get( $this->get_slug(), 'port' ) ); ?>"
145
+ <?php echo $this->options->is_const_defined( $this->get_slug(), 'port' ) ? 'disabled' : ''; ?>
146
+ id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-port" class="small-text" spellcheck="false"
147
+ />
148
+ </div>
149
+ </div>
150
+
151
+ <!-- SMTP Encryption -->
152
+ <div id="wp-mail-smtp-setting-row-<?php echo esc_attr( $this->get_slug() ); ?>-encryption" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-radio wp-mail-smtp-clear">
153
+ <div class="wp-mail-smtp-setting-label">
154
+ <label><?php esc_html_e( 'Encryption', 'wp-mail-smtp' ); ?></label>
155
+ </div>
156
+ <div class="wp-mail-smtp-setting-field">
157
+
158
+ <label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-enc-none">
159
+ <input type="radio" id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-enc-none"
160
+ name="wp-mail-smtp[<?php echo esc_attr( $this->get_slug() ); ?>][encryption]" value="none"
161
+ <?php echo $this->options->is_const_defined( $this->get_slug(), 'encryption' ) ? 'disabled' : ''; ?>
162
+ <?php checked( 'none', $this->options->get( $this->get_slug(), 'encryption' ) ); ?>
163
+ />
164
+ <?php esc_html_e( 'None', 'wp-mail-smtp' ); ?>
165
+ </label>
166
+
167
+ <label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-enc-ssl">
168
+ <input type="radio" id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-enc-ssl"
169
+ name="wp-mail-smtp[<?php echo esc_attr( $this->get_slug() ); ?>][encryption]" value="ssl"
170
+ <?php echo $this->options->is_const_defined( $this->get_slug(), 'encryption' ) ? 'disabled' : ''; ?>
171
+ <?php checked( 'ssl', $this->options->get( $this->get_slug(), 'encryption' ) ); ?>
172
+ />
173
+ <?php esc_html_e( 'SSL', 'wp-mail-smtp' ); ?>
174
+ </label>
175
+
176
+ <label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-enc-tls">
177
+ <input type="radio" id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-enc-tls"
178
+ name="wp-mail-smtp[<?php echo esc_attr( $this->get_slug() ); ?>][encryption]" value="tls"
179
+ <?php echo $this->options->is_const_defined( $this->get_slug(), 'encryption' ) ? 'disabled' : ''; ?>
180
+ <?php checked( 'tls', $this->options->get( $this->get_slug(), 'encryption' ) ); ?>
181
+ />
182
+ <?php esc_html_e( 'TLS', 'wp-mail-smtp' ); ?>
183
+ </label>
184
+
185
+ <p class="desc">
186
+ <?php esc_html_e( 'For most servers TLS is the recommended option. If your SMTP provider offers both SSL and TLS options, we recommend using TLS.', 'wp-mail-smtp' ); ?>
187
+ </p>
188
+ </div>
189
+ </div>
190
+
191
+ <!-- PHPMailer SMTPAutoTLS -->
192
+ <div id="wp-mail-smtp-setting-row-<?php echo esc_attr( $this->get_slug() ); ?>-autotls" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-checkbox-toggle wp-mail-smtp-clear <?php echo $this->options->is_const_defined( $this->get_slug(), 'encryption' ) || 'tls' === $this->options->get( $this->get_slug(), 'encryption' ) ? 'inactive' : ''; ?>">
193
+ <div class="wp-mail-smtp-setting-label">
194
+ <label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-autotls"><?php esc_html_e( 'Auto TLS', 'wp-mail-smtp' ); ?></label>
195
+ </div>
196
+ <div class="wp-mail-smtp-setting-field">
197
+ <label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-autotls">
198
+ <input type="checkbox" id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-autotls"
199
+ name="wp-mail-smtp[<?php echo esc_attr( $this->get_slug() ); ?>][autotls]" value="yes"
200
+ <?php echo $this->options->is_const_defined( $this->get_slug(), 'autotls' ) ? 'disabled' : ''; ?>
201
+ <?php checked( true, $this->options->get( $this->get_slug(), 'autotls' ) ); ?>
202
+ />
203
+ <span class="wp-mail-smtp-setting-toggle-switch"></span>
204
+ <span class="wp-mail-smtp-setting-toggle-checked-label"><?php esc_html_e( 'On', 'wp-mail-smtp' ); ?></span>
205
+ <span class="wp-mail-smtp-setting-toggle-unchecked-label"><?php esc_html_e( 'Off', 'wp-mail-smtp' ); ?></span>
206
+ </label>
207
+ <p class="desc">
208
+ <?php esc_html_e( 'By default TLS encryption is automatically used if the server supports it, which is recommended. In some cases, due to server misconfigurations, this can cause issues and may need to be disabled.', 'wp-mail-smtp' ); ?>
209
+ </p>
210
+ </div>
211
+ </div>
212
+
213
+ <!-- SMTP Authentication -->
214
+ <div id="wp-mail-smtp-setting-row-<?php echo esc_attr( $this->get_slug() ); ?>-auth" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-checkbox-toggle wp-mail-smtp-clear">
215
+ <div class="wp-mail-smtp-setting-label">
216
+ <label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-auth"><?php esc_html_e( 'Authentication', 'wp-mail-smtp' ); ?></label>
217
+ </div>
218
+ <div class="wp-mail-smtp-setting-field">
219
+ <label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-auth">
220
+ <input type="checkbox" id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-auth"
221
+ name="wp-mail-smtp[<?php echo esc_attr( $this->get_slug() ); ?>][auth]" value="yes"
222
+ <?php echo $this->options->is_const_defined( $this->get_slug(), 'auth' ) ? 'disabled' : ''; ?>
223
+ <?php checked( true, $this->options->get( $this->get_slug(), 'auth' ) ); ?>
224
+ />
225
+ <span class="wp-mail-smtp-setting-toggle-switch"></span>
226
+ <span class="wp-mail-smtp-setting-toggle-checked-label"><?php esc_html_e( 'On', 'wp-mail-smtp' ); ?></span>
227
+ <span class="wp-mail-smtp-setting-toggle-unchecked-label"><?php esc_html_e( 'Off', 'wp-mail-smtp' ); ?></span>
228
+ </label>
229
+ </div>
230
+ </div>
231
+
232
+ <!-- SMTP Username -->
233
+ <div id="wp-mail-smtp-setting-row-<?php echo esc_attr( $this->get_slug() ); ?>-user" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-text wp-mail-smtp-clear <?php echo ! $this->options->is_const_defined( $this->get_slug(), 'auth' ) && ! $this->options->get( $this->get_slug(), 'auth' ) ? 'inactive' : ''; ?>">
234
+ <div class="wp-mail-smtp-setting-label">
235
+ <label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-user"><?php esc_html_e( 'SMTP Username', 'wp-mail-smtp' ); ?></label>
236
+ </div>
237
+ <div class="wp-mail-smtp-setting-field">
238
+ <input name="wp-mail-smtp[<?php echo esc_attr( $this->get_slug() ); ?>][user]" type="text"
239
+ value="<?php echo esc_attr( $this->options->get( $this->get_slug(), 'user' ) ); ?>"
240
+ <?php echo $this->options->is_const_defined( $this->get_slug(), 'user' ) ? 'disabled' : ''; ?>
241
+ id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-user" spellcheck="false" autocomplete="off"
242
+ />
243
+ </div>
244
+ </div>
245
+
246
+ <!-- SMTP Password -->
247
+ <div id="wp-mail-smtp-setting-row-<?php echo esc_attr( $this->get_slug() ); ?>-pass" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-password wp-mail-smtp-clear <?php echo ! $this->options->is_const_defined( $this->get_slug(), 'auth' ) && ! $this->options->get( $this->get_slug(), 'auth' ) ? 'inactive' : ''; ?>">
248
+ <div class="wp-mail-smtp-setting-label">
249
+ <label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-pass"><?php esc_html_e( 'SMTP Password', 'wp-mail-smtp' ); ?></label>
250
+ </div>
251
+ <div class="wp-mail-smtp-setting-field">
252
+ <?php if ( $this->options->is_const_defined( $this->get_slug(), 'pass' ) ) : ?>
253
+ <input type="text" value="*************" disabled id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-pass"/>
254
+ <?php else : ?>
255
+ <input name="wp-mail-smtp[<?php echo esc_attr( $this->get_slug() ); ?>][pass]" type="password"
256
+ value="<?php echo esc_attr( $this->options->get( $this->get_slug(), 'pass' ) ); ?>"
257
+ id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-pass" spellcheck="false" autocomplete="off"
258
+ />
259
+ <p class="desc">
260
+ <?php
261
+ printf(
262
+ /* translators: %s - wp-config.php. */
263
+ esc_html__( 'The password is stored in plain text. We highly recommend you setup your password in your WordPress configuration file for improved security; to do this add the lines below to your %s file.', 'wp-mail-smtp' ),
264
+ '<code>wp-config.php</code>'
265
+ );
266
+ ?>
267
+ </p>
268
+ <pre>
269
+ define( 'WPMS_ON', true );
270
+ define( 'WPMS_SMTP_PASS', 'your_password' );
271
+ </pre>
272
+ <?php endif; ?>
273
+ </div>
274
+ </div>
275
+
276
+ <?php
277
+ }
278
+
279
+ /**
280
+ * Check whether we can use this provider based on the PHP version.
281
+ * Valid for those, that use SDK.
282
+ *
283
+ * @return bool
284
+ */
285
+ protected function is_php_correct() {
286
+ return version_compare( phpversion(), $this->php, '>=' );
287
+ }
288
+
289
+ /**
290
+ * Display a helpful message to those users, that are using an outdated version of PHP,
291
+ * which is not supported by the currently selected Provider.
292
+ */
293
+ protected function display_php_warning() {
294
+ ?>
295
+
296
+ <blockquote>
297
+ <?php
298
+ printf(
299
+ /* translators: %1$s - Provider name; %2$s - PHP version required by Provider; %3$s - current PHP version. */
300
+ esc_html__( '%1$s requires PHP %2$s to work and does not support your current PHP version %3$s. Please contact your host and request a PHP upgrade to the latest one.', 'wp-mail-smtp' ),
301
+ $this->title,
302
+ $this->php,
303
+ phpversion()
304
+ )
305
+ ?>
306
+ <br>
307
+ <?php esc_html_e( 'Meanwhile you can switch to the "Other SMTP" Mailer option.', 'wp-mail-smtp' ); ?>
308
+ </blockquote>
309
+
310
+ <?php
311
+ }
312
+ }
src/Providers/OptionInterface.php CHANGED
@@ -1,64 +1,64 @@
1
- <?php
2
-
3
- namespace WPMailSMTP\Providers;
4
-
5
- /**
6
- * Interface ProviderInterface, shared between all current and future providers.
7
- * Defines required methods across all providers.
8
- *
9
- * @since 1.0.0
10
- */
11
- interface OptionInterface {
12
-
13
- /**
14
- * Get the mailer provider slug.
15
- *
16
- * @since 1.0.0
17
- *
18
- * @return string
19
- */
20
- public function get_slug();
21
-
22
- /**
23
- * Get the mailer provider title (or name).
24
- *
25
- * @since 1.0.0
26
- *
27
- * @return string
28
- */
29
- public function get_title();
30
-
31
- /**
32
- * Get the mailer provider description.
33
- *
34
- * @since 1.0.0
35
- *
36
- * @return string
37
- */
38
- public function get_description();
39
-
40
- /**
41
- * Get the mailer provider minimum PHP version.
42
- *
43
- * @since 1.0.0
44
- *
45
- * @return string
46
- */
47
- public function get_php_version();
48
-
49
- /**
50
- * Get the mailer provider logo URL.
51
- *
52
- * @since 1.0.0
53
- *
54
- * @return string
55
- */
56
- public function get_logo_url();
57
-
58
- /**
59
- * Output the mailer provider options.
60
- *
61
- * @since 1.0.0
62
- */
63
- public function display_options();
64
- }
1
+ <?php
2
+
3
+ namespace WPMailSMTP\Providers;
4
+
5
+ /**
6
+ * Interface ProviderInterface, shared between all current and future providers.
7
+ * Defines required methods across all providers.
8
+ *
9
+ * @since 1.0.0
10
+ */
11
+ interface OptionInterface {
12
+
13
+ /**
14
+ * Get the mailer provider slug.
15
+ *
16
+ * @since 1.0.0
17
+ *
18
+ * @return string
19
+ */
20
+ public function get_slug();
21
+
22
+ /**
23
+ * Get the mailer provider title (or name).
24
+ *
25
+ * @since 1.0.0
26
+ *
27
+ * @return string
28
+ */
29
+ public function get_title();
30
+
31
+ /**
32
+ * Get the mailer provider description.
33
+ *
34
+ * @since 1.0.0
35
+ *
36
+ * @return string
37
+ */
38
+ public function get_description();
39
+
40
+ /**
41
+ * Get the mailer provider minimum PHP version.
42
+ *
43
+ * @since 1.0.0
44
+ *
45
+ * @return string
46
+ */
47
+ public function get_php_version();
48
+
49
+ /**
50
+ * Get the mailer provider logo URL.
51
+ *
52
+ * @since 1.0.0
53
+ *
54
+ * @return string
55
+ */
56
+ public function get_logo_url();
57
+
58
+ /**
59
+ * Output the mailer provider options.
60
+ *
61
+ * @since 1.0.0
62
+ */
63
+ public function display_options();
64
+ }
src/Providers/Pepipost/Options.php CHANGED
@@ -1,29 +1,29 @@
1
- <?php
2
-
3
- namespace WPMailSMTP\Providers\Pepipost;
4
-
5
- use WPMailSMTP\Providers\OptionAbstract;
6
-
7
- /**
8
- * Class Option.
9
- *
10
- * @since 1.0.0
11
- */
12
- class Option extends OptionAbstract {
13
-
14
- /**
15
- * Pepipost constructor.
16
- *
17
- * @since 1.0.0
18
- */
19
- public function __construct() {
20
-
21
- parent::__construct(
22
- array(
23
- 'logo_url' => wp_mail_smtp()->plugin_url . '/assets/images/pepipost.png',
24
- 'slug' => 'pepipost',
25
- 'title' => esc_html__( 'Pepipost', 'wp-mail-smtp' ),
26
- )
27
- );
28
- }
29
- }
1
+ <?php
2
+
3
+ namespace WPMailSMTP\Providers\Pepipost;
4
+
5
+ use WPMailSMTP\Providers\OptionAbstract;
6
+
7
+ /**
8
+ * Class Option.
9
+ *
10
+ * @since 1.0.0
11
+ */
12
+ class Option extends OptionAbstract {
13
+
14
+ /**
15
+ * Pepipost constructor.
16
+ *
17
+ * @since 1.0.0
18
+ */
19
+ public function __construct() {
20
+
21
+ parent::__construct(
22
+ array(
23
+ 'logo_url' => wp_mail_smtp()->plugin_url . '/assets/images/pepipost.png',
24
+ 'slug' => 'pepipost',
25
+ 'title' => esc_html__( 'Pepipost', 'wp-mail-smtp' ),
26
+ )
27
+ );
28
+ }
29
+ }
src/Providers/SMTP/Options.php CHANGED
@@ -1,45 +1,45 @@
1
- <?php
2
-
3
- namespace WPMailSMTP\Providers\SMTP;
4
-
5
- use WPMailSMTP\Providers\OptionAbstract;
6
-
7
- /**
8
- * Class SMTP.
9
- *
10
- * @since 1.0.0
11
- */
12
- class Options extends OptionAbstract {
13
-
14
- /**
15
- * SMTP constructor.
16
- *
17
- * @since 1.0.0
18
- */
19
- public function __construct() {
20
-
21
- parent::__construct(
22
- array(
23
- 'logo_url' => wp_mail_smtp()->plugin_url . '/assets/images/smtp.png',
24
- 'slug' => 'smtp',
25
- 'title' => esc_html__( 'Other SMTP', 'wp-mail-smtp' ),
26
- /* translators: %1$s - opening link tag; %2$s - closing link tag. */
27
- 'description' => sprintf(
28
- wp_kses(
29
- __( 'Use the SMTP details provided by your hosting provider or email service.<br><br>To see recommended settings for the popular services as well as troubleshooting tips, check out our %1$sSMTP documentation%2$s.', 'wp-mail-smtp' ),
30
- array(
31
- 'br' => array(),
32
- 'a' => array(
33
- 'href' => array(),
34
- 'rel' => array(),
35
- 'target' => array(),
36
- ),
37
- )
38
- ),
39
- '<a href="https://wpforms.com/docs/how-to-set-up-smtp-using-the-wp-mail-smtp-plugin/" target="_blank" rel="noopener noreferrer">',
40
- '</a>'
41
- ),
42
- )
43
- );
44
- }
45
- }
1
+ <?php
2
+
3
+ namespace WPMailSMTP\Providers\SMTP;
4
+
5
+ use WPMailSMTP\Providers\OptionAbstract;
6
+
7
+ /**
8
+ * Class SMTP.
9
+ *
10
+ * @since 1.0.0
11
+ */
12
+ class Options extends OptionAbstract {
13
+
14
+ /**
15
+ * SMTP constructor.
16
+ *
17
+ * @since 1.0.0
18
+ */
19
+ public function __construct() {
20
+
21
+ parent::__construct(
22
+ array(
23
+ 'logo_url' => wp_mail_smtp()->plugin_url . '/assets/images/smtp.png',
24
+ 'slug' => 'smtp',
25
+ 'title' => esc_html__( 'Other SMTP', 'wp-mail-smtp' ),
26
+ /* translators: %1$s - opening link tag; %2$s - closing link tag. */
27
+ 'description' => sprintf(
28
+ wp_kses(
29
+ __( 'Use the SMTP details provided by your hosting provider or email service.<br><br>To see recommended settings for the popular services as well as troubleshooting tips, check out our %1$sSMTP documentation%2$s.', 'wp-mail-smtp' ),
30
+ array(
31
+ 'br' => array(),
32
+ 'a' => array(
33
+ 'href' => array(),
34
+ 'rel' => array(),
35
+ 'target' => array(),
36
+ ),
37
+ )
38
+ ),
39
+ '<a href="https://wpforms.com/docs/how-to-set-up-smtp-using-the-wp-mail-smtp-plugin/" target="_blank" rel="noopener noreferrer">',
40
+ '</a>'
41
+ ),
42
+ )
43
+ );
44
+ }
45
+ }
src/Providers/Sendgrid/Mailer.php CHANGED
@@ -1,294 +1,294 @@
1
- <?php
2
-
3
- namespace WPMailSMTP\Providers\Sendgrid;
4
-
5
- use WPMailSMTP\Providers\MailerAbstract;
6
-
7
- /**
8
- * Class Mailer.
9
- *
10
- * @since 1.0.0
11
- */
12
- class Mailer extends MailerAbstract {
13
-
14
- /**
15
- * Which response code from HTTP provider is considered to be successful?
16
- *
17
- * @var int
18
- */
19
- protected $email_sent_code = 202;
20
-
21
- /**
22
- * URL to make an API request to.
23
- *
24
- * @var string
25
- */
26
- protected $url = 'https://api.sendgrid.com/v3/mail/send';
27
-
28
- /**
29
- * Mailer constructor.
30
- *
31
- * @since 1.0.0
32
- *
33
- * @param \PHPMailer $phpmailer
34
- */
35
- public function __construct( $phpmailer ) {
36
-
37
- // We want to prefill everything from \PHPMailer class.
38
- parent::__construct( $phpmailer );
39
-
40
- $this->set_header( 'Authorization', 'Bearer ' . $this->options->get( $this->mailer, 'api_key' ) );
41
- $this->set_header( 'content-type', 'application/json' );
42
- }
43
-
44
- /**
45
- * Redefine the way email body is returned.
46
- * By default we are sending an array of data.
47
- * SendGrid requires a JSON, so we encode the body.
48
- *
49
- * @since 1.0.0
50
- */
51
- public function get_body() {
52
-
53
- $body = parent::get_body();
54
-
55
- return wp_json_encode( $body );
56
- }
57
-
58
- /**
59
- * @inheritdoc
60
- */
61
- public function set_from( $email, $name = '' ) {
62
-
63
- if ( ! filter_var( $email, FILTER_VALIDATE_EMAIL ) ) {
64
- return;
65
- }
66
-
67
- $from['email'] = $email;
68
-
69
- if ( ! empty( $name ) ) {
70
- $from['name'] = $name;
71
- }
72
-
73
- $this->set_body_param(
74
- array(
75
- 'from' => $from,
76
- )
77
- );
78
- }
79
-
80
- /**
81
- * @inheritdoc
82
- */
83
- public function set_recipients( $recipients ) {
84
-
85
- if ( empty( $recipients ) ) {
86
- return;
87
- }
88
-
89
- // Allow for now only these recipient types.
90
- $default = array( 'to', 'cc', 'bcc' );
91
- $data = array();
92
-
93
- foreach ( $recipients as $type => $emails ) {
94
- if (
95
- ! in_array( $type, $default, true ) ||
96
- empty( $emails ) ||
97
- ! is_array( $emails )
98
- ) {
99
- continue;
100
- }
101
-
102
- $data[ $type ] = array();
103
-
104
- // Iterate over all emails for each type.
105
- // There might be multiple cc/to/bcc emails.
106
- foreach ( $emails as $email ) {
107
- $holder = array();
108
- $addr = isset( $email[0] ) ? $email[0] : false;
109
- $name = isset( $email[1] ) ? $email[1] : false;
110
-
111
- if ( ! filter_var( $addr, FILTER_VALIDATE_EMAIL ) ) {
112
- continue;
113
- }
114
-
115
- $holder['email'] = $addr;
116
- if ( ! empty( $name ) ) {
117
- $holder['name'] = $name;
118
- }
119
-
120
- array_push( $data[ $type ], $holder );
121
- }
122
- }
123
-
124
- if ( ! empty( $data ) ) {
125
- $this->set_body_param(
126
- array(
127
- 'personalizations' => array( $data ),
128
- )
129
- );
130
- }
131
- }
132
-
133
- /**
134
- * @inheritdoc
135
- */
136
- public function set_content( $content ) {
137
-
138
- if ( empty( $content ) ) {
139
- return;
140
- }
141
-
142
- if ( is_array( $content ) ) {
143
-
144
- $default = array( 'text', 'html' );
145
- $data = array();
146
-
147
- foreach ( $content as $type => $body ) {
148
- if (
149
- ! in_array( $type, $default, true ) ||
150
- empty( $body )
151
- ) {
152
- continue;
153
- }
154
-
155
- $content_type = 'text/plain';
156
- $content_value = $body;
157
-
158
- if ( $type === 'html' ) {
159
- $content_type = 'text/html';
160
- }
161
-
162
- $data[] = array(
163
- 'type' => $content_type,
164
- 'value' => $content_value,
165
- );
166
- }
167
-
168
- $this->set_body_param(
169
- array(
170
- 'content' => $data,
171
- )
172
- );
173
- } else {
174
- $data['type'] = 'text/plain';
175
- $data['value'] = $content;
176
-
177
- if ( $this->phpmailer->ContentType === 'text/html' ) {
178
- $data['type'] = 'text/html';
179
- }
180
-
181
- $this->set_body_param(
182
- array(
183
- 'content' => array( $data ),
184
- )
185
- );
186
- }
187
- }
188
-
189
- /**
190
- * SendGrid accepts an array of files content in body, so we will include all files and send.
191
- * Doesn't handle exceeding the limits etc, as this is done and reported be SendGrid API.
192
- *
193
- * @since 1.0.0
194
- *
195
- * @param array $attachments
196
- */
197
- public function set_attachments( $attachments ) {
198
-
199
- if ( empty( $attachments ) ) {
200
- return;
201
- }
202
-
203
- $data = array();
204
-
205
- foreach ( $attachments as $attachment ) {
206
- $file = false;
207
-
208
- /*
209
- * We are not using WP_Filesystem API as we can't reliably work with it.
210
- * It is not always available, same as credentials for FTP.
211
- */
212
- try {
213
- if ( is_file( $attachment[0] ) && is_readable( $attachment[0] ) ) {
214
- $file = file_get_contents( $attachment[0] );
215
- }
216
- } catch ( \Exception $e ) {
217
- $file = false;
218
- }
219
-
220
- if ( $file === false ) {
221
- continue;
222
- }
223
-
224
- $data[] = array(
225
- 'content' => base64_encode( $file ),
226
- 'type' => $attachment[4],
227
- 'filename' => $attachment[1],
228
- 'disposition' => $attachment[6],
229
- );
230
- }
231
-
232
- if ( ! empty( $data ) ) {
233
- $this->set_body_param(
234
- array(
235
- 'attachments' => $data,
236
- )
237
- );
238
- }
239
- }
240
-
241
- /**
242
- * @inheritdoc
243
- */
244
- public function set_reply_to( $reply_to ) {
245
-
246
- if ( empty( $reply_to ) ) {
247
- return;
248
- }
249
-
250
- $data = array();
251
-
252
- foreach ( $reply_to as $key => $emails ) {
253
- if (
254
- empty( $emails ) ||
255
- ! is_array( $emails )
256
- ) {
257
- continue;
258
- }
259
-
260
- $addr = isset( $emails[0] ) ? $emails[0] : false;
261
- $name = isset( $emails[1] ) ? $emails[1] : false;
262
-
263
- if ( ! filter_var( $addr, FILTER_VALIDATE_EMAIL ) ) {
264
- continue;
265
- }
266
-
267
- $data['email'] = $addr;
268
- if ( ! empty( $name ) ) {
269
- $data['name'] = $name;
270
- }
271
-
272
- break;
273
- }
274
-
275
- if ( ! empty( $data ) ) {
276
- $this->set_body_param(
277
- array(
278
- 'reply_to' => $data,
279
- )
280
- );
281
- }
282
- }
283
-
284
- /**
285
- * SendGrid doesn't support sender or return_path params.
286
- * So we do nothing.
287
- *
288
- * @since 1.0.0
289
- *
290
- * @param string $email
291
- */
292
- public function set_return_path( $email ) {
293
- }
294
- }
1
+ <?php
2
+
3
+ namespace WPMailSMTP\Providers\Sendgrid;
4
+
5
+ use WPMailSMTP\Providers\MailerAbstract;
6
+
7
+ /**
8
+ * Class Mailer.
9
+ *
10
+ * @since 1.0.0
11
+ */
12
+ class Mailer extends MailerAbstract {
13
+
14
+ /**
15
+ * Which response code from HTTP provider is considered to be successful?
16
+ *
17
+ * @var int
18
+ */
19
+ protected $email_sent_code = 202;
20
+
21
+ /**
22
+ * URL to make an API request to.
23
+ *
24
+ * @var string
25
+ */
26
+ protected $url = 'https://api.sendgrid.com/v3/mail/send';
27
+
28
+ /**
29
+ * Mailer constructor.
30
+ *
31
+ * @since 1.0.0
32
+ *
33
+ * @param \PHPMailer $phpmailer
34
+ */
35
+ public function __construct( $phpmailer ) {
36
+
37
+ // We want to prefill everything from \PHPMailer class.
38
+ parent::__construct( $phpmailer );
39
+
40
+ $this->set_header( 'Authorization', 'Bearer ' . $this->options->get( $this->mailer, 'api_key' ) );
41
+ $this->set_header( 'content-type', 'application/json' );
42
+ }
43
+
44
+ /**
45
+ * Redefine the way email body is returned.
46
+ * By default we are sending an array of data.
47
+ * SendGrid requires a JSON, so we encode the body.
48
+ *
49
+ * @since 1.0.0
50
+ */
51
+ public function get_body() {
52
+
53
+ $body = parent::get_body();
54
+
55
+ return wp_json_encode( $body );
56
+ }
57
+
58
+ /**
59
+ * @inheritdoc
60
+ */
61
+ public function set_from( $email, $name = '' ) {
62
+
63
+ if ( ! filter_var( $email, FILTER_VALIDATE_EMAIL ) ) {
64
+ return;
65
+ }
66
+
67
+ $from['email'] = $email;
68
+
69
+ if ( ! empty( $name ) ) {
70
+ $from['name'] = $name;
71
+ }
72
+
73
+ $this->set_body_param(
74
+ array(
75
+ 'from' => $from,
76
+ )
77
+ );
78
+ }
79
+
80
+ /**
81
+ * @inheritdoc
82
+ */
83
+ public function set_recipients( $recipients ) {
84
+
85
+ if ( empty( $recipients ) ) {
86
+ return;
87
+ }
88
+
89
+ // Allow for now only these recipient types.
90
+ $default = array( 'to', 'cc', 'bcc' );
91
+ $data = array();
92
+
93
+ foreach ( $recipients as $type => $emails ) {
94
+ if (
95
+ ! in_array( $type, $default, true ) ||
96
+ empty( $emails ) ||
97
+ ! is_array( $emails )
98
+ ) {
99
+ continue;
100
+ }
101
+
102
+ $data[ $type ] = array();
103
+
104
+ // Iterate over all emails for each type.
105
+ // There might be multiple cc/to/bcc emails.
106
+ foreach ( $emails as $email ) {
107
+ $holder = array();
108
+ $addr = isset( $email[0] ) ? $email[0] : false;
109
+ $name = isset( $email[1] ) ? $email[1] : false;
110
+
111
+ if ( ! filter_var( $addr, FILTER_VALIDATE_EMAIL ) ) {
112
+ continue;
113
+ }
114
+
115
+ $holder['email'] = $addr;
116
+ if ( ! empty( $name ) ) {
117
+ $holder['name'] = $name;
118
+ }
119
+
120
+ array_push( $data[ $type ], $holder );
121
+ }
122
+ }
123
+
124
+ if ( ! empty( $data ) ) {
125
+ $this->set_body_param(
126
+ array(
127
+ 'personalizations' => array( $data ),
128
+ )
129
+ );
130
+ }
131
+ }
132
+
133
+ /**
134
+ * @inheritdoc
135
+ */
136
+ public function set_content( $content ) {
137
+
138
+ if ( empty( $content ) ) {
139
+ return;
140
+ }
141
+
142
+ if ( is_array( $content ) ) {
143
+
144
+ $default = array( 'text', 'html' );
145
+ $data = array();
146
+
147
+ foreach ( $content as $type => $body ) {
148
+ if (
149
+ ! in_array( $type, $default, true ) ||
150
+ empty( $body )
151
+ ) {
152
+ continue;
153
+ }
154
+
155
+ $content_type = 'text/plain';
156
+ $content_value = $body;
157
+
158
+ if ( $type === 'html' ) {
159
+ $content_type = 'text/html';
160
+ }
161
+
162
+ $data[] = array(
163
+ 'type' => $content_type,
164
+ 'value' => $content_value,
165
+ );
166
+ }
167
+
168
+ $this->set_body_param(
169
+ array(
170
+ 'content' => $data,
171
+ )
172
+ );
173
+ } else {
174
+ $data['type'] = 'text/plain';
175
+ $data['value'] = $content;
176
+
177
+ if ( $this->phpmailer->ContentType === 'text/html' ) {
178
+ $data['type'] = 'text/html';
179
+ }
180
+
181
+ $this->set_body_param(
182
+ array(
183
+ 'content' => array( $data ),
184
+ )
185
+ );
186
+ }
187
+ }
188
+
189
+ /**
190
+ * SendGrid accepts an array of files content in body, so we will include all files and send.
191
+ * Doesn't handle exceeding the limits etc, as this is done and reported be SendGrid API.
192
+ *
193
+ * @since 1.0.0
194
+ *
195
+ * @param array $attachments
196
+ */
197
+ public function set_attachments( $attachments ) {
198
+
199
+ if ( empty( $attachments ) ) {
200
+ return;
201
+ }
202
+
203
+ $data = array();
204
+
205
+ foreach ( $attachments as $attachment ) {
206
+ $file = false;
207
+
208
+ /*
209
+ * We are not using WP_Filesystem API as we can't reliably work with it.
210
+ * It is not always available, same as credentials for FTP.
211
+ */
212
+ try {
213
+ if ( is_file( $attachment[0] ) && is_readable( $attachment[0] ) ) {
214
+ $file = file_get_contents( $attachment[0] );
215
+ }
216
+ } catch ( \Exception $e ) {
217
+ $file = false;
218
+ }
219
+
220
+ if ( $file === false ) {
221
+ continue;
222
+ }
223
+
224
+ $data[] = array(
225
+ 'content' => base64_encode( $file ),
226
+ 'type' => $attachment[4],
227
+ 'filename' => $attachment[1],
228
+ 'disposition' => $attachment[6],
229
+ );
230
+ }
231
+
232
+ if ( ! empty( $data ) ) {
233
+ $this->set_body_param(
234
+ array(
235
+ 'attachments' => $data,
236
+ )
237
+ );
238
+ }
239
+ }
240
+
241
+ /**
242
+ * @inheritdoc
243
+ */
244
+ public function set_reply_to( $reply_to ) {
245
+
246
+ if ( empty( $reply_to ) ) {
247
+ return;
248
+ }
249
+
250
+ $data = array();
251
+
252
+ foreach ( $reply_to as $key => $emails ) {
253
+ if (
254
+ empty( $emails ) ||
255
+ ! is_array( $emails )
256
+ ) {
257
+ continue;
258
+ }
259
+
260
+ $addr = isset( $emails[0] ) ? $emails[0] : false;
261
+ $name = isset( $emails[1] ) ? $emails[1] : false;
262
+
263
+ if ( ! filter_var( $addr, FILTER_VALIDATE_EMAIL ) ) {
264
+ continue;
265
+ }
266
+
267
+ $data['email'] = $addr;
268
+ if ( ! empty( $name ) ) {
269
+ $data['name'] = $name;
270
+ }
271
+
272
+ break;
273
+ }
274
+
275
+ if ( ! empty( $data ) ) {
276
+ $this->set_body_param(
277
+ array(
278
+ 'reply_to' => $data,
279
+ )
280
+ );
281
+ }
282
+ }
283
+
284
+ /**
285
+ * SendGrid doesn't support sender or return_path params.
286
+ * So we do nothing.
287
+ *
288
+ * @since 1.0.0
289
+ *
290
+ * @param string $email
291
+ */
292
+ public function set_return_path( $email ) {
293
+ }
294
+ }
src/Providers/Sendgrid/Options.php CHANGED
@@ -1,89 +1,89 @@
1
- <?php
2
-
3
- namespace WPMailSMTP\Providers\Sendgrid;
4
-
5
- use WPMailSMTP\Providers\OptionAbstract;
6
-
7
- /**
8
- * Class Option.
9
- *
10
- * @since 1.0.0
11
- */
12
- class Options extends OptionAbstract {
13
-
14
- /**
15
- * Options constructor.
16
- *
17
- * @since 1.0.0
18
- */
19
- public function __construct() {
20
-
21
- parent::__construct(
22
- array(
23
- 'logo_url' => wp_mail_smtp()->plugin_url . '/assets/images/sendgrid.png',
24
- 'slug' => 'sendgrid',
25
- 'title' => esc_html__( 'SendGrid', 'wp-mail-smtp' ),
26
- 'description' => sprintf(
27
- wp_kses(
28
- /* translators: %1$s - opening link tag; %2$s - closing link tag; %3$s - opening link tag; %4$s - closing link tag. */
29
- __( '%1$sSendGrid%2$s is one of the leading transactional email services, sending over 35 billion emails every month. They provide users 100 free emails per month.<br><br>Read our %3$sSendGrid documentation%4$s to learn how to set up SendGrid and improve your email deliverability.', 'wp-mail-smtp' ),
30
- array(
31
- 'br' => array(),
32
- 'a' => array(
33
- 'href' => array(),
34
- 'rel' => array(),
35
- 'target' => array(),
36
- ),
37
- )
38
- ),
39
- '<a href="https://sendgrid.com" target="_blank" rel="noopener noreferrer">',
40
- '</a>',
41
- '<a href="https://wpforms.com/fix-wordpress-email-notifications-with-sendgrid/" target="_blank" rel="noopener noreferrer">',
42
- '</a>'
43
- ),
44
- )
45
- );
46
- }
47
-
48
- /**
49
- * @inheritdoc
50
- */
51
- public function display_options() {
52
- ?>
53
-
54
- <!-- API Key -->
55
- <div id="wp-mail-smtp-setting-row-<?php echo esc_attr( $this->get_slug() ); ?>-api_key" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-text wp-mail-smtp-clear">
56
- <div class="wp-mail-smtp-setting-label">
57
- <label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-api_key"><?php esc_html_e( 'API Key', 'wp-mail-smtp' ); ?></label>
58
- </div>
59
- <div class="wp-mail-smtp-setting-field">
60
- <input name="wp-mail-smtp[<?php echo esc_attr( $this->get_slug() ); ?>][api_key]" type="text"
61
- value="<?php echo esc_attr( $this->options->get( $this->get_slug(), 'api_key' ) ); ?>"
62
- <?php echo $this->options->is_const_defined( $this->get_slug(), 'api_key' ) ? 'disabled' : ''; ?>
63
- id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-api_key" spellcheck="false"
64
- />
65
- <p class="desc">
66
- <?php
67
- printf(
68
- /* translators: %s - API key link. */
69
- esc_html__( 'Follow this link to get an API Key from SendGrid: %s.', 'wp-mail-smtp' ),
70
- '<a href="https://app.sendgrid.com/settings/api_keys" target="_blank" rel="noopener noreferrer">' .
71
- esc_html__( 'Create API Key', 'wp-mail-smtp' ) .
72
- '</a>'
73
- );
74
- ?>
75
- <br/>
76
- <?php
77
- printf(
78
- /* translators: %s - SendGrid access level. */
79
- esc_html__( 'To send emails you will need only a %s access level for this API key.', 'wp-mail-smtp' ),
80
- '<code>Mail Send</code>'
81
- );
82
- ?>
83
- </p>
84
- </div>
85
- </div>
86
-
87
- <?php
88
- }
89
- }
1
+ <?php
2
+
3
+ namespace WPMailSMTP\Providers\Sendgrid;
4
+
5
+ use WPMailSMTP\Providers\OptionAbstract;
6
+
7
+ /**
8
+ * Class Option.
9
+ *
10
+ * @since 1.0.0
11
+ */
12
+ class Options extends OptionAbstract {
13
+
14
+ /**
15
+ * Options constructor.
16
+ *
17
+ * @since 1.0.0
18
+ */
19
+ public function __construct() {
20
+
21
+ parent::__construct(
22
+ array(
23
+ 'logo_url' => wp_mail_smtp()->plugin_url . '/assets/images/sendgrid.png',
24
+ 'slug' => 'sendgrid',
25
+ 'title' => esc_html__( 'SendGrid', 'wp-mail-smtp' ),
26
+ 'description' => sprintf(
27
+ wp_kses(
28
+ /* translators: %1$s - opening link tag; %2$s - closing link tag; %3$s - opening link tag; %4$s - closing link tag. */
29
+ __( '%1$sSendGrid%2$s is one of the leading transactional email services, sending over 35 billion emails every month. They provide users 100 free emails per month.<br><br>Read our %3$sSendGrid documentation%4$s to learn how to set up SendGrid and improve your email deliverability.', 'wp-mail-smtp' ),
30
+ array(
31
+ 'br' => array(),
32
+ 'a' => array(
33
+ 'href' => array(),
34
+ 'rel' => array(),
35
+ 'target' => array(),
36
+ ),
37
+ )
38
+ ),
39
+ '<a href="https://sendgrid.com" target="_blank" rel="noopener noreferrer">',
40
+ '</a>',
41
+ '<a href="https://wpforms.com/fix-wordpress-email-notifications-with-sendgrid/" target="_blank" rel="noopener noreferrer">',
42
+ '</a>'
43
+ ),
44
+ )
45
+ );
46
+ }
47
+
48
+ /**
49
+ * @inheritdoc
50
+ */
51
+ public function display_options() {
52
+ ?>
53
+
54
+ <!-- API Key -->
55
+ <div id="wp-mail-smtp-setting-row-<?php echo esc_attr( $this->get_slug() ); ?>-api_key" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-text wp-mail-smtp-clear">
56
+ <div class="wp-mail-smtp-setting-label">
57
+ <label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-api_key"><?php esc_html_e( 'API Key', 'wp-mail-smtp' ); ?></label>
58
+ </div>
59
+ <div class="wp-mail-smtp-setting-field">
60
+ <input name="wp-mail-smtp[<?php echo esc_attr( $this->get_slug() ); ?>][api_key]" type="text"
61
+ value="<?php echo esc_attr( $this->options->get( $this->get_slug(), 'api_key' ) ); ?>"
62
+ <?php echo $this->options->is_const_defined( $this->get_slug(), 'api_key' ) ? 'disabled' : ''; ?>
63
+ id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-api_key" spellcheck="false"
64
+ />
65
+ <p class="desc">
66
+ <?php
67
+ printf(
68
+ /* translators: %s - API key link. */
69
+ esc_html__( 'Follow this link to get an API Key from SendGrid: %s.', 'wp-mail-smtp' ),
70
+ '<a href="https://app.sendgrid.com/settings/api_keys" target="_blank" rel="noopener noreferrer">' .
71
+ esc_html__( 'Create API Key', 'wp-mail-smtp' ) .
72
+ '</a>'
73
+ );
74
+ ?>
75
+ <br/>
76
+ <?php
77
+ printf(
78
+ /* translators: %s - SendGrid access level. */
79
+ esc_html__( 'To send emails you will need only a %s access level for this API key.', 'wp-mail-smtp' ),
80
+ '<code>Mail Send</code>'
81
+ );
82
+ ?>
83
+ </p>
84
+ </div>
85
+ </div>
86
+
87
+ <?php
88
+ }
89
+ }
src/Upgrade.php ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WPMailSMTP;
4
+
5
+ /**
6
+ * Class Upgrade helps upgrade plugin options and similar tasks when the
7
+ * occasion arises.
8
+ *
9
+ * @since 1.1.0
10
+ */
11
+ class Upgrade {
12
+
13
+ /**
14
+ * Upgrade constructor.
15
+ *
16
+ * @since 1.1.0
17
+ */
18
+ public function __construct() {
19
+
20
+ $upgrades = $this->upgrades();
21
+
22
+ if ( empty( $upgrades ) ) {
23
+ return;
24
+ }
25
+
26
+ // Run any available upgrades.
27
+ foreach ( $upgrades as $upgrade ) {
28
+ $this->{$upgrade}();
29
+ }
30
+
31
+ // Update version post upgrade(s).
32
+ update_option( 'wp_mail_smtp_version', WPMS_PLUGIN_VER );
33
+ }
34
+
35
+ /**
36
+ * Whether we need to perform an upgrade.
37
+ *
38
+ * @since 1.1.0
39
+ *
40
+ * @return array
41
+ */
42
+ protected function upgrades() {
43
+
44
+ $version = get_option( 'wp_mail_smtp_version' );
45
+ $upgrades = array();
46
+
47
+ // Version 1.1.0 upgrade; prior to this the option was not available.
48
+ if ( empty( $version ) ) {
49
+ $upgrades[] = 'v110_upgrade';
50
+ }
51
+
52
+ return $upgrades;
53
+ }
54
+
55
+ /**
56
+ * Upgrade routine for v1.1.0.
57
+ *
58
+ * Set SMTPAutoTLS to true.
59
+ *
60
+ * @since 1.1.0
61
+ */
62
+ public function v110_upgrade() {
63
+
64
+ $values = Options::init()->get_all();
65
+
66
+ // Enable SMTPAutoTLS option.
67
+ $values['smtp']['autotls'] = true;
68
+
69
+ Options::init()->set( $values );
70
+ }
71
+ }
src/WP.php CHANGED
@@ -1,140 +1,140 @@
1
- <?php
2
-
3
- namespace WPMailSMTP;
4
-
5
- /**
6
- * Class WP provides WordPress shortcuts.
7
- *
8
- * @since 1.0.0
9
- */
10
- class WP {
11
-
12
- /**
13
- * The "queue" of notices.
14
- *
15
- * @var array
16
- */
17
- protected static $admin_notices = array();
18
- /**
19
- * @var string
20
- */
21
- const ADMIN_NOTICE_SUCCESS = 'notice-success';
22
- /**
23
- * @var string
24
- */
25
- const ADMIN_NOTICE_ERROR = 'notice-error';
26
- /**
27
- * @var string
28
- */
29
- const ADMIN_NOTICE_INFO = 'notice-info';
30
- /**
31
- * @var string
32
- */
33
- const ADMIN_NOTICE_WARNING = 'notice-warning';
34
-
35
- /**
36
- * True is WP is processing an AJAX call.
37
- *
38
- * @since 1.0.0
39
- *
40
- * @return bool
41
- */
42
- public static function is_doing_ajax() {
43
-
44
- if ( function_exists( 'wp_doing_ajax' ) ) {
45
- return wp_doing_ajax();
46
- }
47
-
48
- return ( defined( 'DOING_AJAX' ) && DOING_AJAX );
49
- }
50
-
51
- /**
52
- * True if I am in the Admin Panel, not doing AJAX.
53
- *
54
- * @since 1.0.0
55
- *
56
- * @return bool
57
- */
58
- public static function in_wp_admin() {
59
- return ( is_admin() && ! self::is_doing_ajax() );
60
- }
61
-
62
- /**
63
- * Add a notice to the "queue of notices".
64
- *
65
- * @since 1.0.0
66
- *
67
- * @param string $message Message text (HTML is OK).
68
- * @param string $class Display class (severity).
69
- */
70
- public static function add_admin_notice( $message, $class = self::ADMIN_NOTICE_INFO ) {
71
-
72
- self::$admin_notices[] = array(
73
- 'message' => $message,
74
- 'class' => $class,
75
- );
76
- }
77
-
78
- /**
79
- * Display all notices.
80
- *
81
- * @since 1.0.0
82
- */
83
- public static function display_admin_notices() {
84
-
85
- foreach ( (array) self::$admin_notices as $notice ) : ?>
86
-
87
- <div id="message" class="<?php echo esc_attr( $notice['class'] ); ?> notice is-dismissible">
88
- <p>
89
- <?php echo $notice['message']; ?>
90
- </p>
91
- </div>
92
-
93
- <?php
94
- endforeach;
95
- }
96
-
97
- /**
98
- * Check whether WP_DEBUG is active.
99
- *
100
- * @since 1.0.0
101
- *
102
- * @return bool
103
- */
104
- public static function is_debug() {
105
- return defined( 'WP_DEBUG' ) && WP_DEBUG;
106
- }
107
-
108
- /**
109
- * Shortcut to global $wpdb.
110
- *
111
- * @since 1.0.0
112
- *
113
- * @return \wpdb
114
- */
115
- public static function wpdb() {
116
-
117
- global $wpdb;
118
-
119
- return $wpdb;
120
- }
121
-
122
- /**
123
- * Get the postfix for assets files - ".min" or empty.
124
- * ".min" if in production mode.
125
- *
126
- * @since 1.0.0
127
- *
128
- * @return string
129
- */
130
- public static function asset_min() {
131
-
132
- $min = '.min';
133
-
134
- if ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) {
135
- $min = '';
136
- }
137
-
138
- return $min;
139
- }
140
- }
1
+ <?php
2
+
3
+ namespace WPMailSMTP;
4
+
5
+ /**
6
+ * Class WP provides WordPress shortcuts.
7
+ *
8
+ * @since 1.0.0
9
+ */
10
+ class WP {
11
+
12
+ /**
13
+ * The "queue" of notices.
14
+ *
15
+ * @var array
16
+ */
17
+ protected static $admin_notices = array();
18
+ /**
19
+ * @var string
20
+ */
21
+ const ADMIN_NOTICE_SUCCESS = 'notice-success';
22
+ /**
23
+ * @var string
24
+ */
25
+ const ADMIN_NOTICE_ERROR = 'notice-error';
26
+ /**
27
+ * @var string
28
+ */
29
+ const ADMIN_NOTICE_INFO = 'notice-info';
30
+ /**
31
+ * @var string
32
+ */
33
+ const ADMIN_NOTICE_WARNING = 'notice-warning';
34
+
35
+ /**
36
+ * True is WP is processing an AJAX call.
37
+ *
38
+ * @since 1.0.0
39
+ *
40
+ * @return bool
41
+ */
42
+ public static function is_doing_ajax() {
43
+
44
+ if ( function_exists( 'wp_doing_ajax' ) ) {
45
+ return wp_doing_ajax();
46
+ }
47
+
48
+ return ( defined( 'DOING_AJAX' ) && DOING_AJAX );
49
+ }
50
+
51
+ /**
52
+ * True if I am in the Admin Panel, not doing AJAX.
53
+ *
54
+ * @since 1.0.0
55
+ *
56
+ * @return bool
57
+ */
58
+ public static function in_wp_admin() {
59
+ return ( is_admin() && ! self::is_doing_ajax() );
60
+ }
61
+
62
+ /**
63
+ * Add a notice to the "queue of notices".
64
+ *
65
+ * @since 1.0.0
66
+ *
67
+ * @param string $message Message text (HTML is OK).
68
+ * @param string $class Display class (severity).
69
+ */
70
+ public static function add_admin_notice( $message, $class = self::ADMIN_NOTICE_INFO ) {
71
+
72
+ self::$admin_notices[] = array(
73
+ 'message' => $message,
74
+ 'class' => $class,
75
+ );
76
+ }
77
+
78
+ /**
79
+ * Display all notices.
80
+ *
81
+ * @since 1.0.0
82
+ */
83
+ public static function display_admin_notices() {
84
+
85
+ foreach ( (array) self::$admin_notices as $notice ) : ?>
86
+
87
+ <div id="message" class="<?php echo esc_attr( $notice['class'] ); ?> notice is-dismissible">
88
+ <p>
89
+ <?php echo $notice['message']; ?>
90
+ </p>
91
+ </div>
92
+
93
+ <?php
94
+ endforeach;
95
+ }
96
+
97
+ /**
98
+ * Check whether WP_DEBUG is active.
99
+ *
100
+ * @since 1.0.0
101
+ *
102
+ * @return bool
103
+ */
104
+ public static function is_debug() {
105
+ return defined( 'WP_DEBUG' ) && WP_DEBUG;
106
+ }
107
+
108
+ /**
109
+ * Shortcut to global $wpdb.
110
+ *
111
+ * @since 1.0.0
112
+ *
113
+ * @return \wpdb
114
+ */
115
+ public static function wpdb() {
116
+
117
+ global $wpdb;
118
+
119
+ return $wpdb;
120
+ }
121
+
122
+ /**
123
+ * Get the postfix for assets files - ".min" or empty.
124
+ * ".min" if in production mode.
125
+ *
126
+ * @since 1.0.0
127
+ *
128
+ * @return string
129
+ */
130
+ public static function asset_min() {
131
+
132
+ $min = '.min';
133
+
134
+ if ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) {
135
+ $min = '';
136
+ }
137
+
138
+ return $min;
139
+ }
140
+ }
vendor/autoload.php CHANGED
@@ -2,6 +2,6 @@
2
 
3
  // autoload.php @generated by Composer
4
 
5
- require_once __DIR__ . '/composer' . '/autoload_real.php';
6
 
7
- return ComposerAutoloaderInit07e98588aa3894ff9e3dc547d403ad69::getLoader();
2
 
3
  // autoload.php @generated by Composer
4
 
5
+ require_once __DIR__ . '/composer/autoload_real.php';
6
 
7
+ return ComposerAutoloaderInitbd625bfb904527ebcdc364a59295e538::getLoader();
vendor/composer/ClassLoader.php CHANGED
@@ -53,8 +53,9 @@ class ClassLoader
53
 
54
  private $useIncludePath = false;
55
  private $classMap = array();
56
-
57
  private $classMapAuthoritative = false;
 
 
58
 
59
  public function getPrefixes()
60
  {
@@ -271,6 +272,26 @@ class ClassLoader
271
  return $this->classMapAuthoritative;
272
  }
273
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
274
  /**
275
  * Registers this instance as an autoloader.
276
  *
@@ -313,29 +334,34 @@ class ClassLoader
313
  */
314
  public function findFile($class)
315
  {
316
- // work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731
317
- if ('\\' == $class[0]) {
318
- $class = substr($class, 1);
319
- }
320
-
321
  // class map lookup
322
  if (isset($this->classMap[$class])) {
323
  return $this->classMap[$class];
324
  }
325
- if ($this->classMapAuthoritative) {
326
  return false;
327
  }
 
 
 
 
 
 
328
 
329
  $file = $this->findFileWithExtension($class, '.php');
330
 
331
  // Search for Hack files if we are running on HHVM
332
- if ($file === null && defined('HHVM_VERSION')) {
333
  $file = $this->findFileWithExtension($class, '.hh');
334
  }
335
 
336
- if ($file === null) {
 
 
 
 
337
  // Remember that this class does not exist.
338
- return $this->classMap[$class] = false;
339
  }
340
 
341
  return $file;
@@ -348,9 +374,13 @@ class ClassLoader
348
 
349
  $first = $class[0];
350
  if (isset($this->prefixLengthsPsr4[$first])) {
351
- foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) {
352
- if (0 === strpos($class, $prefix)) {
353
- foreach ($this->prefixDirsPsr4[$prefix] as $dir) {
 
 
 
 
354
  if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
355
  return $file;
356
  }
@@ -399,6 +429,8 @@ class ClassLoader
399
  if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
400
  return $file;
401
  }
 
 
402
  }
403
  }
404
 
53
 
54
  private $useIncludePath = false;
55
  private $classMap = array();
 
56
  private $classMapAuthoritative = false;
57
+ private $missingClasses = array();
58
+ private $apcuPrefix;
59
 
60
  public function getPrefixes()
61
  {
272
  return $this->classMapAuthoritative;
273
  }
274
 
275
+ /**
276
+ * APCu prefix to use to cache found/not-found classes, if the extension is enabled.
277
+ *
278
+ * @param string|null $apcuPrefix
279
+ */
280
+ public function setApcuPrefix($apcuPrefix)
281
+ {
282
+ $this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null;
283
+ }
284
+
285
+ /**
286
+ * The APCu prefix in use, or null if APCu caching is not enabled.
287
+ *
288
+ * @return string|null
289
+ */
290
+ public function getApcuPrefix()
291
+ {
292
+ return $this->apcuPrefix;
293
+ }
294
+
295
  /**
296
  * Registers this instance as an autoloader.
297
  *
334
  */
335
  public function findFile($class)
336
  {
 
 
 
 
 
337
  // class map lookup
338
  if (isset($this->classMap[$class])) {
339
  return $this->classMap[$class];
340
  }
341
+ if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
342
  return false;
343
  }
344
+ if (null !== $this->apcuPrefix) {
345
+ $file = apcu_fetch($this->apcuPrefix.$class, $hit);
346
+ if ($hit) {
347
+ return $file;
348
+ }
349
+ }
350
 
351
  $file = $this->findFileWithExtension($class, '.php');
352
 
353
  // Search for Hack files if we are running on HHVM
354
+ if (false === $file && defined('HHVM_VERSION')) {
355
  $file = $this->findFileWithExtension($class, '.hh');
356
  }
357
 
358
+ if (null !== $this->apcuPrefix) {
359
+ apcu_add($this->apcuPrefix.$class, $file);
360
+ }
361
+
362
+ if (false === $file) {
363
  // Remember that this class does not exist.
364
+ $this->missingClasses[$class] = true;
365
  }
366
 
367
  return $file;
374
 
375
  $first = $class[0];
376
  if (isset($this->prefixLengthsPsr4[$first])) {
377
+ $subPath = $class;
378
+ while (false !== $lastPos = strrpos($subPath, '\\')) {
379
+ $subPath = substr($subPath, 0, $lastPos);
380
+ $search = $subPath.'\\';
381
+ if (isset($this->prefixDirsPsr4[$search])) {
382
+ foreach ($this->prefixDirsPsr4[$search] as $dir) {
383
+ $length = $this->prefixLengthsPsr4[$first][$search];
384
  if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
385
  return $file;
386
  }
429
  if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
430
  return $file;
431
  }
432
+
433
+ return false;
434
  }
435
  }
436
 
vendor/composer/LICENSE CHANGED
@@ -1,5 +1,5 @@
1
 
2
- Copyright (c) 2016 Nils Adermann, Jordi Boggiano
3
 
4
  Permission is hereby granted, free of charge, to any person obtaining a copy
5
  of this software and associated documentation files (the "Software"), to deal
1
 
2
+ Copyright (c) Nils Adermann, Jordi Boggiano
3
 
4
  Permission is hereby granted, free of charge, to any person obtaining a copy
5
  of this software and associated documentation files (the "Software"), to deal
vendor/composer/autoload_classmap.php CHANGED
@@ -6,6 +6,234 @@ $vendorDir = dirname(dirname(__FILE__));
6
  $baseDir = dirname($vendorDir);
7
 
8
  return array(
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  'Google_Service_Exception' => $vendorDir . '/google/apiclient/src/Google/Service/Exception.php',
10
  'Google_Service_Resource' => $vendorDir . '/google/apiclient/src/Google/Service/Resource.php',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  );
6
  $baseDir = dirname($vendorDir);
7
 
8
  return array(
9
+ 'Google\\Auth\\ApplicationDefaultCredentials' => $vendorDir . '/google/auth/src/ApplicationDefaultCredentials.php',
10
+ 'Google\\Auth\\CacheTrait' => $vendorDir . '/google/auth/src/CacheTrait.php',
11
+ 'Google\\Auth\\Cache\\InvalidArgumentException' => $vendorDir . '/google/auth/src/Cache/InvalidArgumentException.php',
12
+ 'Google\\Auth\\Cache\\Item' => $vendorDir . '/google/auth/src/Cache/Item.php',
13
+ 'Google\\Auth\\Cache\\MemoryCacheItemPool' => $vendorDir . '/google/auth/src/Cache/MemoryCacheItemPool.php',
14
+ 'Google\\Auth\\CredentialsLoader' => $vendorDir . '/google/auth/src/CredentialsLoader.php',
15
+ 'Google\\Auth\\Credentials\\AppIdentityCredentials' => $vendorDir . '/google/auth/src/Credentials/AppIdentityCredentials.php',
16
+ 'Google\\Auth\\Credentials\\GCECredentials' => $vendorDir . '/google/auth/src/Credentials/GCECredentials.php',
17
+ 'Google\\Auth\\Credentials\\IAMCredentials' => $vendorDir . '/google/auth/src/Credentials/IAMCredentials.php',
18
+ 'Google\\Auth\\Credentials\\ServiceAccountCredentials' => $vendorDir . '/google/auth/src/Credentials/ServiceAccountCredentials.php',
19
+ 'Google\\Auth\\Credentials\\ServiceAccountJwtAccessCredentials' => $vendorDir . '/google/auth/src/Credentials/ServiceAccountJwtAccessCredentials.php',
20
+ 'Google\\Auth\\Credentials\\UserRefreshCredentials' => $vendorDir . '/google/auth/src/Credentials/UserRefreshCredentials.php',
21
+ 'Google\\Auth\\FetchAuthTokenCache' => $vendorDir . '/google/auth/src/FetchAuthTokenCache.php',
22
+ 'Google\\Auth\\FetchAuthTokenInterface' => $vendorDir . '/google/auth/src/FetchAuthTokenInterface.php',
23
+ 'Google\\Auth\\HttpHandler\\Guzzle5HttpHandler' => $vendorDir . '/google/auth/src/HttpHandler/Guzzle5HttpHandler.php',
24
+ 'Google\\Auth\\HttpHandler\\Guzzle6HttpHandler' => $vendorDir . '/google/auth/src/HttpHandler/Guzzle6HttpHandler.php',
25
+ 'Google\\Auth\\HttpHandler\\HttpHandlerFactory' => $vendorDir . '/google/auth/src/HttpHandler/HttpHandlerFactory.php',
26
+ 'Google\\Auth\\Middleware\\AuthTokenMiddleware' => $vendorDir . '/google/auth/src/Middleware/AuthTokenMiddleware.php',
27
+ 'Google\\Auth\\Middleware\\ScopedAccessTokenMiddleware' => $vendorDir . '/google/auth/src/Middleware/ScopedAccessTokenMiddleware.php',
28
+ 'Google\\Auth\\Middleware\\SimpleMiddleware' => $vendorDir . '/google/auth/src/Middleware/SimpleMiddleware.php',
29
+ 'Google\\Auth\\OAuth2' => $vendorDir . '/google/auth/src/OAuth2.php',
30
+ 'Google\\Auth\\Subscriber\\AuthTokenSubscriber' => $vendorDir . '/google/auth/src/Subscriber/AuthTokenSubscriber.php',
31
+ 'Google\\Auth\\Subscriber\\ScopedAccessTokenSubscriber' => $vendorDir . '/google/auth/src/Subscriber/ScopedAccessTokenSubscriber.php',
32
+ 'Google\\Auth\\Subscriber\\SimpleSubscriber' => $vendorDir . '/google/auth/src/Subscriber/SimpleSubscriber.php',
33
+ 'Google_AccessToken_Revoke' => $vendorDir . '/google/apiclient/src/Google/AccessToken/Revoke.php',
34
+ 'Google_AccessToken_Verify' => $vendorDir . '/google/apiclient/src/Google/AccessToken/Verify.php',
35
+ 'Google_AuthHandler_AuthHandlerFactory' => $vendorDir . '/google/apiclient/src/Google/AuthHandler/AuthHandlerFactory.php',
36
+ 'Google_AuthHandler_Guzzle5AuthHandler' => $vendorDir . '/google/apiclient/src/Google/AuthHandler/Guzzle5AuthHandler.php',
37
+ 'Google_AuthHandler_Guzzle6AuthHandler' => $vendorDir . '/google/apiclient/src/Google/AuthHandler/Guzzle6AuthHandler.php',
38
+ 'Google_Client' => $vendorDir . '/google/apiclient/src/Google/Client.php',
39
+ 'Google_Collection' => $vendorDir . '/google/apiclient/src/Google/Collection.php',
40
+ 'Google_Exception' => $vendorDir . '/google/apiclient/src/Google/Exception.php',
41
+ 'Google_Http_Batch' => $vendorDir . '/google/apiclient/src/Google/Http/Batch.php',
42
+ 'Google_Http_MediaFileUpload' => $vendorDir . '/google/apiclient/src/Google/Http/MediaFileUpload.php',
43
+ 'Google_Http_REST' => $vendorDir . '/google/apiclient/src/Google/Http/REST.php',
44
+ 'Google_Model' => $vendorDir . '/google/apiclient/src/Google/Model.php',
45
+ 'Google_Service' => $vendorDir . '/google/apiclient/src/Google/Service.php',
46
  'Google_Service_Exception' => $vendorDir . '/google/apiclient/src/Google/Service/Exception.php',
47
  'Google_Service_Resource' => $vendorDir . '/google/apiclient/src/Google/Service/Resource.php',
48
+ 'Google_Task_Exception' => $vendorDir . '/google/apiclient/src/Google/Task/Exception.php',
49
+ 'Google_Task_Retryable' => $vendorDir . '/google/apiclient/src/Google/Task/Retryable.php',
50
+ 'Google_Task_Runner' => $vendorDir . '/google/apiclient/src/Google/Task/Runner.php',
51
+ 'Google_Utils_UriTemplate' => $vendorDir . '/google/apiclient/src/Google/Utils/UriTemplate.php',
52
+ 'GuzzleHttp\\Client' => $vendorDir . '/guzzlehttp/guzzle/src/Client.php',
53
+ 'GuzzleHttp\\ClientInterface' => $vendorDir . '/guzzlehttp/guzzle/src/ClientInterface.php',
54
+ 'GuzzleHttp\\Cookie\\CookieJar' => $vendorDir . '/guzzlehttp/guzzle/src/Cookie/CookieJar.php',
55
+ 'GuzzleHttp\\Cookie\\CookieJarInterface' => $vendorDir . '/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php',
56
+ 'GuzzleHttp\\Cookie\\FileCookieJar' => $vendorDir . '/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php',
57
+ 'GuzzleHttp\\Cookie\\SessionCookieJar' => $vendorDir . '/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php',
58
+ 'GuzzleHttp\\Cookie\\SetCookie' => $vendorDir . '/guzzlehttp/guzzle/src/Cookie/SetCookie.php',
59
+ 'GuzzleHttp\\Exception\\BadResponseException' => $vendorDir . '/guzzlehttp/guzzle/src/Exception/BadResponseException.php',
60
+ 'GuzzleHttp\\Exception\\ClientException' => $vendorDir . '/guzzlehttp/guzzle/src/Exception/ClientException.php',
61
+ 'GuzzleHttp\\Exception\\ConnectException' => $vendorDir . '/guzzlehttp/guzzle/src/Exception/ConnectException.php',
62
+ 'GuzzleHttp\\Exception\\GuzzleException' => $vendorDir . '/guzzlehttp/guzzle/src/Exception/GuzzleException.php',
63
+ 'GuzzleHttp\\Exception\\RequestException' => $vendorDir . '/guzzlehttp/guzzle/src/Exception/RequestException.php',
64
+ 'GuzzleHttp\\Exception\\SeekException' => $vendorDir . '/guzzlehttp/guzzle/src/Exception/SeekException.php',
65
+ 'GuzzleHttp\\Exception\\ServerException' => $vendorDir . '/guzzlehttp/guzzle/src/Exception/ServerException.php',
66
+ 'GuzzleHttp\\Exception\\TooManyRedirectsException' => $vendorDir . '/guzzlehttp/guzzle/src/Exception/TooManyRedirectsException.php',
67
+ 'GuzzleHttp\\Exception\\TransferException' => $vendorDir . '/guzzlehttp/guzzle/src/Exception/TransferException.php',
68
+ 'GuzzleHttp\\HandlerStack' => $vendorDir . '/guzzlehttp/guzzle/src/HandlerStack.php',
69
+ 'GuzzleHttp\\Handler\\CurlFactory' => $vendorDir . '/guzzlehttp/guzzle/src/Handler/CurlFactory.php',
70
+ 'GuzzleHttp\\Handler\\CurlFactoryInterface' => $vendorDir . '/guzzlehttp/guzzle/src/Handler/CurlFactoryInterface.php',
71
+ 'GuzzleHttp\\Handler\\CurlHandler' => $vendorDir . '/guzzlehttp/guzzle/src/Handler/CurlHandler.php',
72
+ 'GuzzleHttp\\Handler\\CurlMultiHandler' => $vendorDir . '/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php',
73
+ 'GuzzleHttp\\Handler\\EasyHandle' => $vendorDir . '/guzzlehttp/guzzle/src/Handler/EasyHandle.php',
74
+ 'GuzzleHttp\\Handler\\MockHandler' => $vendorDir . '/guzzlehttp/guzzle/src/Handler/MockHandler.php',
75
+ 'GuzzleHttp\\Handler\\Proxy' => $vendorDir . '/guzzlehttp/guzzle/src/Handler/Proxy.php',
76
+ 'GuzzleHttp\\Handler\\StreamHandler' => $vendorDir . '/guzzlehttp/guzzle/src/Handler/StreamHandler.php',
77
+ 'GuzzleHttp\\MessageFormatter' => $vendorDir . '/guzzlehttp/guzzle/src/MessageFormatter.php',
78
+ 'GuzzleHttp\\Middleware' => $vendorDir . '/guzzlehttp/guzzle/src/Middleware.php',
79
+ 'GuzzleHttp\\Pool' => $vendorDir . '/guzzlehttp/guzzle/src/Pool.php',
80
+ 'GuzzleHttp\\PrepareBodyMiddleware' => $vendorDir . '/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php',
81
+ 'GuzzleHttp\\Promise\\AggregateException' => $vendorDir . '/guzzlehttp/promises/src/AggregateException.php',
82
+ 'GuzzleHttp\\Promise\\CancellationException' => $vendorDir . '/guzzlehttp/promises/src/CancellationException.php',
83
+ 'GuzzleHttp\\Promise\\Coroutine' => $vendorDir . '/guzzlehttp/promises/src/Coroutine.php',
84
+ 'GuzzleHttp\\Promise\\EachPromise' => $vendorDir . '/guzzlehttp/promises/src/EachPromise.php',
85
+ 'GuzzleHttp\\Promise\\FulfilledPromise' => $vendorDir . '/guzzlehttp/promises/src/FulfilledPromise.php',
86
+ 'GuzzleHttp\\Promise\\Promise' => $vendorDir . '/guzzlehttp/promises/src/Promise.php',
87
+ 'GuzzleHttp\\Promise\\PromiseInterface' => $vendorDir . '/guzzlehttp/promises/src/PromiseInterface.php',
88
+ 'GuzzleHttp\\Promise\\PromisorInterface' => $vendorDir . '/guzzlehttp/promises/src/PromisorInterface.php',
89
+ 'GuzzleHttp\\Promise\\RejectedPromise' => $vendorDir . '/guzzlehttp/promises/src/RejectedPromise.php',
90
+ 'GuzzleHttp\\Promise\\RejectionException' => $vendorDir . '/guzzlehttp/promises/src/RejectionException.php',
91
+ 'GuzzleHttp\\Promise\\TaskQueue' => $vendorDir . '/guzzlehttp/promises/src/TaskQueue.php',
92
+ 'GuzzleHttp\\Promise\\TaskQueueInterface' => $vendorDir . '/guzzlehttp/promises/src/TaskQueueInterface.php',
93
+ 'GuzzleHttp\\Psr7\\AppendStream' => $vendorDir . '/guzzlehttp/psr7/src/AppendStream.php',
94
+ 'GuzzleHttp\\Psr7\\BufferStream' => $vendorDir . '/guzzlehttp/psr7/src/BufferStream.php',
95
+ 'GuzzleHttp\\Psr7\\CachingStream' => $vendorDir . '/guzzlehttp/psr7/src/CachingStream.php',
96
+ 'GuzzleHttp\\Psr7\\DroppingStream' => $vendorDir . '/guzzlehttp/psr7/src/DroppingStream.php',
97
+ 'GuzzleHttp\\Psr7\\FnStream' => $vendorDir . '/guzzlehttp/psr7/src/FnStream.php',
98
+ 'GuzzleHttp\\Psr7\\InflateStream' => $vendorDir . '/guzzlehttp/psr7/src/InflateStream.php',
99
+ 'GuzzleHttp\\Psr7\\LazyOpenStream' => $vendorDir . '/guzzlehttp/psr7/src/LazyOpenStream.php',
100
+ 'GuzzleHttp\\Psr7\\LimitStream' => $vendorDir . '/guzzlehttp/psr7/src/LimitStream.php',
101
+ 'GuzzleHttp\\Psr7\\MessageTrait' => $vendorDir . '/guzzlehttp/psr7/src/MessageTrait.php',
102
+ 'GuzzleHttp\\Psr7\\MultipartStream' => $vendorDir . '/guzzlehttp/psr7/src/MultipartStream.php',
103
+ 'GuzzleHttp\\Psr7\\NoSeekStream' => $vendorDir . '/guzzlehttp/psr7/src/NoSeekStream.php',
104
+ 'GuzzleHttp\\Psr7\\PumpStream' => $vendorDir . '/guzzlehttp/psr7/src/PumpStream.php',
105
+ 'GuzzleHttp\\Psr7\\Request' => $vendorDir . '/guzzlehttp/psr7/src/Request.php',
106
+ 'GuzzleHttp\\Psr7\\Response' => $vendorDir . '/guzzlehttp/psr7/src/Response.php',
107
+ 'GuzzleHttp\\Psr7\\ServerRequest' => $vendorDir . '/guzzlehttp/psr7/src/ServerRequest.php',
108
+ 'GuzzleHttp\\Psr7\\Stream' => $vendorDir . '/guzzlehttp/psr7/src/Stream.php',
109
+ 'GuzzleHttp\\Psr7\\StreamDecoratorTrait' => $vendorDir . '/guzzlehttp/psr7/src/StreamDecoratorTrait.php',
110
+ 'GuzzleHttp\\Psr7\\StreamWrapper' => $vendorDir . '/guzzlehttp/psr7/src/StreamWrapper.php',
111
+ 'GuzzleHttp\\Psr7\\UploadedFile' => $vendorDir . '/guzzlehttp/psr7/src/UploadedFile.php',
112
+ 'GuzzleHttp\\Psr7\\Uri' => $vendorDir . '/guzzlehttp/psr7/src/Uri.php',
113
+ 'GuzzleHttp\\Psr7\\UriNormalizer' => $vendorDir . '/guzzlehttp/psr7/src/UriNormalizer.php',
114
+ 'GuzzleHttp\\Psr7\\UriResolver' => $vendorDir . '/guzzlehttp/psr7/src/UriResolver.php',
115
+ 'GuzzleHttp\\RedirectMiddleware' => $vendorDir . '/guzzlehttp/guzzle/src/RedirectMiddleware.php',
116
+ 'GuzzleHttp\\RequestOptions' => $vendorDir . '/guzzlehttp/guzzle/src/RequestOptions.php',
117
+ 'GuzzleHttp\\RetryMiddleware' => $vendorDir . '/guzzlehttp/guzzle/src/RetryMiddleware.php',
118
+ 'GuzzleHttp\\TransferStats' => $vendorDir . '/guzzlehttp/guzzle/src/TransferStats.php',
119
+ 'GuzzleHttp\\UriTemplate' => $vendorDir . '/guzzlehttp/guzzle/src/UriTemplate.php',
120
+ 'Monolog\\ErrorHandler' => $vendorDir . '/monolog/monolog/src/Monolog/ErrorHandler.php',
121
+ 'Monolog\\Formatter\\ChromePHPFormatter' => $vendorDir . '/monolog/monolog/src/Monolog/Formatter/ChromePHPFormatter.php',
122
+ 'Monolog\\Formatter\\ElasticaFormatter' => $vendorDir . '/monolog/monolog/src/Monolog/Formatter/ElasticaFormatter.php',
123
+ 'Monolog\\Formatter\\FlowdockFormatter' => $vendorDir . '/monolog/monolog/src/Monolog/Formatter/FlowdockFormatter.php',
124
+ 'Monolog\\Formatter\\FluentdFormatter' => $vendorDir . '/monolog/monolog/src/Monolog/Formatter/FluentdFormatter.php',
125
+ 'Monolog\\Formatter\\FormatterInterface' => $vendorDir . '/monolog/monolog/src/Monolog/Formatter/FormatterInterface.php',
126
+ 'Monolog\\Formatter\\GelfMessageFormatter' => $vendorDir . '/monolog/monolog/src/Monolog/Formatter/GelfMessageFormatter.php',
127
+ 'Monolog\\Formatter\\HtmlFormatter' => $vendorDir . '/monolog/monolog/src/Monolog/Formatter/HtmlFormatter.php',
128
+ 'Monolog\\Formatter\\JsonFormatter' => $vendorDir . '/monolog/monolog/src/Monolog/Formatter/JsonFormatter.php',
129
+ 'Monolog\\Formatter\\LineFormatter' => $vendorDir . '/monolog/monolog/src/Monolog/Formatter/LineFormatter.php',
130
+ 'Monolog\\Formatter\\LogglyFormatter' => $vendorDir . '/monolog/monolog/src/Monolog/Formatter/LogglyFormatter.php',
131
+ 'Monolog\\Formatter\\LogstashFormatter' => $vendorDir . '/monolog/monolog/src/Monolog/Formatter/LogstashFormatter.php',
132
+ 'Monolog\\Formatter\\MongoDBFormatter' => $vendorDir . '/monolog/monolog/src/Monolog/Formatter/MongoDBFormatter.php',
133
+ 'Monolog\\Formatter\\NormalizerFormatter' => $vendorDir . '/monolog/monolog/src/Monolog/Formatter/NormalizerFormatter.php',
134
+ 'Monolog\\Formatter\\ScalarFormatter' => $vendorDir . '/monolog/monolog/src/Monolog/Formatter/ScalarFormatter.php',
135
+ 'Monolog\\Formatter\\WildfireFormatter' => $vendorDir . '/monolog/monolog/src/Monolog/Formatter/WildfireFormatter.php',
136
+ 'Monolog\\Handler\\AbstractHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/AbstractHandler.php',
137
+ 'Monolog\\Handler\\AbstractProcessingHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/AbstractProcessingHandler.php',
138
+ 'Monolog\\Handler\\AbstractSyslogHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/AbstractSyslogHandler.php',
139
+ 'Monolog\\Handler\\AmqpHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/AmqpHandler.php',
140
+ 'Monolog\\Handler\\BrowserConsoleHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/BrowserConsoleHandler.php',
141
+ 'Monolog\\Handler\\BufferHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/BufferHandler.php',
142
+ 'Monolog\\Handler\\ChromePHPHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/ChromePHPHandler.php',
143
+ 'Monolog\\Handler\\CouchDBHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/CouchDBHandler.php',
144
+ 'Monolog\\Handler\\CubeHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/CubeHandler.php',
145
+ 'Monolog\\Handler\\Curl\\Util' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/Curl/Util.php',
146
+ 'Monolog\\Handler\\DeduplicationHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/DeduplicationHandler.php',
147
+ 'Monolog\\Handler\\DoctrineCouchDBHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/DoctrineCouchDBHandler.php',
148
+ 'Monolog\\Handler\\DynamoDbHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/DynamoDbHandler.php',
149
+ 'Monolog\\Handler\\ElasticSearchHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/ElasticSearchHandler.php',
150
+ 'Monolog\\Handler\\ErrorLogHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/ErrorLogHandler.php',
151
+ 'Monolog\\Handler\\FilterHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/FilterHandler.php',
152
+ 'Monolog\\Handler\\FingersCrossedHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/FingersCrossedHandler.php',
153
+ 'Monolog\\Handler\\FingersCrossed\\ActivationStrategyInterface' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php',
154
+ 'Monolog\\Handler\\FingersCrossed\\ChannelLevelActivationStrategy' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php',
155
+ 'Monolog\\Handler\\FingersCrossed\\ErrorLevelActivationStrategy' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php',
156
+ 'Monolog\\Handler\\FirePHPHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/FirePHPHandler.php',
157
+ 'Monolog\\Handler\\FleepHookHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/FleepHookHandler.php',
158
+ 'Monolog\\Handler\\FlowdockHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/FlowdockHandler.php',
159
+ 'Monolog\\Handler\\GelfHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/GelfHandler.php',
160
+ 'Monolog\\Handler\\GroupHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/GroupHandler.php',
161
+ 'Monolog\\Handler\\HandlerInterface' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/HandlerInterface.php',
162
+ 'Monolog\\Handler\\HandlerWrapper' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/HandlerWrapper.php',
163
+ 'Monolog\\Handler\\HipChatHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/HipChatHandler.php',
164
+ 'Monolog\\Handler\\IFTTTHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/IFTTTHandler.php',
165
+ 'Monolog\\Handler\\LogEntriesHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/LogEntriesHandler.php',
166
+ 'Monolog\\Handler\\LogglyHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/LogglyHandler.php',
167
+ 'Monolog\\Handler\\MailHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/MailHandler.php',
168
+ 'Monolog\\Handler\\MandrillHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/MandrillHandler.php',
169
+ 'Monolog\\Handler\\MissingExtensionException' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/MissingExtensionException.php',
170
+ 'Monolog\\Handler\\MongoDBHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/MongoDBHandler.php',
171
+ 'Monolog\\Handler\\NativeMailerHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/NativeMailerHandler.php',
172
+ 'Monolog\\Handler\\NewRelicHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/NewRelicHandler.php',
173
+ 'Monolog\\Handler\\NullHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/NullHandler.php',
174
+ 'Monolog\\Handler\\PHPConsoleHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/PHPConsoleHandler.php',
175
+ 'Monolog\\Handler\\PsrHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/PsrHandler.php',
176
+ 'Monolog\\Handler\\PushoverHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/PushoverHandler.php',
177
+ 'Monolog\\Handler\\RavenHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/RavenHandler.php',
178
+ 'Monolog\\Handler\\RedisHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/RedisHandler.php',
179
+ 'Monolog\\Handler\\RollbarHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/RollbarHandler.php',
180
+ 'Monolog\\Handler\\RotatingFileHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/RotatingFileHandler.php',
181
+ 'Monolog\\Handler\\SamplingHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/SamplingHandler.php',
182
+ 'Monolog\\Handler\\SlackHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/SlackHandler.php',
183
+ 'Monolog\\Handler\\SlackWebhookHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/SlackWebhookHandler.php',
184
+ 'Monolog\\Handler\\Slack\\SlackRecord' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/Slack/SlackRecord.php',
185
+ 'Monolog\\Handler\\SlackbotHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/SlackbotHandler.php',
186
+ 'Monolog\\Handler\\SocketHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/SocketHandler.php',
187
+ 'Monolog\\Handler\\StreamHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/StreamHandler.php',
188
+ 'Monolog\\Handler\\SwiftMailerHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/SwiftMailerHandler.php',
189
+ 'Monolog\\Handler\\SyslogHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/SyslogHandler.php',
190
+ 'Monolog\\Handler\\SyslogUdpHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/SyslogUdpHandler.php',
191
+ 'Monolog\\Handler\\SyslogUdp\\UdpSocket' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/SyslogUdp/UdpSocket.php',
192
+ 'Monolog\\Handler\\WhatFailureGroupHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/WhatFailureGroupHandler.php',
193
+ 'Monolog\\Handler\\ZendMonitorHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/ZendMonitorHandler.php',
194
+ 'Monolog\\Logger' => $vendorDir . '/monolog/monolog/src/Monolog/Logger.php',
195
+ 'Monolog\\Processor\\GitProcessor' => $vendorDir . '/monolog/monolog/src/Monolog/Processor/GitProcessor.php',
196
+ 'Monolog\\Processor\\IntrospectionProcessor' => $vendorDir . '/monolog/monolog/src/Monolog/Processor/IntrospectionProcessor.php',
197
+ 'Monolog\\Processor\\MemoryPeakUsageProcessor' => $vendorDir . '/monolog/monolog/src/Monolog/Processor/MemoryPeakUsageProcessor.php',
198
+ 'Monolog\\Processor\\MemoryProcessor' => $vendorDir . '/monolog/monolog/src/Monolog/Processor/MemoryProcessor.php',
199
+ 'Monolog\\Processor\\MemoryUsageProcessor' => $vendorDir . '/monolog/monolog/src/Monolog/Processor/MemoryUsageProcessor.php',
200
+ 'Monolog\\Processor\\MercurialProcessor' => $vendorDir . '/monolog/monolog/src/Monolog/Processor/MercurialProcessor.php',
201
+ 'Monolog\\Processor\\ProcessIdProcessor' => $vendorDir . '/monolog/monolog/src/Monolog/Processor/ProcessIdProcessor.php',
202
+ 'Monolog\\Processor\\PsrLogMessageProcessor' => $vendorDir . '/monolog/monolog/src/Monolog/Processor/PsrLogMessageProcessor.php',
203
+ 'Monolog\\Processor\\TagProcessor' => $vendorDir . '/monolog/monolog/src/Monolog/Processor/TagProcessor.php',
204
+ 'Monolog\\Processor\\UidProcessor' => $vendorDir . '/monolog/monolog/src/Monolog/Processor/UidProcessor.php',
205
+ 'Monolog\\Processor\\WebProcessor' => $vendorDir . '/monolog/monolog/src/Monolog/Processor/WebProcessor.php',
206
+ 'Monolog\\Registry' => $vendorDir . '/monolog/monolog/src/Monolog/Registry.php',
207
+ 'Psr\\Cache\\CacheException' => $vendorDir . '/psr/cache/src/CacheException.php',
208
+ 'Psr\\Cache\\CacheItemInterface' => $vendorDir . '/psr/cache/src/CacheItemInterface.php',
209
+ 'Psr\\Cache\\CacheItemPoolInterface' => $vendorDir . '/psr/cache/src/CacheItemPoolInterface.php',
210
+ 'Psr\\Cache\\InvalidArgumentException' => $vendorDir . '/psr/cache/src/InvalidArgumentException.php',
211
+ 'Psr\\Http\\Message\\MessageInterface' => $vendorDir . '/psr/http-message/src/MessageInterface.php',
212
+ 'Psr\\Http\\Message\\RequestInterface' => $vendorDir . '/psr/http-message/src/RequestInterface.php',
213
+ 'Psr\\Http\\Message\\ResponseInterface' => $vendorDir . '/psr/http-message/src/ResponseInterface.php',
214
+ 'Psr\\Http\\Message\\ServerRequestInterface' => $vendorDir . '/psr/http-message/src/ServerRequestInterface.php',
215
+ 'Psr\\Http\\Message\\StreamInterface' => $vendorDir . '/psr/http-message/src/StreamInterface.php',
216
+ 'Psr\\Http\\Message\\UploadedFileInterface' => $vendorDir . '/psr/http-message/src/UploadedFileInterface.php',
217
+ 'Psr\\Http\\Message\\UriInterface' => $vendorDir . '/psr/http-message/src/UriInterface.php',
218
+ 'Psr\\Log\\AbstractLogger' => $vendorDir . '/psr/log/Psr/Log/AbstractLogger.php',
219
+ 'Psr\\Log\\InvalidArgumentException' => $vendorDir . '/psr/log/Psr/Log/InvalidArgumentException.php',
220
+ 'Psr\\Log\\LogLevel' => $vendorDir . '/psr/log/Psr/Log/LogLevel.php',
221
+ 'Psr\\Log\\LoggerAwareInterface' => $vendorDir . '/psr/log/Psr/Log/LoggerAwareInterface.php',
222
+ 'Psr\\Log\\LoggerAwareTrait' => $vendorDir . '/psr/log/Psr/Log/LoggerAwareTrait.php',
223
+ 'Psr\\Log\\LoggerInterface' => $vendorDir . '/psr/log/Psr/Log/LoggerInterface.php',
224
+ 'Psr\\Log\\LoggerTrait' => $vendorDir . '/psr/log/Psr/Log/LoggerTrait.php',
225
+ 'Psr\\Log\\NullLogger' => $vendorDir . '/psr/log/Psr/Log/NullLogger.php',
226
+ 'phpseclib\\Crypt\\AES' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/AES.php',
227
+ 'phpseclib\\Crypt\\Base' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/Base.php',
228
+ 'phpseclib\\Crypt\\Blowfish' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/Blowfish.php',
229
+ 'phpseclib\\Crypt\\DES' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/DES.php',
230
+ 'phpseclib\\Crypt\\Hash' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/Hash.php',
231
+ 'phpseclib\\Crypt\\RC2' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/RC2.php',
232
+ 'phpseclib\\Crypt\\RC4' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/RC4.php',
233
+ 'phpseclib\\Crypt\\RSA' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/RSA.php',
234
+ 'phpseclib\\Crypt\\Random' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/Random.php',
235
+ 'phpseclib\\Crypt\\Rijndael' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/Rijndael.php',
236
+ 'phpseclib\\Crypt\\TripleDES' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/TripleDES.php',
237
+ 'phpseclib\\Crypt\\Twofish' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/Twofish.php',
238
+ 'phpseclib\\Math\\BigInteger' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Math/BigInteger.php',
239
  );
vendor/composer/autoload_real.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
- class ComposerAutoloaderInit07e98588aa3894ff9e3dc547d403ad69
6
  {
7
  private static $loader;
8
 
@@ -19,48 +19,39 @@ class ComposerAutoloaderInit07e98588aa3894ff9e3dc547d403ad69
19
  return self::$loader;
20
  }
21
 
22
- spl_autoload_register(array('ComposerAutoloaderInit07e98588aa3894ff9e3dc547d403ad69', 'loadClassLoader'), true, false);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
- spl_autoload_unregister(array('ComposerAutoloaderInit07e98588aa3894ff9e3dc547d403ad69', 'loadClassLoader'));
25
 
26
- $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION');
27
  if ($useStaticLoader) {
28
  require_once __DIR__ . '/autoload_static.php';
29
 
30
- call_user_func(\Composer\Autoload\ComposerStaticInit07e98588aa3894ff9e3dc547d403ad69::getInitializer($loader));
31
  } else {
32
- $map = require __DIR__ . '/autoload_namespaces.php';
33
- foreach ($map as $namespace => $path) {
34
- $loader->set($namespace, $path);
35
- }
36
-
37
- $map = require __DIR__ . '/autoload_psr4.php';
38
- foreach ($map as $namespace => $path) {
39
- $loader->setPsr4($namespace, $path);
40
- }
41
-
42
  $classMap = require __DIR__ . '/autoload_classmap.php';
43
  if ($classMap) {
44
  $loader->addClassMap($classMap);
45
  }
46
  }
47
 
 
48
  $loader->register(false);
49
 
50
  if ($useStaticLoader) {
51
- $includeFiles = Composer\Autoload\ComposerStaticInit07e98588aa3894ff9e3dc547d403ad69::$files;
52
  } else {
53
  $includeFiles = require __DIR__ . '/autoload_files.php';
54
  }
55
  foreach ($includeFiles as $fileIdentifier => $file) {
56
- composerRequire07e98588aa3894ff9e3dc547d403ad69($fileIdentifier, $file);
57
  }
58
 
59
  return $loader;
60
  }
61
  }
62
 
63
- function composerRequire07e98588aa3894ff9e3dc547d403ad69($fileIdentifier, $file)
64
  {
65
  if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
66
  require $file;
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
+ class ComposerAutoloaderInitbd625bfb904527ebcdc364a59295e538
6
  {
7
  private static $loader;
8
 
19
  return self::$loader;
20
  }
21
 
22
+ spl_autoload_register(array('ComposerAutoloaderInitbd625bfb904527ebcdc364a59295e538', 'loadClassLoader'), true, false);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
+ spl_autoload_unregister(array('ComposerAutoloaderInitbd625bfb904527ebcdc364a59295e538', 'loadClassLoader'));
25
 
26
+ $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
27
  if ($useStaticLoader) {
28
  require_once __DIR__ . '/autoload_static.php';
29
 
30
+ call_user_func(\Composer\Autoload\ComposerStaticInitbd625bfb904527ebcdc364a59295e538::getInitializer($loader));
31
  } else {
 
 
 
 
 
 
 
 
 
 
32
  $classMap = require __DIR__ . '/autoload_classmap.php';
33
  if ($classMap) {
34
  $loader->addClassMap($classMap);
35
  }
36
  }
37
 
38
+ $loader->setClassMapAuthoritative(true);
39
  $loader->register(false);
40
 
41
  if ($useStaticLoader) {
42
+ $includeFiles = Composer\Autoload\ComposerStaticInitbd625bfb904527ebcdc364a59295e538::$files;
43
  } else {
44
  $includeFiles = require __DIR__ . '/autoload_files.php';
45
  }
46
  foreach ($includeFiles as $fileIdentifier => $file) {
47
+ composerRequirebd625bfb904527ebcdc364a59295e538($fileIdentifier, $file);
48
  }
49
 
50
  return $loader;
51
  }
52
  }
53
 
54
+ function composerRequirebd625bfb904527ebcdc364a59295e538($fileIdentifier, $file)
55
  {
56
  if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
57
  require $file;
vendor/composer/autoload_static.php CHANGED
@@ -4,7 +4,7 @@
4
 
5
  namespace Composer\Autoload;
6
 
7
- class ComposerStaticInit07e98588aa3894ff9e3dc547d403ad69
8
  {
9
  public static $files = array (
10
  'a0edc8309cc5e1d60e3047b5df6b7052' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/functions_include.php',
@@ -121,17 +121,245 @@ class ComposerStaticInit07e98588aa3894ff9e3dc547d403ad69
121
  );
122
 
123
  public static $classMap = array (
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
124
  'Google_Service_Exception' => __DIR__ . '/..' . '/google/apiclient/src/Google/Service/Exception.php',
125
  'Google_Service_Resource' => __DIR__ . '/..' . '/google/apiclient/src/Google/Service/Resource.php',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
  );
127
 
128
  public static function getInitializer(ClassLoader $loader)
129
  {
130
  return \Closure::bind(function () use ($loader) {
131
- $loader->prefixLengthsPsr4 = ComposerStaticInit07e98588aa3894ff9e3dc547d403ad69::$prefixLengthsPsr4;
132
- $loader->prefixDirsPsr4 = ComposerStaticInit07e98588aa3894ff9e3dc547d403ad69::$prefixDirsPsr4;
133
- $loader->prefixesPsr0 = ComposerStaticInit07e98588aa3894ff9e3dc547d403ad69::$prefixesPsr0;
134
- $loader->classMap = ComposerStaticInit07e98588aa3894ff9e3dc547d403ad69::$classMap;
135
 
136
  }, null, ClassLoader::class);
137
  }
4
 
5
  namespace Composer\Autoload;
6
 
7
+ class ComposerStaticInitbd625bfb904527ebcdc364a59295e538
8
  {
9
  public static $files = array (
10
  'a0edc8309cc5e1d60e3047b5df6b7052' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/functions_include.php',
121
  );
122
 
123
  public static $classMap = array (
124
+ 'Google\\Auth\\ApplicationDefaultCredentials' => __DIR__ . '/..' . '/google/auth/src/ApplicationDefaultCredentials.php',
125
+ 'Google\\Auth\\CacheTrait' => __DIR__ . '/..' . '/google/auth/src/CacheTrait.php',
126
+ 'Google\\Auth\\Cache\\InvalidArgumentException' => __DIR__ . '/..' . '/google/auth/src/Cache/InvalidArgumentException.php',
127
+ 'Google\\Auth\\Cache\\Item' => __DIR__ . '/..' . '/google/auth/src/Cache/Item.php',
128
+ 'Google\\Auth\\Cache\\MemoryCacheItemPool' => __DIR__ . '/..' . '/google/auth/src/Cache/MemoryCacheItemPool.php',
129
+ 'Google\\Auth\\CredentialsLoader' => __DIR__ . '/..' . '/google/auth/src/CredentialsLoader.php',
130
+ 'Google\\Auth\\Credentials\\AppIdentityCredentials' => __DIR__ . '/..' . '/google/auth/src/Credentials/AppIdentityCredentials.php',
131
+ 'Google\\Auth\\Credentials\\GCECredentials' => __DIR__ . '/..' . '/google/auth/src/Credentials/GCECredentials.php',
132
+ 'Google\\Auth\\Credentials\\IAMCredentials' => __DIR__ . '/..' . '/google/auth/src/Credentials/IAMCredentials.php',
133
+ 'Google\\Auth\\Credentials\\ServiceAccountCredentials' => __DIR__ . '/..' . '/google/auth/src/Credentials/ServiceAccountCredentials.php',
134
+ 'Google\\Auth\\Credentials\\ServiceAccountJwtAccessCredentials' => __DIR__ . '/..' . '/google/auth/src/Credentials/ServiceAccountJwtAccessCredentials.php',
135
+ 'Google\\Auth\\Credentials\\UserRefreshCredentials' => __DIR__ . '/..' . '/google/auth/src/Credentials/UserRefreshCredentials.php',
136
+ 'Google\\Auth\\FetchAuthTokenCache' => __DIR__ . '/..' . '/google/auth/src/FetchAuthTokenCache.php',
137
+ 'Google\\Auth\\FetchAuthTokenInterface' => __DIR__ . '/..' . '/google/auth/src/FetchAuthTokenInterface.php',
138
+ 'Google\\Auth\\HttpHandler\\Guzzle5HttpHandler' => __DIR__ . '/..' . '/google/auth/src/HttpHandler/Guzzle5HttpHandler.php',
139
+ 'Google\\Auth\\HttpHandler\\Guzzle6HttpHandler' => __DIR__ . '/..' . '/google/auth/src/HttpHandler/Guzzle6HttpHandler.php',
140
+ 'Google\\Auth\\HttpHandler\\HttpHandlerFactory' => __DIR__ . '/..' . '/google/auth/src/HttpHandler/HttpHandlerFactory.php',
141
+ 'Google\\Auth\\Middleware\\AuthTokenMiddleware' => __DIR__ . '/..' . '/google/auth/src/Middleware/AuthTokenMiddleware.php',
142
+ 'Google\\Auth\\Middleware\\ScopedAccessTokenMiddleware' => __DIR__ . '/..' . '/google/auth/src/Middleware/ScopedAccessTokenMiddleware.php',
143
+ 'Google\\Auth\\Middleware\\SimpleMiddleware' => __DIR__ . '/..' . '/google/auth/src/Middleware/SimpleMiddleware.php',
144
+ 'Google\\Auth\\OAuth2' => __DIR__ . '/..' . '/google/auth/src/OAuth2.php',
145
+ 'Google\\Auth\\Subscriber\\AuthTokenSubscriber' => __DIR__ . '/..' . '/google/auth/src/Subscriber/AuthTokenSubscriber.php',
146
+ 'Google\\Auth\\Subscriber\\ScopedAccessTokenSubscriber' => __DIR__ . '/..' . '/google/auth/src/Subscriber/ScopedAccessTokenSubscriber.php',
147
+ 'Google\\Auth\\Subscriber\\SimpleSubscriber' => __DIR__ . '/..' . '/google/auth/src/Subscriber/SimpleSubscriber.php',
148
+ 'Google_AccessToken_Revoke' => __DIR__ . '/..' . '/google/apiclient/src/Google/AccessToken/Revoke.php',
149
+ 'Google_AccessToken_Verify' => __DIR__ . '/..' . '/google/apiclient/src/Google/AccessToken/Verify.php',
150
+ 'Google_AuthHandler_AuthHandlerFactory' => __DIR__ . '/..' . '/google/apiclient/src/Google/AuthHandler/AuthHandlerFactory.php',
151
+ 'Google_AuthHandler_Guzzle5AuthHandler' => __DIR__ . '/..' . '/google/apiclient/src/Google/AuthHandler/Guzzle5AuthHandler.php',
152
+ 'Google_AuthHandler_Guzzle6AuthHandler' => __DIR__ . '/..' . '/google/apiclient/src/Google/AuthHandler/Guzzle6AuthHandler.php',
153
+ 'Google_Client' => __DIR__ . '/..' . '/google/apiclient/src/Google/Client.php',
154
+ 'Google_Collection' => __DIR__ . '/..' . '/google/apiclient/src/Google/Collection.php',
155
+ 'Google_Exception' => __DIR__ . '/..' . '/google/apiclient/src/Google/Exception.php',
156
+ 'Google_Http_Batch' => __DIR__ . '/..' . '/google/apiclient/src/Google/Http/Batch.php',
157
+ 'Google_Http_MediaFileUpload' => __DIR__ . '/..' . '/google/apiclient/src/Google/Http/MediaFileUpload.php',
158
+ 'Google_Http_REST' => __DIR__ . '/..' . '/google/apiclient/src/Google/Http/REST.php',
159
+ 'Google_Model' => __DIR__ . '/..' . '/google/apiclient/src/Google/Model.php',
160
+ 'Google_Service' => __DIR__ . '/..' . '/google/apiclient/src/Google/Service.php',
161
  'Google_Service_Exception' => __DIR__ . '/..' . '/google/apiclient/src/Google/Service/Exception.php',
162
  'Google_Service_Resource' => __DIR__ . '/..' . '/google/apiclient/src/Google/Service/Resource.php',
163
+ 'Google_Task_Exception' => __DIR__ . '/..' . '/google/apiclient/src/Google/Task/Exception.php',
164
+ 'Google_Task_Retryable' => __DIR__ . '/..' . '/google/apiclient/src/Google/Task/Retryable.php',
165
+ 'Google_Task_Runner' => __DIR__ . '/..' . '/google/apiclient/src/Google/Task/Runner.php',
166
+ 'Google_Utils_UriTemplate' => __DIR__ . '/..' . '/google/apiclient/src/Google/Utils/UriTemplate.php',
167
+ 'GuzzleHttp\\Client' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Client.php',
168
+ 'GuzzleHttp\\ClientInterface' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/ClientInterface.php',
169
+ 'GuzzleHttp\\Cookie\\CookieJar' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Cookie/CookieJar.php',
170
+ 'GuzzleHttp\\Cookie\\CookieJarInterface' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php',
171
+ 'GuzzleHttp\\Cookie\\FileCookieJar' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php',
172
+ 'GuzzleHttp\\Cookie\\SessionCookieJar' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php',
173
+ 'GuzzleHttp\\Cookie\\SetCookie' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Cookie/SetCookie.php',
174
+ 'GuzzleHttp\\Exception\\BadResponseException' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Exception/BadResponseException.php',
175
+ 'GuzzleHttp\\Exception\\ClientException' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Exception/ClientException.php',
176
+ 'GuzzleHttp\\Exception\\ConnectException' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Exception/ConnectException.php',
177
+ 'GuzzleHttp\\Exception\\GuzzleException' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Exception/GuzzleException.php',
178
+ 'GuzzleHttp\\Exception\\RequestException' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Exception/RequestException.php',
179
+ 'GuzzleHttp\\Exception\\SeekException' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Exception/SeekException.php',
180
+ 'GuzzleHttp\\Exception\\ServerException' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Exception/ServerException.php',
181
+ 'GuzzleHttp\\Exception\\TooManyRedirectsException' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Exception/TooManyRedirectsException.php',
182
+ 'GuzzleHttp\\Exception\\TransferException' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Exception/TransferException.php',
183
+ 'GuzzleHttp\\HandlerStack' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/HandlerStack.php',
184
+ 'GuzzleHttp\\Handler\\CurlFactory' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Handler/CurlFactory.php',
185
+ 'GuzzleHttp\\Handler\\CurlFactoryInterface' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Handler/CurlFactoryInterface.php',
186
+ 'GuzzleHttp\\Handler\\CurlHandler' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Handler/CurlHandler.php',
187
+ 'GuzzleHttp\\Handler\\CurlMultiHandler' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php',
188
+ 'GuzzleHttp\\Handler\\EasyHandle' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Handler/EasyHandle.php',
189
+ 'GuzzleHttp\\Handler\\MockHandler' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Handler/MockHandler.php',
190
+ 'GuzzleHttp\\Handler\\Proxy' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Handler/Proxy.php',
191
+ 'GuzzleHttp\\Handler\\StreamHandler' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Handler/StreamHandler.php',
192
+ 'GuzzleHttp\\MessageFormatter' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/MessageFormatter.php',
193
+ 'GuzzleHttp\\Middleware' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Middleware.php',
194
+ 'GuzzleHttp\\Pool' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Pool.php',
195
+ 'GuzzleHttp\\PrepareBodyMiddleware' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php',
196
+ 'GuzzleHttp\\Promise\\AggregateException' => __DIR__ . '/..' . '/guzzlehttp/promises/src/AggregateException.php',
197
+ 'GuzzleHttp\\Promise\\CancellationException' => __DIR__ . '/..' . '/guzzlehttp/promises/src/CancellationException.php',
198
+ 'GuzzleHttp\\Promise\\Coroutine' => __DIR__ . '/..' . '/guzzlehttp/promises/src/Coroutine.php',
199
+ 'GuzzleHttp\\Promise\\EachPromise' => __DIR__ . '/..' . '/guzzlehttp/promises/src/EachPromise.php',
200
+ 'GuzzleHttp\\Promise\\FulfilledPromise' => __DIR__ . '/..' . '/guzzlehttp/promises/src/FulfilledPromise.php',
201
+ 'GuzzleHttp\\Promise\\Promise' => __DIR__ . '/..' . '/guzzlehttp/promises/src/Promise.php',
202
+ 'GuzzleHttp\\Promise\\PromiseInterface' => __DIR__ . '/..' . '/guzzlehttp/promises/src/PromiseInterface.php',
203
+ 'GuzzleHttp\\Promise\\PromisorInterface' => __DIR__ . '/..' . '/guzzlehttp/promises/src/PromisorInterface.php',
204
+ 'GuzzleHttp\\Promise\\RejectedPromise' => __DIR__ . '/..' . '/guzzlehttp/promises/src/RejectedPromise.php',
205
+ 'GuzzleHttp\\Promise\\RejectionException' => __DIR__ . '/..' . '/guzzlehttp/promises/src/RejectionException.php',
206
+ 'GuzzleHttp\\Promise\\TaskQueue' => __DIR__ . '/..' . '/guzzlehttp/promises/src/TaskQueue.php',
207
+ 'GuzzleHttp\\Promise\\TaskQueueInterface' => __DIR__ . '/..' . '/guzzlehttp/promises/src/TaskQueueInterface.php',
208
+ 'GuzzleHttp\\Psr7\\AppendStream' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/AppendStream.php',
209
+ 'GuzzleHttp\\Psr7\\BufferStream' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/BufferStream.php',
210
+ 'GuzzleHttp\\Psr7\\CachingStream' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/CachingStream.php',
211
+ 'GuzzleHttp\\Psr7\\DroppingStream' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/DroppingStream.php',
212
+ 'GuzzleHttp\\Psr7\\FnStream' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/FnStream.php',
213
+ 'GuzzleHttp\\Psr7\\InflateStream' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/InflateStream.php',
214
+ 'GuzzleHttp\\Psr7\\LazyOpenStream' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/LazyOpenStream.php',
215
+ 'GuzzleHttp\\Psr7\\LimitStream' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/LimitStream.php',
216
+ 'GuzzleHttp\\Psr7\\MessageTrait' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/MessageTrait.php',
217
+ 'GuzzleHttp\\Psr7\\MultipartStream' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/MultipartStream.php',
218
+ 'GuzzleHttp\\Psr7\\NoSeekStream' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/NoSeekStream.php',
219
+ 'GuzzleHttp\\Psr7\\PumpStream' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/PumpStream.php',
220
+ 'GuzzleHttp\\Psr7\\Request' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/Request.php',
221
+ 'GuzzleHttp\\Psr7\\Response' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/Response.php',
222
+ 'GuzzleHttp\\Psr7\\ServerRequest' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/ServerRequest.php',
223
+ 'GuzzleHttp\\Psr7\\Stream' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/Stream.php',
224
+ 'GuzzleHttp\\Psr7\\StreamDecoratorTrait' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/StreamDecoratorTrait.php',
225
+ 'GuzzleHttp\\Psr7\\StreamWrapper' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/StreamWrapper.php',
226
+ 'GuzzleHttp\\Psr7\\UploadedFile' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/UploadedFile.php',
227
+ 'GuzzleHttp\\Psr7\\Uri' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/Uri.php',
228
+ 'GuzzleHttp\\Psr7\\UriNormalizer' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/UriNormalizer.php',
229
+ 'GuzzleHttp\\Psr7\\UriResolver' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/UriResolver.php',
230
+ 'GuzzleHttp\\RedirectMiddleware' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/RedirectMiddleware.php',
231
+ 'GuzzleHttp\\RequestOptions' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/RequestOptions.php',
232
+ 'GuzzleHttp\\RetryMiddleware' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/RetryMiddleware.php',
233
+ 'GuzzleHttp\\TransferStats' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/TransferStats.php',
234
+ 'GuzzleHttp\\UriTemplate' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/UriTemplate.php',
235
+ 'Monolog\\ErrorHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/ErrorHandler.php',
236
+ 'Monolog\\Formatter\\ChromePHPFormatter' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Formatter/ChromePHPFormatter.php',
237
+ 'Monolog\\Formatter\\ElasticaFormatter' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Formatter/ElasticaFormatter.php',
238
+ 'Monolog\\Formatter\\FlowdockFormatter' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Formatter/FlowdockFormatter.php',
239
+ 'Monolog\\Formatter\\FluentdFormatter' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Formatter/FluentdFormatter.php',
240
+ 'Monolog\\Formatter\\FormatterInterface' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Formatter/FormatterInterface.php',
241
+ 'Monolog\\Formatter\\GelfMessageFormatter' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Formatter/GelfMessageFormatter.php',
242
+ 'Monolog\\Formatter\\HtmlFormatter' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Formatter/HtmlFormatter.php',
243
+ 'Monolog\\Formatter\\JsonFormatter' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Formatter/JsonFormatter.php',
244
+ 'Monolog\\Formatter\\LineFormatter' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Formatter/LineFormatter.php',
245
+ 'Monolog\\Formatter\\LogglyFormatter' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Formatter/LogglyFormatter.php',
246
+ 'Monolog\\Formatter\\LogstashFormatter' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Formatter/LogstashFormatter.php',
247
+ 'Monolog\\Formatter\\MongoDBFormatter' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Formatter/MongoDBFormatter.php',
248
+ 'Monolog\\Formatter\\NormalizerFormatter' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Formatter/NormalizerFormatter.php',
249
+ 'Monolog\\Formatter\\ScalarFormatter' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Formatter/ScalarFormatter.php',
250
+ 'Monolog\\Formatter\\WildfireFormatter' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Formatter/WildfireFormatter.php',
251
+ 'Monolog\\Handler\\AbstractHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/AbstractHandler.php',
252
+ 'Monolog\\Handler\\AbstractProcessingHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/AbstractProcessingHandler.php',
253
+ 'Monolog\\Handler\\AbstractSyslogHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/AbstractSyslogHandler.php',
254
+ 'Monolog\\Handler\\AmqpHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/AmqpHandler.php',
255
+ 'Monolog\\Handler\\BrowserConsoleHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/BrowserConsoleHandler.php',
256
+ 'Monolog\\Handler\\BufferHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/BufferHandler.php',
257
+ 'Monolog\\Handler\\ChromePHPHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/ChromePHPHandler.php',
258
+ 'Monolog\\Handler\\CouchDBHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/CouchDBHandler.php',
259
+ 'Monolog\\Handler\\CubeHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/CubeHandler.php',
260
+ 'Monolog\\Handler\\Curl\\Util' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/Curl/Util.php',
261
+ 'Monolog\\Handler\\DeduplicationHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/DeduplicationHandler.php',
262
+ 'Monolog\\Handler\\DoctrineCouchDBHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/DoctrineCouchDBHandler.php',
263
+ 'Monolog\\Handler\\DynamoDbHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/DynamoDbHandler.php',
264
+ 'Monolog\\Handler\\ElasticSearchHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/ElasticSearchHandler.php',
265
+ 'Monolog\\Handler\\ErrorLogHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/ErrorLogHandler.php',
266
+ 'Monolog\\Handler\\FilterHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/FilterHandler.php',
267
+ 'Monolog\\Handler\\FingersCrossedHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/FingersCrossedHandler.php',
268
+ 'Monolog\\Handler\\FingersCrossed\\ActivationStrategyInterface' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php',
269
+ 'Monolog\\Handler\\FingersCrossed\\ChannelLevelActivationStrategy' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php',
270
+ 'Monolog\\Handler\\FingersCrossed\\ErrorLevelActivationStrategy' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php',
271
+ 'Monolog\\Handler\\FirePHPHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/FirePHPHandler.php',
272
+ 'Monolog\\Handler\\FleepHookHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/FleepHookHandler.php',
273
+ 'Monolog\\Handler\\FlowdockHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/FlowdockHandler.php',
274
+ 'Monolog\\Handler\\GelfHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/GelfHandler.php',
275
+ 'Monolog\\Handler\\GroupHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/GroupHandler.php',
276
+ 'Monolog\\Handler\\HandlerInterface' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/HandlerInterface.php',
277
+ 'Monolog\\Handler\\HandlerWrapper' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/HandlerWrapper.php',
278
+ 'Monolog\\Handler\\HipChatHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/HipChatHandler.php',
279
+ 'Monolog\\Handler\\IFTTTHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/IFTTTHandler.php',
280
+ 'Monolog\\Handler\\LogEntriesHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/LogEntriesHandler.php',
281
+ 'Monolog\\Handler\\LogglyHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/LogglyHandler.php',
282
+ 'Monolog\\Handler\\MailHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/MailHandler.php',
283
+ 'Monolog\\Handler\\MandrillHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/MandrillHandler.php',
284
+ 'Monolog\\Handler\\MissingExtensionException' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/MissingExtensionException.php',
285
+ 'Monolog\\Handler\\MongoDBHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/MongoDBHandler.php',
286
+ 'Monolog\\Handler\\NativeMailerHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/NativeMailerHandler.php',
287
+ 'Monolog\\Handler\\NewRelicHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/NewRelicHandler.php',
288
+ 'Monolog\\Handler\\NullHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/NullHandler.php',
289
+ 'Monolog\\Handler\\PHPConsoleHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/PHPConsoleHandler.php',
290
+ 'Monolog\\Handler\\PsrHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/PsrHandler.php',
291
+ 'Monolog\\Handler\\PushoverHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/PushoverHandler.php',
292
+ 'Monolog\\Handler\\RavenHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/RavenHandler.php',
293
+ 'Monolog\\Handler\\RedisHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/RedisHandler.php',
294
+ 'Monolog\\Handler\\RollbarHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/RollbarHandler.php',
295
+ 'Monolog\\Handler\\RotatingFileHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/RotatingFileHandler.php',
296
+ 'Monolog\\Handler\\SamplingHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/SamplingHandler.php',
297
+ 'Monolog\\Handler\\SlackHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/SlackHandler.php',
298
+ 'Monolog\\Handler\\SlackWebhookHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/SlackWebhookHandler.php',
299
+ 'Monolog\\Handler\\Slack\\SlackRecord' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/Slack/SlackRecord.php',
300
+ 'Monolog\\Handler\\SlackbotHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/SlackbotHandler.php',
301
+ 'Monolog\\Handler\\SocketHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/SocketHandler.php',
302
+ 'Monolog\\Handler\\StreamHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/StreamHandler.php',
303
+ 'Monolog\\Handler\\SwiftMailerHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/SwiftMailerHandler.php',
304
+ 'Monolog\\Handler\\SyslogHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/SyslogHandler.php',
305
+ 'Monolog\\Handler\\SyslogUdpHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/SyslogUdpHandler.php',
306
+ 'Monolog\\Handler\\SyslogUdp\\UdpSocket' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/SyslogUdp/UdpSocket.php',
307
+ 'Monolog\\Handler\\WhatFailureGroupHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/WhatFailureGroupHandler.php',
308
+ 'Monolog\\Handler\\ZendMonitorHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/ZendMonitorHandler.php',
309
+ 'Monolog\\Logger' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Logger.php',
310
+ 'Monolog\\Processor\\GitProcessor' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Processor/GitProcessor.php',
311
+ 'Monolog\\Processor\\IntrospectionProcessor' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Processor/IntrospectionProcessor.php',
312
+ 'Monolog\\Processor\\MemoryPeakUsageProcessor' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Processor/MemoryPeakUsageProcessor.php',
313
+ 'Monolog\\Processor\\MemoryProcessor' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Processor/MemoryProcessor.php',
314
+ 'Monolog\\Processor\\MemoryUsageProcessor' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Processor/MemoryUsageProcessor.php',
315
+ 'Monolog\\Processor\\MercurialProcessor' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Processor/MercurialProcessor.php',
316
+ 'Monolog\\Processor\\ProcessIdProcessor' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Processor/ProcessIdProcessor.php',
317
+ 'Monolog\\Processor\\PsrLogMessageProcessor' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Processor/PsrLogMessageProcessor.php',
318
+ 'Monolog\\Processor\\TagProcessor' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Processor/TagProcessor.php',
319
+ 'Monolog\\Processor\\UidProcessor' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Processor/UidProcessor.php',
320
+ 'Monolog\\Processor\\WebProcessor' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Processor/WebProcessor.php',
321
+ 'Monolog\\Registry' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Registry.php',
322
+ 'Psr\\Cache\\CacheException' => __DIR__ . '/..' . '/psr/cache/src/CacheException.php',
323
+ 'Psr\\Cache\\CacheItemInterface' => __DIR__ . '/..' . '/psr/cache/src/CacheItemInterface.php',
324
+ 'Psr\\Cache\\CacheItemPoolInterface' => __DIR__ . '/..' . '/psr/cache/src/CacheItemPoolInterface.php',
325
+ 'Psr\\Cache\\InvalidArgumentException' => __DIR__ . '/..' . '/psr/cache/src/InvalidArgumentException.php',
326
+ 'Psr\\Http\\Message\\MessageInterface' => __DIR__ . '/..' . '/psr/http-message/src/MessageInterface.php',
327
+ 'Psr\\Http\\Message\\RequestInterface' => __DIR__ . '/..' . '/psr/http-message/src/RequestInterface.php',
328
+ 'Psr\\Http\\Message\\ResponseInterface' => __DIR__ . '/..' . '/psr/http-message/src/ResponseInterface.php',
329
+ 'Psr\\Http\\Message\\ServerRequestInterface' => __DIR__ . '/..' . '/psr/http-message/src/ServerRequestInterface.php',
330
+ 'Psr\\Http\\Message\\StreamInterface' => __DIR__ . '/..' . '/psr/http-message/src/StreamInterface.php',
331
+ 'Psr\\Http\\Message\\UploadedFileInterface' => __DIR__ . '/..' . '/psr/http-message/src/UploadedFileInterface.php',
332
+ 'Psr\\Http\\Message\\UriInterface' => __DIR__ . '/..' . '/psr/http-message/src/UriInterface.php',
333
+ 'Psr\\Log\\AbstractLogger' => __DIR__ . '/..' . '/psr/log/Psr/Log/AbstractLogger.php',
334
+ 'Psr\\Log\\InvalidArgumentException' => __DIR__ . '/..' . '/psr/log/Psr/Log/InvalidArgumentException.php',
335
+ 'Psr\\Log\\LogLevel' => __DIR__ . '/..' . '/psr/log/Psr/Log/LogLevel.php',
336
+ 'Psr\\Log\\LoggerAwareInterface' => __DIR__ . '/..' . '/psr/log/Psr/Log/LoggerAwareInterface.php',
337
+ 'Psr\\Log\\LoggerAwareTrait' => __DIR__ . '/..' . '/psr/log/Psr/Log/LoggerAwareTrait.php',
338
+ 'Psr\\Log\\LoggerInterface' => __DIR__ . '/..' . '/psr/log/Psr/Log/LoggerInterface.php',
339
+ 'Psr\\Log\\LoggerTrait' => __DIR__ . '/..' . '/psr/log/Psr/Log/LoggerTrait.php',
340
+ 'Psr\\Log\\NullLogger' => __DIR__ . '/..' . '/psr/log/Psr/Log/NullLogger.php',
341
+ 'phpseclib\\Crypt\\AES' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/AES.php',
342
+ 'phpseclib\\Crypt\\Base' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/Base.php',
343
+ 'phpseclib\\Crypt\\Blowfish' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/Blowfish.php',
344
+ 'phpseclib\\Crypt\\DES' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/DES.php',
345
+ 'phpseclib\\Crypt\\Hash' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/Hash.php',
346
+ 'phpseclib\\Crypt\\RC2' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/RC2.php',
347
+ 'phpseclib\\Crypt\\RC4' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/RC4.php',
348
+ 'phpseclib\\Crypt\\RSA' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/RSA.php',
349
+ 'phpseclib\\Crypt\\Random' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/Random.php',
350
+ 'phpseclib\\Crypt\\Rijndael' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/Rijndael.php',
351
+ 'phpseclib\\Crypt\\TripleDES' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/TripleDES.php',
352
+ 'phpseclib\\Crypt\\Twofish' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/Twofish.php',
353
+ 'phpseclib\\Math\\BigInteger' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Math/BigInteger.php',
354
  );
355
 
356
  public static function getInitializer(ClassLoader $loader)
357
  {
358
  return \Closure::bind(function () use ($loader) {
359
+ $loader->prefixLengthsPsr4 = ComposerStaticInitbd625bfb904527ebcdc364a59295e538::$prefixLengthsPsr4;
360
+ $loader->prefixDirsPsr4 = ComposerStaticInitbd625bfb904527ebcdc364a59295e538::$prefixDirsPsr4;
361
+ $loader->prefixesPsr0 = ComposerStaticInitbd625bfb904527ebcdc364a59295e538::$prefixesPsr0;
362
+ $loader->classMap = ComposerStaticInitbd625bfb904527ebcdc364a59295e538::$classMap;
363
 
364
  }, null, ClassLoader::class);
365
  }
vendor/phpseclib/phpseclib/phpseclib/Crypt/Base.php DELETED
@@ -1,2558 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Base Class for all \phpseclib\Crypt\* cipher classes
5
- *
6
- * PHP version 5
7
- *
8
- * Internally for phpseclib developers:
9
- * If you plan to add a new cipher class, please note following rules:
10
- *
11
- * - The new \phpseclib\Crypt\* cipher class should extend \phpseclib\Crypt\Base
12
- *
13
- * - Following methods are then required to be overridden/overloaded:
14
- *
15
- * - _encryptBlock()
16
- *
17
- * - _decryptBlock()
18
- *
19
- * - _setupKey()
20
- *
21
- * - All other methods are optional to be overridden/overloaded
22
- *
23
- * - Look at the source code of the current ciphers how they extend \phpseclib\Crypt\Base
24
- * and take one of them as a start up for the new cipher class.
25
- *
26
- * - Please read all the other comments/notes/hints here also for each class var/method
27
- *
28
- * @category Crypt
29
- * @package Base
30
- * @author Jim Wigginton <terrafrost@php.net>
31
- * @author Hans-Juergen Petrich <petrich@tronic-media.com>
32
- * @copyright 2007 Jim Wigginton
33
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
34
- * @link http://phpseclib.sourceforge.net
35
- */
36
-
37
- namespace phpseclib\Crypt;
38
-
39
- /**
40
- * Base Class for all \phpseclib\Crypt\* cipher classes
41
- *
42
- * @package Base
43
- * @author Jim Wigginton <terrafrost@php.net>
44
- * @author Hans-Juergen Petrich <petrich@tronic-media.com>
45
- */
46
- abstract class Base
47
- {
48
- /**#@+
49
- * @access public
50
- * @see \phpseclib\Crypt\Base::encrypt()
51
- * @see \phpseclib\Crypt\Base::decrypt()
52
- */
53
- /**
54
- * Encrypt / decrypt using the Counter mode.
55
- *
56
- * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
57
- *
58
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
59
- */
60
- const MODE_CTR = -1;
61
- /**
62
- * Encrypt / decrypt using the Electronic Code Book mode.
63
- *
64
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
65
- */
66
- const MODE_ECB = 1;
67
- /**
68
- * Encrypt / decrypt using the Code Book Chaining mode.
69
- *
70
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
71
- */
72
- const MODE_CBC = 2;
73
- /**
74
- * Encrypt / decrypt using the Cipher Feedback mode.
75
- *
76
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
77
- */
78
- const MODE_CFB = 3;
79
- /**
80
- * Encrypt / decrypt using the Output Feedback mode.
81
- *
82
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
83
- */
84
- const MODE_OFB = 4;
85
- /**
86
- * Encrypt / decrypt using streaming mode.
87
- */
88
- const MODE_STREAM = 5;
89
- /**#@-*/
90
-
91
- /**
92
- * Whirlpool available flag
93
- *
94
- * @see \phpseclib\Crypt\Base::_hashInlineCryptFunction()
95
- * @var bool
96
- * @access private
97
- */
98
- static $WHIRLPOOL_AVAILABLE;
99
-
100
- /**#@+
101
- * @access private
102
- * @see \phpseclib\Crypt\Base::__construct()
103
- */
104
- /**
105
- * Base value for the internal implementation $engine switch
106
- */
107
- const ENGINE_INTERNAL = 1;
108
- /**
109
- * Base value for the mcrypt implementation $engine switch
110
- */
111
- const ENGINE_MCRYPT = 2;
112
- /**
113
- * Base value for the mcrypt implementation $engine switch
114
- */
115
- const ENGINE_OPENSSL = 3;
116
- /**#@-*/
117
-
118
- /**
119
- * The Encryption Mode
120
- *
121
- * @see self::__construct()
122
- * @var int
123
- * @access private
124
- */
125
- var $mode;
126
-
127
- /**
128
- * The Block Length of the block cipher
129
- *
130
- * @var int
131
- * @access private
132
- */
133
- var $block_size = 16;
134
-
135
- /**
136
- * The Key
137
- *
138
- * @see self::setKey()
139
- * @var string
140
- * @access private
141
- */
142
- var $key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
143
-
144
- /**
145
- * The Initialization Vector
146
- *
147
- * @see self::setIV()
148
- * @var string
149
- * @access private
150
- */
151
- var $iv;
152
-
153
- /**
154
- * A "sliding" Initialization Vector
155
- *
156
- * @see self::enableContinuousBuffer()
157
- * @see self::_clearBuffers()
158
- * @var string
159
- * @access private
160
- */
161
- var $encryptIV;
162
-
163
- /**
164
- * A "sliding" Initialization Vector
165
- *
166
- * @see self::enableContinuousBuffer()
167
- * @see self::_clearBuffers()
168
- * @var string
169
- * @access private
170
- */
171
- var $decryptIV;
172
-
173
- /**
174
- * Continuous Buffer status
175
- *
176
- * @see self::enableContinuousBuffer()
177
- * @var bool
178
- * @access private
179
- */
180
- var $continuousBuffer = false;
181
-
182
- /**
183
- * Encryption buffer for CTR, OFB and CFB modes
184
- *
185
- * @see self::encrypt()
186
- * @see self::_clearBuffers()
187
- * @var array
188
- * @access private
189
- */
190
- var $enbuffer;
191
-
192
- /**
193
- * Decryption buffer for CTR, OFB and CFB modes
194
- *
195
- * @see self::decrypt()
196
- * @see self::_clearBuffers()
197
- * @var array
198
- * @access private
199
- */
200
- var $debuffer;
201
-
202
- /**
203
- * mcrypt resource for encryption
204
- *
205
- * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
206
- * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
207
- *
208
- * @see self::encrypt()
209
- * @var resource
210
- * @access private
211
- */
212
- var $enmcrypt;
213
-
214
- /**
215
- * mcrypt resource for decryption
216
- *
217
- * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
218
- * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
219
- *
220
- * @see self::decrypt()
221
- * @var resource
222
- * @access private
223
- */
224
- var $demcrypt;
225
-
226
- /**
227
- * Does the enmcrypt resource need to be (re)initialized?
228
- *
229
- * @see \phpseclib\Crypt\Twofish::setKey()
230
- * @see \phpseclib\Crypt\Twofish::setIV()
231
- * @var bool
232
- * @access private
233
- */
234
- var $enchanged = true;
235
-
236
- /**
237
- * Does the demcrypt resource need to be (re)initialized?
238
- *
239
- * @see \phpseclib\Crypt\Twofish::setKey()
240
- * @see \phpseclib\Crypt\Twofish::setIV()
241
- * @var bool
242
- * @access private
243
- */
244
- var $dechanged = true;
245
-
246
- /**
247
- * mcrypt resource for CFB mode
248
- *
249
- * mcrypt's CFB mode, in (and only in) buffered context,
250
- * is broken, so phpseclib implements the CFB mode by it self,
251
- * even when the mcrypt php extension is available.
252
- *
253
- * In order to do the CFB-mode work (fast) phpseclib
254
- * use a separate ECB-mode mcrypt resource.
255
- *
256
- * @link http://phpseclib.sourceforge.net/cfb-demo.phps
257
- * @see self::encrypt()
258
- * @see self::decrypt()
259
- * @see self::_setupMcrypt()
260
- * @var resource
261
- * @access private
262
- */
263
- var $ecb;
264
-
265
- /**
266
- * Optimizing value while CFB-encrypting
267
- *
268
- * Only relevant if $continuousBuffer enabled
269
- * and $engine == self::ENGINE_MCRYPT
270
- *
271
- * It's faster to re-init $enmcrypt if
272
- * $buffer bytes > $cfb_init_len than
273
- * using the $ecb resource furthermore.
274
- *
275
- * This value depends of the chosen cipher
276
- * and the time it would be needed for it's
277
- * initialization [by mcrypt_generic_init()]
278
- * which, typically, depends on the complexity
279
- * on its internaly Key-expanding algorithm.
280
- *
281
- * @see self::encrypt()
282
- * @var int
283
- * @access private
284
- */
285
- var $cfb_init_len = 600;
286
-
287
- /**
288
- * Does internal cipher state need to be (re)initialized?
289
- *
290
- * @see self::setKey()
291
- * @see self::setIV()
292
- * @see self::disableContinuousBuffer()
293
- * @var bool
294
- * @access private
295
- */
296
- var $changed = true;
297
-
298
- /**
299
- * Padding status
300
- *
301
- * @see self::enablePadding()
302
- * @var bool
303
- * @access private
304
- */
305
- var $padding = true;
306
-
307
- /**
308
- * Is the mode one that is paddable?
309
- *
310
- * @see self::__construct()
311
- * @var bool
312
- * @access private
313
- */
314
- var $paddable = false;
315
-
316
- /**
317
- * Holds which crypt engine internaly should be use,
318
- * which will be determined automatically on __construct()
319
- *
320
- * Currently available $engines are:
321
- * - self::ENGINE_OPENSSL (very fast, php-extension: openssl, extension_loaded('openssl') required)
322
- * - self::ENGINE_MCRYPT (fast, php-extension: mcrypt, extension_loaded('mcrypt') required)
323
- * - self::ENGINE_INTERNAL (slower, pure php-engine, no php-extension required)
324
- *
325
- * @see self::_setEngine()
326
- * @see self::encrypt()
327
- * @see self::decrypt()
328
- * @var int
329
- * @access private
330
- */
331
- var $engine;
332
-
333
- /**
334
- * Holds the preferred crypt engine
335
- *
336
- * @see self::_setEngine()
337
- * @see self::setPreferredEngine()
338
- * @var int
339
- * @access private
340
- */
341
- var $preferredEngine;
342
-
343
- /**
344
- * The mcrypt specific name of the cipher
345
- *
346
- * Only used if $engine == self::ENGINE_MCRYPT
347
- *
348
- * @link http://www.php.net/mcrypt_module_open
349
- * @link http://www.php.net/mcrypt_list_algorithms
350
- * @see self::_setupMcrypt()
351
- * @var string
352
- * @access private
353
- */
354
- var $cipher_name_mcrypt;
355
-
356
- /**
357
- * The openssl specific name of the cipher
358
- *
359
- * Only used if $engine == self::ENGINE_OPENSSL
360
- *
361
- * @link http://www.php.net/openssl-get-cipher-methods
362
- * @var string
363
- * @access private
364
- */
365
- var $cipher_name_openssl;
366
-
367
- /**
368
- * The openssl specific name of the cipher in ECB mode
369
- *
370
- * If OpenSSL does not support the mode we're trying to use (CTR)
371
- * it can still be emulated with ECB mode.
372
- *
373
- * @link http://www.php.net/openssl-get-cipher-methods
374
- * @var string
375
- * @access private
376
- */
377
- var $cipher_name_openssl_ecb;
378
-
379
- /**
380
- * The default salt used by setPassword()
381
- *
382
- * @see self::setPassword()
383
- * @var string
384
- * @access private
385
- */
386
- var $password_default_salt = 'phpseclib/salt';
387
-
388
- /**
389
- * The name of the performance-optimized callback function
390
- *
391
- * Used by encrypt() / decrypt()
392
- * only if $engine == self::ENGINE_INTERNAL
393
- *
394
- * @see self::encrypt()
395
- * @see self::decrypt()
396
- * @see self::_setupInlineCrypt()
397
- * @see self::$use_inline_crypt
398
- * @var Callback
399
- * @access private
400
- */
401
- var $inline_crypt;
402
-
403
- /**
404
- * Holds whether performance-optimized $inline_crypt() can/should be used.
405
- *
406
- * @see self::encrypt()
407
- * @see self::decrypt()
408
- * @see self::inline_crypt
409
- * @var mixed
410
- * @access private
411
- */
412
- var $use_inline_crypt;
413
-
414
- /**
415
- * If OpenSSL can be used in ECB but not in CTR we can emulate CTR
416
- *
417
- * @see self::_openssl_ctr_process()
418
- * @var bool
419
- * @access private
420
- */
421
- var $openssl_emulate_ctr = false;
422
-
423
- /**
424
- * Determines what options are passed to openssl_encrypt/decrypt
425
- *
426
- * @see self::isValidEngine()
427
- * @var mixed
428
- * @access private
429
- */
430
- var $openssl_options;
431
-
432
- /**
433
- * Has the key length explicitly been set or should it be derived from the key, itself?
434
- *
435
- * @see self::setKeyLength()
436
- * @var bool
437
- * @access private
438
- */
439
- var $explicit_key_length = false;
440
-
441
- /**
442
- * Don't truncate / null pad key
443
- *
444
- * @see self::_clearBuffers()
445
- * @var bool
446
- * @access private
447
- */
448
- var $skip_key_adjustment = false;
449
-
450
- /**
451
- * Default Constructor.
452
- *
453
- * Determines whether or not the mcrypt extension should be used.
454
- *
455
- * $mode could be:
456
- *
457
- * - self::MODE_ECB
458
- *
459
- * - self::MODE_CBC
460
- *
461
- * - self::MODE_CTR
462
- *
463
- * - self::MODE_CFB
464
- *
465
- * - self::MODE_OFB
466
- *
467
- * If not explicitly set, self::MODE_CBC will be used.
468
- *
469
- * @param int $mode
470
- * @access public
471
- */
472
- function __construct($mode = self::MODE_CBC)
473
- {
474
- // $mode dependent settings
475
- switch ($mode) {
476
- case self::MODE_ECB:
477
- $this->paddable = true;
478
- $this->mode = self::MODE_ECB;
479
- break;
480
- case self::MODE_CTR:
481
- case self::MODE_CFB:
482
- case self::MODE_OFB:
483
- case self::MODE_STREAM:
484
- $this->mode = $mode;
485
- break;
486
- case self::MODE_CBC:
487
- default:
488
- $this->paddable = true;
489
- $this->mode = self::MODE_CBC;
490
- }
491
-
492
- $this->_setEngine();
493
-
494
- // Determining whether inline crypting can be used by the cipher
495
- if ($this->use_inline_crypt !== false) {
496
- $this->use_inline_crypt = version_compare(PHP_VERSION, '5.3.0') >= 0 || function_exists('create_function');
497
- }
498
- }
499
-
500
- /**
501
- * Sets the initialization vector. (optional)
502
- *
503
- * SetIV is not required when self::MODE_ECB (or ie for AES: \phpseclib\Crypt\AES::MODE_ECB) is being used. If not explicitly set, it'll be assumed
504
- * to be all zero's.
505
- *
506
- * @access public
507
- * @param string $iv
508
- * @internal Can be overwritten by a sub class, but does not have to be
509
- */
510
- function setIV($iv)
511
- {
512
- if ($this->mode == self::MODE_ECB) {
513
- return;
514
- }
515
-
516
- $this->iv = $iv;
517
- $this->changed = true;
518
- }
519
-
520
- /**
521
- * Sets the key length.
522
- *
523
- * Keys with explicitly set lengths need to be treated accordingly
524
- *
525
- * @access public
526
- * @param int $length
527
- */
528
- function setKeyLength($length)
529
- {
530
- $this->explicit_key_length = true;
531
- $this->changed = true;
532
- $this->_setEngine();
533
- }
534
-
535
- /**
536
- * Returns the current key length in bits
537
- *
538
- * @access public
539
- * @return int
540
- */
541
- function getKeyLength()
542
- {
543
- return $this->key_length << 3;
544
- }
545
-
546
- /**
547
- * Returns the current block length in bits
548
- *
549
- * @access public
550
- * @return int
551
- */
552
- function getBlockLength()
553
- {
554
- return $this->block_size << 3;
555
- }
556
-
557
- /**
558
- * Sets the key.
559
- *
560
- * The min/max length(s) of the key depends on the cipher which is used.
561
- * If the key not fits the length(s) of the cipher it will paded with null bytes
562
- * up to the closest valid key length. If the key is more than max length,
563
- * we trim the excess bits.
564
- *
565
- * If the key is not explicitly set, it'll be assumed to be all null bytes.
566
- *
567
- * @access public
568
- * @param string $key
569
- * @internal Could, but not must, extend by the child Crypt_* class
570
- */
571
- function setKey($key)
572
- {
573
- if (!$this->explicit_key_length) {
574
- $this->setKeyLength(strlen($key) << 3);
575
- $this->explicit_key_length = false;
576
- }
577
-
578
- $this->key = $key;
579
- $this->changed = true;
580
- $this->_setEngine();
581
- }
582
-
583
- /**
584
- * Sets the password.
585
- *
586
- * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows:
587
- * {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2} or pbkdf1:
588
- * $hash, $salt, $count, $dkLen
589
- *
590
- * Where $hash (default = sha1) currently supports the following hashes: see: Crypt/Hash.php
591
- *
592
- * @see Crypt/Hash.php
593
- * @param string $password
594
- * @param string $method
595
- * @return bool
596
- * @access public
597
- * @internal Could, but not must, extend by the child Crypt_* class
598
- */
599
- function setPassword($password, $method = 'pbkdf2')
600
- {
601
- $key = '';
602
-
603
- switch ($method) {
604
- default: // 'pbkdf2' or 'pbkdf1'
605
- $func_args = func_get_args();
606
-
607
- // Hash function
608
- $hash = isset($func_args[2]) ? $func_args[2] : 'sha1';
609
-
610
- // WPA and WPA2 use the SSID as the salt
611
- $salt = isset($func_args[3]) ? $func_args[3] : $this->password_default_salt;
612
-
613
- // RFC2898#section-4.2 uses 1,000 iterations by default
614
- // WPA and WPA2 use 4,096.
615
- $count = isset($func_args[4]) ? $func_args[4] : 1000;
616
-
617
- // Keylength
618
- if (isset($func_args[5])) {
619
- $dkLen = $func_args[5];
620
- } else {
621
- $dkLen = $method == 'pbkdf1' ? 2 * $this->key_length : $this->key_length;
622
- }
623
-
624
- switch (true) {
625
- case $method == 'pbkdf1':
626
- $hashObj = new Hash();
627
- $hashObj->setHash($hash);
628
- if ($dkLen > $hashObj->getLength()) {
629
- user_error('Derived key too long');
630
- return false;
631
- }
632
- $t = $password . $salt;
633
- for ($i = 0; $i < $count; ++$i) {
634
- $t = $hashObj->hash($t);
635
- }
636
- $key = substr($t, 0, $dkLen);
637
-
638
- $this->setKey(substr($key, 0, $dkLen >> 1));
639
- $this->setIV(substr($key, $dkLen >> 1));
640
-
641
- return true;
642
- // Determining if php[>=5.5.0]'s hash_pbkdf2() function avail- and useable
643
- case !function_exists('hash_pbkdf2'):
644
- case !function_exists('hash_algos'):
645
- case !in_array($hash, hash_algos()):
646
- $i = 1;
647
- while (strlen($key) < $dkLen) {
648
- $hmac = new Hash();
649
- $hmac->setHash($hash);
650
- $hmac->setKey($password);
651
- $f = $u = $hmac->hash($salt . pack('N', $i++));
652
- for ($j = 2; $j <= $count; ++$j) {
653
- $u = $hmac->hash($u);
654
- $f^= $u;
655
- }
656
- $key.= $f;
657
- }
658
- $key = substr($key, 0, $dkLen);
659
- break;
660
- default:
661
- $key = hash_pbkdf2($hash, $password, $salt, $count, $dkLen, true);
662
- }
663
- }
664
-
665
- $this->setKey($key);
666
-
667
- return true;
668
- }
669
-
670
- /**
671
- * Encrypts a message.
672
- *
673
- * $plaintext will be padded with additional bytes such that it's length is a multiple of the block size. Other cipher
674
- * implementations may or may not pad in the same manner. Other common approaches to padding and the reasons why it's
675
- * necessary are discussed in the following
676
- * URL:
677
- *
678
- * {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html}
679
- *
680
- * An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does.
681
- * strlen($plaintext) will still need to be a multiple of the block size, however, arbitrary values can be added to make it that
682
- * length.
683
- *
684
- * @see self::decrypt()
685
- * @access public
686
- * @param string $plaintext
687
- * @return string $ciphertext
688
- * @internal Could, but not must, extend by the child Crypt_* class
689
- */
690
- function encrypt($plaintext)
691
- {
692
- if ($this->paddable) {
693
- $plaintext = $this->_pad($plaintext);
694
- }
695
-
696
- if ($this->engine === self::ENGINE_OPENSSL) {
697
- if ($this->changed) {
698
- $this->_clearBuffers();
699
- $this->changed = false;
700
- }
701
- switch ($this->mode) {
702
- case self::MODE_STREAM:
703
- return openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
704
- case self::MODE_ECB:
705
- $result = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
706
- return !defined('OPENSSL_RAW_DATA') ? substr($result, 0, -$this->block_size) : $result;
707
- case self::MODE_CBC:
708
- $result = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $this->encryptIV);
709
- if (!defined('OPENSSL_RAW_DATA')) {
710
- $result = substr($result, 0, -$this->block_size);
711
- }
712
- if ($this->continuousBuffer) {
713
- $this->encryptIV = substr($result, -$this->block_size);
714
- }
715
- return $result;
716
- case self::MODE_CTR:
717
- return $this->_openssl_ctr_process($plaintext, $this->encryptIV, $this->enbuffer);
718
- case self::MODE_CFB:
719
- // cfb loosely routines inspired by openssl's:
720
- // {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1}
721
- $ciphertext = '';
722
- if ($this->continuousBuffer) {
723
- $iv = &$this->encryptIV;
724
- $pos = &$this->enbuffer['pos'];
725
- } else {
726
- $iv = $this->encryptIV;
727
- $pos = 0;
728
- }
729
- $len = strlen($plaintext);
730
- $i = 0;
731
- if ($pos) {
732
- $orig_pos = $pos;
733
- $max = $this->block_size - $pos;
734
- if ($len >= $max) {
735
- $i = $max;
736
- $len-= $max;
737
- $pos = 0;
738
- } else {
739
- $i = $len;
740
- $pos+= $len;
741
- $len = 0;
742
- }
743
- // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
744
- $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
745
- $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
746
- $plaintext = substr($plaintext, $i);
747
- }
748
-
749
- $overflow = $len % $this->block_size;
750
-
751
- if ($overflow) {
752
- $ciphertext.= openssl_encrypt(substr($plaintext, 0, -$overflow) . str_repeat("\0", $this->block_size), $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
753
- $iv = $this->_string_pop($ciphertext, $this->block_size);
754
-
755
- $size = $len - $overflow;
756
- $block = $iv ^ substr($plaintext, -$overflow);
757
- $iv = substr_replace($iv, $block, 0, $overflow);
758
- $ciphertext.= $block;
759
- $pos = $overflow;
760
- } elseif ($len) {
761
- $ciphertext = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
762
- $iv = substr($ciphertext, -$this->block_size);
763
- }
764
-
765
- return $ciphertext;
766
- case self::MODE_OFB:
767
- return $this->_openssl_ofb_process($plaintext, $this->encryptIV, $this->enbuffer);
768
- }
769
- }
770
-
771
- if ($this->engine === self::ENGINE_MCRYPT) {
772
- if ($this->changed) {
773
- $this->_setupMcrypt();
774
- $this->changed = false;
775
- }
776
- if ($this->enchanged) {
777
- @mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
778
- $this->enchanged = false;
779
- }
780
-
781
- // re: {@link http://phpseclib.sourceforge.net/cfb-demo.phps}
782
- // using mcrypt's default handing of CFB the above would output two different things. using phpseclib's
783
- // rewritten CFB implementation the above outputs the same thing twice.
784
- if ($this->mode == self::MODE_CFB && $this->continuousBuffer) {
785
- $block_size = $this->block_size;
786
- $iv = &$this->encryptIV;
787
- $pos = &$this->enbuffer['pos'];
788
- $len = strlen($plaintext);
789
- $ciphertext = '';
790
- $i = 0;
791
- if ($pos) {
792
- $orig_pos = $pos;
793
- $max = $block_size - $pos;
794
- if ($len >= $max) {
795
- $i = $max;
796
- $len-= $max;
797
- $pos = 0;
798
- } else {
799
- $i = $len;
800
- $pos+= $len;
801
- $len = 0;
802
- }
803
- $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
804
- $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
805
- $this->enbuffer['enmcrypt_init'] = true;
806
- }
807
- if ($len >= $block_size) {
808
- if ($this->enbuffer['enmcrypt_init'] === false || $len > $this->cfb_init_len) {
809
- if ($this->enbuffer['enmcrypt_init'] === true) {
810
- @mcrypt_generic_init($this->enmcrypt, $this->key, $iv);
811
- $this->enbuffer['enmcrypt_init'] = false;
812
- }
813
- $ciphertext.= @mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % $block_size));
814
- $iv = substr($ciphertext, -$block_size);
815
- $len%= $block_size;
816
- } else {
817
- while ($len >= $block_size) {
818
- $iv = @mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, $block_size);
819
- $ciphertext.= $iv;
820
- $len-= $block_size;
821
- $i+= $block_size;
822
- }
823
- }
824
- }
825
-
826
- if ($len) {
827
- $iv = @mcrypt_generic($this->ecb, $iv);
828
- $block = $iv ^ substr($plaintext, -$len);
829
- $iv = substr_replace($iv, $block, 0, $len);
830
- $ciphertext.= $block;
831
- $pos = $len;
832
- }
833
-
834
- return $ciphertext;
835
- }
836
-
837
- $ciphertext = @mcrypt_generic($this->enmcrypt, $plaintext);
838
-
839
- if (!$this->continuousBuffer) {
840
- @mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
841
- }
842
-
843
- return $ciphertext;
844
- }
845
-
846
- if ($this->changed) {
847
- $this->_setup();
848
- $this->changed = false;
849
- }
850
- if ($this->use_inline_crypt) {
851
- $inline = $this->inline_crypt;
852
- return $inline('encrypt', $this, $plaintext);
853
- }
854
-
855
- $buffer = &$this->enbuffer;
856
- $block_size = $this->block_size;
857
- $ciphertext = '';
858
- switch ($this->mode) {
859
- case self::MODE_ECB:
860
- for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
861
- $ciphertext.= $this->_encryptBlock(substr($plaintext, $i, $block_size));
862
- }
863
- break;
864
- case self::MODE_CBC:
865
- $xor = $this->encryptIV;
866
- for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
867
- $block = substr($plaintext, $i, $block_size);
868
- $block = $this->_encryptBlock($block ^ $xor);
869
- $xor = $block;
870
- $ciphertext.= $block;
871
- }
872
- if ($this->continuousBuffer) {
873
- $this->encryptIV = $xor;
874
- }
875
- break;
876
- case self::MODE_CTR:
877
- $xor = $this->encryptIV;
878
- if (strlen($buffer['ciphertext'])) {
879
- for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
880
- $block = substr($plaintext, $i, $block_size);
881
- if (strlen($block) > strlen($buffer['ciphertext'])) {
882
- $buffer['ciphertext'].= $this->_encryptBlock($xor);
883
- }
884
- $this->_increment_str($xor);
885
- $key = $this->_string_shift($buffer['ciphertext'], $block_size);
886
- $ciphertext.= $block ^ $key;
887
- }
888
- } else {
889
- for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
890
- $block = substr($plaintext, $i, $block_size);
891
- $key = $this->_encryptBlock($xor);
892
- $this->_increment_str($xor);
893
- $ciphertext.= $block ^ $key;
894
- }
895
- }
896
- if ($this->continuousBuffer) {
897
- $this->encryptIV = $xor;
898
- if ($start = strlen($plaintext) % $block_size) {
899
- $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
900
- }
901
- }
902
- break;
903
- case self::MODE_CFB:
904
- // cfb loosely routines inspired by openssl's:
905
- // {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1}
906
- if ($this->continuousBuffer) {
907
- $iv = &$this->encryptIV;
908
- $pos = &$buffer['pos'];
909
- } else {
910
- $iv = $this->encryptIV;
911
- $pos = 0;
912
- }
913
- $len = strlen($plaintext);
914
- $i = 0;
915
- if ($pos) {
916
- $orig_pos = $pos;
917
- $max = $block_size - $pos;
918
- if ($len >= $max) {
919
- $i = $max;
920
- $len-= $max;
921
- $pos = 0;
922
- } else {
923
- $i = $len;
924
- $pos+= $len;
925
- $len = 0;
926
- }
927
- // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
928
- $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
929
- $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
930
- }
931
- while ($len >= $block_size) {
932
- $iv = $this->_encryptBlock($iv) ^ substr($plaintext, $i, $block_size);
933
- $ciphertext.= $iv;
934
- $len-= $block_size;
935
- $i+= $block_size;
936
- }
937
- if ($len) {
938
- $iv = $this->_encryptBlock($iv);
939
- $block = $iv ^ substr($plaintext, $i);
940
- $iv = substr_replace($iv, $block, 0, $len);
941
- $ciphertext.= $block;
942
- $pos = $len;
943
- }
944
- break;
945
- case self::MODE_OFB:
946
- $xor = $this->encryptIV;
947
- if (strlen($buffer['xor'])) {
948
- for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
949
- $block = substr($plaintext, $i, $block_size);
950
- if (strlen($block) > strlen($buffer['xor'])) {
951
- $xor = $this->_encryptBlock($xor);
952
- $buffer['xor'].= $xor;
953
- }
954
- $key = $this->_string_shift($buffer['xor'], $block_size);
955
- $ciphertext.= $block ^ $key;
956
- }
957
- } else {
958
- for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
959
- $xor = $this->_encryptBlock($xor);
960
- $ciphertext.= substr($plaintext, $i, $block_size) ^ $xor;
961
- }
962
- $key = $xor;
963
- }
964
- if ($this->continuousBuffer) {
965
- $this->encryptIV = $xor;
966
- if ($start = strlen($plaintext) % $block_size) {
967
- $buffer['xor'] = substr($key, $start) . $buffer['xor'];
968
- }
969
- }
970
- break;
971
- case self::MODE_STREAM:
972
- $ciphertext = $this->_encryptBlock($plaintext);
973
- break;
974
- }
975
-
976
- return $ciphertext;
977
- }
978
-
979
- /**
980
- * Decrypts a message.
981
- *
982
- * If strlen($ciphertext) is not a multiple of the block size, null bytes will be added to the end of the string until
983
- * it is.
984
- *
985
- * @see self::encrypt()
986
- * @access public
987
- * @param string $ciphertext
988
- * @return string $plaintext
989
- * @internal Could, but not must, extend by the child Crypt_* class
990
- */
991
- function decrypt($ciphertext)
992
- {
993
- if ($this->paddable) {
994
- // we pad with chr(0) since that's what mcrypt_generic does. to quote from {@link http://www.php.net/function.mcrypt-generic}:
995
- // "The data is padded with "\0" to make sure the length of the data is n * blocksize."
996
- $ciphertext = str_pad($ciphertext, strlen($ciphertext) + ($this->block_size - strlen($ciphertext) % $this->block_size) % $this->block_size, chr(0));
997
- }
998
-
999
- if ($this->engine === self::ENGINE_OPENSSL) {
1000
- if ($this->changed) {
1001
- $this->_clearBuffers();
1002
- $this->changed = false;
1003
- }
1004
- switch ($this->mode) {
1005
- case self::MODE_STREAM:
1006
- $plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
1007
- break;
1008
- case self::MODE_ECB:
1009
- if (!defined('OPENSSL_RAW_DATA')) {
1010
- $ciphertext.= openssl_encrypt('', $this->cipher_name_openssl_ecb, $this->key, true);
1011
- }
1012
- $plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
1013
- break;
1014
- case self::MODE_CBC:
1015
- if (!defined('OPENSSL_RAW_DATA')) {
1016
- $padding = str_repeat(chr($this->block_size), $this->block_size) ^ substr($ciphertext, -$this->block_size);
1017
- $ciphertext.= substr(openssl_encrypt($padding, $this->cipher_name_openssl_ecb, $this->key, true), 0, $this->block_size);
1018
- $offset = 2 * $this->block_size;
1019
- } else {
1020
- $offset = $this->block_size;
1021
- }
1022
- $plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $this->decryptIV);
1023
- if ($this->continuousBuffer) {
1024
- $this->decryptIV = substr($ciphertext, -$offset, $this->block_size);
1025
- }
1026
- break;
1027
- case self::MODE_CTR:
1028
- $plaintext = $this->_openssl_ctr_process($ciphertext, $this->decryptIV, $this->debuffer);
1029
- break;
1030
- case self::MODE_CFB:
1031
- // cfb loosely routines inspired by openssl's:
1032
- // {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1}
1033
- $plaintext = '';
1034
- if ($this->continuousBuffer) {
1035
- $iv = &$this->decryptIV;
1036
- $pos = &$this->buffer['pos'];
1037
- } else {
1038
- $iv = $this->decryptIV;
1039
- $pos = 0;
1040
- }
1041
- $len = strlen($ciphertext);
1042
- $i = 0;
1043
- if ($pos) {
1044
- $orig_pos = $pos;
1045
- $max = $this->block_size - $pos;
1046
- if ($len >= $max) {
1047
- $i = $max;
1048
- $len-= $max;
1049
- $pos = 0;
1050
- } else {
1051
- $i = $len;
1052
- $pos+= $len;
1053
- $len = 0;
1054
- }
1055
- // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $this->blocksize
1056
- $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
1057
- $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
1058
- $ciphertext = substr($ciphertext, $i);
1059
- }
1060
- $overflow = $len % $this->block_size;
1061
- if ($overflow) {
1062
- $plaintext.= openssl_decrypt(substr($ciphertext, 0, -$overflow), $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
1063
- if ($len - $overflow) {
1064
- $iv = substr($ciphertext, -$overflow - $this->block_size, -$overflow);
1065
- }
1066
- $iv = openssl_encrypt(str_repeat("\0", $this->block_size), $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
1067
- $plaintext.= $iv ^ substr($ciphertext, -$overflow);
1068
- $iv = substr_replace($iv, substr($ciphertext, -$overflow), 0, $overflow);
1069
- $pos = $overflow;
1070
- } elseif ($len) {
1071
- $plaintext.= openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
1072
- $iv = substr($ciphertext, -$this->block_size);
1073
- }
1074
- break;
1075
- case self::MODE_OFB:
1076
- $plaintext = $this->_openssl_ofb_process($ciphertext, $this->decryptIV, $this->debuffer);
1077
- }
1078
-
1079
- return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
1080
- }
1081
-
1082
- if ($this->engine === self::ENGINE_MCRYPT) {
1083
- $block_size = $this->block_size;
1084
- if ($this->changed) {
1085
- $this->_setupMcrypt();
1086
- $this->changed = false;
1087
- }
1088
- if ($this->dechanged) {
1089
- @mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
1090
- $this->dechanged = false;
1091
- }
1092
-
1093
- if ($this->mode == self::MODE_CFB && $this->continuousBuffer) {
1094
- $iv = &$this->decryptIV;
1095
- $pos = &$this->debuffer['pos'];
1096
- $len = strlen($ciphertext);
1097
- $plaintext = '';
1098
- $i = 0;
1099
- if ($pos) {
1100
- $orig_pos = $pos;
1101
- $max = $block_size - $pos;
1102
- if ($len >= $max) {
1103
- $i = $max;
1104
- $len-= $max;
1105
- $pos = 0;
1106
- } else {
1107
- $i = $len;
1108
- $pos+= $len;
1109
- $len = 0;
1110
- }
1111
- // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
1112
- $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
1113
- $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
1114
- }
1115
- if ($len >= $block_size) {
1116
- $cb = substr($ciphertext, $i, $len - $len % $block_size);
1117
- $plaintext.= @mcrypt_generic($this->ecb, $iv . $cb) ^ $cb;
1118
- $iv = substr($cb, -$block_size);
1119
- $len%= $block_size;
1120
- }
1121
- if ($len) {
1122
- $iv = @mcrypt_generic($this->ecb, $iv);
1123
- $plaintext.= $iv ^ substr($ciphertext, -$len);
1124
- $iv = substr_replace($iv, substr($ciphertext, -$len), 0, $len);
1125
- $pos = $len;
1126
- }
1127
-
1128
- return $plaintext;
1129
- }
1130
-
1131
- $plaintext = @mdecrypt_generic($this->demcrypt, $ciphertext);
1132
-
1133
- if (!$this->continuousBuffer) {
1134
- @mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
1135
- }
1136
-
1137
- return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
1138
- }
1139
-
1140
- if ($this->changed) {
1141
- $this->_setup();
1142
- $this->changed = false;
1143
- }
1144
- if ($this->use_inline_crypt) {
1145
- $inline = $this->inline_crypt;
1146
- return $inline('decrypt', $this, $ciphertext);
1147
- }
1148
-
1149
- $block_size = $this->block_size;
1150
-
1151
- $buffer = &$this->debuffer;
1152
- $plaintext = '';
1153
- switch ($this->mode) {
1154
- case self::MODE_ECB:
1155
- for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1156
- $plaintext.= $this->_decryptBlock(substr($ciphertext, $i, $block_size));
1157
- }
1158
- break;
1159
- case self::MODE_CBC:
1160
- $xor = $this->decryptIV;
1161
- for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1162
- $block = substr($ciphertext, $i, $block_size);
1163
- $plaintext.= $this->_decryptBlock($block) ^ $xor;
1164
- $xor = $block;
1165
- }
1166
- if ($this->continuousBuffer) {
1167
- $this->decryptIV = $xor;
1168
- }
1169
- break;
1170
- case self::MODE_CTR:
1171
- $xor = $this->decryptIV;
1172
- if (strlen($buffer['ciphertext'])) {
1173
- for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1174
- $block = substr($ciphertext, $i, $block_size);
1175
- if (strlen($block) > strlen($buffer['ciphertext'])) {
1176
- $buffer['ciphertext'].= $this->_encryptBlock($xor);
1177
- $this->_increment_str($xor);
1178
- }
1179
- $key = $this->_string_shift($buffer['ciphertext'], $block_size);
1180
- $plaintext.= $block ^ $key;
1181
- }
1182
- } else {
1183
- for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1184
- $block = substr($ciphertext, $i, $block_size);
1185
- $key = $this->_encryptBlock($xor);
1186
- $this->_increment_str($xor);
1187
- $plaintext.= $block ^ $key;
1188
- }
1189
- }
1190
- if ($this->continuousBuffer) {
1191
- $this->decryptIV = $xor;
1192
- if ($start = strlen($ciphertext) % $block_size) {
1193
- $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
1194
- }
1195
- }
1196
- break;
1197
- case self::MODE_CFB:
1198
- if ($this->continuousBuffer) {
1199
- $iv = &$this->decryptIV;
1200
- $pos = &$buffer['pos'];
1201
- } else {
1202
- $iv = $this->decryptIV;
1203
- $pos = 0;
1204
- }
1205
- $len = strlen($ciphertext);
1206
- $i = 0;
1207
- if ($pos) {
1208
- $orig_pos = $pos;
1209
- $max = $block_size - $pos;
1210
- if ($len >= $max) {
1211
- $i = $max;
1212
- $len-= $max;
1213
- $pos = 0;
1214
- } else {
1215
- $i = $len;
1216
- $pos+= $len;
1217
- $len = 0;
1218
- }
1219
- // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
1220
- $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
1221
- $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
1222
- }
1223
- while ($len >= $block_size) {
1224
- $iv = $this->_encryptBlock($iv);
1225
- $cb = substr($ciphertext, $i, $block_size);
1226
- $plaintext.= $iv ^ $cb;
1227
- $iv = $cb;
1228
- $len-= $block_size;
1229
- $i+= $block_size;
1230
- }
1231
- if ($len) {
1232
- $iv = $this->_encryptBlock($iv);
1233
- $plaintext.= $iv ^ substr($ciphertext, $i);
1234
- $iv = substr_replace($iv, substr($ciphertext, $i), 0, $len);
1235
- $pos = $len;
1236
- }
1237
- break;
1238
- case self::MODE_OFB:
1239
- $xor = $this->decryptIV;
1240
- if (strlen($buffer['xor'])) {
1241
- for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1242
- $block = substr($ciphertext, $i, $block_size);
1243
- if (strlen($block) > strlen($buffer['xor'])) {
1244
- $xor = $this->_encryptBlock($xor);
1245
- $buffer['xor'].= $xor;
1246
- }
1247
- $key = $this->_string_shift($buffer['xor'], $block_size);
1248
- $plaintext.= $block ^ $key;
1249
- }
1250
- } else {
1251
- for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1252
- $xor = $this->_encryptBlock($xor);
1253
- $plaintext.= substr($ciphertext, $i, $block_size) ^ $xor;
1254
- }
1255
- $key = $xor;
1256
- }
1257
- if ($this->continuousBuffer) {
1258
- $this->decryptIV = $xor;
1259
- if ($start = strlen($ciphertext) % $block_size) {
1260
- $buffer['xor'] = substr($key, $start) . $buffer['xor'];
1261
- }
1262
- }
1263
- break;
1264
- case self::MODE_STREAM:
1265
- $plaintext = $this->_decryptBlock($ciphertext);
1266
- break;
1267
- }
1268
- return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
1269
- }
1270
-
1271
- /**
1272
- * OpenSSL CTR Processor
1273
- *
1274
- * PHP's OpenSSL bindings do not operate in continuous mode so we'll wrap around it. Since the keystream
1275
- * for CTR is the same for both encrypting and decrypting this function is re-used by both Base::encrypt()
1276
- * and Base::decrypt(). Also, OpenSSL doesn't implement CTR for all of it's symmetric ciphers so this
1277
- * function will emulate CTR with ECB when necessary.
1278
- *
1279
- * @see self::encrypt()
1280
- * @see self::decrypt()
1281
- * @param string $plaintext
1282
- * @param string $encryptIV
1283
- * @param array $buffer
1284
- * @return string
1285
- * @access private
1286
- */
1287
- function _openssl_ctr_process($plaintext, &$encryptIV, &$buffer)
1288
- {
1289
- $ciphertext = '';
1290
-
1291
- $block_size = $this->block_size;
1292
- $key = $this->key;
1293
-
1294
- if ($this->openssl_emulate_ctr) {
1295
- $xor = $encryptIV;
1296
- if (strlen($buffer['ciphertext'])) {
1297
- for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
1298
- $block = substr($plaintext, $i, $block_size);
1299
- if (strlen($block) > strlen($buffer['ciphertext'])) {
1300
- $result = openssl_encrypt($xor, $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
1301
- $result = !defined('OPENSSL_RAW_DATA') ? substr($result, 0, -$this->block_size) : $result;
1302
- $buffer['ciphertext'].= $result;
1303
- }
1304
- $this->_increment_str($xor);
1305
- $otp = $this->_string_shift($buffer['ciphertext'], $block_size);
1306
- $ciphertext.= $block ^ $otp;
1307
- }
1308
- } else {
1309
- for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
1310
- $block = substr($plaintext, $i, $block_size);
1311
- $otp = openssl_encrypt($xor, $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
1312
- $otp = !defined('OPENSSL_RAW_DATA') ? substr($otp, 0, -$this->block_size) : $otp;
1313
- $this->_increment_str($xor);
1314
- $ciphertext.= $block ^ $otp;
1315
- }
1316
- }
1317
- if ($this->continuousBuffer) {
1318
- $encryptIV = $xor;
1319
- if ($start = strlen($plaintext) % $block_size) {
1320
- $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
1321
- }
1322
- }
1323
-
1324
- return $ciphertext;
1325
- }
1326
-
1327
- if (strlen($buffer['ciphertext'])) {
1328
- $ciphertext = $plaintext ^ $this->_string_shift($buffer['ciphertext'], strlen($plaintext));
1329
- $plaintext = substr($plaintext, strlen($ciphertext));
1330
-
1331
- if (!strlen($plaintext)) {
1332
- return $ciphertext;
1333
- }
1334
- }
1335
-
1336
- $overflow = strlen($plaintext) % $block_size;
1337
- if ($overflow) {
1338
- $plaintext2 = $this->_string_pop($plaintext, $overflow); // ie. trim $plaintext to a multiple of $block_size and put rest of $plaintext in $plaintext2
1339
- $encrypted = openssl_encrypt($plaintext . str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV);
1340
- $temp = $this->_string_pop($encrypted, $block_size);
1341
- $ciphertext.= $encrypted . ($plaintext2 ^ $temp);
1342
- if ($this->continuousBuffer) {
1343
- $buffer['ciphertext'] = substr($temp, $overflow);
1344
- $encryptIV = $temp;
1345
- }
1346
- } elseif (!strlen($buffer['ciphertext'])) {
1347
- $ciphertext.= openssl_encrypt($plaintext . str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV);
1348
- $temp = $this->_string_pop($ciphertext, $block_size);
1349
- if ($this->continuousBuffer) {
1350
- $encryptIV = $temp;
1351
- }
1352
- }
1353
- if ($this->continuousBuffer) {
1354
- if (!defined('OPENSSL_RAW_DATA')) {
1355
- $encryptIV.= openssl_encrypt('', $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
1356
- }
1357
- $encryptIV = openssl_decrypt($encryptIV, $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
1358
- if ($overflow) {
1359
- $this->_increment_str($encryptIV);
1360
- }
1361
- }
1362
-
1363
- return $ciphertext;
1364
- }
1365
-
1366
- /**
1367
- * OpenSSL OFB Processor
1368
- *
1369
- * PHP's OpenSSL bindings do not operate in continuous mode so we'll wrap around it. Since the keystream
1370
- * for OFB is the same for both encrypting and decrypting this function is re-used by both Base::encrypt()
1371
- * and Base::decrypt().
1372
- *
1373
- * @see self::encrypt()
1374
- * @see self::decrypt()
1375
- * @param string $plaintext
1376
- * @param string $encryptIV
1377
- * @param array $buffer
1378
- * @return string
1379
- * @access private
1380
- */
1381
- function _openssl_ofb_process($plaintext, &$encryptIV, &$buffer)
1382
- {
1383
- if (strlen($buffer['xor'])) {
1384
- $ciphertext = $plaintext ^ $buffer['xor'];
1385
- $buffer['xor'] = substr($buffer['xor'], strlen($ciphertext));
1386
- $plaintext = substr($plaintext, strlen($ciphertext));
1387
- } else {
1388
- $ciphertext = '';
1389
- }
1390
-
1391
- $block_size = $this->block_size;
1392
-
1393
- $len = strlen($plaintext);
1394
- $key = $this->key;
1395
- $overflow = $len % $block_size;
1396
-
1397
- if (strlen($plaintext)) {
1398
- if ($overflow) {
1399
- $ciphertext.= openssl_encrypt(substr($plaintext, 0, -$overflow) . str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV);
1400
- $xor = $this->_string_pop($ciphertext, $block_size);
1401
- if ($this->continuousBuffer) {
1402
- $encryptIV = $xor;
1403
- }
1404
- $ciphertext.= $this->_string_shift($xor, $overflow) ^ substr($plaintext, -$overflow);
1405
- if ($this->continuousBuffer) {
1406
- $buffer['xor'] = $xor;
1407
- }
1408
- } else {
1409
- $ciphertext = openssl_encrypt($plaintext, $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV);
1410
- if ($this->continuousBuffer) {
1411
- $encryptIV = substr($ciphertext, -$block_size) ^ substr($plaintext, -$block_size);
1412
- }
1413
- }
1414
- }
1415
-
1416
- return $ciphertext;
1417
- }
1418
-
1419
- /**
1420
- * phpseclib <-> OpenSSL Mode Mapper
1421
- *
1422
- * May need to be overwritten by classes extending this one in some cases
1423
- *
1424
- * @return int
1425
- * @access private
1426
- */
1427
- function _openssl_translate_mode()
1428
- {
1429
- switch ($this->mode) {
1430
- case self::MODE_ECB:
1431
- return 'ecb';
1432
- case self::MODE_CBC:
1433
- return 'cbc';
1434
- case self::MODE_CTR:
1435
- return 'ctr';
1436
- case self::MODE_CFB:
1437
- return 'cfb';
1438
- case self::MODE_OFB:
1439
- return 'ofb';
1440
- }
1441
- }
1442
-
1443
- /**
1444
- * Pad "packets".
1445
- *
1446
- * Block ciphers working by encrypting between their specified [$this->]block_size at a time
1447
- * If you ever need to encrypt or decrypt something that isn't of the proper length, it becomes necessary to
1448
- * pad the input so that it is of the proper length.
1449
- *
1450
- * Padding is enabled by default. Sometimes, however, it is undesirable to pad strings. Such is the case in SSH,
1451
- * where "packets" are padded with random bytes before being encrypted. Unpad these packets and you risk stripping
1452
- * away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is
1453
- * transmitted separately)
1454
- *
1455
- * @see self::disablePadding()
1456
- * @access public
1457
- */
1458
- function enablePadding()
1459
- {
1460
- $this->padding = true;
1461
- }
1462
-
1463
- /**
1464
- * Do not pad packets.
1465
- *
1466
- * @see self::enablePadding()
1467
- * @access public
1468
- */
1469
- function disablePadding()
1470
- {
1471
- $this->padding = false;
1472
- }
1473
-
1474
- /**
1475
- * Treat consecutive "packets" as if they are a continuous buffer.
1476
- *
1477
- * Say you have a 32-byte plaintext $plaintext. Using the default behavior, the two following code snippets
1478
- * will yield different outputs:
1479
- *
1480
- * <code>
1481
- * echo $rijndael->encrypt(substr($plaintext, 0, 16));
1482
- * echo $rijndael->encrypt(substr($plaintext, 16, 16));
1483
- * </code>
1484
- * <code>
1485
- * echo $rijndael->encrypt($plaintext);
1486
- * </code>
1487
- *
1488
- * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates
1489
- * another, as demonstrated with the following:
1490
- *
1491
- * <code>
1492
- * $rijndael->encrypt(substr($plaintext, 0, 16));
1493
- * echo $rijndael->decrypt($rijndael->encrypt(substr($plaintext, 16, 16)));
1494
- * </code>
1495
- * <code>
1496
- * echo $rijndael->decrypt($rijndael->encrypt(substr($plaintext, 16, 16)));
1497
- * </code>
1498
- *
1499
- * With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different
1500
- * outputs. The reason is due to the fact that the initialization vector's change after every encryption /
1501
- * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant.
1502
- *
1503
- * Put another way, when the continuous buffer is enabled, the state of the \phpseclib\Crypt\*() object changes after each
1504
- * encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that
1505
- * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them),
1506
- * however, they are also less intuitive and more likely to cause you problems.
1507
- *
1508
- * @see self::disableContinuousBuffer()
1509
- * @access public
1510
- * @internal Could, but not must, extend by the child Crypt_* class
1511
- */
1512
- function enableContinuousBuffer()
1513
- {
1514
- if ($this->mode == self::MODE_ECB) {
1515
- return;
1516
- }
1517
-
1518
- $this->continuousBuffer = true;
1519
-
1520
- $this->_setEngine();
1521
- }
1522
-
1523
- /**
1524
- * Treat consecutive packets as if they are a discontinuous buffer.
1525
- *
1526
- * The default behavior.
1527
- *
1528
- * @see self::enableContinuousBuffer()
1529
- * @access public
1530
- * @internal Could, but not must, extend by the child Crypt_* class
1531
- */
1532
- function disableContinuousBuffer()
1533
- {
1534
- if ($this->mode == self::MODE_ECB) {
1535
- return;
1536
- }
1537
- if (!$this->continuousBuffer) {
1538
- return;
1539
- }
1540
-
1541
- $this->continuousBuffer = false;
1542
- $this->changed = true;
1543
-
1544
- $this->_setEngine();
1545
- }
1546
-
1547
- /**
1548
- * Test for engine validity
1549
- *
1550
- * @see self::__construct()
1551
- * @param int $engine
1552
- * @access public
1553
- * @return bool
1554
- */
1555
- function isValidEngine($engine)
1556
- {
1557
- switch ($engine) {
1558
- case self::ENGINE_OPENSSL:
1559
- if ($this->mode == self::MODE_STREAM && $this->continuousBuffer) {
1560
- return false;
1561
- }
1562
- $this->openssl_emulate_ctr = false;
1563
- $result = $this->cipher_name_openssl &&
1564
- extension_loaded('openssl') &&
1565
- // PHP 5.3.0 - 5.3.2 did not let you set IV's
1566
- version_compare(PHP_VERSION, '5.3.3', '>=');
1567
- if (!$result) {
1568
- return false;
1569
- }
1570
-
1571
- // prior to PHP 5.4.0 OPENSSL_RAW_DATA and OPENSSL_ZERO_PADDING were not defined. instead of expecting an integer
1572
- // $options openssl_encrypt expected a boolean $raw_data.
1573
- if (!defined('OPENSSL_RAW_DATA')) {
1574
- $this->openssl_options = true;
1575
- } else {
1576
- $this->openssl_options = OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING;
1577
- }
1578
-
1579
- $methods = openssl_get_cipher_methods();
1580
- if (in_array($this->cipher_name_openssl, $methods)) {
1581
- return true;
1582
- }
1583
- // not all of openssl's symmetric cipher's support ctr. for those
1584
- // that don't we'll emulate it
1585
- switch ($this->mode) {
1586
- case self::MODE_CTR:
1587
- if (in_array($this->cipher_name_openssl_ecb, $methods)) {
1588
- $this->openssl_emulate_ctr = true;
1589
- return true;
1590
- }
1591
- }
1592
- return false;
1593
- case self::ENGINE_MCRYPT:
1594
- return $this->cipher_name_mcrypt &&
1595
- extension_loaded('mcrypt') &&
1596
- in_array($this->cipher_name_mcrypt, @mcrypt_list_algorithms());
1597
- case self::ENGINE_INTERNAL:
1598
- return true;
1599
- }
1600
-
1601
- return false;
1602
- }
1603
-
1604
- /**
1605
- * Sets the preferred crypt engine
1606
- *
1607
- * Currently, $engine could be:
1608
- *
1609
- * - \phpseclib\Crypt\Base::ENGINE_OPENSSL [very fast]
1610
- *
1611
- * - \phpseclib\Crypt\Base::ENGINE_MCRYPT [fast]
1612
- *
1613
- * - \phpseclib\Crypt\Base::ENGINE_INTERNAL [slow]
1614
- *
1615
- * If the preferred crypt engine is not available the fastest available one will be used
1616
- *
1617
- * @see self::__construct()
1618
- * @param int $engine
1619
- * @access public
1620
- */
1621
- function setPreferredEngine($engine)
1622
- {
1623
- switch ($engine) {
1624
- //case self::ENGINE_OPENSSL;
1625
- case self::ENGINE_MCRYPT:
1626
- case self::ENGINE_INTERNAL:
1627
- $this->preferredEngine = $engine;
1628
- break;
1629
- default:
1630
- $this->preferredEngine = self::ENGINE_OPENSSL;
1631
- }
1632
-
1633
- $this->_setEngine();
1634
- }
1635
-
1636
- /**
1637
- * Returns the engine currently being utilized
1638
- *
1639
- * @see self::_setEngine()
1640
- * @access public
1641
- */
1642
- function getEngine()
1643
- {
1644
- return $this->engine;
1645
- }
1646
-
1647
- /**
1648
- * Sets the engine as appropriate
1649
- *
1650
- * @see self::__construct()
1651
- * @access private
1652
- */
1653
- function _setEngine()
1654
- {
1655
- $this->engine = null;
1656
-
1657
- $candidateEngines = array(
1658
- $this->preferredEngine,
1659
- self::ENGINE_OPENSSL,
1660
- self::ENGINE_MCRYPT
1661
- );
1662
- foreach ($candidateEngines as $engine) {
1663
- if ($this->isValidEngine($engine)) {
1664
- $this->engine = $engine;
1665
- break;
1666
- }
1667
- }
1668
- if (!$this->engine) {
1669
- $this->engine = self::ENGINE_INTERNAL;
1670
- }
1671
-
1672
- if ($this->engine != self::ENGINE_MCRYPT && $this->enmcrypt) {
1673
- // Closing the current mcrypt resource(s). _mcryptSetup() will, if needed,
1674
- // (re)open them with the module named in $this->cipher_name_mcrypt
1675
- @mcrypt_module_close($this->enmcrypt);
1676
- @mcrypt_module_close($this->demcrypt);
1677
- $this->enmcrypt = null;
1678
- $this->demcrypt = null;
1679
-
1680
- if ($this->ecb) {
1681
- @mcrypt_module_close($this->ecb);
1682
- $this->ecb = null;
1683
- }
1684
- }
1685
-
1686
- $this->changed = true;
1687
- }
1688
-
1689
- /**
1690
- * Encrypts a block
1691
- *
1692
- * Note: Must be extended by the child \phpseclib\Crypt\* class
1693
- *
1694
- * @access private
1695
- * @param string $in
1696
- * @return string
1697
- */
1698
- abstract function _encryptBlock($in);
1699
-
1700
- /**
1701
- * Decrypts a block
1702
- *
1703
- * Note: Must be extended by the child \phpseclib\Crypt\* class
1704
- *
1705
- * @access private
1706
- * @param string $in
1707
- * @return string
1708
- */
1709
- abstract function _decryptBlock($in);
1710
-
1711
- /**
1712
- * Setup the key (expansion)
1713
- *
1714
- * Only used if $engine == self::ENGINE_INTERNAL
1715
- *
1716
- * Note: Must extend by the child \phpseclib\Crypt\* class
1717
- *
1718
- * @see self::_setup()
1719
- * @access private
1720
- */
1721
- abstract function _setupKey();
1722
-
1723
- /**
1724
- * Setup the self::ENGINE_INTERNAL $engine
1725
- *
1726
- * (re)init, if necessary, the internal cipher $engine and flush all $buffers
1727
- * Used (only) if $engine == self::ENGINE_INTERNAL
1728
- *
1729
- * _setup() will be called each time if $changed === true
1730
- * typically this happens when using one or more of following public methods:
1731
- *
1732
- * - setKey()
1733
- *
1734
- * - setIV()
1735
- *
1736
- * - disableContinuousBuffer()
1737
- *
1738
- * - First run of encrypt() / decrypt() with no init-settings
1739
- *
1740
- * @see self::setKey()
1741
- * @see self::setIV()
1742
- * @see self::disableContinuousBuffer()
1743
- * @access private
1744
- * @internal _setup() is always called before en/decryption.
1745
- * @internal Could, but not must, extend by the child Crypt_* class
1746
- */
1747
- function _setup()
1748
- {
1749
- $this->_clearBuffers();
1750
- $this->_setupKey();
1751
-
1752
- if ($this->use_inline_crypt) {
1753
- $this->_setupInlineCrypt();
1754
- }
1755
- }
1756
-
1757
- /**
1758
- * Setup the self::ENGINE_MCRYPT $engine
1759
- *
1760
- * (re)init, if necessary, the (ext)mcrypt resources and flush all $buffers
1761
- * Used (only) if $engine = self::ENGINE_MCRYPT
1762
- *
1763
- * _setupMcrypt() will be called each time if $changed === true
1764
- * typically this happens when using one or more of following public methods:
1765
- *
1766
- * - setKey()
1767
- *
1768
- * - setIV()
1769
- *
1770
- * - disableContinuousBuffer()
1771
- *
1772
- * - First run of encrypt() / decrypt()
1773
- *
1774
- * @see self::setKey()
1775
- * @see self::setIV()
1776
- * @see self::disableContinuousBuffer()
1777
- * @access private
1778
- * @internal Could, but not must, extend by the child Crypt_* class
1779
- */
1780
- function _setupMcrypt()
1781
- {
1782
- $this->_clearBuffers();
1783
- $this->enchanged = $this->dechanged = true;
1784
-
1785
- if (!isset($this->enmcrypt)) {
1786
- static $mcrypt_modes = array(
1787
- self::MODE_CTR => 'ctr',
1788
- self::MODE_ECB => MCRYPT_MODE_ECB,
1789
- self::MODE_CBC => MCRYPT_MODE_CBC,
1790
- self::MODE_CFB => 'ncfb',
1791
- self::MODE_OFB => MCRYPT_MODE_NOFB,
1792
- self::MODE_STREAM => MCRYPT_MODE_STREAM,
1793
- );
1794
-
1795
- $this->demcrypt = @mcrypt_module_open($this->cipher_name_mcrypt, '', $mcrypt_modes[$this->mode], '');
1796
- $this->enmcrypt = @mcrypt_module_open($this->cipher_name_mcrypt, '', $mcrypt_modes[$this->mode], '');
1797
-
1798
- // we need the $ecb mcrypt resource (only) in MODE_CFB with enableContinuousBuffer()
1799
- // to workaround mcrypt's broken ncfb implementation in buffered mode
1800
- // see: {@link http://phpseclib.sourceforge.net/cfb-demo.phps}
1801
- if ($this->mode == self::MODE_CFB) {
1802
- $this->ecb = @mcrypt_module_open($this->cipher_name_mcrypt, '', MCRYPT_MODE_ECB, '');
1803
- }
1804
- } // else should mcrypt_generic_deinit be called?
1805
-
1806
- if ($this->mode == self::MODE_CFB) {
1807
- @mcrypt_generic_init($this->ecb, $this->key, str_repeat("\0", $this->block_size));
1808
- }
1809
- }
1810
-
1811
- /**
1812
- * Pads a string
1813
- *
1814
- * Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize.
1815
- * $this->block_size - (strlen($text) % $this->block_size) bytes are added, each of which is equal to
1816
- * chr($this->block_size - (strlen($text) % $this->block_size)
1817
- *
1818
- * If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless
1819
- * and padding will, hence forth, be enabled.
1820
- *
1821
- * @see self::_unpad()
1822
- * @param string $text
1823
- * @access private
1824
- * @return string
1825
- */
1826
- function _pad($text)
1827
- {
1828
- $length = strlen($text);
1829
-
1830
- if (!$this->padding) {
1831
- if ($length % $this->block_size == 0) {
1832
- return $text;
1833
- } else {
1834
- user_error("The plaintext's length ($length) is not a multiple of the block size ({$this->block_size})");
1835
- $this->padding = true;
1836
- }
1837
- }
1838
-
1839
- $pad = $this->block_size - ($length % $this->block_size);
1840
-
1841
- return str_pad($text, $length + $pad, chr($pad));
1842
- }
1843
-
1844
- /**
1845
- * Unpads a string.
1846
- *
1847
- * If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong
1848
- * and false will be returned.
1849
- *
1850
- * @see self::_pad()
1851
- * @param string $text
1852
- * @access private
1853
- * @return string
1854
- */
1855
- function _unpad($text)
1856
- {
1857
- if (!$this->padding) {
1858
- return $text;
1859
- }
1860
-
1861
- $length = ord($text[strlen($text) - 1]);
1862
-
1863
- if (!$length || $length > $this->block_size) {
1864
- return false;
1865
- }
1866
-
1867
- return substr($text, 0, -$length);
1868
- }
1869
-
1870
- /**
1871
- * Clears internal buffers
1872
- *
1873
- * Clearing/resetting the internal buffers is done everytime
1874
- * after disableContinuousBuffer() or on cipher $engine (re)init
1875
- * ie after setKey() or setIV()
1876
- *
1877
- * @access public
1878
- * @internal Could, but not must, extend by the child Crypt_* class
1879
- */
1880
- function _clearBuffers()
1881
- {
1882
- $this->enbuffer = $this->debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true);
1883
-
1884
- // mcrypt's handling of invalid's $iv:
1885
- // $this->encryptIV = $this->decryptIV = strlen($this->iv) == $this->block_size ? $this->iv : str_repeat("\0", $this->block_size);
1886
- $this->encryptIV = $this->decryptIV = str_pad(substr($this->iv, 0, $this->block_size), $this->block_size, "\0");
1887
-
1888
- if (!$this->skip_key_adjustment) {
1889
- $this->key = str_pad(substr($this->key, 0, $this->key_length), $this->key_length, "\0");
1890
- }
1891
- }
1892
-
1893
- /**
1894
- * String Shift
1895
- *
1896
- * Inspired by array_shift
1897
- *
1898
- * @param string $string
1899
- * @param int $index
1900
- * @access private
1901
- * @return string
1902
- */
1903
- function _string_shift(&$string, $index = 1)
1904
- {
1905
- $substr = substr($string, 0, $index);
1906
- $string = substr($string, $index);
1907
- return $substr;
1908
- }
1909
-
1910
- /**
1911
- * String Pop
1912
- *
1913
- * Inspired by array_pop
1914
- *
1915
- * @param string $string
1916
- * @param int $index
1917
- * @access private
1918
- * @return string
1919
- */
1920
- function _string_pop(&$string, $index = 1)
1921
- {
1922
- $substr = substr($string, -$index);
1923
- $string = substr($string, 0, -$index);
1924
- return $substr;
1925
- }
1926
-
1927
- /**
1928
- * Increment the current string
1929
- *
1930
- * @see self::decrypt()
1931
- * @see self::encrypt()
1932
- * @param string $var
1933
- * @access private
1934
- */
1935
- function _increment_str(&$var)
1936
- {
1937
- for ($i = 4; $i <= strlen($var); $i+= 4) {
1938
- $temp = substr($var, -$i, 4);
1939
- switch ($temp) {
1940
- case "\xFF\xFF\xFF\xFF":
1941
- $var = substr_replace($var, "\x00\x00\x00\x00", -$i, 4);
1942
- break;
1943
- case "\x7F\xFF\xFF\xFF":
1944
- $var = substr_replace($var, "\x80\x00\x00\x00", -$i, 4);
1945
- return;
1946
- default:
1947
- $temp = unpack('Nnum', $temp);
1948
- $var = substr_replace($var, pack('N', $temp['num'] + 1), -$i, 4);
1949
- return;
1950
- }
1951
- }
1952
-
1953
- $remainder = strlen($var) % 4;
1954
-
1955
- if ($remainder == 0) {
1956
- return;
1957
- }
1958
-
1959
- $temp = unpack('Nnum', str_pad(substr($var, 0, $remainder), 4, "\0", STR_PAD_LEFT));
1960
- $temp = substr(pack('N', $temp['num'] + 1), -$remainder);
1961
- $var = substr_replace($var, $temp, 0, $remainder);
1962
- }
1963
-
1964
- /**
1965
- * Setup the performance-optimized function for de/encrypt()
1966
- *
1967
- * Stores the created (or existing) callback function-name
1968
- * in $this->inline_crypt
1969
- *
1970
- * Internally for phpseclib developers:
1971
- *
1972
- * _setupInlineCrypt() would be called only if:
1973
- *
1974
- * - $engine == self::ENGINE_INTERNAL and
1975
- *
1976
- * - $use_inline_crypt === true
1977
- *
1978
- * - each time on _setup(), after(!) _setupKey()
1979
- *
1980
- *
1981
- * This ensures that _setupInlineCrypt() has always a
1982
- * full ready2go initializated internal cipher $engine state
1983
- * where, for example, the keys allready expanded,
1984
- * keys/block_size calculated and such.
1985
- *
1986
- * It is, each time if called, the responsibility of _setupInlineCrypt():
1987
- *
1988
- * - to set $this->inline_crypt to a valid and fully working callback function
1989
- * as a (faster) replacement for encrypt() / decrypt()
1990
- *
1991
- * - NOT to create unlimited callback functions (for memory reasons!)
1992
- * no matter how often _setupInlineCrypt() would be called. At some
1993
- * point of amount they must be generic re-useable.
1994
- *
1995
- * - the code of _setupInlineCrypt() it self,
1996
- * and the generated callback code,
1997
- * must be, in following order:
1998
- * - 100% safe
1999
- * - 100% compatible to encrypt()/decrypt()
2000
- * - using only php5+ features/lang-constructs/php-extensions if
2001
- * compatibility (down to php4) or fallback is provided
2002
- * - readable/maintainable/understandable/commented and... not-cryptic-styled-code :-)
2003
- * - >= 10% faster than encrypt()/decrypt() [which is, by the way,
2004
- * the reason for the existence of _setupInlineCrypt() :-)]
2005
- * - memory-nice
2006
- * - short (as good as possible)
2007
- *
2008
- * Note: - _setupInlineCrypt() is using _createInlineCryptFunction() to create the full callback function code.
2009
- * - In case of using inline crypting, _setupInlineCrypt() must extend by the child \phpseclib\Crypt\* class.
2010
- * - The following variable names are reserved:
2011
- * - $_* (all variable names prefixed with an underscore)
2012
- * - $self (object reference to it self. Do not use $this, but $self instead)
2013
- * - $in (the content of $in has to en/decrypt by the generated code)
2014
- * - The callback function should not use the 'return' statement, but en/decrypt'ing the content of $in only
2015
- *
2016
- *
2017
- * @see self::_setup()
2018
- * @see self::_createInlineCryptFunction()
2019
- * @see self::encrypt()
2020
- * @see self::decrypt()
2021
- * @access private
2022
- * @internal If a Crypt_* class providing inline crypting it must extend _setupInlineCrypt()
2023
- */
2024
- function _setupInlineCrypt()
2025
- {
2026
- // If, for any reason, an extending \phpseclib\Crypt\Base() \phpseclib\Crypt\* class
2027
- // not using inline crypting then it must be ensured that: $this->use_inline_crypt = false
2028
- // ie in the class var declaration of $use_inline_crypt in general for the \phpseclib\Crypt\* class,
2029
- // in the constructor at object instance-time
2030
- // or, if it's runtime-specific, at runtime
2031
-
2032
- $this->use_inline_crypt = false;
2033
- }
2034
-
2035
- /**
2036
- * Creates the performance-optimized function for en/decrypt()
2037
- *
2038
- * Internally for phpseclib developers:
2039
- *
2040
- * _createInlineCryptFunction():
2041
- *
2042
- * - merge the $cipher_code [setup'ed by _setupInlineCrypt()]
2043
- * with the current [$this->]mode of operation code
2044
- *
2045
- * - create the $inline function, which called by encrypt() / decrypt()
2046
- * as its replacement to speed up the en/decryption operations.
2047
- *
2048
- * - return the name of the created $inline callback function
2049
- *
2050
- * - used to speed up en/decryption
2051
- *
2052
- *
2053
- *
2054
- * The main reason why can speed up things [up to 50%] this way are:
2055
- *
2056
- * - using variables more effective then regular.
2057
- * (ie no use of expensive arrays but integers $k_0, $k_1 ...
2058
- * or even, for example, the pure $key[] values hardcoded)
2059
- *
2060
- * - avoiding 1000's of function calls of ie _encryptBlock()
2061
- * but inlining the crypt operations.
2062
- * in the mode of operation for() loop.
2063
- *
2064
- * - full loop unroll the (sometimes key-dependent) rounds
2065
- * avoiding this way ++$i counters and runtime-if's etc...
2066
- *
2067
- * The basic code architectur of the generated $inline en/decrypt()
2068
- * lambda function, in pseudo php, is:
2069
- *
2070
- * <code>
2071
- * +----------------------------------------------------------------------------------------------+
2072
- * | callback $inline = create_function: |
2073
- * | lambda_function_0001_crypt_ECB($action, $text) |
2074
- * | { |
2075
- * | INSERT PHP CODE OF: |
2076
- * | $cipher_code['init_crypt']; // general init code. |
2077
- * | // ie: $sbox'es declarations used for |
2078
- * | // encrypt and decrypt'ing. |
2079
- * | |
2080
- * | switch ($action) { |
2081
- * | case 'encrypt': |
2082
- * | INSERT PHP CODE OF: |
2083
- * | $cipher_code['init_encrypt']; // encrypt sepcific init code. |
2084
- * | ie: specified $key or $box |
2085
- * | declarations for encrypt'ing. |
2086
- * | |
2087
- * | foreach ($ciphertext) { |
2088
- * | $in = $block_size of $ciphertext; |
2089
- * | |
2090
- * | INSERT PHP CODE OF: |
2091
- * | $cipher_code['encrypt_block']; // encrypt's (string) $in, which is always: |
2092
- * | // strlen($in) == $this->block_size |
2093
- * | // here comes the cipher algorithm in action |
2094
- * | // for encryption. |
2095
- * | // $cipher_code['encrypt_block'] has to |
2096
- * | // encrypt the content of the $in variable |
2097
- * | |
2098
- * | $plaintext .= $in; |
2099
- * | } |
2100
- * | return $plaintext; |
2101
- * | |
2102
- * | case 'decrypt': |
2103
- * | INSERT PHP CODE OF: |
2104
- * | $cipher_code['init_decrypt']; // decrypt sepcific init code |
2105
- * | ie: specified $key or $box |
2106
- * | declarations for decrypt'ing. |
2107
- * | foreach ($plaintext) { |
2108
- * | $in = $block_size of $plaintext; |
2109
- * | |
2110
- * | INSERT PHP CODE OF: |
2111
- * | $cipher_code['decrypt_block']; // decrypt's (string) $in, which is always |
2112
- * | // strlen($in) == $this->block_size |
2113
- * | // here comes the cipher algorithm in action |
2114
- * | // for decryption. |
2115
- * | // $cipher_code['decrypt_block'] has to |
2116
- * | // decrypt the content of the $in variable |
2117
- * | $ciphertext .= $in; |
2118
- * | } |
2119
- * | return $ciphertext; |
2120
- * | } |
2121
- * | } |
2122
- * +----------------------------------------------------------------------------------------------+
2123
- * </code>
2124
- *
2125
- * See also the \phpseclib\Crypt\*::_setupInlineCrypt()'s for
2126
- * productive inline $cipher_code's how they works.
2127
- *
2128
- * Structure of:
2129
- * <code>
2130
- * $cipher_code = array(
2131
- * 'init_crypt' => (string) '', // optional
2132
- * 'init_encrypt' => (string) '', // optional
2133
- * 'init_decrypt' => (string) '', // optional
2134
- * 'encrypt_block' => (string) '', // required
2135
- * 'decrypt_block' => (string) '' // required
2136
- * );
2137
- * </code>
2138
- *
2139
- * @see self::_setupInlineCrypt()
2140
- * @see self::encrypt()
2141
- * @see self::decrypt()
2142
- * @param array $cipher_code
2143
- * @access private
2144
- * @return string (the name of the created callback function)
2145
- */
2146
- function _createInlineCryptFunction($cipher_code)
2147
- {
2148
- $block_size = $this->block_size;
2149
-
2150
- // optional
2151
- $init_crypt = isset($cipher_code['init_crypt']) ? $cipher_code['init_crypt'] : '';
2152
- $init_encrypt = isset($cipher_code['init_encrypt']) ? $cipher_code['init_encrypt'] : '';
2153
- $init_decrypt = isset($cipher_code['init_decrypt']) ? $cipher_code['init_decrypt'] : '';
2154
- // required
2155
- $encrypt_block = $cipher_code['encrypt_block'];
2156
- $decrypt_block = $cipher_code['decrypt_block'];
2157
-
2158
- // Generating mode of operation inline code,
2159
- // merged with the $cipher_code algorithm
2160
- // for encrypt- and decryption.
2161
- switch ($this->mode) {
2162
- case self::MODE_ECB:
2163
- $encrypt = $init_encrypt . '
2164
- $_ciphertext = "";
2165
- $_plaintext_len = strlen($_text);
2166
-
2167
- for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
2168
- $in = substr($_text, $_i, '.$block_size.');
2169
- '.$encrypt_block.'
2170
- $_ciphertext.= $in;
2171
- }
2172
-
2173
- return $_ciphertext;
2174
- ';
2175
-
2176
- $decrypt = $init_decrypt . '
2177
- $_plaintext = "";
2178
- $_text = str_pad($_text, strlen($_text) + ('.$block_size.' - strlen($_text) % '.$block_size.') % '.$block_size.', chr(0));
2179
- $_ciphertext_len = strlen($_text);
2180
-
2181
- for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
2182
- $in = substr($_text, $_i, '.$block_size.');
2183
- '.$decrypt_block.'
2184
- $_plaintext.= $in;
2185
- }
2186
-
2187
- return $self->_unpad($_plaintext);
2188
- ';
2189
- break;
2190
- case self::MODE_CTR:
2191
- $encrypt = $init_encrypt . '
2192
- $_ciphertext = "";
2193
- $_plaintext_len = strlen($_text);
2194
- $_xor = $self->encryptIV;
2195
- $_buffer = &$self->enbuffer;
2196
- if (strlen($_buffer["ciphertext"])) {
2197
- for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
2198
- $_block = substr($_text, $_i, '.$block_size.');
2199
- if (strlen($_block) > strlen($_buffer["ciphertext"])) {
2200
- $in = $_xor;
2201
- '.$encrypt_block.'
2202
- $self->_increment_str($_xor);
2203
- $_buffer["ciphertext"].= $in;
2204
- }
2205
- $_key = $self->_string_shift($_buffer["ciphertext"], '.$block_size.');
2206
- $_ciphertext.= $_block ^ $_key;
2207
- }
2208
- } else {
2209
- for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
2210
- $_block = substr($_text, $_i, '.$block_size.');
2211
- $in = $_xor;
2212
- '.$encrypt_block.'
2213
- $self->_increment_str($_xor);
2214
- $_key = $in;
2215
- $_ciphertext.= $_block ^ $_key;
2216
- }
2217
- }
2218
- if ($self->continuousBuffer) {
2219
- $self->encryptIV = $_xor;
2220
- if ($_start = $_plaintext_len % '.$block_size.') {
2221
- $_buffer["ciphertext"] = substr($_key, $_start) . $_buffer["ciphertext"];
2222
- }
2223
- }
2224
-
2225
- return $_ciphertext;
2226
- ';
2227
-
2228
- $decrypt = $init_encrypt . '
2229
- $_plaintext = "";
2230
- $_ciphertext_len = strlen($_text);
2231
- $_xor = $self->decryptIV;
2232
- $_buffer = &$self->debuffer;
2233
-
2234
- if (strlen($_buffer["ciphertext"])) {
2235
- for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
2236
- $_block = substr($_text, $_i, '.$block_size.');
2237
- if (strlen($_block) > strlen($_buffer["ciphertext"])) {
2238
- $in = $_xor;
2239
- '.$encrypt_block.'
2240
- $self->_increment_str($_xor);
2241
- $_buffer["ciphertext"].= $in;
2242
- }
2243
- $_key = $self->_string_shift($_buffer["ciphertext"], '.$block_size.');
2244
- $_plaintext.= $_block ^ $_key;
2245
- }
2246
- } else {
2247
- for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
2248
- $_block = substr($_text, $_i, '.$block_size.');
2249
- $in = $_xor;
2250
- '.$encrypt_block.'
2251
- $self->_increment_str($_xor);
2252
- $_key = $in;
2253
- $_plaintext.= $_block ^ $_key;
2254
- }
2255
- }
2256
- if ($self->continuousBuffer) {
2257
- $self->decryptIV = $_xor;
2258
- if ($_start = $_ciphertext_len % '.$block_size.') {
2259
- $_buffer["ciphertext"] = substr($_key, $_start) . $_buffer["ciphertext"];
2260
- }
2261
- }
2262
-
2263
- return $_plaintext;
2264
- ';
2265
- break;
2266
- case self::MODE_CFB:
2267
- $encrypt = $init_encrypt . '
2268
- $_ciphertext = "";
2269
- $_buffer = &$self->enbuffer;
2270
-
2271
- if ($self->continuousBuffer) {
2272
- $_iv = &$self->encryptIV;
2273
- $_pos = &$_buffer["pos"];
2274
- } else {
2275
- $_iv = $self->encryptIV;
2276
- $_pos = 0;
2277
- }
2278
- $_len = strlen($_text);
2279
- $_i = 0;
2280
- if ($_pos) {
2281
- $_orig_pos = $_pos;
2282
- $_max = '.$block_size.' - $_pos;
2283
- if ($_len >= $_max) {
2284
- $_i = $_max;
2285
- $_len-= $_max;
2286
- $_pos = 0;
2287
- } else {
2288
- $_i = $_len;
2289
- $_pos+= $_len;
2290
- $_len = 0;
2291
- }
2292
- $_ciphertext = substr($_iv, $_orig_pos) ^ $_text;
2293
- $_iv = substr_replace($_iv, $_ciphertext, $_orig_pos, $_i);
2294
- }
2295
- while ($_len >= '.$block_size.') {
2296
- $in = $_iv;
2297
- '.$encrypt_block.';
2298
- $_iv = $in ^ substr($_text, $_i, '.$block_size.');
2299
- $_ciphertext.= $_iv;
2300
- $_len-= '.$block_size.';
2301
- $_i+= '.$block_size.';
2302
- }
2303
- if ($_len) {
2304
- $in = $_iv;
2305
- '.$encrypt_block.'
2306
- $_iv = $in;
2307
- $_block = $_iv ^ substr($_text, $_i);
2308
- $_iv = substr_replace($_iv, $_block, 0, $_len);
2309
- $_ciphertext.= $_block;
2310
- $_pos = $_len;
2311
- }
2312
- return $_ciphertext;
2313
- ';
2314
-
2315
- $decrypt = $init_encrypt . '
2316
- $_plaintext = "";
2317
- $_buffer = &$self->debuffer;
2318
-
2319
- if ($self->continuousBuffer) {
2320
- $_iv = &$self->decryptIV;
2321
- $_pos = &$_buffer["pos"];
2322
- } else {
2323
- $_iv = $self->decryptIV;
2324
- $_pos = 0;
2325
- }
2326
- $_len = strlen($_text);
2327
- $_i = 0;
2328
- if ($_pos) {
2329
- $_orig_pos = $_pos;
2330
- $_max = '.$block_size.' - $_pos;
2331
- if ($_len >= $_max) {
2332
- $_i = $_max;
2333
- $_len-= $_max;
2334
- $_pos = 0;
2335
- } else {
2336
- $_i = $_len;
2337
- $_pos+= $_len;
2338
- $_len = 0;
2339
- }
2340
- $_plaintext = substr($_iv, $_orig_pos) ^ $_text;
2341
- $_iv = substr_replace($_iv, substr($_text, 0, $_i), $_orig_pos, $_i);
2342
- }
2343
- while ($_len >= '.$block_size.') {
2344
- $in = $_iv;
2345
- '.$encrypt_block.'
2346
- $_iv = $in;
2347
- $cb = substr($_text, $_i, '.$block_size.');
2348
- $_plaintext.= $_iv ^ $cb;
2349
- $_iv = $cb;
2350
- $_len-= '.$block_size.';
2351
- $_i+= '.$block_size.';
2352
- }
2353
- if ($_len) {
2354
- $in = $_iv;
2355
- '.$encrypt_block.'
2356
- $_iv = $in;
2357
- $_plaintext.= $_iv ^ substr($_text, $_i);
2358
- $_iv = substr_replace($_iv, substr($_text, $_i), 0, $_len);
2359
- $_pos = $_len;
2360
- }
2361
-
2362
- return $_plaintext;
2363
- ';
2364
- break;
2365
- case self::MODE_OFB:
2366
- $encrypt = $init_encrypt . '
2367
- $_ciphertext = "";
2368
- $_plaintext_len = strlen($_text);
2369
- $_xor = $self->encryptIV;
2370
- $_buffer = &$self->enbuffer;
2371
-
2372
- if (strlen($_buffer["xor"])) {
2373
- for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
2374
- $_block = substr($_text, $_i, '.$block_size.');
2375
- if (strlen($_block) > strlen($_buffer["xor"])) {
2376
- $in = $_xor;
2377
- '.$encrypt_block.'
2378
- $_xor = $in;
2379
- $_buffer["xor"].= $_xor;
2380
- }
2381
- $_key = $self->_string_shift($_buffer["xor"], '.$block_size.');
2382
- $_ciphertext.= $_block ^ $_key;
2383
- }
2384
- } else {
2385
- for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
2386
- $in = $_xor;
2387
- '.$encrypt_block.'
2388
- $_xor = $in;
2389
- $_ciphertext.= substr($_text, $_i, '.$block_size.') ^ $_xor;
2390
- }
2391
- $_key = $_xor;
2392
- }
2393
- if ($self->continuousBuffer) {
2394
- $self->encryptIV = $_xor;
2395
- if ($_start = $_plaintext_len % '.$block_size.') {
2396
- $_buffer["xor"] = substr($_key, $_start) . $_buffer["xor"];
2397
- }
2398
- }
2399
- return $_ciphertext;
2400
- ';
2401
-
2402
- $decrypt = $init_encrypt . '
2403
- $_plaintext = "";
2404
- $_ciphertext_len = strlen($_text);
2405
- $_xor = $self->decryptIV;
2406
- $_buffer = &$self->debuffer;
2407
-
2408
- if (strlen($_buffer["xor"])) {
2409
- for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
2410
- $_block = substr($_text, $_i, '.$block_size.');
2411
- if (strlen($_block) > strlen($_buffer["xor"])) {
2412
- $in = $_xor;
2413
- '.$encrypt_block.'
2414
- $_xor = $in;
2415
- $_buffer["xor"].= $_xor;
2416
- }
2417
- $_key = $self->_string_shift($_buffer["xor"], '.$block_size.');
2418
- $_plaintext.= $_block ^ $_key;
2419
- }
2420
- } else {
2421
- for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
2422
- $in = $_xor;
2423
- '.$encrypt_block.'
2424
- $_xor = $in;
2425
- $_plaintext.= substr($_text, $_i, '.$block_size.') ^ $_xor;
2426
- }
2427
- $_key = $_xor;
2428
- }
2429
- if ($self->continuousBuffer) {
2430
- $self->decryptIV = $_xor;
2431
- if ($_start = $_ciphertext_len % '.$block_size.') {
2432
- $_buffer["xor"] = substr($_key, $_start) . $_buffer["xor"];
2433
- }
2434
- }
2435
- return $_plaintext;
2436
- ';
2437
- break;
2438
- case self::MODE_STREAM:
2439
- $encrypt = $init_encrypt . '
2440
- $_ciphertext = "";
2441
- '.$encrypt_block.'
2442
- return $_ciphertext;
2443
- ';
2444
- $decrypt = $init_decrypt . '
2445
- $_plaintext = "";
2446
- '.$decrypt_block.'
2447
- return $_plaintext;
2448
- ';
2449
- break;
2450
- // case self::MODE_CBC:
2451
- default:
2452
- $encrypt = $init_encrypt . '
2453
- $_ciphertext = "";
2454
- $_plaintext_len = strlen($_text);
2455
-
2456
- $in = $self->encryptIV;
2457
-
2458
- for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
2459
- $in = substr($_text, $_i, '.$block_size.') ^ $in;
2460
- '.$encrypt_block.'
2461
- $_ciphertext.= $in;
2462
- }
2463
-
2464
- if ($self->continuousBuffer) {
2465
- $self->encryptIV = $in;
2466
- }
2467
-
2468
- return $_ciphertext;
2469
- ';
2470
-
2471
- $decrypt = $init_decrypt . '
2472
- $_plaintext = "";
2473
- $_text = str_pad($_text, strlen($_text) + ('.$block_size.' - strlen($_text) % '.$block_size.') % '.$block_size.', chr(0));
2474
- $_ciphertext_len = strlen($_text);
2475
-
2476
- $_iv = $self->decryptIV;
2477
-
2478
- for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
2479
- $in = $_block = substr($_text, $_i, '.$block_size.');
2480
- '.$decrypt_block.'
2481
- $_plaintext.= $in ^ $_iv;
2482
- $_iv = $_block;
2483
- }
2484
-
2485
- if ($self->continuousBuffer) {
2486
- $self->decryptIV = $_iv;
2487
- }
2488
-
2489
- return $self->_unpad($_plaintext);
2490
- ';
2491
- break;
2492
- }
2493
-
2494
- // Create the $inline function and return its name as string. Ready to run!
2495
- if (version_compare(PHP_VERSION, '5.3.0') >= 0) {
2496
- eval('$func = function ($_action, &$self, $_text) { ' . $init_crypt . 'if ($_action == "encrypt") { ' . $encrypt . ' } else { ' . $decrypt . ' } };');
2497
- return $func;
2498
- }
2499
-
2500
- return create_function('$_action, &$self, $_text', $init_crypt . 'if ($_action == "encrypt") { ' . $encrypt . ' } else { ' . $decrypt . ' }');
2501
- }
2502
-
2503
- /**
2504
- * Holds the lambda_functions table (classwide)
2505
- *
2506
- * Each name of the lambda function, created from
2507
- * _setupInlineCrypt() && _createInlineCryptFunction()
2508
- * is stored, classwide (!), here for reusing.
2509
- *
2510
- * The string-based index of $function is a classwide
2511
- * unique value representing, at least, the $mode of
2512
- * operation (or more... depends of the optimizing level)
2513
- * for which $mode the lambda function was created.
2514
- *
2515
- * @access private
2516
- * @return array &$functions
2517
- */
2518
- function &_getLambdaFunctions()
2519
- {
2520
- static $functions = array();
2521
- return $functions;
2522
- }
2523
-
2524
- /**
2525
- * Generates a digest from $bytes
2526
- *
2527
- * @see self::_setupInlineCrypt()
2528
- * @access private
2529
- * @param $bytes
2530
- * @return string
2531
- */
2532
- function _hashInlineCryptFunction($bytes)
2533
- {
2534
- if (!isset(self::$WHIRLPOOL_AVAILABLE)) {
2535
- self::$WHIRLPOOL_AVAILABLE = extension_loaded('hash') && in_array('whirlpool', hash_algos());
2536
- }
2537
-
2538
- $result = '';
2539
- $hash = $bytes;
2540
-
2541
- switch (true) {
2542
- case self::$WHIRLPOOL_AVAILABLE:
2543
- foreach (str_split($bytes, 64) as $t) {
2544
- $hash = hash('whirlpool', $hash, true);
2545
- $result .= $t ^ $hash;
2546
- }
2547
- return $result . hash('whirlpool', $hash, true);
2548
- default:
2549
- $len = strlen($bytes);
2550
- for ($i = 0; $i < $len; $i+=20) {
2551
- $t = substr($bytes, $i, 20);
2552
- $hash = pack('H*', sha1($hash));
2553
- $result .= $t ^ $hash;
2554
- }
2555
- return $result . pack('H*', sha1($hash));
2556
- }
2557
- }
2558
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/phpseclib/phpseclib/phpseclib/Crypt/Blowfish.php DELETED
@@ -1,577 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Pure-PHP implementation of Blowfish.
5
- *
6
- * Uses mcrypt, if available, and an internal implementation, otherwise.
7
- *
8
- * PHP version 5
9
- *
10
- * Useful resources are as follows:
11
- *
12
- * - {@link http://en.wikipedia.org/wiki/Blowfish_(cipher) Wikipedia description of Blowfish}
13
- *
14
- * Here's a short example of how to use this library:
15
- * <code>
16
- * <?php
17
- * include 'vendor/autoload.php';
18
- *
19
- * $blowfish = new \phpseclib\Crypt\Blowfish();
20
- *
21
- * $blowfish->setKey('12345678901234567890123456789012');
22
- *
23
- * $plaintext = str_repeat('a', 1024);
24
- *
25
- * echo $blowfish->decrypt($blowfish->encrypt($plaintext));
26
- * ?>
27
- * </code>
28
- *
29
- * @category Crypt
30
- * @package Blowfish
31
- * @author Jim Wigginton <terrafrost@php.net>
32
- * @author Hans-Juergen Petrich <petrich@tronic-media.com>
33
- * @copyright 2007 Jim Wigginton
34
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
35
- * @link http://phpseclib.sourceforge.net
36
- */
37
-
38
- namespace phpseclib\Crypt;
39
-
40
- /**
41
- * Pure-PHP implementation of Blowfish.
42
- *
43
- * @package Blowfish
44
- * @author Jim Wigginton <terrafrost@php.net>
45
- * @author Hans-Juergen Petrich <petrich@tronic-media.com>
46
- * @access public
47
- */
48
- class Blowfish extends Base
49
- {
50
- /**
51
- * Block Length of the cipher
52
- *
53
- * @see \phpseclib\Crypt\Base::block_size
54
- * @var int
55
- * @access private
56
- */
57
- var $block_size = 8;
58
-
59
- /**
60
- * The mcrypt specific name of the cipher
61
- *
62
- * @see \phpseclib\Crypt\Base::cipher_name_mcrypt
63
- * @var string
64
- * @access private
65
- */
66
- var $cipher_name_mcrypt = 'blowfish';
67
-
68
- /**
69
- * Optimizing value while CFB-encrypting
70
- *
71
- * @see \phpseclib\Crypt\Base::cfb_init_len
72
- * @var int
73
- * @access private
74
- */
75
- var $cfb_init_len = 500;
76
-
77
- /**
78
- * The fixed subkeys boxes ($sbox0 - $sbox3) with 256 entries each
79
- *
80
- * S-Box 0
81
- *
82
- * @access private
83
- * @var array
84
- */
85
- var $sbox0 = array(
86
- 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
87
- 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
88
- 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
89
- 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
90
- 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
91
- 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
92
- 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
93
- 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
94
- 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
95
- 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
96
- 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
97
- 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
98
- 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
99
- 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
100
- 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
101
- 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
102
- 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
103
- 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
104
- 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
105
- 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
106
- 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
107
- 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
108
- 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
109
- 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
110
- 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
111
- 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
112
- 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
113
- 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
114
- 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
115
- 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
116
- 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
117
- 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a
118
- );
119
-
120
- /**
121
- * S-Box 1
122
- *
123
- * @access private
124
- * @var array
125
- */
126
- var $sbox1 = array(
127
- 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
128
- 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
129
- 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
130
- 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
131
- 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
132
- 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
133
- 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
134
- 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
135
- 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
136
- 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
137
- 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
138
- 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
139
- 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
140
- 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
141
- 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
142
- 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
143
- 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
144
- 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
145
- 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
146
- 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
147
- 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
148
- 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
149
- 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
150
- 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
151
- 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
152
- 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
153
- 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
154
- 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
155
- 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
156
- 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
157
- 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
158
- 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7
159
- );
160
-
161
- /**
162
- * S-Box 2
163
- *
164
- * @access private
165
- * @var array
166
- */
167
- var $sbox2 = array(
168
- 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
169
- 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
170
- 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
171
- 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
172
- 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
173
- 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
174
- 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
175
- 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
176
- 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
177
- 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
178
- 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
179
- 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
180
- 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
181
- 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
182
- 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
183
- 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
184
- 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
185
- 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
186
- 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
187
- 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
188
- 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
189
- 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
190
- 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
191
- 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
192
- 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
193
- 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
194
- 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
195
- 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
196
- 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
197
- 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
198
- 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
199
- 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0
200
- );
201
-
202
- /**
203
- * S-Box 3
204
- *
205
- * @access private
206
- * @var array
207
- */
208
- var $sbox3 = array(
209
- 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
210
- 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
211
- 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
212
- 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
213
- 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
214
- 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
215
- 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
216
- 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
217
- 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
218
- 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
219
- 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
220
- 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
221
- 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
222
- 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
223
- 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
224
- 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
225
- 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
226
- 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
227
- 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
228
- 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
229
- 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
230
- 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
231
- 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
232
- 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
233
- 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
234
- 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
235
- 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
236
- 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
237
- 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
238
- 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
239
- 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
240
- 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
241
- );
242
-
243
- /**
244
- * P-Array consists of 18 32-bit subkeys
245
- *
246
- * @var array
247
- * @access private
248
- */
249
- var $parray = array(
250
- 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0,
251
- 0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
252
- 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b
253
- );
254
-
255
- /**
256
- * The BCTX-working Array
257
- *
258
- * Holds the expanded key [p] and the key-depended s-boxes [sb]
259
- *
260
- * @var array
261
- * @access private
262
- */
263
- var $bctx;
264
-
265
- /**
266
- * Holds the last used key
267
- *
268
- * @var array
269
- * @access private
270
- */
271
- var $kl;
272
-
273
- /**
274
- * The Key Length (in bytes)
275
- *
276
- * @see \phpseclib\Crypt\Base::setKeyLength()
277
- * @var int
278
- * @access private
279
- * @internal The max value is 256 / 8 = 32, the min value is 128 / 8 = 16. Exists in conjunction with $Nk
280
- * because the encryption / decryption / key schedule creation requires this number and not $key_length. We could
281
- * derive this from $key_length or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
282
- * of that, we'll just precompute it once.
283
- */
284
- var $key_length = 16;
285
-
286
- /**
287
- * Sets the key length.
288
- *
289
- * Key lengths can be between 32 and 448 bits.
290
- *
291
- * @access public
292
- * @param int $length
293
- */
294
- function setKeyLength($length)
295
- {
296
- if ($length < 32) {
297
- $this->key_length = 7;
298
- } elseif ($length > 448) {
299
- $this->key_length = 56;
300
- } else {
301
- $this->key_length = $length >> 3;
302
- }
303
-
304
- parent::setKeyLength($length);
305
- }
306
-
307
- /**
308
- * Test for engine validity
309
- *
310
- * This is mainly just a wrapper to set things up for \phpseclib\Crypt\Base::isValidEngine()
311
- *
312
- * @see \phpseclib\Crypt\Base::isValidEngine()
313
- * @param int $engine
314
- * @access public
315
- * @return bool
316
- */
317
- function isValidEngine($engine)
318
- {
319
- if ($engine == self::ENGINE_OPENSSL) {
320
- if (version_compare(PHP_VERSION, '5.3.7') < 0 && $this->key_length != 16) {
321
- return false;
322
- }
323
- if ($this->key_length < 16) {
324
- return false;
325
- }
326
- $this->cipher_name_openssl_ecb = 'bf-ecb';
327
- $this->cipher_name_openssl = 'bf-' . $this->_openssl_translate_mode();
328
- }
329
-
330
- return parent::isValidEngine($engine);
331
- }
332
-
333
- /**
334
- * Setup the key (expansion)
335
- *
336
- * @see \phpseclib\Crypt\Base::_setupKey()
337
- * @access private
338
- */
339
- function _setupKey()
340
- {
341
- if (isset($this->kl['key']) && $this->key === $this->kl['key']) {
342
- // already expanded
343
- return;
344
- }
345
- $this->kl = array('key' => $this->key);
346
-
347
- /* key-expanding p[] and S-Box building sb[] */
348
- $this->bctx = array(
349
- 'p' => array(),
350
- 'sb' => array(
351
- $this->sbox0,
352
- $this->sbox1,
353
- $this->sbox2,
354
- $this->sbox3
355
- )
356
- );
357
-
358
- // unpack binary string in unsigned chars
359
- $key = array_values(unpack('C*', $this->key));
360
- $keyl = count($key);
361
- for ($j = 0, $i = 0; $i < 18; ++$i) {
362
- // xor P1 with the first 32-bits of the key, xor P2 with the second 32-bits ...
363
- for ($data = 0, $k = 0; $k < 4; ++$k) {
364
- $data = ($data << 8) | $key[$j];
365
- if (++$j >= $keyl) {
366
- $j = 0;
367
- }
368
- }
369
- $this->bctx['p'][] = $this->parray[$i] ^ $data;
370
- }
371
-
372
- // encrypt the zero-string, replace P1 and P2 with the encrypted data,
373
- // encrypt P3 and P4 with the new P1 and P2, do it with all P-array and subkeys
374
- $data = "\0\0\0\0\0\0\0\0";
375
- for ($i = 0; $i < 18; $i += 2) {
376
- list($l, $r) = array_values(unpack('N*', $data = $this->_encryptBlock($data)));
377
- $this->bctx['p'][$i ] = $l;
378
- $this->bctx['p'][$i + 1] = $r;
379
- }
380
- for ($i = 0; $i < 4; ++$i) {
381
- for ($j = 0; $j < 256; $j += 2) {
382
- list($l, $r) = array_values(unpack('N*', $data = $this->_encryptBlock($data)));
383
- $this->bctx['sb'][$i][$j ] = $l;
384
- $this->bctx['sb'][$i][$j + 1] = $r;
385
- }
386
- }
387
- }
388
-
389
- /**
390
- * Encrypts a block
391
- *
392
- * @access private
393
- * @param string $in
394
- * @return string
395
- */
396
- function _encryptBlock($in)
397
- {
398
- $p = $this->bctx["p"];
399
- // extract($this->bctx["sb"], EXTR_PREFIX_ALL, "sb"); // slower
400
- $sb_0 = $this->bctx["sb"][0];
401
- $sb_1 = $this->bctx["sb"][1];
402
- $sb_2 = $this->bctx["sb"][2];
403
- $sb_3 = $this->bctx["sb"][3];
404
-
405
- $in = unpack("N*", $in);
406
- $l = $in[1];
407
- $r = $in[2];
408
-
409
- for ($i = 0; $i < 16; $i+= 2) {
410
- $l^= $p[$i];
411
- $r^= ($sb_0[$l >> 24 & 0xff] +
412
- $sb_1[$l >> 16 & 0xff] ^
413
- $sb_2[$l >> 8 & 0xff]) +
414
- $sb_3[$l & 0xff];
415
-
416
- $r^= $p[$i + 1];
417
- $l^= ($sb_0[$r >> 24 & 0xff] +
418
- $sb_1[$r >> 16 & 0xff] ^
419
- $sb_2[$r >> 8 & 0xff]) +
420
- $sb_3[$r & 0xff];
421
- }
422
- return pack("N*", $r ^ $p[17], $l ^ $p[16]);
423
- }
424
-
425
- /**
426
- * Decrypts a block
427
- *
428
- * @access private
429
- * @param string $in
430
- * @return string
431
- */
432
- function _decryptBlock($in)
433
- {
434
- $p = $this->bctx["p"];
435
- $sb_0 = $this->bctx["sb"][0];
436
- $sb_1 = $this->bctx["sb"][1];
437
- $sb_2 = $this->bctx["sb"][2];
438
- $sb_3 = $this->bctx["sb"][3];
439
-
440
- $in = unpack("N*", $in);
441
- $l = $in[1];
442
- $r = $in[2];
443
-
444
- for ($i = 17; $i > 2; $i-= 2) {
445
- $l^= $p[$i];
446
- $r^= ($sb_0[$l >> 24 & 0xff] +
447
- $sb_1[$l >> 16 & 0xff] ^
448
- $sb_2[$l >> 8 & 0xff]) +
449
- $sb_3[$l & 0xff];
450
-
451
- $r^= $p[$i - 1];
452
- $l^= ($sb_0[$r >> 24 & 0xff] +
453
- $sb_1[$r >> 16 & 0xff] ^
454
- $sb_2[$r >> 8 & 0xff]) +
455
- $sb_3[$r & 0xff];
456
- }
457
- return pack("N*", $r ^ $p[0], $l ^ $p[1]);
458
- }
459
-
460
- /**
461
- * Setup the performance-optimized function for de/encrypt()
462
- *
463
- * @see \phpseclib\Crypt\Base::_setupInlineCrypt()
464
- * @access private
465
- */
466
- function _setupInlineCrypt()
467
- {
468
- $lambda_functions =& self::_getLambdaFunctions();
469
-
470
- // We create max. 10 hi-optimized code for memory reason. Means: For each $key one ultra fast inline-crypt function.
471
- // (Currently, for Blowfish, one generated $lambda_function cost on php5.5@32bit ~100kb unfreeable mem and ~180kb on php5.5@64bit)
472
- // After that, we'll still create very fast optimized code but not the hi-ultimative code, for each $mode one.
473
- $gen_hi_opt_code = (bool)(count($lambda_functions) < 10);
474
-
475
- // Generation of a unique hash for our generated code
476
- $code_hash = "Crypt_Blowfish, {$this->mode}";
477
- if ($gen_hi_opt_code) {
478
- $code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key);
479
- }
480
-
481
- if (!isset($lambda_functions[$code_hash])) {
482
- switch (true) {
483
- case $gen_hi_opt_code:
484
- $p = $this->bctx['p'];
485
- $init_crypt = '
486
- static $sb_0, $sb_1, $sb_2, $sb_3;
487
- if (!$sb_0) {
488
- $sb_0 = $self->bctx["sb"][0];
489
- $sb_1 = $self->bctx["sb"][1];
490
- $sb_2 = $self->bctx["sb"][2];
491
- $sb_3 = $self->bctx["sb"][3];
492
- }
493
- ';
494
- break;
495
- default:
496
- $p = array();
497
- for ($i = 0; $i < 18; ++$i) {
498
- $p[] = '$p_' . $i;
499
- }
500
- $init_crypt = '
501
- list($sb_0, $sb_1, $sb_2, $sb_3) = $self->bctx["sb"];
502
- list(' . implode(',', $p) . ') = $self->bctx["p"];
503
-
504
- ';
505
- }
506
-
507
- // Generating encrypt code:
508
- $encrypt_block = '
509
- $in = unpack("N*", $in);
510
- $l = $in[1];
511
- $r = $in[2];
512
- ';
513
- for ($i = 0; $i < 16; $i+= 2) {
514
- $encrypt_block.= '
515
- $l^= ' . $p[$i] . ';
516
- $r^= ($sb_0[$l >> 24 & 0xff] +
517
- $sb_1[$l >> 16 & 0xff] ^
518
- $sb_2[$l >> 8 & 0xff]) +
519
- $sb_3[$l & 0xff];
520
-
521
- $r^= ' . $p[$i + 1] . ';
522
- $l^= ($sb_0[$r >> 24 & 0xff] +
523
- $sb_1[$r >> 16 & 0xff] ^
524
- $sb_2[$r >> 8 & 0xff]) +
525
- $sb_3[$r & 0xff];
526
- ';
527
- }
528
- $encrypt_block.= '
529
- $in = pack("N*",
530
- $r ^ ' . $p[17] . ',
531
- $l ^ ' . $p[16] . '
532
- );
533
- ';
534
-
535
- // Generating decrypt code:
536
- $decrypt_block = '
537
- $in = unpack("N*", $in);
538
- $l = $in[1];
539
- $r = $in[2];
540
- ';
541
-
542
- for ($i = 17; $i > 2; $i-= 2) {
543
- $decrypt_block.= '
544
- $l^= ' . $p[$i] . ';
545
- $r^= ($sb_0[$l >> 24 & 0xff] +
546
- $sb_1[$l >> 16 & 0xff] ^
547
- $sb_2[$l >> 8 & 0xff]) +
548
- $sb_3[$l & 0xff];
549
-
550
- $r^= ' . $p[$i - 1] . ';
551
- $l^= ($sb_0[$r >> 24 & 0xff] +
552
- $sb_1[$r >> 16 & 0xff] ^
553
- $sb_2[$r >> 8 & 0xff]) +
554
- $sb_3[$r & 0xff];
555
- ';
556
- }
557
-
558
- $decrypt_block.= '
559
- $in = pack("N*",
560
- $r ^ ' . $p[0] . ',
561
- $l ^ ' . $p[1] . '
562
- );
563
- ';
564
-
565
- $lambda_functions[$code_hash] = $this->_createInlineCryptFunction(
566
- array(
567
- 'init_crypt' => $init_crypt,
568
- 'init_encrypt' => '',
569
- 'init_decrypt' => '',
570
- 'encrypt_block' => $encrypt_block,
571
- 'decrypt_block' => $decrypt_block
572
- )
573
- );
574
- }
575
- $this->inline_crypt = $lambda_functions[$code_hash];
576
- }
577
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/phpseclib/phpseclib/phpseclib/Crypt/DES.php DELETED
@@ -1,1443 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Pure-PHP implementation of DES.
5
- *
6
- * Uses mcrypt, if available, and an internal implementation, otherwise.
7
- *
8
- * PHP version 5
9
- *
10
- * Useful resources are as follows:
11
- *
12
- * - {@link http://en.wikipedia.org/wiki/DES_supplementary_material Wikipedia: DES supplementary material}
13
- * - {@link http://www.itl.nist.gov/fipspubs/fip46-2.htm FIPS 46-2 - (DES), Data Encryption Standard}
14
- * - {@link http://www.cs.eku.edu/faculty/styer/460/Encrypt/JS-DES.html JavaScript DES Example}
15
- *
16
- * Here's a short example of how to use this library:
17
- * <code>
18
- * <?php
19
- * include 'vendor/autoload.php';
20
- *
21
- * $des = new \phpseclib\Crypt\DES();
22
- *
23
- * $des->setKey('abcdefgh');
24
- *
25
- * $size = 10 * 1024;
26
- * $plaintext = '';
27
- * for ($i = 0; $i < $size; $i++) {
28
- * $plaintext.= 'a';
29
- * }
30
- *
31
- * echo $des->decrypt($des->encrypt($plaintext));
32
- * ?>
33
- * </code>
34
- *
35
- * @category Crypt
36
- * @package DES
37
- * @author Jim Wigginton <terrafrost@php.net>
38
- * @copyright 2007 Jim Wigginton
39
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
40
- * @link http://phpseclib.sourceforge.net
41
- */
42
-
43
- namespace phpseclib\Crypt;
44
-
45
- /**
46
- * Pure-PHP implementation of DES.
47
- *
48
- * @package DES
49
- * @author Jim Wigginton <terrafrost@php.net>
50
- * @access public
51
- */
52
- class DES extends Base
53
- {
54
- /**#@+
55
- * @access private
56
- * @see \phpseclib\Crypt\DES::_setupKey()
57
- * @see \phpseclib\Crypt\DES::_processBlock()
58
- */
59
- /**
60
- * Contains $keys[self::ENCRYPT]
61
- */
62
- const ENCRYPT = 0;
63
- /**
64
- * Contains $keys[self::DECRYPT]
65
- */
66
- const DECRYPT = 1;
67
- /**#@-*/
68
-
69
- /**
70
- * Block Length of the cipher
71
- *
72
- * @see \phpseclib\Crypt\Base::block_size
73
- * @var int
74
- * @access private
75
- */
76
- var $block_size = 8;
77
-
78
- /**
79
- * Key Length (in bytes)
80
- *
81
- * @see \phpseclib\Crypt\Base::setKeyLength()
82
- * @var int
83
- * @access private
84
- */
85
- var $key_length = 8;
86
-
87
- /**
88
- * The mcrypt specific name of the cipher
89
- *
90
- * @see \phpseclib\Crypt\Base::cipher_name_mcrypt
91
- * @var string
92
- * @access private
93
- */
94
- var $cipher_name_mcrypt = 'des';
95
-
96
- /**
97
- * The OpenSSL names of the cipher / modes
98
- *
99
- * @see \phpseclib\Crypt\Base::openssl_mode_names
100
- * @var array
101
- * @access private
102
- */
103
- var $openssl_mode_names = array(
104
- self::MODE_ECB => 'des-ecb',
105
- self::MODE_CBC => 'des-cbc',
106
- self::MODE_CFB => 'des-cfb',
107
- self::MODE_OFB => 'des-ofb'
108
- // self::MODE_CTR is undefined for DES
109
- );
110
-
111
- /**
112
- * Optimizing value while CFB-encrypting
113
- *
114
- * @see \phpseclib\Crypt\Base::cfb_init_len
115
- * @var int
116
- * @access private
117
- */
118
- var $cfb_init_len = 500;
119
-
120
- /**
121
- * Switch for DES/3DES encryption
122
- *
123
- * Used only if $engine == self::ENGINE_INTERNAL
124
- *
125
- * @see self::_setupKey()
126
- * @see self::_processBlock()
127
- * @var int
128
- * @access private
129
- */
130
- var $des_rounds = 1;
131
-
132
- /**
133
- * max possible size of $key
134
- *
135
- * @see self::setKey()
136
- * @var string
137
- * @access private
138
- */
139
- var $key_length_max = 8;
140
-
141
- /**
142
- * The Key Schedule
143
- *
144
- * @see self::_setupKey()
145
- * @var array
146
- * @access private
147
- */
148
- var $keys;
149
-
150
- /**
151
- * Shuffle table.
152
- *
153
- * For each byte value index, the entry holds an 8-byte string
154
- * with each byte containing all bits in the same state as the
155
- * corresponding bit in the index value.
156
- *
157
- * @see self::_processBlock()
158
- * @see self::_setupKey()
159
- * @var array
160
- * @access private
161
- */
162
- var $shuffle = array(
163
- "\x00\x00\x00\x00\x00\x00\x00\x00", "\x00\x00\x00\x00\x00\x00\x00\xFF",
164
- "\x00\x00\x00\x00\x00\x00\xFF\x00", "\x00\x00\x00\x00\x00\x00\xFF\xFF",
165
- "\x00\x00\x00\x00\x00\xFF\x00\x00", "\x00\x00\x00\x00\x00\xFF\x00\xFF",
166
- "\x00\x00\x00\x00\x00\xFF\xFF\x00", "\x00\x00\x00\x00\x00\xFF\xFF\xFF",
167
- "\x00\x00\x00\x00\xFF\x00\x00\x00", "\x00\x00\x00\x00\xFF\x00\x00\xFF",
168
- "\x00\x00\x00\x00\xFF\x00\xFF\x00", "\x00\x00\x00\x00\xFF\x00\xFF\xFF",
169
- "\x00\x00\x00\x00\xFF\xFF\x00\x00", "\x00\x00\x00\x00\xFF\xFF\x00\xFF",
170
- "\x00\x00\x00\x00\xFF\xFF\xFF\x00", "\x00\x00\x00\x00\xFF\xFF\xFF\xFF",
171
- "\x00\x00\x00\xFF\x00\x00\x00\x00", "\x00\x00\x00\xFF\x00\x00\x00\xFF",
172
- "\x00\x00\x00\xFF\x00\x00\xFF\x00", "\x00\x00\x00\xFF\x00\x00\xFF\xFF",
173
- "\x00\x00\x00\xFF\x00\xFF\x00\x00", "\x00\x00\x00\xFF\x00\xFF\x00\xFF",
174
- "\x00\x00\x00\xFF\x00\xFF\xFF\x00", "\x00\x00\x00\xFF\x00\xFF\xFF\xFF",
175
- "\x00\x00\x00\xFF\xFF\x00\x00\x00", "\x00\x00\x00\xFF\xFF\x00\x00\xFF",
176
- "\x00\x00\x00\xFF\xFF\x00\xFF\x00", "\x00\x00\x00\xFF\xFF\x00\xFF\xFF",
177
- "\x00\x00\x00\xFF\xFF\xFF\x00\x00", "\x00\x00\x00\xFF\xFF\xFF\x00\xFF",
178
- "\x00\x00\x00\xFF\xFF\xFF\xFF\x00", "\x00\x00\x00\xFF\xFF\xFF\xFF\xFF",
179
- "\x00\x00\xFF\x00\x00\x00\x00\x00", "\x00\x00\xFF\x00\x00\x00\x00\xFF",
180
- "\x00\x00\xFF\x00\x00\x00\xFF\x00", "\x00\x00\xFF\x00\x00\x00\xFF\xFF",
181
- "\x00\x00\xFF\x00\x00\xFF\x00\x00", "\x00\x00\xFF\x00\x00\xFF\x00\xFF",
182
- "\x00\x00\xFF\x00\x00\xFF\xFF\x00", "\x00\x00\xFF\x00\x00\xFF\xFF\xFF",
183
- "\x00\x00\xFF\x00\xFF\x00\x00\x00", "\x00\x00\xFF\x00\xFF\x00\x00\xFF",
184
- "\x00\x00\xFF\x00\xFF\x00\xFF\x00", "\x00\x00\xFF\x00\xFF\x00\xFF\xFF",
185
- "\x00\x00\xFF\x00\xFF\xFF\x00\x00", "\x00\x00\xFF\x00\xFF\xFF\x00\xFF",
186
- "\x00\x00\xFF\x00\xFF\xFF\xFF\x00", "\x00\x00\xFF\x00\xFF\xFF\xFF\xFF",
187
- "\x00\x00\xFF\xFF\x00\x00\x00\x00", "\x00\x00\xFF\xFF\x00\x00\x00\xFF",
188
- "\x00\x00\xFF\xFF\x00\x00\xFF\x00", "\x00\x00\xFF\xFF\x00\x00\xFF\xFF",
189
- "\x00\x00\xFF\xFF\x00\xFF\x00\x00", "\x00\x00\xFF\xFF\x00\xFF\x00\xFF",
190
- "\x00\x00\xFF\xFF\x00\xFF\xFF\x00", "\x00\x00\xFF\xFF\x00\xFF\xFF\xFF",
191
- "\x00\x00\xFF\xFF\xFF\x00\x00\x00", "\x00\x00\xFF\xFF\xFF\x00\x00\xFF",
192
- "\x00\x00\xFF\xFF\xFF\x00\xFF\x00", "\x00\x00\xFF\xFF\xFF\x00\xFF\xFF",
193
- "\x00\x00\xFF\xFF\xFF\xFF\x00\x00", "\x00\x00\xFF\xFF\xFF\xFF\x00\xFF",
194
- "\x00\x00\xFF\xFF\xFF\xFF\xFF\x00", "\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF",
195
- "\x00\xFF\x00\x00\x00\x00\x00\x00", "\x00\xFF\x00\x00\x00\x00\x00\xFF",
196
- "\x00\xFF\x00\x00\x00\x00\xFF\x00", "\x00\xFF\x00\x00\x00\x00\xFF\xFF",
197
- "\x00\xFF\x00\x00\x00\xFF\x00\x00", "\x00\xFF\x00\x00\x00\xFF\x00\xFF",
198
- "\x00\xFF\x00\x00\x00\xFF\xFF\x00", "\x00\xFF\x00\x00\x00\xFF\xFF\xFF",
199
- "\x00\xFF\x00\x00\xFF\x00\x00\x00", "\x00\xFF\x00\x00\xFF\x00\x00\xFF",
200
- "\x00\xFF\x00\x00\xFF\x00\xFF\x00", "\x00\xFF\x00\x00\xFF\x00\xFF\xFF",
201
- "\x00\xFF\x00\x00\xFF\xFF\x00\x00", "\x00\xFF\x00\x00\xFF\xFF\x00\xFF",
202
- "\x00\xFF\x00\x00\xFF\xFF\xFF\x00", "\x00\xFF\x00\x00\xFF\xFF\xFF\xFF",
203
- "\x00\xFF\x00\xFF\x00\x00\x00\x00", "\x00\xFF\x00\xFF\x00\x00\x00\xFF",
204
- "\x00\xFF\x00\xFF\x00\x00\xFF\x00", "\x00\xFF\x00\xFF\x00\x00\xFF\xFF",
205
- "\x00\xFF\x00\xFF\x00\xFF\x00\x00", "\x00\xFF\x00\xFF\x00\xFF\x00\xFF",
206
- "\x00\xFF\x00\xFF\x00\xFF\xFF\x00", "\x00\xFF\x00\xFF\x00\xFF\xFF\xFF",
207
- "\x00\xFF\x00\xFF\xFF\x00\x00\x00", "\x00\xFF\x00\xFF\xFF\x00\x00\xFF",
208
- "\x00\xFF\x00\xFF\xFF\x00\xFF\x00", "\x00\xFF\x00\xFF\xFF\x00\xFF\xFF",
209
- "\x00\xFF\x00\xFF\xFF\xFF\x00\x00", "\x00\xFF\x00\xFF\xFF\xFF\x00\xFF",
210
- "\x00\xFF\x00\xFF\xFF\xFF\xFF\x00", "\x00\xFF\x00\xFF\xFF\xFF\xFF\xFF",
211
- "\x00\xFF\xFF\x00\x00\x00\x00\x00", "\x00\xFF\xFF\x00\x00\x00\x00\xFF",
212
- "\x00\xFF\xFF\x00\x00\x00\xFF\x00", "\x00\xFF\xFF\x00\x00\x00\xFF\xFF",
213
- "\x00\xFF\xFF\x00\x00\xFF\x00\x00", "\x00\xFF\xFF\x00\x00\xFF\x00\xFF",
214
- "\x00\xFF\xFF\x00\x00\xFF\xFF\x00", "\x00\xFF\xFF\x00\x00\xFF\xFF\xFF",
215
- "\x00\xFF\xFF\x00\xFF\x00\x00\x00", "\x00\xFF\xFF\x00\xFF\x00\x00\xFF",
216
- "\x00\xFF\xFF\x00\xFF\x00\xFF\x00", "\x00\xFF\xFF\x00\xFF\x00\xFF\xFF",
217
- "\x00\xFF\xFF\x00\xFF\xFF\x00\x00", "\x00\xFF\xFF\x00\xFF\xFF\x00\xFF",
218
- "\x00\xFF\xFF\x00\xFF\xFF\xFF\x00", "\x00\xFF\xFF\x00\xFF\xFF\xFF\xFF",
219
- "\x00\xFF\xFF\xFF\x00\x00\x00\x00", "\x00\xFF\xFF\xFF\x00\x00\x00\xFF",
220
- "\x00\xFF\xFF\xFF\x00\x00\xFF\x00", "\x00\xFF\xFF\xFF\x00\x00\xFF\xFF",
221
- "\x00\xFF\xFF\xFF\x00\xFF\x00\x00", "\x00\xFF\xFF\xFF\x00\xFF\x00\xFF",
222
- "\x00\xFF\xFF\xFF\x00\xFF\xFF\x00", "\x00\xFF\xFF\xFF\x00\xFF\xFF\xFF",
223
- "\x00\xFF\xFF\xFF\xFF\x00\x00\x00", "\x00\xFF\xFF\xFF\xFF\x00\x00\xFF",
224
- "\x00\xFF\xFF\xFF\xFF\x00\xFF\x00", "\x00\xFF\xFF\xFF\xFF\x00\xFF\xFF",
225
- "\x00\xFF\xFF\xFF\xFF\xFF\x00\x00", "\x00\xFF\xFF\xFF\xFF\xFF\x00\xFF",
226
- "\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00", "\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF",
227
- "\xFF\x00\x00\x00\x00\x00\x00\x00", "\xFF\x00\x00\x00\x00\x00\x00\xFF",
228
- "\xFF\x00\x00\x00\x00\x00\xFF\x00", "\xFF\x00\x00\x00\x00\x00\xFF\xFF",
229
- "\xFF\x00\x00\x00\x00\xFF\x00\x00", "\xFF\x00\x00\x00\x00\xFF\x00\xFF",
230
- "\xFF\x00\x00\x00\x00\xFF\xFF\x00", "\xFF\x00\x00\x00\x00\xFF\xFF\xFF",
231
- "\xFF\x00\x00\x00\xFF\x00\x00\x00", "\xFF\x00\x00\x00\xFF\x00\x00\xFF",
232
- "\xFF\x00\x00\x00\xFF\x00\xFF\x00", "\xFF\x00\x00\x00\xFF\x00\xFF\xFF",
233
- "\xFF\x00\x00\x00\xFF\xFF\x00\x00", "\xFF\x00\x00\x00\xFF\xFF\x00\xFF",
234
- "\xFF\x00\x00\x00\xFF\xFF\xFF\x00", "\xFF\x00\x00\x00\xFF\xFF\xFF\xFF",
235
- "\xFF\x00\x00\xFF\x00\x00\x00\x00", "\xFF\x00\x00\xFF\x00\x00\x00\xFF",
236
- "\xFF\x00\x00\xFF\x00\x00\xFF\x00", "\xFF\x00\x00\xFF\x00\x00\xFF\xFF",
237
- "\xFF\x00\x00\xFF\x00\xFF\x00\x00", "\xFF\x00\x00\xFF\x00\xFF\x00\xFF",
238
- "\xFF\x00\x00\xFF\x00\xFF\xFF\x00", "\xFF\x00\x00\xFF\x00\xFF\xFF\xFF",
239
- "\xFF\x00\x00\xFF\xFF\x00\x00\x00", "\xFF\x00\x00\xFF\xFF\x00\x00\xFF",
240
- "\xFF\x00\x00\xFF\xFF\x00\xFF\x00", "\xFF\x00\x00\xFF\xFF\x00\xFF\xFF",
241
- "\xFF\x00\x00\xFF\xFF\xFF\x00\x00", "\xFF\x00\x00\xFF\xFF\xFF\x00\xFF",
242
- "\xFF\x00\x00\xFF\xFF\xFF\xFF\x00", "\xFF\x00\x00\xFF\xFF\xFF\xFF\xFF",
243
- "\xFF\x00\xFF\x00\x00\x00\x00\x00", "\xFF\x00\xFF\x00\x00\x00\x00\xFF",
244
- "\xFF\x00\xFF\x00\x00\x00\xFF\x00", "\xFF\x00\xFF\x00\x00\x00\xFF\xFF",
245
- "\xFF\x00\xFF\x00\x00\xFF\x00\x00", "\xFF\x00\xFF\x00\x00\xFF\x00\xFF",
246
- "\xFF\x00\xFF\x00\x00\xFF\xFF\x00", "\xFF\x00\xFF\x00\x00\xFF\xFF\xFF",
247
- "\xFF\x00\xFF\x00\xFF\x00\x00\x00", "\xFF\x00\xFF\x00\xFF\x00\x00\xFF",
248
- "\xFF\x00\xFF\x00\xFF\x00\xFF\x00", "\xFF\x00\xFF\x00\xFF\x00\xFF\xFF",
249
- "\xFF\x00\xFF\x00\xFF\xFF\x00\x00", "\xFF\x00\xFF\x00\xFF\xFF\x00\xFF",
250
- "\xFF\x00\xFF\x00\xFF\xFF\xFF\x00", "\xFF\x00\xFF\x00\xFF\xFF\xFF\xFF",
251
- "\xFF\x00\xFF\xFF\x00\x00\x00\x00", "\xFF\x00\xFF\xFF\x00\x00\x00\xFF",
252
- "\xFF\x00\xFF\xFF\x00\x00\xFF\x00", "\xFF\x00\xFF\xFF\x00\x00\xFF\xFF",
253
- "\xFF\x00\xFF\xFF\x00\xFF\x00\x00", "\xFF\x00\xFF\xFF\x00\xFF\x00\xFF",
254
- "\xFF\x00\xFF\xFF\x00\xFF\xFF\x00", "\xFF\x00\xFF\xFF\x00\xFF\xFF\xFF",
255
- "\xFF\x00\xFF\xFF\xFF\x00\x00\x00", "\xFF\x00\xFF\xFF\xFF\x00\x00\xFF",
256
- "\xFF\x00\xFF\xFF\xFF\x00\xFF\x00", "\xFF\x00\xFF\xFF\xFF\x00\xFF\xFF",
257
- "\xFF\x00\xFF\xFF\xFF\xFF\x00\x00", "\xFF\x00\xFF\xFF\xFF\xFF\x00\xFF",
258
- "\xFF\x00\xFF\xFF\xFF\xFF\xFF\x00", "\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF",
259
- "\xFF\xFF\x00\x00\x00\x00\x00\x00", "\xFF\xFF\x00\x00\x00\x00\x00\xFF",
260
- "\xFF\xFF\x00\x00\x00\x00\xFF\x00", "\xFF\xFF\x00\x00\x00\x00\xFF\xFF",
261
- "\xFF\xFF\x00\x00\x00\xFF\x00\x00", "\xFF\xFF\x00\x00\x00\xFF\x00\xFF",
262
- "\xFF\xFF\x00\x00\x00\xFF\xFF\x00", "\xFF\xFF\x00\x00\x00\xFF\xFF\xFF",
263
- "\xFF\xFF\x00\x00\xFF\x00\x00\x00", "\xFF\xFF\x00\x00\xFF\x00\x00\xFF",
264
- "\xFF\xFF\x00\x00\xFF\x00\xFF\x00", "\xFF\xFF\x00\x00\xFF\x00\xFF\xFF",
265
- "\xFF\xFF\x00\x00\xFF\xFF\x00\x00", "\xFF\xFF\x00\x00\xFF\xFF\x00\xFF",
266
- "\xFF\xFF\x00\x00\xFF\xFF\xFF\x00", "\xFF\xFF\x00\x00\xFF\xFF\xFF\xFF",
267
- "\xFF\xFF\x00\xFF\x00\x00\x00\x00", "\xFF\xFF\x00\xFF\x00\x00\x00\xFF",
268
- "\xFF\xFF\x00\xFF\x00\x00\xFF\x00", "\xFF\xFF\x00\xFF\x00\x00\xFF\xFF",
269
- "\xFF\xFF\x00\xFF\x00\xFF\x00\x00", "\xFF\xFF\x00\xFF\x00\xFF\x00\xFF",
270
- "\xFF\xFF\x00\xFF\x00\xFF\xFF\x00", "\xFF\xFF\x00\xFF\x00\xFF\xFF\xFF",
271
- "\xFF\xFF\x00\xFF\xFF\x00\x00\x00", "\xFF\xFF\x00\xFF\xFF\x00\x00\xFF",
272
- "\xFF\xFF\x00\xFF\xFF\x00\xFF\x00", "\xFF\xFF\x00\xFF\xFF\x00\xFF\xFF",
273
- "\xFF\xFF\x00\xFF\xFF\xFF\x00\x00", "\xFF\xFF\x00\xFF\xFF\xFF\x00\xFF",
274
- "\xFF\xFF\x00\xFF\xFF\xFF\xFF\x00", "\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF",
275
- "\xFF\xFF\xFF\x00\x00\x00\x00\x00", "\xFF\xFF\xFF\x00\x00\x00\x00\xFF",
276
- "\xFF\xFF\xFF\x00\x00\x00\xFF\x00", "\xFF\xFF\xFF\x00\x00\x00\xFF\xFF",
277
- "\xFF\xFF\xFF\x00\x00\xFF\x00\x00", "\xFF\xFF\xFF\x00\x00\xFF\x00\xFF",
278
- "\xFF\xFF\xFF\x00\x00\xFF\xFF\x00", "\xFF\xFF\xFF\x00\x00\xFF\xFF\xFF",
279
- "\xFF\xFF\xFF\x00\xFF\x00\x00\x00", "\xFF\xFF\xFF\x00\xFF\x00\x00\xFF",
280
- "\xFF\xFF\xFF\x00\xFF\x00\xFF\x00", "\xFF\xFF\xFF\x00\xFF\x00\xFF\xFF",
281
- "\xFF\xFF\xFF\x00\xFF\xFF\x00\x00", "\xFF\xFF\xFF\x00\xFF\xFF\x00\xFF",
282
- "\xFF\xFF\xFF\x00\xFF\xFF\xFF\x00", "\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF",
283
- "\xFF\xFF\xFF\xFF\x00\x00\x00\x00", "\xFF\xFF\xFF\xFF\x00\x00\x00\xFF",
284
- "\xFF\xFF\xFF\xFF\x00\x00\xFF\x00", "\xFF\xFF\xFF\xFF\x00\x00\xFF\xFF",
285
- "\xFF\xFF\xFF\xFF\x00\xFF\x00\x00", "\xFF\xFF\xFF\xFF\x00\xFF\x00\xFF",
286
- "\xFF\xFF\xFF\xFF\x00\xFF\xFF\x00", "\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF",
287
- "\xFF\xFF\xFF\xFF\xFF\x00\x00\x00", "\xFF\xFF\xFF\xFF\xFF\x00\x00\xFF",
288
- "\xFF\xFF\xFF\xFF\xFF\x00\xFF\x00", "\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF",
289
- "\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00", "\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF",
290
- "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00", "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
291
- );
292
-
293
- /**
294
- * IP mapping helper table.
295
- *
296
- * Indexing this table with each source byte performs the initial bit permutation.
297
- *
298
- * @var array
299
- * @access private
300
- */
301
- var $ipmap = array(
302
- 0x00, 0x10, 0x01, 0x11, 0x20, 0x30, 0x21, 0x31,
303
- 0x02, 0x12, 0x03, 0x13, 0x22, 0x32, 0x23, 0x33,
304
- 0x40, 0x50, 0x41, 0x51, 0x60, 0x70, 0x61, 0x71,
305
- 0x42, 0x52, 0x43, 0x53, 0x62, 0x72, 0x63, 0x73,
306
- 0x04, 0x14, 0x05, 0x15, 0x24, 0x34, 0x25, 0x35,
307
- 0x06, 0x16, 0x07, 0x17, 0x26, 0x36, 0x27, 0x37,
308
- 0x44, 0x54, 0x45, 0x55, 0x64, 0x74, 0x65, 0x75,
309
- 0x46, 0x56, 0x47, 0x57, 0x66, 0x76, 0x67, 0x77,
310
- 0x80, 0x90, 0x81, 0x91, 0xA0, 0xB0, 0xA1, 0xB1,
311
- 0x82, 0x92, 0x83, 0x93, 0xA2, 0xB2, 0xA3, 0xB3,
312
- 0xC0, 0xD0, 0xC1, 0xD1, 0xE0, 0xF0, 0xE1, 0xF1,
313
- 0xC2, 0xD2, 0xC3, 0xD3, 0xE2, 0xF2, 0xE3, 0xF3,
314
- 0x84, 0x94, 0x85, 0x95, 0xA4, 0xB4, 0xA5, 0xB5,
315
- 0x86, 0x96, 0x87, 0x97, 0xA6, 0xB6, 0xA7, 0xB7,
316
- 0xC4, 0xD4, 0xC5, 0xD5, 0xE4, 0xF4, 0xE5, 0xF5,
317
- 0xC6, 0xD6, 0xC7, 0xD7, 0xE6, 0xF6, 0xE7, 0xF7,
318
- 0x08, 0x18, 0x09, 0x19, 0x28, 0x38, 0x29, 0x39,
319
- 0x0A, 0x1A, 0x0B, 0x1B, 0x2A, 0x3A, 0x2B, 0x3B,
320
- 0x48, 0x58, 0x49, 0x59, 0x68, 0x78, 0x69, 0x79,
321
- 0x4A, 0x5A, 0x4B, 0x5B, 0x6A, 0x7A, 0x6B, 0x7B,
322
- 0x0C, 0x1C, 0x0D, 0x1D, 0x2C, 0x3C, 0x2D, 0x3D,
323
- 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
324
- 0x4C, 0x5C, 0x4D, 0x5D, 0x6C, 0x7C, 0x6D, 0x7D,
325
- 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
326
- 0x88, 0x98, 0x89, 0x99, 0xA8, 0xB8, 0xA9, 0xB9,
327
- 0x8A, 0x9A, 0x8B, 0x9B, 0xAA, 0xBA, 0xAB, 0xBB,
328
- 0xC8, 0xD8, 0xC9, 0xD9, 0xE8, 0xF8, 0xE9, 0xF9,
329
- 0xCA, 0xDA, 0xCB, 0xDB, 0xEA, 0xFA, 0xEB, 0xFB,
330
- 0x8C, 0x9C, 0x8D, 0x9D, 0xAC, 0xBC, 0xAD, 0xBD,
331
- 0x8E, 0x9E, 0x8F, 0x9F, 0xAE, 0xBE, 0xAF, 0xBF,
332
- 0xCC, 0xDC, 0xCD, 0xDD, 0xEC, 0xFC, 0xED, 0xFD,
333
- 0xCE, 0xDE, 0xCF, 0xDF, 0xEE, 0xFE, 0xEF, 0xFF
334
- );
335
-
336
- /**
337
- * Inverse IP mapping helper table.
338
- * Indexing this table with a byte value reverses the bit order.
339
- *
340
- * @var array
341
- * @access private
342
- */
343
- var $invipmap = array(
344
- 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
345
- 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
346
- 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
347
- 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
348
- 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4,
349
- 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
350
- 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
351
- 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
352
- 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
353
- 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
354
- 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
355
- 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
356
- 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
357
- 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
358
- 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
359
- 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
360
- 0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1,
361
- 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
362
- 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9,
363
- 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
364
- 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
365
- 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
366
- 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED,
367
- 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
368
- 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3,
369
- 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
370
- 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
371
- 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
372
- 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,
373
- 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
374
- 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF,
375
- 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
376
- );
377
-
378
- /**
379
- * Pre-permuted S-box1
380
- *
381
- * Each box ($sbox1-$sbox8) has been vectorized, then each value pre-permuted using the
382
- * P table: concatenation can then be replaced by exclusive ORs.
383
- *
384
- * @var array
385
- * @access private
386
- */
387
- var $sbox1 = array(
388
- 0x00808200, 0x00000000, 0x00008000, 0x00808202,
389
- 0x00808002, 0x00008202, 0x00000002, 0x00008000,
390
- 0x00000200, 0x00808200, 0x00808202, 0x00000200,
391
- 0x00800202, 0x00808002, 0x00800000, 0x00000002,
392
- 0x00000202, 0x00800200, 0x00800200, 0x00008200,
393
- 0x00008200, 0x00808000, 0x00808000, 0x00800202,
394
- 0x00008002, 0x00800002, 0x00800002, 0x00008002,
395
- 0x00000000, 0x00000202, 0x00008202, 0x00800000,
396
- 0x00008000, 0x00808202, 0x00000002, 0x00808000,
397
- 0x00808200, 0x00800000, 0x00800000, 0x00000200,
398
- 0x00808002, 0x00008000, 0x00008200, 0x00800002,
399
- 0x00000200, 0x00000002, 0x00800202, 0x00008202,
400
- 0x00808202, 0x00008002, 0x00808000, 0x00800202,
401
- 0x00800002, 0x00000202, 0x00008202, 0x00808200,
402
- 0x00000202, 0x00800200, 0x00800200, 0x00000000,
403
- 0x00008002, 0x00008200, 0x00000000, 0x00808002
404
- );
405
-
406
- /**
407
- * Pre-permuted S-box2
408
- *
409
- * @var array
410
- * @access private
411
- */
412
- var $sbox2 = array(
413
- 0x40084010, 0x40004000, 0x00004000, 0x00084010,
414
- 0x00080000, 0x00000010, 0x40080010, 0x40004010,
415
- 0x40000010, 0x40084010, 0x40084000, 0x40000000,
416
- 0x40004000, 0x00080000, 0x00000010, 0x40080010,
417
- 0x00084000, 0x00080010, 0x40004010, 0x00000000,
418
- 0x40000000, 0x00004000, 0x00084010, 0x40080000,
419
- 0x00080010, 0x40000010, 0x00000000, 0x00084000,
420
- 0x00004010, 0x40084000, 0x40080000, 0x00004010,
421
- 0x00000000, 0x00084010, 0x40080010, 0x00080000,
422
- 0x40004010, 0x40080000, 0x40084000, 0x00004000,
423
- 0x40080000, 0x40004000, 0x00000010, 0x40084010,
424
- 0x00084010, 0x00000010, 0x00004000, 0x40000000,
425
- 0x00004010, 0x40084000, 0x00080000, 0x40000010,
426
- 0x00080010, 0x40004010, 0x40000010, 0x00080010,
427
- 0x00084000, 0x00000000, 0x40004000, 0x00004010,
428
- 0x40000000, 0x40080010, 0x40084010, 0x00084000
429
- );
430
-
431
- /**
432
- * Pre-permuted S-box3
433
- *
434
- * @var array
435
- * @access private
436
- */
437
- var $sbox3 = array(
438
- 0x00000104, 0x04010100, 0x00000000, 0x04010004,
439
- 0x04000100, 0x00000000, 0x00010104, 0x04000100,
440
- 0x00010004, 0x04000004, 0x04000004, 0x00010000,
441
- 0x04010104, 0x00010004, 0x04010000, 0x00000104,
442
- 0x04000000, 0x00000004, 0x04010100, 0x00000100,
443
- 0x00010100, 0x04010000, 0x04010004, 0x00010104,
444
- 0x04000104, 0x00010100, 0x00010000, 0x04000104,
445
- 0x00000004, 0x04010104, 0x00000100, 0x04000000,
446
- 0x04010100, 0x04000000, 0x00010004, 0x00000104,
447
- 0x00010000, 0x04010100, 0x04000100, 0x00000000,
448
- 0x00000100, 0x00010004, 0x04010104, 0x04000100,
449
- 0x04000004, 0x00000100, 0x00000000, 0x04010004,
450
- 0x04000104, 0x00010000, 0x04000000, 0x04010104,
451
- 0x00000004, 0x00010104, 0x00010100, 0x04000004,
452
- 0x04010000, 0x04000104, 0x00000104, 0x04010000,
453
- 0x00010104, 0x00000004, 0x04010004, 0x00010100
454
- );
455
-
456
- /**
457
- * Pre-permuted S-box4
458
- *
459
- * @var array
460
- * @access private
461
- */
462
- var $sbox4 = array(
463
- 0x80401000, 0x80001040, 0x80001040, 0x00000040,
464
- 0x00401040, 0x80400040, 0x80400000, 0x80001000,
465
- 0x00000000, 0x00401000, 0x00401000, 0x80401040,
466
- 0x80000040, 0x00000000, 0x00400040, 0x80400000,
467
- 0x80000000, 0x00001000, 0x00400000, 0x80401000,
468
- 0x00000040, 0x00400000, 0x80001000, 0x00001040,
469
- 0x80400040, 0x80000000, 0x00001040, 0x00400040,
470
- 0x00001000, 0x00401040, 0x80401040, 0x80000040,
471
- 0x00400040, 0x80400000, 0x00401000, 0x80401040,
472
- 0x80000040, 0x00000000, 0x00000000, 0x00401000,
473
- 0x00001040, 0x00400040, 0x80400040, 0x80000000,
474
- 0x80401000, 0x80001040, 0x80001040, 0x00000040,
475
- 0x80401040, 0x80000040, 0x80000000, 0x00001000,
476
- 0x80400000, 0x80001000, 0x00401040, 0x80400040,
477
- 0x80001000, 0x00001040, 0x00400000, 0x80401000,
478
- 0x00000040, 0x00400000, 0x00001000, 0x00401040
479
- );
480
-
481
- /**
482
- * Pre-permuted S-box5
483
- *
484
- * @var array
485
- * @access private
486
- */
487
- var $sbox5 = array(
488
- 0x00000080, 0x01040080, 0x01040000, 0x21000080,
489
- 0x00040000, 0x00000080, 0x20000000, 0x01040000,
490
- 0x20040080, 0x00040000, 0x01000080, 0x20040080,
491
- 0x21000080, 0x21040000, 0x00040080, 0x20000000,
492
- 0x01000000, 0x20040000, 0x20040000, 0x00000000,
493
- 0x20000080, 0x21040080, 0x21040080, 0x01000080,
494
- 0x21040000, 0x20000080, 0x00000000, 0x21000000,
495
- 0x01040080, 0x01000000, 0x21000000, 0x00040080,
496
- 0x00040000, 0x21000080, 0x00000080, 0x01000000,
497
- 0x20000000, 0x01040000, 0x21000080, 0x20040080,
498
- 0x01000080, 0x20000000, 0x21040000, 0x01040080,
499
- 0x20040080, 0x00000080, 0x01000000, 0x21040000,
500
- 0x21040080, 0x00040080, 0x21000000, 0x21040080,
501
- 0x01040000, 0x00000000, 0x20040000, 0x21000000,
502
- 0x00040080, 0x01000080, 0x20000080, 0x00040000,
503
- 0x00000000, 0x20040000, 0x01040080, 0x20000080
504
- );
505
-
506
- /**
507
- * Pre-permuted S-box6
508
- *
509
- * @var array
510
- * @access private
511
- */
512
- var $sbox6 = array(
513
- 0x10000008, 0x10200000, 0x00002000, 0x10202008,
514
- 0x10200000, 0x00000008, 0x10202008, 0x00200000,
515
- 0x10002000, 0x00202008, 0x00200000, 0x10000008,
516
- 0x00200008, 0x10002000, 0x10000000, 0x00002008,
517
- 0x00000000, 0x00200008, 0x10002008, 0x00002000,
518
- 0x00202000, 0x10002008, 0x00000008, 0x10200008,
519
- 0x10200008, 0x00000000, 0x00202008, 0x10202000,
520
- 0x00002008, 0x00202000, 0x10202000, 0x10000000,
521
- 0x10002000, 0x00000008, 0x10200008, 0x00202000,
522
- 0x10202008, 0x00200000, 0x00002008, 0x10000008,
523
- 0x00200000, 0x10002000, 0x10000000, 0x00002008,
524
- 0x10000008, 0x10202008, 0x00202000, 0x10200000,
525
- 0x00202008, 0x10202000, 0x00000000, 0x10200008,
526
- 0x00000008, 0x00002000, 0x10200000, 0x00202008,
527
- 0x00002000, 0x00200008, 0x10002008, 0x00000000,
528
- 0x10202000, 0x10000000, 0x00200008, 0x10002008
529
- );
530
-
531
- /**
532
- * Pre-permuted S-box7
533
- *
534
- * @var array
535
- * @access private
536
- */
537
- var $sbox7 = array(
538
- 0x00100000, 0x02100001, 0x02000401, 0x00000000,
539
- 0x00000400, 0x02000401, 0x00100401, 0x02100400,
540
- 0x02100401, 0x00100000, 0x00000000, 0x02000001,
541
- 0x00000001, 0x02000000, 0x02100001, 0x00000401,
542
- 0x02000400, 0x00100401, 0x00100001, 0x02000400,
543
- 0x02000001, 0x02100000, 0x02100400, 0x00100001,
544
- 0x02100000, 0x00000400, 0x00000401, 0x02100401,
545
- 0x00100400, 0x00000001, 0x02000000, 0x00100400,
546
- 0x02000000, 0x00100400, 0x00100000, 0x02000401,
547
- 0x02000401, 0x02100001, 0x02100001, 0x00000001,
548
- 0x00100001, 0x02000000, 0x02000400, 0x00100000,
549
- 0x02100400, 0x00000401, 0x00100401, 0x02100400,
550
- 0x00000401, 0x02000001, 0x02100401, 0x02100000,
551
- 0x00100400, 0x00000000, 0x00000001, 0x02100401,
552
- 0x00000000, 0x00100401, 0x02100000, 0x00000400,
553
- 0x02000001, 0x02000400, 0x00000400, 0x00100001
554
- );
555
-
556
- /**
557
- * Pre-permuted S-box8
558
- *
559
- * @var array
560
- * @access private
561
- */
562
- var $sbox8 = array(
563
- 0x08000820, 0x00000800, 0x00020000, 0x08020820,
564
- 0x08000000, 0x08000820, 0x00000020, 0x08000000,
565
- 0x00020020, 0x08020000, 0x08020820, 0x00020800,
566
- 0x08020800, 0x00020820, 0x00000800, 0x00000020,
567
- 0x08020000, 0x08000020, 0x08000800, 0x00000820,
568
- 0x00020800, 0x00020020, 0x08020020, 0x08020800,
569
- 0x00000820, 0x00000000, 0x00000000, 0x08020020,
570
- 0x08000020, 0x08000800, 0x00020820, 0x00020000,
571
- 0x00020820, 0x00020000, 0x08020800, 0x00000800,
572
- 0x00000020, 0x08020020, 0x00000800, 0x00020820,
573
- 0x08000800, 0x00000020, 0x08000020, 0x08020000,
574
- 0x08020020, 0x08000000, 0x00020000, 0x08000820,
575
- 0x00000000, 0x08020820, 0x00020020, 0x08000020,
576
- 0x08020000, 0x08000800, 0x08000820, 0x00000000,
577
- 0x08020820, 0x00020800, 0x00020800, 0x00000820,
578
- 0x00000820, 0x00020020, 0x08000000, 0x08020800
579
- );
580
-
581
- /**
582
- * Test for engine validity
583
- *
584
- * This is mainly just a wrapper to set things up for \phpseclib\Crypt\Base::isValidEngine()
585
- *
586
- * @see \phpseclib\Crypt\Base::isValidEngine()
587
- * @param int $engine
588
- * @access public
589
- * @return bool
590
- */
591
- function isValidEngine($engine)
592
- {
593
- if ($this->key_length_max == 8) {
594
- if ($engine == self::ENGINE_OPENSSL) {
595
- $this->cipher_name_openssl_ecb = 'des-ecb';
596
- $this->cipher_name_openssl = 'des-' . $this->_openssl_translate_mode();
597
- }
598
- }
599
-
600
- return parent::isValidEngine($engine);
601
- }
602
-
603
- /**
604
- * Sets the key.
605
- *
606
- * Keys can be of any length. DES, itself, uses 64-bit keys (eg. strlen($key) == 8), however, we
607
- * only use the first eight, if $key has more then eight characters in it, and pad $key with the
608
- * null byte if it is less then eight characters long.
609
- *
610
- * DES also requires that every eighth bit be a parity bit, however, we'll ignore that.
611
- *
612
- * If the key is not explicitly set, it'll be assumed to be all zero's.
613
- *
614
- * @see \phpseclib\Crypt\Base::setKey()
615
- * @access public
616
- * @param string $key
617
- */
618
- function setKey($key)
619
- {
620
- // We check/cut here only up to max length of the key.
621
- // Key padding to the proper length will be done in _setupKey()
622
- if (strlen($key) > $this->key_length_max) {
623
- $key = substr($key, 0, $this->key_length_max);
624
- }
625
-
626
- // Sets the key
627
- parent::setKey($key);
628
- }
629
-
630
- /**
631
- * Encrypts a block
632
- *
633
- * @see \phpseclib\Crypt\Base::_encryptBlock()
634
- * @see \phpseclib\Crypt\Base::encrypt()
635
- * @see self::encrypt()
636
- * @access private
637
- * @param string $in
638
- * @return string
639
- */
640
- function _encryptBlock($in)
641
- {
642
- return $this->_processBlock($in, self::ENCRYPT);
643
- }
644
-
645
- /**
646
- * Decrypts a block
647
- *
648
- * @see \phpseclib\Crypt\Base::_decryptBlock()
649
- * @see \phpseclib\Crypt\Base::decrypt()
650
- * @see self::decrypt()
651
- * @access private
652
- * @param string $in
653
- * @return string
654
- */
655
- function _decryptBlock($in)
656
- {
657
- return $this->_processBlock($in, self::DECRYPT);
658
- }
659
-
660
- /**
661
- * Encrypts or decrypts a 64-bit block
662
- *
663
- * $mode should be either self::ENCRYPT or self::DECRYPT. See
664
- * {@link http://en.wikipedia.org/wiki/Image:Feistel.png Feistel.png} to get a general
665
- * idea of what this function does.
666
- *
667
- * @see self::_encryptBlock()
668
- * @see self::_decryptBlock()
669
- * @access private
670
- * @param string $block
671
- * @param int $mode
672
- * @return string
673
- */
674
- function _processBlock($block, $mode)
675
- {
676
- static $sbox1, $sbox2, $sbox3, $sbox4, $sbox5, $sbox6, $sbox7, $sbox8, $shuffleip, $shuffleinvip;
677
- if (!$sbox1) {
678
- $sbox1 = array_map("intval", $this->sbox1);
679
- $sbox2 = array_map("intval", $this->sbox2);
680
- $sbox3 = array_map("intval", $this->sbox3);
681
- $sbox4 = array_map("intval", $this->sbox4);
682
- $sbox5 = array_map("intval", $this->sbox5);
683
- $sbox6 = array_map("intval", $this->sbox6);
684
- $sbox7 = array_map("intval", $this->sbox7);
685
- $sbox8 = array_map("intval", $this->sbox8);
686
- /* Merge $shuffle with $[inv]ipmap */
687
- for ($i = 0; $i < 256; ++$i) {
688
- $shuffleip[] = $this->shuffle[$this->ipmap[$i]];
689
- $shuffleinvip[] = $this->shuffle[$this->invipmap[$i]];
690
- }
691
- }
692
-
693
- $keys = $this->keys[$mode];
694
- $ki = -1;
695
-
696
- // Do the initial IP permutation.
697
- $t = unpack('Nl/Nr', $block);
698
- list($l, $r) = array($t['l'], $t['r']);
699
- $block = ($shuffleip[ $r & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") |
700
- ($shuffleip[($r >> 8) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") |
701
- ($shuffleip[($r >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") |
702
- ($shuffleip[($r >> 24) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") |
703
- ($shuffleip[ $l & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") |
704
- ($shuffleip[($l >> 8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") |
705
- ($shuffleip[($l >> 16) & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") |
706
- ($shuffleip[($l >> 24) & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01");
707
-
708
- // Extract L0 and R0.
709
- $t = unpack('Nl/Nr', $block);
710
- list($l, $r) = array($t['l'], $t['r']);
711
-
712
- for ($des_round = 0; $des_round < $this->des_rounds; ++$des_round) {
713
- // Perform the 16 steps.
714
- for ($i = 0; $i < 16; $i++) {
715
- // start of "the Feistel (F) function" - see the following URL:
716
- // http://en.wikipedia.org/wiki/Image:Data_Encryption_Standard_InfoBox_Diagram.png
717
- // Merge key schedule.
718
- $b1 = (($r >> 3) & 0x1FFFFFFF) ^ ($r << 29) ^ $keys[++$ki];
719
- $b2 = (($r >> 31) & 0x00000001) ^ ($r << 1) ^ $keys[++$ki];
720
-
721
- // S-box indexing.
722
- $t = $sbox1[($b1 >> 24) & 0x3F] ^ $sbox2[($b2 >> 24) & 0x3F] ^
723
- $sbox3[($b1 >> 16) & 0x3F] ^ $sbox4[($b2 >> 16) & 0x3F] ^
724
- $sbox5[($b1 >> 8) & 0x3F] ^ $sbox6[($b2 >> 8) & 0x3F] ^
725
- $sbox7[ $b1 & 0x3F] ^ $sbox8[ $b2 & 0x3F] ^ $l;
726
- // end of "the Feistel (F) function"
727
-
728
- $l = $r;
729
- $r = $t;
730
- }
731
-
732
- // Last step should not permute L & R.
733
- $t = $l;
734
- $l = $r;
735
- $r = $t;
736
- }
737
-
738
- // Perform the inverse IP permutation.
739
- return ($shuffleinvip[($r >> 24) & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") |
740
- ($shuffleinvip[($l >> 24) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") |
741
- ($shuffleinvip[($r >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") |
742
- ($shuffleinvip[($l >> 16) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") |
743
- ($shuffleinvip[($r >> 8) & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") |
744
- ($shuffleinvip[($l >> 8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") |
745
- ($shuffleinvip[ $r & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") |
746
- ($shuffleinvip[ $l & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01");
747
- }
748
-
749
- /**
750
- * Creates the key schedule
751
- *
752
- * @see \phpseclib\Crypt\Base::_setupKey()
753
- * @access private
754
- */
755
- function _setupKey()
756
- {
757
- if (isset($this->kl['key']) && $this->key === $this->kl['key'] && $this->des_rounds === $this->kl['des_rounds']) {
758
- // already expanded
759
- return;
760
- }
761
- $this->kl = array('key' => $this->key, 'des_rounds' => $this->des_rounds);
762
-
763
- static $shifts = array( // number of key bits shifted per round
764
- 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
765
- );
766
-
767
- static $pc1map = array(
768
- 0x00, 0x00, 0x08, 0x08, 0x04, 0x04, 0x0C, 0x0C,
769
- 0x02, 0x02, 0x0A, 0x0A, 0x06, 0x06, 0x0E, 0x0E,
770
- 0x10, 0x10, 0x18, 0x18, 0x14, 0x14, 0x1C, 0x1C,
771
- 0x12, 0x12, 0x1A, 0x1A, 0x16, 0x16, 0x1E, 0x1E,
772
- 0x20, 0x20, 0x28, 0x28, 0x24, 0x24, 0x2C, 0x2C,
773
- 0x22, 0x22, 0x2A, 0x2A, 0x26, 0x26, 0x2E, 0x2E,
774
- 0x30, 0x30, 0x38, 0x38, 0x34, 0x34, 0x3C, 0x3C,
775
- 0x32, 0x32, 0x3A, 0x3A, 0x36, 0x36, 0x3E, 0x3E,
776
- 0x40, 0x40, 0x48, 0x48, 0x44, 0x44, 0x4C, 0x4C,
777
- 0x42, 0x42, 0x4A, 0x4A, 0x46, 0x46, 0x4E, 0x4E,
778
- 0x50, 0x50, 0x58, 0x58, 0x54, 0x54, 0x5C, 0x5C,
779
- 0x52, 0x52, 0x5A, 0x5A, 0x56, 0x56, 0x5E, 0x5E,
780
- 0x60, 0x60, 0x68, 0x68, 0x64, 0x64, 0x6C, 0x6C,
781
- 0x62, 0x62, 0x6A, 0x6A, 0x66, 0x66, 0x6E, 0x6E,
782
- 0x70, 0x70, 0x78, 0x78, 0x74, 0x74, 0x7C, 0x7C,
783
- 0x72, 0x72, 0x7A, 0x7A, 0x76, 0x76, 0x7E, 0x7E,
784
- 0x80, 0x80, 0x88, 0x88, 0x84, 0x84, 0x8C, 0x8C,
785
- 0x82, 0x82, 0x8A, 0x8A, 0x86, 0x86, 0x8E, 0x8E,
786
- 0x90, 0x90, 0x98, 0x98, 0x94, 0x94, 0x9C, 0x9C,
787
- 0x92, 0x92, 0x9A, 0x9A, 0x96, 0x96, 0x9E, 0x9E,
788
- 0xA0, 0xA0, 0xA8, 0xA8, 0xA4, 0xA4, 0xAC, 0xAC,
789
- 0xA2, 0xA2, 0xAA, 0xAA, 0xA6, 0xA6, 0xAE, 0xAE,
790
- 0xB0, 0xB0, 0xB8, 0xB8, 0xB4, 0xB4, 0xBC, 0xBC,
791
- 0xB2, 0xB2, 0xBA, 0xBA, 0xB6, 0xB6, 0xBE, 0xBE,
792
- 0xC0, 0xC0, 0xC8, 0xC8, 0xC4, 0xC4, 0xCC, 0xCC,
793
- 0xC2, 0xC2, 0xCA, 0xCA, 0xC6, 0xC6, 0xCE, 0xCE,
794
- 0xD0, 0xD0, 0xD8, 0xD8, 0xD4, 0xD4, 0xDC, 0xDC,
795
- 0xD2, 0xD2, 0xDA, 0xDA, 0xD6, 0xD6, 0xDE, 0xDE,
796
- 0xE0, 0xE0, 0xE8, 0xE8, 0xE4, 0xE4, 0xEC, 0xEC,
797
- 0xE2, 0xE2, 0xEA, 0xEA, 0xE6, 0xE6, 0xEE, 0xEE,
798
- 0xF0, 0xF0, 0xF8, 0xF8, 0xF4, 0xF4, 0xFC, 0xFC,
799
- 0xF2, 0xF2, 0xFA, 0xFA, 0xF6, 0xF6, 0xFE, 0xFE
800
- );
801
-
802
- // Mapping tables for the PC-2 transformation.
803
- static $pc2mapc1 = array(
804
- 0x00000000, 0x00000400, 0x00200000, 0x00200400,
805
- 0x00000001, 0x00000401, 0x00200001, 0x00200401,
806
- 0x02000000, 0x02000400, 0x02200000, 0x02200400,
807
- 0x02000001, 0x02000401, 0x02200001, 0x02200401
808
- );
809
- static $pc2mapc2 = array(
810
- 0x00000000, 0x00000800, 0x08000000, 0x08000800,
811
- 0x00010000, 0x00010800, 0x08010000, 0x08010800,
812
- 0x00000000, 0x00000800, 0x08000000, 0x08000800,
813
- 0x00010000, 0x00010800, 0x08010000, 0x08010800,
814
- 0x00000100, 0x00000900, 0x08000100, 0x08000900,
815
- 0x00010100, 0x00010900, 0x08010100, 0x08010900,
816
- 0x00000100, 0x00000900, 0x08000100, 0x08000900,
817
- 0x00010100, 0x00010900, 0x08010100, 0x08010900,
818
- 0x00000010, 0x00000810, 0x08000010, 0x08000810,
819
- 0x00010010, 0x00010810, 0x08010010, 0x08010810,
820
- 0x00000010, 0x00000810, 0x08000010, 0x08000810,
821
- 0x00010010, 0x00010810, 0x08010010, 0x08010810,
822
- 0x00000110, 0x00000910, 0x08000110, 0x08000910,
823
- 0x00010110, 0x00010910, 0x08010110, 0x08010910,
824
- 0x00000110, 0x00000910, 0x08000110, 0x08000910,
825
- 0x00010110, 0x00010910, 0x08010110, 0x08010910,
826
- 0x00040000, 0x00040800, 0x08040000, 0x08040800,
827
- 0x00050000, 0x00050800, 0x08050000, 0x08050800,
828
- 0x00040000, 0x00040800, 0x08040000, 0x08040800,
829
- 0x00050000, 0x00050800, 0x08050000, 0x08050800,
830
- 0x00040100, 0x00040900, 0x08040100, 0x08040900,
831
- 0x00050100, 0x00050900, 0x08050100, 0x08050900,
832
- 0x00040100, 0x00040900, 0x08040100, 0x08040900,
833
- 0x00050100, 0x00050900, 0x08050100, 0x08050900,
834
- 0x00040010, 0x00040810, 0x08040010, 0x08040810,
835
- 0x00050010, 0x00050810, 0x08050010, 0x08050810,
836
- 0x00040010, 0x00040810, 0x08040010, 0x08040810,
837
- 0x00050010, 0x00050810, 0x08050010, 0x08050810,
838
- 0x00040110, 0x00040910, 0x08040110, 0x08040910,
839
- 0x00050110, 0x00050910, 0x08050110, 0x08050910,
840
- 0x00040110, 0x00040910, 0x08040110, 0x08040910,
841
- 0x00050110, 0x00050910, 0x08050110, 0x08050910,
842
- 0x01000000, 0x01000800, 0x09000000, 0x09000800,
843
- 0x01010000, 0x01010800, 0x09010000, 0x09010800,
844
- 0x01000000, 0x01000800, 0x09000000, 0x09000800,
845
- 0x01010000, 0x01010800, 0x09010000, 0x09010800,
846
- 0x01000100, 0x01000900, 0x09000100, 0x09000900,
847
- 0x01010100, 0x01010900, 0x09010100, 0x09010900,
848
- 0x01000100, 0x01000900, 0x09000100, 0x09000900,
849
- 0x01010100, 0x01010900, 0x09010100, 0x09010900,
850
- 0x01000010, 0x01000810, 0x09000010, 0x09000810,
851
- 0x01010010, 0x01010810, 0x09010010, 0x09010810,
852
- 0x01000010, 0x01000810, 0x09000010, 0x09000810,
853
- 0x01010010, 0x01010810, 0x09010010, 0x09010810,
854
- 0x01000110, 0x01000910, 0x09000110, 0x09000910,
855
- 0x01010110, 0x01010910, 0x09010110, 0x09010910,
856
- 0x01000110, 0x01000910, 0x09000110, 0x09000910,
857
- 0x01010110, 0x01010910, 0x09010110, 0x09010910,
858
- 0x01040000, 0x01040800, 0x09040000, 0x09040800,
859
- 0x01050000, 0x01050800, 0x09050000, 0x09050800,
860
- 0x01040000, 0x01040800, 0x09040000, 0x09040800,
861
- 0x01050000, 0x01050800, 0x09050000, 0x09050800,
862
- 0x01040100, 0x01040900, 0x09040100, 0x09040900,
863
- 0x01050100, 0x01050900, 0x09050100, 0x09050900,
864
- 0x01040100, 0x01040900, 0x09040100, 0x09040900,
865
- 0x01050100, 0x01050900, 0x09050100, 0x09050900,
866
- 0x01040010, 0x01040810, 0x09040010, 0x09040810,
867
- 0x01050010, 0x01050810, 0x09050010, 0x09050810,
868
- 0x01040010, 0x01040810, 0x09040010, 0x09040810,
869
- 0x01050010, 0x01050810, 0x09050010, 0x09050810,
870
- 0x01040110, 0x01040910, 0x09040110, 0x09040910,
871
- 0x01050110, 0x01050910, 0x09050110, 0x09050910,
872
- 0x01040110, 0x01040910, 0x09040110, 0x09040910,
873
- 0x01050110, 0x01050910, 0x09050110, 0x09050910
874
- );
875
- static $pc2mapc3 = array(
876
- 0x00000000, 0x00000004, 0x00001000, 0x00001004,
877
- 0x00000000, 0x00000004, 0x00001000, 0x00001004,
878
- 0x10000000, 0x10000004, 0x10001000, 0x10001004,
879
- 0x10000000, 0x10000004, 0x10001000, 0x10001004,
880
- 0x00000020, 0x00000024, 0x00001020, 0x00001024,
881
- 0x00000020, 0x00000024, 0x00001020, 0x00001024,
882
- 0x10000020, 0x10000024, 0x10001020, 0x10001024,
883
- 0x10000020, 0x10000024, 0x10001020, 0x10001024,
884
- 0x00080000, 0x00080004, 0x00081000, 0x00081004,
885
- 0x00080000, 0x00080004, 0x00081000, 0x00081004,
886
- 0x10080000, 0x10080004, 0x10081000, 0x10081004,
887
- 0x10080000, 0x10080004, 0x10081000, 0x10081004,
888
- 0x00080020, 0x00080024, 0x00081020, 0x00081024,
889
- 0x00080020, 0x00080024, 0x00081020, 0x00081024,
890
- 0x10080020, 0x10080024, 0x10081020, 0x10081024,
891
- 0x10080020, 0x10080024, 0x10081020, 0x10081024,
892
- 0x20000000, 0x20000004, 0x20001000, 0x20001004,
893
- 0x20000000, 0x20000004, 0x20001000, 0x20001004,
894
- 0x30000000, 0x30000004, 0x30001000, 0x30001004,
895
- 0x30000000, 0x30000004, 0x30001000, 0x30001004,
896
- 0x20000020, 0x20000024, 0x20001020, 0x20001024,
897
- 0x20000020, 0x20000024, 0x20001020, 0x20001024,
898
- 0x30000020, 0x30000024, 0x30001020, 0x30001024,
899
- 0x30000020, 0x30000024, 0x30001020, 0x30001024,
900
- 0x20080000, 0x20080004, 0x20081000, 0x20081004,
901
- 0x20080000, 0x20080004, 0x20081000, 0x20081004,
902
- 0x30080000, 0x30080004, 0x30081000, 0x30081004,
903
- 0x30080000, 0x30080004, 0x30081000, 0x30081004,
904
- 0x20080020, 0x20080024, 0x20081020, 0x20081024,
905
- 0x20080020, 0x20080024, 0x20081020, 0x20081024,
906
- 0x30080020, 0x30080024, 0x30081020, 0x30081024,
907
- 0x30080020, 0x30080024, 0x30081020, 0x30081024,
908
- 0x00000002, 0x00000006, 0x00001002, 0x00001006,
909
- 0x00000002, 0x00000006, 0x00001002, 0x00001006,
910
- 0x10000002, 0x10000006, 0x10001002, 0x10001006,
911
- 0x10000002, 0x10000006, 0x10001002, 0x10001006,
912
- 0x00000022, 0x00000026, 0x00001022, 0x00001026,
913
- 0x00000022, 0x00000026, 0x00001022, 0x00001026,
914
- 0x10000022, 0x10000026, 0x10001022, 0x10001026,
915
- 0x10000022, 0x10000026, 0x10001022, 0x10001026,
916
- 0x00080002, 0x00080006, 0x00081002, 0x00081006,
917
- 0x00080002, 0x00080006, 0x00081002, 0x00081006,
918
- 0x10080002, 0x10080006, 0x10081002, 0x10081006,
919
- 0x10080002, 0x10080006, 0x10081002, 0x10081006,
920
- 0x00080022, 0x00080026, 0x00081022, 0x00081026,
921
- 0x00080022, 0x00080026, 0x00081022, 0x00081026,
922
- 0x10080022, 0x10080026, 0x10081022, 0x10081026,
923
- 0x10080022, 0x10080026, 0x10081022, 0x10081026,
924
- 0x20000002, 0x20000006, 0x20001002, 0x20001006,
925
- 0x20000002, 0x20000006, 0x20001002, 0x20001006,
926
- 0x30000002, 0x30000006, 0x30001002, 0x30001006,
927
- 0x30000002, 0x30000006, 0x30001002, 0x30001006,
928
- 0x20000022, 0x20000026, 0x20001022, 0x20001026,
929
- 0x20000022, 0x20000026, 0x20001022, 0x20001026,
930
- 0x30000022, 0x30000026, 0x30001022, 0x30001026,
931
- 0x30000022, 0x30000026, 0x30001022, 0x30001026,
932
- 0x20080002, 0x20080006, 0x20081002, 0x20081006,
933
- 0x20080002, 0x20080006, 0x20081002, 0x20081006,
934
- 0x30080002, 0x30080006, 0x30081002, 0x30081006,
935
- 0x30080002, 0x30080006, 0x30081002, 0x30081006,
936
- 0x20080022, 0x20080026, 0x20081022, 0x20081026,
937
- 0x20080022, 0x20080026, 0x20081022, 0x20081026,
938
- 0x30080022, 0x30080026, 0x30081022, 0x30081026,
939
- 0x30080022, 0x30080026, 0x30081022, 0x30081026
940
- );
941
- static $pc2mapc4 = array(
942
- 0x00000000, 0x00100000, 0x00000008, 0x00100008,
943
- 0x00000200, 0x00100200, 0x00000208, 0x00100208,
944
- 0x00000000, 0x00100000, 0x00000008, 0x00100008,
945
- 0x00000200, 0x00100200, 0x00000208, 0x00100208,
946
- 0x04000000, 0x04100000, 0x04000008, 0x04100008,
947
- 0x04000200, 0x04100200, 0x04000208, 0x04100208,
948
- 0x04000000, 0x04100000, 0x04000008, 0x04100008,
949
- 0x04000200, 0x04100200, 0x04000208, 0x04100208,
950
- 0x00002000, 0x00102000, 0x00002008, 0x00102008,
951
- 0x00002200, 0x00102200, 0x00002208, 0x00102208,
952
- 0x00002000, 0x00102000, 0x00002008, 0x00102008,
953
- 0x00002200, 0x00102200, 0x00002208, 0x00102208,
954
- 0x04002000, 0x04102000, 0x04002008, 0x04102008,
955
- 0x04002200, 0x04102200, 0x04002208, 0x04102208,
956
- 0x04002000, 0x04102000, 0x04002008, 0x04102008,
957
- 0x04002200, 0x04102200, 0x04002208, 0x04102208,
958
- 0x00000000, 0x00100000, 0x00000008, 0x00100008,
959
- 0x00000200, 0x00100200, 0x00000208, 0x00100208,
960
- 0x00000000, 0x00100000, 0x00000008, 0x00100008,
961
- 0x00000200, 0x00100200, 0x00000208, 0x00100208,
962
- 0x04000000, 0x04100000, 0x04000008, 0x04100008,
963
- 0x04000200, 0x04100200, 0x04000208, 0x04100208,
964
- 0x04000000, 0x04100000, 0x04000008, 0x04100008,
965
- 0x04000200, 0x04100200, 0x04000208, 0x04100208,
966
- 0x00002000, 0x00102000, 0x00002008, 0x00102008,
967
- 0x00002200, 0x00102200, 0x00002208, 0x00102208,
968
- 0x00002000, 0x00102000, 0x00002008, 0x00102008,
969
- 0x00002200, 0x00102200, 0x00002208, 0x00102208,
970
- 0x04002000, 0x04102000, 0x04002008, 0x04102008,
971
- 0x04002200, 0x04102200, 0x04002208, 0x04102208,
972
- 0x04002000, 0x04102000, 0x04002008, 0x04102008,
973
- 0x04002200, 0x04102200, 0x04002208, 0x04102208,
974
- 0x00020000, 0x00120000, 0x00020008, 0x00120008,
975
- 0x00020200, 0x00120200, 0x00020208, 0x00120208,
976
- 0x00020000, 0x00120000, 0x00020008, 0x00120008,
977
- 0x00020200, 0x00120200, 0x00020208, 0x00120208,
978
- 0x04020000, 0x04120000, 0x04020008, 0x04120008,
979
- 0x04020200, 0x04120200, 0x04020208, 0x04120208,
980
- 0x04020000, 0x04120000, 0x04020008, 0x04120008,
981
- 0x04020200, 0x04120200, 0x04020208, 0x04120208,
982
- 0x00022000, 0x00122000, 0x00022008, 0x00122008,
983
- 0x00022200, 0x00122200, 0x00022208, 0x00122208,
984
- 0x00022000, 0x00122000, 0x00022008, 0x00122008,
985
- 0x00022200, 0x00122200, 0x00022208, 0x00122208,
986
- 0x04022000, 0x04122000, 0x04022008, 0x04122008,
987
- 0x04022200, 0x04122200, 0x04022208, 0x04122208,
988
- 0x04022000, 0x04122000, 0x04022008, 0x04122008,
989
- 0x04022200, 0x04122200, 0x04022208, 0x04122208,
990
- 0x00020000, 0x00120000, 0x00020008, 0x00120008,
991
- 0x00020200, 0x00120200, 0x00020208, 0x00120208,
992
- 0x00020000, 0x00120000, 0x00020008, 0x00120008,
993
- 0x00020200, 0x00120200, 0x00020208, 0x00120208,
994
- 0x04020000, 0x04120000, 0x04020008, 0x04120008,
995
- 0x04020200, 0x04120200, 0x04020208, 0x04120208,
996
- 0x04020000, 0x04120000, 0x04020008, 0x04120008,
997
- 0x04020200, 0x04120200, 0x04020208, 0x04120208,
998
- 0x00022000, 0x00122000, 0x00022008, 0x00122008,
999
- 0x00022200, 0x00122200, 0x00022208, 0x00122208,
1000
- 0x00022000, 0x00122000, 0x00022008, 0x00122008,
1001
- 0x00022200, 0x00122200, 0x00022208, 0x00122208,
1002
- 0x04022000, 0x04122000, 0x04022008, 0x04122008,
1003
- 0x04022200, 0x04122200, 0x04022208, 0x04122208,
1004
- 0x04022000, 0x04122000, 0x04022008, 0x04122008,
1005
- 0x04022200, 0x04122200, 0x04022208, 0x04122208
1006
- );
1007
- static $pc2mapd1 = array(
1008
- 0x00000000, 0x00000001, 0x08000000, 0x08000001,
1009
- 0x00200000, 0x00200001, 0x08200000, 0x08200001,
1010
- 0x00000002, 0x00000003, 0x08000002, 0x08000003,
1011
- 0x00200002, 0x00200003, 0x08200002, 0x08200003
1012
- );
1013
- static $pc2mapd2 = array(
1014
- 0x00000000, 0x00100000, 0x00000800, 0x00100800,
1015
- 0x00000000, 0x00100000, 0x00000800, 0x00100800,
1016
- 0x04000000, 0x04100000, 0x04000800, 0x04100800,
1017
- 0x04000000, 0x04100000, 0x04000800, 0x04100800,
1018
- 0x00000004, 0x00100004, 0x00000804, 0x00100804,
1019
- 0x00000004, 0x00100004, 0x00000804, 0x00100804,
1020
- 0x04000004, 0x04100004, 0x04000804, 0x04100804,
1021
- 0x04000004, 0x04100004, 0x04000804, 0x04100804,
1022
- 0x00000000, 0x00100000, 0x00000800, 0x00100800,
1023
- 0x00000000, 0x00100000, 0x00000800, 0x00100800,
1024
- 0x04000000, 0x04100000, 0x04000800, 0x04100800,
1025
- 0x04000000, 0x04100000, 0x04000800, 0x04100800,
1026
- 0x00000004, 0x00100004, 0x00000804, 0x00100804,
1027
- 0x00000004, 0x00100004, 0x00000804, 0x00100804,
1028
- 0x04000004, 0x04100004, 0x04000804, 0x04100804,
1029
- 0x04000004, 0x04100004, 0x04000804, 0x04100804,
1030
- 0x00000200, 0x00100200, 0x00000A00, 0x00100A00,
1031
- 0x00000200, 0x00100200, 0x00000A00, 0x00100A00,
1032
- 0x04000200, 0x04100200, 0x04000A00, 0x04100A00,
1033
- 0x04000200, 0x04100200, 0x04000A00, 0x04100A00,
1034
- 0x00000204, 0x00100204, 0x00000A04, 0x00100A04,
1035
- 0x00000204, 0x00100204, 0x00000A04, 0x00100A04,
1036
- 0x04000204, 0x04100204, 0x04000A04, 0x04100A04,
1037
- 0x04000204, 0x04100204, 0x04000A04, 0x04100A04,
1038
- 0x00000200, 0x00100200, 0x00000A00, 0x00100A00,
1039
- 0x00000200, 0x00100200, 0x00000A00, 0x00100A00,
1040
- 0x04000200, 0x04100200, 0x04000A00, 0x04100A00,
1041
- 0x04000200, 0x04100200, 0x04000A00, 0x04100A00,
1042
- 0x00000204, 0x00100204, 0x00000A04, 0x00100A04,
1043
- 0x00000204, 0x00100204, 0x00000A04, 0x00100A04,
1044
- 0x04000204, 0x04100204, 0x04000A04, 0x04100A04,
1045
- 0x04000204, 0x04100204, 0x04000A04, 0x04100A04,
1046
- 0x00020000, 0x00120000, 0x00020800, 0x00120800,
1047
- 0x00020000, 0x00120000, 0x00020800, 0x00120800,
1048
- 0x04020000, 0x04120000, 0x04020800, 0x04120800,
1049
- 0x04020000, 0x04120000, 0x04020800, 0x04120800,
1050
- 0x00020004, 0x00120004, 0x00020804, 0x00120804,
1051
- 0x00020004, 0x00120004, 0x00020804, 0x00120804,
1052
- 0x04020004, 0x04120004, 0x04020804, 0x04120804,
1053
- 0x04020004, 0x04120004, 0x04020804, 0x04120804,
1054
- 0x00020000, 0x00120000, 0x00020800, 0x00120800,
1055
- 0x00020000, 0x00120000, 0x00020800, 0x00120800,
1056
- 0x04020000, 0x04120000, 0x04020800, 0x04120800,
1057
- 0x04020000, 0x04120000, 0x04020800, 0x04120800,
1058
- 0x00020004, 0x00120004, 0x00020804, 0x00120804,
1059
- 0x00020004, 0x00120004, 0x00020804, 0x00120804,
1060
- 0x04020004, 0x04120004, 0x04020804, 0x04120804,
1061
- 0x04020004, 0x04120004, 0x04020804, 0x04120804,
1062
- 0x00020200, 0x00120200, 0x00020A00, 0x00120A00,
1063
- 0x00020200, 0x00120200, 0x00020A00, 0x00120A00,
1064
- 0x04020200, 0x04120200, 0x04020A00, 0x04120A00,
1065
- 0x04020200, 0x04120200, 0x04020A00, 0x04120A00,
1066
- 0x00020204, 0x00120204, 0x00020A04, 0x00120A04,
1067
- 0x00020204, 0x00120204, 0x00020A04, 0x00120A04,
1068
- 0x04020204, 0x04120204, 0x04020A04, 0x04120A04,
1069
- 0x04020204, 0x04120204, 0x04020A04, 0x04120A04,
1070
- 0x00020200, 0x00120200, 0x00020A00, 0x00120A00,
1071
- 0x00020200, 0x00120200, 0x00020A00, 0x00120A00,
1072
- 0x04020200, 0x04120200, 0x04020A00, 0x04120A00,
1073
- 0x04020200, 0x04120200, 0x04020A00, 0x04120A00,
1074
- 0x00020204, 0x00120204, 0x00020A04, 0x00120A04,
1075
- 0x00020204, 0x00120204, 0x00020A04, 0x00120A04,
1076
- 0x04020204, 0x04120204, 0x04020A04, 0x04120A04,
1077
- 0x04020204, 0x04120204, 0x04020A04, 0x04120A04
1078
- );
1079
- static $pc2mapd3 = array(
1080
- 0x00000000, 0x00010000, 0x02000000, 0x02010000,
1081
- 0x00000020, 0x00010020, 0x02000020, 0x02010020,
1082
- 0x00040000, 0x00050000, 0x02040000, 0x02050000,
1083
- 0x00040020, 0x00050020, 0x02040020, 0x02050020,
1084
- 0x00002000, 0x00012000, 0x02002000, 0x02012000,
1085
- 0x00002020, 0x00012020, 0x02002020, 0x02012020,
1086
- 0x00042000, 0x00052000, 0x02042000, 0x02052000,
1087
- 0x00042020, 0x00052020, 0x02042020, 0x02052020,
1088
- 0x00000000, 0x00010000, 0x02000000, 0x02010000,
1089
- 0x00000020, 0x00010020, 0x02000020, 0x02010020,
1090
- 0x00040000, 0x00050000, 0x02040000, 0x02050000,
1091
- 0x00040020, 0x00050020, 0x02040020, 0x02050020,
1092
- 0x00002000, 0x00012000, 0x02002000, 0x02012000,
1093
- 0x00002020, 0x00012020, 0x02002020, 0x02012020,
1094
- 0x00042000, 0x00052000, 0x02042000, 0x02052000,
1095
- 0x00042020, 0x00052020, 0x02042020, 0x02052020,
1096
- 0x00000010, 0x00010010, 0x02000010, 0x02010010,
1097
- 0x00000030, 0x00010030, 0x02000030, 0x02010030,
1098
- 0x00040010, 0x00050010, 0x02040010, 0x02050010,
1099
- 0x00040030, 0x00050030, 0x02040030, 0x02050030,
1100
- 0x00002010, 0x00012010, 0x02002010, 0x02012010,
1101
- 0x00002030, 0x00012030, 0x02002030, 0x02012030,
1102
- 0x00042010, 0x00052010, 0x02042010, 0x02052010,
1103
- 0x00042030, 0x00052030, 0x02042030, 0x02052030,
1104
- 0x00000010, 0x00010010, 0x02000010, 0x02010010,
1105
- 0x00000030, 0x00010030, 0x02000030, 0x02010030,
1106
- 0x00040010, 0x00050010, 0x02040010, 0x02050010,
1107
- 0x00040030, 0x00050030, 0x02040030, 0x02050030,
1108
- 0x00002010, 0x00012010, 0x02002010, 0x02012010,
1109
- 0x00002030, 0x00012030, 0x02002030, 0x02012030,
1110
- 0x00042010, 0x00052010, 0x02042010, 0x02052010,
1111
- 0x00042030, 0x00052030, 0x02042030, 0x02052030,
1112
- 0x20000000, 0x20010000, 0x22000000, 0x22010000,
1113
- 0x20000020, 0x20010020, 0x22000020, 0x22010020,
1114
- 0x20040000, 0x20050000, 0x22040000, 0x22050000,
1115
- 0x20040020, 0x20050020, 0x22040020, 0x22050020,
1116
- 0x20002000, 0x20012000, 0x22002000, 0x22012000,
1117
- 0x20002020, 0x20012020, 0x22002020, 0x22012020,
1118
- 0x20042000, 0x20052000, 0x22042000, 0x22052000,
1119
- 0x20042020, 0x20052020, 0x22042020, 0x22052020,
1120
- 0x20000000, 0x20010000, 0x22000000, 0x22010000,
1121
- 0x20000020, 0x20010020, 0x22000020, 0x22010020,
1122
- 0x20040000, 0x20050000, 0x22040000, 0x22050000,
1123
- 0x20040020, 0x20050020, 0x22040020, 0x22050020,
1124
- 0x20002000, 0x20012000, 0x22002000, 0x22012000,
1125
- 0x20002020, 0x20012020, 0x22002020, 0x22012020,
1126
- 0x20042000, 0x20052000, 0x22042000, 0x22052000,
1127
- 0x20042020, 0x20052020, 0x22042020, 0x22052020,
1128
- 0x20000010, 0x20010010, 0x22000010, 0x22010010,
1129
- 0x20000030, 0x20010030, 0x22000030, 0x22010030,
1130
- 0x20040010, 0x20050010, 0x22040010, 0x22050010,
1131
- 0x20040030, 0x20050030, 0x22040030, 0x22050030,
1132
- 0x20002010, 0x20012010, 0x22002010, 0x22012010,
1133
- 0x20002030, 0x20012030, 0x22002030, 0x22012030,
1134
- 0x20042010, 0x20052010, 0x22042010, 0x22052010,
1135
- 0x20042030, 0x20052030, 0x22042030, 0x22052030,
1136
- 0x20000010, 0x20010010, 0x22000010, 0x22010010,
1137
- 0x20000030, 0x20010030, 0x22000030, 0x22010030,
1138
- 0x20040010, 0x20050010, 0x22040010, 0x22050010,
1139
- 0x20040030, 0x20050030, 0x22040030, 0x22050030,
1140
- 0x20002010, 0x20012010, 0x22002010, 0x22012010,
1141
- 0x20002030, 0x20012030, 0x22002030, 0x22012030,
1142
- 0x20042010, 0x20052010, 0x22042010, 0x22052010,
1143
- 0x20042030, 0x20052030, 0x22042030, 0x22052030
1144
- );
1145
- static $pc2mapd4 = array(
1146
- 0x00000000, 0x00000400, 0x01000000, 0x01000400,
1147
- 0x00000000, 0x00000400, 0x01000000, 0x01000400,
1148
- 0x00000100, 0x00000500, 0x01000100, 0x01000500,
1149
- 0x00000100, 0x00000500, 0x01000100, 0x01000500,
1150
- 0x10000000, 0x10000400, 0x11000000, 0x11000400,
1151
- 0x10000000, 0x10000400, 0x11000000, 0x11000400,
1152
- 0x10000100, 0x10000500, 0x11000100, 0x11000500,
1153
- 0x10000100, 0x10000500, 0x11000100, 0x11000500,
1154
- 0x00080000, 0x00080400, 0x01080000, 0x01080400,
1155
- 0x00080000, 0x00080400, 0x01080000, 0x01080400,
1156
- 0x00080100, 0x00080500, 0x01080100, 0x01080500,
1157
- 0x00080100, 0x00080500, 0x01080100, 0x01080500,
1158
- 0x10080000, 0x10080400, 0x11080000, 0x11080400,
1159
- 0x10080000, 0x10080400, 0x11080000, 0x11080400,
1160
- 0x10080100, 0x10080500, 0x11080100, 0x11080500,
1161
- 0x10080100, 0x10080500, 0x11080100, 0x11080500,
1162
- 0x00000008, 0x00000408, 0x01000008, 0x01000408,
1163
- 0x00000008, 0x00000408, 0x01000008, 0x01000408,
1164
- 0x00000108, 0x00000508, 0x01000108, 0x01000508,
1165
- 0x00000108, 0x00000508, 0x01000108, 0x01000508,
1166
- 0x10000008, 0x10000408, 0x11000008, 0x11000408,
1167
- 0x10000008, 0x10000408, 0x11000008, 0x11000408,
1168
- 0x10000108, 0x10000508, 0x11000108, 0x11000508,
1169
- 0x10000108, 0x10000508, 0x11000108, 0x11000508,
1170
- 0x00080008, 0x00080408, 0x01080008, 0x01080408,
1171
- 0x00080008, 0x00080408, 0x01080008, 0x01080408,
1172
- 0x00080108, 0x00080508, 0x01080108, 0x01080508,
1173
- 0x00080108, 0x00080508, 0x01080108, 0x01080508,
1174
- 0x10080008, 0x10080408, 0x11080008, 0x11080408,
1175
- 0x10080008, 0x10080408, 0x11080008, 0x11080408,
1176
- 0x10080108, 0x10080508, 0x11080108, 0x11080508,
1177
- 0x10080108, 0x10080508, 0x11080108, 0x11080508,
1178
- 0x00001000, 0x00001400, 0x01001000, 0x01001400,
1179
- 0x00001000, 0x00001400, 0x01001000, 0x01001400,
1180
- 0x00001100, 0x00001500, 0x01001100, 0x01001500,
1181
- 0x00001100, 0x00001500, 0x01001100, 0x01001500,
1182
- 0x10001000, 0x10001400, 0x11001000, 0x11001400,
1183
- 0x10001000, 0x10001400, 0x11001000, 0x11001400,
1184
- 0x10001100, 0x10001500, 0x11001100, 0x11001500,
1185
- 0x10001100, 0x10001500, 0x11001100, 0x11001500,
1186
- 0x00081000, 0x00081400, 0x01081000, 0x01081400,
1187
- 0x00081000, 0x00081400, 0x01081000, 0x01081400,
1188
- 0x00081100, 0x00081500, 0x01081100, 0x01081500,
1189
- 0x00081100, 0x00081500, 0x01081100, 0x01081500,
1190
- 0x10081000, 0x10081400, 0x11081000, 0x11081400,
1191
- 0x10081000, 0x10081400, 0x11081000, 0x11081400,
1192
- 0x10081100, 0x10081500, 0x11081100, 0x11081500,
1193
- 0x10081100, 0x10081500, 0x11081100, 0x11081500,
1194
- 0x00001008, 0x00001408, 0x01001008, 0x01001408,
1195
- 0x00001008, 0x00001408, 0x01001008, 0x01001408,
1196
- 0x00001108, 0x00001508, 0x01001108, 0x01001508,
1197
- 0x00001108, 0x00001508, 0x01001108, 0x01001508,
1198
- 0x10001008, 0x10001408, 0x11001008, 0x11001408,
1199
- 0x10001008, 0x10001408, 0x11001008, 0x11001408,
1200
- 0x10001108, 0x10001508, 0x11001108, 0x11001508,
1201
- 0x10001108, 0x10001508, 0x11001108, 0x11001508,
1202
- 0x00081008, 0x00081408, 0x01081008, 0x01081408,
1203
- 0x00081008, 0x00081408, 0x01081008, 0x01081408,
1204
- 0x00081108, 0x00081508, 0x01081108, 0x01081508,
1205
- 0x00081108, 0x00081508, 0x01081108, 0x01081508,
1206
- 0x10081008, 0x10081408, 0x11081008, 0x11081408,
1207
- 0x10081008, 0x10081408, 0x11081008, 0x11081408,
1208
- 0x10081108, 0x10081508, 0x11081108, 0x11081508,
1209
- 0x10081108, 0x10081508, 0x11081108, 0x11081508
1210
- );
1211
-
1212
- $keys = array();
1213
- for ($des_round = 0; $des_round < $this->des_rounds; ++$des_round) {
1214
- // pad the key and remove extra characters as appropriate.
1215
- $key = str_pad(substr($this->key, $des_round * 8, 8), 8, "\0");
1216
-
1217
- // Perform the PC/1 transformation and compute C and D.
1218
- $t = unpack('Nl/Nr', $key);
1219
- list($l, $r) = array($t['l'], $t['r']);
1220
- $key = ($this->shuffle[$pc1map[ $r & 0xFF]] & "\x80\x80\x80\x80\x80\x80\x80\x00") |
1221
- ($this->shuffle[$pc1map[($r >> 8) & 0xFF]] & "\x40\x40\x40\x40\x40\x40\x40\x00") |
1222
- ($this->shuffle[$pc1map[($r >> 16) & 0xFF]] & "\x20\x20\x20\x20\x20\x20\x20\x00") |
1223
- ($this->shuffle[$pc1map[($r >> 24) & 0xFF]] & "\x10\x10\x10\x10\x10\x10\x10\x00") |
1224
- ($this->shuffle[$pc1map[ $l & 0xFF]] & "\x08\x08\x08\x08\x08\x08\x08\x00") |
1225
- ($this->shuffle[$pc1map[($l >> 8) & 0xFF]] & "\x04\x04\x04\x04\x04\x04\x04\x00") |
1226
- ($this->shuffle[$pc1map[($l >> 16) & 0xFF]] & "\x02\x02\x02\x02\x02\x02\x02\x00") |
1227
- ($this->shuffle[$pc1map[($l >> 24) & 0xFF]] & "\x01\x01\x01\x01\x01\x01\x01\x00");
1228
- $key = unpack('Nc/Nd', $key);
1229
- $c = ( $key['c'] >> 4) & 0x0FFFFFFF;
1230
- $d = (($key['d'] >> 4) & 0x0FFFFFF0) | ($key['c'] & 0x0F);
1231
-
1232
- $keys[$des_round] = array(
1233
- self::ENCRYPT => array(),
1234
- self::DECRYPT => array_fill(0, 32, 0)
1235
- );
1236
- for ($i = 0, $ki = 31; $i < 16; ++$i, $ki-= 2) {
1237
- $c <<= $shifts[$i];
1238
- $c = ($c | ($c >> 28)) & 0x0FFFFFFF;
1239
- $d <<= $shifts[$i];
1240
- $d = ($d | ($d >> 28)) & 0x0FFFFFFF;
1241
-
1242
- // Perform the PC-2 transformation.
1243
- $cp = $pc2mapc1[ $c >> 24 ] | $pc2mapc2[($c >> 16) & 0xFF] |
1244
- $pc2mapc3[($c >> 8) & 0xFF] | $pc2mapc4[ $c & 0xFF];
1245
- $dp = $pc2mapd1[ $d >> 24 ] | $pc2mapd2[($d >> 16) & 0xFF] |
1246
- $pc2mapd3[($d >> 8) & 0xFF] | $pc2mapd4[ $d & 0xFF];
1247
-
1248
- // Reorder: odd bytes/even bytes. Push the result in key schedule.
1249
- $val1 = ( $cp & 0xFF000000) | (($cp << 8) & 0x00FF0000) |
1250
- (($dp >> 16) & 0x0000FF00) | (($dp >> 8) & 0x000000FF);
1251
- $val2 = (($cp << 8) & 0xFF000000) | (($cp << 16) & 0x00FF0000) |
1252
- (($dp >> 8) & 0x0000FF00) | ( $dp & 0x000000FF);
1253
- $keys[$des_round][self::ENCRYPT][ ] = $val1;
1254
- $keys[$des_round][self::DECRYPT][$ki - 1] = $val1;
1255
- $keys[$des_round][self::ENCRYPT][ ] = $val2;
1256
- $keys[$des_round][self::DECRYPT][$ki ] = $val2;
1257
- }
1258
- }
1259
-
1260
- switch ($this->des_rounds) {
1261
- case 3: // 3DES keys
1262
- $this->keys = array(
1263
- self::ENCRYPT => array_merge(
1264
- $keys[0][self::ENCRYPT],
1265
- $keys[1][self::DECRYPT],
1266
- $keys[2][self::ENCRYPT]
1267
- ),
1268
- self::DECRYPT => array_merge(
1269
- $keys[2][self::DECRYPT],
1270
- $keys[1][self::ENCRYPT],
1271
- $keys[0][self::DECRYPT]
1272
- )
1273
- );
1274
- break;
1275
- // case 1: // DES keys
1276
- default:
1277
- $this->keys = array(
1278
- self::ENCRYPT => $keys[0][self::ENCRYPT],
1279
- self::DECRYPT => $keys[0][self::DECRYPT]
1280
- );
1281
- }
1282
- }
1283
-
1284
- /**
1285
- * Setup the performance-optimized function for de/encrypt()
1286
- *
1287
- * @see \phpseclib\Crypt\Base::_setupInlineCrypt()
1288
- * @access private
1289
- */
1290
- function _setupInlineCrypt()
1291
- {
1292
- $lambda_functions =& self::_getLambdaFunctions();
1293
-
1294
- // Engine configuration for:
1295
- // - DES ($des_rounds == 1) or
1296
- // - 3DES ($des_rounds == 3)
1297
- $des_rounds = $this->des_rounds;
1298
-
1299
- // We create max. 10 hi-optimized code for memory reason. Means: For each $key one ultra fast inline-crypt function.
1300
- // (Currently, for DES, one generated $lambda_function cost on php5.5@32bit ~135kb unfreeable mem and ~230kb on php5.5@64bit)
1301
- // (Currently, for TripleDES, one generated $lambda_function cost on php5.5@32bit ~240kb unfreeable mem and ~340kb on php5.5@64bit)
1302
- // After that, we'll still create very fast optimized code but not the hi-ultimative code, for each $mode one
1303
- $gen_hi_opt_code = (bool)( count($lambda_functions) < 10 );
1304
-
1305
- // Generation of a unique hash for our generated code
1306
- $code_hash = "Crypt_DES, $des_rounds, {$this->mode}";
1307
- if ($gen_hi_opt_code) {
1308
- // For hi-optimized code, we create for each combination of
1309
- // $mode, $des_rounds and $this->key its own encrypt/decrypt function.
1310
- // After max 10 hi-optimized functions, we create generic
1311
- // (still very fast.. but not ultra) functions for each $mode/$des_rounds
1312
- // Currently 2 * 5 generic functions will be then max. possible.
1313
- $code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key);
1314
- }
1315
-
1316
- // Is there a re-usable $lambda_functions in there? If not, we have to create it.
1317
- if (!isset($lambda_functions[$code_hash])) {
1318
- // Init code for both, encrypt and decrypt.
1319
- $init_crypt = 'static $sbox1, $sbox2, $sbox3, $sbox4, $sbox5, $sbox6, $sbox7, $sbox8, $shuffleip, $shuffleinvip;
1320
- if (!$sbox1) {
1321
- $sbox1 = array_map("intval", $self->sbox1);
1322
- $sbox2 = array_map("intval", $self->sbox2);
1323
- $sbox3 = array_map("intval", $self->sbox3);
1324
- $sbox4 = array_map("intval", $self->sbox4);
1325
- $sbox5 = array_map("intval", $self->sbox5);
1326
- $sbox6 = array_map("intval", $self->sbox6);
1327
- $sbox7 = array_map("intval", $self->sbox7);
1328
- $sbox8 = array_map("intval", $self->sbox8);'
1329
- /* Merge $shuffle with $[inv]ipmap */ . '
1330
- for ($i = 0; $i < 256; ++$i) {
1331
- $shuffleip[] = $self->shuffle[$self->ipmap[$i]];
1332
- $shuffleinvip[] = $self->shuffle[$self->invipmap[$i]];
1333
- }
1334
- }
1335
- ';
1336
-
1337
- switch (true) {
1338
- case $gen_hi_opt_code:
1339
- // In Hi-optimized code mode, we use our [3]DES key schedule as hardcoded integers.
1340
- // No futher initialisation of the $keys schedule is necessary.
1341
- // That is the extra performance boost.
1342
- $k = array(
1343
- self::ENCRYPT => $this->keys[self::ENCRYPT],
1344
- self::DECRYPT => $this->keys[self::DECRYPT]
1345
- );
1346
- $init_encrypt = '';
1347
- $init_decrypt = '';
1348
- break;
1349
- default:
1350
- // In generic optimized code mode, we have to use, as the best compromise [currently],
1351
- // our key schedule as $ke/$kd arrays. (with hardcoded indexes...)
1352
- $k = array(
1353
- self::ENCRYPT => array(),
1354
- self::DECRYPT => array()
1355
- );
1356
- for ($i = 0, $c = count($this->keys[self::ENCRYPT]); $i < $c; ++$i) {
1357
- $k[self::ENCRYPT][$i] = '$ke[' . $i . ']';
1358
- $k[self::DECRYPT][$i] = '$kd[' . $i . ']';
1359
- }
1360
- $init_encrypt = '$ke = $self->keys[$self::ENCRYPT];';
1361
- $init_decrypt = '$kd = $self->keys[$self::DECRYPT];';
1362
- break;
1363
- }
1364
-
1365
- // Creating code for en- and decryption.
1366
- $crypt_block = array();
1367
- foreach (array(self::ENCRYPT, self::DECRYPT) as $c) {
1368
- /* Do the initial IP permutation. */
1369
- $crypt_block[$c] = '
1370
- $in = unpack("N*", $in);
1371
- $l = $in[1];
1372
- $r = $in[2];
1373
- $in = unpack("N*",
1374
- ($shuffleip[ $r & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") |
1375
- ($shuffleip[($r >> 8) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") |
1376
- ($shuffleip[($r >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") |
1377
- ($shuffleip[($r >> 24) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") |
1378
- ($shuffleip[ $l & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") |
1379
- ($shuffleip[($l >> 8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") |
1380
- ($shuffleip[($l >> 16) & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") |
1381
- ($shuffleip[($l >> 24) & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01")
1382
- );
1383
- ' . /* Extract L0 and R0 */ '
1384
- $l = $in[1];
1385
- $r = $in[2];
1386
- ';
1387
-
1388
- $l = '$l';
1389
- $r = '$r';
1390
-
1391
- // Perform DES or 3DES.
1392
- for ($ki = -1, $des_round = 0; $des_round < $des_rounds; ++$des_round) {
1393
- // Perform the 16 steps.
1394
- for ($i = 0; $i < 16; ++$i) {
1395
- // start of "the Feistel (F) function" - see the following URL:
1396
- // http://en.wikipedia.org/wiki/Image:Data_Encryption_Standard_InfoBox_Diagram.png
1397
- // Merge key schedule.
1398
- $crypt_block[$c].= '
1399
- $b1 = ((' . $r . ' >> 3) & 0x1FFFFFFF) ^ (' . $r . ' << 29) ^ ' . $k[$c][++$ki] . ';
1400
- $b2 = ((' . $r . ' >> 31) & 0x00000001) ^ (' . $r . ' << 1) ^ ' . $k[$c][++$ki] . ';' .
1401
- /* S-box indexing. */
1402
- $l . ' = $sbox1[($b1 >> 24) & 0x3F] ^ $sbox2[($b2 >> 24) & 0x3F] ^
1403
- $sbox3[($b1 >> 16) & 0x3F] ^ $sbox4[($b2 >> 16) & 0x3F] ^
1404
- $sbox5[($b1 >> 8) & 0x3F] ^ $sbox6[($b2 >> 8) & 0x3F] ^
1405
- $sbox7[ $b1 & 0x3F] ^ $sbox8[ $b2 & 0x3F] ^ ' . $l . ';
1406
- ';
1407
- // end of "the Feistel (F) function"
1408
-
1409
- // swap L & R
1410
- list($l, $r) = array($r, $l);
1411
- }
1412
- list($l, $r) = array($r, $l);
1413
- }
1414
-
1415
- // Perform the inverse IP permutation.
1416
- $crypt_block[$c].= '$in =
1417
- ($shuffleinvip[($l >> 24) & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") |
1418
- ($shuffleinvip[($r >> 24) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") |
1419
- ($shuffleinvip[($l >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") |
1420
- ($shuffleinvip[($r >> 16) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") |
1421
- ($shuffleinvip[($l >> 8) & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") |
1422
- ($shuffleinvip[($r >> 8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") |
1423
- ($shuffleinvip[ $l & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") |
1424
- ($shuffleinvip[ $r & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01");
1425
- ';
1426
- }
1427
-
1428
- // Creates the inline-crypt function
1429
- $lambda_functions[$code_hash] = $this->_createInlineCryptFunction(
1430
- array(
1431
- 'init_crypt' => $init_crypt,
1432
- 'init_encrypt' => $init_encrypt,
1433
- 'init_decrypt' => $init_decrypt,
1434
- 'encrypt_block' => $crypt_block[self::ENCRYPT],
1435
- 'decrypt_block' => $crypt_block[self::DECRYPT]
1436
- )
1437
- );
1438
- }
1439
-
1440
- // Set the inline-crypt function as callback in: $this->inline_crypt
1441
- $this->inline_crypt = $lambda_functions[$code_hash];
1442
- }
1443
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/phpseclib/phpseclib/phpseclib/Crypt/Hash.php DELETED
@@ -1,824 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Pure-PHP implementations of keyed-hash message authentication codes (HMACs) and various cryptographic hashing functions.
5
- *
6
- * Uses hash() or mhash() if available and an internal implementation, otherwise. Currently supports the following:
7
- *
8
- * md2, md5, md5-96, sha1, sha1-96, sha256, sha256-96, sha384, and sha512, sha512-96
9
- *
10
- * If {@link self::setKey() setKey()} is called, {@link self::hash() hash()} will return the HMAC as opposed to
11
- * the hash. If no valid algorithm is provided, sha1 will be used.
12
- *
13
- * PHP version 5
14
- *
15
- * {@internal The variable names are the same as those in
16
- * {@link http://tools.ietf.org/html/rfc2104#section-2 RFC2104}.}}
17
- *
18
- * Here's a short example of how to use this library:
19
- * <code>
20
- * <?php
21
- * include 'vendor/autoload.php';
22
- *
23
- * $hash = new \phpseclib\Crypt\Hash('sha1');
24
- *
25
- * $hash->setKey('abcdefg');
26
- *
27
- * echo base64_encode($hash->hash('abcdefg'));
28
- * ?>
29
- * </code>
30
- *
31
- * @category Crypt
32
- * @package Hash
33
- * @author Jim Wigginton <terrafrost@php.net>
34
- * @copyright 2007 Jim Wigginton
35
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
36
- * @link http://phpseclib.sourceforge.net
37
- */
38
-
39
- namespace phpseclib\Crypt;
40
-
41
- use phpseclib\Math\BigInteger;
42
-
43
- /**
44
- * Pure-PHP implementations of keyed-hash message authentication codes (HMACs) and various cryptographic hashing functions.
45
- *
46
- * @package Hash
47
- * @author Jim Wigginton <terrafrost@php.net>
48
- * @access public
49
- */
50
- class Hash
51
- {
52
- /**#@+
53
- * @access private
54
- * @see \phpseclib\Crypt\Hash::__construct()
55
- */
56
- /**
57
- * Toggles the internal implementation
58
- */
59
- const MODE_INTERNAL = 1;
60
- /**
61
- * Toggles the mhash() implementation, which has been deprecated on PHP 5.3.0+.
62
- */
63
- const MODE_MHASH = 2;
64
- /**
65
- * Toggles the hash() implementation, which works on PHP 5.1.2+.
66
- */
67
- const MODE_HASH = 3;
68
- /**#@-*/
69
-
70
- /**
71
- * Hash Parameter
72
- *
73
- * @see self::setHash()
74
- * @var int
75
- * @access private
76
- */
77
- var $hashParam;
78
-
79
- /**
80
- * Byte-length of compression blocks / key (Internal HMAC)
81
- *
82
- * @see self::setAlgorithm()
83
- * @var int
84
- * @access private
85
- */
86
- var $b;
87
-
88
- /**
89
- * Byte-length of hash output (Internal HMAC)
90
- *
91
- * @see self::setHash()
92
- * @var int
93
- * @access private
94
- */
95
- var $l = false;
96
-
97
- /**
98
- * Hash Algorithm
99
- *
100
- * @see self::setHash()
101
- * @var string
102
- * @access private
103
- */
104
- var $hash;
105
-
106
- /**
107
- * Key
108
- *
109
- * @see self::setKey()
110
- * @var string
111
- * @access private
112
- */
113
- var $key = false;
114
-
115
- /**
116
- * Outer XOR (Internal HMAC)
117
- *
118
- * @see self::setKey()
119
- * @var string
120
- * @access private
121
- */
122
- var $opad;
123
-
124
- /**
125
- * Inner XOR (Internal HMAC)
126
- *
127
- * @see self::setKey()
128
- * @var string
129
- * @access private
130
- */
131
- var $ipad;
132
-
133
- /**
134
- * Default Constructor.
135
- *
136
- * @param string $hash
137
- * @return \phpseclib\Crypt\Hash
138
- * @access public
139
- */
140
- function __construct($hash = 'sha1')
141
- {
142
- if (!defined('CRYPT_HASH_MODE')) {
143
- switch (true) {
144
- case extension_loaded('hash'):
145
- define('CRYPT_HASH_MODE', self::MODE_HASH);
146
- break;
147
- case extension_loaded('mhash'):
148
- define('CRYPT_HASH_MODE', self::MODE_MHASH);
149
- break;
150
- default:
151
- define('CRYPT_HASH_MODE', self::MODE_INTERNAL);
152
- }
153
- }
154
-
155
- $this->setHash($hash);
156
- }
157
-
158
- /**
159
- * Sets the key for HMACs
160
- *
161
- * Keys can be of any length.
162
- *
163
- * @access public
164
- * @param string $key
165
- */
166
- function setKey($key = false)
167
- {
168
- $this->key = $key;
169
- }
170
-
171
- /**
172
- * Gets the hash function.
173
- *
174
- * As set by the constructor or by the setHash() method.
175
- *
176
- * @access public
177
- * @return string
178
- */
179
- function getHash()
180
- {
181
- return $this->hashParam;
182
- }
183
-
184
- /**
185
- * Sets the hash function.
186
- *
187
- * @access public
188
- * @param string $hash
189
- */
190
- function setHash($hash)
191
- {
192
- $this->hashParam = $hash = strtolower($hash);
193
- switch ($hash) {
194
- case 'md5-96':
195
- case 'sha1-96':
196
- case 'sha256-96':
197
- case 'sha512-96':
198
- $hash = substr($hash, 0, -3);
199
- $this->l = 12; // 96 / 8 = 12
200
- break;
201
- case 'md2':
202
- case 'md5':
203
- $this->l = 16;
204
- break;
205
- case 'sha1':
206
- $this->l = 20;
207
- break;
208
- case 'sha256':
209
- $this->l = 32;
210
- break;
211
- case 'sha384':
212
- $this->l = 48;
213
- break;
214
- case 'sha512':
215
- $this->l = 64;
216
- }
217
-
218
- switch ($hash) {
219
- case 'md2':
220
- $mode = CRYPT_HASH_MODE == self::MODE_HASH && in_array('md2', hash_algos()) ?
221
- self::MODE_HASH : self::MODE_INTERNAL;
222
- break;
223
- case 'sha384':
224
- case 'sha512':
225
- $mode = CRYPT_HASH_MODE == self::MODE_MHASH ? self::MODE_INTERNAL : CRYPT_HASH_MODE;
226
- break;
227
- default:
228
- $mode = CRYPT_HASH_MODE;
229
- }
230
-
231
- switch ($mode) {
232
- case self::MODE_MHASH:
233
- switch ($hash) {
234
- case 'md5':
235
- $this->hash = MHASH_MD5;
236
- break;
237
- case 'sha256':
238
- $this->hash = MHASH_SHA256;
239
- break;
240
- case 'sha1':
241
- default:
242
- $this->hash = MHASH_SHA1;
243
- }
244
- return;
245
- case self::MODE_HASH:
246
- switch ($hash) {
247
- case 'md5':
248
- $this->hash = 'md5';
249
- return;
250
- case 'md2':
251
- case 'sha256':
252
- case 'sha384':
253
- case 'sha512':
254
- $this->hash = $hash;
255
- return;
256
- case 'sha1':
257
- default:
258
- $this->hash = 'sha1';
259
- }
260
- return;
261
- }
262
-
263
- switch ($hash) {
264
- case 'md2':
265
- $this->b = 16;
266
- $this->hash = array($this, '_md2');
267
- break;
268
- case 'md5':
269
- $this->b = 64;
270
- $this->hash = array($this, '_md5');
271
- break;
272
- case 'sha256':
273
- $this->b = 64;
274
- $this->hash = array($this, '_sha256');
275
- break;
276
- case 'sha384':
277
- case 'sha512':
278
- $this->b = 128;
279
- $this->hash = array($this, '_sha512');
280
- break;
281
- case 'sha1':
282
- default:
283
- $this->b = 64;
284
- $this->hash = array($this, '_sha1');
285
- }
286
-
287
- $this->ipad = str_repeat(chr(0x36), $this->b);
288
- $this->opad = str_repeat(chr(0x5C), $this->b);
289
- }
290
-
291
- /**
292
- * Compute the HMAC.
293
- *
294
- * @access public
295
- * @param string $text
296
- * @return string
297
- */
298
- function hash($text)
299
- {
300
- $mode = is_array($this->hash) ? self::MODE_INTERNAL : CRYPT_HASH_MODE;
301
-
302
- if (!empty($this->key) || is_string($this->key)) {
303
- switch ($mode) {
304
- case self::MODE_MHASH:
305
- $output = mhash($this->hash, $text, $this->key);
306
- break;
307
- case self::MODE_HASH:
308
- $output = hash_hmac($this->hash, $text, $this->key, true);
309
- break;
310
- case self::MODE_INTERNAL:
311
- /* "Applications that use keys longer than B bytes will first hash the key using H and then use the
312
- resultant L byte string as the actual key to HMAC."
313
-
314
- -- http://tools.ietf.org/html/rfc2104#section-2 */
315
- $key = strlen($this->key) > $this->b ? call_user_func($this->hash, $this->key) : $this->key;
316
-
317
- $key = str_pad($key, $this->b, chr(0)); // step 1
318
- $temp = $this->ipad ^ $key; // step 2
319
- $temp .= $text; // step 3
320
- $temp = call_user_func($this->hash, $temp); // step 4
321
- $output = $this->opad ^ $key; // step 5
322
- $output.= $temp; // step 6
323
- $output = call_user_func($this->hash, $output); // step 7
324
- }
325
- } else {
326
- switch ($mode) {
327
- case self::MODE_MHASH:
328
- $output = mhash($this->hash, $text);
329
- break;
330
- case self::MODE_HASH:
331
- $output = hash($this->hash, $text, true);
332
- break;
333
- case self::MODE_INTERNAL:
334
- $output = call_user_func($this->hash, $text);
335
- }
336
- }
337
-
338
- return substr($output, 0, $this->l);
339
- }
340
-
341
- /**
342
- * Returns the hash length (in bytes)
343
- *
344
- * @access public
345
- * @return int
346
- */
347
- function getLength()
348
- {
349
- return $this->l;
350
- }
351
-
352
- /**
353
- * Wrapper for MD5
354
- *
355
- * @access private
356
- * @param string $m
357
- */
358
- function _md5($m)
359
- {
360
- return pack('H*', md5($m));
361
- }
362
-
363
- /**
364
- * Wrapper for SHA1
365
- *
366
- * @access private
367
- * @param string $m
368
- */
369
- function _sha1($m)
370
- {
371
- return pack('H*', sha1($m));
372
- }
373
-
374
- /**
375
- * Pure-PHP implementation of MD2
376
- *
377
- * See {@link http://tools.ietf.org/html/rfc1319 RFC1319}.
378
- *
379
- * @access private
380
- * @param string $m
381
- */
382
- function _md2($m)
383
- {
384
- static $s = array(
385
- 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6,
386
- 19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188,
387
- 76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24,
388
- 138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251,
389
- 245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63,
390
- 148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50,
391
- 39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165,
392
- 181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210,
393
- 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157,
394
- 112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27,
395
- 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15,
396
- 85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197,
397
- 234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65,
398
- 129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123,
399
- 8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233,
400
- 203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228,
401
- 166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237,
402
- 31, 26, 219, 153, 141, 51, 159, 17, 131, 20
403
- );
404
-
405
- // Step 1. Append Padding Bytes
406
- $pad = 16 - (strlen($m) & 0xF);
407
- $m.= str_repeat(chr($pad), $pad);
408
-
409
- $length = strlen($m);
410
-
411
- // Step 2. Append Checksum
412
- $c = str_repeat(chr(0), 16);
413
- $l = chr(0);
414
- for ($i = 0; $i < $length; $i+= 16) {
415
- for ($j = 0; $j < 16; $j++) {
416
- // RFC1319 incorrectly states that C[j] should be set to S[c xor L]
417
- //$c[$j] = chr($s[ord($m[$i + $j] ^ $l)]);
418
- // per <http://www.rfc-editor.org/errata_search.php?rfc=1319>, however, C[j] should be set to S[c xor L] xor C[j]
419
- $c[$j] = chr($s[ord($m[$i + $j] ^ $l)] ^ ord($c[$j]));
420
- $l = $c[$j];
421
- }
422
- }
423
- $m.= $c;
424
-
425
- $length+= 16;
426
-
427
- // Step 3. Initialize MD Buffer
428
- $x = str_repeat(chr(0), 48);
429
-
430
- // Step 4. Process Message in 16-Byte Blocks
431
- for ($i = 0; $i < $length; $i+= 16) {
432
- for ($j = 0; $j < 16; $j++) {
433
- $x[$j + 16] = $m[$i + $j];
434
- $x[$j + 32] = $x[$j + 16] ^ $x[$j];
435
- }
436
- $t = chr(0);
437
- for ($j = 0; $j < 18; $j++) {
438
- for ($k = 0; $k < 48; $k++) {
439
- $x[$k] = $t = $x[$k] ^ chr($s[ord($t)]);
440
- //$t = $x[$k] = $x[$k] ^ chr($s[ord($t)]);
441
- }
442
- $t = chr(ord($t) + $j);
443
- }
444
- }
445
-
446
- // Step 5. Output
447
- return substr($x, 0, 16);
448
- }
449
-
450
- /**
451
- * Pure-PHP implementation of SHA256
452
- *
453
- * See {@link http://en.wikipedia.org/wiki/SHA_hash_functions#SHA-256_.28a_SHA-2_variant.29_pseudocode SHA-256 (a SHA-2 variant) pseudocode - Wikipedia}.
454
- *
455
- * @access private
456
- * @param string $m
457
- */
458
- function _sha256($m)
459
- {
460
- if (extension_loaded('suhosin')) {
461
- return pack('H*', sha256($m));
462
- }
463
-
464
- // Initialize variables
465
- $hash = array(
466
- 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
467
- );
468
- // Initialize table of round constants
469
- // (first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311)
470
- static $k = array(
471
- 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
472
- 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
473
- 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
474
- 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
475
- 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
476
- 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
477
- 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
478
- 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
479
- );
480
-
481
- // Pre-processing
482
- $length = strlen($m);
483
- // to round to nearest 56 mod 64, we'll add 64 - (length + (64 - 56)) % 64
484
- $m.= str_repeat(chr(0), 64 - (($length + 8) & 0x3F));
485
- $m[$length] = chr(0x80);
486
- // we don't support hashing strings 512MB long
487
- $m.= pack('N2', 0, $length << 3);
488
-
489
- // Process the message in successive 512-bit chunks
490
- $chunks = str_split($m, 64);
491
- foreach ($chunks as $chunk) {
492
- $w = array();
493
- for ($i = 0; $i < 16; $i++) {
494
- extract(unpack('Ntemp', $this->_string_shift($chunk, 4)));
495
- $w[] = $temp;
496
- }
497
-
498
- // Extend the sixteen 32-bit words into sixty-four 32-bit words
499
- for ($i = 16; $i < 64; $i++) {
500
- // @codingStandardsIgnoreStart
501
- $s0 = $this->_rightRotate($w[$i - 15], 7) ^
502
- $this->_rightRotate($w[$i - 15], 18) ^
503
- $this->_rightShift( $w[$i - 15], 3);
504
- $s1 = $this->_rightRotate($w[$i - 2], 17) ^
505
- $this->_rightRotate($w[$i - 2], 19) ^
506
- $this->_rightShift( $w[$i - 2], 10);
507
- // @codingStandardsIgnoreEnd
508
- $w[$i] = $this->_add($w[$i - 16], $s0, $w[$i - 7], $s1);
509
- }
510
-
511
- // Initialize hash value for this chunk
512
- list($a, $b, $c, $d, $e, $f, $g, $h) = $hash;
513
-
514
- // Main loop
515
- for ($i = 0; $i < 64; $i++) {
516
- $s0 = $this->_rightRotate($a, 2) ^
517
- $this->_rightRotate($a, 13) ^
518
- $this->_rightRotate($a, 22);
519
- $maj = ($a & $b) ^
520
- ($a & $c) ^
521
- ($b & $c);
522
- $t2 = $this->_add($s0, $maj);
523
-
524
- $s1 = $this->_rightRotate($e, 6) ^
525
- $this->_rightRotate($e, 11) ^
526
- $this->_rightRotate($e, 25);
527
- $ch = ($e & $f) ^
528
- ($this->_not($e) & $g);
529
- $t1 = $this->_add($h, $s1, $ch, $k[$i], $w[$i]);
530
-
531
- $h = $g;
532
- $g = $f;
533
- $f = $e;
534
- $e = $this->_add($d, $t1);
535
- $d = $c;
536
- $c = $b;
537
- $b = $a;
538
- $a = $this->_add($t1, $t2);
539
- }
540
-
541
- // Add this chunk's hash to result so far
542
- $hash = array(
543
- $this->_add($hash[0], $a),
544
- $this->_add($hash[1], $b),
545
- $this->_add($hash[2], $c),
546
- $this->_add($hash[3], $d),
547
- $this->_add($hash[4], $e),
548
- $this->_add($hash[5], $f),
549
- $this->_add($hash[6], $g),
550
- $this->_add($hash[7], $h)
551
- );
552
- }
553
-
554
- // Produce the final hash value (big-endian)
555
- return pack('N8', $hash[0], $hash[1], $hash[2], $hash[3], $hash[4], $hash[5], $hash[6], $hash[7]);
556
- }
557
-
558
- /**
559
- * Pure-PHP implementation of SHA384 and SHA512
560
- *
561
- * @access private
562
- * @param string $m
563
- */
564
- function _sha512($m)
565
- {
566
- static $init384, $init512, $k;
567
-
568
- if (!isset($k)) {
569
- // Initialize variables
570
- $init384 = array( // initial values for SHA384
571
- 'cbbb9d5dc1059ed8', '629a292a367cd507', '9159015a3070dd17', '152fecd8f70e5939',
572
- '67332667ffc00b31', '8eb44a8768581511', 'db0c2e0d64f98fa7', '47b5481dbefa4fa4'
573
- );
574
- $init512 = array( // initial values for SHA512
575
- '6a09e667f3bcc908', 'bb67ae8584caa73b', '3c6ef372fe94f82b', 'a54ff53a5f1d36f1',
576
- '510e527fade682d1', '9b05688c2b3e6c1f', '1f83d9abfb41bd6b', '5be0cd19137e2179'
577
- );
578
-
579
- for ($i = 0; $i < 8; $i++) {
580
- $init384[$i] = new BigInteger($init384[$i], 16);
581
- $init384[$i]->setPrecision(64);
582
- $init512[$i] = new BigInteger($init512[$i], 16);
583
- $init512[$i]->setPrecision(64);
584
- }
585
-
586
- // Initialize table of round constants
587
- // (first 64 bits of the fractional parts of the cube roots of the first 80 primes 2..409)
588
- $k = array(
589
- '428a2f98d728ae22', '7137449123ef65cd', 'b5c0fbcfec4d3b2f', 'e9b5dba58189dbbc',
590
- '3956c25bf348b538', '59f111f1b605d019', '923f82a4af194f9b', 'ab1c5ed5da6d8118',
591
- 'd807aa98a3030242', '12835b0145706fbe', '243185be4ee4b28c', '550c7dc3d5ffb4e2',
592
- '72be5d74f27b896f', '80deb1fe3b1696b1', '9bdc06a725c71235', 'c19bf174cf692694',
593
- 'e49b69c19ef14ad2', 'efbe4786384f25e3', '0fc19dc68b8cd5b5', '240ca1cc77ac9c65',
594
- '2de92c6f592b0275', '4a7484aa6ea6e483', '5cb0a9dcbd41fbd4', '76f988da831153b5',
595
- '983e5152ee66dfab', 'a831c66d2db43210', 'b00327c898fb213f', 'bf597fc7beef0ee4',
596
- 'c6e00bf33da88fc2', 'd5a79147930aa725', '06ca6351e003826f', '142929670a0e6e70',
597
- '27b70a8546d22ffc', '2e1b21385c26c926', '4d2c6dfc5ac42aed', '53380d139d95b3df',
598
- '650a73548baf63de', '766a0abb3c77b2a8', '81c2c92e47edaee6', '92722c851482353b',
599
- 'a2bfe8a14cf10364', 'a81a664bbc423001', 'c24b8b70d0f89791', 'c76c51a30654be30',
600
- 'd192e819d6ef5218', 'd69906245565a910', 'f40e35855771202a', '106aa07032bbd1b8',
601
- '19a4c116b8d2d0c8', '1e376c085141ab53', '2748774cdf8eeb99', '34b0bcb5e19b48a8',
602
- '391c0cb3c5c95a63', '4ed8aa4ae3418acb', '5b9cca4f7763e373', '682e6ff3d6b2b8a3',
603
- '748f82ee5defb2fc', '78a5636f43172f60', '84c87814a1f0ab72', '8cc702081a6439ec',
604
- '90befffa23631e28', 'a4506cebde82bde9', 'bef9a3f7b2c67915', 'c67178f2e372532b',
605
- 'ca273eceea26619c', 'd186b8c721c0c207', 'eada7dd6cde0eb1e', 'f57d4f7fee6ed178',
606
- '06f067aa72176fba', '0a637dc5a2c898a6', '113f9804bef90dae', '1b710b35131c471b',
607
- '28db77f523047d84', '32caab7b40c72493', '3c9ebe0a15c9bebc', '431d67c49c100d4c',
608
- '4cc5d4becb3e42b6', '597f299cfc657e2a', '5fcb6fab3ad6faec', '6c44198c4a475817'
609
- );
610
-
611
- for ($i = 0; $i < 80; $i++) {
612
- $k[$i] = new BigInteger($k[$i], 16);
613
- }
614
- }
615
-
616
- $hash = $this->l == 48 ? $init384 : $init512;
617
-
618
- // Pre-processing
619
- $length = strlen($m);
620
- // to round to nearest 112 mod 128, we'll add 128 - (length + (128 - 112)) % 128
621
- $m.= str_repeat(chr(0), 128 - (($length + 16) & 0x7F));
622
- $m[$length] = chr(0x80);
623
- // we don't support hashing strings 512MB long
624
- $m.= pack('N4', 0, 0, 0, $length << 3);
625
-
626
- // Process the message in successive 1024-bit chunks
627
- $chunks = str_split($m, 128);
628
- foreach ($chunks as $chunk) {
629
- $w = array();
630
- for ($i = 0; $i < 16; $i++) {
631
- $temp = new BigInteger($this->_string_shift($chunk, 8), 256);
632
- $temp->setPrecision(64);
633
- $w[] = $temp;
634
- }
635
-
636
- // Extend the sixteen 32-bit words into eighty 32-bit words
637
- for ($i = 16; $i < 80; $i++) {
638
- $temp = array(
639
- $w[$i - 15]->bitwise_rightRotate(1),
640
- $w[$i - 15]->bitwise_rightRotate(8),
641
- $w[$i - 15]->bitwise_rightShift(7)
642
- );
643
- $s0 = $temp[0]->bitwise_xor($temp[1]);
644
- $s0 = $s0->bitwise_xor($temp[2]);
645
- $temp = array(
646
- $w[$i - 2]->bitwise_rightRotate(19),
647
- $w[$i - 2]->bitwise_rightRotate(61),
648
- $w[$i - 2]->bitwise_rightShift(6)
649
- );
650
- $s1 = $temp[0]->bitwise_xor($temp[1]);
651
- $s1 = $s1->bitwise_xor($temp[2]);
652
- $w[$i] = $w[$i - 16]->copy();
653
- $w[$i] = $w[$i]->add($s0);
654
- $w[$i] = $w[$i]->add($w[$i - 7]);
655
- $w[$i] = $w[$i]->add($s1);
656
- }
657
-
658
- // Initialize hash value for this chunk
659
- $a = $hash[0]->copy();
660
- $b = $hash[1]->copy();
661
- $c = $hash[2]->copy();
662
- $d = $hash[3]->copy();
663
- $e = $hash[4]->copy();
664
- $f = $hash[5]->copy();
665
- $g = $hash[6]->copy();
666
- $h = $hash[7]->copy();
667
-
668
- // Main loop
669
- for ($i = 0; $i < 80; $i++) {
670
- $temp = array(
671
- $a->bitwise_rightRotate(28),
672
- $a->bitwise_rightRotate(34),
673
- $a->bitwise_rightRotate(39)
674
- );
675
- $s0 = $temp[0]->bitwise_xor($temp[1]);
676
- $s0 = $s0->bitwise_xor($temp[2]);
677
- $temp = array(
678
- $a->bitwise_and($b),
679
- $a->bitwise_and($c),
680
- $b->bitwise_and($c)
681
- );
682
- $maj = $temp[0]->bitwise_xor($temp[1]);
683
- $maj = $maj->bitwise_xor($temp[2]);
684
- $t2 = $s0->add($maj);
685
-
686
- $temp = array(
687
- $e->bitwise_rightRotate(14),
688
- $e->bitwise_rightRotate(18),
689
- $e->bitwise_rightRotate(41)
690
- );
691
- $s1 = $temp[0]->bitwise_xor($temp[1]);
692
- $s1 = $s1->bitwise_xor($temp[2]);
693
- $temp = array(
694
- $e->bitwise_and($f),
695
- $g->bitwise_and($e->bitwise_not())
696
- );
697
- $ch = $temp[0]->bitwise_xor($temp[1]);
698
- $t1 = $h->add($s1);
699
- $t1 = $t1->add($ch);
700
- $t1 = $t1->add($k[$i]);
701
- $t1 = $t1->add($w[$i]);
702
-
703
- $h = $g->copy();
704
- $g = $f->copy();
705
- $f = $e->copy();
706
- $e = $d->add($t1);
707
- $d = $c->copy();
708
- $c = $b->copy();
709
- $b = $a->copy();
710
- $a = $t1->add($t2);
711
- }
712
-
713
- // Add this chunk's hash to result so far
714
- $hash = array(
715
- $hash[0]->add($a),
716
- $hash[1]->add($b),
717
- $hash[2]->add($c),
718
- $hash[3]->add($d),
719
- $hash[4]->add($e),
720
- $hash[5]->add($f),
721
- $hash[6]->add($g),
722
- $hash[7]->add($h)
723
- );
724
- }
725
-
726
- // Produce the final hash value (big-endian)
727
- // (\phpseclib\Crypt\Hash::hash() trims the output for hashes but not for HMACs. as such, we trim the output here)
728
- $temp = $hash[0]->toBytes() . $hash[1]->toBytes() . $hash[2]->toBytes() . $hash[3]->toBytes() .
729
- $hash[4]->toBytes() . $hash[5]->toBytes();
730
- if ($this->l != 48) {
731
- $temp.= $hash[6]->toBytes() . $hash[7]->toBytes();
732
- }
733
-
734
- return $temp;
735
- }
736
-
737
- /**
738
- * Right Rotate
739
- *
740
- * @access private
741
- * @param int $int
742
- * @param int $amt
743
- * @see self::_sha256()
744
- * @return int
745
- */
746
- function _rightRotate($int, $amt)
747
- {
748
- $invamt = 32 - $amt;
749
- $mask = (1 << $invamt) - 1;
750
- return (($int << $invamt) & 0xFFFFFFFF) | (($int >> $amt) & $mask);
751
- }
752
-
753
- /**
754
- * Right Shift
755
- *
756
- * @access private
757
- * @param int $int
758
- * @param int $amt
759
- * @see self::_sha256()
760
- * @return int
761
- */
762
- function _rightShift($int, $amt)
763
- {
764
- $mask = (1 << (32 - $amt)) - 1;
765
- return ($int >> $amt) & $mask;
766
- }
767
-
768
- /**
769
- * Not
770
- *
771
- * @access private
772
- * @param int $int
773
- * @see self::_sha256()
774
- * @return int
775
- */
776
- function _not($int)
777
- {
778
- return ~$int & 0xFFFFFFFF;
779
- }
780
-
781
- /**
782
- * Add
783
- *
784
- * _sha256() adds multiple unsigned 32-bit integers. Since PHP doesn't support unsigned integers and since the
785
- * possibility of overflow exists, care has to be taken. BigInteger could be used but this should be faster.
786
- *
787
- * @param int $...
788
- * @return int
789
- * @see self::_sha256()
790
- * @access private
791
- */
792
- function _add()
793
- {
794
- static $mod;
795
- if (!isset($mod)) {
796
- $mod = pow(2, 32);
797
- }
798
-
799
- $result = 0;
800
- $arguments = func_get_args();
801
- foreach ($arguments as $argument) {
802
- $result+= $argument < 0 ? ($argument & 0x7FFFFFFF) + 0x80000000 : $argument;
803
- }
804
-
805
- return fmod($result, $mod);
806
- }
807
-
808
- /**
809
- * String Shift
810
- *
811
- * Inspired by array_shift
812
- *
813
- * @param string $string
814
- * @param int $index
815
- * @return string
816
- * @access private
817
- */
818
- function _string_shift(&$string, $index = 1)
819
- {
820
- $substr = substr($string, 0, $index);
821
- $string = substr($string, $index);
822
- return $substr;
823
- }
824
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/phpseclib/phpseclib/phpseclib/Crypt/RC2.php DELETED
@@ -1,688 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Pure-PHP implementation of RC2.
5
- *
6
- * Uses mcrypt, if available, and an internal implementation, otherwise.
7
- *
8
- * PHP version 5
9
- *
10
- * Useful resources are as follows:
11
- *
12
- * - {@link http://tools.ietf.org/html/rfc2268}
13
- *
14
- * Here's a short example of how to use this library:
15
- * <code>
16
- * <?php
17
- * include 'vendor/autoload.php';
18
- *
19
- * $rc2 = new \phpseclib\Crypt\RC2();
20
- *
21
- * $rc2->setKey('abcdefgh');
22
- *
23
- * $plaintext = str_repeat('a', 1024);
24
- *
25
- * echo $rc2->decrypt($rc2->encrypt($plaintext));
26
- * ?>
27
- * </code>
28
- *
29
- * @category Crypt
30
- * @package RC2
31
- * @author Patrick Monnerat <pm@datasphere.ch>
32
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
33
- * @link http://phpseclib.sourceforge.net
34
- */
35
-
36
- namespace phpseclib\Crypt;
37
-
38
- /**
39
- * Pure-PHP implementation of RC2.
40
- *
41
- * @package RC2
42
- * @access public
43
- */
44
- class RC2 extends Base
45
- {
46
- /**
47
- * Block Length of the cipher
48
- *
49
- * @see \phpseclib\Crypt\Base::block_size
50
- * @var int
51
- * @access private
52
- */
53
- var $block_size = 8;
54
-
55
- /**
56
- * The Key
57
- *
58
- * @see \phpseclib\Crypt\Base::key
59
- * @see self::setKey()
60
- * @var string
61
- * @access private
62
- */
63
- var $key;
64
-
65
- /**
66
- * The Original (unpadded) Key
67
- *
68
- * @see \phpseclib\Crypt\Base::key
69
- * @see self::setKey()
70
- * @see self::encrypt()
71
- * @see self::decrypt()
72
- * @var string
73
- * @access private
74
- */
75
- var $orig_key;
76
-
77
- /**
78
- * Don't truncate / null pad key
79
- *
80
- * @see \phpseclib\Crypt\Base::_clearBuffers()
81
- * @var bool
82
- * @access private
83
- */
84
- var $skip_key_adjustment = true;
85
-
86
- /**
87
- * Key Length (in bytes)
88
- *
89
- * @see \phpseclib\Crypt\RC2::setKeyLength()
90
- * @var int
91
- * @access private
92
- */
93
- var $key_length = 16; // = 128 bits
94
-
95
- /**
96
- * The mcrypt specific name of the cipher
97
- *
98
- * @see \phpseclib\Crypt\Base::cipher_name_mcrypt
99
- * @var string
100
- * @access private
101
- */
102
- var $cipher_name_mcrypt = 'rc2';
103
-
104
- /**
105
- * Optimizing value while CFB-encrypting
106
- *
107
- * @see \phpseclib\Crypt\Base::cfb_init_len
108
- * @var int
109
- * @access private
110
- */
111
- var $cfb_init_len = 500;
112
-
113
- /**
114
- * The key length in bits.
115
- *
116
- * @see self::setKeyLength()
117
- * @see self::setKey()
118
- * @var int
119
- * @access private
120
- * @internal Should be in range [1..1024].
121
- * @internal Changing this value after setting the key has no effect.
122
- */
123
- var $default_key_length = 1024;
124
-
125
- /**
126
- * The key length in bits.
127
- *
128
- * @see self::isValidEnine()
129
- * @see self::setKey()
130
- * @var int
131
- * @access private
132
- * @internal Should be in range [1..1024].
133
- */
134
- var $current_key_length;
135
-
136
- /**
137
- * The Key Schedule
138
- *
139
- * @see self::_setupKey()
140
- * @var array
141
- * @access private
142
- */
143
- var $keys;
144
-
145
- /**
146
- * Key expansion randomization table.
147
- * Twice the same 256-value sequence to save a modulus in key expansion.
148
- *
149
- * @see self::setKey()
150
- * @var array
151
- * @access private
152
- */
153
- var $pitable = array(
154
- 0xD9, 0x78, 0xF9, 0xC4, 0x19, 0xDD, 0xB5, 0xED,
155
- 0x28, 0xE9, 0xFD, 0x79, 0x4A, 0xA0, 0xD8, 0x9D,
156
- 0xC6, 0x7E, 0x37, 0x83, 0x2B, 0x76, 0x53, 0x8E,
157
- 0x62, 0x4C, 0x64, 0x88, 0x44, 0x8B, 0xFB, 0xA2,
158
- 0x17, 0x9A, 0x59, 0xF5, 0x87, 0xB3, 0x4F, 0x13,
159
- 0x61, 0x45, 0x6D, 0x8D, 0x09, 0x81, 0x7D, 0x32,
160
- 0xBD, 0x8F, 0x40, 0xEB, 0x86, 0xB7, 0x7B, 0x0B,
161
- 0xF0, 0x95, 0x21, 0x22, 0x5C, 0x6B, 0x4E, 0x82,
162
- 0x54, 0xD6, 0x65, 0x93, 0xCE, 0x60, 0xB2, 0x1C,
163
- 0x73, 0x56, 0xC0, 0x14, 0xA7, 0x8C, 0xF1, 0xDC,
164
- 0x12, 0x75, 0xCA, 0x1F, 0x3B, 0xBE, 0xE4, 0xD1,
165
- 0x42, 0x3D, 0xD4, 0x30, 0xA3, 0x3C, 0xB6, 0x26,
166
- 0x6F, 0xBF, 0x0E, 0xDA, 0x46, 0x69, 0x07, 0x57,
167
- 0x27, 0xF2, 0x1D, 0x9B, 0xBC, 0x94, 0x43, 0x03,
168
- 0xF8, 0x11, 0xC7, 0xF6, 0x90, 0xEF, 0x3E, 0xE7,
169
- 0x06, 0xC3, 0xD5, 0x2F, 0xC8, 0x66, 0x1E, 0xD7,
170
- 0x08, 0xE8, 0xEA, 0xDE, 0x80, 0x52, 0xEE, 0xF7,
171
- 0x84, 0xAA, 0x72, 0xAC, 0x35, 0x4D, 0x6A, 0x2A,
172
- 0x96, 0x1A, 0xD2, 0x71, 0x5A, 0x15, 0x49, 0x74,
173
- 0x4B, 0x9F, 0xD0, 0x5E, 0x04, 0x18, 0xA4, 0xEC,
174
- 0xC2, 0xE0, 0x41, 0x6E, 0x0F, 0x51, 0xCB, 0xCC,
175
- 0x24, 0x91, 0xAF, 0x50, 0xA1, 0xF4, 0x70, 0x39,
176
- 0x99, 0x7C, 0x3A, 0x85, 0x23, 0xB8, 0xB4, 0x7A,
177
- 0xFC, 0x02, 0x36, 0x5B, 0x25, 0x55, 0x97, 0x31,
178
- 0x2D, 0x5D, 0xFA, 0x98, 0xE3, 0x8A, 0x92, 0xAE,
179
- 0x05, 0xDF, 0x29, 0x10, 0x67, 0x6C, 0xBA, 0xC9,
180
- 0xD3, 0x00, 0xE6, 0xCF, 0xE1, 0x9E, 0xA8, 0x2C,
181
- 0x63, 0x16, 0x01, 0x3F, 0x58, 0xE2, 0x89, 0xA9,
182
- 0x0D, 0x38, 0x34, 0x1B, 0xAB, 0x33, 0xFF, 0xB0,
183
- 0xBB, 0x48, 0x0C, 0x5F, 0xB9, 0xB1, 0xCD, 0x2E,
184
- 0xC5, 0xF3, 0xDB, 0x47, 0xE5, 0xA5, 0x9C, 0x77,
185
- 0x0A, 0xA6, 0x20, 0x68, 0xFE, 0x7F, 0xC1, 0xAD,
186
- 0xD9, 0x78, 0xF9, 0xC4, 0x19, 0xDD, 0xB5, 0xED,
187
- 0x28, 0xE9, 0xFD, 0x79, 0x4A, 0xA0, 0xD8, 0x9D,
188
- 0xC6, 0x7E, 0x37, 0x83, 0x2B, 0x76, 0x53, 0x8E,
189
- 0x62, 0x4C, 0x64, 0x88, 0x44, 0x8B, 0xFB, 0xA2,
190
- 0x17, 0x9A, 0x59, 0xF5, 0x87, 0xB3, 0x4F, 0x13,
191
- 0x61, 0x45, 0x6D, 0x8D, 0x09, 0x81, 0x7D, 0x32,
192
- 0xBD, 0x8F, 0x40, 0xEB, 0x86, 0xB7, 0x7B, 0x0B,
193
- 0xF0, 0x95, 0x21, 0x22, 0x5C, 0x6B, 0x4E, 0x82,
194
- 0x54, 0xD6, 0x65, 0x93, 0xCE, 0x60, 0xB2, 0x1C,
195
- 0x73, 0x56, 0xC0, 0x14, 0xA7, 0x8C, 0xF1, 0xDC,
196
- 0x12, 0x75, 0xCA, 0x1F, 0x3B, 0xBE, 0xE4, 0xD1,
197
- 0x42, 0x3D, 0xD4, 0x30, 0xA3, 0x3C, 0xB6, 0x26,
198
- 0x6F, 0xBF, 0x0E, 0xDA, 0x46, 0x69, 0x07, 0x57,
199
- 0x27, 0xF2, 0x1D, 0x9B, 0xBC, 0x94, 0x43, 0x03,
200
- 0xF8, 0x11, 0xC7, 0xF6, 0x90, 0xEF, 0x3E, 0xE7,
201
- 0x06, 0xC3, 0xD5, 0x2F, 0xC8, 0x66, 0x1E, 0xD7,
202
- 0x08, 0xE8, 0xEA, 0xDE, 0x80, 0x52, 0xEE, 0xF7,
203
- 0x84, 0xAA, 0x72, 0xAC, 0x35, 0x4D, 0x6A, 0x2A,
204
- 0x96, 0x1A, 0xD2, 0x71, 0x5A, 0x15, 0x49, 0x74,
205
- 0x4B, 0x9F, 0xD0, 0x5E, 0x04, 0x18, 0xA4, 0xEC,
206
- 0xC2, 0xE0, 0x41, 0x6E, 0x0F, 0x51, 0xCB, 0xCC,
207
- 0x24, 0x91, 0xAF, 0x50, 0xA1, 0xF4, 0x70, 0x39,
208
- 0x99, 0x7C, 0x3A, 0x85, 0x23, 0xB8, 0xB4, 0x7A,
209
- 0xFC, 0x02, 0x36, 0x5B, 0x25, 0x55, 0x97, 0x31,
210
- 0x2D, 0x5D, 0xFA, 0x98, 0xE3, 0x8A, 0x92, 0xAE,
211
- 0x05, 0xDF, 0x29, 0x10, 0x67, 0x6C, 0xBA, 0xC9,
212
- 0xD3, 0x00, 0xE6, 0xCF, 0xE1, 0x9E, 0xA8, 0x2C,
213
- 0x63, 0x16, 0x01, 0x3F, 0x58, 0xE2, 0x89, 0xA9,
214
- 0x0D, 0x38, 0x34, 0x1B, 0xAB, 0x33, 0xFF, 0xB0,
215
- 0xBB, 0x48, 0x0C, 0x5F, 0xB9, 0xB1, 0xCD, 0x2E,
216
- 0xC5, 0xF3, 0xDB, 0x47, 0xE5, 0xA5, 0x9C, 0x77,
217
- 0x0A, 0xA6, 0x20, 0x68, 0xFE, 0x7F, 0xC1, 0xAD
218
- );
219
-
220
- /**
221
- * Inverse key expansion randomization table.
222
- *
223
- * @see self::setKey()
224
- * @var array
225
- * @access private
226
- */
227
- var $invpitable = array(
228
- 0xD1, 0xDA, 0xB9, 0x6F, 0x9C, 0xC8, 0x78, 0x66,
229
- 0x80, 0x2C, 0xF8, 0x37, 0xEA, 0xE0, 0x62, 0xA4,
230
- 0xCB, 0x71, 0x50, 0x27, 0x4B, 0x95, 0xD9, 0x20,
231
- 0x9D, 0x04, 0x91, 0xE3, 0x47, 0x6A, 0x7E, 0x53,
232
- 0xFA, 0x3A, 0x3B, 0xB4, 0xA8, 0xBC, 0x5F, 0x68,
233
- 0x08, 0xCA, 0x8F, 0x14, 0xD7, 0xC0, 0xEF, 0x7B,
234
- 0x5B, 0xBF, 0x2F, 0xE5, 0xE2, 0x8C, 0xBA, 0x12,
235
- 0xE1, 0xAF, 0xB2, 0x54, 0x5D, 0x59, 0x76, 0xDB,
236
- 0x32, 0xA2, 0x58, 0x6E, 0x1C, 0x29, 0x64, 0xF3,
237
- 0xE9, 0x96, 0x0C, 0x98, 0x19, 0x8D, 0x3E, 0x26,
238
- 0xAB, 0xA5, 0x85, 0x16, 0x40, 0xBD, 0x49, 0x67,
239
- 0xDC, 0x22, 0x94, 0xBB, 0x3C, 0xC1, 0x9B, 0xEB,
240
- 0x45, 0x28, 0x18, 0xD8, 0x1A, 0x42, 0x7D, 0xCC,
241
- 0xFB, 0x65, 0x8E, 0x3D, 0xCD, 0x2A, 0xA3, 0x60,
242
- 0xAE, 0x93, 0x8A, 0x48, 0x97, 0x51, 0x15, 0xF7,
243
- 0x01, 0x0B, 0xB7, 0x36, 0xB1, 0x2E, 0x11, 0xFD,
244
- 0x84, 0x2D, 0x3F, 0x13, 0x88, 0xB3, 0x34, 0x24,
245
- 0x1B, 0xDE, 0xC5, 0x1D, 0x4D, 0x2B, 0x17, 0x31,
246
- 0x74, 0xA9, 0xC6, 0x43, 0x6D, 0x39, 0x90, 0xBE,
247
- 0xC3, 0xB0, 0x21, 0x6B, 0xF6, 0x0F, 0xD5, 0x99,
248
- 0x0D, 0xAC, 0x1F, 0x5C, 0x9E, 0xF5, 0xF9, 0x4C,
249
- 0xD6, 0xDF, 0x89, 0xE4, 0x8B, 0xFF, 0xC7, 0xAA,
250
- 0xE7, 0xED, 0x46, 0x25, 0xB6, 0x06, 0x5E, 0x35,
251
- 0xB5, 0xEC, 0xCE, 0xE8, 0x6C, 0x30, 0x55, 0x61,
252
- 0x4A, 0xFE, 0xA0, 0x79, 0x03, 0xF0, 0x10, 0x72,
253
- 0x7C, 0xCF, 0x52, 0xA6, 0xA7, 0xEE, 0x44, 0xD3,
254
- 0x9A, 0x57, 0x92, 0xD0, 0x5A, 0x7A, 0x41, 0x7F,
255
- 0x0E, 0x00, 0x63, 0xF2, 0x4F, 0x05, 0x83, 0xC9,
256
- 0xA1, 0xD4, 0xDD, 0xC4, 0x56, 0xF4, 0xD2, 0x77,
257
- 0x81, 0x09, 0x82, 0x33, 0x9F, 0x07, 0x86, 0x75,
258
- 0x38, 0x4E, 0x69, 0xF1, 0xAD, 0x23, 0x73, 0x87,
259
- 0x70, 0x02, 0xC2, 0x1E, 0xB8, 0x0A, 0xFC, 0xE6
260
- );
261
-
262
- /**
263
- * Test for engine validity
264
- *
265
- * This is mainly just a wrapper to set things up for \phpseclib\Crypt\Base::isValidEngine()
266
- *
267
- * @see \phpseclib\Crypt\Base::__construct()
268
- * @param int $engine
269
- * @access public
270
- * @return bool
271
- */
272
- function isValidEngine($engine)
273
- {
274
- switch ($engine) {
275
- case self::ENGINE_OPENSSL:
276
- if ($this->current_key_length != 128 || strlen($this->orig_key) < 16) {
277
- return false;
278
- }
279
- $this->cipher_name_openssl_ecb = 'rc2-ecb';
280
- $this->cipher_name_openssl = 'rc2-' . $this->_openssl_translate_mode();
281
- }
282
-
283
- return parent::isValidEngine($engine);
284
- }
285
-
286
- /**
287
- * Sets the key length.
288
- *
289
- * Valid key lengths are 8 to 1024.
290
- * Calling this function after setting the key has no effect until the next
291
- * \phpseclib\Crypt\RC2::setKey() call.
292
- *
293
- * @access public
294
- * @param int $length in bits
295
- */
296
- function setKeyLength($length)
297
- {
298
- if ($length < 8) {
299
- $this->default_key_length = 8;
300
- } elseif ($length > 1024) {
301
- $this->default_key_length = 128;
302
- } else {
303
- $this->default_key_length = $length;
304
- }
305
- $this->current_key_length = $this->default_key_length;
306
-
307
- parent::setKeyLength($length);
308
- }
309
-
310
- /**
311
- * Returns the current key length
312
- *
313
- * @access public
314
- * @return int
315
- */
316
- function getKeyLength()
317
- {
318
- return $this->current_key_length;
319
- }
320
-
321
- /**
322
- * Sets the key.
323
- *
324
- * Keys can be of any length. RC2, itself, uses 8 to 1024 bit keys (eg.
325
- * strlen($key) <= 128), however, we only use the first 128 bytes if $key
326
- * has more then 128 bytes in it, and set $key to a single null byte if
327
- * it is empty.
328
- *
329
- * If the key is not explicitly set, it'll be assumed to be a single
330
- * null byte.
331
- *
332
- * @see \phpseclib\Crypt\Base::setKey()
333
- * @access public
334
- * @param string $key
335
- * @param int $t1 optional Effective key length in bits.
336
- */
337
- function setKey($key, $t1 = 0)
338
- {
339
- $this->orig_key = $key;
340
-
341
- if ($t1 <= 0) {
342
- $t1 = $this->default_key_length;
343
- } elseif ($t1 > 1024) {
344
- $t1 = 1024;
345
- }
346
- $this->current_key_length = $t1;
347
- // Key byte count should be 1..128.
348
- $key = strlen($key) ? substr($key, 0, 128) : "\x00";
349
- $t = strlen($key);
350
-
351
- // The mcrypt RC2 implementation only supports effective key length
352
- // of 1024 bits. It is however possible to handle effective key
353
- // lengths in range 1..1024 by expanding the key and applying
354
- // inverse pitable mapping to the first byte before submitting it
355
- // to mcrypt.
356
-
357
- // Key expansion.
358
- $l = array_values(unpack('C*', $key));
359
- $t8 = ($t1 + 7) >> 3;
360
- $tm = 0xFF >> (8 * $t8 - $t1);
361
-
362
- // Expand key.
363
- $pitable = $this->pitable;
364
- for ($i = $t; $i < 128; $i++) {
365
- $l[$i] = $pitable[$l[$i - 1] + $l[$i - $t]];
366
- }
367
- $i = 128 - $t8;
368
- $l[$i] = $pitable[$l[$i] & $tm];
369
- while ($i--) {
370
- $l[$i] = $pitable[$l[$i + 1] ^ $l[$i + $t8]];
371
- }
372
-
373
- // Prepare the key for mcrypt.
374
- $l[0] = $this->invpitable[$l[0]];
375
- array_unshift($l, 'C*');
376
-
377
- parent::setKey(call_user_func_array('pack', $l));
378
- }
379
-
380
- /**
381
- * Encrypts a message.
382
- *
383
- * Mostly a wrapper for \phpseclib\Crypt\Base::encrypt, with some additional OpenSSL handling code
384
- *
385
- * @see self::decrypt()
386
- * @access public
387
- * @param string $plaintext
388
- * @return string $ciphertext
389
- */
390
- function encrypt($plaintext)
391
- {
392
- if ($this->engine == self::ENGINE_OPENSSL) {
393
- $temp = $this->key;
394
- $this->key = $this->orig_key;
395
- $result = parent::encrypt($plaintext);
396
- $this->key = $temp;
397
- return $result;
398
- }
399
-
400
- return parent::encrypt($plaintext);
401
- }
402
-
403
- /**
404
- * Decrypts a message.
405
- *
406
- * Mostly a wrapper for \phpseclib\Crypt\Base::decrypt, with some additional OpenSSL handling code
407
- *
408
- * @see self::encrypt()
409
- * @access public
410
- * @param string $ciphertext
411
- * @return string $plaintext
412
- */
413
- function decrypt($ciphertext)
414
- {
415
- if ($this->engine == self::ENGINE_OPENSSL) {
416
- $temp = $this->key;
417
- $this->key = $this->orig_key;
418
- $result = parent::decrypt($ciphertext);
419
- $this->key = $temp;
420
- return $result;
421
- }
422
-
423
- return parent::decrypt($ciphertext);
424
- }
425
-
426
- /**
427
- * Encrypts a block
428
- *
429
- * @see \phpseclib\Crypt\Base::_encryptBlock()
430
- * @see \phpseclib\Crypt\Base::encrypt()
431
- * @access private
432
- * @param string $in
433
- * @return string
434
- */
435
- function _encryptBlock($in)
436
- {
437
- list($r0, $r1, $r2, $r3) = array_values(unpack('v*', $in));
438
- $keys = $this->keys;
439
- $limit = 20;
440
- $actions = array($limit => 44, 44 => 64);
441
- $j = 0;
442
-
443
- for (;;) {
444
- // Mixing round.
445
- $r0 = (($r0 + $keys[$j++] + ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF) << 1;
446
- $r0 |= $r0 >> 16;
447
- $r1 = (($r1 + $keys[$j++] + ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF) << 2;
448
- $r1 |= $r1 >> 16;
449
- $r2 = (($r2 + $keys[$j++] + ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF) << 3;
450
- $r2 |= $r2 >> 16;
451
- $r3 = (($r3 + $keys[$j++] + ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF) << 5;
452
- $r3 |= $r3 >> 16;
453
-
454
- if ($j === $limit) {
455
- if ($limit === 64) {
456
- break;
457
- }
458
-
459
- // Mashing round.
460
- $r0 += $keys[$r3 & 0x3F];
461
- $r1 += $keys[$r0 & 0x3F];
462
- $r2 += $keys[$r1 & 0x3F];
463
- $r3 += $keys[$r2 & 0x3F];
464
- $limit = $actions[$limit];
465
- }
466
- }
467
-
468
- return pack('vvvv', $r0, $r1, $r2, $r3);
469
- }
470
-
471
- /**
472
- * Decrypts a block
473
- *
474
- * @see \phpseclib\Crypt\Base::_decryptBlock()
475
- * @see \phpseclib\Crypt\Base::decrypt()
476
- * @access private
477
- * @param string $in
478
- * @return string
479
- */
480
- function _decryptBlock($in)
481
- {
482
- list($r0, $r1, $r2, $r3) = array_values(unpack('v*', $in));
483
- $keys = $this->keys;
484
- $limit = 44;
485
- $actions = array($limit => 20, 20 => 0);
486
- $j = 64;
487
-
488
- for (;;) {
489
- // R-mixing round.
490
- $r3 = ($r3 | ($r3 << 16)) >> 5;
491
- $r3 = ($r3 - $keys[--$j] - ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF;
492
- $r2 = ($r2 | ($r2 << 16)) >> 3;
493
- $r2 = ($r2 - $keys[--$j] - ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF;
494
- $r1 = ($r1 | ($r1 << 16)) >> 2;
495
- $r1 = ($r1 - $keys[--$j] - ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF;
496
- $r0 = ($r0 | ($r0 << 16)) >> 1;
497
- $r0 = ($r0 - $keys[--$j] - ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF;
498
-
499
- if ($j === $limit) {
500
- if ($limit === 0) {
501
- break;
502
- }
503
-
504
- // R-mashing round.
505
- $r3 = ($r3 - $keys[$r2 & 0x3F]) & 0xFFFF;
506
- $r2 = ($r2 - $keys[$r1 & 0x3F]) & 0xFFFF;
507
- $r1 = ($r1 - $keys[$r0 & 0x3F]) & 0xFFFF;
508
- $r0 = ($r0 - $keys[$r3 & 0x3F]) & 0xFFFF;
509
- $limit = $actions[$limit];
510
- }
511
- }
512
-
513
- return pack('vvvv', $r0, $r1, $r2, $r3);
514
- }
515
-
516
- /**
517
- * Setup the \phpseclib\Crypt\Base::ENGINE_MCRYPT $engine
518
- *
519
- * @see \phpseclib\Crypt\Base::_setupMcrypt()
520
- * @access private
521
- */
522
- function _setupMcrypt()
523
- {
524
- if (!isset($this->key)) {
525
- $this->setKey('');
526
- }
527
-
528
- parent::_setupMcrypt();
529
- }
530
-
531
- /**
532
- * Creates the key schedule
533
- *
534
- * @see \phpseclib\Crypt\Base::_setupKey()
535
- * @access private
536
- */
537
- function _setupKey()
538
- {
539
- if (!isset($this->key)) {
540
- $this->setKey('');
541
- }
542
-
543
- // Key has already been expanded in \phpseclib\Crypt\RC2::setKey():
544
- // Only the first value must be altered.
545
- $l = unpack('Ca/Cb/v*', $this->key);
546
- array_unshift($l, $this->pitable[$l['a']] | ($l['b'] << 8));
547
- unset($l['a']);
548
- unset($l['b']);
549
- $this->keys = $l;
550
- }
551
-
552
- /**
553
- * Setup the performance-optimized function for de/encrypt()
554
- *
555
- * @see \phpseclib\Crypt\Base::_setupInlineCrypt()
556
- * @access private
557
- */
558
- function _setupInlineCrypt()
559
- {
560
- $lambda_functions =& self::_getLambdaFunctions();
561
-
562
- // The first 10 generated $lambda_functions will use the $keys hardcoded as integers
563
- // for the mixing rounds, for better inline crypt performance [~20% faster].
564
- // But for memory reason we have to limit those ultra-optimized $lambda_functions to an amount of 10.
565
- // (Currently, for Crypt_RC2, one generated $lambda_function cost on php5.5@32bit ~60kb unfreeable mem and ~100kb on php5.5@64bit)
566
- $gen_hi_opt_code = (bool)(count($lambda_functions) < 10);
567
-
568
- // Generation of a unique hash for our generated code
569
- $code_hash = "Crypt_RC2, {$this->mode}";
570
- if ($gen_hi_opt_code) {
571
- $code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key);
572
- }
573
-
574
- // Is there a re-usable $lambda_functions in there?
575
- // If not, we have to create it.
576
- if (!isset($lambda_functions[$code_hash])) {
577
- // Init code for both, encrypt and decrypt.
578
- $init_crypt = '$keys = $self->keys;';
579
-
580
- switch (true) {
581
- case $gen_hi_opt_code:
582
- $keys = $this->keys;
583
- default:
584
- $keys = array();
585
- foreach ($this->keys as $k => $v) {
586
- $keys[$k] = '$keys[' . $k . ']';
587
- }
588
- }
589
-
590
- // $in is the current 8 bytes block which has to be en/decrypt
591
- $encrypt_block = $decrypt_block = '
592
- $in = unpack("v4", $in);
593
- $r0 = $in[1];
594
- $r1 = $in[2];
595
- $r2 = $in[3];
596
- $r3 = $in[4];
597
- ';
598
-
599
- // Create code for encryption.
600
- $limit = 20;
601
- $actions = array($limit => 44, 44 => 64);
602
- $j = 0;
603
-
604
- for (;;) {
605
- // Mixing round.
606
- $encrypt_block .= '
607
- $r0 = (($r0 + ' . $keys[$j++] . ' +
608
- ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF) << 1;
609
- $r0 |= $r0 >> 16;
610
- $r1 = (($r1 + ' . $keys[$j++] . ' +
611
- ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF) << 2;
612
- $r1 |= $r1 >> 16;
613
- $r2 = (($r2 + ' . $keys[$j++] . ' +
614
- ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF) << 3;
615
- $r2 |= $r2 >> 16;
616
- $r3 = (($r3 + ' . $keys[$j++] . ' +
617
- ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF) << 5;
618
- $r3 |= $r3 >> 16;';
619
-
620
- if ($j === $limit) {
621
- if ($limit === 64) {
622
- break;
623
- }
624
-
625
- // Mashing round.
626
- $encrypt_block .= '
627
- $r0 += $keys[$r3 & 0x3F];
628
- $r1 += $keys[$r0 & 0x3F];
629
- $r2 += $keys[$r1 & 0x3F];
630
- $r3 += $keys[$r2 & 0x3F];';
631
- $limit = $actions[$limit];
632
- }
633
- }
634
-
635
- $encrypt_block .= '$in = pack("v4", $r0, $r1, $r2, $r3);';
636
-
637
- // Create code for decryption.
638
- $limit = 44;
639
- $actions = array($limit => 20, 20 => 0);
640
- $j = 64;
641
-
642
- for (;;) {
643
- // R-mixing round.
644
- $decrypt_block .= '
645
- $r3 = ($r3 | ($r3 << 16)) >> 5;
646
- $r3 = ($r3 - ' . $keys[--$j] . ' -
647
- ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF;
648
- $r2 = ($r2 | ($r2 << 16)) >> 3;
649
- $r2 = ($r2 - ' . $keys[--$j] . ' -
650
- ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF;
651
- $r1 = ($r1 | ($r1 << 16)) >> 2;
652
- $r1 = ($r1 - ' . $keys[--$j] . ' -
653
- ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF;
654
- $r0 = ($r0 | ($r0 << 16)) >> 1;
655
- $r0 = ($r0 - ' . $keys[--$j] . ' -
656
- ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF;';
657
-
658
- if ($j === $limit) {
659
- if ($limit === 0) {
660
- break;
661
- }
662
-
663
- // R-mashing round.
664
- $decrypt_block .= '
665
- $r3 = ($r3 - $keys[$r2 & 0x3F]) & 0xFFFF;
666
- $r2 = ($r2 - $keys[$r1 & 0x3F]) & 0xFFFF;
667
- $r1 = ($r1 - $keys[$r0 & 0x3F]) & 0xFFFF;
668
- $r0 = ($r0 - $keys[$r3 & 0x3F]) & 0xFFFF;';
669
- $limit = $actions[$limit];
670
- }
671
- }
672
-
673
- $decrypt_block .= '$in = pack("v4", $r0, $r1, $r2, $r3);';
674
-
675
- // Creates the inline-crypt function
676
- $lambda_functions[$code_hash] = $this->_createInlineCryptFunction(
677
- array(
678
- 'init_crypt' => $init_crypt,
679
- 'encrypt_block' => $encrypt_block,
680
- 'decrypt_block' => $decrypt_block
681
- )
682
- );
683
- }
684
-
685
- // Set the inline-crypt function as callback in: $this->inline_crypt
686
- $this->inline_crypt = $lambda_functions[$code_hash];
687
- }
688
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/phpseclib/phpseclib/phpseclib/Crypt/RC4.php DELETED
@@ -1,342 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Pure-PHP implementation of RC4.
5
- *
6
- * Uses mcrypt, if available, and an internal implementation, otherwise.
7
- *
8
- * PHP version 5
9
- *
10
- * Useful resources are as follows:
11
- *
12
- * - {@link http://www.mozilla.org/projects/security/pki/nss/draft-kaukonen-cipher-arcfour-03.txt ARCFOUR Algorithm}
13
- * - {@link http://en.wikipedia.org/wiki/RC4 - Wikipedia: RC4}
14
- *
15
- * RC4 is also known as ARCFOUR or ARC4. The reason is elaborated upon at Wikipedia. This class is named RC4 and not
16
- * ARCFOUR or ARC4 because RC4 is how it is referred to in the SSH1 specification.
17
- *
18
- * Here's a short example of how to use this library:
19
- * <code>
20
- * <?php
21
- * include 'vendor/autoload.php';
22
- *
23
- * $rc4 = new \phpseclib\Crypt\RC4();
24
- *
25
- * $rc4->setKey('abcdefgh');
26
- *
27
- * $size = 10 * 1024;
28
- * $plaintext = '';
29
- * for ($i = 0; $i < $size; $i++) {
30
- * $plaintext.= 'a';
31
- * }
32
- *
33
- * echo $rc4->decrypt($rc4->encrypt($plaintext));
34
- * ?>
35
- * </code>
36
- *
37
- * @category Crypt
38
- * @package RC4
39
- * @author Jim Wigginton <terrafrost@php.net>
40
- * @copyright 2007 Jim Wigginton
41
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
42
- * @link http://phpseclib.sourceforge.net
43
- */
44
-
45
- namespace phpseclib\Crypt;
46
-
47
- /**
48
- * Pure-PHP implementation of RC4.
49
- *
50
- * @package RC4
51
- * @author Jim Wigginton <terrafrost@php.net>
52
- * @access public
53
- */
54
- class RC4 extends Base
55
- {
56
- /**#@+
57
- * @access private
58
- * @see \phpseclib\Crypt\RC4::_crypt()
59
- */
60
- const ENCRYPT = 0;
61
- const DECRYPT = 1;
62
- /**#@-*/
63
-
64
- /**
65
- * Block Length of the cipher
66
- *
67
- * RC4 is a stream cipher
68
- * so we the block_size to 0
69
- *
70
- * @see \phpseclib\Crypt\Base::block_size
71
- * @var int
72
- * @access private
73
- */
74
- var $block_size = 0;
75
-
76
- /**
77
- * Key Length (in bytes)
78
- *
79
- * @see \phpseclib\Crypt\RC4::setKeyLength()
80
- * @var int
81
- * @access private
82
- */
83
- var $key_length = 128; // = 1024 bits
84
-
85
- /**
86
- * The mcrypt specific name of the cipher
87
- *
88
- * @see \phpseclib\Crypt\Base::cipher_name_mcrypt
89
- * @var string
90
- * @access private
91
- */
92
- var $cipher_name_mcrypt = 'arcfour';
93
-
94
- /**
95
- * Holds whether performance-optimized $inline_crypt() can/should be used.
96
- *
97
- * @see \phpseclib\Crypt\Base::inline_crypt
98
- * @var mixed
99
- * @access private
100
- */
101
- var $use_inline_crypt = false; // currently not available
102
-
103
- /**
104
- * The Key
105
- *
106
- * @see self::setKey()
107
- * @var string
108
- * @access private
109
- */
110
- var $key;
111
-
112
- /**
113
- * The Key Stream for decryption and encryption
114
- *
115
- * @see self::setKey()
116
- * @var array
117
- * @access private
118
- */
119
- var $stream;
120
-
121
- /**
122
- * Default Constructor.
123
- *
124
- * Determines whether or not the mcrypt extension should be used.
125
- *
126
- * @see \phpseclib\Crypt\Base::__construct()
127
- * @return \phpseclib\Crypt\RC4
128
- * @access public
129
- */
130
- function __construct()
131
- {
132
- parent::__construct(Base::MODE_STREAM);
133
- }
134
-
135
- /**
136
- * Test for engine validity
137
- *
138
- * This is mainly just a wrapper to set things up for \phpseclib\Crypt\Base::isValidEngine()
139
- *
140
- * @see \phpseclib\Crypt\Base::__construct()
141
- * @param int $engine
142
- * @access public
143
- * @return bool
144
- */
145
- function isValidEngine($engine)
146
- {
147
- if ($engine == Base::ENGINE_OPENSSL) {
148
- if (version_compare(PHP_VERSION, '5.3.7') >= 0) {
149
- $this->cipher_name_openssl = 'rc4-40';
150
- } else {
151
- switch (strlen($this->key)) {
152
- case 5:
153
- $this->cipher_name_openssl = 'rc4-40';
154
- break;
155
- case 8:
156
- $this->cipher_name_openssl = 'rc4-64';
157
- break;
158
- case 16:
159
- $this->cipher_name_openssl = 'rc4';
160
- break;
161
- default:
162
- return false;
163
- }
164
- }
165
- }
166
-
167
- return parent::isValidEngine($engine);
168
- }
169
-
170
- /**
171
- * Dummy function.
172
- *
173
- * Some protocols, such as WEP, prepend an "initialization vector" to the key, effectively creating a new key [1].
174
- * If you need to use an initialization vector in this manner, feel free to prepend it to the key, yourself, before
175
- * calling setKey().
176
- *
177
- * [1] WEP's initialization vectors (IV's) are used in a somewhat insecure way. Since, in that protocol,
178
- * the IV's are relatively easy to predict, an attack described by
179
- * {@link http://www.drizzle.com/~aboba/IEEE/rc4_ksaproc.pdf Scott Fluhrer, Itsik Mantin, and Adi Shamir}
180
- * can be used to quickly guess at the rest of the key. The following links elaborate:
181
- *
182
- * {@link http://www.rsa.com/rsalabs/node.asp?id=2009 http://www.rsa.com/rsalabs/node.asp?id=2009}
183
- * {@link http://en.wikipedia.org/wiki/Related_key_attack http://en.wikipedia.org/wiki/Related_key_attack}
184
- *
185
- * @param string $iv
186
- * @see self::setKey()
187
- * @access public
188
- */
189
- function setIV($iv)
190
- {
191
- }
192
-
193
- /**
194
- * Sets the key length
195
- *
196
- * Keys can be between 1 and 256 bytes long.
197
- *
198
- * @access public
199
- * @param int $length
200
- */
201
- function setKeyLength($length)
202
- {
203
- if ($length < 8) {
204
- $this->key_length = 1;
205
- } elseif ($length > 2048) {
206
- $this->key_length = 256;
207
- } else {
208
- $this->key_length = $length >> 3;
209
- }
210
-
211
- parent::setKeyLength($length);
212
- }
213
-
214
- /**
215
- * Encrypts a message.
216
- *
217
- * @see \phpseclib\Crypt\Base::decrypt()
218
- * @see self::_crypt()
219
- * @access public
220
- * @param string $plaintext
221
- * @return string $ciphertext
222
- */
223
- function encrypt($plaintext)
224
- {
225
- if ($this->engine != Base::ENGINE_INTERNAL) {
226
- return parent::encrypt($plaintext);
227
- }
228
- return $this->_crypt($plaintext, self::ENCRYPT);
229
- }
230
-
231
- /**
232
- * Decrypts a message.
233
- *
234
- * $this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)).
235
- * At least if the continuous buffer is disabled.
236
- *
237
- * @see \phpseclib\Crypt\Base::encrypt()
238
- * @see self::_crypt()
239
- * @access public
240
- * @param string $ciphertext
241
- * @return string $plaintext
242
- */
243
- function decrypt($ciphertext)
244
- {
245
- if ($this->engine != Base::ENGINE_INTERNAL) {
246
- return parent::decrypt($ciphertext);
247
- }
248
- return $this->_crypt($ciphertext, self::DECRYPT);
249
- }
250
-
251
- /**
252
- * Encrypts a block
253
- *
254
- * @access private
255
- * @param string $in
256
- */
257
- function _encryptBlock($in)
258
- {
259
- // RC4 does not utilize this method
260
- }
261
-
262
- /**
263
- * Decrypts a block
264
- *
265
- * @access private
266
- * @param string $in
267
- */
268
- function _decryptBlock($in)
269
- {
270
- // RC4 does not utilize this method
271
- }
272
-
273
- /**
274
- * Setup the key (expansion)
275
- *
276
- * @see \phpseclib\Crypt\Base::_setupKey()
277
- * @access private
278
- */
279
- function _setupKey()
280
- {
281
- $key = $this->key;
282
- $keyLength = strlen($key);
283
- $keyStream = range(0, 255);
284
- $j = 0;
285
- for ($i = 0; $i < 256; $i++) {
286
- $j = ($j + $keyStream[$i] + ord($key[$i % $keyLength])) & 255;
287
- $temp = $keyStream[$i];
288
- $keyStream[$i] = $keyStream[$j];
289
- $keyStream[$j] = $temp;
290
- }
291
-
292
- $this->stream = array();
293
- $this->stream[self::DECRYPT] = $this->stream[self::ENCRYPT] = array(
294
- 0, // index $i
295
- 0, // index $j
296
- $keyStream
297
- );
298
- }
299
-
300
- /**
301
- * Encrypts or decrypts a message.
302
- *
303
- * @see self::encrypt()
304
- * @see self::decrypt()
305
- * @access private
306
- * @param string $text
307
- * @param int $mode
308
- * @return string $text
309
- */
310
- function _crypt($text, $mode)
311
- {
312
- if ($this->changed) {
313
- $this->_setup();
314
- $this->changed = false;
315
- }
316
-
317
- $stream = &$this->stream[$mode];
318
- if ($this->continuousBuffer) {
319
- $i = &$stream[0];
320
- $j = &$stream[1];
321
- $keyStream = &$stream[2];
322
- } else {
323
- $i = $stream[0];
324
- $j = $stream[1];
325
- $keyStream = $stream[2];
326
- }
327
-
328
- $len = strlen($text);
329
- for ($k = 0; $k < $len; ++$k) {
330
- $i = ($i + 1) & 255;
331
- $ksi = $keyStream[$i];
332
- $j = ($j + $ksi) & 255;
333
- $ksj = $keyStream[$j];
334
-
335
- $keyStream[$i] = $ksj;
336
- $keyStream[$j] = $ksi;
337
- $text[$k] = $text[$k] ^ chr($keyStream[($ksj + $ksi) & 255]);
338
- }
339
-
340
- return $text;
341
- }
342
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/phpseclib/phpseclib/phpseclib/Crypt/TripleDES.php DELETED
@@ -1,460 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Pure-PHP implementation of Triple DES.
5
- *
6
- * Uses mcrypt, if available, and an internal implementation, otherwise. Operates in the EDE3 mode (encrypt-decrypt-encrypt).
7
- *
8
- * PHP version 5
9
- *
10
- * Here's a short example of how to use this library:
11
- * <code>
12
- * <?php
13
- * include 'vendor/autoload.php';
14
- *
15
- * $des = new \phpseclib\Crypt\TripleDES();
16
- *
17
- * $des->setKey('abcdefghijklmnopqrstuvwx');
18
- *
19
- * $size = 10 * 1024;
20
- * $plaintext = '';
21
- * for ($i = 0; $i < $size; $i++) {
22
- * $plaintext.= 'a';
23
- * }
24
- *
25
- * echo $des->decrypt($des->encrypt($plaintext));
26
- * ?>
27
- * </code>
28
- *
29
- * @category Crypt
30
- * @package TripleDES
31
- * @author Jim Wigginton <terrafrost@php.net>
32
- * @copyright 2007 Jim Wigginton
33
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
34
- * @link http://phpseclib.sourceforge.net
35
- */
36
-
37
- namespace phpseclib\Crypt;
38
-
39
- /**
40
- * Pure-PHP implementation of Triple DES.
41
- *
42
- * @package TripleDES
43
- * @author Jim Wigginton <terrafrost@php.net>
44
- * @access public
45
- */
46
- class TripleDES extends DES
47
- {
48
- /**
49
- * Encrypt / decrypt using inner chaining
50
- *
51
- * Inner chaining is used by SSH-1 and is generally considered to be less secure then outer chaining (self::MODE_CBC3).
52
- */
53
- const MODE_3CBC = -2;
54
-
55
- /**
56
- * Encrypt / decrypt using outer chaining
57
- *
58
- * Outer chaining is used by SSH-2 and when the mode is set to \phpseclib\Crypt\Base::MODE_CBC.
59
- */
60
- const MODE_CBC3 = Base::MODE_CBC;
61
-
62
- /**
63
- * Key Length (in bytes)
64
- *
65
- * @see \phpseclib\Crypt\TripleDES::setKeyLength()
66
- * @var int
67
- * @access private
68
- */
69
- var $key_length = 24;
70
-
71
- /**
72
- * The default salt used by setPassword()
73
- *
74
- * @see \phpseclib\Crypt\Base::password_default_salt
75
- * @see \phpseclib\Crypt\Base::setPassword()
76
- * @var string
77
- * @access private
78
- */
79
- var $password_default_salt = 'phpseclib';
80
-
81
- /**
82
- * The mcrypt specific name of the cipher
83
- *
84
- * @see \phpseclib\Crypt\DES::cipher_name_mcrypt
85
- * @see \phpseclib\Crypt\Base::cipher_name_mcrypt
86
- * @var string
87
- * @access private
88
- */
89
- var $cipher_name_mcrypt = 'tripledes';
90
-
91
- /**
92
- * Optimizing value while CFB-encrypting
93
- *
94
- * @see \phpseclib\Crypt\Base::cfb_init_len
95
- * @var int
96
- * @access private
97
- */
98
- var $cfb_init_len = 750;
99
-
100
- /**
101
- * max possible size of $key
102
- *
103
- * @see self::setKey()
104
- * @see \phpseclib\Crypt\DES::setKey()
105
- * @var string
106
- * @access private
107
- */
108
- var $key_length_max = 24;
109
-
110
- /**
111
- * Internal flag whether using self::MODE_3CBC or not
112
- *
113
- * @var bool
114
- * @access private
115
- */
116
- var $mode_3cbc;
117
-
118
- /**
119
- * The \phpseclib\Crypt\DES objects
120
- *
121
- * Used only if $mode_3cbc === true
122
- *
123
- * @var array
124
- * @access private
125
- */
126
- var $des;
127
-
128
- /**
129
- * Default Constructor.
130
- *
131
- * Determines whether or not the mcrypt extension should be used.
132
- *
133
- * $mode could be:
134
- *
135
- * - \phpseclib\Crypt\Base::MODE_ECB
136
- *
137
- * - \phpseclib\Crypt\Base::MODE_CBC
138
- *
139
- * - \phpseclib\Crypt\Base::MODE_CTR
140
- *
141
- * - \phpseclib\Crypt\Base::MODE_CFB
142
- *
143
- * - \phpseclib\Crypt\Base::MODE_OFB
144
- *
145
- * - \phpseclib\Crypt\TripleDES::MODE_3CBC
146
- *
147
- * If not explicitly set, \phpseclib\Crypt\Base::MODE_CBC will be used.
148
- *
149
- * @see \phpseclib\Crypt\DES::__construct()
150
- * @see \phpseclib\Crypt\Base::__construct()
151
- * @param int $mode
152
- * @access public
153
- */
154
- function __construct($mode = Base::MODE_CBC)
155
- {
156
- switch ($mode) {
157
- // In case of self::MODE_3CBC, we init as CRYPT_DES_MODE_CBC
158
- // and additional flag us internally as 3CBC
159
- case self::MODE_3CBC:
160
- parent::__construct(Base::MODE_CBC);
161
- $this->mode_3cbc = true;
162
-
163
- // This three $des'es will do the 3CBC work (if $key > 64bits)
164
- $this->des = array(
165
- new DES(Base::MODE_CBC),
166
- new DES(Base::MODE_CBC),
167
- new DES(Base::MODE_CBC),
168
- );
169
-
170
- // we're going to be doing the padding, ourselves, so disable it in the \phpseclib\Crypt\DES objects
171
- $this->des[0]->disablePadding();
172
- $this->des[1]->disablePadding();
173
- $this->des[2]->disablePadding();
174
- break;
175
- // If not 3CBC, we init as usual
176
- default:
177
- parent::__construct($mode);
178
- }
179
- }
180
-
181
- /**
182
- * Test for engine validity
183
- *
184
- * This is mainly just a wrapper to set things up for \phpseclib\Crypt\Base::isValidEngine()
185
- *
186
- * @see \phpseclib\Crypt\Base::__construct()
187
- * @param int $engine
188
- * @access public
189
- * @return bool
190
- */
191
- function isValidEngine($engine)
192
- {
193
- if ($engine == self::ENGINE_OPENSSL) {
194
- $this->cipher_name_openssl_ecb = 'des-ede3';
195
- $mode = $this->_openssl_translate_mode();
196
- $this->cipher_name_openssl = $mode == 'ecb' ? 'des-ede3' : 'des-ede3-' . $mode;
197
- }
198
-
199
- return parent::isValidEngine($engine);
200
- }
201
-
202
- /**
203
- * Sets the initialization vector. (optional)
204
- *
205
- * SetIV is not required when \phpseclib\Crypt\Base::MODE_ECB is being used. If not explicitly set, it'll be assumed
206
- * to be all zero's.
207
- *
208
- * @see \phpseclib\Crypt\Base::setIV()
209
- * @access public
210
- * @param string $iv
211
- */
212
- function setIV($iv)
213
- {
214
- parent::setIV($iv);
215
- if ($this->mode_3cbc) {
216
- $this->des[0]->setIV($iv);
217
- $this->des[1]->setIV($iv);
218
- $this->des[2]->setIV($iv);
219
- }
220
- }
221
-
222
- /**
223
- * Sets the key length.
224
- *
225
- * Valid key lengths are 64, 128 and 192
226
- *
227
- * @see \phpseclib\Crypt\Base:setKeyLength()
228
- * @access public
229
- * @param int $length
230
- */
231
- function setKeyLength($length)
232
- {
233
- $length >>= 3;
234
- switch (true) {
235
- case $length <= 8:
236
- $this->key_length = 8;
237
- break;
238
- case $length <= 16:
239
- $this->key_length = 16;
240
- break;
241
- default:
242
- $this->key_length = 24;
243
- }
244
-
245
- parent::setKeyLength($length);
246
- }
247
-
248
- /**
249
- * Sets the key.
250
- *
251
- * Keys can be of any length. Triple DES, itself, can use 128-bit (eg. strlen($key) == 16) or
252
- * 192-bit (eg. strlen($key) == 24) keys. This function pads and truncates $key as appropriate.
253
- *
254
- * DES also requires that every eighth bit be a parity bit, however, we'll ignore that.
255
- *
256
- * If the key is not explicitly set, it'll be assumed to be all null bytes.
257
- *
258
- * @access public
259
- * @see \phpseclib\Crypt\DES::setKey()
260
- * @see \phpseclib\Crypt\Base::setKey()
261
- * @param string $key
262
- */
263
- function setKey($key)
264
- {
265
- $length = $this->explicit_key_length ? $this->key_length : strlen($key);
266
- if ($length > 8) {
267
- $key = str_pad(substr($key, 0, 24), 24, chr(0));
268
- // if $key is between 64 and 128-bits, use the first 64-bits as the last, per this:
269
- // http://php.net/function.mcrypt-encrypt#47973
270
- $key = $length <= 16 ? substr_replace($key, substr($key, 0, 8), 16) : substr($key, 0, 24);
271
- } else {
272
- $key = str_pad($key, 8, chr(0));
273
- }
274
- parent::setKey($key);
275
-
276
- // And in case of self::MODE_3CBC:
277
- // if key <= 64bits we not need the 3 $des to work,
278
- // because we will then act as regular DES-CBC with just a <= 64bit key.
279
- // So only if the key > 64bits (> 8 bytes) we will call setKey() for the 3 $des.
280
- if ($this->mode_3cbc && $length > 8) {
281
- $this->des[0]->setKey(substr($key, 0, 8));
282
- $this->des[1]->setKey(substr($key, 8, 8));
283
- $this->des[2]->setKey(substr($key, 16, 8));
284
- }
285
- }
286
-
287
- /**
288
- * Encrypts a message.
289
- *
290
- * @see \phpseclib\Crypt\Base::encrypt()
291
- * @access public
292
- * @param string $plaintext
293
- * @return string $cipertext
294
- */
295
- function encrypt($plaintext)
296
- {
297
- // parent::en/decrypt() is able to do all the work for all modes and keylengths,
298
- // except for: self::MODE_3CBC (inner chaining CBC) with a key > 64bits
299
-
300
- // if the key is smaller then 8, do what we'd normally do
301
- if ($this->mode_3cbc && strlen($this->key) > 8) {
302
- return $this->des[2]->encrypt(
303
- $this->des[1]->decrypt(
304
- $this->des[0]->encrypt(
305
- $this->_pad($plaintext)
306
- )
307
- )
308
- );
309
- }
310
-
311
- return parent::encrypt($plaintext);
312
- }
313
-
314
- /**
315
- * Decrypts a message.
316
- *
317
- * @see \phpseclib\Crypt\Base::decrypt()
318
- * @access public
319
- * @param string $ciphertext
320
- * @return string $plaintext
321
- */
322
- function decrypt($ciphertext)
323
- {
324
- if ($this->mode_3cbc && strlen($this->key) > 8) {
325
- return $this->_unpad(
326
- $this->des[0]->decrypt(
327
- $this->des[1]->encrypt(
328
- $this->des[2]->decrypt(
329
- str_pad($ciphertext, (strlen($ciphertext) + 7) & 0xFFFFFFF8, "\0")
330
- )
331
- )
332
- )
333
- );
334
- }
335
-
336
- return parent::decrypt($ciphertext);
337
- }
338
-
339
- /**
340
- * Treat consecutive "packets" as if they are a continuous buffer.
341
- *
342
- * Say you have a 16-byte plaintext $plaintext. Using the default behavior, the two following code snippets
343
- * will yield different outputs:
344
- *
345
- * <code>
346
- * echo $des->encrypt(substr($plaintext, 0, 8));
347
- * echo $des->encrypt(substr($plaintext, 8, 8));
348
- * </code>
349
- * <code>
350
- * echo $des->encrypt($plaintext);
351
- * </code>
352
- *
353
- * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates
354
- * another, as demonstrated with the following:
355
- *
356
- * <code>
357
- * $des->encrypt(substr($plaintext, 0, 8));
358
- * echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8)));
359
- * </code>
360
- * <code>
361
- * echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8)));
362
- * </code>
363
- *
364
- * With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different
365
- * outputs. The reason is due to the fact that the initialization vector's change after every encryption /
366
- * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant.
367
- *
368
- * Put another way, when the continuous buffer is enabled, the state of the \phpseclib\Crypt\DES() object changes after each
369
- * encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that
370
- * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them),
371
- * however, they are also less intuitive and more likely to cause you problems.
372
- *
373
- * @see \phpseclib\Crypt\Base::enableContinuousBuffer()
374
- * @see self::disableContinuousBuffer()
375
- * @access public
376
- */
377
- function enableContinuousBuffer()
378
- {
379
- parent::enableContinuousBuffer();
380
- if ($this->mode_3cbc) {
381
- $this->des[0]->enableContinuousBuffer();
382
- $this->des[1]->enableContinuousBuffer();
383
- $this->des[2]->enableContinuousBuffer();
384
- }
385
- }
386
-
387
- /**
388
- * Treat consecutive packets as if they are a discontinuous buffer.
389
- *
390
- * The default behavior.
391
- *
392
- * @see \phpseclib\Crypt\Base::disableContinuousBuffer()
393
- * @see self::enableContinuousBuffer()
394
- * @access public
395
- */
396
- function disableContinuousBuffer()
397
- {
398
- parent::disableContinuousBuffer();
399
- if ($this->mode_3cbc) {
400
- $this->des[0]->disableContinuousBuffer();
401
- $this->des[1]->disableContinuousBuffer();
402
- $this->des[2]->disableContinuousBuffer();
403
- }
404
- }
405
-
406
- /**
407
- * Creates the key schedule
408
- *
409
- * @see \phpseclib\Crypt\DES::_setupKey()
410
- * @see \phpseclib\Crypt\Base::_setupKey()
411
- * @access private
412
- */
413
- function _setupKey()
414
- {
415
- switch (true) {
416
- // if $key <= 64bits we configure our internal pure-php cipher engine
417
- // to act as regular [1]DES, not as 3DES. mcrypt.so::tripledes does the same.
418
- case strlen($this->key) <= 8:
419
- $this->des_rounds = 1;
420
- break;
421
-
422
- // otherwise, if $key > 64bits, we configure our engine to work as 3DES.
423
- default:
424
- $this->des_rounds = 3;
425
-
426
- // (only) if 3CBC is used we have, of course, to setup the $des[0-2] keys also separately.
427
- if ($this->mode_3cbc) {
428
- $this->des[0]->_setupKey();
429
- $this->des[1]->_setupKey();
430
- $this->des[2]->_setupKey();
431
-
432
- // because $des[0-2] will, now, do all the work we can return here
433
- // not need unnecessary stress parent::_setupKey() with our, now unused, $key.
434
- return;
435
- }
436
- }
437
- // setup our key
438
- parent::_setupKey();
439
- }
440
-
441
- /**
442
- * Sets the internal crypt engine
443
- *
444
- * @see \phpseclib\Crypt\Base::__construct()
445
- * @see \phpseclib\Crypt\Base::setPreferredEngine()
446
- * @param int $engine
447
- * @access public
448
- * @return int
449
- */
450
- function setPreferredEngine($engine)
451
- {
452
- if ($this->mode_3cbc) {
453
- $this->des[0]->setPreferredEngine($engine);
454
- $this->des[1]->setPreferredEngine($engine);
455
- $this->des[2]->setPreferredEngine($engine);
456
- }
457
-
458
- return parent::setPreferredEngine($engine);
459
- }
460
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/phpseclib/phpseclib/phpseclib/Crypt/Twofish.php DELETED
@@ -1,808 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Pure-PHP implementation of Twofish.
5
- *
6
- * Uses mcrypt, if available, and an internal implementation, otherwise.
7
- *
8
- * PHP version 5
9
- *
10
- * Useful resources are as follows:
11
- *
12
- * - {@link http://en.wikipedia.org/wiki/Twofish Wikipedia description of Twofish}
13
- *
14
- * Here's a short example of how to use this library:
15
- * <code>
16
- * <?php
17
- * include 'vendor/autoload.php';
18
- *
19
- * $twofish = new \phpseclib\Crypt\Twofish();
20
- *
21
- * $twofish->setKey('12345678901234567890123456789012');
22
- *
23
- * $plaintext = str_repeat('a', 1024);
24
- *
25
- * echo $twofish->decrypt($twofish->encrypt($plaintext));
26
- * ?>
27
- * </code>
28
- *
29
- * @category Crypt
30
- * @package Twofish
31
- * @author Jim Wigginton <terrafrost@php.net>
32
- * @author Hans-Juergen Petrich <petrich@tronic-media.com>
33
- * @copyright 2007 Jim Wigginton
34
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
35
- * @link http://phpseclib.sourceforge.net
36
- */
37
-
38
- namespace phpseclib\Crypt;
39
-
40
- /**
41
- * Pure-PHP implementation of Twofish.
42
- *
43
- * @package Twofish
44
- * @author Jim Wigginton <terrafrost@php.net>
45
- * @author Hans-Juergen Petrich <petrich@tronic-media.com>
46
- * @access public
47
- */
48
- class Twofish extends Base
49
- {
50
- /**
51
- * The mcrypt specific name of the cipher
52
- *
53
- * @see \phpseclib\Crypt\Base::cipher_name_mcrypt
54
- * @var string
55
- * @access private
56
- */
57
- var $cipher_name_mcrypt = 'twofish';
58
-
59
- /**
60
- * Optimizing value while CFB-encrypting
61
- *
62
- * @see \phpseclib\Crypt\Base::cfb_init_len
63
- * @var int
64
- * @access private
65
- */
66
- var $cfb_init_len = 800;
67
-
68
- /**
69
- * Q-Table
70
- *
71
- * @var array
72
- * @access private
73
- */
74
- var $q0 = array(
75
- 0xA9, 0x67, 0xB3, 0xE8, 0x04, 0xFD, 0xA3, 0x76,
76
- 0x9A, 0x92, 0x80, 0x78, 0xE4, 0xDD, 0xD1, 0x38,
77
- 0x0D, 0xC6, 0x35, 0x98, 0x18, 0xF7, 0xEC, 0x6C,
78
- 0x43, 0x75, 0x37, 0x26, 0xFA, 0x13, 0x94, 0x48,
79
- 0xF2, 0xD0, 0x8B, 0x30, 0x84, 0x54, 0xDF, 0x23,
80
- 0x19, 0x5B, 0x3D, 0x59, 0xF3, 0xAE, 0xA2, 0x82,
81
- 0x63, 0x01, 0x83, 0x2E, 0xD9, 0x51, 0x9B, 0x7C,
82
- 0xA6, 0xEB, 0xA5, 0xBE, 0x16, 0x0C, 0xE3, 0x61,
83
- 0xC0, 0x8C, 0x3A, 0xF5, 0x73, 0x2C, 0x25, 0x0B,
84
- 0xBB, 0x4E, 0x89, 0x6B, 0x53, 0x6A, 0xB4, 0xF1,
85
- 0xE1, 0xE6, 0xBD, 0x45, 0xE2, 0xF4, 0xB6, 0x66,
86
- 0xCC, 0x95, 0x03, 0x56, 0xD4, 0x1C, 0x1E, 0xD7,
87
- 0xFB, 0xC3, 0x8E, 0xB5, 0xE9, 0xCF, 0xBF, 0xBA,
88
- 0xEA, 0x77, 0x39, 0xAF, 0x33, 0xC9, 0x62, 0x71,
89
- 0x81, 0x79, 0x09, 0xAD, 0x24, 0xCD, 0xF9, 0xD8,
90
- 0xE5, 0xC5, 0xB9, 0x4D, 0x44, 0x08, 0x86, 0xE7,
91
- 0xA1, 0x1D, 0xAA, 0xED, 0x06, 0x70, 0xB2, 0xD2,
92
- 0x41, 0x7B, 0xA0, 0x11, 0x31, 0xC2, 0x27, 0x90,
93
- 0x20, 0xF6, 0x60, 0xFF, 0x96, 0x5C, 0xB1, 0xAB,
94
- 0x9E, 0x9C, 0x52, 0x1B, 0x5F, 0x93, 0x0A, 0xEF,
95
- 0x91, 0x85, 0x49, 0xEE, 0x2D, 0x4F, 0x8F, 0x3B,
96
- 0x47, 0x87, 0x6D, 0x46, 0xD6, 0x3E, 0x69, 0x64,
97
- 0x2A, 0xCE, 0xCB, 0x2F, 0xFC, 0x97, 0x05, 0x7A,
98
- 0xAC, 0x7F, 0xD5, 0x1A, 0x4B, 0x0E, 0xA7, 0x5A,
99
- 0x28, 0x14, 0x3F, 0x29, 0x88, 0x3C, 0x4C, 0x02,
100
- 0xB8, 0xDA, 0xB0, 0x17, 0x55, 0x1F, 0x8A, 0x7D,
101
- 0x57, 0xC7, 0x8D, 0x74, 0xB7, 0xC4, 0x9F, 0x72,
102
- 0x7E, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34,
103
- 0x6E, 0x50, 0xDE, 0x68, 0x65, 0xBC, 0xDB, 0xF8,
104
- 0xC8, 0xA8, 0x2B, 0x40, 0xDC, 0xFE, 0x32, 0xA4,
105
- 0xCA, 0x10, 0x21, 0xF0, 0xD3, 0x5D, 0x0F, 0x00,
106
- 0x6F, 0x9D, 0x36, 0x42, 0x4A, 0x5E, 0xC1, 0xE0
107
- );
108
-
109
- /**
110
- * Q-Table
111
- *
112
- * @var array
113
- * @access private
114
- */
115
- var $q1 = array(
116
- 0x75, 0xF3, 0xC6, 0xF4, 0xDB, 0x7B, 0xFB, 0xC8,
117
- 0x4A, 0xD3, 0xE6, 0x6B, 0x45, 0x7D, 0xE8, 0x4B,
118
- 0xD6, 0x32, 0xD8, 0xFD, 0x37, 0x71, 0xF1, 0xE1,
119
- 0x30, 0x0F, 0xF8, 0x1B, 0x87, 0xFA, 0x06, 0x3F,
120
- 0x5E, 0xBA, 0xAE, 0x5B, 0x8A, 0x00, 0xBC, 0x9D,
121
- 0x6D, 0xC1, 0xB1, 0x0E, 0x80, 0x5D, 0xD2, 0xD5,
122
- 0xA0, 0x84, 0x07, 0x14, 0xB5, 0x90, 0x2C, 0xA3,
123
- 0xB2, 0x73, 0x4C, 0x54, 0x92, 0x74, 0x36, 0x51,
124
- 0x38, 0xB0, 0xBD, 0x5A, 0xFC, 0x60, 0x62, 0x96,
125
- 0x6C, 0x42, 0xF7, 0x10, 0x7C, 0x28, 0x27, 0x8C,
126
- 0x13, 0x95, 0x9C, 0xC7, 0x24, 0x46, 0x3B, 0x70,
127
- 0xCA, 0xE3, 0x85, 0xCB, 0x11, 0xD0, 0x93, 0xB8,
128
- 0xA6, 0x83, 0x20, 0xFF, 0x9F, 0x77, 0xC3, 0xCC,
129
- 0x03, 0x6F, 0x08, 0xBF, 0x40, 0xE7, 0x2B, 0xE2,
130
- 0x79, 0x0C, 0xAA, 0x82, 0x41, 0x3A, 0xEA, 0xB9,
131
- 0xE4, 0x9A, 0xA4, 0x97, 0x7E, 0xDA, 0x7A, 0x17,
132
- 0x66, 0x94, 0xA1, 0x1D, 0x3D, 0xF0, 0xDE, 0xB3,
133
- 0x0B, 0x72, 0xA7, 0x1C, 0xEF, 0xD1, 0x53, 0x3E,
134
- 0x8F, 0x33, 0x26, 0x5F, 0xEC, 0x76, 0x2A, 0x49,
135
- 0x81, 0x88, 0xEE, 0x21, 0xC4, 0x1A, 0xEB, 0xD9,
136
- 0xC5, 0x39, 0x99, 0xCD, 0xAD, 0x31, 0x8B, 0x01,
137
- 0x18, 0x23, 0xDD, 0x1F, 0x4E, 0x2D, 0xF9, 0x48,
138
- 0x4F, 0xF2, 0x65, 0x8E, 0x78, 0x5C, 0x58, 0x19,
139
- 0x8D, 0xE5, 0x98, 0x57, 0x67, 0x7F, 0x05, 0x64,
140
- 0xAF, 0x63, 0xB6, 0xFE, 0xF5, 0xB7, 0x3C, 0xA5,
141
- 0xCE, 0xE9, 0x68, 0x44, 0xE0, 0x4D, 0x43, 0x69,
142
- 0x29, 0x2E, 0xAC, 0x15, 0x59, 0xA8, 0x0A, 0x9E,
143
- 0x6E, 0x47, 0xDF, 0x34, 0x35, 0x6A, 0xCF, 0xDC,
144
- 0x22, 0xC9, 0xC0, 0x9B, 0x89, 0xD4, 0xED, 0xAB,
145
- 0x12, 0xA2, 0x0D, 0x52, 0xBB, 0x02, 0x2F, 0xA9,
146
- 0xD7, 0x61, 0x1E, 0xB4, 0x50, 0x04, 0xF6, 0xC2,
147
- 0x16, 0x25, 0x86, 0x56, 0x55, 0x09, 0xBE, 0x91
148
- );
149
-
150
- /**
151
- * M-Table
152
- *
153
- * @var array
154
- * @access private
155
- */
156
- var $m0 = array(
157
- 0xBCBC3275, 0xECEC21F3, 0x202043C6, 0xB3B3C9F4, 0xDADA03DB, 0x02028B7B, 0xE2E22BFB, 0x9E9EFAC8,
158
- 0xC9C9EC4A, 0xD4D409D3, 0x18186BE6, 0x1E1E9F6B, 0x98980E45, 0xB2B2387D, 0xA6A6D2E8, 0x2626B74B,
159
- 0x3C3C57D6, 0x93938A32, 0x8282EED8, 0x525298FD, 0x7B7BD437, 0xBBBB3771, 0x5B5B97F1, 0x474783E1,
160
- 0x24243C30, 0x5151E20F, 0xBABAC6F8, 0x4A4AF31B, 0xBFBF4887, 0x0D0D70FA, 0xB0B0B306, 0x7575DE3F,
161
- 0xD2D2FD5E, 0x7D7D20BA, 0x666631AE, 0x3A3AA35B, 0x59591C8A, 0x00000000, 0xCDCD93BC, 0x1A1AE09D,
162
- 0xAEAE2C6D, 0x7F7FABC1, 0x2B2BC7B1, 0xBEBEB90E, 0xE0E0A080, 0x8A8A105D, 0x3B3B52D2, 0x6464BAD5,
163
- 0xD8D888A0, 0xE7E7A584, 0x5F5FE807, 0x1B1B1114, 0x2C2CC2B5, 0xFCFCB490, 0x3131272C, 0x808065A3,
164
- 0x73732AB2, 0x0C0C8173, 0x79795F4C, 0x6B6B4154, 0x4B4B0292, 0x53536974, 0x94948F36, 0x83831F51,
165
- 0x2A2A3638, 0xC4C49CB0, 0x2222C8BD, 0xD5D5F85A, 0xBDBDC3FC, 0x48487860, 0xFFFFCE62, 0x4C4C0796,
166
- 0x4141776C, 0xC7C7E642, 0xEBEB24F7, 0x1C1C1410, 0x5D5D637C, 0x36362228, 0x6767C027, 0xE9E9AF8C,
167
- 0x4444F913, 0x1414EA95, 0xF5F5BB9C, 0xCFCF18C7, 0x3F3F2D24, 0xC0C0E346, 0x7272DB3B, 0x54546C70,
168
- 0x29294CCA, 0xF0F035E3, 0x0808FE85, 0xC6C617CB, 0xF3F34F11, 0x8C8CE4D0, 0xA4A45993, 0xCACA96B8,
169
- 0x68683BA6, 0xB8B84D83, 0x38382820, 0xE5E52EFF, 0xADAD569F, 0x0B0B8477, 0xC8C81DC3, 0x9999FFCC,
170
- 0x5858ED03, 0x19199A6F, 0x0E0E0A08, 0x95957EBF, 0x70705040, 0xF7F730E7, 0x6E6ECF2B, 0x1F1F6EE2,
171
- 0xB5B53D79, 0x09090F0C, 0x616134AA, 0x57571682, 0x9F9F0B41, 0x9D9D803A, 0x111164EA, 0x2525CDB9,
172
- 0xAFAFDDE4, 0x4545089A, 0xDFDF8DA4, 0xA3A35C97, 0xEAEAD57E, 0x353558DA, 0xEDEDD07A, 0x4343FC17,
173
- 0xF8F8CB66, 0xFBFBB194, 0x3737D3A1, 0xFAFA401D, 0xC2C2683D, 0xB4B4CCF0, 0x32325DDE, 0x9C9C71B3,
174
- 0x5656E70B, 0xE3E3DA72, 0x878760A7, 0x15151B1C, 0xF9F93AEF, 0x6363BFD1, 0x3434A953, 0x9A9A853E,
175
- 0xB1B1428F, 0x7C7CD133, 0x88889B26, 0x3D3DA65F, 0xA1A1D7EC, 0xE4E4DF76, 0x8181942A, 0x91910149,
176
- 0x0F0FFB81, 0xEEEEAA88, 0x161661EE, 0xD7D77321, 0x9797F5C4, 0xA5A5A81A, 0xFEFE3FEB, 0x6D6DB5D9,
177
- 0x7878AEC5, 0xC5C56D39, 0x1D1DE599, 0x7676A4CD, 0x3E3EDCAD, 0xCBCB6731, 0xB6B6478B, 0xEFEF5B01,
178
- 0x12121E18, 0x6060C523, 0x6A6AB0DD, 0x4D4DF61F, 0xCECEE94E, 0xDEDE7C2D, 0x55559DF9, 0x7E7E5A48,
179
- 0x2121B24F, 0x03037AF2, 0xA0A02665, 0x5E5E198E, 0x5A5A6678, 0x65654B5C, 0x62624E58, 0xFDFD4519,
180
- 0x0606F48D, 0x404086E5, 0xF2F2BE98, 0x3333AC57, 0x17179067, 0x05058E7F, 0xE8E85E05, 0x4F4F7D64,
181
- 0x89896AAF, 0x10109563, 0x74742FB6, 0x0A0A75FE, 0x5C5C92F5, 0x9B9B74B7, 0x2D2D333C, 0x3030D6A5,
182
- 0x2E2E49CE, 0x494989E9, 0x46467268, 0x77775544, 0xA8A8D8E0, 0x9696044D, 0x2828BD43, 0xA9A92969,
183
- 0xD9D97929, 0x8686912E, 0xD1D187AC, 0xF4F44A15, 0x8D8D1559, 0xD6D682A8, 0xB9B9BC0A, 0x42420D9E,
184
- 0xF6F6C16E, 0x2F2FB847, 0xDDDD06DF, 0x23233934, 0xCCCC6235, 0xF1F1C46A, 0xC1C112CF, 0x8585EBDC,
185
- 0x8F8F9E22, 0x7171A1C9, 0x9090F0C0, 0xAAAA539B, 0x0101F189, 0x8B8BE1D4, 0x4E4E8CED, 0x8E8E6FAB,
186
- 0xABABA212, 0x6F6F3EA2, 0xE6E6540D, 0xDBDBF252, 0x92927BBB, 0xB7B7B602, 0x6969CA2F, 0x3939D9A9,
187
- 0xD3D30CD7, 0xA7A72361, 0xA2A2AD1E, 0xC3C399B4, 0x6C6C4450, 0x07070504, 0x04047FF6, 0x272746C2,
188
- 0xACACA716, 0xD0D07625, 0x50501386, 0xDCDCF756, 0x84841A55, 0xE1E15109, 0x7A7A25BE, 0x1313EF91
189
- );
190
-
191
- /**
192
- * M-Table
193
- *
194
- * @var array
195
- * @access private
196
- */
197
- var $m1 = array(
198
- 0xA9D93939, 0x67901717, 0xB3719C9C, 0xE8D2A6A6, 0x04050707, 0xFD985252, 0xA3658080, 0x76DFE4E4,
199
- 0x9A084545, 0x92024B4B, 0x80A0E0E0, 0x78665A5A, 0xE4DDAFAF, 0xDDB06A6A, 0xD1BF6363, 0x38362A2A,
200
- 0x0D54E6E6, 0xC6432020, 0x3562CCCC, 0x98BEF2F2, 0x181E1212, 0xF724EBEB, 0xECD7A1A1, 0x6C774141,
201
- 0x43BD2828, 0x7532BCBC, 0x37D47B7B, 0x269B8888, 0xFA700D0D, 0x13F94444, 0x94B1FBFB, 0x485A7E7E,
202
- 0xF27A0303, 0xD0E48C8C, 0x8B47B6B6, 0x303C2424, 0x84A5E7E7, 0x54416B6B, 0xDF06DDDD, 0x23C56060,
203
- 0x1945FDFD, 0x5BA33A3A, 0x3D68C2C2, 0x59158D8D, 0xF321ECEC, 0xAE316666, 0xA23E6F6F, 0x82165757,
204
- 0x63951010, 0x015BEFEF, 0x834DB8B8, 0x2E918686, 0xD9B56D6D, 0x511F8383, 0x9B53AAAA, 0x7C635D5D,
205
- 0xA63B6868, 0xEB3FFEFE, 0xA5D63030, 0xBE257A7A, 0x16A7ACAC, 0x0C0F0909, 0xE335F0F0, 0x6123A7A7,
206
- 0xC0F09090, 0x8CAFE9E9, 0x3A809D9D, 0xF5925C5C, 0x73810C0C, 0x2C273131, 0x2576D0D0, 0x0BE75656,
207
- 0xBB7B9292, 0x4EE9CECE, 0x89F10101, 0x6B9F1E1E, 0x53A93434, 0x6AC4F1F1, 0xB499C3C3, 0xF1975B5B,
208
- 0xE1834747, 0xE66B1818, 0xBDC82222, 0x450E9898, 0xE26E1F1F, 0xF4C9B3B3, 0xB62F7474, 0x66CBF8F8,
209
- 0xCCFF9999, 0x95EA1414, 0x03ED5858, 0x56F7DCDC, 0xD4E18B8B, 0x1C1B1515, 0x1EADA2A2, 0xD70CD3D3,
210
- 0xFB2BE2E2, 0xC31DC8C8, 0x8E195E5E, 0xB5C22C2C, 0xE9894949, 0xCF12C1C1, 0xBF7E9595, 0xBA207D7D,
211
- 0xEA641111, 0x77840B0B, 0x396DC5C5, 0xAF6A8989, 0x33D17C7C, 0xC9A17171, 0x62CEFFFF, 0x7137BBBB,
212
- 0x81FB0F0F, 0x793DB5B5, 0x0951E1E1, 0xADDC3E3E, 0x242D3F3F, 0xCDA47676, 0xF99D5555, 0xD8EE8282,
213
- 0xE5864040, 0xC5AE7878, 0xB9CD2525, 0x4D049696, 0x44557777, 0x080A0E0E, 0x86135050, 0xE730F7F7,
214
- 0xA1D33737, 0x1D40FAFA, 0xAA346161, 0xED8C4E4E, 0x06B3B0B0, 0x706C5454, 0xB22A7373, 0xD2523B3B,
215
- 0x410B9F9F, 0x7B8B0202, 0xA088D8D8, 0x114FF3F3, 0x3167CBCB, 0xC2462727, 0x27C06767, 0x90B4FCFC,
216
- 0x20283838, 0xF67F0404, 0x60784848, 0xFF2EE5E5, 0x96074C4C, 0x5C4B6565, 0xB1C72B2B, 0xAB6F8E8E,
217
- 0x9E0D4242, 0x9CBBF5F5, 0x52F2DBDB, 0x1BF34A4A, 0x5FA63D3D, 0x9359A4A4, 0x0ABCB9B9, 0xEF3AF9F9,
218
- 0x91EF1313, 0x85FE0808, 0x49019191, 0xEE611616, 0x2D7CDEDE, 0x4FB22121, 0x8F42B1B1, 0x3BDB7272,
219
- 0x47B82F2F, 0x8748BFBF, 0x6D2CAEAE, 0x46E3C0C0, 0xD6573C3C, 0x3E859A9A, 0x6929A9A9, 0x647D4F4F,
220
- 0x2A948181, 0xCE492E2E, 0xCB17C6C6, 0x2FCA6969, 0xFCC3BDBD, 0x975CA3A3, 0x055EE8E8, 0x7AD0EDED,
221
- 0xAC87D1D1, 0x7F8E0505, 0xD5BA6464, 0x1AA8A5A5, 0x4BB72626, 0x0EB9BEBE, 0xA7608787, 0x5AF8D5D5,
222
- 0x28223636, 0x14111B1B, 0x3FDE7575, 0x2979D9D9, 0x88AAEEEE, 0x3C332D2D, 0x4C5F7979, 0x02B6B7B7,
223
- 0xB896CACA, 0xDA583535, 0xB09CC4C4, 0x17FC4343, 0x551A8484, 0x1FF64D4D, 0x8A1C5959, 0x7D38B2B2,
224
- 0x57AC3333, 0xC718CFCF, 0x8DF40606, 0x74695353, 0xB7749B9B, 0xC4F59797, 0x9F56ADAD, 0x72DAE3E3,
225
- 0x7ED5EAEA, 0x154AF4F4, 0x229E8F8F, 0x12A2ABAB, 0x584E6262, 0x07E85F5F, 0x99E51D1D, 0x34392323,
226
- 0x6EC1F6F6, 0x50446C6C, 0xDE5D3232, 0x68724646, 0x6526A0A0, 0xBC93CDCD, 0xDB03DADA, 0xF8C6BABA,
227
- 0xC8FA9E9E, 0xA882D6D6, 0x2BCF6E6E, 0x40507070, 0xDCEB8585, 0xFE750A0A, 0x328A9393, 0xA48DDFDF,
228
- 0xCA4C2929, 0x10141C1C, 0x2173D7D7, 0xF0CCB4B4, 0xD309D4D4, 0x5D108A8A, 0x0FE25151, 0x00000000,
229
- 0x6F9A1919, 0x9DE01A1A, 0x368F9494, 0x42E6C7C7, 0x4AECC9C9, 0x5EFDD2D2, 0xC1AB7F7F, 0xE0D8A8A8
230
- );
231
-
232
- /**
233
- * M-Table
234
- *
235
- * @var array
236
- * @access private
237
- */
238
- var $m2 = array(
239
- 0xBC75BC32, 0xECF3EC21, 0x20C62043, 0xB3F4B3C9, 0xDADBDA03, 0x027B028B, 0xE2FBE22B, 0x9EC89EFA,
240
- 0xC94AC9EC, 0xD4D3D409, 0x18E6186B, 0x1E6B1E9F, 0x9845980E, 0xB27DB238, 0xA6E8A6D2, 0x264B26B7,
241
- 0x3CD63C57, 0x9332938A, 0x82D882EE, 0x52FD5298, 0x7B377BD4, 0xBB71BB37, 0x5BF15B97, 0x47E14783,
242
- 0x2430243C, 0x510F51E2, 0xBAF8BAC6, 0x4A1B4AF3, 0xBF87BF48, 0x0DFA0D70, 0xB006B0B3, 0x753F75DE,
243
- 0xD25ED2FD, 0x7DBA7D20, 0x66AE6631, 0x3A5B3AA3, 0x598A591C, 0x00000000, 0xCDBCCD93, 0x1A9D1AE0,
244
- 0xAE6DAE2C, 0x7FC17FAB, 0x2BB12BC7, 0xBE0EBEB9, 0xE080E0A0, 0x8A5D8A10, 0x3BD23B52, 0x64D564BA,
245
- 0xD8A0D888, 0xE784E7A5, 0x5F075FE8, 0x1B141B11, 0x2CB52CC2, 0xFC90FCB4, 0x312C3127, 0x80A38065,
246
- 0x73B2732A, 0x0C730C81, 0x794C795F, 0x6B546B41, 0x4B924B02, 0x53745369, 0x9436948F, 0x8351831F,
247
- 0x2A382A36, 0xC4B0C49C, 0x22BD22C8, 0xD55AD5F8, 0xBDFCBDC3, 0x48604878, 0xFF62FFCE, 0x4C964C07,
248
- 0x416C4177, 0xC742C7E6, 0xEBF7EB24, 0x1C101C14, 0x5D7C5D63, 0x36283622, 0x672767C0, 0xE98CE9AF,
249
- 0x441344F9, 0x149514EA, 0xF59CF5BB, 0xCFC7CF18, 0x3F243F2D, 0xC046C0E3, 0x723B72DB, 0x5470546C,
250
- 0x29CA294C, 0xF0E3F035, 0x088508FE, 0xC6CBC617, 0xF311F34F, 0x8CD08CE4, 0xA493A459, 0xCAB8CA96,
251
- 0x68A6683B, 0xB883B84D, 0x38203828, 0xE5FFE52E, 0xAD9FAD56, 0x0B770B84, 0xC8C3C81D, 0x99CC99FF,
252
- 0x580358ED, 0x196F199A, 0x0E080E0A, 0x95BF957E, 0x70407050, 0xF7E7F730, 0x6E2B6ECF, 0x1FE21F6E,
253
- 0xB579B53D, 0x090C090F, 0x61AA6134, 0x57825716, 0x9F419F0B, 0x9D3A9D80, 0x11EA1164, 0x25B925CD,
254
- 0xAFE4AFDD, 0x459A4508, 0xDFA4DF8D, 0xA397A35C, 0xEA7EEAD5, 0x35DA3558, 0xED7AEDD0, 0x431743FC,
255
- 0xF866F8CB, 0xFB94FBB1, 0x37A137D3, 0xFA1DFA40, 0xC23DC268, 0xB4F0B4CC, 0x32DE325D, 0x9CB39C71,
256
- 0x560B56E7, 0xE372E3DA, 0x87A78760, 0x151C151B, 0xF9EFF93A, 0x63D163BF, 0x345334A9, 0x9A3E9A85,
257
- 0xB18FB142, 0x7C337CD1, 0x8826889B, 0x3D5F3DA6, 0xA1ECA1D7, 0xE476E4DF, 0x812A8194, 0x91499101,
258
- 0x0F810FFB, 0xEE88EEAA, 0x16EE1661, 0xD721D773, 0x97C497F5, 0xA51AA5A8, 0xFEEBFE3F, 0x6DD96DB5,
259
- 0x78C578AE, 0xC539C56D, 0x1D991DE5, 0x76CD76A4, 0x3EAD3EDC, 0xCB31CB67, 0xB68BB647, 0xEF01EF5B,
260
- 0x1218121E, 0x602360C5, 0x6ADD6AB0, 0x4D1F4DF6, 0xCE4ECEE9, 0xDE2DDE7C, 0x55F9559D, 0x7E487E5A,
261
- 0x214F21B2, 0x03F2037A, 0xA065A026, 0x5E8E5E19, 0x5A785A66, 0x655C654B, 0x6258624E, 0xFD19FD45,
262
- 0x068D06F4, 0x40E54086, 0xF298F2BE, 0x335733AC, 0x17671790, 0x057F058E, 0xE805E85E, 0x4F644F7D,
263
- 0x89AF896A, 0x10631095, 0x74B6742F, 0x0AFE0A75, 0x5CF55C92, 0x9BB79B74, 0x2D3C2D33, 0x30A530D6,
264
- 0x2ECE2E49, 0x49E94989, 0x46684672, 0x77447755, 0xA8E0A8D8, 0x964D9604, 0x284328BD, 0xA969A929,
265
- 0xD929D979, 0x862E8691, 0xD1ACD187, 0xF415F44A, 0x8D598D15, 0xD6A8D682, 0xB90AB9BC, 0x429E420D,
266
- 0xF66EF6C1, 0x2F472FB8, 0xDDDFDD06, 0x23342339, 0xCC35CC62, 0xF16AF1C4, 0xC1CFC112, 0x85DC85EB,
267
- 0x8F228F9E, 0x71C971A1, 0x90C090F0, 0xAA9BAA53, 0x018901F1, 0x8BD48BE1, 0x4EED4E8C, 0x8EAB8E6F,
268
- 0xAB12ABA2, 0x6FA26F3E, 0xE60DE654, 0xDB52DBF2, 0x92BB927B, 0xB702B7B6, 0x692F69CA, 0x39A939D9,
269
- 0xD3D7D30C, 0xA761A723, 0xA21EA2AD, 0xC3B4C399, 0x6C506C44, 0x07040705, 0x04F6047F, 0x27C22746,
270
- 0xAC16ACA7, 0xD025D076, 0x50865013, 0xDC56DCF7, 0x8455841A, 0xE109E151, 0x7ABE7A25, 0x139113EF
271
- );
272
-
273
- /**
274
- * M-Table
275
- *
276
- * @var array
277
- * @access private
278
- */
279
- var $m3 = array(
280
- 0xD939A9D9, 0x90176790, 0x719CB371, 0xD2A6E8D2, 0x05070405, 0x9852FD98, 0x6580A365, 0xDFE476DF,
281
- 0x08459A08, 0x024B9202, 0xA0E080A0, 0x665A7866, 0xDDAFE4DD, 0xB06ADDB0, 0xBF63D1BF, 0x362A3836,
282
- 0x54E60D54, 0x4320C643, 0x62CC3562, 0xBEF298BE, 0x1E12181E, 0x24EBF724, 0xD7A1ECD7, 0x77416C77,
283
- 0xBD2843BD, 0x32BC7532, 0xD47B37D4, 0x9B88269B, 0x700DFA70, 0xF94413F9, 0xB1FB94B1, 0x5A7E485A,
284
- 0x7A03F27A, 0xE48CD0E4, 0x47B68B47, 0x3C24303C, 0xA5E784A5, 0x416B5441, 0x06DDDF06, 0xC56023C5,
285
- 0x45FD1945, 0xA33A5BA3, 0x68C23D68, 0x158D5915, 0x21ECF321, 0x3166AE31, 0x3E6FA23E, 0x16578216,
286
- 0x95106395, 0x5BEF015B, 0x4DB8834D, 0x91862E91, 0xB56DD9B5, 0x1F83511F, 0x53AA9B53, 0x635D7C63,
287
- 0x3B68A63B, 0x3FFEEB3F, 0xD630A5D6, 0x257ABE25, 0xA7AC16A7, 0x0F090C0F, 0x35F0E335, 0x23A76123,
288
- 0xF090C0F0, 0xAFE98CAF, 0x809D3A80, 0x925CF592, 0x810C7381, 0x27312C27, 0x76D02576, 0xE7560BE7,
289
- 0x7B92BB7B, 0xE9CE4EE9, 0xF10189F1, 0x9F1E6B9F, 0xA93453A9, 0xC4F16AC4, 0x99C3B499, 0x975BF197,
290
- 0x8347E183, 0x6B18E66B, 0xC822BDC8, 0x0E98450E, 0x6E1FE26E, 0xC9B3F4C9, 0x2F74B62F, 0xCBF866CB,
291
- 0xFF99CCFF, 0xEA1495EA, 0xED5803ED, 0xF7DC56F7, 0xE18BD4E1, 0x1B151C1B, 0xADA21EAD, 0x0CD3D70C,
292
- 0x2BE2FB2B, 0x1DC8C31D, 0x195E8E19, 0xC22CB5C2, 0x8949E989, 0x12C1CF12, 0x7E95BF7E, 0x207DBA20,
293
- 0x6411EA64, 0x840B7784, 0x6DC5396D, 0x6A89AF6A, 0xD17C33D1, 0xA171C9A1, 0xCEFF62CE, 0x37BB7137,
294
- 0xFB0F81FB, 0x3DB5793D, 0x51E10951, 0xDC3EADDC, 0x2D3F242D, 0xA476CDA4, 0x9D55F99D, 0xEE82D8EE,
295
- 0x8640E586, 0xAE78C5AE, 0xCD25B9CD, 0x04964D04, 0x55774455, 0x0A0E080A, 0x13508613, 0x30F7E730,
296
- 0xD337A1D3, 0x40FA1D40, 0x3461AA34, 0x8C4EED8C, 0xB3B006B3, 0x6C54706C, 0x2A73B22A, 0x523BD252,
297
- 0x0B9F410B, 0x8B027B8B, 0x88D8A088, 0x4FF3114F, 0x67CB3167, 0x4627C246, 0xC06727C0, 0xB4FC90B4,
298
- 0x28382028, 0x7F04F67F, 0x78486078, 0x2EE5FF2E, 0x074C9607, 0x4B655C4B, 0xC72BB1C7, 0x6F8EAB6F,
299
- 0x0D429E0D, 0xBBF59CBB, 0xF2DB52F2, 0xF34A1BF3, 0xA63D5FA6, 0x59A49359, 0xBCB90ABC, 0x3AF9EF3A,
300
- 0xEF1391EF, 0xFE0885FE, 0x01914901, 0x6116EE61, 0x7CDE2D7C, 0xB2214FB2, 0x42B18F42, 0xDB723BDB,
301
- 0xB82F47B8, 0x48BF8748, 0x2CAE6D2C, 0xE3C046E3, 0x573CD657, 0x859A3E85, 0x29A96929, 0x7D4F647D,
302
- 0x94812A94, 0x492ECE49, 0x17C6CB17, 0xCA692FCA, 0xC3BDFCC3, 0x5CA3975C, 0x5EE8055E, 0xD0ED7AD0,
303
- 0x87D1AC87, 0x8E057F8E, 0xBA64D5BA, 0xA8A51AA8, 0xB7264BB7, 0xB9BE0EB9, 0x6087A760, 0xF8D55AF8,
304
- 0x22362822, 0x111B1411, 0xDE753FDE, 0x79D92979, 0xAAEE88AA, 0x332D3C33, 0x5F794C5F, 0xB6B702B6,
305
- 0x96CAB896, 0x5835DA58, 0x9CC4B09C, 0xFC4317FC, 0x1A84551A, 0xF64D1FF6, 0x1C598A1C, 0x38B27D38,
306
- 0xAC3357AC, 0x18CFC718, 0xF4068DF4, 0x69537469, 0x749BB774, 0xF597C4F5, 0x56AD9F56, 0xDAE372DA,
307
- 0xD5EA7ED5, 0x4AF4154A, 0x9E8F229E, 0xA2AB12A2, 0x4E62584E, 0xE85F07E8, 0xE51D99E5, 0x39233439,
308
- 0xC1F66EC1, 0x446C5044, 0x5D32DE5D, 0x72466872, 0x26A06526, 0x93CDBC93, 0x03DADB03, 0xC6BAF8C6,
309
- 0xFA9EC8FA, 0x82D6A882, 0xCF6E2BCF, 0x50704050, 0xEB85DCEB, 0x750AFE75, 0x8A93328A, 0x8DDFA48D,
310
- 0x4C29CA4C, 0x141C1014, 0x73D72173, 0xCCB4F0CC, 0x09D4D309, 0x108A5D10, 0xE2510FE2, 0x00000000,
311
- 0x9A196F9A, 0xE01A9DE0, 0x8F94368F, 0xE6C742E6, 0xECC94AEC, 0xFDD25EFD, 0xAB7FC1AB, 0xD8A8E0D8
312
- );
313
-
314
- /**
315
- * The Key Schedule Array
316
- *
317
- * @var array
318
- * @access private
319
- */
320
- var $K = array();
321
-
322
- /**
323
- * The Key depended S-Table 0
324
- *
325
- * @var array
326
- * @access private
327
- */
328
- var $S0 = array();
329
-
330
- /**
331
- * The Key depended S-Table 1
332
- *
333
- * @var array
334
- * @access private
335
- */
336
- var $S1 = array();
337
-
338
- /**
339
- * The Key depended S-Table 2
340
- *
341
- * @var array
342
- * @access private
343
- */
344
- var $S2 = array();
345
-
346
- /**
347
- * The Key depended S-Table 3
348
- *
349
- * @var array
350
- * @access private
351
- */
352
- var $S3 = array();
353
-
354
- /**
355
- * Holds the last used key
356
- *
357
- * @var array
358
- * @access private
359
- */
360
- var $kl;
361
-
362
- /**
363
- * The Key Length (in bytes)
364
- *
365
- * @see Crypt_Twofish::setKeyLength()
366
- * @var int
367
- * @access private
368
- */
369
- var $key_length = 16;
370
-
371
- /**
372
- * Sets the key length.
373
- *
374
- * Valid key lengths are 128, 192 or 256 bits
375
- *
376
- * @access public
377
- * @param int $length
378
- */
379
- function setKeyLength($length)
380
- {
381
- switch (true) {
382
- case $length <= 128:
383
- $this->key_length = 16;
384
- break;
385
- case $length <= 192:
386
- $this->key_length = 24;
387
- break;
388
- default:
389
- $this->key_length = 32;
390
- }
391
-
392
- parent::setKeyLength($length);
393
- }
394
-
395
- /**
396
- * Setup the key (expansion)
397
- *
398
- * @see \phpseclib\Crypt\Base::_setupKey()
399
- * @access private
400
- */
401
- function _setupKey()
402
- {
403
- if (isset($this->kl['key']) && $this->key === $this->kl['key']) {
404
- // already expanded
405
- return;
406
- }
407
- $this->kl = array('key' => $this->key);
408
-
409
- /* Key expanding and generating the key-depended s-boxes */
410
- $le_longs = unpack('V*', $this->key);
411
- $key = unpack('C*', $this->key);
412
- $m0 = $this->m0;
413
- $m1 = $this->m1;
414
- $m2 = $this->m2;
415
- $m3 = $this->m3;
416
- $q0 = $this->q0;
417
- $q1 = $this->q1;
418
-
419
- $K = $S0 = $S1 = $S2 = $S3 = array();
420
-
421
- switch (strlen($this->key)) {
422
- case 16:
423
- list($s7, $s6, $s5, $s4) = $this->_mdsrem($le_longs[1], $le_longs[2]);
424
- list($s3, $s2, $s1, $s0) = $this->_mdsrem($le_longs[3], $le_longs[4]);
425
- for ($i = 0, $j = 1; $i < 40; $i+= 2, $j+= 2) {
426
- $A = $m0[$q0[$q0[$i] ^ $key[ 9]] ^ $key[1]] ^
427
- $m1[$q0[$q1[$i] ^ $key[10]] ^ $key[2]] ^
428
- $m2[$q1[$q0[$i] ^ $key[11]] ^ $key[3]] ^
429
- $m3[$q1[$q1[$i] ^ $key[12]] ^ $key[4]];
430
- $B = $m0[$q0[$q0[$j] ^ $key[13]] ^ $key[5]] ^
431
- $m1[$q0[$q1[$j] ^ $key[14]] ^ $key[6]] ^
432
- $m2[$q1[$q0[$j] ^ $key[15]] ^ $key[7]] ^
433
- $m3[$q1[$q1[$j] ^ $key[16]] ^ $key[8]];
434
- $B = ($B << 8) | ($B >> 24 & 0xff);
435
- $K[] = $A+= $B;
436
- $K[] = (($A+= $B) << 9 | $A >> 23 & 0x1ff);
437
- }
438
- for ($i = 0; $i < 256; ++$i) {
439
- $S0[$i] = $m0[$q0[$q0[$i] ^ $s4] ^ $s0];
440
- $S1[$i] = $m1[$q0[$q1[$i] ^ $s5] ^ $s1];
441
- $S2[$i] = $m2[$q1[$q0[$i] ^ $s6] ^ $s2];
442
- $S3[$i] = $m3[$q1[$q1[$i] ^ $s7] ^ $s3];
443
- }
444
- break;
445
- case 24:
446
- list($sb, $sa, $s9, $s8) = $this->_mdsrem($le_longs[1], $le_longs[2]);
447
- list($s7, $s6, $s5, $s4) = $this->_mdsrem($le_longs[3], $le_longs[4]);
448
- list($s3, $s2, $s1, $s0) = $this->_mdsrem($le_longs[5], $le_longs[6]);
449
- for ($i = 0, $j = 1; $i < 40; $i+= 2, $j+= 2) {
450
- $A = $m0[$q0[$q0[$q1[$i] ^ $key[17]] ^ $key[ 9]] ^ $key[1]] ^
451
- $m1[$q0[$q1[$q1[$i] ^ $key[18]] ^ $key[10]] ^ $key[2]] ^
452
- $m2[$q1[$q0[$q0[$i] ^ $key[19]] ^ $key[11]] ^ $key[3]] ^
453
- $m3[$q1[$q1[$q0[$i] ^ $key[20]] ^ $key[12]] ^ $key[4]];
454
- $B = $m0[$q0[$q0[$q1[$j] ^ $key[21]] ^ $key[13]] ^ $key[5]] ^
455
- $m1[$q0[$q1[$q1[$j] ^ $key[22]] ^ $key[14]] ^ $key[6]] ^
456
- $m2[$q1[$q0[$q0[$j] ^ $key[23]] ^ $key[15]] ^ $key[7]] ^
457
- $m3[$q1[$q1[$q0[$j] ^ $key[24]] ^ $key[16]] ^ $key[8]];
458
- $B = ($B << 8) | ($B >> 24 & 0xff);
459
- $K[] = $A+= $B;
460
- $K[] = (($A+= $B) << 9 | $A >> 23 & 0x1ff);
461
- }
462
- for ($i = 0; $i < 256; ++$i) {
463
- $S0[$i] = $m0[$q0[$q0[$q1[$i] ^ $s8] ^ $s4] ^ $s0];
464
- $S1[$i] = $m1[$q0[$q1[$q1[$i] ^ $s9] ^ $s5] ^ $s1];
465
- $S2[$i] = $m2[$q1[$q0[$q0[$i] ^ $sa] ^ $s6] ^ $s2];
466
- $S3[$i] = $m3[$q1[$q1[$q0[$i] ^ $sb] ^ $s7] ^ $s3];
467
- }
468
- break;
469
- default: // 32
470
- list($sf, $se, $sd, $sc) = $this->_mdsrem($le_longs[1], $le_longs[2]);
471
- list($sb, $sa, $s9, $s8) = $this->_mdsrem($le_longs[3], $le_longs[4]);
472
- list($s7, $s6, $s5, $s4) = $this->_mdsrem($le_longs[5], $le_longs[6]);
473
- list($s3, $s2, $s1, $s0) = $this->_mdsrem($le_longs[7], $le_longs[8]);
474
- for ($i = 0, $j = 1; $i < 40; $i+= 2, $j+= 2) {
475
- $A = $m0[$q0[$q0[$q1[$q1[$i] ^ $key[25]] ^ $key[17]] ^ $key[ 9]] ^ $key[1]] ^
476
- $m1[$q0[$q1[$q1[$q0[$i] ^ $key[26]] ^ $key[18]] ^ $key[10]] ^ $key[2]] ^
477
- $m2[$q1[$q0[$q0[$q0[$i] ^ $key[27]] ^ $key[19]] ^ $key[11]] ^ $key[3]] ^
478
- $m3[$q1[$q1[$q0[$q1[$i] ^ $key[28]] ^ $key[20]] ^ $key[12]] ^ $key[4]];
479
- $B = $m0[$q0[$q0[$q1[$q1[$j] ^ $key[29]] ^ $key[21]] ^ $key[13]] ^ $key[5]] ^
480
- $m1[$q0[$q1[$q1[$q0[$j] ^ $key[30]] ^ $key[22]] ^ $key[14]] ^ $key[6]] ^
481
- $m2[$q1[$q0[$q0[$q0[$j] ^ $key[31]] ^ $key[23]] ^ $key[15]] ^ $key[7]] ^
482
- $m3[$q1[$q1[$q0[$q1[$j] ^ $key[32]] ^ $key[24]] ^ $key[16]] ^ $key[8]];
483
- $B = ($B << 8) | ($B >> 24 & 0xff);
484
- $K[] = $A+= $B;
485
- $K[] = (($A+= $B) << 9 | $A >> 23 & 0x1ff);
486
- }
487
- for ($i = 0; $i < 256; ++$i) {
488
- $S0[$i] = $m0[$q0[$q0[$q1[$q1[$i] ^ $sc] ^ $s8] ^ $s4] ^ $s0];
489
- $S1[$i] = $m1[$q0[$q1[$q1[$q0[$i] ^ $sd] ^ $s9] ^ $s5] ^ $s1];
490
- $S2[$i] = $m2[$q1[$q0[$q0[$q0[$i] ^ $se] ^ $sa] ^ $s6] ^ $s2];
491
- $S3[$i] = $m3[$q1[$q1[$q0[$q1[$i] ^ $sf] ^ $sb] ^ $s7] ^ $s3];
492
- }
493
- }
494
-
495
- $this->K = $K;
496
- $this->S0 = $S0;
497
- $this->S1 = $S1;
498
- $this->S2 = $S2;
499
- $this->S3 = $S3;
500
- }
501
-
502
- /**
503
- * _mdsrem function using by the twofish cipher algorithm
504
- *
505
- * @access private
506
- * @param string $A
507
- * @param string $B
508
- * @return array
509
- */
510
- function _mdsrem($A, $B)
511
- {
512
- // No gain by unrolling this loop.
513
- for ($i = 0; $i < 8; ++$i) {
514
- // Get most significant coefficient.
515
- $t = 0xff & ($B >> 24);
516
-
517
- // Shift the others up.
518
- $B = ($B << 8) | (0xff & ($A >> 24));
519
- $A<<= 8;
520
-
521
- $u = $t << 1;
522
-
523
- // Subtract the modular polynomial on overflow.
524
- if ($t & 0x80) {
525
- $u^= 0x14d;
526
- }
527
-
528
- // Remove t * (a * x^2 + 1).
529
- $B ^= $t ^ ($u << 16);
530
-
531
- // Form u = a*t + t/a = t*(a + 1/a).
532
- $u^= 0x7fffffff & ($t >> 1);
533
-
534
- // Add the modular polynomial on underflow.
535
- if ($t & 0x01) {
536
- $u^= 0xa6 ;
537
- }
538
-
539
- // Remove t * (a + 1/a) * (x^3 + x).
540
- $B^= ($u << 24) | ($u << 8);
541
- }
542
-
543
- return array(
544
- 0xff & $B >> 24,
545
- 0xff & $B >> 16,
546
- 0xff & $B >> 8,
547
- 0xff & $B);
548
- }
549
-
550
- /**
551
- * Encrypts a block
552
- *
553
- * @access private
554
- * @param string $in
555
- * @return string
556
- */
557
- function _encryptBlock($in)
558
- {
559
- $S0 = $this->S0;
560
- $S1 = $this->S1;
561
- $S2 = $this->S2;
562
- $S3 = $this->S3;
563
- $K = $this->K;
564
-
565
- $in = unpack("V4", $in);
566
- $R0 = $K[0] ^ $in[1];
567
- $R1 = $K[1] ^ $in[2];
568
- $R2 = $K[2] ^ $in[3];
569
- $R3 = $K[3] ^ $in[4];
570
-
571
- $ki = 7;
572
- while ($ki < 39) {
573
- $t0 = $S0[ $R0 & 0xff] ^
574
- $S1[($R0 >> 8) & 0xff] ^
575
- $S2[($R0 >> 16) & 0xff] ^
576
- $S3[($R0 >> 24) & 0xff];
577
- $t1 = $S0[($R1 >> 24) & 0xff] ^
578
- $S1[ $R1 & 0xff] ^
579
- $S2[($R1 >> 8) & 0xff] ^
580
- $S3[($R1 >> 16) & 0xff];
581
- $R2^= $t0 + $t1 + $K[++$ki];
582
- $R2 = ($R2 >> 1 & 0x7fffffff) | ($R2 << 31);
583
- $R3 = ((($R3 >> 31) & 1) | ($R3 << 1)) ^ ($t0 + ($t1 << 1) + $K[++$ki]);
584
-
585
- $t0 = $S0[ $R2 & 0xff] ^
586
- $S1[($R2 >> 8) & 0xff] ^
587
- $S2[($R2 >> 16) & 0xff] ^
588
- $S3[($R2 >> 24) & 0xff];
589
- $t1 = $S0[($R3 >> 24) & 0xff] ^
590
- $S1[ $R3 & 0xff] ^
591
- $S2[($R3 >> 8) & 0xff] ^
592
- $S3[($R3 >> 16) & 0xff];
593
- $R0^= ($t0 + $t1 + $K[++$ki]);
594
- $R0 = ($R0 >> 1 & 0x7fffffff) | ($R0 << 31);
595
- $R1 = ((($R1 >> 31) & 1) | ($R1 << 1)) ^ ($t0 + ($t1 << 1) + $K[++$ki]);
596
- }
597
-
598
- // @codingStandardsIgnoreStart
599
- return pack("V4", $K[4] ^ $R2,
600
- $K[5] ^ $R3,
601
- $K[6] ^ $R0,
602
- $K[7] ^ $R1);
603
- // @codingStandardsIgnoreEnd
604
- }
605
-
606
- /**
607
- * Decrypts a block
608
- *
609
- * @access private
610
- * @param string $in
611
- * @return string
612
- */
613
- function _decryptBlock($in)
614
- {
615
- $S0 = $this->S0;
616
- $S1 = $this->S1;
617
- $S2 = $this->S2;
618
- $S3 = $this->S3;
619
- $K = $this->K;
620
-
621
- $in = unpack("V4", $in);
622
- $R0 = $K[4] ^ $in[1];
623
- $R1 = $K[5] ^ $in[2];
624
- $R2 = $K[6] ^ $in[3];
625
- $R3 = $K[7] ^ $in[4];
626
-
627
- $ki = 40;
628
- while ($ki > 8) {
629
- $t0 = $S0[$R0 & 0xff] ^
630
- $S1[$R0 >> 8 & 0xff] ^
631
- $S2[$R0 >> 16 & 0xff] ^
632
- $S3[$R0 >> 24 & 0xff];
633
- $t1 = $S0[$R1 >> 24 & 0xff] ^
634
- $S1[$R1 & 0xff] ^
635
- $S2[$R1 >> 8 & 0xff] ^
636
- $S3[$R1 >> 16 & 0xff];
637
- $R3^= $t0 + ($t1 << 1) + $K[--$ki];
638
- $R3 = $R3 >> 1 & 0x7fffffff | $R3 << 31;
639
- $R2 = ($R2 >> 31 & 0x1 | $R2 << 1) ^ ($t0 + $t1 + $K[--$ki]);
640
-
641
- $t0 = $S0[$R2 & 0xff] ^
642
- $S1[$R2 >> 8 & 0xff] ^
643
- $S2[$R2 >> 16 & 0xff] ^
644
- $S3[$R2 >> 24 & 0xff];
645
- $t1 = $S0[$R3 >> 24 & 0xff] ^
646
- $S1[$R3 & 0xff] ^
647
- $S2[$R3 >> 8 & 0xff] ^
648
- $S3[$R3 >> 16 & 0xff];
649
- $R1^= $t0 + ($t1 << 1) + $K[--$ki];
650
- $R1 = $R1 >> 1 & 0x7fffffff | $R1 << 31;
651
- $R0 = ($R0 >> 31 & 0x1 | $R0 << 1) ^ ($t0 + $t1 + $K[--$ki]);
652
- }
653
-
654
- // @codingStandardsIgnoreStart
655
- return pack("V4", $K[0] ^ $R2,
656
- $K[1] ^ $R3,
657
- $K[2] ^ $R0,
658
- $K[3] ^ $R1);
659
- // @codingStandardsIgnoreEnd
660
- }
661
-
662
- /**
663
- * Setup the performance-optimized function for de/encrypt()
664
- *
665
- * @see \phpseclib\Crypt\Base::_setupInlineCrypt()
666
- * @access private
667
- */
668
- function _setupInlineCrypt()
669
- {
670
- $lambda_functions =& self::_getLambdaFunctions();
671
-
672
- // Max. 10 Ultra-Hi-optimized inline-crypt functions. After that, we'll (still) create very fast code, but not the ultimate fast one.
673
- // (Currently, for Crypt_Twofish, one generated $lambda_function cost on php5.5@32bit ~140kb unfreeable mem and ~240kb on php5.5@64bit)
674
- $gen_hi_opt_code = (bool)(count($lambda_functions) < 10);
675
-
676
- // Generation of a unique hash for our generated code
677
- $code_hash = "Crypt_Twofish, {$this->mode}";
678
- if ($gen_hi_opt_code) {
679
- $code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key);
680
- }
681
-
682
- if (!isset($lambda_functions[$code_hash])) {
683
- switch (true) {
684
- case $gen_hi_opt_code:
685
- $K = $this->K;
686
- $init_crypt = '
687
- static $S0, $S1, $S2, $S3;
688
- if (!$S0) {
689
- for ($i = 0; $i < 256; ++$i) {
690
- $S0[] = (int)$self->S0[$i];
691
- $S1[] = (int)$self->S1[$i];
692
- $S2[] = (int)$self->S2[$i];
693
- $S3[] = (int)$self->S3[$i];
694
- }
695
- }
696
- ';
697
- break;
698
- default:
699
- $K = array();
700
- for ($i = 0; $i < 40; ++$i) {
701
- $K[] = '$K_' . $i;
702
- }
703
- $init_crypt = '
704
- $S0 = $self->S0;
705
- $S1 = $self->S1;
706
- $S2 = $self->S2;
707
- $S3 = $self->S3;
708
- list(' . implode(',', $K) . ') = $self->K;
709
- ';
710
- }
711
-
712
- // Generating encrypt code:
713
- $encrypt_block = '
714
- $in = unpack("V4", $in);
715
- $R0 = '.$K[0].' ^ $in[1];
716
- $R1 = '.$K[1].' ^ $in[2];
717
- $R2 = '.$K[2].' ^ $in[3];
718
- $R3 = '.$K[3].' ^ $in[4];
719
- ';
720
- for ($ki = 7, $i = 0; $i < 8; ++$i) {
721
- $encrypt_block.= '
722
- $t0 = $S0[ $R0 & 0xff] ^
723
- $S1[($R0 >> 8) & 0xff] ^
724
- $S2[($R0 >> 16) & 0xff] ^
725
- $S3[($R0 >> 24) & 0xff];
726
- $t1 = $S0[($R1 >> 24) & 0xff] ^
727
- $S1[ $R1 & 0xff] ^
728
- $S2[($R1 >> 8) & 0xff] ^
729
- $S3[($R1 >> 16) & 0xff];
730
- $R2^= ($t0 + $t1 + '.$K[++$ki].');
731
- $R2 = ($R2 >> 1 & 0x7fffffff) | ($R2 << 31);
732
- $R3 = ((($R3 >> 31) & 1) | ($R3 << 1)) ^ ($t0 + ($t1 << 1) + '.$K[++$ki].');
733
-
734
- $t0 = $S0[ $R2 & 0xff] ^
735
- $S1[($R2 >> 8) & 0xff] ^
736
- $S2[($R2 >> 16) & 0xff] ^
737
- $S3[($R2 >> 24) & 0xff];
738
- $t1 = $S0[($R3 >> 24) & 0xff] ^
739
- $S1[ $R3 & 0xff] ^
740
- $S2[($R3 >> 8) & 0xff] ^
741
- $S3[($R3 >> 16) & 0xff];
742
- $R0^= ($t0 + $t1 + '.$K[++$ki].');
743
- $R0 = ($R0 >> 1 & 0x7fffffff) | ($R0 << 31);
744
- $R1 = ((($R1 >> 31) & 1) | ($R1 << 1)) ^ ($t0 + ($t1 << 1) + '.$K[++$ki].');
745
- ';
746
- }
747
- $encrypt_block.= '
748
- $in = pack("V4", '.$K[4].' ^ $R2,
749
- '.$K[5].' ^ $R3,
750
- '.$K[6].' ^ $R0,
751
- '.$K[7].' ^ $R1);
752
- ';
753
-
754
- // Generating decrypt code:
755
- $decrypt_block = '
756
- $in = unpack("V4", $in);
757
- $R0 = '.$K[4].' ^ $in[1];
758
- $R1 = '.$K[5].' ^ $in[2];
759
- $R2 = '.$K[6].' ^ $in[3];
760
- $R3 = '.$K[7].' ^ $in[4];
761
- ';
762
- for ($ki = 40, $i = 0; $i < 8; ++$i) {
763
- $decrypt_block.= '
764
- $t0 = $S0[$R0 & 0xff] ^
765
- $S1[$R0 >> 8 & 0xff] ^
766
- $S2[$R0 >> 16 & 0xff] ^
767
- $S3[$R0 >> 24 & 0xff];
768
- $t1 = $S0[$R1 >> 24 & 0xff] ^
769
- $S1[$R1 & 0xff] ^
770
- $S2[$R1 >> 8 & 0xff] ^
771
- $S3[$R1 >> 16 & 0xff];
772
- $R3^= $t0 + ($t1 << 1) + '.$K[--$ki].';
773
- $R3 = $R3 >> 1 & 0x7fffffff | $R3 << 31;
774
- $R2 = ($R2 >> 31 & 0x1 | $R2 << 1) ^ ($t0 + $t1 + '.$K[--$ki].');
775
-
776
- $t0 = $S0[$R2 & 0xff] ^
777
- $S1[$R2 >> 8 & 0xff] ^
778
- $S2[$R2 >> 16 & 0xff] ^
779
- $S3[$R2 >> 24 & 0xff];
780
- $t1 = $S0[$R3 >> 24 & 0xff] ^
781
- $S1[$R3 & 0xff] ^
782
- $S2[$R3 >> 8 & 0xff] ^
783
- $S3[$R3 >> 16 & 0xff];
784
- $R1^= $t0 + ($t1 << 1) + '.$K[--$ki].';
785
- $R1 = $R1 >> 1 & 0x7fffffff | $R1 << 31;
786
- $R0 = ($R0 >> 31 & 0x1 | $R0 << 1) ^ ($t0 + $t1 + '.$K[--$ki].');
787
- ';
788
- }
789
- $decrypt_block.= '
790
- $in = pack("V4", '.$K[0].' ^ $R2,
791
- '.$K[1].' ^ $R3,
792
- '.$K[2].' ^ $R0,
793
- '.$K[3].' ^ $R1);
794
- ';
795
-
796
- $lambda_functions[$code_hash] = $this->_createInlineCryptFunction(
797
- array(
798
- 'init_crypt' => $init_crypt,
799
- 'init_encrypt' => '',
800
- 'init_decrypt' => '',
801
- 'encrypt_block' => $encrypt_block,
802
- 'decrypt_block' => $decrypt_block
803
- )
804
- );
805
- }
806
- $this->inline_crypt = $lambda_functions[$code_hash];
807
- }
808
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/phpseclib/phpseclib/phpseclib/File/ANSI.php DELETED
@@ -1,577 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Pure-PHP ANSI Decoder
5
- *
6
- * PHP version 5
7
- *
8
- * If you call read() in \phpseclib\Net\SSH2 you may get {@link http://en.wikipedia.org/wiki/ANSI_escape_code ANSI escape codes} back.
9
- * They'd look like chr(0x1B) . '[00m' or whatever (0x1B = ESC). They tell a
10
- * {@link http://en.wikipedia.org/wiki/Terminal_emulator terminal emulator} how to format the characters, what
11
- * color to display them in, etc. \phpseclib\File\ANSI is a {@link http://en.wikipedia.org/wiki/VT100 VT100} terminal emulator.
12
- *
13
- * @category File
14
- * @package ANSI
15
- * @author Jim Wigginton <terrafrost@php.net>
16
- * @copyright 2012 Jim Wigginton
17
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
18
- * @link http://phpseclib.sourceforge.net
19
- */
20
-
21
- namespace phpseclib\File;
22
-
23
- /**
24
- * Pure-PHP ANSI Decoder
25
- *
26
- * @package ANSI
27
- * @author Jim Wigginton <terrafrost@php.net>
28
- * @access public
29
- */
30
- class ANSI
31
- {
32
- /**
33
- * Max Width
34
- *
35
- * @var int
36
- * @access private
37
- */
38
- var $max_x;
39
-
40
- /**
41
- * Max Height
42
- *
43
- * @var int
44
- * @access private
45
- */
46
- var $max_y;
47
-
48
- /**
49
- * Max History
50
- *
51
- * @var int
52
- * @access private
53
- */
54
- var $max_history;
55
-
56
- /**
57
- * History
58
- *
59
- * @var array
60
- * @access private
61
- */
62
- var $history;
63
-
64
- /**
65
- * History Attributes
66
- *
67
- * @var array
68
- * @access private
69
- */
70
- var $history_attrs;
71
-
72
- /**
73
- * Current Column
74
- *
75
- * @var int
76
- * @access private
77
- */
78
- var $x;
79
-
80
- /**
81
- * Current Row
82
- *
83
- * @var int
84
- * @access private
85
- */
86
- var $y;
87
-
88
- /**
89
- * Old Column
90
- *
91
- * @var int
92
- * @access private
93
- */
94
- var $old_x;
95
-
96
- /**
97
- * Old Row
98
- *
99
- * @var int
100
- * @access private
101
- */
102
- var $old_y;
103
-
104
- /**
105
- * An empty attribute cell
106
- *
107
- * @var object
108
- * @access private
109
- */
110
- var $base_attr_cell;
111
-
112
- /**
113
- * The current attribute cell
114
- *
115
- * @var object
116
- * @access private
117
- */
118
- var $attr_cell;
119
-
120
- /**
121
- * An empty attribute row
122
- *
123
- * @var array
124
- * @access private
125
- */
126
- var $attr_row;
127
-
128
- /**
129
- * The current screen text
130
- *
131
- * @var array
132
- * @access private
133
- */
134
- var $screen;
135
-
136
- /**
137
- * The current screen attributes
138
- *
139
- * @var array
140
- * @access private
141
- */
142
- var $attrs;
143
-
144
- /**
145
- * Current ANSI code
146
- *
147
- * @var string
148
- * @access private
149
- */
150
- var $ansi;
151
-
152
- /**
153
- * Tokenization
154
- *
155
- * @var array
156
- * @access private
157
- */
158
- var $tokenization;
159
-
160
- /**
161
- * Default Constructor.
162
- *
163
- * @return \phpseclib\File\ANSI
164
- * @access public
165
- */
166
- function __construct()
167
- {
168
- $attr_cell = new \stdClass();
169
- $attr_cell->bold = false;
170
- $attr_cell->underline = false;
171
- $attr_cell->blink = false;
172
- $attr_cell->background = 'black';
173
- $attr_cell->foreground = 'white';
174
- $attr_cell->reverse = false;
175
- $this->base_attr_cell = clone $attr_cell;
176
- $this->attr_cell = clone $attr_cell;
177
-
178
- $this->setHistory(200);
179
- $this->setDimensions(80, 24);
180
- }
181
-
182
- /**
183
- * Set terminal width and height
184
- *
185
- * Resets the screen as well
186
- *
187
- * @param int $x
188
- * @param int $y
189
- * @access public
190
- */
191
- function setDimensions($x, $y)
192
- {
193
- $this->max_x = $x - 1;
194
- $this->max_y = $y - 1;
195
- $this->x = $this->y = 0;
196
- $this->history = $this->history_attrs = array();
197
- $this->attr_row = array_fill(0, $this->max_x + 2, $this->base_attr_cell);
198
- $this->screen = array_fill(0, $this->max_y + 1, '');
199
- $this->attrs = array_fill(0, $this->max_y + 1, $this->attr_row);
200
- $this->ansi = '';
201
- }
202
-
203
- /**
204
- * Set the number of lines that should be logged past the terminal height
205
- *
206
- * @param int $x
207
- * @param int $y
208
- * @access public
209
- */
210
- function setHistory($history)
211
- {
212
- $this->max_history = $history;
213
- }
214
-
215
- /**
216
- * Load a string
217
- *
218
- * @param string $source
219
- * @access public
220
- */
221
- function loadString($source)
222
- {
223
- $this->setDimensions($this->max_x + 1, $this->max_y + 1);
224
- $this->appendString($source);
225
- }
226
-
227
- /**
228
- * Appdend a string
229
- *
230
- * @param string $source
231
- * @access public
232
- */
233
- function appendString($source)
234
- {
235
- $this->tokenization = array('');
236
- for ($i = 0; $i < strlen($source); $i++) {
237
- if (strlen($this->ansi)) {
238
- $this->ansi.= $source[$i];
239
- $chr = ord($source[$i]);
240
- // http://en.wikipedia.org/wiki/ANSI_escape_code#Sequence_elements
241
- // single character CSI's not currently supported
242
- switch (true) {
243
- case $this->ansi == "\x1B=":
244
- $this->ansi = '';
245
- continue 2;
246
- case strlen($this->ansi) == 2 && $chr >= 64 && $chr <= 95 && $chr != ord('['):
247
- case strlen($this->ansi) > 2 && $chr >= 64 && $chr <= 126:
248
- break;
249
- default:
250
- continue 2;
251
- }
252
- $this->tokenization[] = $this->ansi;
253
- $this->tokenization[] = '';
254
- // http://ascii-table.com/ansi-escape-sequences-vt-100.php
255
- switch ($this->ansi) {
256
- case "\x1B[H": // Move cursor to upper left corner
257
- $this->old_x = $this->x;
258
- $this->old_y = $this->y;
259
- $this->x = $this->y = 0;
260
- break;
261
- case "\x1B[J": // Clear screen from cursor down
262
- $this->history = array_merge($this->history, array_slice(array_splice($this->screen, $this->y + 1), 0, $this->old_y));
263
- $this->screen = array_merge($this->screen, array_fill($this->y, $this->max_y, ''));
264
-
265
- $this->history_attrs = array_merge($this->history_attrs, array_slice(array_splice($this->attrs, $this->y + 1), 0, $this->old_y));
266
- $this->attrs = array_merge($this->attrs, array_fill($this->y, $this->max_y, $this->attr_row));
267
-
268
- if (count($this->history) == $this->max_history) {
269
- array_shift($this->history);
270
- array_shift($this->history_attrs);
271
- }
272
- case "\x1B[K": // Clear screen from cursor right
273
- $this->screen[$this->y] = substr($this->screen[$this->y], 0, $this->x);
274
-
275
- array_splice($this->attrs[$this->y], $this->x + 1, $this->max_x - $this->x, array_fill($this->x, $this->max_x - $this->x - 1, $this->base_attr_cell));
276
- break;
277
- case "\x1B[2K": // Clear entire line
278
- $this->screen[$this->y] = str_repeat(' ', $this->x);
279
- $this->attrs[$this->y] = $this->attr_row;
280
- break;
281
- case "\x1B[?1h": // set cursor key to application
282
- case "\x1B[?25h": // show the cursor
283
- case "\x1B(B": // set united states g0 character set
284
- break;
285
- case "\x1BE": // Move to next line
286
- $this->_newLine();
287
- $this->x = 0;
288
- break;
289
- default:
290
- switch (true) {
291
- case preg_match('#\x1B\[(\d+)B#', $this->ansi, $match): // Move cursor down n lines
292
- $this->old_y = $this->y;
293
- $this->y+= $match[1];
294
- break;
295
- case preg_match('#\x1B\[(\d+);(\d+)H#', $this->ansi, $match): // Move cursor to screen location v,h
296
- $this->old_x = $this->x;
297
- $this->old_y = $this->y;
298
- $this->x = $match[2] - 1;
299
- $this->y = $match[1] - 1;
300
- break;
301
- case preg_match('#\x1B\[(\d+)C#', $this->ansi, $match): // Move cursor right n lines
302
- $this->old_x = $this->x;
303
- $this->x+= $match[1];
304
- break;
305
- case preg_match('#\x1B\[(\d+)D#', $this->ansi, $match): // Move cursor left n lines
306
- $this->old_x = $this->x;
307
- $this->x-= $match[1];
308
- if ($this->x < 0) {
309
- $this->x = 0;
310
- }
311
- break;
312
- case preg_match('#\x1B\[(\d+);(\d+)r#', $this->ansi, $match): // Set top and bottom lines of a window
313
- break;
314
- case preg_match('#\x1B\[(\d*(?:;\d*)*)m#', $this->ansi, $match): // character attributes
315
- $attr_cell = &$this->attr_cell;
316
- $mods = explode(';', $match[1]);
317
- foreach ($mods as $mod) {
318
- switch ($mod) {
319
- case 0: // Turn off character attributes
320
- $attr_cell = clone $this->base_attr_cell;
321
- break;
322
- case 1: // Turn bold mode on
323
- $attr_cell->bold = true;
324
- break;
325
- case 4: // Turn underline mode on
326
- $attr_cell->underline = true;
327
- break;
328
- case 5: // Turn blinking mode on
329
- $attr_cell->blink = true;
330
- break;
331
- case 7: // Turn reverse video on
332
- $attr_cell->reverse = !$attr_cell->reverse;
333
- $temp = $attr_cell->background;
334
- $attr_cell->background = $attr_cell->foreground;
335
- $attr_cell->foreground = $temp;
336
- break;
337
- default: // set colors
338
- //$front = $attr_cell->reverse ? &$attr_cell->background : &$attr_cell->foreground;
339
- $front = &$attr_cell->{ $attr_cell->reverse ? 'background' : 'foreground' };
340
- //$back = $attr_cell->reverse ? &$attr_cell->foreground : &$attr_cell->background;
341
- $back = &$attr_cell->{ $attr_cell->reverse ? 'foreground' : 'background' };
342
- switch ($mod) {
343
- // @codingStandardsIgnoreStart
344
- case 30: $front = 'black'; break;
345
- case 31: $front = 'red'; break;
346
- case 32: $front = 'green'; break;
347
- case 33: $front = 'yellow'; break;
348
- case 34: $front = 'blue'; break;
349
- case 35: $front = 'magenta'; break;
350
- case 36: $front = 'cyan'; break;
351
- case 37: $front = 'white'; break;
352
-
353
- case 40: $back = 'black'; break;
354
- case 41: $back = 'red'; break;
355
- case 42: $back = 'green'; break;
356
- case 43: $back = 'yellow'; break;
357
- case 44: $back = 'blue'; break;
358
- case 45: $back = 'magenta'; break;
359
- case 46: $back = 'cyan'; break;
360
- case 47: $back = 'white'; break;
361
- // @codingStandardsIgnoreEnd
362
-
363
- default:
364
- //user_error('Unsupported attribute: ' . $mod);
365
- $this->ansi = '';
366
- break 2;
367
- }
368
- }
369
- }
370
- break;
371
- default:
372
- //user_error("{$this->ansi} is unsupported\r\n");
373
- }
374
- }
375
- $this->ansi = '';
376
- continue;
377
- }
378
-
379
- $this->tokenization[count($this->tokenization) - 1].= $source[$i];
380
- switch ($source[$i]) {
381
- case "\r":
382
- $this->x = 0;
383
- break;
384
- case "\n":
385
- $this->_newLine();
386
- break;
387
- case "\x08": // backspace
388
- if ($this->x) {
389
- $this->x--;
390
- $this->attrs[$this->y][$this->x] = clone $this->base_attr_cell;
391
- $this->screen[$this->y] = substr_replace(
392
- $this->screen[$this->y],
393
- $source[$i],
394
- $this->x,
395
- 1
396
- );
397
- }
398
- break;
399
- case "\x0F": // shift
400
- break;
401
- case "\x1B": // start ANSI escape code
402
- $this->tokenization[count($this->tokenization) - 1] = substr($this->tokenization[count($this->tokenization) - 1], 0, -1);
403
- //if (!strlen($this->tokenization[count($this->tokenization) - 1])) {
404
- // array_pop($this->tokenization);
405
- //}
406
- $this->ansi.= "\x1B";
407
- break;
408
- default:
409
- $this->attrs[$this->y][$this->x] = clone $this->attr_cell;
410
- if ($this->x > strlen($this->screen[$this->y])) {
411
- $this->screen[$this->y] = str_repeat(' ', $this->x);
412
- }
413
- $this->screen[$this->y] = substr_replace(
414
- $this->screen[$this->y],
415
- $source[$i],
416
- $this->x,
417
- 1
418
- );
419
-
420
- if ($this->x > $this->max_x) {
421
- $this->x = 0;
422
- $this->_newLine();
423
- } else {
424
- $this->x++;
425
- }
426
- }
427
- }
428
- }
429
-
430
- /**
431
- * Add a new line
432
- *
433
- * Also update the $this->screen and $this->history buffers
434
- *
435
- * @access private
436
- */
437
- function _newLine()
438
- {
439
- //if ($this->y < $this->max_y) {
440
- // $this->y++;
441
- //}
442
-
443
- while ($this->y >= $this->max_y) {
444
- $this->history = array_merge($this->history, array(array_shift($this->screen)));
445
- $this->screen[] = '';
446
-
447
- $this->history_attrs = array_merge($this->history_attrs, array(array_shift($this->attrs)));
448
- $this->attrs[] = $this->attr_row;
449
-
450
- if (count($this->history) >= $this->max_history) {
451
- array_shift($this->history);
452
- array_shift($this->history_attrs);
453
- }
454
-
455
- $this->y--;
456
- }
457
- $this->y++;
458
- }
459
-
460
- /**
461
- * Returns the current coordinate without preformating
462
- *
463
- * @access private
464
- * @return string
465
- */
466
- function _processCoordinate($last_attr, $cur_attr, $char)
467
- {
468
- $output = '';
469
-
470
- if ($last_attr != $cur_attr) {
471
- $close = $open = '';
472
- if ($last_attr->foreground != $cur_attr->foreground) {
473
- if ($cur_attr->foreground != 'white') {
474
- $open.= '<span style="color: ' . $cur_attr->foreground . '">';
475
- }
476
- if ($last_attr->foreground != 'white') {
477
- $close = '</span>' . $close;
478
- }
479
- }
480
- if ($last_attr->background != $cur_attr->background) {
481
- if ($cur_attr->background != 'black') {
482
- $open.= '<span style="background: ' . $cur_attr->background . '">';
483
- }
484
- if ($last_attr->background != 'black') {
485
- $close = '</span>' . $close;
486
- }
487
- }
488
- if ($last_attr->bold != $cur_attr->bold) {
489
- if ($cur_attr->bold) {
490
- $open.= '<b>';
491
- } else {
492
- $close = '</b>' . $close;
493
- }
494
- }
495
- if ($last_attr->underline != $cur_attr->underline) {
496
- if ($cur_attr->underline) {
497
- $open.= '<u>';
498
- } else {
499
- $close = '</u>' . $close;
500
- }
501
- }
502
- if ($last_attr->blink != $cur_attr->blink) {
503
- if ($cur_attr->blink) {
504
- $open.= '<blink>';
505
- } else {
506
- $close = '</blink>' . $close;
507
- }
508
- }
509
- $output.= $close . $open;
510
- }
511
-
512
- $output.= htmlspecialchars($char);
513
-
514
- return $output;
515
- }
516
-
517
- /**
518
- * Returns the current screen without preformating
519
- *
520
- * @access private
521
- * @return string
522
- */
523
- function _getScreen()
524
- {
525
- $output = '';
526
- $last_attr = $this->base_attr_cell;
527
- for ($i = 0; $i <= $this->max_y; $i++) {
528
- for ($j = 0; $j <= $this->max_x; $j++) {
529
- $cur_attr = $this->attrs[$i][$j];
530
- $output.= $this->_processCoordinate($last_attr, $cur_attr, isset($this->screen[$i][$j]) ? $this->screen[$i][$j] : '');
531
- $last_attr = $this->attrs[$i][$j];
532
- }
533
- $output.= "\r\n";
534
- }
535
- $output = substr($output, 0, -2);
536
- // close any remaining open tags
537
- $output.= $this->_processCoordinate($last_attr, $this->base_attr_cell, '');
538
- return rtrim($output);
539
- }
540
-
541
- /**
542
- * Returns the current screen
543
- *
544
- * @access public
545
- * @return string
546
- */
547
- function getScreen()
548
- {
549
- return '<pre width="' . ($this->max_x + 1) . '" style="color: white; background: black">' . $this->_getScreen() . '</pre>';
550
- }
551
-
552
- /**
553
- * Returns the current screen and the x previous lines
554
- *
555
- * @access public
556
- * @return string
557
- */
558
- function getHistory()
559
- {
560
- $scrollback = '';
561
- $last_attr = $this->base_attr_cell;
562
- for ($i = 0; $i < count($this->history); $i++) {
563
- for ($j = 0; $j <= $this->max_x + 1; $j++) {
564
- $cur_attr = $this->history_attrs[$i][$j];
565
- $scrollback.= $this->_processCoordinate($last_attr, $cur_attr, isset($this->history[$i][$j]) ? $this->history[$i][$j] : '');
566
- $last_attr = $this->history_attrs[$i][$j];
567
- }
568
- $scrollback.= "\r\n";
569
- }
570
- $base_attr_cell = $this->base_attr_cell;
571
- $this->base_attr_cell = $last_attr;
572
- $scrollback.= $this->_getScreen();
573
- $this->base_attr_cell = $base_attr_cell;
574
-
575
- return '<pre width="' . ($this->max_x + 1) . '" style="color: white; background: black">' . $scrollback . '</span></pre>';
576
- }
577
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/phpseclib/phpseclib/phpseclib/File/ASN1.php DELETED
@@ -1,1325 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Pure-PHP ASN.1 Parser
5
- *
6
- * PHP version 5
7
- *
8
- * ASN.1 provides the semantics for data encoded using various schemes. The most commonly
9
- * utilized scheme is DER or the "Distinguished Encoding Rules". PEM's are base64 encoded
10
- * DER blobs.
11
- *
12
- * \phpseclib\File\ASN1 decodes and encodes DER formatted messages and places them in a semantic context.
13
- *
14
- * Uses the 1988 ASN.1 syntax.
15
- *
16
- * @category File
17
- * @package ASN1
18
- * @author Jim Wigginton <terrafrost@php.net>
19
- * @copyright 2012 Jim Wigginton
20
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
21
- * @link http://phpseclib.sourceforge.net
22
- */
23
-
24
- namespace phpseclib\File;
25
-
26
- use phpseclib\File\ASN1\Element;
27
- use phpseclib\Math\BigInteger;
28
- use DateTime;
29
- use DateTimeZone;
30
-
31
- /**
32
- * Pure-PHP ASN.1 Parser
33
- *
34
- * @package ASN1
35
- * @author Jim Wigginton <terrafrost@php.net>
36
- * @access public
37
- */
38
- class ASN1
39
- {
40
- /**#@+
41
- * Tag Classes
42
- *
43
- * @access private
44
- * @link http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#page=12
45
- */
46
- const CLASS_UNIVERSAL = 0;
47
- const CLASS_APPLICATION = 1;
48
- const CLASS_CONTEXT_SPECIFIC = 2;
49
- const CLASS_PRIVATE = 3;
50
- /**#@-*/
51
-
52
- /**#@+
53
- * Tag Classes
54
- *
55
- * @access private
56
- * @link http://www.obj-sys.com/asn1tutorial/node124.html
57
- */
58
- const TYPE_BOOLEAN = 1;
59
- const TYPE_INTEGER = 2;
60
- const TYPE_BIT_STRING = 3;
61
- const TYPE_OCTET_STRING = 4;
62
- const TYPE_NULL = 5;
63
- const TYPE_OBJECT_IDENTIFIER = 6;
64
- //const TYPE_OBJECT_DESCRIPTOR = 7;
65
- //const TYPE_INSTANCE_OF = 8; // EXTERNAL
66
- const TYPE_REAL = 9;
67
- const TYPE_ENUMERATED = 10;
68
- //const TYPE_EMBEDDED = 11;
69
- const TYPE_UTF8_STRING = 12;
70
- //const TYPE_RELATIVE_OID = 13;
71
- const TYPE_SEQUENCE = 16; // SEQUENCE OF
72
- const TYPE_SET = 17; // SET OF
73
- /**#@-*/
74
- /**#@+
75
- * More Tag Classes
76
- *
77
- * @access private
78
- * @link http://www.obj-sys.com/asn1tutorial/node10.html
79
- */
80
- const TYPE_NUMERIC_STRING = 18;
81
- const TYPE_PRINTABLE_STRING = 19;
82
- const TYPE_TELETEX_STRING = 20; // T61String
83
- const TYPE_VIDEOTEX_STRING = 21;
84
- const TYPE_IA5_STRING = 22;
85
- const TYPE_UTC_TIME = 23;
86
- const TYPE_GENERALIZED_TIME = 24;
87
- const TYPE_GRAPHIC_STRING = 25;
88
- const TYPE_VISIBLE_STRING = 26; // ISO646String
89
- const TYPE_GENERAL_STRING = 27;
90
- const TYPE_UNIVERSAL_STRING = 28;
91
- //const TYPE_CHARACTER_STRING = 29;
92
- const TYPE_BMP_STRING = 30;
93
- /**#@-*/
94
-
95
- /**#@+
96
- * Tag Aliases
97
- *
98
- * These tags are kinda place holders for other tags.
99
- *
100
- * @access private
101
- */
102
- const TYPE_CHOICE = -1;
103
- const TYPE_ANY = -2;
104
- /**#@-*/
105
-
106
- /**
107
- * ASN.1 object identifier
108
- *
109
- * @var array
110
- * @access private
111
- * @link http://en.wikipedia.org/wiki/Object_identifier
112
- */
113
- var $oids = array();
114
-
115
- /**
116
- * Default date format
117
- *
118
- * @var string
119
- * @access private
120
- * @link http://php.net/class.datetime
121
- */
122
- var $format = 'D, d M Y H:i:s O';
123
-
124
- /**
125
- * Default date format
126
- *
127
- * @var array
128
- * @access private
129
- * @see self::setTimeFormat()
130
- * @see self::asn1map()
131
- * @link http://php.net/class.datetime
132
- */
133
- var $encoded;
134
-
135
- /**
136
- * Filters
137
- *
138
- * If the mapping type is self::TYPE_ANY what do we actually encode it as?
139
- *
140
- * @var array
141
- * @access private
142
- * @see self::_encode_der()
143
- */
144
- var $filters;
145
-
146
- /**
147
- * Type mapping table for the ANY type.
148
- *
149
- * Structured or unknown types are mapped to a \phpseclib\File\ASN1\Element.
150
- * Unambiguous types get the direct mapping (int/real/bool).
151
- * Others are mapped as a choice, with an extra indexing level.
152
- *
153
- * @var array
154
- * @access public
155
- */
156
- var $ANYmap = array(
157
- self::TYPE_BOOLEAN => true,
158
- self::TYPE_INTEGER => true,
159
- self::TYPE_BIT_STRING => 'bitString',
160
- self::TYPE_OCTET_STRING => 'octetString',
161
- self::TYPE_NULL => 'null',
162
- self::TYPE_OBJECT_IDENTIFIER => 'objectIdentifier',
163
- self::TYPE_REAL => true,
164
- self::TYPE_ENUMERATED => 'enumerated',
165
- self::TYPE_UTF8_STRING => 'utf8String',
166
- self::TYPE_NUMERIC_STRING => 'numericString',
167
- self::TYPE_PRINTABLE_STRING => 'printableString',
168
- self::TYPE_TELETEX_STRING => 'teletexString',
169
- self::TYPE_VIDEOTEX_STRING => 'videotexString',
170
- self::TYPE_IA5_STRING => 'ia5String',
171
- self::TYPE_UTC_TIME => 'utcTime',
172
- self::TYPE_GENERALIZED_TIME => 'generalTime',
173
- self::TYPE_GRAPHIC_STRING => 'graphicString',
174
- self::TYPE_VISIBLE_STRING => 'visibleString',
175
- self::TYPE_GENERAL_STRING => 'generalString',
176
- self::TYPE_UNIVERSAL_STRING => 'universalString',
177
- //self::TYPE_CHARACTER_STRING => 'characterString',
178
- self::TYPE_BMP_STRING => 'bmpString'
179
- );
180
-
181
- /**
182
- * String type to character size mapping table.
183
- *
184
- * Non-convertable types are absent from this table.
185
- * size == 0 indicates variable length encoding.
186
- *
187
- * @var array
188
- * @access public
189
- */
190
- var $stringTypeSize = array(
191
- self::TYPE_UTF8_STRING => 0,
192
- self::TYPE_BMP_STRING => 2,
193
- self::TYPE_UNIVERSAL_STRING => 4,
194
- self::TYPE_PRINTABLE_STRING => 1,
195
- self::TYPE_TELETEX_STRING => 1,
196
- self::TYPE_IA5_STRING => 1,
197
- self::TYPE_VISIBLE_STRING => 1,
198
- );
199
-
200
- /**
201
- * Parse BER-encoding
202
- *
203
- * Serves a similar purpose to openssl's asn1parse
204
- *
205
- * @param string $encoded
206
- * @return array
207
- * @access public
208
- */
209
- function decodeBER($encoded)
210
- {
211
- if ($encoded instanceof Element) {
212
- $encoded = $encoded->element;
213
- }
214
-
215
- $this->encoded = $encoded;
216
- // encapsulate in an array for BC with the old decodeBER
217
- return array($this->_decode_ber($encoded));
218
- }
219
-
220
- /**
221
- * Parse BER-encoding (Helper function)
222
- *
223
- * Sometimes we want to get the BER encoding of a particular tag. $start lets us do that without having to reencode.
224
- * $encoded is passed by reference for the recursive calls done for self::TYPE_BIT_STRING and
225
- * self::TYPE_OCTET_STRING. In those cases, the indefinite length is used.
226
- *
227
- * @param string $encoded
228
- * @param int $start
229
- * @param int $encoded_pos
230
- * @return array
231
- * @access private
232
- */
233
- function _decode_ber($encoded, $start = 0, $encoded_pos = 0)
234
- {
235
- $current = array('start' => $start);
236
-
237
- $type = ord($encoded[$encoded_pos++]);
238
- $start++;
239
-
240
- $constructed = ($type >> 5) & 1;
241
-
242
- $tag = $type & 0x1F;
243
- if ($tag == 0x1F) {
244
- $tag = 0;
245
- // process septets (since the eighth bit is ignored, it's not an octet)
246
- do {
247
- $loop = ord($encoded[0]) >> 7;
248
- $tag <<= 7;
249
- $tag |= ord($encoded[$encoded_pos++]) & 0x7F;
250
- $start++;
251
- } while ($loop);
252
- }
253
-
254
- // Length, as discussed in paragraph 8.1.3 of X.690-0207.pdf#page=13
255
- $length = ord($encoded[$encoded_pos++]);
256
- $start++;
257
- if ($length == 0x80) { // indefinite length
258
- // "[A sender shall] use the indefinite form (see 8.1.3.6) if the encoding is constructed and is not all
259
- // immediately available." -- paragraph 8.1.3.2.c
260
- $length = strlen($encoded) - $encoded_pos;
261
- } elseif ($length & 0x80) { // definite length, long form
262
- // technically, the long form of the length can be represented by up to 126 octets (bytes), but we'll only
263
- // support it up to four.
264
- $length&= 0x7F;
265
- $temp = substr($encoded, $encoded_pos, $length);
266
- $encoded_pos += $length;
267
- // tags of indefinte length don't really have a header length; this length includes the tag
268
- $current+= array('headerlength' => $length + 2);
269
- $start+= $length;
270
- extract(unpack('Nlength', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4)));
271
- } else {
272
- $current+= array('headerlength' => 2);
273
- }
274
-
275
- if ($length > (strlen($encoded) - $encoded_pos)) {
276
- return false;
277
- }
278
-
279
- $content = substr($encoded, $encoded_pos, $length);
280
- $content_pos = 0;
281
-
282
- // at this point $length can be overwritten. it's only accurate for definite length things as is
283
-
284
- /* Class is UNIVERSAL, APPLICATION, PRIVATE, or CONTEXT-SPECIFIC. The UNIVERSAL class is restricted to the ASN.1
285
- built-in types. It defines an application-independent data type that must be distinguishable from all other
286
- data types. The other three classes are user defined. The APPLICATION class distinguishes data types that
287
- have a wide, scattered use within a particular presentation context. PRIVATE distinguishes data types within
288
- a particular organization or country. CONTEXT-SPECIFIC distinguishes members of a sequence or set, the
289
- alternatives of a CHOICE, or universally tagged set members. Only the class number appears in braces for this
290
- data type; the term CONTEXT-SPECIFIC does not appear.
291
-
292
- -- http://www.obj-sys.com/asn1tutorial/node12.html */
293
- $class = ($type >> 6) & 3;
294
- switch ($class) {
295
- case self::CLASS_APPLICATION:
296
- case self::CLASS_PRIVATE:
297
- case self::CLASS_CONTEXT_SPECIFIC:
298
- if (!$constructed) {
299
- return array(
300
- 'type' => $class,
301
- 'constant' => $tag,
302
- 'content' => $content,
303
- 'length' => $length + $start - $current['start']
304
- );
305
- }
306
-
307
- $newcontent = array();
308
- $remainingLength = $length;
309
- while ($remainingLength > 0) {
310
- $temp = $this->_decode_ber($content, $start, $content_pos);
311
- $length = $temp['length'];
312
- // end-of-content octets - see paragraph 8.1.5
313
- if (substr($content, $content_pos + $length, 2) == "\0\0") {
314
- $length+= 2;
315
- $start+= $length;
316
- $newcontent[] = $temp;
317
- break;
318
- }
319
- $start+= $length;
320
- $remainingLength-= $length;
321
- $newcontent[] = $temp;
322
- $content_pos += $length;
323
- }
324
-
325
- return array(
326
- 'type' => $class,
327
- 'constant' => $tag,
328
- // the array encapsulation is for BC with the old format
329
- 'content' => $newcontent,
330
- // the only time when $content['headerlength'] isn't defined is when the length is indefinite.
331
- // the absence of $content['headerlength'] is how we know if something is indefinite or not.
332
- // technically, it could be defined to be 2 and then another indicator could be used but whatever.
333
- 'length' => $start - $current['start']
334
- ) + $current;
335
- }
336
-
337
- $current+= array('type' => $tag);
338
-
339
- // decode UNIVERSAL tags
340
- switch ($tag) {
341
- case self::TYPE_BOOLEAN:
342
- // "The contents octets shall consist of a single octet." -- paragraph 8.2.1
343
- //if (strlen($content) != 1) {
344
- // return false;
345
- //}
346
- $current['content'] = (bool) ord($content[$content_pos]);
347
- break;
348
- case self::TYPE_INTEGER:
349
- case self::TYPE_ENUMERATED:
350
- $current['content'] = new BigInteger(substr($content, $content_pos), -256);
351
- break;
352
- case self::TYPE_REAL: // not currently supported
353
- return false;
354
- case self::TYPE_BIT_STRING:
355
- // The initial octet shall encode, as an unsigned binary integer with bit 1 as the least significant bit,
356
- // the number of unused bits in the final subsequent octet. The number shall be in the range zero to
357
- // seven.
358
- if (!$constructed) {
359
- $current['content'] = substr($content, $content_pos);
360
- } else {
361
- $temp = $this->_decode_ber($content, $start, $content_pos);
362
- $length-= (strlen($content) - $content_pos);
363
- $last = count($temp) - 1;
364
- for ($i = 0; $i < $last; $i++) {
365
- // all subtags should be bit strings
366
- //if ($temp[$i]['type'] != self::TYPE_BIT_STRING) {
367
- // return false;
368
- //}
369
- $current['content'].= substr($temp[$i]['content'], 1);
370
- }
371
- // all subtags should be bit strings
372
- //if ($temp[$last]['type'] != self::TYPE_BIT_STRING) {
373
- // return false;
374
- //}
375
- $current['content'] = $temp[$last]['content'][0] . $current['content'] . substr($temp[$i]['content'], 1);
376
- }
377
- break;
378
- case self::TYPE_OCTET_STRING:
379
- if (!$constructed) {
380
- $current['content'] = substr($content, $content_pos);
381
- } else {
382
- $current['content'] = '';
383
- $length = 0;
384
- while (substr($content, $content_pos, 2) != "\0\0") {
385
- $temp = $this->_decode_ber($content, $length + $start, $content_pos);
386
- $content_pos += $temp['length'];
387
- // all subtags should be octet strings
388
- //if ($temp['type'] != self::TYPE_OCTET_STRING) {
389
- // return false;
390
- //}
391
- $current['content'].= $temp['content'];
392
- $length+= $temp['length'];
393
- }
394
- if (substr($content, $content_pos, 2) == "\0\0") {
395
- $length+= 2; // +2 for the EOC
396
- }
397
- }
398
- break;
399
- case self::TYPE_NULL:
400
- // "The contents octets shall not contain any octets." -- paragraph 8.8.2
401
- //if (strlen($content)) {
402
- // return false;
403
- //}
404
- break;
405
- case self::TYPE_SEQUENCE:
406
- case self::TYPE_SET:
407
- $offset = 0;
408
- $current['content'] = array();
409
- $content_len = strlen($content);
410
- while ($content_pos < $content_len) {
411
- // if indefinite length construction was used and we have an end-of-content string next
412
- // see paragraphs 8.1.1.3, 8.1.3.2, 8.1.3.6, 8.1.5, and (for an example) 8.6.4.2
413
- if (!isset($current['headerlength']) && substr($content, $content_pos, 2) == "\0\0") {
414
- $length = $offset + 2; // +2 for the EOC
415
- break 2;
416
- }
417
- $temp = $this->_decode_ber($content, $start + $offset, $content_pos);
418
- $content_pos += $temp['length'];
419
- $current['content'][] = $temp;
420
- $offset+= $temp['length'];
421
- }
422
- break;
423
- case self::TYPE_OBJECT_IDENTIFIER:
424
- $temp = ord($content[$content_pos++]);
425
- $current['content'] = sprintf('%d.%d', floor($temp / 40), $temp % 40);
426
- $valuen = 0;
427
- // process septets
428
- $content_len = strlen($content);
429
- while ($content_pos < $content_len) {
430
- $temp = ord($content[$content_pos++]);
431
- $valuen <<= 7;
432
- $valuen |= $temp & 0x7F;
433
- if (~$temp & 0x80) {
434
- $current['content'].= ".$valuen";
435
- $valuen = 0;
436
- }
437
- }
438
- // the eighth bit of the last byte should not be 1
439
- //if ($temp >> 7) {
440
- // return false;
441
- //}
442
- break;
443
- /* Each character string type shall be encoded as if it had been declared:
444
- [UNIVERSAL x] IMPLICIT OCTET STRING
445
-
446
- -- X.690-0207.pdf#page=23 (paragraph 8.21.3)
447
-
448
- Per that, we're not going to do any validation. If there are any illegal characters in the string,
449
- we don't really care */
450
- case self::TYPE_NUMERIC_STRING:
451
- // 0,1,2,3,4,5,6,7,8,9, and space
452
- case self::TYPE_PRINTABLE_STRING:
453
- // Upper and lower case letters, digits, space, apostrophe, left/right parenthesis, plus sign, comma,
454
- // hyphen, full stop, solidus, colon, equal sign, question mark
455
- case self::TYPE_TELETEX_STRING:
456
- // The Teletex character set in CCITT's T61, space, and delete
457
- // see http://en.wikipedia.org/wiki/Teletex#Character_sets
458
- case self::TYPE_VIDEOTEX_STRING:
459
- // The Videotex character set in CCITT's T.100 and T.101, space, and delete
460
- case self::TYPE_VISIBLE_STRING:
461
- // Printing character sets of international ASCII, and space
462
- case self::TYPE_IA5_STRING:
463
- // International Alphabet 5 (International ASCII)
464
- case self::TYPE_GRAPHIC_STRING:
465
- // All registered G sets, and space
466
- case self::TYPE_GENERAL_STRING:
467
- // All registered C and G sets, space and delete
468
- case self::TYPE_UTF8_STRING:
469
- // ????
470
- case self::TYPE_BMP_STRING:
471
- $current['content'] = substr($content, $content_pos);
472
- break;
473
- case self::TYPE_UTC_TIME:
474
- case self::TYPE_GENERALIZED_TIME:
475
- $current['content'] = $this->_decodeTime(substr($content, $content_pos), $tag);
476
- default:
477
- }
478
-
479
- $start+= $length;
480
-
481
- // ie. length is the length of the full TLV encoding - it's not just the length of the value
482
- return $current + array('length' => $start - $current['start']);
483
- }
484
-
485
- /**
486
- * ASN.1 Map
487
- *
488
- * Provides an ASN.1 semantic mapping ($mapping) from a parsed BER-encoding to a human readable format.
489
- *
490
- * "Special" mappings may be applied on a per tag-name basis via $special.
491
- *
492
- * @param array $decoded
493
- * @param array $mapping
494
- * @param array $special
495
- * @return array
496
- * @access public
497
- */
498
- function asn1map($decoded, $mapping, $special = array())
499
- {
500
- if (isset($mapping['explicit']) && is_array($decoded['content'])) {
501
- $decoded = $decoded['content'][0];
502
- }
503
-
504
- switch (true) {
505
- case $mapping['type'] == self::TYPE_ANY:
506
- $intype = $decoded['type'];
507
- if (isset($decoded['constant']) || !isset($this->ANYmap[$intype]) || (ord($this->encoded[$decoded['start']]) & 0x20)) {
508
- return new Element(substr($this->encoded, $decoded['start'], $decoded['length']));
509
- }
510
- $inmap = $this->ANYmap[$intype];
511
- if (is_string($inmap)) {
512
- return array($inmap => $this->asn1map($decoded, array('type' => $intype) + $mapping, $special));
513
- }
514
- break;
515
- case $mapping['type'] == self::TYPE_CHOICE:
516
- foreach ($mapping['children'] as $key => $option) {
517
- switch (true) {
518
- case isset($option['constant']) && $option['constant'] == $decoded['constant']:
519
- case !isset($option['constant']) && $option['type'] == $decoded['type']:
520
- $value = $this->asn1map($decoded, $option, $special);
521
- break;
522
- case !isset($option['constant']) && $option['type'] == self::TYPE_CHOICE:
523
- $v = $this->asn1map($decoded, $option, $special);
524
- if (isset($v)) {
525
- $value = $v;
526
- }
527
- }
528
- if (isset($value)) {
529
- if (isset($special[$key])) {
530
- $value = call_user_func($special[$key], $value);
531
- }
532
- return array($key => $value);
533
- }
534
- }
535
- return null;
536
- case isset($mapping['implicit']):
537
- case isset($mapping['explicit']):
538
- case $decoded['type'] == $mapping['type']:
539
- break;
540
- default:
541
- // if $decoded['type'] and $mapping['type'] are both strings, but different types of strings,
542
- // let it through
543
- switch (true) {
544
- case $decoded['type'] < 18: // self::TYPE_NUMERIC_STRING == 18
545
- case $decoded['type'] > 30: // self::TYPE_BMP_STRING == 30
546
- case $mapping['type'] < 18:
547
- case $mapping['type'] > 30:
548
- return null;
549
- }
550
- }
551
-
552
- if (isset($mapping['implicit'])) {
553
- $decoded['type'] = $mapping['type'];
554
- }
555
-
556
- switch ($decoded['type']) {
557
- case self::TYPE_SEQUENCE:
558
- $map = array();
559
-
560
- // ignore the min and max
561
- if (isset($mapping['min']) && isset($mapping['max'])) {
562
- $child = $mapping['children'];
563
- foreach ($decoded['content'] as $content) {
564
- if (($map[] = $this->asn1map($content, $child, $special)) === null) {
565
- return null;
566
- }
567
- }
568
-
569
- return $map;
570
- }
571
-
572
- $n = count($decoded['content']);
573
- $i = 0;
574
-
575
- foreach ($mapping['children'] as $key => $child) {
576
- $maymatch = $i < $n; // Match only existing input.
577
- if ($maymatch) {
578
- $temp = $decoded['content'][$i];
579
-
580
- if ($child['type'] != self::TYPE_CHOICE) {
581
- // Get the mapping and input class & constant.
582
- $childClass = $tempClass = self::CLASS_UNIVERSAL;
583
- $constant = null;
584
- if (isset($temp['constant'])) {
585
- $tempClass = isset($temp['class']) ? $temp['class'] : self::CLASS_CONTEXT_SPECIFIC;
586
- }
587
- if (isset($child['class'])) {
588
- $childClass = $child['class'];
589
- $constant = $child['cast'];
590
- } elseif (isset($child['constant'])) {
591
- $childClass = self::CLASS_CONTEXT_SPECIFIC;
592
- $constant = $child['constant'];
593
- }
594
-
595
- if (isset($constant) && isset($temp['constant'])) {
596
- // Can only match if constants and class match.
597
- $maymatch = $constant == $temp['constant'] && $childClass == $tempClass;
598
- } else {
599
- // Can only match if no constant expected and type matches or is generic.
600
- $maymatch = !isset($child['constant']) && array_search($child['type'], array($temp['type'], self::TYPE_ANY, self::TYPE_CHOICE)) !== false;
601
- }
602
- }
603
- }
604
-
605
- if ($maymatch) {
606
- // Attempt submapping.
607
- $candidate = $this->asn1map($temp, $child, $special);
608
- $maymatch = $candidate !== null;
609
- }
610
-
611
- if ($maymatch) {
612
- // Got the match: use it.
613
- if (isset($special[$key])) {
614
- $candidate = call_user_func($special[$key], $candidate);
615
- }
616
- $map[$key] = $candidate;
617
- $i++;
618
- } elseif (isset($child['default'])) {
619
- $map[$key] = $child['default']; // Use default.
620
- } elseif (!isset($child['optional'])) {
621
- return null; // Syntax error.
622
- }
623
- }
624
-
625
- // Fail mapping if all input items have not been consumed.
626
- return $i < $n ? null: $map;
627
-
628
- // the main diff between sets and sequences is the encapsulation of the foreach in another for loop
629
- case self::TYPE_SET:
630
- $map = array();
631
-
632
- // ignore the min and max
633
- if (isset($mapping['min']) && isset($mapping['max'])) {
634
- $child = $mapping['children'];
635
- foreach ($decoded['content'] as $content) {
636
- if (($map[] = $this->asn1map($content, $child, $special)) === null) {
637
- return null;
638
- }
639
- }
640
-
641
- return $map;
642
- }
643
-
644
- for ($i = 0; $i < count($decoded['content']); $i++) {
645
- $temp = $decoded['content'][$i];
646
- $tempClass = self::CLASS_UNIVERSAL;
647
- if (isset($temp['constant'])) {
648
- $tempClass = isset($temp['class']) ? $temp['class'] : self::CLASS_CONTEXT_SPECIFIC;
649
- }
650
-
651
- foreach ($mapping['children'] as $key => $child) {
652
- if (isset($map[$key])) {
653
- continue;
654
- }
655
- $maymatch = true;
656
- if ($child['type'] != self::TYPE_CHOICE) {
657
- $childClass = self::CLASS_UNIVERSAL;
658
- $constant = null;
659
- if (isset($child['class'])) {
660
- $childClass = $child['class'];
661
- $constant = $child['cast'];
662
- } elseif (isset($child['constant'])) {
663
- $childClass = self::CLASS_CONTEXT_SPECIFIC;
664
- $constant = $child['constant'];
665
- }
666
-
667
- if (isset($constant) && isset($temp['constant'])) {
668
- // Can only match if constants and class match.
669
- $maymatch = $constant == $temp['constant'] && $childClass == $tempClass;
670
- } else {
671
- // Can only match if no constant expected and type matches or is generic.
672
- $maymatch = !isset($child['constant']) && array_search($child['type'], array($temp['type'], self::TYPE_ANY, self::TYPE_CHOICE)) !== false;
673
- }
674
- }
675
-
676
- if ($maymatch) {
677
- // Attempt submapping.
678
- $candidate = $this->asn1map($temp, $child, $special);
679
- $maymatch = $candidate !== null;
680
- }
681
-
682
- if (!$maymatch) {
683
- break;
684
- }
685
-
686
- // Got the match: use it.
687
- if (isset($special[$key])) {
688
- $candidate = call_user_func($special[$key], $candidate);
689
- }
690
- $map[$key] = $candidate;
691
- break;
692
- }
693
- }
694
-
695
- foreach ($mapping['children'] as $key => $child) {
696
- if (!isset($map[$key])) {
697
- if (isset($child['default'])) {
698
- $map[$key] = $child['default'];
699
- } elseif (!isset($child['optional'])) {
700
- return null;
701
- }
702
- }
703
- }
704
- return $map;
705
- case self::TYPE_OBJECT_IDENTIFIER:
706
- return isset($this->oids[$decoded['content']]) ? $this->oids[$decoded['content']] : $decoded['content'];
707
- case self::TYPE_UTC_TIME:
708
- case self::TYPE_GENERALIZED_TIME:
709
- if (isset($mapping['implicit'])) {
710
- $decoded['content'] = $this->_decodeTime($decoded['content'], $decoded['type']);
711
- }
712
- return $decoded['content'] ? $decoded['content']->format($this->format) : false;
713
- case self::TYPE_BIT_STRING:
714
- if (isset($mapping['mapping'])) {
715
- $offset = ord($decoded['content'][0]);
716
- $size = (strlen($decoded['content']) - 1) * 8 - $offset;
717
- /*
718
- From X.680-0207.pdf#page=46 (21.7):
719
-
720
- "When a "NamedBitList" is used in defining a bitstring type ASN.1 encoding rules are free to add (or remove)
721
- arbitrarily any trailing 0 bits to (or from) values that are being encoded or decoded. Application designers should
722
- therefore ensure that different semantics are not associated with such values which differ only in the number of trailing
723
- 0 bits."
724
- */
725
- $bits = count($mapping['mapping']) == $size ? array() : array_fill(0, count($mapping['mapping']) - $size, false);
726
- for ($i = strlen($decoded['content']) - 1; $i > 0; $i--) {
727
- $current = ord($decoded['content'][$i]);
728
- for ($j = $offset; $j < 8; $j++) {
729
- $bits[] = (bool) ($current & (1 << $j));
730
- }
731
- $offset = 0;
732
- }
733
- $values = array();
734
- $map = array_reverse($mapping['mapping']);
735
- foreach ($map as $i => $value) {
736
- if ($bits[$i]) {
737
- $values[] = $value;
738
- }
739
- }
740
- return $values;
741
- }
742
- case self::TYPE_OCTET_STRING:
743
- return base64_encode($decoded['content']);
744
- case self::TYPE_NULL:
745
- return '';
746
- case self::TYPE_BOOLEAN:
747
- return $decoded['content'];
748
- case self::TYPE_NUMERIC_STRING:
749
- case self::TYPE_PRINTABLE_STRING:
750
- case self::TYPE_TELETEX_STRING:
751
- case self::TYPE_VIDEOTEX_STRING:
752
- case self::TYPE_IA5_STRING:
753
- case self::TYPE_GRAPHIC_STRING:
754
- case self::TYPE_VISIBLE_STRING:
755
- case self::TYPE_GENERAL_STRING:
756
- case self::TYPE_UNIVERSAL_STRING:
757
- case self::TYPE_UTF8_STRING:
758
- case self::TYPE_BMP_STRING:
759
- return $decoded['content'];
760
- case self::TYPE_INTEGER:
761
- case self::TYPE_ENUMERATED:
762
- $temp = $decoded['content'];
763
- if (isset($mapping['implicit'])) {
764
- $temp = new BigInteger($decoded['content'], -256);
765
- }
766
- if (isset($mapping['mapping'])) {
767
- $temp = (int) $temp->toString();
768
- return isset($mapping['mapping'][$temp]) ?
769
- $mapping['mapping'][$temp] :
770
- false;
771
- }
772
- return $temp;
773
- }
774
- }
775
-
776
- /**
777
- * ASN.1 Encode
778
- *
779
- * DER-encodes an ASN.1 semantic mapping ($mapping). Some libraries would probably call this function
780
- * an ASN.1 compiler.
781
- *
782
- * "Special" mappings can be applied via $special.
783
- *
784
- * @param string $source
785
- * @param string $mapping
786
- * @param int $idx
787
- * @return string
788
- * @access public
789
- */
790
- function encodeDER($source, $mapping, $special = array())
791
- {
792
- $this->location = array();
793
- return $this->_encode_der($source, $mapping, null, $special);
794
- }
795
-
796
- /**
797
- * ASN.1 Encode (Helper function)
798
- *
799
- * @param string $source
800
- * @param string $mapping
801
- * @param int $idx
802
- * @return string
803
- * @access private
804
- */
805
- function _encode_der($source, $mapping, $idx = null, $special = array())
806
- {
807
- if ($source instanceof Element) {
808
- return $source->element;
809
- }
810
-
811
- // do not encode (implicitly optional) fields with value set to default
812
- if (isset($mapping['default']) && $source === $mapping['default']) {
813
- return '';
814
- }
815
-
816
- if (isset($idx)) {
817
- if (isset($special[$idx])) {
818
- $source = call_user_func($special[$idx], $source);
819
- }
820
- $this->location[] = $idx;
821
- }
822
-
823
- $tag = $mapping['type'];
824
-
825
- switch ($tag) {
826
- case self::TYPE_SET: // Children order is not important, thus process in sequence.
827
- case self::TYPE_SEQUENCE:
828
- $tag|= 0x20; // set the constructed bit
829
-
830
- // ignore the min and max
831
- if (isset($mapping['min']) && isset($mapping['max'])) {
832
- $value = array();
833
- $child = $mapping['children'];
834
-
835
- foreach ($source as $content) {
836
- $temp = $this->_encode_der($content, $child, null, $special);
837
- if ($temp === false) {
838
- return false;
839
- }
840
- $value[]= $temp;
841
- }
842
- /* "The encodings of the component values of a set-of value shall appear in ascending order, the encodings being compared
843
- as octet strings with the shorter components being padded at their trailing end with 0-octets.
844
- NOTE - The padding octets are for comparison purposes only and do not appear in the encodings."
845
-
846
- -- sec 11.6 of http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf */
847
- if ($mapping['type'] == self::TYPE_SET) {
848
- sort($value);
849
- }
850
- $value = implode($value, '');
851
- break;
852
- }
853
-
854
- $value = '';
855
- foreach ($mapping['children'] as $key => $child) {
856
- if (!array_key_exists($key, $source)) {
857
- if (!isset($child['optional'])) {
858
- return false;
859
- }
860
- continue;
861
- }
862
-
863
- $temp = $this->_encode_der($source[$key], $child, $key, $special);
864
- if ($temp === false) {
865
- return false;
866
- }
867
-
868
- // An empty child encoding means it has been optimized out.
869
- // Else we should have at least one tag byte.
870
- if ($temp === '') {
871
- continue;
872
- }
873
-
874
- // if isset($child['constant']) is true then isset($child['optional']) should be true as well
875
- if (isset($child['constant'])) {
876
- /*
877
- From X.680-0207.pdf#page=58 (30.6):
878
-
879
- "The tagging construction specifies explicit tagging if any of the following holds:
880
- ...
881
- c) the "Tag Type" alternative is used and the value of "TagDefault" for the module is IMPLICIT TAGS or
882
- AUTOMATIC TAGS, but the type defined by "Type" is an untagged choice type, an untagged open type, or
883
- an untagged "DummyReference" (see ITU-T Rec. X.683 | ISO/IEC 8824-4, 8.3)."
884
- */
885
- if (isset($child['explicit']) || $child['type'] == self::TYPE_CHOICE) {
886
- $subtag = chr((self::CLASS_CONTEXT_SPECIFIC << 6) | 0x20 | $child['constant']);
887
- $temp = $subtag . $this->_encodeLength(strlen($temp)) . $temp;
888
- } else {
889
- $subtag = chr((self::CLASS_CONTEXT_SPECIFIC << 6) | (ord($temp[0]) & 0x20) | $child['constant']);
890
- $temp = $subtag . substr($temp, 1);
891
- }
892
- }
893
- $value.= $temp;
894
- }
895
- break;
896
- case self::TYPE_CHOICE:
897
- $temp = false;
898
-
899
- foreach ($mapping['children'] as $key => $child) {
900
- if (!isset($source[$key])) {
901
- continue;
902
- }
903
-
904
- $temp = $this->_encode_der($source[$key], $child, $key, $special);
905
- if ($temp === false) {
906
- return false;
907
- }
908
-
909
- // An empty child encoding means it has been optimized out.
910
- // Else we should have at least one tag byte.
911
- if ($temp === '') {
912
- continue;
913
- }
914
-
915
- $tag = ord($temp[0]);
916
-
917
- // if isset($child['constant']) is true then isset($child['optional']) should be true as well
918
- if (isset($child['constant'])) {
919
- if (isset($child['explicit']) || $child['type'] == self::TYPE_CHOICE) {
920
- $subtag = chr((self::CLASS_CONTEXT_SPECIFIC << 6) | 0x20 | $child['constant']);
921
- $temp = $subtag . $this->_encodeLength(strlen($temp)) . $temp;
922
- } else {
923
- $subtag = chr((self::CLASS_CONTEXT_SPECIFIC << 6) | (ord($temp[0]) & 0x20) | $child['constant']);
924
- $temp = $subtag . substr($temp, 1);
925
- }
926
- }
927
- }
928
-
929
- if (isset($idx)) {
930
- array_pop($this->location);
931
- }
932
-
933
- if ($temp && isset($mapping['cast'])) {
934
- $temp[0] = chr(($mapping['class'] << 6) | ($tag & 0x20) | $mapping['cast']);
935
- }
936
-
937
- return $temp;
938
- case self::TYPE_INTEGER:
939
- case self::TYPE_ENUMERATED:
940
- if (!isset($mapping['mapping'])) {
941
- if (is_numeric($source)) {
942
- $source = new BigInteger($source);
943
- }
944
- $value = $source->toBytes(true);
945
- } else {
946
- $value = array_search($source, $mapping['mapping']);
947
- if ($value === false) {
948
- return false;
949
- }
950
- $value = new BigInteger($value);
951
- $value = $value->toBytes(true);
952
- }
953
- if (!strlen($value)) {
954
- $value = chr(0);
955
- }
956
- break;
957
- case self::TYPE_UTC_TIME:
958
- case self::TYPE_GENERALIZED_TIME:
959
- $format = $mapping['type'] == self::TYPE_UTC_TIME ? 'y' : 'Y';
960
- $format.= 'mdHis';
961
- $date = new DateTime($source, new DateTimeZone('GMT'));
962
- $value = $date->format($format) . 'Z';
963
- break;
964
- case self::TYPE_BIT_STRING:
965
- if (isset($mapping['mapping'])) {
966
- $bits = array_fill(0, count($mapping['mapping']), 0);
967
- $size = 0;
968
- for ($i = 0; $i < count($mapping['mapping']); $i++) {
969
- if (in_array($mapping['mapping'][$i], $source)) {
970
- $bits[$i] = 1;
971
- $size = $i;
972
- }
973
- }
974
-
975
- if (isset($mapping['min']) && $mapping['min'] >= 1 && $size < $mapping['min']) {
976
- $size = $mapping['min'] - 1;
977
- }
978
-
979
- $offset = 8 - (($size + 1) & 7);
980
- $offset = $offset !== 8 ? $offset : 0;
981
-
982
- $value = chr($offset);
983
-
984
- for ($i = $size + 1; $i < count($mapping['mapping']); $i++) {
985
- unset($bits[$i]);
986
- }
987
-
988
- $bits = implode('', array_pad($bits, $size + $offset + 1, 0));
989
- $bytes = explode(' ', rtrim(chunk_split($bits, 8, ' ')));
990
- foreach ($bytes as $byte) {
991
- $value.= chr(bindec($byte));
992
- }
993
-
994
- break;
995
- }
996
- case self::TYPE_OCTET_STRING:
997
- /* The initial octet shall encode, as an unsigned binary integer with bit 1 as the least significant bit,
998
- the number of unused bits in the final subsequent octet. The number shall be in the range zero to seven.
999
-
1000
- -- http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#page=16 */
1001
- $value = base64_decode($source);
1002
- break;
1003
- case self::TYPE_OBJECT_IDENTIFIER:
1004
- $oid = preg_match('#(?:\d+\.)+#', $source) ? $source : array_search($source, $this->oids);
1005
- if ($oid === false) {
1006
- user_error('Invalid OID');
1007
- return false;
1008
- }
1009
- $value = '';
1010
- $parts = explode('.', $oid);
1011
- $value = chr(40 * $parts[0] + $parts[1]);
1012
- for ($i = 2; $i < count($parts); $i++) {
1013
- $temp = '';
1014
- if (!$parts[$i]) {
1015
- $temp = "\0";
1016
- } else {
1017
- while ($parts[$i]) {
1018
- $temp = chr(0x80 | ($parts[$i] & 0x7F)) . $temp;
1019
- $parts[$i] >>= 7;
1020
- }
1021
- $temp[strlen($temp) - 1] = $temp[strlen($temp) - 1] & chr(0x7F);
1022
- }
1023
- $value.= $temp;
1024
- }
1025
- break;
1026
- case self::TYPE_ANY:
1027
- $loc = $this->location;
1028
- if (isset($idx)) {
1029
- array_pop($this->location);
1030
- }
1031
-
1032
- switch (true) {
1033
- case !isset($source):
1034
- return $this->_encode_der(null, array('type' => self::TYPE_NULL) + $mapping, null, $special);
1035
- case is_int($source):
1036
- case $source instanceof BigInteger:
1037
- return $this->_encode_der($source, array('type' => self::TYPE_INTEGER) + $mapping, null, $special);
1038
- case is_float($source):
1039
- return $this->_encode_der($source, array('type' => self::TYPE_REAL) + $mapping, null, $special);
1040
- case is_bool($source):
1041
- return $this->_encode_der($source, array('type' => self::TYPE_BOOLEAN) + $mapping, null, $special);
1042
- case is_array($source) && count($source) == 1:
1043
- $typename = implode('', array_keys($source));
1044
- $outtype = array_search($typename, $this->ANYmap, true);
1045
- if ($outtype !== false) {
1046
- return $this->_encode_der($source[$typename], array('type' => $outtype) + $mapping, null, $special);
1047
- }
1048
- }
1049
-
1050
- $filters = $this->filters;
1051
- foreach ($loc as $part) {
1052
- if (!isset($filters[$part])) {
1053
- $filters = false;
1054
- break;
1055
- }
1056
- $filters = $filters[$part];
1057
- }
1058
- if ($filters === false) {
1059
- user_error('No filters defined for ' . implode('/', $loc));
1060
- return false;
1061
- }
1062
- return $this->_encode_der($source, $filters + $mapping, null, $special);
1063
- case self::TYPE_NULL:
1064
- $value = '';
1065
- break;
1066
- case self::TYPE_NUMERIC_STRING:
1067
- case self::TYPE_TELETEX_STRING:
1068
- case self::TYPE_PRINTABLE_STRING:
1069
- case self::TYPE_UNIVERSAL_STRING:
1070
- case self::TYPE_UTF8_STRING:
1071
- case self::TYPE_BMP_STRING:
1072
- case self::TYPE_IA5_STRING:
1073
- case self::TYPE_VISIBLE_STRING:
1074
- case self::TYPE_VIDEOTEX_STRING:
1075
- case self::TYPE_GRAPHIC_STRING:
1076
- case self::TYPE_GENERAL_STRING:
1077
- $value = $source;
1078
- break;
1079
- case self::TYPE_BOOLEAN:
1080
- $value = $source ? "\xFF" : "\x00";
1081
- break;
1082
- default:
1083
- user_error('Mapping provides no type definition for ' . implode('/', $this->location));
1084
- return false;
1085
- }
1086
-
1087
- if (isset($idx)) {
1088
- array_pop($this->location);
1089
- }
1090
-
1091
- if (isset($mapping['cast'])) {
1092
- if (isset($mapping['explicit']) || $mapping['type'] == self::TYPE_CHOICE) {
1093
- $value = chr($tag) . $this->_encodeLength(strlen($value)) . $value;
1094
- $tag = ($mapping['class'] << 6) | 0x20 | $mapping['cast'];
1095
- } else {
1096
- $tag = ($mapping['class'] << 6) | (ord($temp[0]) & 0x20) | $mapping['cast'];
1097
- }
1098
- }
1099
-
1100
- return chr($tag) . $this->_encodeLength(strlen($value)) . $value;
1101
- }
1102
-
1103
- /**
1104
- * DER-encode the length
1105
- *
1106
- * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See
1107
- * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
1108
- *
1109
- * @access private
1110
- * @param int $length
1111
- * @return string
1112
- */
1113
- function _encodeLength($length)
1114
- {
1115
- if ($length <= 0x7F) {
1116
- return chr($length);
1117
- }
1118
-
1119
- $temp = ltrim(pack('N', $length), chr(0));
1120
- return pack('Ca*', 0x80 | strlen($temp), $temp);
1121
- }
1122
-
1123
- /**
1124
- * BER-decode the time
1125
- *
1126
- * Called by _decode_ber() and in the case of implicit tags asn1map().
1127
- *
1128
- * @access private
1129
- * @param string $content
1130
- * @param int $tag
1131
- * @return string
1132
- */
1133
- function _decodeTime($content, $tag)
1134
- {
1135
- /* UTCTime:
1136
- http://tools.ietf.org/html/rfc5280#section-4.1.2.5.1
1137
- http://www.obj-sys.com/asn1tutorial/node15.html
1138
-
1139
- GeneralizedTime:
1140
- http://tools.ietf.org/html/rfc5280#section-4.1.2.5.2
1141
- http://www.obj-sys.com/asn1tutorial/node14.html */
1142
-
1143
- $format = 'YmdHis';
1144
-
1145
- if ($tag == self::TYPE_UTC_TIME) {
1146
- // https://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#page=28 says "the seconds
1147
- // element shall always be present" but none-the-less I've seen X509 certs where it isn't and if the
1148
- // browsers parse it phpseclib ought to too
1149
- if (preg_match('#^(\d{10})(Z|[+-]\d{4})$#', $content, $matches)) {
1150
- $content = $matches[1] . '00' . $matches[2];
1151
- }
1152
- $prefix = substr($content, 0, 2) >= 50 ? '19' : '20';
1153
- $content = $prefix . $content;
1154
- } elseif (strpos($content, '.') !== false) {
1155
- $format.= '.u';
1156
- }
1157
-
1158
- if ($content[strlen($content) - 1] == 'Z') {
1159
- $content = substr($content, 0, -1) . '+0000';
1160
- }
1161
-
1162
- if (strpos($content, '-') !== false || strpos($content, '+') !== false) {
1163
- $format.= 'O';
1164
- }
1165
-
1166
- // error supression isn't necessary as of PHP 7.0:
1167
- // http://php.net/manual/en/migration70.other-changes.php
1168
- return @DateTime::createFromFormat($format, $content);
1169
- }
1170
-
1171
- /**
1172
- * Set the time format
1173
- *
1174
- * Sets the time / date format for asn1map().
1175
- *
1176
- * @access public
1177
- * @param string $format
1178
- */
1179
- function setTimeFormat($format)
1180
- {
1181
- $this->format = $format;
1182
- }
1183
-
1184
- /**
1185
- * Load OIDs
1186
- *
1187
- * Load the relevant OIDs for a particular ASN.1 semantic mapping.
1188
- *
1189
- * @access public
1190
- * @param array $oids
1191
- */
1192
- function loadOIDs($oids)
1193
- {
1194
- $this->oids = $oids;
1195
- }
1196
-
1197
- /**
1198
- * Load filters
1199
- *
1200
- * See \phpseclib\File\X509, etc, for an example.
1201
- *
1202
- * @access public
1203
- * @param array $filters
1204
- */
1205
- function loadFilters($filters)
1206
- {
1207
- $this->filters = $filters;
1208
- }
1209
-
1210
- /**
1211
- * String Shift
1212
- *
1213
- * Inspired by array_shift
1214
- *
1215
- * @param string $string
1216
- * @param int $index
1217
- * @return string
1218
- * @access private
1219
- */
1220
- function _string_shift(&$string, $index = 1)
1221
- {
1222
- $substr = substr($string, 0, $index);
1223
- $string = substr($string, $index);
1224
- return $substr;
1225
- }
1226
-
1227
- /**
1228
- * String type conversion
1229
- *
1230
- * This is a lazy conversion, dealing only with character size.
1231
- * No real conversion table is used.
1232
- *
1233
- * @param string $in
1234
- * @param int $from
1235
- * @param int $to
1236
- * @return string
1237
- * @access public
1238
- */
1239
- function convert($in, $from = self::TYPE_UTF8_STRING, $to = self::TYPE_UTF8_STRING)
1240
- {
1241
- if (!isset($this->stringTypeSize[$from]) || !isset($this->stringTypeSize[$to])) {
1242
- return false;
1243
- }
1244
- $insize = $this->stringTypeSize[$from];
1245
- $outsize = $this->stringTypeSize[$to];
1246
- $inlength = strlen($in);
1247
- $out = '';
1248
-
1249
- for ($i = 0; $i < $inlength;) {
1250
- if ($inlength - $i < $insize) {
1251
- return false;
1252
- }
1253
-
1254
- // Get an input character as a 32-bit value.
1255
- $c = ord($in[$i++]);
1256
- switch (true) {
1257
- case $insize == 4:
1258
- $c = ($c << 8) | ord($in[$i++]);
1259
- $c = ($c << 8) | ord($in[$i++]);
1260
- case $insize == 2:
1261
- $c = ($c << 8) | ord($in[$i++]);
1262
- case $insize == 1:
1263
- break;
1264
- case ($c & 0x80) == 0x00:
1265
- break;
1266
- case ($c & 0x40) == 0x00:
1267
- return false;
1268
- default:
1269
- $bit = 6;
1270
- do {
1271
- if ($bit > 25 || $i >= $inlength || (ord($in[$i]) & 0xC0) != 0x80) {
1272
- return false;
1273
- }
1274
- $c = ($c << 6) | (ord($in[$i++]) & 0x3F);
1275
- $bit += 5;
1276
- $mask = 1 << $bit;
1277
- } while ($c & $bit);
1278
- $c &= $mask - 1;
1279
- break;
1280
- }
1281
-
1282
- // Convert and append the character to output string.
1283
- $v = '';
1284
- switch (true) {
1285
- case $outsize == 4:
1286
- $v .= chr($c & 0xFF);
1287
- $c >>= 8;
1288
- $v .= chr($c & 0xFF);
1289
- $c >>= 8;
1290
- case $outsize == 2:
1291
- $v .= chr($c & 0xFF);
1292
- $c >>= 8;
1293
- case $outsize == 1:
1294
- $v .= chr($c & 0xFF);
1295
- $c >>= 8;
1296
- if ($c) {
1297
- return false;
1298
- }
1299
- break;
1300
- case ($c & 0x80000000) != 0:
1301
- return false;
1302
- case $c >= 0x04000000:
1303
- $v .= chr(0x80 | ($c & 0x3F));
1304
- $c = ($c >> 6) | 0x04000000;
1305
- case $c >= 0x00200000:
1306
- $v .= chr(0x80 | ($c & 0x3F));
1307
- $c = ($c >> 6) | 0x00200000;
1308
- case $c >= 0x00010000:
1309
- $v .= chr(0x80 | ($c & 0x3F));
1310
- $c = ($c >> 6) | 0x00010000;
1311
- case $c >= 0x00000800:
1312
- $v .= chr(0x80 | ($c & 0x3F));
1313
- $c = ($c >> 6) | 0x00000800;
1314
- case $c >= 0x00000080:
1315
- $v .= chr(0x80 | ($c & 0x3F));
1316
- $c = ($c >> 6) | 0x000000C0;
1317
- default:
1318
- $v .= chr($c);
1319
- break;
1320
- }
1321
- $out .= strrev($v);
1322
- }
1323
- return $out;
1324
- }
1325
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/phpseclib/phpseclib/phpseclib/File/ASN1/Element.php DELETED
@@ -1,47 +0,0 @@
1
- <?php
2
- /**
3
- * Pure-PHP ASN.1 Parser
4
- *
5
- * PHP version 5
6
- *
7
- * @category File
8
- * @package ASN1
9
- * @author Jim Wigginton <terrafrost@php.net>
10
- * @copyright 2012 Jim Wigginton
11
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
12
- * @link http://phpseclib.sourceforge.net
13
- */
14
-
15
- namespace phpseclib\File\ASN1;
16
-
17
- /**
18
- * ASN.1 Element
19
- *
20
- * Bypass normal encoding rules in phpseclib\File\ASN1::encodeDER()
21
- *
22
- * @package ASN1
23
- * @author Jim Wigginton <terrafrost@php.net>
24
- * @access public
25
- */
26
- class Element
27
- {
28
- /**
29
- * Raw element value
30
- *
31
- * @var string
32
- * @access private
33
- */
34
- var $element;
35
-
36
- /**
37
- * Constructor
38
- *
39
- * @param string $encoded
40
- * @return \phpseclib\File\ASN1\Element
41
- * @access public
42
- */
43
- function __construct($encoded)
44
- {
45
- $this->element = $encoded;
46
- }
47
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/phpseclib/phpseclib/phpseclib/File/X509.php DELETED
@@ -1,4846 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Pure-PHP X.509 Parser
5
- *
6
- * PHP version 5
7
- *
8
- * Encode and decode X.509 certificates.
9
- *
10
- * The extensions are from {@link http://tools.ietf.org/html/rfc5280 RFC5280} and
11
- * {@link http://web.archive.org/web/19961027104704/http://www3.netscape.com/eng/security/cert-exts.html Netscape Certificate Extensions}.
12
- *
13
- * Note that loading an X.509 certificate and resaving it may invalidate the signature. The reason being that the signature is based on a
14
- * portion of the certificate that contains optional parameters with default values. ie. if the parameter isn't there the default value is
15
- * used. Problem is, if the parameter is there and it just so happens to have the default value there are two ways that that parameter can
16
- * be encoded. It can be encoded explicitly or left out all together. This would effect the signature value and thus may invalidate the
17
- * the certificate all together unless the certificate is re-signed.
18
- *
19
- * @category File
20
- * @package X509
21
- * @author Jim Wigginton <terrafrost@php.net>
22
- * @copyright 2012 Jim Wigginton
23
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
24
- * @link http://phpseclib.sourceforge.net
25
- */
26
-
27
- namespace phpseclib\File;
28
-
29
- use phpseclib\Crypt\Hash;
30
- use phpseclib\Crypt\Random;
31
- use phpseclib\Crypt\RSA;
32
- use phpseclib\File\ASN1\Element;
33
- use phpseclib\Math\BigInteger;
34
- use DateTime;
35
- use DateTimeZone;
36
-
37
- /**
38
- * Pure-PHP X.509 Parser
39
- *
40
- * @package X509
41
- * @author Jim Wigginton <terrafrost@php.net>
42
- * @access public
43
- */
44
- class X509
45
- {
46
- /**
47
- * Flag to only accept signatures signed by certificate authorities
48
- *
49
- * Not really used anymore but retained all the same to suppress E_NOTICEs from old installs
50
- *
51
- * @access public
52
- */
53
- const VALIDATE_SIGNATURE_BY_CA = 1;
54
-
55
- /**#@+
56
- * @access public
57
- * @see \phpseclib\File\X509::getDN()
58
- */
59
- /**
60
- * Return internal array representation
61
- */
62
- const DN_ARRAY = 0;
63
- /**
64
- * Return string
65
- */
66
- const DN_STRING = 1;
67
- /**
68
- * Return ASN.1 name string
69
- */
70
- const DN_ASN1 = 2;
71
- /**
72
- * Return OpenSSL compatible array
73
- */
74
- const DN_OPENSSL = 3;
75
- /**
76
- * Return canonical ASN.1 RDNs string
77
- */
78
- const DN_CANON = 4;
79
- /**
80
- * Return name hash for file indexing
81
- */
82
- const DN_HASH = 5;
83
- /**#@-*/
84
-
85
- /**#@+
86
- * @access public
87
- * @see \phpseclib\File\X509::saveX509()
88
- * @see \phpseclib\File\X509::saveCSR()
89
- * @see \phpseclib\File\X509::saveCRL()
90
- */
91
- /**
92
- * Save as PEM
93
- *
94
- * ie. a base64-encoded PEM with a header and a footer
95
- */
96
- const FORMAT_PEM = 0;
97
- /**
98
- * Save as DER
99
- */
100
- const FORMAT_DER = 1;
101
- /**
102
- * Save as a SPKAC
103
- *
104
- * Only works on CSRs. Not currently supported.
105
- */
106
- const FORMAT_SPKAC = 2;
107
- /**
108
- * Auto-detect the format
109
- *
110
- * Used only by the load*() functions
111
- */
112
- const FORMAT_AUTO_DETECT = 3;
113
- /**#@-*/
114
-
115
- /**
116
- * Attribute value disposition.
117
- * If disposition is >= 0, this is the index of the target value.
118
- */
119
- const ATTR_ALL = -1; // All attribute values (array).
120
- const ATTR_APPEND = -2; // Add a value.
121
- const ATTR_REPLACE = -3; // Clear first, then add a value.
122
-
123
- /**
124
- * ASN.1 syntax for X.509 certificates
125
- *
126
- * @var array
127
- * @access private
128
- */
129
- var $Certificate;
130
-
131
- /**#@+
132
- * ASN.1 syntax for various extensions
133
- *
134
- * @access private
135
- */
136
- var $DirectoryString;
137
- var $PKCS9String;
138
- var $AttributeValue;
139
- var $Extensions;
140
- var $KeyUsage;
141
- var $ExtKeyUsageSyntax;
142
- var $BasicConstraints;
143
- var $KeyIdentifier;
144
- var $CRLDistributionPoints;
145
- var $AuthorityKeyIdentifier;
146
- var $CertificatePolicies;
147
- var $AuthorityInfoAccessSyntax;
148
- var $SubjectAltName;
149
- var $SubjectDirectoryAttributes;
150
- var $PrivateKeyUsagePeriod;
151
- var $IssuerAltName;
152
- var $PolicyMappings;
153
- var $NameConstraints;
154
-
155
- var $CPSuri;
156
- var $UserNotice;
157
-
158
- var $netscape_cert_type;
159
- var $netscape_comment;
160
- var $netscape_ca_policy_url;
161
-
162
- var $Name;
163
- var $RelativeDistinguishedName;
164
- var $CRLNumber;
165
- var $CRLReason;
166
- var $IssuingDistributionPoint;
167
- var $InvalidityDate;
168
- var $CertificateIssuer;
169
- var $HoldInstructionCode;
170
- var $SignedPublicKeyAndChallenge;
171
- /**#@-*/
172
-
173
- /**#@+
174
- * ASN.1 syntax for various DN attributes
175
- *
176
- * @access private
177
- */
178
- var $PostalAddress;
179
- /**#@-*/
180
-
181
- /**
182
- * ASN.1 syntax for Certificate Signing Requests (RFC2986)
183
- *
184
- * @var array
185
- * @access private
186
- */
187
- var $CertificationRequest;
188
-
189
- /**
190
- * ASN.1 syntax for Certificate Revocation Lists (RFC5280)
191
- *
192
- * @var array
193
- * @access private
194
- */
195
- var $CertificateList;
196
-
197
- /**
198
- * Distinguished Name
199
- *
200
- * @var array
201
- * @access private
202
- */
203
- var $dn;
204
-
205
- /**
206
- * Public key
207
- *
208
- * @var string
209
- * @access private
210
- */
211
- var $publicKey;
212
-
213
- /**
214
- * Private key
215
- *
216
- * @var string
217
- * @access private
218
- */
219
- var $privateKey;
220
-
221
- /**
222
- * Object identifiers for X.509 certificates
223
- *
224
- * @var array
225
- * @access private
226
- * @link http://en.wikipedia.org/wiki/Object_identifier
227
- */
228
- var $oids;
229
-
230
- /**
231
- * The certificate authorities
232
- *
233
- * @var array
234
- * @access private
235
- */
236
- var $CAs;
237
-
238
- /**
239
- * The currently loaded certificate
240
- *
241
- * @var array
242
- * @access private
243
- */
244
- var $currentCert;
245
-
246
- /**
247
- * The signature subject
248
- *
249
- * There's no guarantee \phpseclib\File\X509 is going to re-encode an X.509 cert in the same way it was originally
250
- * encoded so we take save the portion of the original cert that the signature would have made for.
251
- *
252
- * @var string
253
- * @access private
254
- */
255
- var $signatureSubject;
256
-
257
- /**
258
- * Certificate Start Date
259
- *
260
- * @var string
261
- * @access private
262
- */
263
- var $startDate;
264
-
265
- /**
266
- * Certificate End Date
267
- *
268
- * @var string
269
- * @access private
270
- */
271
- var $endDate;
272
-
273
- /**
274
- * Serial Number
275
- *
276
- * @var string
277
- * @access private
278
- */
279
- var $serialNumber;
280
-
281
- /**
282
- * Key Identifier
283
- *
284
- * See {@link http://tools.ietf.org/html/rfc5280#section-4.2.1.1 RFC5280#section-4.2.1.1} and
285
- * {@link http://tools.ietf.org/html/rfc5280#section-4.2.1.2 RFC5280#section-4.2.1.2}.
286
- *
287
- * @var string
288
- * @access private
289
- */
290
- var $currentKeyIdentifier;
291
-
292
- /**
293
- * CA Flag
294
- *
295
- * @var bool
296
- * @access private
297
- */
298
- var $caFlag = false;
299
-
300
- /**
301
- * SPKAC Challenge
302
- *
303
- * @var string
304
- * @access private
305
- */
306
- var $challenge;
307
-
308
- /**
309
- * Default Constructor.
310
- *
311
- * @return \phpseclib\File\X509
312
- * @access public
313
- */
314
- function __construct()
315
- {
316
- // Explicitly Tagged Module, 1988 Syntax
317
- // http://tools.ietf.org/html/rfc5280#appendix-A.1
318
-
319
- $this->DirectoryString = array(
320
- 'type' => ASN1::TYPE_CHOICE,
321
- 'children' => array(
322
- 'teletexString' => array('type' => ASN1::TYPE_TELETEX_STRING),
323
- 'printableString' => array('type' => ASN1::TYPE_PRINTABLE_STRING),
324
- 'universalString' => array('type' => ASN1::TYPE_UNIVERSAL_STRING),
325
- 'utf8String' => array('type' => ASN1::TYPE_UTF8_STRING),
326
- 'bmpString' => array('type' => ASN1::TYPE_BMP_STRING)
327
- )
328
- );
329
-
330
- $this->PKCS9String = array(
331
- 'type' => ASN1::TYPE_CHOICE,
332
- 'children' => array(
333
- 'ia5String' => array('type' => ASN1::TYPE_IA5_STRING),
334
- 'directoryString' => $this->DirectoryString
335
- )
336
- );
337
-
338
- $this->AttributeValue = array('type' => ASN1::TYPE_ANY);
339
-
340
- $AttributeType = array('type' => ASN1::TYPE_OBJECT_IDENTIFIER);
341
-
342
- $AttributeTypeAndValue = array(
343
- 'type' => ASN1::TYPE_SEQUENCE,
344
- 'children' => array(
345
- 'type' => $AttributeType,
346
- 'value'=> $this->AttributeValue
347
- )
348
- );
349
-
350
- /*
351
- In practice, RDNs containing multiple name-value pairs (called "multivalued RDNs") are rare,
352
- but they can be useful at times when either there is no unique attribute in the entry or you
353
- want to ensure that the entry's DN contains some useful identifying information.
354
-
355
- - https://www.opends.org/wiki/page/DefinitionRelativeDistinguishedName
356
- */
357
- $this->RelativeDistinguishedName = array(
358
- 'type' => ASN1::TYPE_SET,
359
- 'min' => 1,
360
- 'max' => -1,
361
- 'children' => $AttributeTypeAndValue
362
- );
363
-
364
- // http://tools.ietf.org/html/rfc5280#section-4.1.2.4
365
- $RDNSequence = array(
366
- 'type' => ASN1::TYPE_SEQUENCE,
367
- // RDNSequence does not define a min or a max, which means it doesn't have one
368
- 'min' => 0,
369
- 'max' => -1,
370
- 'children' => $this->RelativeDistinguishedName
371
- );
372
-
373
- $this->Name = array(
374
- 'type' => ASN1::TYPE_CHOICE,
375
- 'children' => array(
376
- 'rdnSequence' => $RDNSequence
377
- )
378
- );
379
-
380
- // http://tools.ietf.org/html/rfc5280#section-4.1.1.2
381
- $AlgorithmIdentifier = array(
382
- 'type' => ASN1::TYPE_SEQUENCE,
383
- 'children' => array(
384
- 'algorithm' => array('type' => ASN1::TYPE_OBJECT_IDENTIFIER),
385
- 'parameters' => array(
386
- 'type' => ASN1::TYPE_ANY,
387
- 'optional' => true
388
- )
389
- )
390
- );
391
-
392
- /*
393
- A certificate using system MUST reject the certificate if it encounters
394
- a critical extension it does not recognize; however, a non-critical
395
- extension may be ignored if it is not recognized.
396
-
397
- http://tools.ietf.org/html/rfc5280#section-4.2
398
- */
399
- $Extension = array(
400
- 'type' => ASN1::TYPE_SEQUENCE,
401
- 'children' => array(
402
- 'extnId' => array('type' => ASN1::TYPE_OBJECT_IDENTIFIER),
403
- 'critical' => array(
404
- 'type' => ASN1::TYPE_BOOLEAN,
405
- 'optional' => true,
406
- 'default' => false
407
- ),
408
- 'extnValue' => array('type' => ASN1::TYPE_OCTET_STRING)
409
- )
410
- );
411
-
412
- $this->Extensions = array(
413
- 'type' => ASN1::TYPE_SEQUENCE,
414
- 'min' => 1,
415
- // technically, it's MAX, but we'll assume anything < 0 is MAX
416
- 'max' => -1,
417
- // if 'children' isn't an array then 'min' and 'max' must be defined
418
- 'children' => $Extension
419
- );
420
-
421
- $SubjectPublicKeyInfo = array(
422
- 'type' => ASN1::TYPE_SEQUENCE,
423
- 'children' => array(
424
- 'algorithm' => $AlgorithmIdentifier,
425
- 'subjectPublicKey' => array('type' => ASN1::TYPE_BIT_STRING)
426
- )
427
- );
428
-
429
- $UniqueIdentifier = array('type' => ASN1::TYPE_BIT_STRING);
430
-
431
- $Time = array(
432
- 'type' => ASN1::TYPE_CHOICE,
433
- 'children' => array(
434
- 'utcTime' => array('type' => ASN1::TYPE_UTC_TIME),
435
- 'generalTime' => array('type' => ASN1::TYPE_GENERALIZED_TIME)
436
- )
437
- );
438
-
439
- // http://tools.ietf.org/html/rfc5280#section-4.1.2.5
440
- $Validity = array(
441
- 'type' => ASN1::TYPE_SEQUENCE,
442
- 'children' => array(
443
- 'notBefore' => $Time,
444
- 'notAfter' => $Time
445
- )
446
- );
447
-
448
- $CertificateSerialNumber = array('type' => ASN1::TYPE_INTEGER);
449
-
450
- $Version = array(
451
- 'type' => ASN1::TYPE_INTEGER,
452
- 'mapping' => array('v1', 'v2', 'v3')
453
- );
454
-
455
- // assert($TBSCertificate['children']['signature'] == $Certificate['children']['signatureAlgorithm'])
456
- $TBSCertificate = array(
457
- 'type' => ASN1::TYPE_SEQUENCE,
458
- 'children' => array(
459
- // technically, default implies optional, but we'll define it as being optional, none-the-less, just to
460
- // reenforce that fact
461
- 'version' => array(
462
- 'constant' => 0,
463
- 'optional' => true,
464
- 'explicit' => true,
465
- 'default' => 'v1'
466
- ) + $Version,
467
- 'serialNumber' => $CertificateSerialNumber,
468
- 'signature' => $AlgorithmIdentifier,
469
- 'issuer' => $this->Name,
470
- 'validity' => $Validity,
471
- 'subject' => $this->Name,
472
- 'subjectPublicKeyInfo' => $SubjectPublicKeyInfo,
473
- // implicit means that the T in the TLV structure is to be rewritten, regardless of the type
474
- 'issuerUniqueID' => array(
475
- 'constant' => 1,
476
- 'optional' => true,
477
- 'implicit' => true
478
- ) + $UniqueIdentifier,
479
- 'subjectUniqueID' => array(
480
- 'constant' => 2,
481
- 'optional' => true,
482
- 'implicit' => true
483
- ) + $UniqueIdentifier,
484
- // <http://tools.ietf.org/html/rfc2459#page-74> doesn't use the EXPLICIT keyword but if
485
- // it's not IMPLICIT, it's EXPLICIT
486
- 'extensions' => array(
487
- 'constant' => 3,
488
- 'optional' => true,
489
- 'explicit' => true
490
- ) + $this->Extensions
491
- )
492
- );
493
-
494
- $this->Certificate = array(
495
- 'type' => ASN1::TYPE_SEQUENCE,
496
- 'children' => array(
497
- 'tbsCertificate' => $TBSCertificate,
498
- 'signatureAlgorithm' => $AlgorithmIdentifier,
499
- 'signature' => array('type' => ASN1::TYPE_BIT_STRING)
500
- )
501
- );
502
-
503
- $this->KeyUsage = array(
504
- 'type' => ASN1::TYPE_BIT_STRING,
505
- 'mapping' => array(
506
- 'digitalSignature',
507
- 'nonRepudiation',
508
- 'keyEncipherment',
509
- 'dataEncipherment',
510
- 'keyAgreement',
511
- 'keyCertSign',
512
- 'cRLSign',
513
- 'encipherOnly',
514
- 'decipherOnly'
515
- )
516
- );
517
-
518
- $this->BasicConstraints = array(
519
- 'type' => ASN1::TYPE_SEQUENCE,
520
- 'children' => array(
521
- 'cA' => array(
522
- 'type' => ASN1::TYPE_BOOLEAN,
523
- 'optional' => true,
524
- 'default' => false
525
- ),
526
- 'pathLenConstraint' => array(
527
- 'type' => ASN1::TYPE_INTEGER,
528
- 'optional' => true
529
- )
530
- )
531
- );
532
-
533
- $this->KeyIdentifier = array('type' => ASN1::TYPE_OCTET_STRING);
534
-
535
- $OrganizationalUnitNames = array(
536
- 'type' => ASN1::TYPE_SEQUENCE,
537
- 'min' => 1,
538
- 'max' => 4, // ub-organizational-units
539
- 'children' => array('type' => ASN1::TYPE_PRINTABLE_STRING)
540
- );
541
-
542
- $PersonalName = array(
543
- 'type' => ASN1::TYPE_SET,
544
- 'children' => array(
545
- 'surname' => array(
546
- 'type' => ASN1::TYPE_PRINTABLE_STRING,
547
- 'constant' => 0,
548
- 'optional' => true,
549
- 'implicit' => true
550
- ),
551
- 'given-name' => array(
552
- 'type' => ASN1::TYPE_PRINTABLE_STRING,
553
- 'constant' => 1,
554
- 'optional' => true,
555
- 'implicit' => true
556
- ),
557
- 'initials' => array(
558
- 'type' => ASN1::TYPE_PRINTABLE_STRING,
559
- 'constant' => 2,
560
- 'optional' => true,
561
- 'implicit' => true
562
- ),
563
- 'generation-qualifier' => array(
564
- 'type' => ASN1::TYPE_PRINTABLE_STRING,
565
- 'constant' => 3,
566
- 'optional' => true,
567
- 'implicit' => true
568
- )
569
- )
570
- );
571
-
572
- $NumericUserIdentifier = array('type' => ASN1::TYPE_NUMERIC_STRING);
573
-
574
- $OrganizationName = array('type' => ASN1::TYPE_PRINTABLE_STRING);
575
-
576
- $PrivateDomainName = array(
577
- 'type' => ASN1::TYPE_CHOICE,
578
- 'children' => array(
579
- 'numeric' => array('type' => ASN1::TYPE_NUMERIC_STRING),
580
- 'printable' => array('type' => ASN1::TYPE_PRINTABLE_STRING)
581
- )
582
- );
583
-
584
- $TerminalIdentifier = array('type' => ASN1::TYPE_PRINTABLE_STRING);
585
-
586
- $NetworkAddress = array('type' => ASN1::TYPE_NUMERIC_STRING);
587
-
588
- $AdministrationDomainName = array(
589
- 'type' => ASN1::TYPE_CHOICE,
590
- // if class isn't present it's assumed to be \phpseclib\File\ASN1::CLASS_UNIVERSAL or
591
- // (if constant is present) \phpseclib\File\ASN1::CLASS_CONTEXT_SPECIFIC
592
- 'class' => ASN1::CLASS_APPLICATION,
593
- 'cast' => 2,
594
- 'children' => array(
595
- 'numeric' => array('type' => ASN1::TYPE_NUMERIC_STRING),
596
- 'printable' => array('type' => ASN1::TYPE_PRINTABLE_STRING)
597
- )
598
- );
599
-
600
- $CountryName = array(
601
- 'type' => ASN1::TYPE_CHOICE,
602
- // if class isn't present it's assumed to be \phpseclib\File\ASN1::CLASS_UNIVERSAL or
603
- // (if constant is present) \phpseclib\File\ASN1::CLASS_CONTEXT_SPECIFIC
604
- 'class' => ASN1::CLASS_APPLICATION,
605
- 'cast' => 1,
606
- 'children' => array(
607
- 'x121-dcc-code' => array('type' => ASN1::TYPE_NUMERIC_STRING),
608
- 'iso-3166-alpha2-code' => array('type' => ASN1::TYPE_PRINTABLE_STRING)
609
- )
610
- );
611
-
612
- $AnotherName = array(
613
- 'type' => ASN1::TYPE_SEQUENCE,
614
- 'children' => array(
615
- 'type-id' => array('type' => ASN1::TYPE_OBJECT_IDENTIFIER),
616
- 'value' => array(
617
- 'type' => ASN1::TYPE_ANY,
618
- 'constant' => 0,
619
- 'optional' => true,
620
- 'explicit' => true
621
- )
622
- )
623
- );
624
-
625
- $ExtensionAttribute = array(
626
- 'type' => ASN1::TYPE_SEQUENCE,
627
- 'children' => array(
628
- 'extension-attribute-type' => array(
629
- 'type' => ASN1::TYPE_PRINTABLE_STRING,
630
- 'constant' => 0,
631
- 'optional' => true,
632
- 'implicit' => true
633
- ),
634
- 'extension-attribute-value' => array(
635
- 'type' => ASN1::TYPE_ANY,
636
- 'constant' => 1,
637
- 'optional' => true,
638
- 'explicit' => true
639
- )
640
- )
641
- );
642
-
643
- $ExtensionAttributes = array(
644
- 'type' => ASN1::TYPE_SET,
645
- 'min' => 1,
646
- 'max' => 256, // ub-extension-attributes
647
- 'children' => $ExtensionAttribute
648
- );
649
-
650
- $BuiltInDomainDefinedAttribute = array(
651
- 'type' => ASN1::TYPE_SEQUENCE,
652
- 'children' => array(
653
- 'type' => array('type' => ASN1::TYPE_PRINTABLE_STRING),
654
- 'value' => array('type' => ASN1::TYPE_PRINTABLE_STRING)
655
- )
656
- );
657
-
658
- $BuiltInDomainDefinedAttributes = array(
659
- 'type' => ASN1::TYPE_SEQUENCE,
660
- 'min' => 1,
661
- 'max' => 4, // ub-domain-defined-attributes
662
- 'children' => $BuiltInDomainDefinedAttribute
663
- );
664
-
665
- $BuiltInStandardAttributes = array(
666
- 'type' => ASN1::TYPE_SEQUENCE,
667
- 'children' => array(
668
- 'country-name' => array('optional' => true) + $CountryName,
669
- 'administration-domain-name' => array('optional' => true) + $AdministrationDomainName,
670
- 'network-address' => array(
671
- 'constant' => 0,
672
- 'optional' => true,
673
- 'implicit' => true
674
- ) + $NetworkAddress,
675
- 'terminal-identifier' => array(
676
- 'constant' => 1,
677
- 'optional' => true,
678
- 'implicit' => true
679
- ) + $TerminalIdentifier,
680
- 'private-domain-name' => array(
681
- 'constant' => 2,
682
- 'optional' => true,
683
- 'explicit' => true
684
- ) + $PrivateDomainName,
685
- 'organization-name' => array(
686
- 'constant' => 3,
687
- 'optional' => true,
688
- 'implicit' => true
689
- ) + $OrganizationName,
690
- 'numeric-user-identifier' => array(
691
- 'constant' => 4,
692
- 'optional' => true,
693
- 'implicit' => true
694
- ) + $NumericUserIdentifier,
695
- 'personal-name' => array(
696
- 'constant' => 5,
697
- 'optional' => true,
698
- 'implicit' => true
699
- ) + $PersonalName,
700
- 'organizational-unit-names' => array(
701
- 'constant' => 6,
702
- 'optional' => true,
703
- 'implicit' => true
704
- ) + $OrganizationalUnitNames
705
- )
706
- );
707
-
708
- $ORAddress = array(
709
- 'type' => ASN1::TYPE_SEQUENCE,
710
- 'children' => array(
711
- 'built-in-standard-attributes' => $BuiltInStandardAttributes,
712
- 'built-in-domain-defined-attributes' => array('optional' => true) + $BuiltInDomainDefinedAttributes,
713
- 'extension-attributes' => array('optional' => true) + $ExtensionAttributes
714
- )
715
- );
716
-
717
- $EDIPartyName = array(
718
- 'type' => ASN1::TYPE_SEQUENCE,
719
- 'children' => array(
720
- 'nameAssigner' => array(
721
- 'constant' => 0,
722
- 'optional' => true,
723
- 'implicit' => true
724
- ) + $this->DirectoryString,
725
- // partyName is technically required but \phpseclib\File\ASN1 doesn't currently support non-optional constants and
726
- // setting it to optional gets the job done in any event.
727
- 'partyName' => array(
728
- 'constant' => 1,
729
- 'optional' => true,
730
- 'implicit' => true
731
- ) + $this->DirectoryString
732
- )
733
- );
734
-
735
- $GeneralName = array(
736
- 'type' => ASN1::TYPE_CHOICE,
737
- 'children' => array(
738
- 'otherName' => array(
739
- 'constant' => 0,
740
- 'optional' => true,
741
- 'implicit' => true
742
- ) + $AnotherName,
743
- 'rfc822Name' => array(
744
- 'type' => ASN1::TYPE_IA5_STRING,
745
- 'constant' => 1,
746
- 'optional' => true,
747
- 'implicit' => true
748
- ),
749
- 'dNSName' => array(
750
- 'type' => ASN1::TYPE_IA5_STRING,
751
- 'constant' => 2,
752
- 'optional' => true,
753
- 'implicit' => true
754
- ),
755
- 'x400Address' => array(
756
- 'constant' => 3,
757
- 'optional' => true,
758
- 'implicit' => true
759
- ) + $ORAddress,
760
- 'directoryName' => array(
761
- 'constant' => 4,
762
- 'optional' => true,
763
- 'explicit' => true
764
- ) + $this->Name,
765
- 'ediPartyName' => array(
766
- 'constant' => 5,
767
- 'optional' => true,
768
- 'implicit' => true
769
- ) + $EDIPartyName,
770
- 'uniformResourceIdentifier' => array(
771
- 'type' => ASN1::TYPE_IA5_STRING,
772
- 'constant' => 6,
773
- 'optional' => true,
774
- 'implicit' => true
775
- ),
776
- 'iPAddress' => array(
777
- 'type' => ASN1::TYPE_OCTET_STRING,
778
- 'constant' => 7,
779
- 'optional' => true,
780
- 'implicit' => true
781
- ),
782
- 'registeredID' => array(
783
- 'type' => ASN1::TYPE_OBJECT_IDENTIFIER,
784
- 'constant' => 8,
785
- 'optional' => true,
786
- 'implicit' => true
787
- )
788
- )
789
- );
790
-
791
- $GeneralNames = array(
792
- 'type' => ASN1::TYPE_SEQUENCE,
793
- 'min' => 1,
794
- 'max' => -1,
795
- 'children' => $GeneralName
796
- );
797
-
798
- $this->IssuerAltName = $GeneralNames;
799
-
800
- $ReasonFlags = array(
801
- 'type' => ASN1::TYPE_BIT_STRING,
802
- 'mapping' => array(
803
- 'unused',
804
- 'keyCompromise',
805
- 'cACompromise',
806
- 'affiliationChanged',
807
- 'superseded',
808
- 'cessationOfOperation',
809
- 'certificateHold',
810
- 'privilegeWithdrawn',
811
- 'aACompromise'
812
- )
813
- );
814
-
815
- $DistributionPointName = array(
816
- 'type' => ASN1::TYPE_CHOICE,
817
- 'children' => array(
818
- 'fullName' => array(
819
- 'constant' => 0,
820
- 'optional' => true,
821
- 'implicit' => true
822
- ) + $GeneralNames,
823
- 'nameRelativeToCRLIssuer' => array(
824
- 'constant' => 1,
825
- 'optional' => true,
826
- 'implicit' => true
827
- ) + $this->RelativeDistinguishedName
828
- )
829
- );
830
-
831
- $DistributionPoint = array(
832
- 'type' => ASN1::TYPE_SEQUENCE,
833
- 'children' => array(
834
- 'distributionPoint' => array(
835
- 'constant' => 0,
836
- 'optional' => true,
837
- 'explicit' => true
838
- ) + $DistributionPointName,
839
- 'reasons' => array(
840
- 'constant' => 1,
841
- 'optional' => true,
842
- 'implicit' => true
843
- ) + $ReasonFlags,
844
- 'cRLIssuer' => array(
845
- 'constant' => 2,
846
- 'optional' => true,
847
- 'implicit' => true
848
- ) + $GeneralNames
849
- )
850
- );
851
-
852
- $this->CRLDistributionPoints = array(
853
- 'type' => ASN1::TYPE_SEQUENCE,
854
- 'min' => 1,
855
- 'max' => -1,
856
- 'children' => $DistributionPoint
857
- );
858
-
859
- $this->AuthorityKeyIdentifier = array(
860
- 'type' => ASN1::TYPE_SEQUENCE,
861
- 'children' => array(
862
- 'keyIdentifier' => array(
863
- 'constant' => 0,
864
- 'optional' => true,
865
- 'implicit' => true
866
- ) + $this->KeyIdentifier,
867
- 'authorityCertIssuer' => array(
868
- 'constant' => 1,
869
- 'optional' => true,
870
- 'implicit' => true
871
- ) + $GeneralNames,
872
- 'authorityCertSerialNumber' => array(
873
- 'constant' => 2,
874
- 'optional' => true,
875
- 'implicit' => true
876
- ) + $CertificateSerialNumber
877
- )
878
- );
879
-
880
- $PolicyQualifierId = array('type' => ASN1::TYPE_OBJECT_IDENTIFIER);
881
-
882
- $PolicyQualifierInfo = array(
883
- 'type' => ASN1::TYPE_SEQUENCE,
884
- 'children' => array(
885
- 'policyQualifierId' => $PolicyQualifierId,
886
- 'qualifier' => array('type' => ASN1::TYPE_ANY)
887
- )
888
- );
889
-
890
- $CertPolicyId = array('type' => ASN1::TYPE_OBJECT_IDENTIFIER);
891
-
892
- $PolicyInformation = array(
893
- 'type' => ASN1::TYPE_SEQUENCE,
894
- 'children' => array(
895
- 'policyIdentifier' => $CertPolicyId,
896
- 'policyQualifiers' => array(
897
- 'type' => ASN1::TYPE_SEQUENCE,
898
- 'min' => 0,
899
- 'max' => -1,
900
- 'optional' => true,
901
- 'children' => $PolicyQualifierInfo
902
- )
903
- )
904
- );
905
-
906
- $this->CertificatePolicies = array(
907
- 'type' => ASN1::TYPE_SEQUENCE,
908
- 'min' => 1,
909
- 'max' => -1,
910
- 'children' => $PolicyInformation
911
- );
912
-
913
- $this->PolicyMappings = array(
914
- 'type' => ASN1::TYPE_SEQUENCE,
915
- 'min' => 1,
916
- 'max' => -1,
917
- 'children' => array(
918
- 'type' => ASN1::TYPE_SEQUENCE,
919
- 'children' => array(
920
- 'issuerDomainPolicy' => $CertPolicyId,
921
- 'subjectDomainPolicy' => $CertPolicyId
922
- )
923
- )
924
- );
925
-
926
- $KeyPurposeId = array('type' => ASN1::TYPE_OBJECT_IDENTIFIER);
927
-
928
- $this->ExtKeyUsageSyntax = array(
929
- 'type' => ASN1::TYPE_SEQUENCE,
930
- 'min' => 1,
931
- 'max' => -1,
932
- 'children' => $KeyPurposeId
933
- );
934
-
935
- $AccessDescription = array(
936
- 'type' => ASN1::TYPE_SEQUENCE,
937
- 'children' => array(
938
- 'accessMethod' => array('type' => ASN1::TYPE_OBJECT_IDENTIFIER),
939
- 'accessLocation' => $GeneralName
940
- )
941
- );
942
-
943
- $this->AuthorityInfoAccessSyntax = array(
944
- 'type' => ASN1::TYPE_SEQUENCE,
945
- 'min' => 1,
946
- 'max' => -1,
947
- 'children' => $AccessDescription
948
- );
949
-
950
- $this->SubjectAltName = $GeneralNames;
951
-
952
- $this->PrivateKeyUsagePeriod = array(
953
- 'type' => ASN1::TYPE_SEQUENCE,
954
- 'children' => array(
955
- 'notBefore' => array(
956
- 'constant' => 0,
957
- 'optional' => true,
958
- 'implicit' => true,
959
- 'type' => ASN1::TYPE_GENERALIZED_TIME),
960
- 'notAfter' => array(
961
- 'constant' => 1,
962
- 'optional' => true,
963
- 'implicit' => true,
964
- 'type' => ASN1::TYPE_GENERALIZED_TIME)
965
- )
966
- );
967
-
968
- $BaseDistance = array('type' => ASN1::TYPE_INTEGER);
969
-
970
- $GeneralSubtree = array(
971
- 'type' => ASN1::TYPE_SEQUENCE,
972
- 'children' => array(
973
- 'base' => $GeneralName,
974
- 'minimum' => array(
975
- 'constant' => 0,
976
- 'optional' => true,
977
- 'implicit' => true,
978
- 'default' => new BigInteger(0)
979
- ) + $BaseDistance,
980
- 'maximum' => array(
981
- 'constant' => 1,
982
- 'optional' => true,
983
- 'implicit' => true,
984
- ) + $BaseDistance
985
- )
986
- );
987
-
988
- $GeneralSubtrees = array(
989
- 'type' => ASN1::TYPE_SEQUENCE,
990
- 'min' => 1,
991
- 'max' => -1,
992
- 'children' => $GeneralSubtree
993
- );
994
-
995
- $this->NameConstraints = array(
996
- 'type' => ASN1::TYPE_SEQUENCE,
997
- 'children' => array(
998
- 'permittedSubtrees' => array(
999
- 'constant' => 0,
1000
- 'optional' => true,
1001
- 'implicit' => true
1002
- ) + $GeneralSubtrees,
1003
- 'excludedSubtrees' => array(
1004
- 'constant' => 1,
1005
- 'optional' => true,
1006
- 'implicit' => true
1007
- ) + $GeneralSubtrees
1008
- )
1009
- );
1010
-
1011
- $this->CPSuri = array('type' => ASN1::TYPE_IA5_STRING);
1012
-
1013
- $DisplayText = array(
1014
- 'type' => ASN1::TYPE_CHOICE,
1015
- 'children' => array(
1016
- 'ia5String' => array('type' => ASN1::TYPE_IA5_STRING),
1017
- 'visibleString' => array('type' => ASN1::TYPE_VISIBLE_STRING),
1018
- 'bmpString' => array('type' => ASN1::TYPE_BMP_STRING),
1019
- 'utf8String' => array('type' => ASN1::TYPE_UTF8_STRING)
1020
- )
1021
- );
1022
-
1023
- $NoticeReference = array(
1024
- 'type' => ASN1::TYPE_SEQUENCE,
1025
- 'children' => array(
1026
- 'organization' => $DisplayText,
1027
- 'noticeNumbers' => array(
1028
- 'type' => ASN1::TYPE_SEQUENCE,
1029
- 'min' => 1,
1030
- 'max' => 200,
1031
- 'children' => array('type' => ASN1::TYPE_INTEGER)
1032
- )
1033
- )
1034
- );
1035
-
1036
- $this->UserNotice = array(
1037
- 'type' => ASN1::TYPE_SEQUENCE,
1038
- 'children' => array(
1039
- 'noticeRef' => array(
1040
- 'optional' => true,
1041
- 'implicit' => true
1042
- ) + $NoticeReference,
1043
- 'explicitText' => array(
1044
- 'optional' => true,
1045
- 'implicit' => true
1046
- ) + $DisplayText
1047
- )
1048
- );
1049
-
1050
- // mapping is from <http://www.mozilla.org/projects/security/pki/nss/tech-notes/tn3.html>
1051
- $this->netscape_cert_type = array(
1052
- 'type' => ASN1::TYPE_BIT_STRING,
1053
- 'mapping' => array(
1054
- 'SSLClient',
1055
- 'SSLServer',
1056
- 'Email',
1057
- 'ObjectSigning',
1058
- 'Reserved',
1059
- 'SSLCA',
1060
- 'EmailCA',
1061
- 'ObjectSigningCA'
1062
- )
1063
- );
1064
-
1065
- $this->netscape_comment = array('type' => ASN1::TYPE_IA5_STRING);
1066
- $this->netscape_ca_policy_url = array('type' => ASN1::TYPE_IA5_STRING);
1067
-
1068
- // attribute is used in RFC2986 but we're using the RFC5280 definition
1069
-
1070
- $Attribute = array(
1071
- 'type' => ASN1::TYPE_SEQUENCE,
1072
- 'children' => array(
1073
- 'type' => $AttributeType,
1074
- 'value'=> array(
1075
- 'type' => ASN1::TYPE_SET,
1076
- 'min' => 1,
1077
- 'max' => -1,
1078
- 'children' => $this->AttributeValue
1079
- )
1080
- )
1081
- );
1082
-
1083
- $this->SubjectDirectoryAttributes = array(
1084
- 'type' => ASN1::TYPE_SEQUENCE,
1085
- 'min' => 1,
1086
- 'max' => -1,
1087
- 'children' => $Attribute
1088
- );
1089
-
1090
- // adapted from <http://tools.ietf.org/html/rfc2986>
1091
-
1092
- $Attributes = array(
1093
- 'type' => ASN1::TYPE_SET,
1094
- 'min' => 1,
1095
- 'max' => -1,
1096
- 'children' => $Attribute
1097
- );
1098
-
1099
- $CertificationRequestInfo = array(
1100
- 'type' => ASN1::TYPE_SEQUENCE,
1101
- 'children' => array(
1102
- 'version' => array(
1103
- 'type' => ASN1::TYPE_INTEGER,
1104
- 'mapping' => array('v1')
1105
- ),
1106
- 'subject' => $this->Name,
1107
- 'subjectPKInfo' => $SubjectPublicKeyInfo,
1108
- 'attributes' => array(
1109
- 'constant' => 0,
1110
- 'optional' => true,
1111
- 'implicit' => true
1112
- ) + $Attributes,
1113
- )
1114
- );
1115
-
1116
- $this->CertificationRequest = array(
1117
- 'type' => ASN1::TYPE_SEQUENCE,
1118
- 'children' => array(
1119
- 'certificationRequestInfo' => $CertificationRequestInfo,
1120
- 'signatureAlgorithm' => $AlgorithmIdentifier,
1121
- 'signature' => array('type' => ASN1::TYPE_BIT_STRING)
1122
- )
1123
- );
1124
-
1125
- $RevokedCertificate = array(
1126
- 'type' => ASN1::TYPE_SEQUENCE,
1127
- 'children' => array(
1128
- 'userCertificate' => $CertificateSerialNumber,
1129
- 'revocationDate' => $Time,
1130
- 'crlEntryExtensions' => array(
1131
- 'optional' => true
1132
- ) + $this->Extensions
1133
- )
1134
- );
1135
-
1136
- $TBSCertList = array(
1137
- 'type' => ASN1::TYPE_SEQUENCE,
1138
- 'children' => array(
1139
- 'version' => array(
1140
- 'optional' => true,
1141
- 'default' => 'v1'
1142
- ) + $Version,
1143
- 'signature' => $AlgorithmIdentifier,
1144
- 'issuer' => $this->Name,
1145
- 'thisUpdate' => $Time,
1146
- 'nextUpdate' => array(
1147
- 'optional' => true
1148
- ) + $Time,
1149
- 'revokedCertificates' => array(
1150
- 'type' => ASN1::TYPE_SEQUENCE,
1151
- 'optional' => true,
1152
- 'min' => 0,
1153
- 'max' => -1,
1154
- 'children' => $RevokedCertificate
1155
- ),
1156
- 'crlExtensions' => array(
1157
- 'constant' => 0,
1158
- 'optional' => true,
1159
- 'explicit' => true
1160
- ) + $this->Extensions
1161
- )
1162
- );
1163
-
1164
- $this->CertificateList = array(
1165
- 'type' => ASN1::TYPE_SEQUENCE,
1166
- 'children' => array(
1167
- 'tbsCertList' => $TBSCertList,
1168
- 'signatureAlgorithm' => $AlgorithmIdentifier,
1169
- 'signature' => array('type' => ASN1::TYPE_BIT_STRING)
1170
- )
1171
- );
1172
-
1173
- $this->CRLNumber = array('type' => ASN1::TYPE_INTEGER);
1174
-
1175
- $this->CRLReason = array('type' => ASN1::TYPE_ENUMERATED,
1176
- 'mapping' => array(
1177
- 'unspecified',
1178
- 'keyCompromise',
1179
- 'cACompromise',
1180
- 'affiliationChanged',
1181
- 'superseded',
1182
- 'cessationOfOperation',
1183
- 'certificateHold',
1184
- // Value 7 is not used.
1185
- 8 => 'removeFromCRL',
1186
- 'privilegeWithdrawn',
1187
- 'aACompromise'
1188
- )
1189
- );
1190
-
1191
- $this->IssuingDistributionPoint = array('type' => ASN1::TYPE_SEQUENCE,
1192
- 'children' => array(
1193
- 'distributionPoint' => array(
1194
- 'constant' => 0,
1195
- 'optional' => true,
1196
- 'explicit' => true
1197
- ) + $DistributionPointName,
1198
- 'onlyContainsUserCerts' => array(
1199
- 'type' => ASN1::TYPE_BOOLEAN,
1200
- 'constant' => 1,
1201
- 'optional' => true,
1202
- 'default' => false,
1203
- 'implicit' => true
1204
- ),
1205
- 'onlyContainsCACerts' => array(
1206
- 'type' => ASN1::TYPE_BOOLEAN,
1207
- 'constant' => 2,
1208
- 'optional' => true,
1209
- 'default' => false,
1210
- 'implicit' => true
1211
- ),
1212
- 'onlySomeReasons' => array(
1213
- 'constant' => 3,
1214
- 'optional' => true,
1215
- 'implicit' => true
1216
- ) + $ReasonFlags,
1217
- 'indirectCRL' => array(
1218
- 'type' => ASN1::TYPE_BOOLEAN,
1219
- 'constant' => 4,
1220
- 'optional' => true,
1221
- 'default' => false,
1222
- 'implicit' => true
1223
- ),
1224
- 'onlyContainsAttributeCerts' => array(
1225
- 'type' => ASN1::TYPE_BOOLEAN,
1226
- 'constant' => 5,
1227
- 'optional' => true,
1228
- 'default' => false,
1229
- 'implicit' => true
1230
- )
1231
- )
1232
- );
1233
-
1234
- $this->InvalidityDate = array('type' => ASN1::TYPE_GENERALIZED_TIME);
1235
-
1236
- $this->CertificateIssuer = $GeneralNames;
1237
-
1238
- $this->HoldInstructionCode = array('type' => ASN1::TYPE_OBJECT_IDENTIFIER);
1239
-
1240
- $PublicKeyAndChallenge = array(
1241
- 'type' => ASN1::TYPE_SEQUENCE,
1242
- 'children' => array(
1243
- 'spki' => $SubjectPublicKeyInfo,
1244
- 'challenge' => array('type' => ASN1::TYPE_IA5_STRING)
1245
- )
1246
- );
1247
-
1248
- $this->SignedPublicKeyAndChallenge = array(
1249
- 'type' => ASN1::TYPE_SEQUENCE,
1250
- 'children' => array(
1251
- 'publicKeyAndChallenge' => $PublicKeyAndChallenge,
1252
- 'signatureAlgorithm' => $AlgorithmIdentifier,
1253
- 'signature' => array('type' => ASN1::TYPE_BIT_STRING)
1254
- )
1255
- );
1256
-
1257
- $this->PostalAddress = array(
1258
- 'type' => ASN1::TYPE_SEQUENCE,
1259
- 'optional' => true,
1260
- 'min' => 1,
1261
- 'max' => -1,
1262
- 'children' => $this->DirectoryString
1263
- );
1264
-
1265
- // OIDs from RFC5280 and those RFCs mentioned in RFC5280#section-4.1.1.2
1266
- $this->oids = array(
1267
- '1.3.6.1.5.5.7' => 'id-pkix',
1268
- '1.3.6.1.5.5.7.1' => 'id-pe',
1269
- '1.3.6.1.5.5.7.2' => 'id-qt',
1270
- '1.3.6.1.5.5.7.3' => 'id-kp',
1271
- '1.3.6.1.5.5.7.48' => 'id-ad',
1272
- '1.3.6.1.5.5.7.2.1' => 'id-qt-cps',
1273
- '1.3.6.1.5.5.7.2.2' => 'id-qt-unotice',
1274
- '1.3.6.1.5.5.7.48.1' =>'id-ad-ocsp',
1275
- '1.3.6.1.5.5.7.48.2' => 'id-ad-caIssuers',
1276
- '1.3.6.1.5.5.7.48.3' => 'id-ad-timeStamping',
1277
- '1.3.6.1.5.5.7.48.5' => 'id-ad-caRepository',
1278
- '2.5.4' => 'id-at',
1279
- '2.5.4.41' => 'id-at-name',
1280
- '2.5.4.4' => 'id-at-surname',
1281
- '2.5.4.42' => 'id-at-givenName',
1282
- '2.5.4.43' => 'id-at-initials',
1283
- '2.5.4.44' => 'id-at-generationQualifier',
1284
- '2.5.4.3' => 'id-at-commonName',
1285
- '2.5.4.7' => 'id-at-localityName',
1286
- '2.5.4.8' => 'id-at-stateOrProvinceName',
1287
- '2.5.4.10' => 'id-at-organizationName',
1288
- '2.5.4.11' => 'id-at-organizationalUnitName',
1289
- '2.5.4.12' => 'id-at-title',
1290
- '2.5.4.13' => 'id-at-description',
1291
- '2.5.4.46' => 'id-at-dnQualifier',
1292
- '2.5.4.6' => 'id-at-countryName',
1293
- '2.5.4.5' => 'id-at-serialNumber',
1294
- '2.5.4.65' => 'id-at-pseudonym',
1295
- '2.5.4.17' => 'id-at-postalCode',
1296
- '2.5.4.9' => 'id-at-streetAddress',
1297
- '2.5.4.45' => 'id-at-uniqueIdentifier',
1298
- '2.5.4.72' => 'id-at-role',
1299
- '2.5.4.16' => 'id-at-postalAddress',
1300
-
1301
- '0.9.2342.19200300.100.1.25' => 'id-domainComponent',
1302
- '1.2.840.113549.1.9' => 'pkcs-9',
1303
- '1.2.840.113549.1.9.1' => 'pkcs-9-at-emailAddress',
1304
- '2.5.29' => 'id-ce',
1305
- '2.5.29.35' => 'id-ce-authorityKeyIdentifier',
1306
- '2.5.29.14' => 'id-ce-subjectKeyIdentifier',
1307
- '2.5.29.15' => 'id-ce-keyUsage',
1308
- '2.5.29.16' => 'id-ce-privateKeyUsagePeriod',
1309
- '2.5.29.32' => 'id-ce-certificatePolicies',
1310
- '2.5.29.32.0' => 'anyPolicy',
1311
-
1312
- '2.5.29.33' => 'id-ce-policyMappings',
1313
- '2.5.29.17' => 'id-ce-subjectAltName',
1314
- '2.5.29.18' => 'id-ce-issuerAltName',
1315
- '2.5.29.9' => 'id-ce-subjectDirectoryAttributes',
1316
- '2.5.29.19' => 'id-ce-basicConstraints',
1317
- '2.5.29.30' => 'id-ce-nameConstraints',
1318
- '2.5.29.36' => 'id-ce-policyConstraints',
1319
- '2.5.29.31' => 'id-ce-cRLDistributionPoints',
1320
- '2.5.29.37' => 'id-ce-extKeyUsage',
1321
- '2.5.29.37.0' => 'anyExtendedKeyUsage',
1322
- '1.3.6.1.5.5.7.3.1' => 'id-kp-serverAuth',
1323
- '1.3.6.1.5.5.7.3.2' => 'id-kp-clientAuth',
1324
- '1.3.6.1.5.5.7.3.3' => 'id-kp-codeSigning',
1325
- '1.3.6.1.5.5.7.3.4' => 'id-kp-emailProtection',
1326
- '1.3.6.1.5.5.7.3.8' => 'id-kp-timeStamping',
1327
- '1.3.6.1.5.5.7.3.9' => 'id-kp-OCSPSigning',
1328
- '2.5.29.54' => 'id-ce-inhibitAnyPolicy',
1329
- '2.5.29.46' => 'id-ce-freshestCRL',
1330
- '1.3.6.1.5.5.7.1.1' => 'id-pe-authorityInfoAccess',
1331
- '1.3.6.1.5.5.7.1.11' => 'id-pe-subjectInfoAccess',
1332
- '2.5.29.20' => 'id-ce-cRLNumber',
1333
- '2.5.29.28' => 'id-ce-issuingDistributionPoint',
1334
- '2.5.29.27' => 'id-ce-deltaCRLIndicator',
1335
- '2.5.29.21' => 'id-ce-cRLReasons',
1336
- '2.5.29.29' => 'id-ce-certificateIssuer',
1337
- '2.5.29.23' => 'id-ce-holdInstructionCode',
1338
- '1.2.840.10040.2' => 'holdInstruction',
1339
- '1.2.840.10040.2.1' => 'id-holdinstruction-none',
1340
- '1.2.840.10040.2.2' => 'id-holdinstruction-callissuer',
1341
- '1.2.840.10040.2.3' => 'id-holdinstruction-reject',
1342
- '2.5.29.24' => 'id-ce-invalidityDate',
1343
-
1344
- '1.2.840.113549.2.2' => 'md2',
1345
- '1.2.840.113549.2.5' => 'md5',
1346
- '1.3.14.3.2.26' => 'id-sha1',
1347
- '1.2.840.10040.4.1' => 'id-dsa',
1348
- '1.2.840.10040.4.3' => 'id-dsa-with-sha1',
1349
- '1.2.840.113549.1.1' => 'pkcs-1',
1350
- '1.2.840.113549.1.1.1' => 'rsaEncryption',
1351
- '1.2.840.113549.1.1.2' => 'md2WithRSAEncryption',
1352
- '1.2.840.113549.1.1.4' => 'md5WithRSAEncryption',
1353
- '1.2.840.113549.1.1.5' => 'sha1WithRSAEncryption',
1354
- '1.2.840.10046.2.1' => 'dhpublicnumber',
1355
- '2.16.840.1.101.2.1.1.22' => 'id-keyExchangeAlgorithm',
1356
- '1.2.840.10045' => 'ansi-X9-62',
1357
- '1.2.840.10045.4' => 'id-ecSigType',
1358
- '1.2.840.10045.4.1' => 'ecdsa-with-SHA1',
1359
- '1.2.840.10045.1' => 'id-fieldType',
1360
- '1.2.840.10045.1.1' => 'prime-field',
1361
- '1.2.840.10045.1.2' => 'characteristic-two-field',
1362
- '1.2.840.10045.1.2.3' => 'id-characteristic-two-basis',
1363
- '1.2.840.10045.1.2.3.1' => 'gnBasis',
1364
- '1.2.840.10045.1.2.3.2' => 'tpBasis',
1365
- '1.2.840.10045.1.2.3.3' => 'ppBasis',
1366
- '1.2.840.10045.2' => 'id-publicKeyType',
1367
- '1.2.840.10045.2.1' => 'id-ecPublicKey',
1368
- '1.2.840.10045.3' => 'ellipticCurve',
1369
- '1.2.840.10045.3.0' => 'c-TwoCurve',
1370
- '1.2.840.10045.3.0.1' => 'c2pnb163v1',
1371
- '1.2.840.10045.3.0.2' => 'c2pnb163v2',
1372
- '1.2.840.10045.3.0.3' => 'c2pnb163v3',
1373
- '1.2.840.10045.3.0.4' => 'c2pnb176w1',
1374
- '1.2.840.10045.3.0.5' => 'c2pnb191v1',
1375
- '1.2.840.10045.3.0.6' => 'c2pnb191v2',
1376
- '1.2.840.10045.3.0.7' => 'c2pnb191v3',
1377
- '1.2.840.10045.3.0.8' => 'c2pnb191v4',
1378
- '1.2.840.10045.3.0.9' => 'c2pnb191v5',
1379
- '1.2.840.10045.3.0.10' => 'c2pnb208w1',
1380
- '1.2.840.10045.3.0.11' => 'c2pnb239v1',
1381
- '1.2.840.10045.3.0.12' => 'c2pnb239v2',
1382
- '1.2.840.10045.3.0.13' => 'c2pnb239v3',
1383
- '1.2.840.10045.3.0.14' => 'c2pnb239v4',
1384
- '1.2.840.10045.3.0.15' => 'c2pnb239v5',
1385
- '1.2.840.10045.3.0.16' => 'c2pnb272w1',
1386
- '1.2.840.10045.3.0.17' => 'c2pnb304w1',
1387
- '1.2.840.10045.3.0.18' => 'c2pnb359v1',
1388
- '1.2.840.10045.3.0.19' => 'c2pnb368w1',
1389
- '1.2.840.10045.3.0.20' => 'c2pnb431r1',
1390
- '1.2.840.10045.3.1' => 'primeCurve',
1391
- '1.2.840.10045.3.1.1' => 'prime192v1',
1392
- '1.2.840.10045.3.1.2' => 'prime192v2',
1393
- '1.2.840.10045.3.1.3' => 'prime192v3',
1394
- '1.2.840.10045.3.1.4' => 'prime239v1',
1395
- '1.2.840.10045.3.1.5' => 'prime239v2',
1396
- '1.2.840.10045.3.1.6' => 'prime239v3',
1397
- '1.2.840.10045.3.1.7' => 'prime256v1',
1398
- '1.2.840.113549.1.1.7' => 'id-RSAES-OAEP',
1399
- '1.2.840.113549.1.1.9' => 'id-pSpecified',
1400
- '1.2.840.113549.1.1.10' => 'id-RSASSA-PSS',
1401
- '1.2.840.113549.1.1.8' => 'id-mgf1',
1402
- '1.2.840.113549.1.1.14' => 'sha224WithRSAEncryption',
1403
- '1.2.840.113549.1.1.11' => 'sha256WithRSAEncryption',
1404
- '1.2.840.113549.1.1.12' => 'sha384WithRSAEncryption',
1405
- '1.2.840.113549.1.1.13' => 'sha512WithRSAEncryption',
1406
- '2.16.840.1.101.3.4.2.4' => 'id-sha224',
1407
- '2.16.840.1.101.3.4.2.1' => 'id-sha256',
1408
- '2.16.840.1.101.3.4.2.2' => 'id-sha384',
1409
- '2.16.840.1.101.3.4.2.3' => 'id-sha512',
1410
- '1.2.643.2.2.4' => 'id-GostR3411-94-with-GostR3410-94',
1411
- '1.2.643.2.2.3' => 'id-GostR3411-94-with-GostR3410-2001',
1412
- '1.2.643.2.2.20' => 'id-GostR3410-2001',
1413
- '1.2.643.2.2.19' => 'id-GostR3410-94',
1414
- // Netscape Object Identifiers from "Netscape Certificate Extensions"
1415
- '2.16.840.1.113730' => 'netscape',
1416
- '2.16.840.1.113730.1' => 'netscape-cert-extension',
1417
- '2.16.840.1.113730.1.1' => 'netscape-cert-type',
1418
- '2.16.840.1.113730.1.13' => 'netscape-comment',
1419
- '2.16.840.1.113730.1.8' => 'netscape-ca-policy-url',
1420
- // the following are X.509 extensions not supported by phpseclib
1421
- '1.3.6.1.5.5.7.1.12' => 'id-pe-logotype',
1422
- '1.2.840.113533.7.65.0' => 'entrustVersInfo',
1423
- '2.16.840.1.113733.1.6.9' => 'verisignPrivate',
1424
- // for Certificate Signing Requests
1425
- // see http://tools.ietf.org/html/rfc2985
1426
- '1.2.840.113549.1.9.2' => 'pkcs-9-at-unstructuredName', // PKCS #9 unstructured name
1427
- '1.2.840.113549.1.9.7' => 'pkcs-9-at-challengePassword', // Challenge password for certificate revocations
1428
- '1.2.840.113549.1.9.14' => 'pkcs-9-at-extensionRequest' // Certificate extension request
1429
- );
1430
- }
1431
-
1432
- /**
1433
- * Load X.509 certificate
1434
- *
1435
- * Returns an associative array describing the X.509 cert or a false if the cert failed to load
1436
- *
1437
- * @param string $cert
1438
- * @param int $mode
1439
- * @access public
1440
- * @return mixed
1441
- */
1442
- function loadX509($cert, $mode = self::FORMAT_AUTO_DETECT)
1443
- {
1444
- if (is_array($cert) && isset($cert['tbsCertificate'])) {
1445
- unset($this->currentCert);
1446
- unset($this->currentKeyIdentifier);
1447
- $this->dn = $cert['tbsCertificate']['subject'];
1448
- if (!isset($this->dn)) {
1449
- return false;
1450
- }
1451
- $this->currentCert = $cert;
1452
-
1453
- $currentKeyIdentifier = $this->getExtension('id-ce-subjectKeyIdentifier');
1454
- $this->currentKeyIdentifier = is_string($currentKeyIdentifier) ? $currentKeyIdentifier : null;
1455
-
1456
- unset($this->signatureSubject);
1457
-
1458
- return $cert;
1459
- }
1460
-
1461
- $asn1 = new ASN1();
1462
-
1463
- if ($mode != self::FORMAT_DER) {
1464
- $newcert = $this->_extractBER($cert);
1465
- if ($mode == self::FORMAT_PEM && $cert == $newcert) {
1466
- return false;
1467
- }
1468
- $cert = $newcert;
1469
- }
1470
-
1471
- if ($cert === false) {
1472
- $this->currentCert = false;
1473
- return false;
1474
- }
1475
-
1476
- $asn1->loadOIDs($this->oids);
1477
- $decoded = $asn1->decodeBER($cert);
1478
-
1479
- if (!empty($decoded)) {
1480
- $x509 = $asn1->asn1map($decoded[0], $this->Certificate);
1481
- }
1482
- if (!isset($x509) || $x509 === false) {
1483
- $this->currentCert = false;
1484
- return false;
1485
- }
1486
-
1487
- $this->signatureSubject = substr($cert, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']);
1488
-
1489
- if ($this->_isSubArrayValid($x509, 'tbsCertificate/extensions')) {
1490
- $this->_mapInExtensions($x509, 'tbsCertificate/extensions', $asn1);
1491
- }
1492
- $this->_mapInDNs($x509, 'tbsCertificate/issuer/rdnSequence', $asn1);
1493
- $this->_mapInDNs($x509, 'tbsCertificate/subject/rdnSequence', $asn1);
1494
-
1495
- $key = &$x509['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'];
1496
- $key = $this->_reformatKey($x509['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['algorithm'], $key);
1497
-
1498
- $this->currentCert = $x509;
1499
- $this->dn = $x509['tbsCertificate']['subject'];
1500
-
1501
- $currentKeyIdentifier = $this->getExtension('id-ce-subjectKeyIdentifier');
1502
- $this->currentKeyIdentifier = is_string($currentKeyIdentifier) ? $currentKeyIdentifier : null;
1503
-
1504
- return $x509;
1505
- }
1506
-
1507
- /**
1508
- * Save X.509 certificate
1509
- *
1510
- * @param array $cert
1511
- * @param int $format optional
1512
- * @access public
1513
- * @return string
1514
- */
1515
- function saveX509($cert, $format = self::FORMAT_PEM)
1516
- {
1517
- if (!is_array($cert) || !isset($cert['tbsCertificate'])) {
1518
- return false;
1519
- }
1520
-
1521
- switch (true) {
1522
- // "case !$a: case !$b: break; default: whatever();" is the same thing as "if ($a && $b) whatever()"
1523
- case !($algorithm = $this->_subArray($cert, 'tbsCertificate/subjectPublicKeyInfo/algorithm/algorithm')):
1524
- case is_object($cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']):
1525
- break;
1526
- default:
1527
- switch ($algorithm) {
1528
- case 'rsaEncryption':
1529
- $cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']
1530
- = base64_encode("\0" . base64_decode(preg_replace('#-.+-|[\r\n]#', '', $cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'])));
1531
- /* "[For RSA keys] the parameters field MUST have ASN.1 type NULL for this algorithm identifier."
1532
- -- https://tools.ietf.org/html/rfc3279#section-2.3.1
1533
-
1534
- given that and the fact that RSA keys appear ot be the only key type for which the parameters field can be blank,
1535
- it seems like perhaps the ASN.1 description ought not say the parameters field is OPTIONAL, but whatever.
1536
- */
1537
- $cert['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['parameters'] = null;
1538
- // https://tools.ietf.org/html/rfc3279#section-2.2.1
1539
- $cert['signatureAlgorithm']['parameters'] = null;
1540
- $cert['tbsCertificate']['signature']['parameters'] = null;
1541
- }
1542
- }
1543
-
1544
- $asn1 = new ASN1();
1545
- $asn1->loadOIDs($this->oids);
1546
-
1547
- $filters = array();
1548
- $type_utf8_string = array('type' => ASN1::TYPE_UTF8_STRING);
1549
- $filters['tbsCertificate']['signature']['parameters'] = $type_utf8_string;
1550
- $filters['tbsCertificate']['signature']['issuer']['rdnSequence']['value'] = $type_utf8_string;
1551
- $filters['tbsCertificate']['issuer']['rdnSequence']['value'] = $type_utf8_string;
1552
- $filters['tbsCertificate']['subject']['rdnSequence']['value'] = $type_utf8_string;
1553
- $filters['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['parameters'] = $type_utf8_string;
1554
- $filters['signatureAlgorithm']['parameters'] = $type_utf8_string;
1555
- $filters['authorityCertIssuer']['directoryName']['rdnSequence']['value'] = $type_utf8_string;
1556
- //$filters['policyQualifiers']['qualifier'] = $type_utf8_string;
1557
- $filters['distributionPoint']['fullName']['directoryName']['rdnSequence']['value'] = $type_utf8_string;
1558
- $filters['directoryName']['rdnSequence']['value'] = $type_utf8_string;
1559
-
1560
- /* in the case of policyQualifiers/qualifier, the type has to be \phpseclib\File\ASN1::TYPE_IA5_STRING.
1561
- \phpseclib\File\ASN1::TYPE_PRINTABLE_STRING will cause OpenSSL's X.509 parser to spit out random
1562
- characters.
1563
- */
1564
- $filters['policyQualifiers']['qualifier']
1565
- = array('type' => ASN1::TYPE_IA5_STRING);
1566
-
1567
- $asn1->loadFilters($filters);
1568
-
1569
- $this->_mapOutExtensions($cert, 'tbsCertificate/extensions', $asn1);
1570
- $this->_mapOutDNs($cert, 'tbsCertificate/issuer/rdnSequence', $asn1);
1571
- $this->_mapOutDNs($cert, 'tbsCertificate/subject/rdnSequence', $asn1);
1572
-
1573
- $cert = $asn1->encodeDER($cert, $this->Certificate);
1574
-
1575
- switch ($format) {
1576
- case self::FORMAT_DER:
1577
- return $cert;
1578
- // case self::FORMAT_PEM:
1579
- default:
1580
- return "-----BEGIN CERTIFICATE-----\r\n" . chunk_split(base64_encode($cert), 64) . '-----END CERTIFICATE-----';
1581
- }
1582
- }
1583
-
1584
- /**
1585
- * Map extension values from octet string to extension-specific internal
1586
- * format.
1587
- *
1588
- * @param array ref $root
1589
- * @param string $path
1590
- * @param object $asn1
1591
- * @access private
1592
- */
1593
- function _mapInExtensions(&$root, $path, $asn1)
1594
- {
1595
- $extensions = &$this->_subArrayUnchecked($root, $path);
1596
-
1597
- if ($extensions) {
1598
- for ($i = 0; $i < count($extensions); $i++) {
1599
- $id = $extensions[$i]['extnId'];
1600
- $value = &$extensions[$i]['extnValue'];
1601
- $value = base64_decode($value);
1602
- $decoded = $asn1->decodeBER($value);
1603
- /* [extnValue] contains the DER encoding of an ASN.1 value
1604
- corresponding to the extension type identified by extnID */
1605
- $map = $this->_getMapping($id);
1606
- if (!is_bool($map)) {
1607
- $mapped = $asn1->asn1map($decoded[0], $map, array('iPAddress' => array($this, '_decodeIP')));
1608
- $value = $mapped === false ? $decoded[0] : $mapped;
1609
-
1610
- if ($id == 'id-ce-certificatePolicies') {
1611
- for ($j = 0; $j < count($value); $j++) {
1612
- if (!isset($value[$j]['policyQualifiers'])) {
1613
- continue;
1614
- }
1615
- for ($k = 0; $k < count($value[$j]['policyQualifiers']); $k++) {
1616
- $subid = $value[$j]['policyQualifiers'][$k]['policyQualifierId'];
1617
- $map = $this->_getMapping($subid);
1618
- $subvalue = &$value[$j]['policyQualifiers'][$k]['qualifier'];
1619
- if ($map !== false) {
1620
- $decoded = $asn1->decodeBER($subvalue);
1621
- $mapped = $asn1->asn1map($decoded[0], $map);
1622
- $subvalue = $mapped === false ? $decoded[0] : $mapped;
1623
- }
1624
- }
1625
- }
1626
- }
1627
- } else {
1628
- $value = base64_encode($value);
1629
- }
1630
- }
1631
- }
1632
- }
1633
-
1634
- /**
1635
- * Map extension values from extension-specific internal format to
1636
- * octet string.
1637
- *
1638
- * @param array ref $root
1639
- * @param string $path
1640
- * @param object $asn1
1641
- * @access private
1642
- */
1643
- function _mapOutExtensions(&$root, $path, $asn1)
1644
- {
1645
- $extensions = &$this->_subArray($root, $path);
1646
-
1647
- if (is_array($extensions)) {
1648
- $size = count($extensions);
1649
- for ($i = 0; $i < $size; $i++) {
1650
- if ($extensions[$i] instanceof Element) {
1651
- continue;
1652
- }
1653
-
1654
- $id = $extensions[$i]['extnId'];
1655
- $value = &$extensions[$i]['extnValue'];
1656
-
1657
- switch ($id) {
1658
- case 'id-ce-certificatePolicies':
1659
- for ($j = 0; $j < count($value); $j++) {
1660
- if (!isset($value[$j]['policyQualifiers'])) {
1661
- continue;
1662
- }
1663
- for ($k = 0; $k < count($value[$j]['policyQualifiers']); $k++) {
1664
- $subid = $value[$j]['policyQualifiers'][$k]['policyQualifierId'];
1665
- $map = $this->_getMapping($subid);
1666
- $subvalue = &$value[$j]['policyQualifiers'][$k]['qualifier'];
1667
- if ($map !== false) {
1668
- // by default \phpseclib\File\ASN1 will try to render qualifier as a \phpseclib\File\ASN1::TYPE_IA5_STRING since it's
1669
- // actual type is \phpseclib\File\ASN1::TYPE_ANY
1670
- $subvalue = new Element($asn1->encodeDER($subvalue, $map));
1671
- }
1672
- }
1673
- }
1674
- break;
1675
- case 'id-ce-authorityKeyIdentifier': // use 00 as the serial number instead of an empty string
1676
- if (isset($value['authorityCertSerialNumber'])) {
1677
- if ($value['authorityCertSerialNumber']->toBytes() == '') {
1678
- $temp = chr((ASN1::CLASS_CONTEXT_SPECIFIC << 6) | 2) . "\1\0";
1679
- $value['authorityCertSerialNumber'] = new Element($temp);
1680
- }
1681
- }
1682
- }
1683
-
1684
- /* [extnValue] contains the DER encoding of an ASN.1 value
1685
- corresponding to the extension type identified by extnID */
1686
- $map = $this->_getMapping($id);
1687
- if (is_bool($map)) {
1688
- if (!$map) {
1689
- user_error($id . ' is not a currently supported extension');
1690
- unset($extensions[$i]);
1691
- }
1692
- } else {
1693
- $temp = $asn1->encodeDER($value, $map, array('iPAddress' => array($this, '_encodeIP')));
1694
- $value = base64_encode($temp);
1695
- }
1696
- }
1697
- }
1698
- }
1699
-
1700
- /**
1701
- * Map attribute values from ANY type to attribute-specific internal
1702
- * format.
1703
- *
1704
- * @param array ref $root
1705
- * @param string $path
1706
- * @param object $asn1
1707
- * @access private
1708
- */
1709
- function _mapInAttributes(&$root, $path, $asn1)
1710
- {
1711
- $attributes = &$this->_subArray($root, $path);
1712
-
1713
- if (is_array($attributes)) {
1714
- for ($i = 0; $i < count($attributes); $i++) {
1715
- $id = $attributes[$i]['type'];
1716
- /* $value contains the DER encoding of an ASN.1 value
1717
- corresponding to the attribute type identified by type */
1718
- $map = $this->_getMapping($id);
1719
- if (is_array($attributes[$i]['value'])) {
1720
- $values = &$attributes[$i]['value'];
1721
- for ($j = 0; $j < count($values); $j++) {
1722
- $value = $asn1->encodeDER($values[$j], $this->AttributeValue);
1723
- $decoded = $asn1->decodeBER($value);
1724
- if (!is_bool($map)) {
1725
- $mapped = $asn1->asn1map($decoded[0], $map);
1726
- if ($mapped !== false) {
1727
- $values[$j] = $mapped;
1728
- }
1729
- if ($id == 'pkcs-9-at-extensionRequest' && $this->_isSubArrayValid($values, $j)) {
1730
- $this->_mapInExtensions($values, $j, $asn1);
1731
- }
1732
- } elseif ($map) {
1733
- $values[$j] = base64_encode($value);
1734
- }
1735
- }
1736
- }
1737
- }
1738
- }
1739
- }
1740
-
1741
- /**
1742
- * Map attribute values from attribute-specific internal format to
1743
- * ANY type.
1744
- *
1745
- * @param array ref $root
1746
- * @param string $path
1747
- * @param object $asn1
1748
- * @access private
1749
- */
1750
- function _mapOutAttributes(&$root, $path, $asn1)
1751
- {
1752
- $attributes = &$this->_subArray($root, $path);
1753
-
1754
- if (is_array($attributes)) {
1755
- $size = count($attributes);
1756
- for ($i = 0; $i < $size; $i++) {
1757
- /* [value] contains the DER encoding of an ASN.1 value
1758
- corresponding to the attribute type identified by type */
1759
- $id = $attributes[$i]['type'];
1760
- $map = $this->_getMapping($id);
1761
- if ($map === false) {
1762
- user_error($id . ' is not a currently supported attribute', E_USER_NOTICE);
1763
- unset($attributes[$i]);
1764
- } elseif (is_array($attributes[$i]['value'])) {
1765
- $values = &$attributes[$i]['value'];
1766
- for ($j = 0; $j < count($values); $j++) {
1767
- switch ($id) {
1768
- case 'pkcs-9-at-extensionRequest':
1769
- $this->_mapOutExtensions($values, $j, $asn1);
1770
- break;
1771
- }
1772
-
1773
- if (!is_bool($map)) {
1774
- $temp = $asn1->encodeDER($values[$j], $map);
1775
- $decoded = $asn1->decodeBER($temp);
1776
- $values[$j] = $asn1->asn1map($decoded[0], $this->AttributeValue);
1777
- }
1778
- }
1779
- }
1780
- }
1781
- }
1782
- }
1783
-
1784
- /**
1785
- * Map DN values from ANY type to DN-specific internal
1786
- * format.
1787
- *
1788
- * @param array ref $root
1789
- * @param string $path
1790
- * @param object $asn1
1791
- * @access private
1792
- */
1793
- function _mapInDNs(&$root, $path, $asn1)
1794
- {
1795
- $dns = &$this->_subArray($root, $path);
1796
-
1797
- if (is_array($dns)) {
1798
- for ($i = 0; $i < count($dns); $i++) {
1799
- for ($j = 0; $j < count($dns[$i]); $j++) {
1800
- $type = $dns[$i][$j]['type'];
1801
- $value = &$dns[$i][$j]['value'];
1802
- if (is_object($value) && $value instanceof Element) {
1803
- $map = $this->_getMapping($type);
1804
- if (!is_bool($map)) {
1805
- $decoded = $asn1->decodeBER($value);
1806
- $value = $asn1->asn1map($decoded[0], $map);
1807
- }
1808
- }
1809
- }
1810
- }
1811
- }
1812
- }
1813
-
1814
- /**
1815
- * Map DN values from DN-specific internal format to
1816
- * ANY type.
1817
- *
1818
- * @param array ref $root
1819
- * @param string $path
1820
- * @param object $asn1
1821
- * @access private
1822
- */
1823
- function _mapOutDNs(&$root, $path, $asn1)
1824
- {
1825
- $dns = &$this->_subArray($root, $path);
1826
-
1827
- if (is_array($dns)) {
1828
- $size = count($dns);
1829
- for ($i = 0; $i < $size; $i++) {
1830
- for ($j = 0; $j < count($dns[$i]); $j++) {
1831
- $type = $dns[$i][$j]['type'];
1832
- $value = &$dns[$i][$j]['value'];
1833
- if (is_object($value) && $value instanceof Element) {
1834
- continue;
1835
- }
1836
-
1837
- $map = $this->_getMapping($type);
1838
- if (!is_bool($map)) {
1839
- $value = new Element($asn1->encodeDER($value, $map));
1840
- }
1841
- }
1842
- }
1843
- }
1844
- }
1845
-
1846
- /**
1847
- * Associate an extension ID to an extension mapping
1848
- *
1849
- * @param string $extnId
1850
- * @access private
1851
- * @return mixed
1852
- */
1853
- function _getMapping($extnId)
1854
- {
1855
- if (!is_string($extnId)) { // eg. if it's a \phpseclib\File\ASN1\Element object
1856
- return true;
1857
- }
1858
-
1859
- switch ($extnId) {
1860
- case 'id-ce-keyUsage':
1861
- return $this->KeyUsage;
1862
- case 'id-ce-basicConstraints':
1863
- return $this->BasicConstraints;
1864
- case 'id-ce-subjectKeyIdentifier':
1865
- return $this->KeyIdentifier;
1866
- case 'id-ce-cRLDistributionPoints':
1867
- return $this->CRLDistributionPoints;
1868
- case 'id-ce-authorityKeyIdentifier':
1869
- return $this->AuthorityKeyIdentifier;
1870
- case 'id-ce-certificatePolicies':
1871
- return $this->CertificatePolicies;
1872
- case 'id-ce-extKeyUsage':
1873
- return $this->ExtKeyUsageSyntax;
1874
- case 'id-pe-authorityInfoAccess':
1875
- return $this->AuthorityInfoAccessSyntax;
1876
- case 'id-ce-subjectAltName':
1877
- return $this->SubjectAltName;
1878
- case 'id-ce-subjectDirectoryAttributes':
1879
- return $this->SubjectDirectoryAttributes;
1880
- case 'id-ce-privateKeyUsagePeriod':
1881
- return $this->PrivateKeyUsagePeriod;
1882
- case 'id-ce-issuerAltName':
1883
- return $this->IssuerAltName;
1884
- case 'id-ce-policyMappings':
1885
- return $this->PolicyMappings;
1886
- case 'id-ce-nameConstraints':
1887
- return $this->NameConstraints;
1888
-
1889
- case 'netscape-cert-type':
1890
- return $this->netscape_cert_type;
1891
- case 'netscape-comment':
1892
- return $this->netscape_comment;
1893
- case 'netscape-ca-policy-url':
1894
- return $this->netscape_ca_policy_url;
1895
-
1896
- // since id-qt-cps isn't a constructed type it will have already been decoded as a string by the time it gets
1897
- // back around to asn1map() and we don't want it decoded again.
1898
- //case 'id-qt-cps':
1899
- // return $this->CPSuri;
1900
- case 'id-qt-unotice':
1901
- return $this->UserNotice;
1902
-
1903
- // the following OIDs are unsupported but we don't want them to give notices when calling saveX509().
1904
- case 'id-pe-logotype': // http://www.ietf.org/rfc/rfc3709.txt
1905
- case 'entrustVersInfo':
1906
- // http://support.microsoft.com/kb/287547
1907
- case '1.3.6.1.4.1.311.20.2': // szOID_ENROLL_CERTTYPE_EXTENSION
1908
- case '1.3.6.1.4.1.311.21.1': // szOID_CERTSRV_CA_VERSION
1909
- // "SET Secure Electronic Transaction Specification"
1910
- // http://www.maithean.com/docs/set_bk3.pdf
1911
- case '2.23.42.7.0': // id-set-hashedRootKey
1912
- // "Certificate Transparency"
1913
- // https://tools.ietf.org/html/rfc6962
1914
- case '1.3.6.1.4.1.11129.2.4.2':
1915
- return true;
1916
-
1917
- // CSR attributes
1918
- case 'pkcs-9-at-unstructuredName':
1919
- return $this->PKCS9String;
1920
- case 'pkcs-9-at-challengePassword':
1921
- return $this->DirectoryString;
1922
- case 'pkcs-9-at-extensionRequest':
1923
- return $this->Extensions;
1924
-
1925
- // CRL extensions.
1926
- case 'id-ce-cRLNumber':
1927
- return $this->CRLNumber;
1928
- case 'id-ce-deltaCRLIndicator':
1929
- return $this->CRLNumber;
1930
- case 'id-ce-issuingDistributionPoint':
1931
- return $this->IssuingDistributionPoint;
1932
- case 'id-ce-freshestCRL':
1933
- return $this->CRLDistributionPoints;
1934
- case 'id-ce-cRLReasons':
1935
- return $this->CRLReason;
1936
- case 'id-ce-invalidityDate':
1937
- return $this->InvalidityDate;
1938
- case 'id-ce-certificateIssuer':
1939
- return $this->CertificateIssuer;
1940
- case 'id-ce-holdInstructionCode':
1941
- return $this->HoldInstructionCode;
1942
- case 'id-at-postalAddress':
1943
- return $this->PostalAddress;
1944
- }
1945
-
1946
- return false;
1947
- }
1948
-
1949
- /**
1950
- * Load an X.509 certificate as a certificate authority
1951
- *
1952
- * @param string $cert
1953
- * @access public
1954
- * @return bool
1955
- */
1956
- function loadCA($cert)
1957
- {
1958
- $olddn = $this->dn;
1959
- $oldcert = $this->currentCert;
1960
- $oldsigsubj = $this->signatureSubject;
1961
- $oldkeyid = $this->currentKeyIdentifier;
1962
-
1963
- $cert = $this->loadX509($cert);
1964
- if (!$cert) {
1965
- $this->dn = $olddn;
1966
- $this->currentCert = $oldcert;
1967
- $this->signatureSubject = $oldsigsubj;
1968
- $this->currentKeyIdentifier = $oldkeyid;
1969
-
1970
- return false;
1971
- }
1972
-
1973
- /* From RFC5280 "PKIX Certificate and CRL Profile":
1974
-
1975
- If the keyUsage extension is present, then the subject public key
1976
- MUST NOT be used to verify signatures on certificates or CRLs unless
1977
- the corresponding keyCertSign or cRLSign bit is set. */
1978
- //$keyUsage = $this->getExtension('id-ce-keyUsage');
1979
- //if ($keyUsage && !in_array('keyCertSign', $keyUsage)) {
1980
- // return false;
1981
- //}
1982
-
1983
- /* From RFC5280 "PKIX Certificate and CRL Profile":
1984
-
1985
- The cA boolean indicates whether the certified public key may be used
1986
- to verify certificate signatures. If the cA boolean is not asserted,
1987
- then the keyCertSign bit in the key usage extension MUST NOT be
1988
- asserted. If the basic constraints extension is not present in a
1989
- version 3 certificate, or the extension is present but the cA boolean
1990
- is not asserted, then the certified public key MUST NOT be used to
1991
- verify certificate signatures. */
1992
- //$basicConstraints = $this->getExtension('id-ce-basicConstraints');
1993
- //if (!$basicConstraints || !$basicConstraints['cA']) {
1994
- // return false;
1995
- //}
1996
-
1997
- $this->CAs[] = $cert;
1998
-
1999
- $this->dn = $olddn;
2000
- $this->currentCert = $oldcert;
2001
- $this->signatureSubject = $oldsigsubj;
2002
-
2003
- return true;
2004
- }
2005
-
2006
- /**
2007
- * Validate an X.509 certificate against a URL
2008
- *
2009
- * From RFC2818 "HTTP over TLS":
2010
- *
2011
- * Matching is performed using the matching rules specified by
2012
- * [RFC2459]. If more than one identity of a given type is present in
2013
- * the certificate (e.g., more than one dNSName name, a match in any one
2014
- * of the set is considered acceptable.) Names may contain the wildcard
2015
- * character * which is considered to match any single domain name
2016
- * component or component fragment. E.g., *.a.com matches foo.a.com but
2017
- * not bar.foo.a.com. f*.com matches foo.com but not bar.com.
2018
- *
2019
- * @param string $url
2020
- * @access public
2021
- * @return bool
2022
- */
2023
- function validateURL($url)
2024
- {
2025
- if (!is_array($this->currentCert) || !isset($this->currentCert['tbsCertificate'])) {
2026
- return false;
2027
- }
2028
-
2029
- $components = parse_url($url);
2030
- if (!isset($components['host'])) {
2031
- return false;
2032
- }
2033
-
2034
- if ($names = $this->getExtension('id-ce-subjectAltName')) {
2035
- foreach ($names as $name) {
2036
- foreach ($name as $key => $value) {
2037
- $value = str_replace(array('.', '*'), array('\.', '[^.]*'), $value);
2038
- switch ($key) {
2039
- case 'dNSName':
2040
- /* From RFC2818 "HTTP over TLS":
2041
-
2042
- If a subjectAltName extension of type dNSName is present, that MUST
2043
- be used as the identity. Otherwise, the (most specific) Common Name
2044
- field in the Subject field of the certificate MUST be used. Although
2045
- the use of the Common Name is existing practice, it is deprecated and
2046
- Certification Authorities are encouraged to use the dNSName instead. */
2047
- if (preg_match('#^' . $value . '$#', $components['host'])) {
2048
- return true;
2049
- }
2050
- break;
2051
- case 'iPAddress':
2052
- /* From RFC2818 "HTTP over TLS":
2053
-
2054
- In some cases, the URI is specified as an IP address rather than a
2055
- hostname. In this case, the iPAddress subjectAltName must be present
2056
- in the certificate and must exactly match the IP in the URI. */
2057
- if (preg_match('#(?:\d{1-3}\.){4}#', $components['host'] . '.') && preg_match('#^' . $value . '$#', $components['host'])) {
2058
- return true;
2059
- }
2060
- }
2061
- }
2062
- }
2063
- return false;
2064
- }
2065
-
2066
- if ($value = $this->getDNProp('id-at-commonName')) {
2067
- $value = str_replace(array('.', '*'), array('\.', '[^.]*'), $value[0]);
2068
- return preg_match('#^' . $value . '$#', $components['host']);
2069
- }
2070
-
2071
- return false;
2072
- }
2073
-
2074
- /**
2075
- * Validate a date
2076
- *
2077
- * If $date isn't defined it is assumed to be the current date.
2078
- *
2079
- * @param int $date optional
2080
- * @access public
2081
- */
2082
- function validateDate($date = null)
2083
- {
2084
- if (!is_array($this->currentCert) || !isset($this->currentCert['tbsCertificate'])) {
2085
- return false;
2086
- }
2087
-
2088
- if (!isset($date)) {
2089
- $date = new DateTime($date, new DateTimeZone(@date_default_timezone_get()));
2090
- }
2091
-
2092
- $notBefore = $this->currentCert['tbsCertificate']['validity']['notBefore'];
2093
- $notBefore = isset($notBefore['generalTime']) ? $notBefore['generalTime'] : $notBefore['utcTime'];
2094
-
2095
- $notAfter = $this->currentCert['tbsCertificate']['validity']['notAfter'];
2096
- $notAfter = isset($notAfter['generalTime']) ? $notAfter['generalTime'] : $notAfter['utcTime'];
2097
-
2098
- switch (true) {
2099
- case $date < new DateTime($notBefore, new DateTimeZone(@date_default_timezone_get())):
2100
- case $date > new DateTime($notAfter, new DateTimeZone(@date_default_timezone_get())):
2101
- return false;
2102
- }
2103
-
2104
- return true;
2105
- }
2106
-
2107
- /**
2108
- * Validate a signature
2109
- *
2110
- * Works on X.509 certs, CSR's and CRL's.
2111
- * Returns true if the signature is verified, false if it is not correct or null on error
2112
- *
2113
- * By default returns false for self-signed certs. Call validateSignature(false) to make this support
2114
- * self-signed.
2115
- *
2116
- * The behavior of this function is inspired by {@link http://php.net/openssl-verify openssl_verify}.
2117
- *
2118
- * @param bool $caonly optional
2119
- * @access public
2120
- * @return mixed
2121
- */
2122
- function validateSignature($caonly = true)
2123
- {
2124
- if (!is_array($this->currentCert) || !isset($this->signatureSubject)) {
2125
- return null;
2126
- }
2127
-
2128
- /* TODO:
2129
- "emailAddress attribute values are not case-sensitive (e.g., "subscriber@example.com" is the same as "SUBSCRIBER@EXAMPLE.COM")."
2130
- -- http://tools.ietf.org/html/rfc5280#section-4.1.2.6
2131
-
2132
- implement pathLenConstraint in the id-ce-basicConstraints extension */
2133
-
2134
- switch (true) {
2135
- case isset($this->currentCert['tbsCertificate']):
2136
- // self-signed cert
2137
- switch (true) {
2138
- case !defined('FILE_X509_IGNORE_TYPE') && $this->currentCert['tbsCertificate']['issuer'] === $this->currentCert['tbsCertificate']['subject']:
2139
- case defined('FILE_X509_IGNORE_TYPE') && $this->getIssuerDN(self::DN_STRING) === $this->getDN(self::DN_STRING):
2140
- $authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier');
2141
- $subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier');
2142
- switch (true) {
2143
- case !is_array($authorityKey):
2144
- case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
2145
- $signingCert = $this->currentCert; // working cert
2146
- }
2147
- }
2148
-
2149
- if (!empty($this->CAs)) {
2150
- for ($i = 0; $i < count($this->CAs); $i++) {
2151
- // even if the cert is a self-signed one we still want to see if it's a CA;
2152
- // if not, we'll conditionally return an error
2153
- $ca = $this->CAs[$i];
2154
- switch (true) {
2155
- case !defined('FILE_X509_IGNORE_TYPE') && $this->currentCert['tbsCertificate']['issuer'] === $ca['tbsCertificate']['subject']:
2156
- case defined('FILE_X509_IGNORE_TYPE') && $this->getDN(self::DN_STRING, $this->currentCert['tbsCertificate']['issuer']) === $this->getDN(self::DN_STRING, $ca['tbsCertificate']['subject']):
2157
- $authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier');
2158
- $subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca);
2159
- switch (true) {
2160
- case !is_array($authorityKey):
2161
- case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
2162
- $signingCert = $ca; // working cert
2163
- break 3;
2164
- }
2165
- }
2166
- }
2167
- if (count($this->CAs) == $i && $caonly) {
2168
- return false;
2169
- }
2170
- } elseif (!isset($signingCert) || $caonly) {
2171
- return false;
2172
- }
2173
- return $this->_validateSignature(
2174
- $signingCert['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['algorithm'],
2175
- $signingCert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'],
2176
- $this->currentCert['signatureAlgorithm']['algorithm'],
2177
- substr(base64_decode($this->currentCert['signature']), 1),
2178
- $this->signatureSubject
2179
- );
2180
- case isset($this->currentCert['certificationRequestInfo']):
2181
- return $this->_validateSignature(
2182
- $this->currentCert['certificationRequestInfo']['subjectPKInfo']['algorithm']['algorithm'],
2183
- $this->currentCert['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'],
2184
- $this->currentCert['signatureAlgorithm']['algorithm'],
2185
- substr(base64_decode($this->currentCert['signature']), 1),
2186
- $this->signatureSubject
2187
- );
2188
- case isset($this->currentCert['publicKeyAndChallenge']):
2189
- return $this->_validateSignature(
2190
- $this->currentCert['publicKeyAndChallenge']['spki']['algorithm']['algorithm'],
2191
- $this->currentCert['publicKeyAndChallenge']['spki']['subjectPublicKey'],
2192
- $this->currentCert['signatureAlgorithm']['algorithm'],
2193
- substr(base64_decode($this->currentCert['signature']), 1),
2194
- $this->signatureSubject
2195
- );
2196
- case isset($this->currentCert['tbsCertList']):
2197
- if (!empty($this->CAs)) {
2198
- for ($i = 0; $i < count($this->CAs); $i++) {
2199
- $ca = $this->CAs[$i];
2200
- switch (true) {
2201
- case !defined('FILE_X509_IGNORE_TYPE') && $this->currentCert['tbsCertList']['issuer'] === $ca['tbsCertificate']['subject']:
2202
- case defined('FILE_X509_IGNORE_TYPE') && $this->getDN(self::DN_STRING, $this->currentCert['tbsCertList']['issuer']) === $this->getDN(self::DN_STRING, $ca['tbsCertificate']['subject']):
2203
- $authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier');
2204
- $subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca);
2205
- switch (true) {
2206
- case !is_array($authorityKey):
2207
- case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
2208
- $signingCert = $ca; // working cert
2209
- break 3;
2210
- }
2211
- }
2212
- }
2213
- }
2214
- if (!isset($signingCert)) {
2215
- return false;
2216
- }
2217
- return $this->_validateSignature(
2218
- $signingCert['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['algorithm'],
2219
- $signingCert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'],
2220
- $this->currentCert['signatureAlgorithm']['algorithm'],
2221
- substr(base64_decode($this->currentCert['signature']), 1),
2222
- $this->signatureSubject
2223
- );
2224
- default:
2225
- return false;
2226
- }
2227
- }
2228
-
2229
- /**
2230
- * Validates a signature
2231
- *
2232
- * Returns true if the signature is verified, false if it is not correct or null on error
2233
- *
2234
- * @param string $publicKeyAlgorithm
2235
- * @param string $publicKey
2236
- * @param string $signatureAlgorithm
2237
- * @param string $signature
2238
- * @param string $signatureSubject
2239
- * @access private
2240
- * @return int
2241
- */
2242
- function _validateSignature($publicKeyAlgorithm, $publicKey, $signatureAlgorithm, $signature, $signatureSubject)
2243
- {
2244
- switch ($publicKeyAlgorithm) {
2245
- case 'rsaEncryption':
2246
- $rsa = new RSA();
2247
- $rsa->loadKey($publicKey);
2248
-
2249
- switch ($signatureAlgorithm) {
2250
- case 'md2WithRSAEncryption':
2251
- case 'md5WithRSAEncryption':
2252
- case 'sha1WithRSAEncryption':
2253
- case 'sha224WithRSAEncryption':
2254
- case 'sha256WithRSAEncryption':
2255
- case 'sha384WithRSAEncryption':
2256
- case 'sha512WithRSAEncryption':
2257
- $rsa->setHash(preg_replace('#WithRSAEncryption$#', '', $signatureAlgorithm));
2258
- $rsa->setSignatureMode(RSA::SIGNATURE_PKCS1);
2259
- if (!@$rsa->verify($signatureSubject, $signature)) {
2260
- return false;
2261
- }
2262
- break;
2263
- default:
2264
- return null;
2265
- }
2266
- break;
2267
- default:
2268
- return null;
2269
- }
2270
-
2271
- return true;
2272
- }
2273
-
2274
- /**
2275
- * Reformat public keys
2276
- *
2277
- * Reformats a public key to a format supported by phpseclib (if applicable)
2278
- *
2279
- * @param string $algorithm
2280
- * @param string $key
2281
- * @access private
2282
- * @return string
2283
- */
2284
- function _reformatKey($algorithm, $key)
2285
- {
2286
- switch ($algorithm) {
2287
- case 'rsaEncryption':
2288
- return
2289
- "-----BEGIN RSA PUBLIC KEY-----\r\n" .
2290
- // subjectPublicKey is stored as a bit string in X.509 certs. the first byte of a bit string represents how many bits
2291
- // in the last byte should be ignored. the following only supports non-zero stuff but as none of the X.509 certs Firefox
2292
- // uses as a cert authority actually use a non-zero bit I think it's safe to assume that none do.
2293
- chunk_split(base64_encode(substr(base64_decode($key), 1)), 64) .
2294
- '-----END RSA PUBLIC KEY-----';
2295
- default:
2296
- return $key;
2297
- }
2298
- }
2299
-
2300
- /**
2301
- * Decodes an IP address
2302
- *
2303
- * Takes in a base64 encoded "blob" and returns a human readable IP address
2304
- *
2305
- * @param string $ip
2306
- * @access private
2307
- * @return string
2308
- */
2309
- function _decodeIP($ip)
2310
- {
2311
- return inet_ntop(base64_decode($ip));
2312
- }
2313
-
2314
- /**
2315
- * Encodes an IP address
2316
- *
2317
- * Takes a human readable IP address into a base64-encoded "blob"
2318
- *
2319
- * @param string $ip
2320
- * @access private
2321
- * @return string
2322
- */
2323
- function _encodeIP($ip)
2324
- {
2325
- return base64_encode(inet_pton($ip));
2326
- }
2327
-
2328
- /**
2329
- * "Normalizes" a Distinguished Name property
2330
- *
2331
- * @param string $propName
2332
- * @access private
2333
- * @return mixed
2334
- */
2335
- function _translateDNProp($propName)
2336
- {
2337
- switch (strtolower($propName)) {
2338
- case 'id-at-countryname':
2339
- case 'countryname':
2340
- case 'c':
2341
- return 'id-at-countryName';
2342
- case 'id-at-organizationname':
2343
- case 'organizationname':
2344
- case 'o':
2345
- return 'id-at-organizationName';
2346
- case 'id-at-dnqualifier':
2347
- case 'dnqualifier':
2348
- return 'id-at-dnQualifier';
2349
- case 'id-at-commonname':
2350
- case 'commonname':
2351
- case 'cn':
2352
- return 'id-at-commonName';
2353
- case 'id-at-stateorprovincename':
2354
- case 'stateorprovincename':
2355
- case 'state':
2356
- case 'province':
2357
- case 'provincename':
2358
- case 'st':
2359
- return 'id-at-stateOrProvinceName';
2360
- case 'id-at-localityname':
2361
- case 'localityname':
2362
- case 'l':
2363
- return 'id-at-localityName';
2364
- case 'id-emailaddress':
2365
- case 'emailaddress':
2366
- return 'pkcs-9-at-emailAddress';
2367
- case 'id-at-serialnumber':
2368
- case 'serialnumber':
2369
- return 'id-at-serialNumber';
2370
- case 'id-at-postalcode':
2371
- case 'postalcode':
2372
- return 'id-at-postalCode';
2373
- case 'id-at-streetaddress':
2374
- case 'streetaddress':
2375
- return 'id-at-streetAddress';
2376
- case 'id-at-name':
2377
- case 'name':
2378
- return 'id-at-name';
2379
- case 'id-at-givenname':
2380
- case 'givenname':
2381
- return 'id-at-givenName';
2382
- case 'id-at-surname':
2383
- case 'surname':
2384
- case 'sn':
2385
- return 'id-at-surname';
2386
- case 'id-at-initials':
2387
- case 'initials':
2388
- return 'id-at-initials';
2389
- case 'id-at-generationqualifier':
2390
- case 'generationqualifier':
2391
- return 'id-at-generationQualifier';
2392
- case 'id-at-organizationalunitname':
2393
- case 'organizationalunitname':
2394
- case 'ou':
2395
- return 'id-at-organizationalUnitName';
2396
- case 'id-at-pseudonym':
2397
- case 'pseudonym':
2398
- return 'id-at-pseudonym';
2399
- case 'id-at-title':
2400
- case 'title':
2401
- return 'id-at-title';
2402
- case 'id-at-description':
2403
- case 'description':
2404
- return 'id-at-description';
2405
- case 'id-at-role':
2406
- case 'role':
2407
- return 'id-at-role';
2408
- case 'id-at-uniqueidentifier':
2409
- case 'uniqueidentifier':
2410
- case 'x500uniqueidentifier':
2411
- return 'id-at-uniqueIdentifier';
2412
- case 'postaladdress':
2413
- case 'id-at-postaladdress':
2414
- return 'id-at-postalAddress';
2415
- default:
2416
- return false;
2417
- }
2418
- }
2419
-
2420
- /**
2421
- * Set a Distinguished Name property
2422
- *
2423
- * @param string $propName
2424
- * @param mixed $propValue
2425
- * @param string $type optional
2426
- * @access public
2427
- * @return bool
2428
- */
2429
- function setDNProp($propName, $propValue, $type = 'utf8String')
2430
- {
2431
- if (empty($this->dn)) {
2432
- $this->dn = array('rdnSequence' => array());
2433
- }
2434
-
2435
- if (($propName = $this->_translateDNProp($propName)) === false) {
2436
- return false;
2437
- }
2438
-
2439
- foreach ((array) $propValue as $v) {
2440
- if (!is_array($v) && isset($type)) {
2441
- $v = array($type => $v);
2442
- }
2443
- $this->dn['rdnSequence'][] = array(
2444
- array(
2445
- 'type' => $propName,
2446
- 'value'=> $v
2447
- )
2448
- );
2449
- }
2450
-
2451
- return true;
2452
- }
2453
-
2454
- /**
2455
- * Remove Distinguished Name properties
2456
- *
2457
- * @param string $propName
2458
- * @access public
2459
- */
2460
- function removeDNProp($propName)
2461
- {
2462
- if (empty($this->dn)) {
2463
- return;
2464
- }
2465
-
2466
- if (($propName = $this->_translateDNProp($propName)) === false) {
2467
- return;
2468
- }
2469
-
2470
- $dn = &$this->dn['rdnSequence'];
2471
- $size = count($dn);
2472
- for ($i = 0; $i < $size; $i++) {
2473
- if ($dn[$i][0]['type'] == $propName) {
2474
- unset($dn[$i]);
2475
- }
2476
- }
2477
-
2478
- $dn = array_values($dn);
2479
- }
2480
-
2481
- /**
2482
- * Get Distinguished Name properties
2483
- *
2484
- * @param string $propName
2485
- * @param array $dn optional
2486
- * @param bool $withType optional
2487
- * @return mixed
2488
- * @access public
2489
- */
2490
- function getDNProp($propName, $dn = null, $withType = false)
2491
- {
2492
- if (!isset($dn)) {
2493
- $dn = $this->dn;
2494
- }
2495
-
2496
- if (empty($dn)) {
2497
- return false;
2498
- }
2499
-
2500
- if (($propName = $this->_translateDNProp($propName)) === false) {
2501
- return false;
2502
- }
2503
-
2504
- $asn1 = new ASN1();
2505
- $asn1->loadOIDs($this->oids);
2506
- $filters = array();
2507
- $filters['value'] = array('type' => ASN1::TYPE_UTF8_STRING);
2508
- $asn1->loadFilters($filters);
2509
- $this->_mapOutDNs($dn, 'rdnSequence', $asn1);
2510
- $dn = $dn['rdnSequence'];
2511
- $result = array();
2512
- for ($i = 0; $i < count($dn); $i++) {
2513
- if ($dn[$i][0]['type'] == $propName) {
2514
- $v = $dn[$i][0]['value'];
2515
- if (!$withType) {
2516
- if (is_array($v)) {
2517
- foreach ($v as $type => $s) {
2518
- $type = array_search($type, $asn1->ANYmap, true);
2519
- if ($type !== false && isset($asn1->stringTypeSize[$type])) {
2520
- $s = $asn1->convert($s, $type);
2521
- if ($s !== false) {
2522
- $v = $s;
2523
- break;
2524
- }
2525
- }
2526
- }
2527
- if (is_array($v)) {
2528
- $v = array_pop($v); // Always strip data type.
2529
- }
2530
- } elseif (is_object($v) && $v instanceof Element) {
2531
- $map = $this->_getMapping($propName);
2532
- if (!is_bool($map)) {
2533
- $decoded = $asn1->decodeBER($v);
2534
- $v = $asn1->asn1map($decoded[0], $map);
2535
- }
2536
- }
2537
- }
2538
- $result[] = $v;
2539
- }
2540
- }
2541
-
2542
- return $result;
2543
- }
2544
-
2545
- /**
2546
- * Set a Distinguished Name
2547
- *
2548
- * @param mixed $dn
2549
- * @param bool $merge optional
2550
- * @param string $type optional
2551
- * @access public
2552
- * @return bool
2553
- */
2554
- function setDN($dn, $merge = false, $type = 'utf8String')
2555
- {
2556
- if (!$merge) {
2557
- $this->dn = null;
2558
- }
2559
-
2560
- if (is_array($dn)) {
2561
- if (isset($dn['rdnSequence'])) {
2562
- $this->dn = $dn; // No merge here.
2563
- return true;
2564
- }
2565
-
2566
- // handles stuff generated by openssl_x509_parse()
2567
- foreach ($dn as $prop => $value) {
2568
- if (!$this->setDNProp($prop, $value, $type)) {
2569
- return false;
2570
- }
2571
- }
2572
- return true;
2573
- }
2574
-
2575
- // handles everything else
2576
- $results = preg_split('#((?:^|, *|/)(?:C=|O=|OU=|CN=|L=|ST=|SN=|postalCode=|streetAddress=|emailAddress=|serialNumber=|organizationalUnitName=|title=|description=|role=|x500UniqueIdentifier=|postalAddress=))#', $dn, -1, PREG_SPLIT_DELIM_CAPTURE);
2577
- for ($i = 1; $i < count($results); $i+=2) {
2578
- $prop = trim($results[$i], ', =/');
2579
- $value = $results[$i + 1];
2580
- if (!$this->setDNProp($prop, $value, $type)) {
2581
- return false;
2582
- }
2583
- }
2584
-
2585
- return true;
2586
- }
2587
-
2588
- /**
2589
- * Get the Distinguished Name for a certificates subject
2590
- *
2591
- * @param mixed $format optional
2592
- * @param array $dn optional
2593
- * @access public
2594
- * @return bool
2595
- */
2596
- function getDN($format = self::DN_ARRAY, $dn = null)
2597
- {
2598
- if (!isset($dn)) {
2599
- $dn = isset($this->currentCert['tbsCertList']) ? $this->currentCert['tbsCertList']['issuer'] : $this->dn;
2600
- }
2601
-
2602
- switch ((int) $format) {
2603
- case self::DN_ARRAY:
2604
- return $dn;
2605
- case self::DN_ASN1:
2606
- $asn1 = new ASN1();
2607
- $asn1->loadOIDs($this->oids);
2608
- $filters = array();
2609
- $filters['rdnSequence']['value'] = array('type' => ASN1::TYPE_UTF8_STRING);
2610
- $asn1->loadFilters($filters);
2611
- $this->_mapOutDNs($dn, 'rdnSequence', $asn1);
2612
- return $asn1->encodeDER($dn, $this->Name);
2613
- case self::DN_CANON:
2614
- // No SEQUENCE around RDNs and all string values normalized as
2615
- // trimmed lowercase UTF-8 with all spacing as one blank.
2616
- // constructed RDNs will not be canonicalized
2617
- $asn1 = new ASN1();
2618
- $asn1->loadOIDs($this->oids);
2619
- $filters = array();
2620
- $filters['value'] = array('type' => ASN1::TYPE_UTF8_STRING);
2621
- $asn1->loadFilters($filters);
2622
- $result = '';
2623
- $this->_mapOutDNs($dn, 'rdnSequence', $asn1);
2624
- foreach ($dn['rdnSequence'] as $rdn) {
2625
- foreach ($rdn as $i => $attr) {
2626
- $attr = &$rdn[$i];
2627
- if (is_array($attr['value'])) {
2628
- foreach ($attr['value'] as $type => $v) {
2629
- $type = array_search($type, $asn1->ANYmap, true);
2630
- if ($type !== false && isset($asn1->stringTypeSize[$type])) {
2631
- $v = $asn1->convert($v, $type);
2632
- if ($v !== false) {
2633
- $v = preg_replace('/\s+/', ' ', $v);
2634
- $attr['value'] = strtolower(trim($v));
2635
- break;
2636
- }
2637
- }
2638
- }
2639
- }
2640
- }
2641
- $result .= $asn1->encodeDER($rdn, $this->RelativeDistinguishedName);
2642
- }
2643
- return $result;
2644
- case self::DN_HASH:
2645
- $dn = $this->getDN(self::DN_CANON, $dn);
2646
- $hash = new Hash('sha1');
2647
- $hash = $hash->hash($dn);
2648
- extract(unpack('Vhash', $hash));
2649
- return strtolower(bin2hex(pack('N', $hash)));
2650
- }
2651
-
2652
- // Default is to return a string.
2653
- $start = true;
2654
- $output = '';
2655
-
2656
- $result = array();
2657
- $asn1 = new ASN1();
2658
- $asn1->loadOIDs($this->oids);
2659
- $filters = array();
2660
- $filters['rdnSequence']['value'] = array('type' => ASN1::TYPE_UTF8_STRING);
2661
- $asn1->loadFilters($filters);
2662
- $this->_mapOutDNs($dn, 'rdnSequence', $asn1);
2663
-
2664
- foreach ($dn['rdnSequence'] as $field) {
2665
- $prop = $field[0]['type'];
2666
- $value = $field[0]['value'];
2667
-
2668
- $delim = ', ';
2669
- switch ($prop) {
2670
- case 'id-at-countryName':
2671
- $desc = 'C';
2672
- break;
2673
- case 'id-at-stateOrProvinceName':
2674
- $desc = 'ST';
2675
- break;
2676
- case 'id-at-organizationName':
2677
- $desc = 'O';
2678
- break;
2679
- case 'id-at-organizationalUnitName':
2680
- $desc = 'OU';
2681
- break;
2682
- case 'id-at-commonName':
2683
- $desc = 'CN';
2684
- break;
2685
- case 'id-at-localityName':
2686
- $desc = 'L';
2687
- break;
2688
- case 'id-at-surname':
2689
- $desc = 'SN';
2690
- break;
2691
- case 'id-at-uniqueIdentifier':
2692
- $delim = '/';
2693
- $desc = 'x500UniqueIdentifier';
2694
- break;
2695
- case 'id-at-postalAddress':
2696
- $delim = '/';
2697
- $desc = 'postalAddress';
2698
- break;
2699
- default:
2700
- $delim = '/';
2701
- $desc = preg_replace('#.+-([^-]+)$#', '$1', $prop);
2702
- }
2703
-
2704
- if (!$start) {
2705
- $output.= $delim;
2706
- }
2707
- if (is_array($value)) {
2708
- foreach ($value as $type => $v) {
2709
- $type = array_search($type, $asn1->ANYmap, true);
2710
- if ($type !== false && isset($asn1->stringTypeSize[$type])) {
2711
- $v = $asn1->convert($v, $type);
2712
- if ($v !== false) {
2713
- $value = $v;
2714
- break;
2715
- }
2716
- }
2717
- }
2718
- if (is_array($value)) {
2719
- $value = array_pop($value); // Always strip data type.
2720
- }
2721
- } elseif (is_object($value) && $value instanceof Element) {
2722
- $callback = create_function('$x', 'return "\x" . bin2hex($x[0]);');
2723
- $value = strtoupper(preg_replace_callback('#[^\x20-\x7E]#', $callback, $value->element));
2724
- }
2725
- $output.= $desc . '=' . $value;
2726
- $result[$desc] = isset($result[$desc]) ?
2727
- array_merge((array) $dn[$prop], array($value)) :
2728
- $value;
2729
- $start = false;
2730
- }
2731
-
2732
- return $format == self::DN_OPENSSL ? $result : $output;
2733
- }
2734
-
2735
- /**
2736
- * Get the Distinguished Name for a certificate/crl issuer
2737
- *
2738
- * @param int $format optional
2739
- * @access public
2740
- * @return mixed
2741
- */
2742
- function getIssuerDN($format = self::DN_ARRAY)
2743
- {
2744
- switch (true) {
2745
- case !isset($this->currentCert) || !is_array($this->currentCert):
2746
- break;
2747
- case isset($this->currentCert['tbsCertificate']):
2748
- return $this->getDN($format, $this->currentCert['tbsCertificate']['issuer']);
2749
- case isset($this->currentCert['tbsCertList']):
2750
- return $this->getDN($format, $this->currentCert['tbsCertList']['issuer']);
2751
- }
2752
-
2753
- return false;
2754
- }
2755
-
2756
- /**
2757
- * Get the Distinguished Name for a certificate/csr subject
2758
- * Alias of getDN()
2759
- *
2760
- * @param int $format optional
2761
- * @access public
2762
- * @return mixed
2763
- */
2764
- function getSubjectDN($format = self::DN_ARRAY)
2765
- {
2766
- switch (true) {
2767
- case !empty($this->dn):
2768
- return $this->getDN($format);
2769
- case !isset($this->currentCert) || !is_array($this->currentCert):
2770
- break;
2771
- case isset($this->currentCert['tbsCertificate']):
2772
- return $this->getDN($format, $this->currentCert['tbsCertificate']['subject']);
2773
- case isset($this->currentCert['certificationRequestInfo']):
2774
- return $this->getDN($format, $this->currentCert['certificationRequestInfo']['subject']);
2775
- }
2776
-
2777
- return false;
2778
- }
2779
-
2780
- /**
2781
- * Get an individual Distinguished Name property for a certificate/crl issuer
2782
- *
2783
- * @param string $propName
2784
- * @param bool $withType optional
2785
- * @access public
2786
- * @return mixed
2787
- */
2788
- function getIssuerDNProp($propName, $withType = false)
2789
- {
2790
- switch (true) {
2791
- case !isset($this->currentCert) || !is_array($this->currentCert):
2792
- break;
2793
- case isset($this->currentCert['tbsCertificate']):
2794
- return $this->getDNProp($propName, $this->currentCert['tbsCertificate']['issuer'], $withType);
2795
- case isset($this->currentCert['tbsCertList']):
2796
- return $this->getDNProp($propName, $this->currentCert['tbsCertList']['issuer'], $withType);
2797
- }
2798
-
2799
- return false;
2800
- }
2801
-
2802
- /**
2803
- * Get an individual Distinguished Name property for a certificate/csr subject
2804
- *
2805
- * @param string $propName
2806
- * @param bool $withType optional
2807
- * @access public
2808
- * @return mixed
2809
- */
2810
- function getSubjectDNProp($propName, $withType = false)
2811
- {
2812
- switch (true) {
2813
- case !empty($this->dn):
2814
- return $this->getDNProp($propName, null, $withType);
2815
- case !isset($this->currentCert) || !is_array($this->currentCert):
2816
- break;
2817
- case isset($this->currentCert['tbsCertificate']):
2818
- return $this->getDNProp($propName, $this->currentCert['tbsCertificate']['subject'], $withType);
2819
- case isset($this->currentCert['certificationRequestInfo']):
2820
- return $this->getDNProp($propName, $this->currentCert['certificationRequestInfo']['subject'], $withType);
2821
- }
2822
-
2823
- return false;
2824
- }
2825
-
2826
- /**
2827
- * Get the certificate chain for the current cert
2828
- *
2829
- * @access public
2830
- * @return mixed
2831
- */
2832
- function getChain()
2833
- {
2834
- $chain = array($this->currentCert);
2835
-
2836
- if (!is_array($this->currentCert) || !isset($this->currentCert['tbsCertificate'])) {
2837
- return false;
2838
- }
2839
- if (empty($this->CAs)) {
2840
- return $chain;
2841
- }
2842
- while (true) {
2843
- $currentCert = $chain[count($chain) - 1];
2844
- for ($i = 0; $i < count($this->CAs); $i++) {
2845
- $ca = $this->CAs[$i];
2846
- if ($currentCert['tbsCertificate']['issuer'] === $ca['tbsCertificate']['subject']) {
2847
- $authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier', $currentCert);
2848
- $subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca);
2849
- switch (true) {
2850
- case !is_array($authorityKey):
2851
- case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
2852
- if ($currentCert === $ca) {
2853
- break 3;
2854
- }
2855
- $chain[] = $ca;
2856
- break 2;
2857
- }
2858
- }
2859
- }
2860
- if ($i == count($this->CAs)) {
2861
- break;
2862
- }
2863
- }
2864
- foreach ($chain as $key => $value) {
2865
- $chain[$key] = new X509();
2866
- $chain[$key]->loadX509($value);
2867
- }
2868
- return $chain;
2869
- }
2870
-
2871
- /**
2872
- * Set public key
2873
- *
2874
- * Key needs to be a \phpseclib\Crypt\RSA object
2875
- *
2876
- * @param object $key
2877
- * @access public
2878
- * @return bool
2879
- */
2880
- function setPublicKey($key)
2881
- {
2882
- $key->setPublicKey();
2883
- $this->publicKey = $key;
2884
- }
2885
-
2886
- /**
2887
- * Set private key
2888
- *
2889
- * Key needs to be a \phpseclib\Crypt\RSA object
2890
- *
2891
- * @param object $key
2892
- * @access public
2893
- */
2894
- function setPrivateKey($key)
2895
- {
2896
- $this->privateKey = $key;
2897
- }
2898
-
2899
- /**
2900
- * Set challenge
2901
- *
2902
- * Used for SPKAC CSR's
2903
- *
2904
- * @param string $challenge
2905
- * @access public
2906
- */
2907
- function setChallenge($challenge)
2908
- {
2909
- $this->challenge = $challenge;
2910
- }
2911
-
2912
- /**
2913
- * Gets the public key
2914
- *
2915
- * Returns a \phpseclib\Crypt\RSA object or a false.
2916
- *
2917
- * @access public
2918
- * @return mixed
2919
- */
2920
- function getPublicKey()
2921
- {
2922
- if (isset($this->publicKey)) {
2923
- return $this->publicKey;
2924
- }
2925
-
2926
- if (isset($this->currentCert) && is_array($this->currentCert)) {
2927
- foreach (array('tbsCertificate/subjectPublicKeyInfo', 'certificationRequestInfo/subjectPKInfo') as $path) {
2928
- $keyinfo = $this->_subArray($this->currentCert, $path);
2929
- if (!empty($keyinfo)) {
2930
- break;
2931
- }
2932
- }
2933
- }
2934
- if (empty($keyinfo)) {
2935
- return false;
2936
- }
2937
-
2938
- $key = $keyinfo['subjectPublicKey'];
2939
-
2940
- switch ($keyinfo['algorithm']['algorithm']) {
2941
- case 'rsaEncryption':
2942
- $publicKey = new RSA();
2943
- $publicKey->loadKey($key);
2944
- $publicKey->setPublicKey();
2945
- break;
2946
- default:
2947
- return false;
2948
- }
2949
-
2950
- return $publicKey;
2951
- }
2952
-
2953
- /**
2954
- * Load a Certificate Signing Request
2955
- *
2956
- * @param string $csr
2957
- * @access public
2958
- * @return mixed
2959
- */
2960
- function loadCSR($csr, $mode = self::FORMAT_AUTO_DETECT)
2961
- {
2962
- if (is_array($csr) && isset($csr['certificationRequestInfo'])) {
2963
- unset($this->currentCert);
2964
- unset($this->currentKeyIdentifier);
2965
- unset($this->signatureSubject);
2966
- $this->dn = $csr['certificationRequestInfo']['subject'];
2967
- if (!isset($this->dn)) {
2968
- return false;
2969
- }
2970
-
2971
- $this->currentCert = $csr;
2972
- return $csr;
2973
- }
2974
-
2975
- // see http://tools.ietf.org/html/rfc2986
2976
-
2977
- $asn1 = new ASN1();
2978
-
2979
- if ($mode != self::FORMAT_DER) {
2980
- $newcsr = $this->_extractBER($csr);
2981
- if ($mode == self::FORMAT_PEM && $csr == $newcsr) {
2982
- return false;
2983
- }
2984
- $csr = $newcsr;
2985
- }
2986
- $orig = $csr;
2987
-
2988
- if ($csr === false) {
2989
- $this->currentCert = false;
2990
- return false;
2991
- }
2992
-
2993
- $asn1->loadOIDs($this->oids);
2994
- $decoded = $asn1->decodeBER($csr);
2995
-
2996
- if (empty($decoded)) {
2997
- $this->currentCert = false;
2998
- return false;
2999
- }
3000
-
3001
- $csr = $asn1->asn1map($decoded[0], $this->CertificationRequest);
3002
- if (!isset($csr) || $csr === false) {
3003
- $this->currentCert = false;
3004
- return false;
3005
- }
3006
-
3007
- $this->_mapInAttributes($csr, 'certificationRequestInfo/attributes', $asn1);
3008
- $this->_mapInDNs($csr, 'certificationRequestInfo/subject/rdnSequence', $asn1);
3009
-
3010
- $this->dn = $csr['certificationRequestInfo']['subject'];
3011
-
3012
- $this->signatureSubject = substr($orig, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']);
3013
-
3014
- $algorithm = &$csr['certificationRequestInfo']['subjectPKInfo']['algorithm']['algorithm'];
3015
- $key = &$csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'];
3016
- $key = $this->_reformatKey($algorithm, $key);
3017
-
3018
- switch ($algorithm) {
3019
- case 'rsaEncryption':
3020
- $this->publicKey = new RSA();
3021
- $this->publicKey->loadKey($key);
3022
- $this->publicKey->setPublicKey();
3023
- break;
3024
- default:
3025
- $this->publicKey = null;
3026
- }
3027
-
3028
- $this->currentKeyIdentifier = null;
3029
- $this->currentCert = $csr;
3030
-
3031
- return $csr;
3032
- }
3033
-
3034
- /**
3035
- * Save CSR request
3036
- *
3037
- * @param array $csr
3038
- * @param int $format optional
3039
- * @access public
3040
- * @return string
3041
- */
3042
- function saveCSR($csr, $format = self::FORMAT_PEM)
3043
- {
3044
- if (!is_array($csr) || !isset($csr['certificationRequestInfo'])) {
3045
- return false;
3046
- }
3047
-
3048
- switch (true) {
3049
- case !($algorithm = $this->_subArray($csr, 'certificationRequestInfo/subjectPKInfo/algorithm/algorithm')):
3050
- case is_object($csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey']):
3051
- break;
3052
- default:
3053
- switch ($algorithm) {
3054
- case 'rsaEncryption':
3055
- $csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey']
3056
- = base64_encode("\0" . base64_decode(preg_replace('#-.+-|[\r\n]#', '', $csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'])));
3057
- $csr['certificationRequestInfo']['subjectPKInfo']['algorithm']['parameters'] = null;
3058
- $csr['signatureAlgorithm']['parameters'] = null;
3059
- $csr['certificationRequestInfo']['signature']['parameters'] = null;
3060
- }
3061
- }
3062
-
3063
- $asn1 = new ASN1();
3064
-
3065
- $asn1->loadOIDs($this->oids);
3066
-
3067
- $filters = array();
3068
- $filters['certificationRequestInfo']['subject']['rdnSequence']['value']
3069
- = array('type' => ASN1::TYPE_UTF8_STRING);
3070
-
3071
- $asn1->loadFilters($filters);
3072
-
3073
- $this->_mapOutDNs($csr, 'certificationRequestInfo/subject/rdnSequence', $asn1);
3074
- $this->_mapOutAttributes($csr, 'certificationRequestInfo/attributes', $asn1);
3075
- $csr = $asn1->encodeDER($csr, $this->CertificationRequest);
3076
-
3077
- switch ($format) {
3078
- case self::FORMAT_DER:
3079
- return $csr;
3080
- // case self::FORMAT_PEM:
3081
- default:
3082
- return "-----BEGIN CERTIFICATE REQUEST-----\r\n" . chunk_split(base64_encode($csr), 64) . '-----END CERTIFICATE REQUEST-----';
3083
- }
3084
- }
3085
-
3086
- /**
3087
- * Load a SPKAC CSR
3088
- *
3089
- * SPKAC's are produced by the HTML5 keygen element:
3090
- *
3091
- * https://developer.mozilla.org/en-US/docs/HTML/Element/keygen
3092
- *
3093
- * @param string $csr
3094
- * @access public
3095
- * @return mixed
3096
- */
3097
- function loadSPKAC($spkac)
3098
- {
3099
- if (is_array($spkac) && isset($spkac['publicKeyAndChallenge'])) {
3100
- unset($this->currentCert);
3101
- unset($this->currentKeyIdentifier);
3102
- unset($this->signatureSubject);
3103
- $this->currentCert = $spkac;
3104
- return $spkac;
3105
- }
3106
-
3107
- // see http://www.w3.org/html/wg/drafts/html/master/forms.html#signedpublickeyandchallenge
3108
-
3109
- $asn1 = new ASN1();
3110
-
3111
- // OpenSSL produces SPKAC's that are preceded by the string SPKAC=
3112
- $temp = preg_replace('#(?:SPKAC=)|[ \r\n\\\]#', '', $spkac);
3113
- $temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false;
3114
- if ($temp != false) {
3115
- $spkac = $temp;
3116
- }
3117
- $orig = $spkac;
3118
-
3119
- if ($spkac === false) {
3120
- $this->currentCert = false;
3121
- return false;
3122
- }
3123
-
3124
- $asn1->loadOIDs($this->oids);
3125
- $decoded = $asn1->decodeBER($spkac);
3126
-
3127
- if (empty($decoded)) {
3128
- $this->currentCert = false;
3129
- return false;
3130
- }
3131
-
3132
- $spkac = $asn1->asn1map($decoded[0], $this->SignedPublicKeyAndChallenge);
3133
-
3134
- if (!isset($spkac) || $spkac === false) {
3135
- $this->currentCert = false;
3136
- return false;
3137
- }
3138
-
3139
- $this->signatureSubject = substr($orig, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']);
3140
-
3141
- $algorithm = &$spkac['publicKeyAndChallenge']['spki']['algorithm']['algorithm'];
3142
- $key = &$spkac['publicKeyAndChallenge']['spki']['subjectPublicKey'];
3143
- $key = $this->_reformatKey($algorithm, $key);
3144
-
3145
- switch ($algorithm) {
3146
- case 'rsaEncryption':
3147
- $this->publicKey = new RSA();
3148
- $this->publicKey->loadKey($key);
3149
- $this->publicKey->setPublicKey();
3150
- break;
3151
- default:
3152
- $this->publicKey = null;
3153
- }
3154
-
3155
- $this->currentKeyIdentifier = null;
3156
- $this->currentCert = $spkac;
3157
-
3158
- return $spkac;
3159
- }
3160
-
3161
- /**
3162
- * Save a SPKAC CSR request
3163
- *
3164
- * @param array $csr
3165
- * @param int $format optional
3166
- * @access public
3167
- * @return string
3168
- */
3169
- function saveSPKAC($spkac, $format = self::FORMAT_PEM)
3170
- {
3171
- if (!is_array($spkac) || !isset($spkac['publicKeyAndChallenge'])) {
3172
- return false;
3173
- }
3174
-
3175
- $algorithm = $this->_subArray($spkac, 'publicKeyAndChallenge/spki/algorithm/algorithm');
3176
- switch (true) {
3177
- case !$algorithm:
3178
- case is_object($spkac['publicKeyAndChallenge']['spki']['subjectPublicKey']):
3179
- break;
3180
- default:
3181
- switch ($algorithm) {
3182
- case 'rsaEncryption':
3183
- $spkac['publicKeyAndChallenge']['spki']['subjectPublicKey']
3184
- = base64_encode("\0" . base64_decode(preg_replace('#-.+-|[\r\n]#', '', $spkac['publicKeyAndChallenge']['spki']['subjectPublicKey'])));
3185
- }
3186
- }
3187
-
3188
- $asn1 = new ASN1();
3189
-
3190
- $asn1->loadOIDs($this->oids);
3191
- $spkac = $asn1->encodeDER($spkac, $this->SignedPublicKeyAndChallenge);
3192
-
3193
- switch ($format) {
3194
- case self::FORMAT_DER:
3195
- return $spkac;
3196
- // case self::FORMAT_PEM:
3197
- default:
3198
- // OpenSSL's implementation of SPKAC requires the SPKAC be preceded by SPKAC= and since there are pretty much
3199
- // no other SPKAC decoders phpseclib will use that same format
3200
- return 'SPKAC=' . base64_encode($spkac);
3201
- }
3202
- }
3203
-
3204
- /**
3205
- * Load a Certificate Revocation List
3206
- *
3207
- * @param string $crl
3208
- * @access public
3209
- * @return mixed
3210
- */
3211
- function loadCRL($crl, $mode = self::FORMAT_AUTO_DETECT)
3212
- {
3213
- if (is_array($crl) && isset($crl['tbsCertList'])) {
3214
- $this->currentCert = $crl;
3215
- unset($this->signatureSubject);
3216
- return $crl;
3217
- }
3218
-
3219
- $asn1 = new ASN1();
3220
-
3221
- if ($mode != self::FORMAT_DER) {
3222
- $newcrl = $this->_extractBER($crl);
3223
- if ($mode == self::FORMAT_PEM && $crl == $newcrl) {
3224
- return false;
3225
- }
3226
- $crl = $newcrl;
3227
- }
3228
- $orig = $crl;
3229
-
3230
- if ($crl === false) {
3231
- $this->currentCert = false;
3232
- return false;
3233
- }
3234
-
3235
- $asn1->loadOIDs($this->oids);
3236
- $decoded = $asn1->decodeBER($crl);
3237
-
3238
- if (empty($decoded)) {
3239
- $this->currentCert = false;
3240
- return false;
3241
- }
3242
-
3243
- $crl = $asn1->asn1map($decoded[0], $this->CertificateList);
3244
- if (!isset($crl) || $crl === false) {
3245
- $this->currentCert = false;
3246
- return false;
3247
- }
3248
-
3249
- $this->signatureSubject = substr($orig, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']);
3250
-
3251
- $this->_mapInDNs($crl, 'tbsCertList/issuer/rdnSequence', $asn1);
3252
- if ($this->_isSubArrayValid($crl, 'tbsCertList/crlExtensions')) {
3253
- $this->_mapInExtensions($crl, 'tbsCertList/crlExtensions', $asn1);
3254
- }
3255
- if ($this->_isSubArrayValid($crl, 'tbsCertList/revokedCertificates')) {
3256
- $rclist_ref = &$this->_subArrayUnchecked($crl, 'tbsCertList/revokedCertificates');
3257
- if ($rclist_ref) {
3258
- $rclist = $crl['tbsCertList']['revokedCertificates'];
3259
- foreach ($rclist as $i => $extension) {
3260
- if ($this->_isSubArrayValid($rclist, "$i/crlEntryExtensions", $asn1)) {
3261
- $this->_mapInExtensions($rclist_ref, "$i/crlEntryExtensions", $asn1);
3262
- }
3263
- }
3264
- }
3265
- }
3266
-
3267
- $this->currentKeyIdentifier = null;
3268
- $this->currentCert = $crl;
3269
-
3270
- return $crl;
3271
- }
3272
-
3273
- /**
3274
- * Save Certificate Revocation List.
3275
- *
3276
- * @param array $crl
3277
- * @param int $format optional
3278
- * @access public
3279
- * @return string
3280
- */
3281
- function saveCRL($crl, $format = self::FORMAT_PEM)
3282
- {
3283
- if (!is_array($crl) || !isset($crl['tbsCertList'])) {
3284
- return false;
3285
- }
3286
-
3287
- $asn1 = new ASN1();
3288
-
3289
- $asn1->loadOIDs($this->oids);
3290
-
3291
- $filters = array();
3292
- $filters['tbsCertList']['issuer']['rdnSequence']['value']
3293
- = array('type' => ASN1::TYPE_UTF8_STRING);
3294
- $filters['tbsCertList']['signature']['parameters']
3295
- = array('type' => ASN1::TYPE_UTF8_STRING);
3296
- $filters['signatureAlgorithm']['parameters']
3297
- = array('type' => ASN1::TYPE_UTF8_STRING);
3298
-
3299
- if (empty($crl['tbsCertList']['signature']['parameters'])) {
3300
- $filters['tbsCertList']['signature']['parameters']
3301
- = array('type' => ASN1::TYPE_NULL);
3302
- }
3303
-
3304
- if (empty($crl['signatureAlgorithm']['parameters'])) {
3305
- $filters['signatureAlgorithm']['parameters']
3306
- = array('type' => ASN1::TYPE_NULL);
3307
- }
3308
-
3309
- $asn1->loadFilters($filters);
3310
-
3311
- $this->_mapOutDNs($crl, 'tbsCertList/issuer/rdnSequence', $asn1);
3312
- $this->_mapOutExtensions($crl, 'tbsCertList/crlExtensions', $asn1);
3313
- $rclist = &$this->_subArray($crl, 'tbsCertList/revokedCertificates');
3314
- if (is_array($rclist)) {
3315
- foreach ($rclist as $i => $extension) {
3316
- $this->_mapOutExtensions($rclist, "$i/crlEntryExtensions", $asn1);
3317
- }
3318
- }
3319
-
3320
- $crl = $asn1->encodeDER($crl, $this->CertificateList);
3321
-
3322
- switch ($format) {
3323
- case self::FORMAT_DER:
3324
- return $crl;
3325
- // case self::FORMAT_PEM:
3326
- default:
3327
- return "-----BEGIN X509 CRL-----\r\n" . chunk_split(base64_encode($crl), 64) . '-----END X509 CRL-----';
3328
- }
3329
- }
3330
-
3331
- /**
3332
- * Helper function to build a time field according to RFC 3280 section
3333
- * - 4.1.2.5 Validity
3334
- * - 5.1.2.4 This Update
3335
- * - 5.1.2.5 Next Update
3336
- * - 5.1.2.6 Revoked Certificates
3337
- * by choosing utcTime iff year of date given is before 2050 and generalTime else.
3338
- *
3339
- * @param string $date in format date('D, d M Y H:i:s O')
3340
- * @access private
3341
- * @return array
3342
- */
3343
- function _timeField($date)
3344
- {
3345
- if ($date instanceof Element) {
3346
- return $date;
3347
- }
3348
- $dateObj = new DateTime($date, new DateTimeZone('GMT'));
3349
- $year = $dateObj->format('Y'); // the same way ASN1.php parses this
3350
- if ($year < 2050) {
3351
- return array('utcTime' => $date);
3352
- } else {
3353
- return array('generalTime' => $date);
3354
- }
3355
- }
3356
-
3357
- /**
3358
- * Sign an X.509 certificate
3359
- *
3360
- * $issuer's private key needs to be loaded.
3361
- * $subject can be either an existing X.509 cert (if you want to resign it),
3362
- * a CSR or something with the DN and public key explicitly set.
3363
- *
3364
- * @param \phpseclib\File\X509 $issuer
3365
- * @param \phpseclib\File\X509 $subject
3366
- * @param string $signatureAlgorithm optional
3367
- * @access public
3368
- * @return mixed
3369
- */
3370
- function sign($issuer, $subject, $signatureAlgorithm = 'sha1WithRSAEncryption')
3371
- {
3372
- if (!is_object($issuer->privateKey) || empty($issuer->dn)) {
3373
- return false;
3374
- }
3375
-
3376
- if (isset($subject->publicKey) && !($subjectPublicKey = $subject->_formatSubjectPublicKey())) {
3377
- return false;
3378
- }
3379
-
3380
- $currentCert = isset($this->currentCert) ? $this->currentCert : null;
3381
- $signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject: null;
3382
-
3383
- if (isset($subject->currentCert) && is_array($subject->currentCert) && isset($subject->currentCert['tbsCertificate'])) {
3384
- $this->currentCert = $subject->currentCert;
3385
- $this->currentCert['tbsCertificate']['signature']['algorithm'] = $signatureAlgorithm;
3386
- $this->currentCert['signatureAlgorithm']['algorithm'] = $signatureAlgorithm;
3387
-
3388
- if (!empty($this->startDate)) {
3389
- $this->currentCert['tbsCertificate']['validity']['notBefore'] = $this->_timeField($this->startDate);
3390
- }
3391
- if (!empty($this->endDate)) {
3392
- $this->currentCert['tbsCertificate']['validity']['notAfter'] = $this->_timeField($this->endDate);
3393
- }
3394
- if (!empty($this->serialNumber)) {
3395
- $this->currentCert['tbsCertificate']['serialNumber'] = $this->serialNumber;
3396
- }
3397
- if (!empty($subject->dn)) {
3398
- $this->currentCert['tbsCertificate']['subject'] = $subject->dn;
3399
- }
3400
- if (!empty($subject->publicKey)) {
3401
- $this->currentCert['tbsCertificate']['subjectPublicKeyInfo'] = $subjectPublicKey;
3402
- }
3403
- $this->removeExtension('id-ce-authorityKeyIdentifier');
3404
- if (isset($subject->domains)) {
3405
- $this->removeExtension('id-ce-subjectAltName');
3406
- }
3407
- } elseif (isset($subject->currentCert) && is_array($subject->currentCert) && isset($subject->currentCert['tbsCertList'])) {
3408
- return false;
3409
- } else {
3410
- if (!isset($subject->publicKey)) {
3411
- return false;
3412
- }
3413
-
3414
- $startDate = new DateTime('now', new DateTimeZone(@date_default_timezone_get()));
3415
- $startDate = !empty($this->startDate) ? $this->startDate : $startDate->format('D, d M Y H:i:s O');
3416
-
3417
- $endDate = new DateTime('+1 year', new DateTimeZone(@date_default_timezone_get()));
3418
- $endDate = !empty($this->endDate) ? $this->endDate : $endDate->format('D, d M Y H:i:s O');
3419
-
3420
- /* "The serial number MUST be a positive integer"
3421
- "Conforming CAs MUST NOT use serialNumber values longer than 20 octets."
3422
- -- https://tools.ietf.org/html/rfc5280#section-4.1.2.2
3423
-
3424
- for the integer to be positive the leading bit needs to be 0 hence the
3425
- application of a bitmap
3426
- */
3427
- $serialNumber = !empty($this->serialNumber) ?
3428
- $this->serialNumber :
3429
- new BigInteger(Random::string(20) & ("\x7F" . str_repeat("\xFF", 19)), 256);
3430
-
3431
- $this->currentCert = array(
3432
- 'tbsCertificate' =>
3433
- array(
3434
- 'version' => 'v3',
3435
- 'serialNumber' => $serialNumber, // $this->setserialNumber()
3436
- 'signature' => array('algorithm' => $signatureAlgorithm),
3437
- 'issuer' => false, // this is going to be overwritten later
3438
- 'validity' => array(
3439
- 'notBefore' => $this->_timeField($startDate), // $this->setStartDate()
3440
- 'notAfter' => $this->_timeField($endDate) // $this->setEndDate()
3441
- ),
3442
- 'subject' => $subject->dn,
3443
- 'subjectPublicKeyInfo' => $subjectPublicKey
3444
- ),
3445
- 'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm),
3446
- 'signature' => false // this is going to be overwritten later
3447
- );
3448
-
3449
- // Copy extensions from CSR.
3450
- $csrexts = $subject->getAttribute('pkcs-9-at-extensionRequest', 0);
3451
-
3452
- if (!empty($csrexts)) {
3453
- $this->currentCert['tbsCertificate']['extensions'] = $csrexts;
3454
- }
3455
- }
3456
-
3457
- $this->currentCert['tbsCertificate']['issuer'] = $issuer->dn;
3458
-
3459
- if (isset($issuer->currentKeyIdentifier)) {
3460
- $this->setExtension('id-ce-authorityKeyIdentifier', array(
3461
- //'authorityCertIssuer' => array(
3462
- // array(
3463
- // 'directoryName' => $issuer->dn
3464
- // )
3465
- //),
3466
- 'keyIdentifier' => $issuer->currentKeyIdentifier
3467
- ));
3468
- //$extensions = &$this->currentCert['tbsCertificate']['extensions'];
3469
- //if (isset($issuer->serialNumber)) {
3470
- // $extensions[count($extensions) - 1]['authorityCertSerialNumber'] = $issuer->serialNumber;
3471
- //}
3472
- //unset($extensions);
3473
- }
3474
-
3475
- if (isset($subject->currentKeyIdentifier)) {
3476
- $this->setExtension('id-ce-subjectKeyIdentifier', $subject->currentKeyIdentifier);
3477
- }
3478
-
3479
- $altName = array();
3480
-
3481
- if (isset($subject->domains) && count($subject->domains)) {
3482
- $altName = array_map(array('\phpseclib\File\X509', '_dnsName'), $subject->domains);
3483
- }
3484
-
3485
- if (isset($subject->ipAddresses) && count($subject->ipAddresses)) {
3486
- // should an IP address appear as the CN if no domain name is specified? idk
3487
- //$ips = count($subject->domains) ? $subject->ipAddresses : array_slice($subject->ipAddresses, 1);
3488
- $ipAddresses = array();
3489
- foreach ($subject->ipAddresses as $ipAddress) {
3490
- $encoded = $subject->_ipAddress($ipAddress);
3491
- if ($encoded !== false) {
3492
- $ipAddresses[] = $encoded;
3493
- }
3494
- }
3495
- if (count($ipAddresses)) {
3496
- $altName = array_merge($altName, $ipAddresses);
3497
- }
3498
- }
3499
-
3500
- if (!empty($altName)) {
3501
- $this->setExtension('id-ce-subjectAltName', $altName);
3502
- }
3503
-
3504
- if ($this->caFlag) {
3505
- $keyUsage = $this->getExtension('id-ce-keyUsage');
3506
- if (!$keyUsage) {
3507
- $keyUsage = array();
3508
- }
3509
-
3510
- $this->setExtension(
3511
- 'id-ce-keyUsage',
3512
- array_values(array_unique(array_merge($keyUsage, array('cRLSign', 'keyCertSign'))))
3513
- );
3514
-
3515
- $basicConstraints = $this->getExtension('id-ce-basicConstraints');
3516
- if (!$basicConstraints) {
3517
- $basicConstraints = array();
3518
- }
3519
-
3520
- $this->setExtension(
3521
- 'id-ce-basicConstraints',
3522
- array_unique(array_merge(array('cA' => true), $basicConstraints)),
3523
- true
3524
- );
3525
-
3526
- if (!isset($subject->currentKeyIdentifier)) {
3527
- $this->setExtension('id-ce-subjectKeyIdentifier', base64_encode($this->computeKeyIdentifier($this->currentCert)), false, false);
3528
- }
3529
- }
3530
-
3531
- // resync $this->signatureSubject
3532
- // save $tbsCertificate in case there are any \phpseclib\File\ASN1\Element objects in it
3533
- $tbsCertificate = $this->currentCert['tbsCertificate'];
3534
- $this->loadX509($this->saveX509($this->currentCert));
3535
-
3536
- $result = $this->_sign($issuer->privateKey, $signatureAlgorithm);
3537
- $result['tbsCertificate'] = $tbsCertificate;
3538
-
3539
- $this->currentCert = $currentCert;
3540
- $this->signatureSubject = $signatureSubject;
3541
-
3542
- return $result;
3543
- }
3544
-
3545
- /**
3546
- * Sign a CSR
3547
- *
3548
- * @access public
3549
- * @return mixed
3550
- */
3551
- function signCSR($signatureAlgorithm = 'sha1WithRSAEncryption')
3552
- {
3553
- if (!is_object($this->privateKey) || empty($this->dn)) {
3554
- return false;
3555
- }
3556
-
3557
- $origPublicKey = $this->publicKey;
3558
- $class = get_class($this->privateKey);
3559
- $this->publicKey = new $class();
3560
- $this->publicKey->loadKey($this->privateKey->getPublicKey());
3561
- $this->publicKey->setPublicKey();
3562
- if (!($publicKey = $this->_formatSubjectPublicKey())) {
3563
- return false;
3564
- }
3565
- $this->publicKey = $origPublicKey;
3566
-
3567
- $currentCert = isset($this->currentCert) ? $this->currentCert : null;
3568
- $signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject: null;
3569
-
3570
- if (isset($this->currentCert) && is_array($this->currentCert) && isset($this->currentCert['certificationRequestInfo'])) {
3571
- $this->currentCert['signatureAlgorithm']['algorithm'] = $signatureAlgorithm;
3572
- if (!empty($this->dn)) {
3573
- $this->currentCert['certificationRequestInfo']['subject'] = $this->dn;
3574
- }
3575
- $this->currentCert['certificationRequestInfo']['subjectPKInfo'] = $publicKey;
3576
- } else {
3577
- $this->currentCert = array(
3578
- 'certificationRequestInfo' =>
3579
- array(
3580
- 'version' => 'v1',
3581
- 'subject' => $this->dn,
3582
- 'subjectPKInfo' => $publicKey
3583
- ),
3584
- 'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm),
3585
- 'signature' => false // this is going to be overwritten later
3586
- );
3587
- }
3588
-
3589
- // resync $this->signatureSubject
3590
- // save $certificationRequestInfo in case there are any \phpseclib\File\ASN1\Element objects in it
3591
- $certificationRequestInfo = $this->currentCert['certificationRequestInfo'];
3592
- $this->loadCSR($this->saveCSR($this->currentCert));
3593
-
3594
- $result = $this->_sign($this->privateKey, $signatureAlgorithm);
3595
- $result['certificationRequestInfo'] = $certificationRequestInfo;
3596
-
3597
- $this->currentCert = $currentCert;
3598
- $this->signatureSubject = $signatureSubject;
3599
-
3600
- return $result;
3601
- }
3602
-
3603
- /**
3604
- * Sign a SPKAC
3605
- *
3606
- * @access public
3607
- * @return mixed
3608
- */
3609
- function signSPKAC($signatureAlgorithm = 'sha1WithRSAEncryption')
3610
- {
3611
- if (!is_object($this->privateKey)) {
3612
- return false;
3613
- }
3614
-
3615
- $origPublicKey = $this->publicKey;
3616
- $class = get_class($this->privateKey);
3617
- $this->publicKey = new $class();
3618
- $this->publicKey->loadKey($this->privateKey->getPublicKey());
3619
- $this->publicKey->setPublicKey();
3620
- $publicKey = $this->_formatSubjectPublicKey();
3621
- if (!$publicKey) {
3622
- return false;
3623
- }
3624
- $this->publicKey = $origPublicKey;
3625
-
3626
- $currentCert = isset($this->currentCert) ? $this->currentCert : null;
3627
- $signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject: null;
3628
-
3629
- // re-signing a SPKAC seems silly but since everything else supports re-signing why not?
3630
- if (isset($this->currentCert) && is_array($this->currentCert) && isset($this->currentCert['publicKeyAndChallenge'])) {
3631
- $this->currentCert['signatureAlgorithm']['algorithm'] = $signatureAlgorithm;
3632
- $this->currentCert['publicKeyAndChallenge']['spki'] = $publicKey;
3633
- if (!empty($this->challenge)) {
3634
- // the bitwise AND ensures that the output is a valid IA5String
3635
- $this->currentCert['publicKeyAndChallenge']['challenge'] = $this->challenge & str_repeat("\x7F", strlen($this->challenge));
3636
- }
3637
- } else {
3638
- $this->currentCert = array(
3639
- 'publicKeyAndChallenge' =>
3640
- array(
3641
- 'spki' => $publicKey,
3642
- // quoting <https://developer.mozilla.org/en-US/docs/Web/HTML/Element/keygen>,
3643
- // "A challenge string that is submitted along with the public key. Defaults to an empty string if not specified."
3644
- // both Firefox and OpenSSL ("openssl spkac -key private.key") behave this way
3645
- // we could alternatively do this instead if we ignored the specs:
3646
- // Random::string(8) & str_repeat("\x7F", 8)
3647
- 'challenge' => !empty($this->challenge) ? $this->challenge : ''
3648
- ),
3649
- 'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm),
3650
- 'signature' => false // this is going to be overwritten later
3651
- );
3652
- }
3653
-
3654
- // resync $this->signatureSubject
3655
- // save $publicKeyAndChallenge in case there are any \phpseclib\File\ASN1\Element objects in it
3656
- $publicKeyAndChallenge = $this->currentCert['publicKeyAndChallenge'];
3657
- $this->loadSPKAC($this->saveSPKAC($this->currentCert));
3658
-
3659
- $result = $this->_sign($this->privateKey, $signatureAlgorithm);
3660
- $result['publicKeyAndChallenge'] = $publicKeyAndChallenge;
3661
-
3662
- $this->currentCert = $currentCert;
3663
- $this->signatureSubject = $signatureSubject;
3664
-
3665
- return $result;
3666
- }
3667
-
3668
- /**
3669
- * Sign a CRL
3670
- *
3671
- * $issuer's private key needs to be loaded.
3672
- *
3673
- * @param \phpseclib\File\X509 $issuer
3674
- * @param \phpseclib\File\X509 $crl
3675
- * @param string $signatureAlgorithm optional
3676
- * @access public
3677
- * @return mixed
3678
- */
3679
- function signCRL($issuer, $crl, $signatureAlgorithm = 'sha1WithRSAEncryption')
3680
- {
3681
- if (!is_object($issuer->privateKey) || empty($issuer->dn)) {
3682
- return false;
3683
- }
3684
-
3685
- $currentCert = isset($this->currentCert) ? $this->currentCert : null;
3686
- $signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject : null;
3687
-
3688
- $thisUpdate = new DateTime('now', new DateTimeZone(@date_default_timezone_get()));
3689
- $thisUpdate = !empty($this->startDate) ? $this->startDate : $thisUpdate->format('D, d M Y H:i:s O');
3690
-
3691
- if (isset($crl->currentCert) && is_array($crl->currentCert) && isset($crl->currentCert['tbsCertList'])) {
3692
- $this->currentCert = $crl->currentCert;
3693
- $this->currentCert['tbsCertList']['signature']['algorithm'] = $signatureAlgorithm;
3694
- $this->currentCert['signatureAlgorithm']['algorithm'] = $signatureAlgorithm;
3695
- } else {
3696
- $this->currentCert = array(
3697
- 'tbsCertList' =>
3698
- array(
3699
- 'version' => 'v2',
3700
- 'signature' => array('algorithm' => $signatureAlgorithm),
3701
- 'issuer' => false, // this is going to be overwritten later
3702
- 'thisUpdate' => $this->_timeField($thisUpdate) // $this->setStartDate()
3703
- ),
3704
- 'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm),
3705
- 'signature' => false // this is going to be overwritten later
3706
- );
3707
- }
3708
-
3709
- $tbsCertList = &$this->currentCert['tbsCertList'];
3710
- $tbsCertList['issuer'] = $issuer->dn;
3711
- $tbsCertList['thisUpdate'] = $this->_timeField($thisUpdate);
3712
-
3713
- if (!empty($this->endDate)) {
3714
- $tbsCertList['nextUpdate'] = $this->_timeField($this->endDate); // $this->setEndDate()
3715
- } else {
3716
- unset($tbsCertList['nextUpdate']);
3717
- }
3718
-
3719
- if (!empty($this->serialNumber)) {
3720
- $crlNumber = $this->serialNumber;
3721
- } else {
3722
- $crlNumber = $this->getExtension('id-ce-cRLNumber');
3723
- // "The CRL number is a non-critical CRL extension that conveys a
3724
- // monotonically increasing sequence number for a given CRL scope and
3725
- // CRL issuer. This extension allows users to easily determine when a
3726
- // particular CRL supersedes another CRL."
3727
- // -- https://tools.ietf.org/html/rfc5280#section-5.2.3
3728
- $crlNumber = $crlNumber !== false ? $crlNumber->add(new BigInteger(1)) : null;
3729
- }
3730
-
3731
- $this->removeExtension('id-ce-authorityKeyIdentifier');
3732
- $this->removeExtension('id-ce-issuerAltName');
3733
-
3734
- // Be sure version >= v2 if some extension found.
3735
- $version = isset($tbsCertList['version']) ? $tbsCertList['version'] : 0;
3736
- if (!$version) {
3737
- if (!empty($tbsCertList['crlExtensions'])) {
3738
- $version = 1; // v2.
3739
- } elseif (!empty($tbsCertList['revokedCertificates'])) {
3740
- foreach ($tbsCertList['revokedCertificates'] as $cert) {
3741
- if (!empty($cert['crlEntryExtensions'])) {
3742
- $version = 1; // v2.
3743
- }
3744
- }
3745
- }
3746
-
3747
- if ($version) {
3748
- $tbsCertList['version'] = $version;
3749
- }
3750
- }
3751
-
3752
- // Store additional extensions.
3753
- if (!empty($tbsCertList['version'])) { // At least v2.
3754
- if (!empty($crlNumber)) {
3755
- $this->setExtension('id-ce-cRLNumber', $crlNumber);
3756
- }
3757
-
3758
- if (isset($issuer->currentKeyIdentifier)) {
3759
- $this->setExtension('id-ce-authorityKeyIdentifier', array(
3760
- //'authorityCertIssuer' => array(
3761
- // array(
3762
- // 'directoryName' => $issuer->dn
3763
- // )
3764
- //),
3765
- 'keyIdentifier' => $issuer->currentKeyIdentifier
3766
- ));
3767
- //$extensions = &$tbsCertList['crlExtensions'];
3768
- //if (isset($issuer->serialNumber)) {
3769
- // $extensions[count($extensions) - 1]['authorityCertSerialNumber'] = $issuer->serialNumber;
3770
- //}
3771
- //unset($extensions);
3772
- }
3773
-
3774
- $issuerAltName = $this->getExtension('id-ce-subjectAltName', $issuer->currentCert);
3775
-
3776
- if ($issuerAltName !== false) {
3777
- $this->setExtension('id-ce-issuerAltName', $issuerAltName);
3778
- }
3779
- }
3780
-
3781
- if (empty($tbsCertList['revokedCertificates'])) {
3782
- unset($tbsCertList['revokedCertificates']);
3783
- }
3784
-
3785
- unset($tbsCertList);
3786
-
3787
- // resync $this->signatureSubject
3788
- // save $tbsCertList in case there are any \phpseclib\File\ASN1\Element objects in it
3789
- $tbsCertList = $this->currentCert['tbsCertList'];
3790
- $this->loadCRL($this->saveCRL($this->currentCert));
3791
-
3792
- $result = $this->_sign($issuer->privateKey, $signatureAlgorithm);
3793
- $result['tbsCertList'] = $tbsCertList;
3794
-
3795
- $this->currentCert = $currentCert;
3796
- $this->signatureSubject = $signatureSubject;
3797
-
3798
- return $result;
3799
- }
3800
-
3801
- /**
3802
- * X.509 certificate signing helper function.
3803
- *
3804
- * @param object $key
3805
- * @param \phpseclib\File\X509 $subject
3806
- * @param string $signatureAlgorithm
3807
- * @access public
3808
- * @return mixed
3809
- */
3810
- function _sign($key, $signatureAlgorithm)
3811
- {
3812
- if ($key instanceof RSA) {
3813
- switch ($signatureAlgorithm) {
3814
- case 'md2WithRSAEncryption':
3815
- case 'md5WithRSAEncryption':
3816
- case 'sha1WithRSAEncryption':
3817
- case 'sha224WithRSAEncryption':
3818
- case 'sha256WithRSAEncryption':
3819
- case 'sha384WithRSAEncryption':
3820
- case 'sha512WithRSAEncryption':
3821
- $key->setHash(preg_replace('#WithRSAEncryption$#', '', $signatureAlgorithm));
3822
- $key->setSignatureMode(RSA::SIGNATURE_PKCS1);
3823
-
3824
- $this->currentCert['signature'] = base64_encode("\0" . $key->sign($this->signatureSubject));
3825
- return $this->currentCert;
3826
- }
3827
- }
3828
-
3829
- return false;
3830
- }
3831
-
3832
- /**
3833
- * Set certificate start date
3834
- *
3835
- * @param string $date
3836
- * @access public
3837
- */
3838
- function setStartDate($date)
3839
- {
3840
- if (!is_object($date) || !is_a($date, 'DateTime')) {
3841
- $date = new DateTime($date, new DateTimeZone(@date_default_timezone_get()));
3842
- }
3843
-
3844
- $this->startDate = $date->format('D, d M Y H:i:s O');
3845
- }
3846
-
3847
- /**
3848
- * Set certificate end date
3849
- *
3850
- * @param string $date
3851
- * @access public
3852
- */
3853
- function setEndDate($date)
3854
- {
3855
- /*
3856
- To indicate that a certificate has no well-defined expiration date,
3857
- the notAfter SHOULD be assigned the GeneralizedTime value of
3858
- 99991231235959Z.
3859
-
3860
- -- http://tools.ietf.org/html/rfc5280#section-4.1.2.5
3861
- */
3862
- if (strtolower($date) == 'lifetime') {
3863
- $temp = '99991231235959Z';
3864
- $asn1 = new ASN1();
3865
- $temp = chr(ASN1::TYPE_GENERALIZED_TIME) . $asn1->_encodeLength(strlen($temp)) . $temp;
3866
- $this->endDate = new Element($temp);
3867
- } else {
3868
- if (!is_object($date) || !is_a($date, 'DateTime')) {
3869
- $date = new DateTime($date, new DateTimeZone(@date_default_timezone_get()));
3870
- }
3871
-
3872
- $this->endDate = $date->format('D, d M Y H:i:s O');
3873
- }
3874
- }
3875
-
3876
- /**
3877
- * Set Serial Number
3878
- *
3879
- * @param string $serial
3880
- * @param $base optional
3881
- * @access public
3882
- */
3883
- function setSerialNumber($serial, $base = -256)
3884
- {
3885
- $this->serialNumber = new BigInteger($serial, $base);
3886
- }
3887
-
3888
- /**
3889
- * Turns the certificate into a certificate authority
3890
- *
3891
- * @access public
3892
- */
3893
- function makeCA()
3894
- {
3895
- $this->caFlag = true;
3896
- }
3897
-
3898
- /**
3899
- * Check for validity of subarray
3900
- *
3901
- * This is intended for use in conjunction with _subArrayUnchecked(),
3902
- * implementing the checks included in _subArray() but without copying
3903
- * a potentially large array by passing its reference by-value to is_array().
3904
- *
3905
- * @param array $root
3906
- * @param string $path
3907
- * @return boolean
3908
- * @access private
3909
- */
3910
- function _isSubArrayValid($root, $path)
3911
- {
3912
- if (!is_array($root)) {
3913
- return false;
3914
- }
3915
-
3916
- foreach (explode('/', $path) as $i) {
3917
- if (!is_array($root)) {
3918
- return false;
3919
- }
3920
-
3921
- if (!isset($root[$i])) {
3922
- return true;
3923
- }
3924
-
3925
- $root = $root[$i];
3926
- }
3927
-
3928
- return true;
3929
- }
3930
-
3931
- /**
3932
- * Get a reference to a subarray
3933
- *
3934
- * This variant of _subArray() does no is_array() checking,
3935
- * so $root should be checked with _isSubArrayValid() first.
3936
- *
3937
- * This is here for performance reasons:
3938
- * Passing a reference (i.e. $root) by-value (i.e. to is_array())
3939
- * creates a copy. If $root is an especially large array, this is expensive.
3940
- *
3941
- * @param array $root
3942
- * @param string $path absolute path with / as component separator
3943
- * @param bool $create optional
3944
- * @access private
3945
- * @return array|false
3946
- */
3947
- function &_subArrayUnchecked(&$root, $path, $create = false)
3948
- {
3949
- $false = false;
3950
-
3951
- foreach (explode('/', $path) as $i) {
3952
- if (!isset($root[$i])) {
3953
- if (!$create) {
3954
- return $false;
3955
- }
3956
-
3957
- $root[$i] = array();
3958
- }
3959
-
3960
- $root = &$root[$i];
3961
- }
3962
-
3963
- return $root;
3964
- }
3965
-
3966
- /**
3967
- * Get a reference to a subarray
3968
- *
3969
- * @param array $root
3970
- * @param string $path absolute path with / as component separator
3971
- * @param bool $create optional
3972
- * @access private
3973
- * @return array|false
3974
- */
3975
- function &_subArray(&$root, $path, $create = false)
3976
- {
3977
- $false = false;
3978
-
3979
- if (!is_array($root)) {
3980
- return $false;
3981
- }
3982
-
3983
- foreach (explode('/', $path) as $i) {
3984
- if (!is_array($root)) {
3985
- return $false;
3986
- }
3987
-
3988
- if (!isset($root[$i])) {
3989
- if (!$create) {
3990
- return $false;
3991
- }
3992
-
3993
- $root[$i] = array();
3994
- }
3995
-
3996
- $root = &$root[$i];
3997
- }
3998
-
3999
- return $root;
4000
- }
4001
-
4002
- /**
4003
- * Get a reference to an extension subarray
4004
- *
4005
- * @param array $root
4006
- * @param string $path optional absolute path with / as component separator
4007
- * @param bool $create optional
4008
- * @access private
4009
- * @return array|false
4010
- */
4011
- function &_extensions(&$root, $path = null, $create = false)
4012
- {
4013
- if (!isset($root)) {
4014
- $root = $this->currentCert;
4015
- }
4016
-
4017
- switch (true) {
4018
- case !empty($path):
4019
- case !is_array($root):
4020
- break;
4021
- case isset($root['tbsCertificate']):
4022
- $path = 'tbsCertificate/extensions';
4023
- break;
4024
- case isset($root['tbsCertList']):
4025
- $path = 'tbsCertList/crlExtensions';
4026
- break;
4027
- case isset($root['certificationRequestInfo']):
4028
- $pth = 'certificationRequestInfo/attributes';
4029
- $attributes = &$this->_subArray($root, $pth, $create);
4030
-
4031
- if (is_array($attributes)) {
4032
- foreach ($attributes as $key => $value) {
4033
- if ($value['type'] == 'pkcs-9-at-extensionRequest') {
4034
- $path = "$pth/$key/value/0";
4035
- break 2;
4036
- }
4037
- }
4038
- if ($create) {
4039
- $key = count($attributes);
4040
- $attributes[] = array('type' => 'pkcs-9-at-extensionRequest', 'value' => array());
4041
- $path = "$pth/$key/value/0";
4042
- }
4043
- }
4044
- break;
4045
- }
4046
-
4047
- $extensions = &$this->_subArray($root, $path, $create);
4048
-
4049
- if (!is_array($extensions)) {
4050
- $false = false;
4051
- return $false;
4052
- }
4053
-
4054
- return $extensions;
4055
- }
4056
-
4057
- /**
4058
- * Remove an Extension
4059
- *
4060
- * @param string $id
4061
- * @param string $path optional
4062
- * @access private
4063
- * @return bool
4064
- */
4065
- function _removeExtension($id, $path = null)
4066
- {
4067
- $extensions = &$this->_extensions($this->currentCert, $path);
4068
-
4069
- if (!is_array($extensions)) {
4070
- return false;
4071
- }
4072
-
4073
- $result = false;
4074
- foreach ($extensions as $key => $value) {
4075
- if ($value['extnId'] == $id) {
4076
- unset($extensions[$key]);
4077
- $result = true;
4078
- }
4079
- }
4080
-
4081
- $extensions = array_values($extensions);
4082
- return $result;
4083
- }
4084
-
4085
- /**
4086
- * Get an Extension
4087
- *
4088
- * Returns the extension if it exists and false if not
4089
- *
4090
- * @param string $id
4091
- * @param array $cert optional
4092
- * @param string $path optional
4093
- * @access private
4094
- * @return mixed
4095
- */
4096
- function _getExtension($id, $cert = null, $path = null)
4097
- {
4098
- $extensions = $this->_extensions($cert, $path);
4099
-
4100
- if (!is_array($extensions)) {
4101
- return false;
4102
- }
4103
-
4104
- foreach ($extensions as $key => $value) {
4105
- if ($value['extnId'] == $id) {
4106
- return $value['extnValue'];
4107
- }
4108
- }
4109
-
4110
- return false;
4111
- }
4112
-
4113
- /**
4114
- * Returns a list of all extensions in use
4115
- *
4116
- * @param array $cert optional
4117
- * @param string $path optional
4118
- * @access private
4119
- * @return array
4120
- */
4121
- function _getExtensions($cert = null, $path = null)
4122
- {
4123
- $exts = $this->_extensions($cert, $path);
4124
- $extensions = array();
4125
-
4126
- if (is_array($exts)) {
4127
- foreach ($exts as $extension) {
4128
- $extensions[] = $extension['extnId'];
4129
- }
4130
- }
4131
-
4132
- return $extensions;
4133
- }
4134
-
4135
- /**
4136
- * Set an Extension
4137
- *
4138
- * @param string $id
4139
- * @param mixed $value
4140
- * @param bool $critical optional
4141
- * @param bool $replace optional
4142
- * @param string $path optional
4143
- * @access private
4144
- * @return bool
4145
- */
4146
- function _setExtension($id, $value, $critical = false, $replace = true, $path = null)
4147
- {
4148
- $extensions = &$this->_extensions($this->currentCert, $path, true);
4149
-
4150
- if (!is_array($extensions)) {
4151
- return false;
4152
- }
4153
-
4154
- $newext = array('extnId' => $id, 'critical' => $critical, 'extnValue' => $value);
4155
-
4156
- foreach ($extensions as $key => $value) {
4157
- if ($value['extnId'] == $id) {
4158
- if (!$replace) {
4159
- return false;
4160
- }
4161
-
4162
- $extensions[$key] = $newext;
4163
- return true;
4164
- }
4165
- }
4166
-
4167
- $extensions[] = $newext;
4168
- return true;
4169
- }
4170
-
4171
- /**
4172
- * Remove a certificate, CSR or CRL Extension
4173
- *
4174
- * @param string $id
4175
- * @access public
4176
- * @return bool
4177
- */
4178
- function removeExtension($id)
4179
- {
4180
- return $this->_removeExtension($id);
4181
- }
4182
-
4183
- /**
4184
- * Get a certificate, CSR or CRL Extension
4185
- *
4186
- * Returns the extension if it exists and false if not
4187
- *
4188
- * @param string $id
4189
- * @param array $cert optional
4190
- * @access public
4191
- * @return mixed
4192
- */
4193
- function getExtension($id, $cert = null)
4194
- {
4195
- return $this->_getExtension($id, $cert);
4196
- }
4197
-
4198
- /**
4199
- * Returns a list of all extensions in use in certificate, CSR or CRL
4200
- *
4201
- * @param array $cert optional
4202
- * @access public
4203
- * @return array
4204
- */
4205
- function getExtensions($cert = null)
4206
- {
4207
- return $this->_getExtensions($cert);
4208
- }
4209
-
4210
- /**
4211
- * Set a certificate, CSR or CRL Extension
4212
- *
4213
- * @param string $id
4214
- * @param mixed $value
4215
- * @param bool $critical optional
4216
- * @param bool $replace optional
4217
- * @access public
4218
- * @return bool
4219
- */
4220
- function setExtension($id, $value, $critical = false, $replace = true)
4221
- {
4222
- return $this->_setExtension($id, $value, $critical, $replace);
4223
- }
4224
-
4225
- /**
4226
- * Remove a CSR attribute.
4227
- *
4228
- * @param string $id
4229
- * @param int $disposition optional
4230
- * @access public
4231
- * @return bool
4232
- */
4233
- function removeAttribute($id, $disposition = self::ATTR_ALL)
4234
- {
4235
- $attributes = &$this->_subArray($this->currentCert, 'certificationRequestInfo/attributes');
4236
-
4237
- if (!is_array($attributes)) {
4238
- return false;
4239
- }
4240
-
4241
- $result = false;
4242
- foreach ($attributes as $key => $attribute) {
4243
- if ($attribute['type'] == $id) {
4244
- $n = count($attribute['value']);
4245
- switch (true) {
4246
- case $disposition == self::ATTR_APPEND:
4247
- case $disposition == self::ATTR_REPLACE:
4248
- return false;
4249
- case $disposition >= $n:
4250
- $disposition -= $n;
4251
- break;
4252
- case $disposition == self::ATTR_ALL:
4253
- case $n == 1:
4254
- unset($attributes[$key]);
4255
- $result = true;
4256
- break;
4257
- default:
4258
- unset($attributes[$key]['value'][$disposition]);
4259
- $attributes[$key]['value'] = array_values($attributes[$key]['value']);
4260
- $result = true;
4261
- break;
4262
- }
4263
- if ($result && $disposition != self::ATTR_ALL) {
4264
- break;
4265
- }
4266
- }
4267
- }
4268
-
4269
- $attributes = array_values($attributes);
4270
- return $result;
4271
- }
4272
-
4273
- /**
4274
- * Get a CSR attribute
4275
- *
4276
- * Returns the attribute if it exists and false if not
4277
- *
4278
- * @param string $id
4279
- * @param int $disposition optional
4280
- * @param array $csr optional
4281
- * @access public
4282
- * @return mixed
4283
- */
4284
- function getAttribute($id, $disposition = self::ATTR_ALL, $csr = null)
4285
- {
4286
- if (empty($csr)) {
4287
- $csr = $this->currentCert;
4288
- }
4289
-
4290
- $attributes = $this->_subArray($csr, 'certificationRequestInfo/attributes');
4291
-
4292
- if (!is_array($attributes)) {
4293
- return false;
4294
- }
4295
-
4296
- foreach ($attributes as $key => $attribute) {
4297
- if ($attribute['type'] == $id) {
4298
- $n = count($attribute['value']);
4299
- switch (true) {
4300
- case $disposition == self::ATTR_APPEND:
4301
- case $disposition == self::ATTR_REPLACE:
4302
- return false;
4303
- case $disposition == self::ATTR_ALL:
4304
- return $attribute['value'];
4305
- case $disposition >= $n:
4306
- $disposition -= $n;
4307
- break;
4308
- default:
4309
- return $attribute['value'][$disposition];
4310
- }
4311
- }
4312
- }
4313
-
4314
- return false;
4315
- }
4316
-
4317
- /**
4318
- * Returns a list of all CSR attributes in use
4319
- *
4320
- * @param array $csr optional
4321
- * @access public
4322
- * @return array
4323
- */
4324
- function getAttributes($csr = null)
4325
- {
4326
- if (empty($csr)) {
4327
- $csr = $this->currentCert;
4328
- }
4329
-
4330
- $attributes = $this->_subArray($csr, 'certificationRequestInfo/attributes');
4331
- $attrs = array();
4332
-
4333
- if (is_array($attributes)) {
4334
- foreach ($attributes as $attribute) {
4335
- $attrs[] = $attribute['type'];
4336
- }
4337
- }
4338
-
4339
- return $attrs;
4340
- }
4341
-
4342
- /**
4343
- * Set a CSR attribute
4344
- *
4345
- * @param string $id
4346
- * @param mixed $value
4347
- * @param bool $disposition optional
4348
- * @access public
4349
- * @return bool
4350
- */
4351
- function setAttribute($id, $value, $disposition = self::ATTR_ALL)
4352
- {
4353
- $attributes = &$this->_subArray($this->currentCert, 'certificationRequestInfo/attributes', true);
4354
-
4355
- if (!is_array($attributes)) {
4356
- return false;
4357
- }
4358
-
4359
- switch ($disposition) {
4360
- case self::ATTR_REPLACE:
4361
- $disposition = self::ATTR_APPEND;
4362
- case self::ATTR_ALL:
4363
- $this->removeAttribute($id);
4364
- break;
4365
- }
4366
-
4367
- foreach ($attributes as $key => $attribute) {
4368
- if ($attribute['type'] == $id) {
4369
- $n = count($attribute['value']);
4370
- switch (true) {
4371
- case $disposition == self::ATTR_APPEND:
4372
- $last = $key;
4373
- break;
4374
- case $disposition >= $n:
4375
- $disposition -= $n;
4376
- break;
4377
- default:
4378
- $attributes[$key]['value'][$disposition] = $value;
4379
- return true;
4380
- }
4381
- }
4382
- }
4383
-
4384
- switch (true) {
4385
- case $disposition >= 0:
4386
- return false;
4387
- case isset($last):
4388
- $attributes[$last]['value'][] = $value;
4389
- break;
4390
- default:
4391
- $attributes[] = array('type' => $id, 'value' => $disposition == self::ATTR_ALL ? $value: array($value));
4392
- break;
4393
- }
4394
-
4395
- return true;
4396
- }
4397
-
4398
- /**
4399
- * Sets the subject key identifier
4400
- *
4401
- * This is used by the id-ce-authorityKeyIdentifier and the id-ce-subjectKeyIdentifier extensions.
4402
- *
4403
- * @param string $value
4404
- * @access public
4405
- */
4406
- function setKeyIdentifier($value)
4407
- {
4408
- if (empty($value)) {
4409
- unset($this->currentKeyIdentifier);
4410
- } else {
4411
- $this->currentKeyIdentifier = base64_encode($value);
4412
- }
4413
- }
4414
-
4415
- /**
4416
- * Compute a public key identifier.
4417
- *
4418
- * Although key identifiers may be set to any unique value, this function
4419
- * computes key identifiers from public key according to the two
4420
- * recommended methods (4.2.1.2 RFC 3280).
4421
- * Highly polymorphic: try to accept all possible forms of key:
4422
- * - Key object
4423
- * - \phpseclib\File\X509 object with public or private key defined
4424
- * - Certificate or CSR array
4425
- * - \phpseclib\File\ASN1\Element object
4426
- * - PEM or DER string
4427
- *
4428
- * @param mixed $key optional
4429
- * @param int $method optional
4430
- * @access public
4431
- * @return string binary key identifier
4432
- */
4433
- function computeKeyIdentifier($key = null, $method = 1)
4434
- {
4435
- if (is_null($key)) {
4436
- $key = $this;
4437
- }
4438
-
4439
- switch (true) {
4440
- case is_string($key):
4441
- break;
4442
- case is_array($key) && isset($key['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']):
4443
- return $this->computeKeyIdentifier($key['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'], $method);
4444
- case is_array($key) && isset($key['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey']):
4445
- return $this->computeKeyIdentifier($key['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'], $method);
4446
- case !is_object($key):
4447
- return false;
4448
- case $key instanceof Element:
4449
- // Assume the element is a bitstring-packed key.
4450
- $asn1 = new ASN1();
4451
- $decoded = $asn1->decodeBER($key->element);
4452
- if (empty($decoded)) {
4453
- return false;
4454
- }
4455
- $raw = $asn1->asn1map($decoded[0], array('type' => ASN1::TYPE_BIT_STRING));
4456
- if (empty($raw)) {
4457
- return false;
4458
- }
4459
- $raw = base64_decode($raw);
4460
- // If the key is private, compute identifier from its corresponding public key.
4461
- $key = new RSA();
4462
- if (!$key->loadKey($raw)) {
4463
- return false; // Not an unencrypted RSA key.
4464
- }
4465
- if ($key->getPrivateKey() !== false) { // If private.
4466
- return $this->computeKeyIdentifier($key, $method);
4467
- }
4468
- $key = $raw; // Is a public key.
4469
- break;
4470
- case $key instanceof X509:
4471
- if (isset($key->publicKey)) {
4472
- return $this->computeKeyIdentifier($key->publicKey, $method);
4473
- }
4474
- if (isset($key->privateKey)) {
4475
- return $this->computeKeyIdentifier($key->privateKey, $method);
4476
- }
4477
- if (isset($key->currentCert['tbsCertificate']) || isset($key->currentCert['certificationRequestInfo'])) {
4478
- return $this->computeKeyIdentifier($key->currentCert, $method);
4479
- }
4480
- return false;
4481
- default: // Should be a key object (i.e.: \phpseclib\Crypt\RSA).
4482
- $key = $key->getPublicKey(RSA::PUBLIC_FORMAT_PKCS1);
4483
- break;
4484
- }
4485
-
4486
- // If in PEM format, convert to binary.
4487
- $key = $this->_extractBER($key);
4488
-
4489
- // Now we have the key string: compute its sha-1 sum.
4490
- $hash = new Hash('sha1');
4491
- $hash = $hash->hash($key);
4492
-
4493
- if ($method == 2) {
4494
- $hash = substr($hash, -8);
4495
- $hash[0] = chr((ord($hash[0]) & 0x0F) | 0x40);
4496
- }
4497
-
4498
- return $hash;
4499
- }
4500
-
4501
- /**
4502
- * Format a public key as appropriate
4503
- *
4504
- * @access private
4505
- * @return array
4506
- */
4507
- function _formatSubjectPublicKey()
4508
- {
4509
- if ($this->publicKey instanceof RSA) {
4510
- // the following two return statements do the same thing. i dunno.. i just prefer the later for some reason.
4511
- // the former is a good example of how to do fuzzing on the public key
4512
- //return new Element(base64_decode(preg_replace('#-.+-|[\r\n]#', '', $this->publicKey->getPublicKey())));
4513
- return array(
4514
- 'algorithm' => array('algorithm' => 'rsaEncryption'),
4515
- 'subjectPublicKey' => $this->publicKey->getPublicKey(RSA::PUBLIC_FORMAT_PKCS1)
4516
- );
4517
- }
4518
-
4519
- return false;
4520
- }
4521
-
4522
- /**
4523
- * Set the domain name's which the cert is to be valid for
4524
- *
4525
- * @access public
4526
- * @return array
4527
- */
4528
- function setDomain()
4529
- {
4530
- $this->domains = func_get_args();
4531
- $this->removeDNProp('id-at-commonName');
4532
- $this->setDNProp('id-at-commonName', $this->domains[0]);
4533
- }
4534
-
4535
- /**
4536
- * Set the IP Addresses's which the cert is to be valid for
4537
- *
4538
- * @access public
4539
- * @param string $ipAddress optional
4540
- */
4541
- function setIPAddress()
4542
- {
4543
- $this->ipAddresses = func_get_args();
4544
- /*
4545
- if (!isset($this->domains)) {
4546
- $this->removeDNProp('id-at-commonName');
4547
- $this->setDNProp('id-at-commonName', $this->ipAddresses[0]);
4548
- }
4549
- */
4550
- }
4551
-
4552
- /**
4553
- * Helper function to build domain array
4554
- *
4555
- * @access private
4556
- * @param string $domain
4557
- * @return array
4558
- */
4559
- function _dnsName($domain)
4560
- {
4561
- return array('dNSName' => $domain);
4562
- }
4563
-
4564
- /**
4565
- * Helper function to build IP Address array
4566
- *
4567
- * (IPv6 is not currently supported)
4568
- *
4569
- * @access private
4570
- * @param string $address
4571
- * @return array
4572
- */
4573
- function _iPAddress($address)
4574
- {
4575
- return array('iPAddress' => $address);
4576
- }
4577
-
4578
- /**
4579
- * Get the index of a revoked certificate.
4580
- *
4581
- * @param array $rclist
4582
- * @param string $serial
4583
- * @param bool $create optional
4584
- * @access private
4585
- * @return int|false
4586
- */
4587
- function _revokedCertificate(&$rclist, $serial, $create = false)
4588
- {
4589
- $serial = new BigInteger($serial);
4590
-
4591
- foreach ($rclist as $i => $rc) {
4592
- if (!($serial->compare($rc['userCertificate']))) {
4593
- return $i;
4594
- }
4595
- }
4596
-
4597
- if (!$create) {
4598
- return false;
4599
- }
4600
-
4601
- $i = count($rclist);
4602
- $revocationDate = new DateTime('now', new DateTimeZone(@date_default_timezone_get()));
4603
- $rclist[] = array('userCertificate' => $serial,
4604
- 'revocationDate' => $this->_timeField($revocationDate->format('D, d M Y H:i:s O')));
4605
- return $i;
4606
- }
4607
-
4608
- /**
4609
- * Revoke a certificate.
4610
- *
4611
- * @param string $serial
4612
- * @param string $date optional
4613
- * @access public
4614
- * @return bool
4615
- */
4616
- function revoke($serial, $date = null)
4617
- {
4618
- if (isset($this->currentCert['tbsCertList'])) {
4619
- if (is_array($rclist = &$this->_subArray($this->currentCert, 'tbsCertList/revokedCertificates', true))) {
4620
- if ($this->_revokedCertificate($rclist, $serial) === false) { // If not yet revoked
4621
- if (($i = $this->_revokedCertificate($rclist, $serial, true)) !== false) {
4622
- if (!empty($date)) {
4623
- $rclist[$i]['revocationDate'] = $this->_timeField($date);
4624
- }
4625
-
4626
- return true;
4627
- }
4628
- }
4629
- }
4630
- }
4631
-
4632
- return false;
4633
- }
4634
-
4635
- /**
4636
- * Unrevoke a certificate.
4637
- *
4638
- * @param string $serial
4639
- * @access public
4640
- * @return bool
4641
- */
4642
- function unrevoke($serial)
4643
- {
4644
- if (is_array($rclist = &$this->_subArray($this->currentCert, 'tbsCertList/revokedCertificates'))) {
4645
- if (($i = $this->_revokedCertificate($rclist, $serial)) !== false) {
4646
- unset($rclist[$i]);
4647
- $rclist = array_values($rclist);
4648
- return true;
4649
- }
4650
- }
4651
-
4652
- return false;
4653
- }
4654
-
4655
- /**
4656
- * Get a revoked certificate.
4657
- *
4658
- * @param string $serial
4659
- * @access public
4660
- * @return mixed
4661
- */
4662
- function getRevoked($serial)
4663
- {
4664
- if (is_array($rclist = $this->_subArray($this->currentCert, 'tbsCertList/revokedCertificates'))) {
4665
- if (($i = $this->_revokedCertificate($rclist, $serial)) !== false) {
4666
- return $rclist[$i];
4667
- }
4668
- }
4669
-
4670
- return false;
4671
- }
4672
-
4673
- /**
4674
- * List revoked certificates
4675
- *
4676
- * @param array $crl optional
4677
- * @access public
4678
- * @return array
4679
- */
4680
- function listRevoked($crl = null)
4681
- {
4682
- if (!isset($crl)) {
4683
- $crl = $this->currentCert;
4684
- }
4685
-
4686
- if (!isset($crl['tbsCertList'])) {
4687
- return false;
4688
- }
4689
-
4690
- $result = array();
4691
-
4692
- if (is_array($rclist = $this->_subArray($crl, 'tbsCertList/revokedCertificates'))) {
4693
- foreach ($rclist as $rc) {
4694
- $result[] = $rc['userCertificate']->toString();
4695
- }
4696
- }
4697
-
4698
- return $result;
4699
- }
4700
-
4701
- /**
4702
- * Remove a Revoked Certificate Extension
4703
- *
4704
- * @param string $serial
4705
- * @param string $id
4706
- * @access public
4707
- * @return bool
4708
- */
4709
- function removeRevokedCertificateExtension($serial, $id)
4710
- {
4711
- if (is_array($rclist = &$this->_subArray($this->currentCert, 'tbsCertList/revokedCertificates'))) {
4712
- if (($i = $this->_revokedCertificate($rclist, $serial)) !== false) {
4713
- return $this->_removeExtension($id, "tbsCertList/revokedCertificates/$i/crlEntryExtensions");
4714
- }
4715
- }
4716
-
4717
- return false;
4718
- }
4719
-
4720
- /**
4721
- * Get a Revoked Certificate Extension
4722
- *
4723
- * Returns the extension if it exists and false if not
4724
- *
4725
- * @param string $serial
4726
- * @param string $id
4727
- * @param array $crl optional
4728
- * @access public
4729
- * @return mixed
4730
- */
4731
- function getRevokedCertificateExtension($serial, $id, $crl = null)
4732
- {
4733
- if (!isset($crl)) {
4734
- $crl = $this->currentCert;
4735
- }
4736
-
4737
- if (is_array($rclist = $this->_subArray($crl, 'tbsCertList/revokedCertificates'))) {
4738
- if (($i = $this->_revokedCertificate($rclist, $serial)) !== false) {
4739
- return $this->_getExtension($id, $crl, "tbsCertList/revokedCertificates/$i/crlEntryExtensions");
4740
- }
4741
- }
4742
-
4743
- return false;
4744
- }
4745
-
4746
- /**
4747
- * Returns a list of all extensions in use for a given revoked certificate
4748
- *
4749
- * @param string $serial
4750
- * @param array $crl optional
4751
- * @access public
4752
- * @return array
4753
- */
4754
- function getRevokedCertificateExtensions($serial, $crl = null)
4755
- {
4756
- if (!isset($crl)) {
4757
- $crl = $this->currentCert;
4758
- }
4759
-
4760
- if (is_array($rclist = $this->_subArray($crl, 'tbsCertList/revokedCertificates'))) {
4761
- if (($i = $this->_revokedCertificate($rclist, $serial)) !== false) {
4762
- return $this->_getExtensions($crl, "tbsCertList/revokedCertificates/$i/crlEntryExtensions");
4763
- }
4764
- }
4765
-
4766
- return false;
4767
- }
4768
-
4769
- /**
4770
- * Set a Revoked Certificate Extension
4771
- *
4772
- * @param string $serial
4773
- * @param string $id
4774
- * @param mixed $value
4775
- * @param bool $critical optional
4776
- * @param bool $replace optional
4777
- * @access public
4778
- * @return bool
4779
- */
4780
- function setRevokedCertificateExtension($serial, $id, $value, $critical = false, $replace = true)
4781
- {
4782
- if (isset($this->currentCert['tbsCertList'])) {
4783
- if (is_array($rclist = &$this->_subArray($this->currentCert, 'tbsCertList/revokedCertificates', true))) {
4784
- if (($i = $this->_revokedCertificate($rclist, $serial, true)) !== false) {
4785
- return $this->_setExtension($id, $value, $critical, $replace, "tbsCertList/revokedCertificates/$i/crlEntryExtensions");
4786
- }
4787
- }
4788
- }
4789
-
4790
- return false;
4791
- }
4792
-
4793
- /**
4794
- * Extract raw BER from Base64 encoding
4795
- *
4796
- * @access private
4797
- * @param string $str
4798
- * @return string
4799
- */
4800
- function _extractBER($str)
4801
- {
4802
- /* X.509 certs are assumed to be base64 encoded but sometimes they'll have additional things in them
4803
- * above and beyond the ceritificate.
4804
- * ie. some may have the following preceding the -----BEGIN CERTIFICATE----- line:
4805
- *
4806
- * Bag Attributes
4807
- * localKeyID: 01 00 00 00
4808
- * subject=/O=organization/OU=org unit/CN=common name
4809
- * issuer=/O=organization/CN=common name
4810
- */
4811
- $temp = preg_replace('#.*?^-+[^-]+-+[\r\n ]*$#ms', '', $str, 1);
4812
- // remove the -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- stuff
4813
- $temp = preg_replace('#-+[^-]+-+#', '', $temp);
4814
- // remove new lines
4815
- $temp = str_replace(array("\r", "\n", ' '), '', $temp);
4816
- $temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false;
4817
- return $temp != false ? $temp : $str;
4818
- }
4819
-
4820
- /**
4821
- * Returns the OID corresponding to a name
4822
- *
4823
- * What's returned in the associative array returned by loadX509() (or load*()) is either a name or an OID if
4824
- * no OID to name mapping is available. The problem with this is that what may be an unmapped OID in one version
4825
- * of phpseclib may not be unmapped in the next version, so apps that are looking at this OID may not be able
4826
- * to work from version to version.
4827
- *
4828
- * This method will return the OID if a name is passed to it and if no mapping is avialable it'll assume that
4829
- * what's being passed to it already is an OID and return that instead. A few examples.
4830
- *
4831
- * getOID('2.16.840.1.101.3.4.2.1') == '2.16.840.1.101.3.4.2.1'
4832
- * getOID('id-sha256') == '2.16.840.1.101.3.4.2.1'
4833
- * getOID('zzz') == 'zzz'
4834
- *
4835
- * @access public
4836
- * @return string
4837
- */
4838
- function getOID($name)
4839
- {
4840
- static $reverseMap;
4841
- if (!isset($reverseMap)) {
4842
- $reverseMap = array_flip($this->oids);
4843
- }
4844
- return isset($reverseMap[$name]) ? $reverseMap[$name] : $name;
4845
- }
4846
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/phpseclib/phpseclib/phpseclib/Net/SCP.php DELETED
@@ -1,337 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Pure-PHP implementation of SCP.
5
- *
6
- * PHP version 5
7
- *
8
- * The API for this library is modeled after the API from PHP's {@link http://php.net/book.ftp FTP extension}.
9
- *
10
- * Here's a short example of how to use this library:
11
- * <code>
12
- * <?php
13
- * include 'vendor/autoload.php';
14
- *
15
- * $ssh = new \phpseclib\Net\SSH2('www.domain.tld');
16
- * if (!$ssh->login('username', 'password')) {
17
- * exit('bad login');
18
- * }
19
- * $scp = new \phpseclib\Net\SCP($ssh);
20
- *
21
- * $scp->put('abcd', str_repeat('x', 1024*1024));
22
- * ?>
23
- * </code>
24
- *
25
- * @category Net
26
- * @package SCP
27
- * @author Jim Wigginton <terrafrost@php.net>
28
- * @copyright 2010 Jim Wigginton
29
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
30
- * @link http://phpseclib.sourceforge.net
31
- */
32
-
33
- namespace phpseclib\Net;
34
-
35
- /**
36
- * Pure-PHP implementations of SCP.
37
- *
38
- * @package SCP
39
- * @author Jim Wigginton <terrafrost@php.net>
40
- * @access public
41
- */
42
- class SCP
43
- {
44
- /**#@+
45
- * @access public
46
- * @see \phpseclib\Net\SCP::put()
47
- */
48
- /**
49
- * Reads data from a local file.
50
- */
51
- const SOURCE_LOCAL_FILE = 1;
52
- /**
53
- * Reads data from a string.
54
- */
55
- const SOURCE_STRING = 2;
56
- /**#@-*/
57
-
58
- /**#@+
59
- * @access private
60
- * @see \phpseclib\Net\SCP::_send()
61
- * @see \phpseclib\Net\SCP::_receive()
62
- */
63
- /**
64
- * SSH1 is being used.
65
- */
66
- const MODE_SSH1 = 1;
67
- /**
68
- * SSH2 is being used.
69
- */
70
- const MODE_SSH2 = 2;
71
- /**#@-*/
72
-
73
- /**
74
- * SSH Object
75
- *
76
- * @var object
77
- * @access private
78
- */
79
- var $ssh;
80
-
81
- /**
82
- * Packet Size
83
- *
84
- * @var int
85
- * @access private
86
- */
87
- var $packet_size;
88
-
89
- /**
90
- * Mode
91
- *
92
- * @var int
93
- * @access private
94
- */
95
- var $mode;
96
-
97
- /**
98
- * Default Constructor.
99
- *
100
- * Connects to an SSH server
101
- *
102
- * @param \phpseclib\Net\SSH1|\phpseclib\Net\SSH2 $ssh
103
- * @return \phpseclib\Net\SCP
104
- * @access public
105
- */
106
- function __construct($ssh)
107
- {
108
- if ($ssh instanceof SSH2) {
109
- $this->mode = self::MODE_SSH2;
110
- } elseif ($ssh instanceof SSH1) {
111
- $this->packet_size = 50000;
112
- $this->mode = self::MODE_SSH1;
113
- } else {
114
- return;
115
- }
116
-
117
- $this->ssh = $ssh;
118
- }
119
-
120
- /**
121
- * Uploads a file to the SCP server.
122
- *
123
- * By default, \phpseclib\Net\SCP::put() does not read from the local filesystem. $data is dumped directly into $remote_file.
124
- * So, for example, if you set $data to 'filename.ext' and then do \phpseclib\Net\SCP::get(), you will get a file, twelve bytes
125
- * long, containing 'filename.ext' as its contents.
126
- *
127
- * Setting $mode to self::SOURCE_LOCAL_FILE will change the above behavior. With self::SOURCE_LOCAL_FILE, $remote_file will
128
- * contain as many bytes as filename.ext does on your local filesystem. If your filename.ext is 1MB then that is how
129
- * large $remote_file will be, as well.
130
- *
131
- * Currently, only binary mode is supported. As such, if the line endings need to be adjusted, you will need to take
132
- * care of that, yourself.
133
- *
134
- * @param string $remote_file
135
- * @param string $data
136
- * @param int $mode
137
- * @param callable $callback
138
- * @return bool
139
- * @access public
140
- */
141
- function put($remote_file, $data, $mode = self::SOURCE_STRING, $callback = null)
142
- {
143
- if (!isset($this->ssh)) {
144
- return false;
145
- }
146
-
147
- if (!$this->ssh->exec('scp -t ' . escapeshellarg($remote_file), false)) { // -t = to
148
- return false;
149
- }
150
-
151
- $temp = $this->_receive();
152
- if ($temp !== chr(0)) {
153
- return false;
154
- }
155
-
156
- if ($this->mode == self::MODE_SSH2) {
157
- $this->packet_size = $this->ssh->packet_size_client_to_server[SSH2::CHANNEL_EXEC] - 4;
158
- }
159
-
160
- $remote_file = basename($remote_file);
161
-
162
- if ($mode == self::SOURCE_STRING) {
163
- $size = strlen($data);
164
- } else {
165
- if (!is_file($data)) {
166
- user_error("$data is not a valid file", E_USER_NOTICE);
167
- return false;
168
- }
169
-
170
- $fp = @fopen($data, 'rb');
171
- if (!$fp) {
172
- return false;
173
- }
174
- $size = filesize($data);
175
- }
176
-
177
- $this->_send('C0644 ' . $size . ' ' . $remote_file . "\n");
178
-
179
- $temp = $this->_receive();
180
- if ($temp !== chr(0)) {
181
- return false;
182
- }
183
-
184
- $sent = 0;
185
- while ($sent < $size) {
186
- $temp = $mode & self::SOURCE_STRING ? substr($data, $sent, $this->packet_size) : fread($fp, $this->packet_size);
187
- $this->_send($temp);
188
- $sent+= strlen($temp);
189
-
190
- if (is_callable($callback)) {
191
- call_user_func($callback, $sent);
192
- }
193
- }
194
- $this->_close();
195
-
196
- if ($mode != self::SOURCE_STRING) {
197
- fclose($fp);
198
- }
199
-
200
- return true;
201
- }
202
-
203
- /**
204
- * Downloads a file from the SCP server.
205
- *
206
- * Returns a string containing the contents of $remote_file if $local_file is left undefined or a boolean false if
207
- * the operation was unsuccessful. If $local_file is defined, returns true or false depending on the success of the
208
- * operation
209
- *
210
- * @param string $remote_file
211
- * @param string $local_file
212
- * @return mixed
213
- * @access public
214
- */
215
- function get($remote_file, $local_file = false)
216
- {
217
- if (!isset($this->ssh)) {
218
- return false;
219
- }
220
-
221
- if (!$this->ssh->exec('scp -f ' . escapeshellarg($remote_file), false)) { // -f = from
222
- return false;
223
- }
224
-
225
- $this->_send("\0");
226
-
227
- if (!preg_match('#(?<perms>[^ ]+) (?<size>\d+) (?<name>.+)#', rtrim($this->_receive()), $info)) {
228
- return false;
229
- }
230
-
231
- $this->_send("\0");
232
-
233
- $size = 0;
234
-
235
- if ($local_file !== false) {
236
- $fp = @fopen($local_file, 'wb');
237
- if (!$fp) {
238
- return false;
239
- }
240
- }
241
-
242
- $content = '';
243
- while ($size < $info['size']) {
244
- $data = $this->_receive();
245
- // SCP usually seems to split stuff out into 16k chunks
246
- $size+= strlen($data);
247
-
248
- if ($local_file === false) {
249
- $content.= $data;
250
- } else {
251
- fputs($fp, $data);
252
- }
253
- }
254
-
255
- $this->_close();
256
-
257
- if ($local_file !== false) {
258
- fclose($fp);
259
- return true;
260
- }
261
-
262
- return $content;
263
- }
264
-
265
- /**
266
- * Sends a packet to an SSH server
267
- *
268
- * @param string $data
269
- * @access private
270
- */
271
- function _send($data)
272
- {
273
- switch ($this->mode) {
274
- case self::MODE_SSH2:
275
- $this->ssh->_send_channel_packet(SSH2::CHANNEL_EXEC, $data);
276
- break;
277
- case self::MODE_SSH1:
278
- $data = pack('CNa*', NET_SSH1_CMSG_STDIN_DATA, strlen($data), $data);
279
- $this->ssh->_send_binary_packet($data);
280
- }
281
- }
282
-
283
- /**
284
- * Receives a packet from an SSH server
285
- *
286
- * @return string
287
- * @access private
288
- */
289
- function _receive()
290
- {
291
- switch ($this->mode) {
292
- case self::MODE_SSH2:
293
- return $this->ssh->_get_channel_packet(SSH2::CHANNEL_EXEC, true);
294
- case self::MODE_SSH1:
295
- if (!$this->ssh->bitmap) {
296
- return false;
297
- }
298
- while (true) {
299
- $response = $this->ssh->_get_binary_packet();
300
- switch ($response[SSH1::RESPONSE_TYPE]) {
301
- case NET_SSH1_SMSG_STDOUT_DATA:
302
- if (strlen($response[SSH1::RESPONSE_DATA]) < 4) {
303
- return false;
304
- }
305
- extract(unpack('Nlength', $response[SSH1::RESPONSE_DATA]));
306
- return $this->ssh->_string_shift($response[SSH1::RESPONSE_DATA], $length);
307
- case NET_SSH1_SMSG_STDERR_DATA:
308
- break;
309
- case NET_SSH1_SMSG_EXITSTATUS:
310
- $this->ssh->_send_binary_packet(chr(NET_SSH1_CMSG_EXIT_CONFIRMATION));
311
- fclose($this->ssh->fsock);
312
- $this->ssh->bitmap = 0;
313
- return false;
314
- default:
315
- user_error('Unknown packet received', E_USER_NOTICE);
316
- return false;
317
- }
318
- }
319
- }
320
- }
321
-
322
- /**
323
- * Closes the connection to an SSH server
324
- *
325
- * @access private
326
- */
327
- function _close()
328
- {
329
- switch ($this->mode) {
330
- case self::MODE_SSH2:
331
- $this->ssh->_close_channel(SSH2::CHANNEL_EXEC, true);
332
- break;
333
- case self::MODE_SSH1:
334
- $this->ssh->disconnect();
335
- }
336
- }
337
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/phpseclib/phpseclib/phpseclib/Net/SFTP.php DELETED
@@ -1,3104 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Pure-PHP implementation of SFTP.
5
- *
6
- * PHP version 5
7
- *
8
- * Currently only supports SFTPv2 and v3, which, according to wikipedia.org, "is the most widely used version,
9
- * implemented by the popular OpenSSH SFTP server". If you want SFTPv4/5/6 support, provide me with access
10
- * to an SFTPv4/5/6 server.
11
- *
12
- * The API for this library is modeled after the API from PHP's {@link http://php.net/book.ftp FTP extension}.
13
- *
14
- * Here's a short example of how to use this library:
15
- * <code>
16
- * <?php
17
- * include 'vendor/autoload.php';
18
- *
19
- * $sftp = new \phpseclib\Net\SFTP('www.domain.tld');
20
- * if (!$sftp->login('username', 'password')) {
21
- * exit('Login Failed');
22
- * }
23
- *
24
- * echo $sftp->pwd() . "\r\n";
25
- * $sftp->put('filename.ext', 'hello, world!');
26
- * print_r($sftp->nlist());
27
- * ?>
28
- * </code>
29
- *
30
- * @category Net
31
- * @package SFTP
32
- * @author Jim Wigginton <terrafrost@php.net>
33
- * @copyright 2009 Jim Wigginton
34
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
35
- * @link http://phpseclib.sourceforge.net
36
- */
37
-
38
- namespace phpseclib\Net;
39
-
40
- /**
41
- * Pure-PHP implementations of SFTP.
42
- *
43
- * @package SFTP
44
- * @author Jim Wigginton <terrafrost@php.net>
45
- * @access public
46
- */
47
- class SFTP extends SSH2
48
- {
49
- /**
50
- * SFTP channel constant
51
- *
52
- * \phpseclib\Net\SSH2::exec() uses 0 and \phpseclib\Net\SSH2::read() / \phpseclib\Net\SSH2::write() use 1.
53
- *
54
- * @see \phpseclib\Net\SSH2::_send_channel_packet()
55
- * @see \phpseclib\Net\SSH2::_get_channel_packet()
56
- * @access private
57
- */
58
- const CHANNEL = 0x100;
59
-
60
- /**#@+
61
- * @access public
62
- * @see \phpseclib\Net\SFTP::put()
63
- */
64
- /**
65
- * Reads data from a local file.
66
- */
67
- const SOURCE_LOCAL_FILE = 1;
68
- /**
69
- * Reads data from a string.
70
- */
71
- // this value isn't really used anymore but i'm keeping it reserved for historical reasons
72
- const SOURCE_STRING = 2;
73
- /**
74
- * Reads data from callback:
75
- * function callback($length) returns string to proceed, null for EOF
76
- */
77
- const SOURCE_CALLBACK = 16;
78
- /**
79
- * Resumes an upload
80
- */
81
- const RESUME = 4;
82
- /**
83
- * Append a local file to an already existing remote file
84
- */
85
- const RESUME_START = 8;
86
- /**#@-*/
87
-
88
- /**
89
- * Packet Types
90
- *
91
- * @see self::__construct()
92
- * @var array
93
- * @access private
94
- */
95
- var $packet_types = array();
96
-
97
- /**
98
- * Status Codes
99
- *
100
- * @see self::__construct()
101
- * @var array
102
- * @access private
103
- */
104
- var $status_codes = array();
105
-
106
- /**
107
- * The Request ID
108
- *
109
- * The request ID exists in the off chance that a packet is sent out-of-order. Of course, this library doesn't support
110
- * concurrent actions, so it's somewhat academic, here.
111
- *
112
- * @var int
113
- * @see self::_send_sftp_packet()
114
- * @access private
115
- */
116
- var $request_id = false;
117
-
118
- /**
119
- * The Packet Type
120
- *
121
- * The request ID exists in the off chance that a packet is sent out-of-order. Of course, this library doesn't support
122
- * concurrent actions, so it's somewhat academic, here.
123
- *
124
- * @var int
125
- * @see self::_get_sftp_packet()
126
- * @access private
127
- */
128
- var $packet_type = -1;
129
-
130
- /**
131
- * Packet Buffer
132
- *
133
- * @var string
134
- * @see self::_get_sftp_packet()
135
- * @access private
136
- */
137
- var $packet_buffer = '';
138
-
139
- /**
140
- * Extensions supported by the server
141
- *
142
- * @var array
143
- * @see self::_initChannel()
144
- * @access private
145
- */
146
- var $extensions = array();
147
-
148
- /**
149
- * Server SFTP version
150
- *
151
- * @var int
152
- * @see self::_initChannel()
153
- * @access private
154
- */
155
- var $version;
156
-
157
- /**
158
- * Current working directory
159
- *
160
- * @var string
161
- * @see self::realpath()
162
- * @see self::chdir()
163
- * @access private
164
- */
165
- var $pwd = false;
166
-
167
- /**
168
- * Packet Type Log
169
- *
170
- * @see self::getLog()
171
- * @var array
172
- * @access private
173
- */
174
- var $packet_type_log = array();
175
-
176
- /**
177
- * Packet Log
178
- *
179
- * @see self::getLog()
180
- * @var array
181
- * @access private
182
- */
183
- var $packet_log = array();
184
-
185
- /**
186
- * Error information
187
- *
188
- * @see self::getSFTPErrors()
189
- * @see self::getLastSFTPError()
190
- * @var array
191
- * @access private
192
- */
193
- var $sftp_errors = array();
194
-
195
- /**
196
- * Stat Cache
197
- *
198
- * Rather than always having to open a directory and close it immediately there after to see if a file is a directory
199
- * we'll cache the results.
200
- *
201
- * @see self::_update_stat_cache()
202
- * @see self::_remove_from_stat_cache()
203
- * @see self::_query_stat_cache()
204
- * @var array
205
- * @access private
206
- */
207
- var $stat_cache = array();
208
-
209
- /**
210
- * Max SFTP Packet Size
211
- *
212
- * @see self::__construct()
213
- * @see self::get()
214
- * @var array
215
- * @access private
216
- */
217
- var $max_sftp_packet;
218
-
219
- /**
220
- * Stat Cache Flag
221
- *
222
- * @see self::disableStatCache()
223
- * @see self::enableStatCache()
224
- * @var bool
225
- * @access private
226
- */
227
- var $use_stat_cache = true;
228
-
229
- /**
230
- * Sort Options
231
- *
232
- * @see self::_comparator()
233
- * @see self::setListOrder()
234
- * @var array
235
- * @access private
236
- */
237
- var $sortOptions = array();
238
-
239
- /**
240
- * Canonicalization Flag
241
- *
242
- * Determines whether or not paths should be canonicalized before being
243
- * passed on to the remote server.
244
- *
245
- * @see self::enablePathCanonicalization()
246
- * @see self::disablePathCanonicalization()
247
- * @see self::realpath()
248
- * @var bool
249
- * @access private
250
- */
251
- var $canonicalize_paths = true;
252
-
253
- /**
254
- * Default Constructor.
255
- *
256
- * Connects to an SFTP server
257
- *
258
- * @param string $host
259
- * @param int $port
260
- * @param int $timeout
261
- * @return \phpseclib\Net\SFTP
262
- * @access public
263
- */
264
- function __construct($host, $port = 22, $timeout = 10)
265
- {
266
- parent::__construct($host, $port, $timeout);
267
-
268
- $this->max_sftp_packet = 1 << 15;
269
-
270
- $this->packet_types = array(
271
- 1 => 'NET_SFTP_INIT',
272
- 2 => 'NET_SFTP_VERSION',
273
- /* the format of SSH_FXP_OPEN changed between SFTPv4 and SFTPv5+:
274
- SFTPv5+: http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.1.1
275
- pre-SFTPv5 : http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-6.3 */
276
- 3 => 'NET_SFTP_OPEN',
277
- 4 => 'NET_SFTP_CLOSE',
278
- 5 => 'NET_SFTP_READ',
279
- 6 => 'NET_SFTP_WRITE',
280
- 7 => 'NET_SFTP_LSTAT',
281
- 9 => 'NET_SFTP_SETSTAT',
282
- 11 => 'NET_SFTP_OPENDIR',
283
- 12 => 'NET_SFTP_READDIR',
284
- 13 => 'NET_SFTP_REMOVE',
285
- 14 => 'NET_SFTP_MKDIR',
286
- 15 => 'NET_SFTP_RMDIR',
287
- 16 => 'NET_SFTP_REALPATH',
288
- 17 => 'NET_SFTP_STAT',
289
- /* the format of SSH_FXP_RENAME changed between SFTPv4 and SFTPv5+:
290
- SFTPv5+: http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.3
291
- pre-SFTPv5 : http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-6.5 */
292
- 18 => 'NET_SFTP_RENAME',
293
- 19 => 'NET_SFTP_READLINK',
294
- 20 => 'NET_SFTP_SYMLINK',
295
-
296
- 101=> 'NET_SFTP_STATUS',
297
- 102=> 'NET_SFTP_HANDLE',
298
- /* the format of SSH_FXP_NAME changed between SFTPv3 and SFTPv4+:
299
- SFTPv4+: http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-9.4
300
- pre-SFTPv4 : http://tools.ietf.org/html/draft-ietf-secsh-filexfer-02#section-7 */
301
- 103=> 'NET_SFTP_DATA',
302
- 104=> 'NET_SFTP_NAME',
303
- 105=> 'NET_SFTP_ATTRS',
304
-
305
- 200=> 'NET_SFTP_EXTENDED'
306
- );
307
- $this->status_codes = array(
308
- 0 => 'NET_SFTP_STATUS_OK',
309
- 1 => 'NET_SFTP_STATUS_EOF',
310
- 2 => 'NET_SFTP_STATUS_NO_SUCH_FILE',
311
- 3 => 'NET_SFTP_STATUS_PERMISSION_DENIED',
312
- 4 => 'NET_SFTP_STATUS_FAILURE',
313
- 5 => 'NET_SFTP_STATUS_BAD_MESSAGE',
314
- 6 => 'NET_SFTP_STATUS_NO_CONNECTION',
315
- 7 => 'NET_SFTP_STATUS_CONNECTION_LOST',
316
- 8 => 'NET_SFTP_STATUS_OP_UNSUPPORTED',
317
- 9 => 'NET_SFTP_STATUS_INVALID_HANDLE',
318
- 10 => 'NET_SFTP_STATUS_NO_SUCH_PATH',
319
- 11 => 'NET_SFTP_STATUS_FILE_ALREADY_EXISTS',
320
- 12 => 'NET_SFTP_STATUS_WRITE_PROTECT',
321
- 13 => 'NET_SFTP_STATUS_NO_MEDIA',
322
- 14 => 'NET_SFTP_STATUS_NO_SPACE_ON_FILESYSTEM',
323
- 15 => 'NET_SFTP_STATUS_QUOTA_EXCEEDED',
324
- 16 => 'NET_SFTP_STATUS_UNKNOWN_PRINCIPAL',
325
- 17 => 'NET_SFTP_STATUS_LOCK_CONFLICT',
326
- 18 => 'NET_SFTP_STATUS_DIR_NOT_EMPTY',
327
- 19 => 'NET_SFTP_STATUS_NOT_A_DIRECTORY',
328
- 20 => 'NET_SFTP_STATUS_INVALID_FILENAME',
329
- 21 => 'NET_SFTP_STATUS_LINK_LOOP',
330
- 22 => 'NET_SFTP_STATUS_CANNOT_DELETE',
331
- 23 => 'NET_SFTP_STATUS_INVALID_PARAMETER',
332
- 24 => 'NET_SFTP_STATUS_FILE_IS_A_DIRECTORY',
333
- 25 => 'NET_SFTP_STATUS_BYTE_RANGE_LOCK_CONFLICT',
334
- 26 => 'NET_SFTP_STATUS_BYTE_RANGE_LOCK_REFUSED',
335
- 27 => 'NET_SFTP_STATUS_DELETE_PENDING',
336
- 28 => 'NET_SFTP_STATUS_FILE_CORRUPT',
337
- 29 => 'NET_SFTP_STATUS_OWNER_INVALID',
338
- 30 => 'NET_SFTP_STATUS_GROUP_INVALID',
339
- 31 => 'NET_SFTP_STATUS_NO_MATCHING_BYTE_RANGE_LOCK'
340
- );
341
- // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-7.1
342
- // the order, in this case, matters quite a lot - see \phpseclib\Net\SFTP::_parseAttributes() to understand why
343
- $this->attributes = array(
344
- 0x00000001 => 'NET_SFTP_ATTR_SIZE',
345
- 0x00000002 => 'NET_SFTP_ATTR_UIDGID', // defined in SFTPv3, removed in SFTPv4+
346
- 0x00000004 => 'NET_SFTP_ATTR_PERMISSIONS',
347
- 0x00000008 => 'NET_SFTP_ATTR_ACCESSTIME',
348
- // 0x80000000 will yield a floating point on 32-bit systems and converting floating points to integers
349
- // yields inconsistent behavior depending on how php is compiled. so we left shift -1 (which, in
350
- // two's compliment, consists of all 1 bits) by 31. on 64-bit systems this'll yield 0xFFFFFFFF80000000.
351
- // that's not a problem, however, and 'anded' and a 32-bit number, as all the leading 1 bits are ignored.
352
- -1 << 31 => 'NET_SFTP_ATTR_EXTENDED'
353
- );
354
- // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-6.3
355
- // the flag definitions change somewhat in SFTPv5+. if SFTPv5+ support is added to this library, maybe name
356
- // the array for that $this->open5_flags and similarly alter the constant names.
357
- $this->open_flags = array(
358
- 0x00000001 => 'NET_SFTP_OPEN_READ',
359
- 0x00000002 => 'NET_SFTP_OPEN_WRITE',
360
- 0x00000004 => 'NET_SFTP_OPEN_APPEND',
361
- 0x00000008 => 'NET_SFTP_OPEN_CREATE',
362
- 0x00000010 => 'NET_SFTP_OPEN_TRUNCATE',
363
- 0x00000020 => 'NET_SFTP_OPEN_EXCL'
364
- );
365
- // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-5.2
366
- // see \phpseclib\Net\SFTP::_parseLongname() for an explanation
367
- $this->file_types = array(
368
- 1 => 'NET_SFTP_TYPE_REGULAR',
369
- 2 => 'NET_SFTP_TYPE_DIRECTORY',
370
- 3 => 'NET_SFTP_TYPE_SYMLINK',
371
- 4 => 'NET_SFTP_TYPE_SPECIAL',
372
- 5 => 'NET_SFTP_TYPE_UNKNOWN',
373
- // the followin types were first defined for use in SFTPv5+
374
- // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-05#section-5.2
375
- 6 => 'NET_SFTP_TYPE_SOCKET',
376
- 7 => 'NET_SFTP_TYPE_CHAR_DEVICE',
377
- 8 => 'NET_SFTP_TYPE_BLOCK_DEVICE',
378
- 9 => 'NET_SFTP_TYPE_FIFO'
379
- );
380
- $this->_define_array(
381
- $this->packet_types,
382
- $this->status_codes,
383
- $this->attributes,
384
- $this->open_flags,
385
- $this->file_types
386
- );
387
-
388
- if (!defined('NET_SFTP_QUEUE_SIZE')) {
389
- define('NET_SFTP_QUEUE_SIZE', 32);
390
- }
391
- }
392
-
393
- /**
394
- * Login
395
- *
396
- * @param string $username
397
- * @param string $password
398
- * @return bool
399
- * @access public
400
- */
401
- function login($username)
402
- {
403
- $args = func_get_args();
404
- if (!call_user_func_array(array(&$this, '_login'), $args)) {
405
- return false;
406
- }
407
-
408
- $this->window_size_server_to_client[self::CHANNEL] = $this->window_size;
409
-
410
- $packet = pack(
411
- 'CNa*N3',
412
- NET_SSH2_MSG_CHANNEL_OPEN,
413
- strlen('session'),
414
- 'session',
415
- self::CHANNEL,
416
- $this->window_size,
417
- 0x4000
418
- );
419
-
420
- if (!$this->_send_binary_packet($packet)) {
421
- return false;
422
- }
423
-
424
- $this->channel_status[self::CHANNEL] = NET_SSH2_MSG_CHANNEL_OPEN;
425
-
426
- $response = $this->_get_channel_packet(self::CHANNEL, true);
427
- if ($response === false) {
428
- return false;
429
- }
430
-
431
- $packet = pack(
432
- 'CNNa*CNa*',
433
- NET_SSH2_MSG_CHANNEL_REQUEST,
434
- $this->server_channels[self::CHANNEL],
435
- strlen('subsystem'),
436
- 'subsystem',
437
- 1,
438
- strlen('sftp'),
439
- 'sftp'
440
- );
441
- if (!$this->_send_binary_packet($packet)) {
442
- return false;
443
- }
444
-
445
- $this->channel_status[self::CHANNEL] = NET_SSH2_MSG_CHANNEL_REQUEST;
446
-
447
- $response = $this->_get_channel_packet(self::CHANNEL, true);
448
- if ($response === false) {
449
- // from PuTTY's psftp.exe
450
- $command = "test -x /usr/lib/sftp-server && exec /usr/lib/sftp-server\n" .
451
- "test -x /usr/local/lib/sftp-server && exec /usr/local/lib/sftp-server\n" .
452
- "exec sftp-server";
453
- // we don't do $this->exec($command, false) because exec() operates on a different channel and plus the SSH_MSG_CHANNEL_OPEN that exec() does
454
- // is redundant
455
- $packet = pack(
456
- 'CNNa*CNa*',
457
- NET_SSH2_MSG_CHANNEL_REQUEST,
458
- $this->server_channels[self::CHANNEL],
459
- strlen('exec'),
460
- 'exec',
461
- 1,
462
- strlen($command),
463
- $command
464
- );
465
- if (!$this->_send_binary_packet($packet)) {
466
- return false;
467
- }
468
-
469
- $this->channel_status[self::CHANNEL] = NET_SSH2_MSG_CHANNEL_REQUEST;
470
-
471
- $response = $this->_get_channel_packet(self::CHANNEL, true);
472
- if ($response === false) {
473
- return false;
474
- }
475
- }
476
-
477
- $this->channel_status[self::CHANNEL] = NET_SSH2_MSG_CHANNEL_DATA;
478
-
479
- if (!$this->_send_sftp_packet(NET_SFTP_INIT, "\0\0\0\3")) {
480
- return false;
481
- }
482
-
483
- $response = $this->_get_sftp_packet();
484
- if ($this->packet_type != NET_SFTP_VERSION) {
485
- user_error('Expected SSH_FXP_VERSION');
486
- return false;
487
- }
488
-
489
- if (strlen($response) < 4) {
490
- return false;
491
- }
492
- extract(unpack('Nversion', $this->_string_shift($response, 4)));
493
- $this->version = $version;
494
- while (!empty($response)) {
495
- if (strlen($response) < 4) {
496
- return false;
497
- }
498
- extract(unpack('Nlength', $this->_string_shift($response, 4)));
499
- $key = $this->_string_shift($response, $length);
500
- if (strlen($response) < 4) {
501
- return false;
502
- }
503
- extract(unpack('Nlength', $this->_string_shift($response, 4)));
504
- $value = $this->_string_shift($response, $length);
505
- $this->extensions[$key] = $value;
506
- }
507
-
508
- /*
509
- SFTPv4+ defines a 'newline' extension. SFTPv3 seems to have unofficial support for it via 'newline@vandyke.com',
510
- however, I'm not sure what 'newline@vandyke.com' is supposed to do (the fact that it's unofficial means that it's
511
- not in the official SFTPv3 specs) and 'newline@vandyke.com' / 'newline' are likely not drop-in substitutes for
512
- one another due to the fact that 'newline' comes with a SSH_FXF_TEXT bitmask whereas it seems unlikely that
513
- 'newline@vandyke.com' would.
514
- */
515
- /*
516
- if (isset($this->extensions['newline@vandyke.com'])) {
517
- $this->extensions['newline'] = $this->extensions['newline@vandyke.com'];
518
- unset($this->extensions['newline@vandyke.com']);
519
- }
520
- */
521
-
522
- $this->request_id = 1;
523
-
524
- /*
525
- A Note on SFTPv4/5/6 support:
526
- <http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-5.1> states the following:
527
-
528
- "If the client wishes to interoperate with servers that support noncontiguous version
529
- numbers it SHOULD send '3'"
530
-
531
- Given that the server only sends its version number after the client has already done so, the above
532
- seems to be suggesting that v3 should be the default version. This makes sense given that v3 is the
533
- most popular.
534
-
535
- <http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-5.5> states the following;
536
-
537
- "If the server did not send the "versions" extension, or the version-from-list was not included, the
538
- server MAY send a status response describing the failure, but MUST then close the channel without
539
- processing any further requests."
540
-
541
- So what do you do if you have a client whose initial SSH_FXP_INIT packet says it implements v3 and
542
- a server whose initial SSH_FXP_VERSION reply says it implements v4 and only v4? If it only implements
543
- v4, the "versions" extension is likely not going to have been sent so version re-negotiation as discussed
544
- in draft-ietf-secsh-filexfer-13 would be quite impossible. As such, what \phpseclib\Net\SFTP would do is close the
545
- channel and reopen it with a new and updated SSH_FXP_INIT packet.
546
- */
547
- switch ($this->version) {
548
- case 2:
549
- case 3:
550
- break;
551
- default:
552
- return false;
553
- }
554
-
555
- $this->pwd = $this->_realpath('.');
556
-
557
- $this->_update_stat_cache($this->pwd, array());
558
-
559
- return true;
560
- }
561
-
562
- /**
563
- * Disable the stat cache
564
- *
565
- * @access public
566
- */
567
- function disableStatCache()
568
- {
569
- $this->use_stat_cache = false;
570
- }
571
-
572
- /**
573
- * Enable the stat cache
574
- *
575
- * @access public
576
- */
577
- function enableStatCache()
578
- {
579
- $this->use_stat_cache = true;
580
- }
581
-
582
- /**
583
- * Clear the stat cache
584
- *
585
- * @access public
586
- */
587
- function clearStatCache()
588
- {
589
- $this->stat_cache = array();
590
- }
591
-
592
- /**
593
- * Enable path canonicalization
594
- *
595
- * @access public
596
- */
597
- function enablePathCanonicalization()
598
- {
599
- $this->canonicalize_paths = true;
600
- }
601
-
602
- /**
603
- * Enable path canonicalization
604
- *
605
- * @access public
606
- */
607
- function disablePathCanonicalization()
608
- {
609
- $this->canonicalize_paths = false;
610
- }
611
-
612
- /**
613
- * Returns the current directory name
614
- *
615
- * @return mixed
616
- * @access public
617
- */
618
- function pwd()
619
- {
620
- return $this->pwd;
621
- }
622
-
623
- /**
624
- * Logs errors
625
- *
626
- * @param string $response
627
- * @param int $status
628
- * @access public
629
- */
630
- function _logError($response, $status = -1)
631
- {
632
- if ($status == -1) {
633
- if (strlen($response) < 4) {
634
- return;
635
- }
636
- extract(unpack('Nstatus', $this->_string_shift($response, 4)));
637
- }
638
-
639
- $error = $this->status_codes[$status];
640
-
641
- if ($this->version > 2 || strlen($response) < 4) {
642
- extract(unpack('Nlength', $this->_string_shift($response, 4)));
643
- $this->sftp_errors[] = $error . ': ' . $this->_string_shift($response, $length);
644
- } else {
645
- $this->sftp_errors[] = $error;
646
- }
647
- }
648
-
649
- /**
650
- * Returns canonicalized absolute pathname
651
- *
652
- * realpath() expands all symbolic links and resolves references to '/./', '/../' and extra '/' characters in the input
653
- * path and returns the canonicalized absolute pathname.
654
- *
655
- * @param string $path
656
- * @return mixed
657
- * @access public
658
- */
659
- function realpath($path)
660
- {
661
- return $this->_realpath($path);
662
- }
663
-
664
- /**
665
- * Canonicalize the Server-Side Path Name
666
- *
667
- * SFTP doesn't provide a mechanism by which the current working directory can be changed, so we'll emulate it. Returns
668
- * the absolute (canonicalized) path.
669
- *
670
- * If canonicalize_paths has been disabled using disablePathCanonicalization(), $path is returned as-is.
671
- *
672
- * @see self::chdir()
673
- * @see self::disablePathCanonicalization()
674
- * @param string $path
675
- * @return mixed
676
- * @access private
677
- */
678
- function _realpath($path)
679
- {
680
- if (!$this->canonicalize_paths) {
681
- return $path;
682
- }
683
-
684
- if ($this->pwd === false) {
685
- // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.9
686
- if (!$this->_send_sftp_packet(NET_SFTP_REALPATH, pack('Na*', strlen($path), $path))) {
687
- return false;
688
- }
689
-
690
- $response = $this->_get_sftp_packet();
691
- switch ($this->packet_type) {
692
- case NET_SFTP_NAME:
693
- // although SSH_FXP_NAME is implemented differently in SFTPv3 than it is in SFTPv4+, the following
694
- // should work on all SFTP versions since the only part of the SSH_FXP_NAME packet the following looks
695
- // at is the first part and that part is defined the same in SFTP versions 3 through 6.
696
- $this->_string_shift($response, 4); // skip over the count - it should be 1, anyway
697
- if (strlen($response) < 4) {
698
- return false;
699
- }
700
- extract(unpack('Nlength', $this->_string_shift($response, 4)));
701
- return $this->_string_shift($response, $length);
702
- case NET_SFTP_STATUS:
703
- $this->_logError($response);
704
- return false;
705
- default:
706
- user_error('Expected SSH_FXP_NAME or SSH_FXP_STATUS');
707
- return false;
708
- }
709
- }
710
-
711
- if ($path[0] != '/') {
712
- $path = $this->pwd . '/' . $path;
713
- }
714
-
715
- $path = explode('/', $path);
716
- $new = array();
717
- foreach ($path as $dir) {
718
- if (!strlen($dir)) {
719
- continue;
720
- }
721
- switch ($dir) {
722
- case '..':
723
- array_pop($new);
724
- case '.':
725
- break;
726
- default:
727
- $new[] = $dir;
728
- }
729
- }
730
-
731
- return '/' . implode('/', $new);
732
- }
733
-
734
- /**
735
- * Changes the current directory
736
- *
737
- * @param string $dir
738
- * @return bool
739
- * @access public
740
- */
741
- function chdir($dir)
742
- {
743
- if (!($this->bitmap & SSH2::MASK_LOGIN)) {
744
- return false;
745
- }
746
-
747
- // assume current dir if $dir is empty
748
- if ($dir === '') {
749
- $dir = './';
750
- // suffix a slash if needed
751
- } elseif ($dir[strlen($dir) - 1] != '/') {
752
- $dir.= '/';
753
- }
754
-
755
- $dir = $this->_realpath($dir);
756
-
757
- // confirm that $dir is, in fact, a valid directory
758
- if ($this->use_stat_cache && is_array($this->_query_stat_cache($dir))) {
759
- $this->pwd = $dir;
760
- return true;
761
- }
762
-
763
- // we could do a stat on the alleged $dir to see if it's a directory but that doesn't tell us
764
- // the currently logged in user has the appropriate permissions or not. maybe you could see if
765
- // the file's uid / gid match the currently logged in user's uid / gid but how there's no easy
766
- // way to get those with SFTP
767
-
768
- if (!$this->_send_sftp_packet(NET_SFTP_OPENDIR, pack('Na*', strlen($dir), $dir))) {
769
- return false;
770
- }
771
-
772
- // see \phpseclib\Net\SFTP::nlist() for a more thorough explanation of the following
773
- $response = $this->_get_sftp_packet();
774
- switch ($this->packet_type) {
775
- case NET_SFTP_HANDLE:
776
- $handle = substr($response, 4);
777
- break;
778
- case NET_SFTP_STATUS:
779
- $this->_logError($response);
780
- return false;
781
- default:
782
- user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
783
- return false;
784
- }
785
-
786
- if (!$this->_close_handle($handle)) {
787
- return false;
788
- }
789
-
790
- $this->_update_stat_cache($dir, array());
791
-
792
- $this->pwd = $dir;
793
- return true;
794
- }
795
-
796
- /**
797
- * Returns a list of files in the given directory
798
- *
799
- * @param string $dir
800
- * @param bool $recursive
801
- * @return mixed
802
- * @access public
803
- */
804
- function nlist($dir = '.', $recursive = false)
805
- {
806
- return $this->_nlist_helper($dir, $recursive, '');
807
- }
808
-
809
- /**
810
- * Helper method for nlist
811
- *
812
- * @param string $dir
813
- * @param bool $recursive
814
- * @param string $relativeDir
815
- * @return mixed
816
- * @access private
817
- */
818
- function _nlist_helper($dir, $recursive, $relativeDir)
819
- {
820
- $files = $this->_list($dir, false);
821
-
822
- if (!$recursive || $files === false) {
823
- return $files;
824
- }
825
-
826
- $result = array();
827
- foreach ($files as $value) {
828
- if ($value == '.' || $value == '..') {
829
- if ($relativeDir == '') {
830
- $result[] = $value;
831
- }
832
- continue;
833
- }
834
- if (is_array($this->_query_stat_cache($this->_realpath($dir . '/' . $value)))) {
835
- $temp = $this->_nlist_helper($dir . '/' . $value, true, $relativeDir . $value . '/');
836
- $result = array_merge($result, $temp);
837
- } else {
838
- $result[] = $relativeDir . $value;
839
- }
840
- }
841
-
842
- return $result;
843
- }
844
-
845
- /**
846
- * Returns a detailed list of files in the given directory
847
- *
848
- * @param string $dir
849
- * @param bool $recursive
850
- * @return mixed
851
- * @access public
852
- */
853
- function rawlist($dir = '.', $recursive = false)
854
- {
855
- $files = $this->_list($dir, true);
856
- if (!$recursive || $files === false) {
857
- return $files;
858
- }
859
-
860
- static $depth = 0;
861
-
862
- foreach ($files as $key => $value) {
863
- if ($depth != 0 && $key == '..') {
864
- unset($files[$key]);
865
- continue;
866
- }
867
- if ($key != '.' && $key != '..' && is_array($this->_query_stat_cache($this->_realpath($dir . '/' . $key)))) {
868
- $depth++;
869
- $files[$key] = $this->rawlist($dir . '/' . $key, true);
870
- $depth--;
871
- } else {
872
- $files[$key] = (object) $value;
873
- }
874
- }
875
-
876
- return $files;
877
- }
878
-
879
- /**
880
- * Reads a list, be it detailed or not, of files in the given directory
881
- *
882
- * @param string $dir
883
- * @param bool $raw
884
- * @return mixed
885
- * @access private
886
- */
887
- function _list($dir, $raw = true)
888
- {
889
- if (!($this->bitmap & SSH2::MASK_LOGIN)) {
890
- return false;
891
- }
892
-
893
- $dir = $this->_realpath($dir . '/');
894
- if ($dir === false) {
895
- return false;
896
- }
897
-
898
- // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.1.2
899
- if (!$this->_send_sftp_packet(NET_SFTP_OPENDIR, pack('Na*', strlen($dir), $dir))) {
900
- return false;
901
- }
902
-
903
- $response = $this->_get_sftp_packet();
904
- switch ($this->packet_type) {
905
- case NET_SFTP_HANDLE:
906
- // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-9.2
907
- // since 'handle' is the last field in the SSH_FXP_HANDLE packet, we'll just remove the first four bytes that
908
- // represent the length of the string and leave it at that
909
- $handle = substr($response, 4);
910
- break;
911
- case NET_SFTP_STATUS:
912
- // presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
913
- $this->_logError($response);
914
- return false;
915
- default:
916
- user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
917
- return false;
918
- }
919
-
920
- $this->_update_stat_cache($dir, array());
921
-
922
- $contents = array();
923
- while (true) {
924
- // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.2.2
925
- // why multiple SSH_FXP_READDIR packets would be sent when the response to a single one can span arbitrarily many
926
- // SSH_MSG_CHANNEL_DATA messages is not known to me.
927
- if (!$this->_send_sftp_packet(NET_SFTP_READDIR, pack('Na*', strlen($handle), $handle))) {
928
- return false;
929
- }
930
-
931
- $response = $this->_get_sftp_packet();
932
- switch ($this->packet_type) {
933
- case NET_SFTP_NAME:
934
- if (strlen($response) < 4) {
935
- return false;
936
- }
937
- extract(unpack('Ncount', $this->_string_shift($response, 4)));
938
- for ($i = 0; $i < $count; $i++) {
939
- if (strlen($response) < 4) {
940
- return false;
941
- }
942
- extract(unpack('Nlength', $this->_string_shift($response, 4)));
943
- $shortname = $this->_string_shift($response, $length);
944
- if (strlen($response) < 4) {
945
- return false;
946
- }
947
- extract(unpack('Nlength', $this->_string_shift($response, 4)));
948
- $longname = $this->_string_shift($response, $length);
949
- $attributes = $this->_parseAttributes($response);
950
- if (!isset($attributes['type'])) {
951
- $fileType = $this->_parseLongname($longname);
952
- if ($fileType) {
953
- $attributes['type'] = $fileType;
954
- }
955
- }
956
- $contents[$shortname] = $attributes + array('filename' => $shortname);
957
-
958
- if (isset($attributes['type']) && $attributes['type'] == NET_SFTP_TYPE_DIRECTORY && ($shortname != '.' && $shortname != '..')) {
959
- $this->_update_stat_cache($dir . '/' . $shortname, array());
960
- } else {
961
- if ($shortname == '..') {
962
- $temp = $this->_realpath($dir . '/..') . '/.';
963
- } else {
964
- $temp = $dir . '/' . $shortname;
965
- }
966
- $this->_update_stat_cache($temp, (object) array('lstat' => $attributes));
967
- }
968
- // SFTPv6 has an optional boolean end-of-list field, but we'll ignore that, since the
969
- // final SSH_FXP_STATUS packet should tell us that, already.
970
- }
971
- break;
972
- case NET_SFTP_STATUS:
973
- if (strlen($response) < 4) {
974
- return false;
975
- }
976
- extract(unpack('Nstatus', $this->_string_shift($response, 4)));
977
- if ($status != NET_SFTP_STATUS_EOF) {
978
- $this->_logError($response, $status);
979
- return false;
980
- }
981
- break 2;
982
- default:
983
- user_error('Expected SSH_FXP_NAME or SSH_FXP_STATUS');
984
- return false;
985
- }
986
- }
987
-
988
- if (!$this->_close_handle($handle)) {
989
- return false;
990
- }
991
-
992
- if (count($this->sortOptions)) {
993
- uasort($contents, array(&$this, '_comparator'));
994
- }
995
-
996
- return $raw ? $contents : array_keys($contents);
997
- }
998
-
999
- /**
1000
- * Compares two rawlist entries using parameters set by setListOrder()
1001
- *
1002
- * Intended for use with uasort()
1003
- *
1004
- * @param array $a
1005
- * @param array $b
1006
- * @return int
1007
- * @access private
1008
- */
1009
- function _comparator($a, $b)
1010
- {
1011
- switch (true) {
1012
- case $a['filename'] === '.' || $b['filename'] === '.':
1013
- if ($a['filename'] === $b['filename']) {
1014
- return 0;
1015
- }
1016
- return $a['filename'] === '.' ? -1 : 1;
1017
- case $a['filename'] === '..' || $b['filename'] === '..':
1018
- if ($a['filename'] === $b['filename']) {
1019
- return 0;
1020
- }
1021
- return $a['filename'] === '..' ? -1 : 1;
1022
- case isset($a['type']) && $a['type'] === NET_SFTP_TYPE_DIRECTORY:
1023
- if (!isset($b['type'])) {
1024
- return 1;
1025
- }
1026
- if ($b['type'] !== $a['type']) {
1027
- return -1;
1028
- }
1029
- break;
1030
- case isset($b['type']) && $b['type'] === NET_SFTP_TYPE_DIRECTORY:
1031
- return 1;
1032
- }
1033
- foreach ($this->sortOptions as $sort => $order) {
1034
- if (!isset($a[$sort]) || !isset($b[$sort])) {
1035
- if (isset($a[$sort])) {
1036
- return -1;
1037
- }
1038
- if (isset($b[$sort])) {
1039
- return 1;
1040
- }
1041
- return 0;
1042
- }
1043
- switch ($sort) {
1044
- case 'filename':
1045
- $result = strcasecmp($a['filename'], $b['filename']);
1046
- if ($result) {
1047
- return $order === SORT_DESC ? -$result : $result;
1048
- }
1049
- break;
1050
- case 'permissions':
1051
- case 'mode':
1052
- $a[$sort]&= 07777;
1053
- $b[$sort]&= 07777;
1054
- default:
1055
- if ($a[$sort] === $b[$sort]) {
1056
- break;
1057
- }
1058
- return $order === SORT_ASC ? $a[$sort] - $b[$sort] : $b[$sort] - $a[$sort];
1059
- }
1060
- }
1061
- }
1062
-
1063
- /**
1064
- * Defines how nlist() and rawlist() will be sorted - if at all.
1065
- *
1066
- * If sorting is enabled directories and files will be sorted independently with
1067
- * directories appearing before files in the resultant array that is returned.
1068
- *
1069
- * Any parameter returned by stat is a valid sort parameter for this function.
1070
- * Filename comparisons are case insensitive.
1071
- *
1072
- * Examples:
1073
- *
1074
- * $sftp->setListOrder('filename', SORT_ASC);
1075
- * $sftp->setListOrder('size', SORT_DESC, 'filename', SORT_ASC);
1076
- * $sftp->setListOrder(true);
1077
- * Separates directories from files but doesn't do any sorting beyond that
1078
- * $sftp->setListOrder();
1079
- * Don't do any sort of sorting
1080
- *
1081
- * @access public
1082
- */
1083
- function setListOrder()
1084
- {
1085
- $this->sortOptions = array();
1086
- $args = func_get_args();
1087
- if (empty($args)) {
1088
- return;
1089
- }
1090
- $len = count($args) & 0x7FFFFFFE;
1091
- for ($i = 0; $i < $len; $i+=2) {
1092
- $this->sortOptions[$args[$i]] = $args[$i + 1];
1093
- }
1094
- if (!count($this->sortOptions)) {
1095
- $this->sortOptions = array('bogus' => true);
1096
- }
1097
- }
1098
-
1099
- /**
1100
- * Returns the file size, in bytes, or false, on failure
1101
- *
1102
- * Files larger than 4GB will show up as being exactly 4GB.
1103
- *
1104
- * @param string $filename
1105
- * @return mixed
1106
- * @access public
1107
- */
1108
- function size($filename)
1109
- {
1110
- if (!($this->bitmap & SSH2::MASK_LOGIN)) {
1111
- return false;
1112
- }
1113
-
1114
- $result = $this->stat($filename);
1115
- if ($result === false) {
1116
- return false;
1117
- }
1118
- return isset($result['size']) ? $result['size'] : -1;
1119
- }
1120
-
1121
- /**
1122
- * Save files / directories to cache
1123
- *
1124
- * @param string $path
1125
- * @param mixed $value
1126
- * @access private
1127
- */
1128
- function _update_stat_cache($path, $value)
1129
- {
1130
- if ($this->use_stat_cache === false) {
1131
- return;
1132
- }
1133
-
1134
- // preg_replace('#^/|/(?=/)|/$#', '', $dir) == str_replace('//', '/', trim($path, '/'))
1135
- $dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $path));
1136
-
1137
- $temp = &$this->stat_cache;
1138
- $max = count($dirs) - 1;
1139
- foreach ($dirs as $i => $dir) {
1140
- // if $temp is an object that means one of two things.
1141
- // 1. a file was deleted and changed to a directory behind phpseclib's back
1142
- // 2. it's a symlink. when lstat is done it's unclear what it's a symlink to
1143
- if (is_object($temp)) {
1144
- $temp = array();
1145
- }
1146
- if (!isset($temp[$dir])) {
1147
- $temp[$dir] = array();
1148
- }
1149
- if ($i === $max) {
1150
- if (is_object($temp[$dir])) {
1151
- if (!isset($value->stat) && isset($temp[$dir]->stat)) {
1152
- $value->stat = $temp[$dir]->stat;
1153
- }
1154
- if (!isset($value->lstat) && isset($temp[$dir]->lstat)) {
1155
- $value->lstat = $temp[$dir]->lstat;
1156
- }
1157
- }
1158
- $temp[$dir] = $value;
1159
- break;
1160
- }
1161
- $temp = &$temp[$dir];
1162
- }
1163
- }
1164
-
1165
- /**
1166
- * Remove files / directories from cache
1167
- *
1168
- * @param string $path
1169
- * @return bool
1170
- * @access private
1171
- */
1172
- function _remove_from_stat_cache($path)
1173
- {
1174
- $dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $path));
1175
-
1176
- $temp = &$this->stat_cache;
1177
- $max = count($dirs) - 1;
1178
- foreach ($dirs as $i => $dir) {
1179
- if ($i === $max) {
1180
- unset($temp[$dir]);
1181
- return true;
1182
- }
1183
- if (!isset($temp[$dir])) {
1184
- return false;
1185
- }
1186
- $temp = &$temp[$dir];
1187
- }
1188
- }
1189
-
1190
- /**
1191
- * Checks cache for path
1192
- *
1193
- * Mainly used by file_exists
1194
- *
1195
- * @param string $dir
1196
- * @return mixed
1197
- * @access private
1198
- */
1199
- function _query_stat_cache($path)
1200
- {
1201
- $dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $path));
1202
-
1203
- $temp = &$this->stat_cache;
1204
- foreach ($dirs as $dir) {
1205
- if (!isset($temp[$dir])) {
1206
- return null;
1207
- }
1208
- $temp = &$temp[$dir];
1209
- }
1210
- return $temp;
1211
- }
1212
-
1213
- /**
1214
- * Returns general information about a file.
1215
- *
1216
- * Returns an array on success and false otherwise.
1217
- *
1218
- * @param string $filename
1219
- * @return mixed
1220
- * @access public
1221
- */
1222
- function stat($filename)
1223
- {
1224
- if (!($this->bitmap & SSH2::MASK_LOGIN)) {
1225
- return false;
1226
- }
1227
-
1228
- $filename = $this->_realpath($filename);
1229
- if ($filename === false) {
1230
- return false;
1231
- }
1232
-
1233
- if ($this->use_stat_cache) {
1234
- $result = $this->_query_stat_cache($filename);
1235
- if (is_array($result) && isset($result['.']) && isset($result['.']->stat)) {
1236
- return $result['.']->stat;
1237
- }
1238
- if (is_object($result) && isset($result->stat)) {
1239
- return $result->stat;
1240
- }
1241
- }
1242
-
1243
- $stat = $this->_stat($filename, NET_SFTP_STAT);
1244
- if ($stat === false) {
1245
- $this->_remove_from_stat_cache($filename);
1246
- return false;
1247
- }
1248
- if (isset($stat['type'])) {
1249
- if ($stat['type'] == NET_SFTP_TYPE_DIRECTORY) {
1250
- $filename.= '/.';
1251
- }
1252
- $this->_update_stat_cache($filename, (object) array('stat' => $stat));
1253
- return $stat;
1254
- }
1255
-
1256
- $pwd = $this->pwd;
1257
- $stat['type'] = $this->chdir($filename) ?
1258
- NET_SFTP_TYPE_DIRECTORY :
1259
- NET_SFTP_TYPE_REGULAR;
1260
- $this->pwd = $pwd;
1261
-
1262
- if ($stat['type'] == NET_SFTP_TYPE_DIRECTORY) {
1263
- $filename.= '/.';
1264
- }
1265
- $this->_update_stat_cache($filename, (object) array('stat' => $stat));
1266
-
1267
- return $stat;
1268
- }
1269
-
1270
- /**
1271
- * Returns general information about a file or symbolic link.
1272
- *
1273
- * Returns an array on success and false otherwise.
1274
- *
1275
- * @param string $filename
1276
- * @return mixed
1277
- * @access public
1278
- */
1279
- function lstat($filename)
1280
- {
1281
- if (!($this->bitmap & SSH2::MASK_LOGIN)) {
1282
- return false;
1283
- }
1284
-
1285
- $filename = $this->_realpath($filename);
1286
- if ($filename === false) {
1287
- return false;
1288
- }
1289
-
1290
- if ($this->use_stat_cache) {
1291
- $result = $this->_query_stat_cache($filename);
1292
- if (is_array($result) && isset($result['.']) && isset($result['.']->lstat)) {
1293
- return $result['.']->lstat;
1294
- }
1295
- if (is_object($result) && isset($result->lstat)) {
1296
- return $result->lstat;
1297
- }
1298
- }
1299
-
1300
- $lstat = $this->_stat($filename, NET_SFTP_LSTAT);
1301
- if ($lstat === false) {
1302
- $this->_remove_from_stat_cache($filename);
1303
- return false;
1304
- }
1305
- if (isset($lstat['type'])) {
1306
- if ($lstat['type'] == NET_SFTP_TYPE_DIRECTORY) {
1307
- $filename.= '/.';
1308
- }
1309
- $this->_update_stat_cache($filename, (object) array('lstat' => $lstat));
1310
- return $lstat;
1311
- }
1312
-
1313
- $stat = $this->_stat($filename, NET_SFTP_STAT);
1314
-
1315
- if ($lstat != $stat) {
1316
- $lstat = array_merge($lstat, array('type' => NET_SFTP_TYPE_SYMLINK));
1317
- $this->_update_stat_cache($filename, (object) array('lstat' => $lstat));
1318
- return $stat;
1319
- }
1320
-
1321
- $pwd = $this->pwd;
1322
- $lstat['type'] = $this->chdir($filename) ?
1323
- NET_SFTP_TYPE_DIRECTORY :
1324
- NET_SFTP_TYPE_REGULAR;
1325
- $this->pwd = $pwd;
1326
-
1327
- if ($lstat['type'] == NET_SFTP_TYPE_DIRECTORY) {
1328
- $filename.= '/.';
1329
- }
1330
- $this->_update_stat_cache($filename, (object) array('lstat' => $lstat));
1331
-
1332
- return $lstat;
1333
- }
1334
-
1335
- /**
1336
- * Returns general information about a file or symbolic link
1337
- *
1338
- * Determines information without calling \phpseclib\Net\SFTP::realpath().
1339
- * The second parameter can be either NET_SFTP_STAT or NET_SFTP_LSTAT.
1340
- *
1341
- * @param string $filename
1342
- * @param int $type
1343
- * @return mixed
1344
- * @access private
1345
- */
1346
- function _stat($filename, $type)
1347
- {
1348
- // SFTPv4+ adds an additional 32-bit integer field - flags - to the following:
1349
- $packet = pack('Na*', strlen($filename), $filename);
1350
- if (!$this->_send_sftp_packet($type, $packet)) {
1351
- return false;
1352
- }
1353
-
1354
- $response = $this->_get_sftp_packet();
1355
- switch ($this->packet_type) {
1356
- case NET_SFTP_ATTRS:
1357
- return $this->_parseAttributes($response);
1358
- case NET_SFTP_STATUS:
1359
- $this->_logError($response);
1360
- return false;
1361
- }
1362
-
1363
- user_error('Expected SSH_FXP_ATTRS or SSH_FXP_STATUS');
1364
- return false;
1365
- }
1366
-
1367
- /**
1368
- * Truncates a file to a given length
1369
- *
1370
- * @param string $filename
1371
- * @param int $new_size
1372
- * @return bool
1373
- * @access public
1374
- */
1375
- function truncate($filename, $new_size)
1376
- {
1377
- $attr = pack('N3', NET_SFTP_ATTR_SIZE, $new_size / 4294967296, $new_size); // 4294967296 == 0x100000000 == 1<<32
1378
-
1379
- return $this->_setstat($filename, $attr, false);
1380
- }
1381
-
1382
- /**
1383
- * Sets access and modification time of file.
1384
- *
1385
- * If the file does not exist, it will be created.
1386
- *
1387
- * @param string $filename
1388
- * @param int $time
1389
- * @param int $atime
1390
- * @return bool
1391
- * @access public
1392
- */
1393
- function touch($filename, $time = null, $atime = null)
1394
- {
1395
- if (!($this->bitmap & SSH2::MASK_LOGIN)) {
1396
- return false;
1397
- }
1398
-
1399
- $filename = $this->_realpath($filename);
1400
- if ($filename === false) {
1401
- return false;
1402
- }
1403
-
1404
- if (!isset($time)) {
1405
- $time = time();
1406
- }
1407
- if (!isset($atime)) {
1408
- $atime = $time;
1409
- }
1410
-
1411
- $flags = NET_SFTP_OPEN_WRITE | NET_SFTP_OPEN_CREATE | NET_SFTP_OPEN_EXCL;
1412
- $attr = pack('N3', NET_SFTP_ATTR_ACCESSTIME, $time, $atime);
1413
- $packet = pack('Na*Na*', strlen($filename), $filename, $flags, $attr);
1414
- if (!$this->_send_sftp_packet(NET_SFTP_OPEN, $packet)) {
1415
- return false;
1416
- }
1417
-
1418
- $response = $this->_get_sftp_packet();
1419
- switch ($this->packet_type) {
1420
- case NET_SFTP_HANDLE:
1421
- return $this->_close_handle(substr($response, 4));
1422
- case NET_SFTP_STATUS:
1423
- $this->_logError($response);
1424
- break;
1425
- default:
1426
- user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
1427
- return false;
1428
- }
1429
-
1430
- return $this->_setstat($filename, $attr, false);
1431
- }
1432
-
1433
- /**
1434
- * Changes file or directory owner
1435
- *
1436
- * Returns true on success or false on error.
1437
- *
1438
- * @param string $filename
1439
- * @param int $uid
1440
- * @param bool $recursive
1441
- * @return bool
1442
- * @access public
1443
- */
1444
- function chown($filename, $uid, $recursive = false)
1445
- {
1446
- // quoting from <http://www.kernel.org/doc/man-pages/online/pages/man2/chown.2.html>,
1447
- // "if the owner or group is specified as -1, then that ID is not changed"
1448
- $attr = pack('N3', NET_SFTP_ATTR_UIDGID, $uid, -1);
1449
-
1450
- return $this->_setstat($filename, $attr, $recursive);
1451
- }
1452
-
1453
- /**
1454
- * Changes file or directory group
1455
- *
1456
- * Returns true on success or false on error.
1457
- *
1458
- * @param string $filename
1459
- * @param int $gid
1460
- * @param bool $recursive
1461
- * @return bool
1462
- * @access public
1463
- */
1464
- function chgrp($filename, $gid, $recursive = false)
1465
- {
1466
- $attr = pack('N3', NET_SFTP_ATTR_UIDGID, -1, $gid);
1467
-
1468
- return $this->_setstat($filename, $attr, $recursive);
1469
- }
1470
-
1471
- /**
1472
- * Set permissions on a file.
1473
- *
1474
- * Returns the new file permissions on success or false on error.
1475
- * If $recursive is true than this just returns true or false.
1476
- *
1477
- * @param int $mode
1478
- * @param string $filename
1479
- * @param bool $recursive
1480
- * @return mixed
1481
- * @access public
1482
- */
1483
- function chmod($mode, $filename, $recursive = false)
1484
- {
1485
- if (is_string($mode) && is_int($filename)) {
1486
- $temp = $mode;
1487
- $mode = $filename;
1488
- $filename = $temp;
1489
- }
1490
-
1491
- $attr = pack('N2', NET_SFTP_ATTR_PERMISSIONS, $mode & 07777);
1492
- if (!$this->_setstat($filename, $attr, $recursive)) {
1493
- return false;
1494
- }
1495
- if ($recursive) {
1496
- return true;
1497
- }
1498
-
1499
- $filename = $this->realpath($filename);
1500
- // rather than return what the permissions *should* be, we'll return what they actually are. this will also
1501
- // tell us if the file actually exists.
1502
- // incidentally, SFTPv4+ adds an additional 32-bit integer field - flags - to the following:
1503
- $packet = pack('Na*', strlen($filename), $filename);
1504
- if (!$this->_send_sftp_packet(NET_SFTP_STAT, $packet)) {
1505
- return false;
1506
- }
1507
-
1508
- $response = $this->_get_sftp_packet();
1509
- switch ($this->packet_type) {
1510
- case NET_SFTP_ATTRS:
1511
- $attrs = $this->_parseAttributes($response);
1512
- return $attrs['permissions'];
1513
- case NET_SFTP_STATUS:
1514
- $this->_logError($response);
1515
- return false;
1516
- }
1517
-
1518
- user_error('Expected SSH_FXP_ATTRS or SSH_FXP_STATUS');
1519
- return false;
1520
- }
1521
-
1522
- /**
1523
- * Sets information about a file
1524
- *
1525
- * @param string $filename
1526
- * @param string $attr
1527
- * @param bool $recursive
1528
- * @return bool
1529
- * @access private
1530
- */
1531
- function _setstat($filename, $attr, $recursive)
1532
- {
1533
- if (!($this->bitmap & SSH2::MASK_LOGIN)) {
1534
- return false;
1535
- }
1536
-
1537
- $filename = $this->_realpath($filename);
1538
- if ($filename === false) {
1539
- return false;
1540
- }
1541
-
1542
- $this->_remove_from_stat_cache($filename);
1543
-
1544
- if ($recursive) {
1545
- $i = 0;
1546
- $result = $this->_setstat_recursive($filename, $attr, $i);
1547
- $this->_read_put_responses($i);
1548
- return $result;
1549
- }
1550
-
1551
- // SFTPv4+ has an additional byte field - type - that would need to be sent, as well. setting it to
1552
- // SSH_FILEXFER_TYPE_UNKNOWN might work. if not, we'd have to do an SSH_FXP_STAT before doing an SSH_FXP_SETSTAT.
1553
- if (!$this->_send_sftp_packet(NET_SFTP_SETSTAT, pack('Na*a*', strlen($filename), $filename, $attr))) {
1554
- return false;
1555
- }
1556
-
1557
- /*
1558
- "Because some systems must use separate system calls to set various attributes, it is possible that a failure
1559
- response will be returned, but yet some of the attributes may be have been successfully modified. If possible,
1560
- servers SHOULD avoid this situation; however, clients MUST be aware that this is possible."
1561
-
1562
- -- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.6
1563
- */
1564
- $response = $this->_get_sftp_packet();
1565
- if ($this->packet_type != NET_SFTP_STATUS) {
1566
- user_error('Expected SSH_FXP_STATUS');
1567
- return false;
1568
- }
1569
-
1570
- if (strlen($response) < 4) {
1571
- return false;
1572
- }
1573
- extract(unpack('Nstatus', $this->_string_shift($response, 4)));
1574
- if ($status != NET_SFTP_STATUS_OK) {
1575
- $this->_logError($response, $status);
1576
- return false;
1577
- }
1578
-
1579
- return true;
1580
- }
1581
-
1582
- /**
1583
- * Recursively sets information on directories on the SFTP server
1584
- *
1585
- * Minimizes directory lookups and SSH_FXP_STATUS requests for speed.
1586
- *
1587
- * @param string $path
1588
- * @param string $attr
1589
- * @param int $i
1590
- * @return bool
1591
- * @access private
1592
- */
1593
- function _setstat_recursive($path, $attr, &$i)
1594
- {
1595
- if (!$this->_read_put_responses($i)) {
1596
- return false;
1597
- }
1598
- $i = 0;
1599
- $entries = $this->_list($path, true);
1600
-
1601
- if ($entries === false) {
1602
- return $this->_setstat($path, $attr, false);
1603
- }
1604
-
1605
- // normally $entries would have at least . and .. but it might not if the directories
1606
- // permissions didn't allow reading
1607
- if (empty($entries)) {
1608
- return false;
1609
- }
1610
-
1611
- unset($entries['.'], $entries['..']);
1612
- foreach ($entries as $filename => $props) {
1613
- if (!isset($props['type'])) {
1614
- return false;
1615
- }
1616
-
1617
- $temp = $path . '/' . $filename;
1618
- if ($props['type'] == NET_SFTP_TYPE_DIRECTORY) {
1619
- if (!$this->_setstat_recursive($temp, $attr, $i)) {
1620
- return false;
1621
- }
1622
- } else {
1623
- if (!$this->_send_sftp_packet(NET_SFTP_SETSTAT, pack('Na*a*', strlen($temp), $temp, $attr))) {
1624
- return false;
1625
- }
1626
-
1627
- $i++;
1628
-
1629
- if ($i >= NET_SFTP_QUEUE_SIZE) {
1630
- if (!$this->_read_put_responses($i)) {
1631
- return false;
1632
- }
1633
- $i = 0;
1634
- }
1635
- }
1636
- }
1637
-
1638
- if (!$this->_send_sftp_packet(NET_SFTP_SETSTAT, pack('Na*a*', strlen($path), $path, $attr))) {
1639
- return false;
1640
- }
1641
-
1642
- $i++;
1643
-
1644
- if ($i >= NET_SFTP_QUEUE_SIZE) {
1645
- if (!$this->_read_put_responses($i)) {
1646
- return false;
1647
- }
1648
- $i = 0;
1649
- }
1650
-
1651
- return true;
1652
- }
1653
-
1654
- /**
1655
- * Return the target of a symbolic link
1656
- *
1657
- * @param string $link
1658
- * @return mixed
1659
- * @access public
1660
- */
1661
- function readlink($link)
1662
- {
1663
- if (!($this->bitmap & SSH2::MASK_LOGIN)) {
1664
- return false;
1665
- }
1666
-
1667
- $link = $this->_realpath($link);
1668
-
1669
- if (!$this->_send_sftp_packet(NET_SFTP_READLINK, pack('Na*', strlen($link), $link))) {
1670
- return false;
1671
- }
1672
-
1673
- $response = $this->_get_sftp_packet();
1674
- switch ($this->packet_type) {
1675
- case NET_SFTP_NAME:
1676
- break;
1677
- case NET_SFTP_STATUS:
1678
- $this->_logError($response);
1679
- return false;
1680
- default:
1681
- user_error('Expected SSH_FXP_NAME or SSH_FXP_STATUS');
1682
- return false;
1683
- }
1684
-
1685
- if (strlen($response) < 4) {
1686
- return false;
1687
- }
1688
- extract(unpack('Ncount', $this->_string_shift($response, 4)));
1689
- // the file isn't a symlink
1690
- if (!$count) {
1691
- return false;
1692
- }
1693
-
1694
- if (strlen($response) < 4) {
1695
- return false;
1696
- }
1697
- extract(unpack('Nlength', $this->_string_shift($response, 4)));
1698
- return $this->_string_shift($response, $length);
1699
- }
1700
-
1701
- /**
1702
- * Create a symlink
1703
- *
1704
- * symlink() creates a symbolic link to the existing target with the specified name link.
1705
- *
1706
- * @param string $target
1707
- * @param string $link
1708
- * @return bool
1709
- * @access public
1710
- */
1711
- function symlink($target, $link)
1712
- {
1713
- if (!($this->bitmap & SSH2::MASK_LOGIN)) {
1714
- return false;
1715
- }
1716
-
1717
- //$target = $this->_realpath($target);
1718
- $link = $this->_realpath($link);
1719
-
1720
- $packet = pack('Na*Na*', strlen($target), $target, strlen($link), $link);
1721
- if (!$this->_send_sftp_packet(NET_SFTP_SYMLINK, $packet)) {
1722
- return false;
1723
- }
1724
-
1725
- $response = $this->_get_sftp_packet();
1726
- if ($this->packet_type != NET_SFTP_STATUS) {
1727
- user_error('Expected SSH_FXP_STATUS');
1728
- return false;
1729
- }
1730
-
1731
- if (strlen($response) < 4) {
1732
- return false;
1733
- }
1734
- extract(unpack('Nstatus', $this->_string_shift($response, 4)));
1735
- if ($status != NET_SFTP_STATUS_OK) {
1736
- $this->_logError($response, $status);
1737
- return false;
1738
- }
1739
-
1740
- return true;
1741
- }
1742
-
1743
- /**
1744
- * Creates a directory.
1745
- *
1746
- * @param string $dir
1747
- * @return bool
1748
- * @access public
1749
- */
1750
- function mkdir($dir, $mode = -1, $recursive = false)
1751
- {
1752
- if (!($this->bitmap & SSH2::MASK_LOGIN)) {
1753
- return false;
1754
- }
1755
-
1756
- $dir = $this->_realpath($dir);
1757
- // by not providing any permissions, hopefully the server will use the logged in users umask - their
1758
- // default permissions.
1759
- $attr = $mode == -1 ? "\0\0\0\0" : pack('N2', NET_SFTP_ATTR_PERMISSIONS, $mode & 07777);
1760
-
1761
- if ($recursive) {
1762
- $dirs = explode('/', preg_replace('#/(?=/)|/$#', '', $dir));
1763
- if (empty($dirs[0])) {
1764
- array_shift($dirs);
1765
- $dirs[0] = '/' . $dirs[0];
1766
- }
1767
- for ($i = 0; $i < count($dirs); $i++) {
1768
- $temp = array_slice($dirs, 0, $i + 1);
1769
- $temp = implode('/', $temp);
1770
- $result = $this->_mkdir_helper($temp, $attr);
1771
- }
1772
- return $result;
1773
- }
1774
-
1775
- return $this->_mkdir_helper($dir, $attr);
1776
- }
1777
-
1778
- /**
1779
- * Helper function for directory creation
1780
- *
1781
- * @param string $dir
1782
- * @return bool
1783
- * @access private
1784
- */
1785
- function _mkdir_helper($dir, $attr)
1786
- {
1787
- if (!$this->_send_sftp_packet(NET_SFTP_MKDIR, pack('Na*a*', strlen($dir), $dir, $attr))) {
1788
- return false;
1789
- }
1790
-
1791
- $response = $this->_get_sftp_packet();
1792
- if ($this->packet_type != NET_SFTP_STATUS) {
1793
- user_error('Expected SSH_FXP_STATUS');
1794
- return false;
1795
- }
1796
-
1797
- if (strlen($response) < 4) {
1798
- return false;
1799
- }
1800
- extract(unpack('Nstatus', $this->_string_shift($response, 4)));
1801
- if ($status != NET_SFTP_STATUS_OK) {
1802
- $this->_logError($response, $status);
1803
- return false;
1804
- }
1805
-
1806
- return true;
1807
- }
1808
-
1809
- /**
1810
- * Removes a directory.
1811
- *
1812
- * @param string $dir
1813
- * @return bool
1814
- * @access public
1815
- */
1816
- function rmdir($dir)
1817
- {
1818
- if (!($this->bitmap & SSH2::MASK_LOGIN)) {
1819
- return false;
1820
- }
1821
-
1822
- $dir = $this->_realpath($dir);
1823
- if ($dir === false) {
1824
- return false;
1825
- }
1826
-
1827
- if (!$this->_send_sftp_packet(NET_SFTP_RMDIR, pack('Na*', strlen($dir), $dir))) {
1828
- return false;
1829
- }
1830
-
1831
- $response = $this->_get_sftp_packet();
1832
- if ($this->packet_type != NET_SFTP_STATUS) {
1833
- user_error('Expected SSH_FXP_STATUS');
1834
- return false;
1835
- }
1836
-
1837
- if (strlen($response) < 4) {
1838
- return false;
1839
- }
1840
- extract(unpack('Nstatus', $this->_string_shift($response, 4)));
1841
- if ($status != NET_SFTP_STATUS_OK) {
1842
- // presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED?
1843
- $this->_logError($response, $status);
1844
- return false;
1845
- }
1846
-
1847
- $this->_remove_from_stat_cache($dir);
1848
- // the following will do a soft delete, which would be useful if you deleted a file
1849
- // and then tried to do a stat on the deleted file. the above, in contrast, does
1850
- // a hard delete
1851
- //$this->_update_stat_cache($dir, false);
1852
-
1853
- return true;
1854
- }
1855
-
1856
- /**
1857
- * Uploads a file to the SFTP server.
1858
- *
1859
- * By default, \phpseclib\Net\SFTP::put() does not read from the local filesystem. $data is dumped directly into $remote_file.
1860
- * So, for example, if you set $data to 'filename.ext' and then do \phpseclib\Net\SFTP::get(), you will get a file, twelve bytes
1861
- * long, containing 'filename.ext' as its contents.
1862
- *
1863
- * Setting $mode to self::SOURCE_LOCAL_FILE will change the above behavior. With self::SOURCE_LOCAL_FILE, $remote_file will
1864
- * contain as many bytes as filename.ext does on your local filesystem. If your filename.ext is 1MB then that is how
1865
- * large $remote_file will be, as well.
1866
- *
1867
- * Setting $mode to self::SOURCE_CALLBACK will use $data as callback function, which gets only one parameter -- number of bytes to return, and returns a string if there is some data or null if there is no more data
1868
- *
1869
- * If $data is a resource then it'll be used as a resource instead.
1870
- *
1871
- * Currently, only binary mode is supported. As such, if the line endings need to be adjusted, you will need to take
1872
- * care of that, yourself.
1873
- *
1874
- * $mode can take an additional two parameters - self::RESUME and self::RESUME_START. These are bitwise AND'd with
1875
- * $mode. So if you want to resume upload of a 300mb file on the local file system you'd set $mode to the following:
1876
- *
1877
- * self::SOURCE_LOCAL_FILE | self::RESUME
1878
- *
1879
- * If you wanted to simply append the full contents of a local file to the full contents of a remote file you'd replace
1880
- * self::RESUME with self::RESUME_START.
1881
- *
1882
- * If $mode & (self::RESUME | self::RESUME_START) then self::RESUME_START will be assumed.
1883
- *
1884
- * $start and $local_start give you more fine grained control over this process and take precident over self::RESUME
1885
- * when they're non-negative. ie. $start could let you write at the end of a file (like self::RESUME) or in the middle
1886
- * of one. $local_start could let you start your reading from the end of a file (like self::RESUME_START) or in the
1887
- * middle of one.
1888
- *
1889
- * Setting $local_start to > 0 or $mode | self::RESUME_START doesn't do anything unless $mode | self::SOURCE_LOCAL_FILE.
1890
- *
1891
- * @param string $remote_file
1892
- * @param string|resource $data
1893
- * @param int $mode
1894
- * @param int $start
1895
- * @param int $local_start
1896
- * @param callable|null $progressCallback
1897
- * @return bool
1898
- * @access public
1899
- * @internal ASCII mode for SFTPv4/5/6 can be supported by adding a new function - \phpseclib\Net\SFTP::setMode().
1900
- */
1901
- function put($remote_file, $data, $mode = self::SOURCE_STRING, $start = -1, $local_start = -1, $progressCallback = null)
1902
- {
1903
- if (!($this->bitmap & SSH2::MASK_LOGIN)) {
1904
- return false;
1905
- }
1906
-
1907
- $remote_file = $this->_realpath($remote_file);
1908
- if ($remote_file === false) {
1909
- return false;
1910
- }
1911
-
1912
- $this->_remove_from_stat_cache($remote_file);
1913
-
1914
- $flags = NET_SFTP_OPEN_WRITE | NET_SFTP_OPEN_CREATE;
1915
- // according to the SFTP specs, NET_SFTP_OPEN_APPEND should "force all writes to append data at the end of the file."
1916
- // in practice, it doesn't seem to do that.
1917
- //$flags|= ($mode & self::RESUME) ? NET_SFTP_OPEN_APPEND : NET_SFTP_OPEN_TRUNCATE;
1918
-
1919
- if ($start >= 0) {
1920
- $offset = $start;
1921
- } elseif ($mode & self::RESUME) {
1922
- // if NET_SFTP_OPEN_APPEND worked as it should _size() wouldn't need to be called
1923
- $size = $this->size($remote_file);
1924
- $offset = $size !== false ? $size : 0;
1925
- } else {
1926
- $offset = 0;
1927
- $flags|= NET_SFTP_OPEN_TRUNCATE;
1928
- }
1929
-
1930
- $packet = pack('Na*N2', strlen($remote_file), $remote_file, $flags, 0);
1931
- if (!$this->_send_sftp_packet(NET_SFTP_OPEN, $packet)) {
1932
- return false;
1933
- }
1934
-
1935
- $response = $this->_get_sftp_packet();
1936
- switch ($this->packet_type) {
1937
- case NET_SFTP_HANDLE:
1938
- $handle = substr($response, 4);
1939
- break;
1940
- case NET_SFTP_STATUS:
1941
- $this->_logError($response);
1942
- return false;
1943
- default:
1944
- user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
1945
- return false;
1946
- }
1947
-
1948
- // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.2.3
1949
- $dataCallback = false;
1950
- switch (true) {
1951
- case $mode & self::S