Completed
Push — master ( b790b0...129907 )
by Roy
02:04
created

woocommerce-gateway-stripe.php (7 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * Plugin Name: WooCommerce Stripe Gateway
4
 * Plugin URI: https://wordpress.org/plugins/woocommerce-gateway-stripe/
5
 * Description: Take credit card payments on your store using Stripe.
6
 * Author: WooCommerce
7
 * Author URI: https://woocommerce.com/
8
 * Version: 4.0.7
9
 * Requires at least: 4.4
10
 * Tested up to: 4.9
11
 * WC requires at least: 2.6
12
 * WC tested up to: 3.3
13
 * Text Domain: woocommerce-gateway-stripe
14
 * Domain Path: /languages/
15
 *
16
 */
17
18
if ( ! defined( 'ABSPATH' ) ) {
19
	exit;
20
}
21
22
if ( ! class_exists( 'WC_Stripe' ) ) :
23
	/**
24
	 * Required minimums and constants
25
	 */
26
	define( 'WC_STRIPE_VERSION', '4.0.7' );
27
	define( 'WC_STRIPE_MIN_PHP_VER', '5.6.0' );
28
	define( 'WC_STRIPE_MIN_WC_VER', '2.6.0' );
29
	define( 'WC_STRIPE_MAIN_FILE', __FILE__ );
30
	define( 'WC_STRIPE_PLUGIN_URL', untrailingslashit( plugins_url( basename( plugin_dir_path( __FILE__ ) ), basename( __FILE__ ) ) ) );
31
	define( 'WC_STRIPE_PLUGIN_PATH', untrailingslashit( plugin_dir_path( __FILE__ ) ) );
32
33
	class WC_Stripe {
34
35
		/**
36
		 * @var Singleton The reference the *Singleton* instance of this class
37
		 */
38
		private static $instance;
39
40
		/**
41
		 * @var Reference to logging class.
42
		 */
43
		private static $log;
0 ignored issues
show
The property $log is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
44
45
		/**
46
		 * Returns the *Singleton* instance of this class.
47
		 *
48
		 * @return Singleton The *Singleton* instance.
49
		 */
50
		public static function get_instance() {
51
			if ( null === self::$instance ) {
52
				self::$instance = new self();
0 ignored issues
show
Documentation Bug introduced by
It seems like new self() of type object<WC_Stripe> is incompatible with the declared type object<Singleton> of property $instance.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
53
			}
54
			return self::$instance;
0 ignored issues
show
Bug Compatibility introduced by
The expression self::$instance; of type WC_Stripe|Singleton adds the type WC_Stripe to the return on line 54 which is incompatible with the return type documented by WC_Stripe::get_instance of type Singleton.
Loading history...
55
		}
56
57
		/**
58
		 * Private clone method to prevent cloning of the instance of the
59
		 * *Singleton* instance.
60
		 *
61
		 * @return void
62
		 */
63
		private function __clone() {}
64
65
		/**
66
		 * Private unserialize method to prevent unserializing of the *Singleton*
67
		 * instance.
68
		 *
69
		 * @return void
70
		 */
71
		private function __wakeup() {}
72
73
		/**
74
		 * Notices (array)
75
		 * @var array
76
		 */
77
		public $notices = array();
78
79
		/**
80
		 * Protected constructor to prevent creating a new instance of the
81
		 * *Singleton* via the `new` operator from outside of this class.
82
		 */
83
		private function __construct() {
84
			add_action( 'admin_init', array( $this, 'check_environment' ) );
85
			add_action( 'admin_notices', array( $this, 'admin_notices' ), 15 );
86
			add_action( 'plugins_loaded', array( $this, 'init' ) );
87
			add_action( 'wp_loaded', array( $this, 'hide_notices' ) );
88
		}
89
90
		/**
91
		 * Init the plugin after plugins_loaded so environment variables are set.
92
		 *
93
		 * @since 1.0.0
94
		 * @version 4.0.0
95
		 */
96
		public function init() {
97
			require_once( dirname( __FILE__ ) . '/includes/class-wc-stripe-exception.php' );
98
			require_once( dirname( __FILE__ ) . '/includes/class-wc-stripe-logger.php' );
99
			require_once( dirname( __FILE__ ) . '/includes/class-wc-stripe-helper.php' );
100
			include_once( dirname( __FILE__ ) . '/includes/class-wc-stripe-api.php' );
101
102
			// Don't hook anything else in the plugin if we're in an incompatible environment.
103
			if ( self::get_environment_warning() ) {
104
				return;
105
			}
106
107
			load_plugin_textdomain( 'woocommerce-gateway-stripe', false, plugin_basename( dirname( __FILE__ ) ) . '/languages' );
108
109
			require_once( dirname( __FILE__ ) . '/includes/abstracts/abstract-wc-stripe-payment-gateway.php' );
110
			require_once( dirname( __FILE__ ) . '/includes/class-wc-stripe-webhook-handler.php' );
111
			require_once( dirname( __FILE__ ) . '/includes/class-wc-stripe-sepa-payment-token.php' );
112
			require_once( dirname( __FILE__ ) . '/includes/class-wc-stripe-apple-pay-registration.php' );
113
			require_once( dirname( __FILE__ ) . '/includes/class-wc-gateway-stripe.php' );
114
			require_once( dirname( __FILE__ ) . '/includes/payment-methods/class-wc-gateway-stripe-bancontact.php' );
115
			require_once( dirname( __FILE__ ) . '/includes/payment-methods/class-wc-gateway-stripe-sofort.php' );
116
			require_once( dirname( __FILE__ ) . '/includes/payment-methods/class-wc-gateway-stripe-giropay.php' );
117
			require_once( dirname( __FILE__ ) . '/includes/payment-methods/class-wc-gateway-stripe-ideal.php' );
118
			require_once( dirname( __FILE__ ) . '/includes/payment-methods/class-wc-gateway-stripe-p24.php' );
119
			require_once( dirname( __FILE__ ) . '/includes/payment-methods/class-wc-gateway-stripe-alipay.php' );
120
			require_once( dirname( __FILE__ ) . '/includes/payment-methods/class-wc-gateway-stripe-sepa.php' );
121
			require_once( dirname( __FILE__ ) . '/includes/payment-methods/class-wc-gateway-stripe-bitcoin.php' );
122
			require_once( dirname( __FILE__ ) . '/includes/payment-methods/class-wc-stripe-payment-request.php' );
123
			require_once( dirname( __FILE__ ) . '/includes/compat/class-wc-stripe-compat.php' );
124
			require_once( dirname( __FILE__ ) . '/includes/compat/class-wc-stripe-sepa-compat.php' );
125
			require_once( dirname( __FILE__ ) . '/includes/class-wc-stripe-order-handler.php' );
126
			require_once( dirname( __FILE__ ) . '/includes/class-wc-stripe-payment-tokens.php' );
127
			require_once( dirname( __FILE__ ) . '/includes/class-wc-stripe-customer.php' );
128
129
			// REMOVE IN THE FUTURE.
130
			require_once( dirname( __FILE__ ) . '/includes/deprecated/class-wc-stripe-apple-pay.php' );
131
132
			add_filter( 'woocommerce_payment_gateways', array( $this, 'add_gateways' ) );
133
			add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), array( $this, 'plugin_action_links' ) );
134
			add_filter( 'woocommerce_get_sections_checkout', array( $this, 'filter_gateway_order_admin' ) );
135
		}
136
137
		/**
138
		 * Hides any admin notices.
139
		 *
140
		 * @since 4.0.0
141
		 * @version 4.0.0
142
		 */
143
		public function hide_notices() {
144
			if ( isset( $_GET['wc-stripe-hide-notice'] ) && isset( $_GET['_wc_stripe_notice_nonce'] ) ) {
145
				if ( ! wp_verify_nonce( $_GET['_wc_stripe_notice_nonce'], 'wc_stripe_hide_notices_nonce' ) ) {
146
					wp_die( __( 'Action failed. Please refresh the page and retry.', 'woocommerce-gateway-stripe' ) );
147
				}
148
149
				if ( ! current_user_can( 'manage_woocommerce' ) ) {
150
					wp_die( __( 'Cheatin&#8217; huh?', 'woocommerce-gateway-stripe' ) );
151
				}
152
153
				$notice = wc_clean( $_GET['wc-stripe-hide-notice'] );
154
155
				switch ( $notice ) {
156
					case 'ssl':
157
						update_option( 'wc_stripe_show_ssl_notice', 'no' );
158
						break;
159
					case 'keys':
160
						update_option( 'wc_stripe_show_keys_notice', 'no' );
161
						break;
162
				}
163
			}
164
		}
165
166
		/**
167
		 * Allow this class and other classes to add slug keyed notices (to avoid duplication).
168
		 *
169
		 * @since 1.0.0
170
		 * @version 4.0.0
171
		 */
172
		public function add_admin_notice( $slug, $class, $message, $dismissible = false ) {
173
			$this->notices[ $slug ] = array(
174
				'class'       => $class,
175
				'message'     => $message,
176
				'dismissible' => $dismissible,
177
			);
178
		}
179
180
		/**
181
		 * Display any notices we've collected thus far (e.g. for connection, disconnection).
182
		 *
183
		 * @since 1.0.0
184
		 * @version 4.0.0
185
		 */
186
		public function admin_notices() {
187
			if ( ! current_user_can( 'manage_woocommerce' ) ) {
188
				return;
189
			}
190
191
			foreach ( (array) $this->notices as $notice_key => $notice ) {
192
				echo '<div class="' . esc_attr( $notice['class'] ) . '" style="position:relative;">';
193
194
				if ( $notice['dismissible'] ) {
195
				?>
196
					<a href="<?php echo esc_url( wp_nonce_url( add_query_arg( 'wc-stripe-hide-notice', $notice_key ), 'wc_stripe_hide_notices_nonce', '_wc_stripe_notice_nonce' ) ); ?>" class="woocommerce-message-close notice-dismiss" style="position:absolute;right:1px;padding:9px;text-decoration:none;"></a>
197
				<?php
198
				}
199
200
				echo '<p>';
201
				echo wp_kses( $notice['message'], array( 'a' => array( 'href' => array() ) ) );
202
				echo '</p></div>';
203
			}
204
		}
205
206
		/**
207
		 * Checks the environment for compatibility problems.  Returns a string with the first incompatibility
208
		 * found or false if the environment has no problems.
209
		 *
210
		 * @since 1.0.0
211
		 * @version 4.0.0
212
		 */
213
		public function get_environment_warning() {
214 View Code Duplication
			if ( version_compare( phpversion(), WC_STRIPE_MIN_PHP_VER, '<' ) ) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
215
				/* translators: 1) int version 2) int version */
216
				$message = __( 'WooCommerce Stripe - The minimum PHP version required for this plugin is %1$s. You are running %2$s.', 'woocommerce-gateway-stripe' );
217
218
				return sprintf( $message, WC_STRIPE_MIN_PHP_VER, phpversion() );
219
			}
220
221
			if ( ! defined( 'WC_VERSION' ) ) {
222
				return __( 'WooCommerce Stripe requires WooCommerce to be activated to work.', 'woocommerce-gateway-stripe' );
223
			}
224
225 View Code Duplication
			if ( version_compare( WC_VERSION, WC_STRIPE_MIN_WC_VER, '<' ) ) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
226
				/* translators: 1) int version 2) int version */
227
				$message = __( 'WooCommerce Stripe - The minimum WooCommerce version required for this plugin is %1$s. You are running %2$s.', 'woocommerce-gateway-stripe' );
228
229
				return sprintf( $message, WC_STRIPE_MIN_WC_VER, WC_VERSION );
230
			}
231
232
			if ( ! function_exists( 'curl_init' ) ) {
233
				return __( 'WooCommerce Stripe - cURL is not installed.', 'woocommerce-gateway-stripe' );
234
			}
235
236
			return false;
237
		}
238
239
		/**
240
		 * Get setting link.
241
		 *
242
		 * @since 1.0.0
243
		 *
244
		 * @return string Setting link
245
		 */
246
		public function get_setting_link() {
247
			$use_id_as_section = function_exists( 'WC' ) ? version_compare( WC()->version, '2.6', '>=' ) : false;
248
249
			$section_slug = $use_id_as_section ? 'stripe' : strtolower( 'WC_Gateway_Stripe' );
250
251
			return admin_url( 'admin.php?page=wc-settings&tab=checkout&section=' . $section_slug );
252
		}
253
254
		/**
255
		 * The backup sanity check, in case the plugin is activated in a weird way,
256
		 * or the environment changes after activation. Also handles upgrade routines.
257
		 *
258
		 * @since 1.0.0
259
		 * @version 4.0.0
260
		 */
261
		public function check_environment() {
262
			if ( ! defined( 'IFRAME_REQUEST' ) && ( WC_STRIPE_VERSION !== get_option( 'wc_stripe_version' ) ) ) {
263
				$this->install();
264
265
				do_action( 'woocommerce_stripe_updated' );
266
			}
267
268
			$environment_warning = $this->get_environment_warning();
269
270
			if ( $environment_warning && is_plugin_active( plugin_basename( __FILE__ ) ) ) {
271
				$this->add_admin_notice( 'bad_environment', 'error', $environment_warning );
272
			}
273
274
			$show_ssl_notice  = get_option( 'wc_stripe_show_ssl_notice' );
275
			$show_keys_notice = get_option( 'wc_stripe_show_keys_notice' );
276
			$options          = get_option( 'woocommerce_stripe_settings' );
277
			$testmode         = ( isset( $options['testmode'] ) && 'yes' === $options['testmode'] ) ? true : false;
278
			$test_pub_key     = isset( $options['test_publishable_key'] ) ? $options['test_publishable_key'] : '';
279
			$test_secret_key  = isset( $options['test_secret_key'] ) ? $options['test_secret_key'] : '';
280
			$live_pub_key     = isset( $options['publishable_key'] ) ? $options['publishable_key'] : '';
281
			$live_secret_key  = isset( $options['secret_key'] ) ? $options['secret_key'] : '';
282
283
			if ( isset( $options['enabled'] ) && 'yes' === $options['enabled'] && empty( $show_keys_notice ) ) {
284
				$secret  = WC_Stripe_API::get_secret_key();
285
286
				if ( empty( $secret ) && ! ( isset( $_GET['page'], $_GET['section'] ) && 'wc-settings' === $_GET['page'] && 'stripe' === $_GET['section'] ) ) {
287
					$setting_link = $this->get_setting_link();
288
					/* translators: 1) link */
289
					$this->add_admin_notice( 'keys', 'notice notice-warning', sprintf( __( 'Stripe is almost ready. To get started, <a href="%s">set your Stripe account keys</a>.', 'woocommerce-gateway-stripe' ), $setting_link ), true );
290
				}
291
292
				// Check if keys are entered properly per live/test mode.
293
				if ( $testmode ) {
294 View Code Duplication
					if (
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
295
						! empty( $test_pub_key ) && ! preg_match( '/^pk_test_/', $test_pub_key )
296
						|| ( ! empty( $test_secret_key ) && ! preg_match( '/^sk_test_/', $test_secret_key )
297
						&& ! empty( $test_secret_key ) && ! preg_match( '/^rk_test_/', $test_secret_key ) ) )
298
					{
299
						$setting_link = $this->get_setting_link();
300
						/* translators: 1) link */
301
						$this->add_admin_notice( 'keys', 'notice notice-error', sprintf( __( 'Stripe is in test mode however your test keys may not be valid. Test keys start with pk_test and sk_test or rk_test. Please go to your settings and, <a href="%s">set your Stripe account keys</a>.', 'woocommerce-gateway-stripe' ), $setting_link ), true );
302
					}
303 View Code Duplication
				} else {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
304
					if (
305
						! empty( $live_pub_key ) && ! preg_match( '/^pk_live_/', $live_pub_key )
306
						|| ( ! empty( $live_secret_key ) && ! preg_match( '/^sk_live_/', $live_secret_key )
307
						&& ! empty( $live_secret_key ) && ! preg_match( '/^rk_live_/', $live_secret_key ) ) )
308
					{
309
						$setting_link = $this->get_setting_link();
310
						/* translators: 1) link */
311
						$this->add_admin_notice( 'keys', 'notice notice-error', sprintf( __( 'Stripe is in live mode however your test keys may not be valid. Live keys start with pk_live and sk_live or rk_live. Please go to your settings and, <a href="%s">set your Stripe account keys</a>.', 'woocommerce-gateway-stripe' ), $setting_link ), true );
312
					}
313
				}
314
			}
315
316
			if ( empty( $show_ssl_notice ) && isset( $options['enabled'] ) && 'yes' === $options['enabled'] ) {
317
				// Show message if enabled and FORCE SSL is disabled and WordpressHTTPS plugin is not detected.
318
				if ( ( function_exists( 'wc_site_is_https' ) && ! wc_site_is_https() ) && ( 'no' === get_option( 'woocommerce_force_ssl_checkout' ) && ! class_exists( 'WordPressHTTPS' ) ) ) {
319
					/* translators: 1) link 2) link */
320
					$this->add_admin_notice( 'ssl', 'notice notice-warning', sprintf( __( 'Stripe is enabled, but the <a href="%1$s">force SSL option</a> is disabled; your checkout may not be secure! Please enable SSL and ensure your server has a valid <a href="%2$s" target="_blank">SSL certificate</a> - Stripe will only work in test mode.', 'woocommerce-gateway-stripe' ), admin_url( 'admin.php?page=wc-settings&tab=checkout' ), 'https://en.wikipedia.org/wiki/Transport_Layer_Security' ), true );
321
				}
322
			}
323
		}
324
325
		/**
326
		 * Updates the plugin version in db
327
		 *
328
		 * @since 3.1.0
329
		 * @version 4.0.0
330
		 */
331
		public function update_plugin_version() {
332
			delete_option( 'wc_stripe_version' );
333
			update_option( 'wc_stripe_version', WC_STRIPE_VERSION );
334
		}
335
336
		/**
337
		 * Handles upgrade routines.
338
		 *
339
		 * @since 3.1.0
340
		 * @version 3.1.0
341
		 */
342
		public function install() {
343
			if ( ! defined( 'WC_STRIPE_INSTALLING' ) ) {
344
				define( 'WC_STRIPE_INSTALLING', true );
345
			}
346
347
			$this->update_plugin_version();
348
		}
349
350
		/**
351
		 * Adds plugin action links.
352
		 *
353
		 * @since 1.0.0
354
		 * @version 4.0.0
355
		 */
356
		public function plugin_action_links( $links ) {
357
			$plugin_links = array(
358
				'<a href="admin.php?page=wc-settings&tab=checkout&section=stripe">' . esc_html__( 'Settings', 'woocommerce-gateway-stripe' ) . '</a>',
359
				'<a href="https://docs.woocommerce.com/document/stripe/">' . esc_html__( 'Docs', 'woocommerce-gateway-stripe' ) . '</a>',
360
				'<a href="https://woocommerce.com/contact-us/">' . esc_html__( 'Support', 'woocommerce-gateway-stripe' ) . '</a>',
361
			);
362
			return array_merge( $plugin_links, $links );
363
		}
364
365
		/**
366
		 * Add the gateways to WooCommerce.
367
		 *
368
		 * @since 1.0.0
369
		 * @version 4.0.0
370
		 */
371
		public function add_gateways( $methods ) {
372
			if ( class_exists( 'WC_Subscriptions_Order' ) && function_exists( 'wcs_create_renewal_order' ) || class_exists( 'WC_Pre_Orders_Order' ) ) {
373
				$methods[] = 'WC_Stripe_Compat';
374
				$methods[] = 'WC_Stripe_Sepa_Compat';
375
			} else {
376
				$methods[] = 'WC_Gateway_Stripe';
377
				$methods[] = 'WC_Gateway_Stripe_Sepa';
378
			}
379
380
			$methods[] = 'WC_Gateway_Stripe_Bancontact';
381
			$methods[] = 'WC_Gateway_Stripe_Sofort';
382
			$methods[] = 'WC_Gateway_Stripe_Giropay';
383
			$methods[] = 'WC_Gateway_Stripe_Ideal';
384
			$methods[] = 'WC_Gateway_Stripe_P24';
385
			$methods[] = 'WC_Gateway_Stripe_Alipay';
386
			$methods[] = 'WC_Gateway_Stripe_Bitcoin';
387
388
			return $methods;
389
		}
390
391
		/**
392
		 * Modifies the order of the gateways displayed in admin.
393
		 *
394
		 * @since 4.0.0
395
		 * @version 4.0.0
396
		 */
397
		public function filter_gateway_order_admin( $sections ) {
398
			unset( $sections['stripe'] );
399
			unset( $sections['stripe_bancontact'] );
400
			unset( $sections['stripe_sofort'] );
401
			unset( $sections['stripe_giropay'] );
402
			unset( $sections['stripe_ideal'] );
403
			unset( $sections['stripe_p24'] );
404
			unset( $sections['stripe_alipay'] );
405
			unset( $sections['stripe_sepa'] );
406
			unset( $sections['stripe_bitcoin'] );
407
408
			$sections['stripe']            = 'Stripe';
409
			$sections['stripe_bancontact'] = __( 'Stripe Bancontact', 'woocommerce-gateway-stripe' );
410
			$sections['stripe_sofort']     = __( 'Stripe SOFORT', 'woocommerce-gateway-stripe' );
411
			$sections['stripe_giropay']    = __( 'Stripe Giropay', 'woocommerce-gateway-stripe' );
412
			$sections['stripe_ideal']      = __( 'Stripe iDeal', 'woocommerce-gateway-stripe' );
413
			$sections['stripe_p24']        = __( 'Stripe P24', 'woocommerce-gateway-stripe' );
414
			$sections['stripe_alipay']     = __( 'Stripe Alipay', 'woocommerce-gateway-stripe' );
415
			$sections['stripe_sepa']       = __( 'Stripe SEPA Direct Debit', 'woocommerce-gateway-stripe' );
416
			$sections['stripe_bitcoin']    = __( 'Stripe Bitcoin', 'woocommerce-gateway-stripe' );
417
418
			return $sections;
419
		}
420
	}
421
422
	WC_Stripe::get_instance();
423
424
endif;
425