GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( 74a577...62d274 )
by Brad
02:30
created

FS_Plugin_Updater::catch_plugin_update_row()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 18 and the first side effect is on line 12.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
	/**
3
	 * @package     Freemius
4
	 * @copyright   Copyright (c) 2015, Freemius, Inc.
5
	 * @license     http://opensource.org/licenses/gpl-2.0.php GNU Public License
6
	 * @since       1.0.4
7
	 *
8
	 * @link        https://github.com/easydigitaldownloads/EDD-License-handler/blob/master/EDD_SL_Plugin_Updater.php
9
	 */
10
11
	if ( ! defined( 'ABSPATH' ) ) {
12
		exit;
13
	}
14
15
	// Uncomment this line for testing.
16
//	set_site_transient( 'update_plugins', null );
17
18
	class FS_Plugin_Updater {
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
19
20
		/**
21
		 * @var Freemius
22
		 * @since 1.0.4
23
		 */
24
		private $_fs;
25
		/**
26
		 * @var FS_Logger
27
		 * @since 1.0.4
28
		 */
29
		private $_logger;
30
		/**
31
		 * @var object
32
		 * @since 1.1.8.1
33
		 */
34
		private $_update_details;
35
36
		function __construct( Freemius $freemius ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
37
			$this->_fs = $freemius;
38
39
			$this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_' . $freemius->get_slug() . '_updater', WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );
40
41
			$this->_filters();
42
		}
43
44
		/**
45
		 * Initiate required filters.
46
		 *
47
		 * @author Vova Feldman (@svovaf)
48
		 * @since  1.0.4
49
		 */
50
		private function _filters() {
51
			// Override request for plugin information
52
			add_filter( 'plugins_api', array( &$this, 'plugins_api_filter' ), 10, 3 );
53
54
			// WP 3.0+
55
			add_filter( 'pre_set_site_transient_update_plugins', array(
56
				&$this,
57
				'pre_set_site_transient_update_plugins_filter'
58
			) );
59
60
			if ( ! $this->_fs->has_active_valid_license() ) {
61
				/**
62
				 * If user has the premium plugin's code but do NOT have an active license,
63
				 * encourage him to upgrade by showing that there's a new release, but instead
64
				 * of showing an update link, show upgrade link to the pricing page.
65
				 *
66
				 * @since 1.1.6
67
				 *
68
				 */
69
				// WP 2.9+
70
				add_action( "after_plugin_row_{$this->_fs->get_plugin_basename()}", array(
71
					&$this,
72
					'catch_plugin_update_row'
73
				), 9 );
74
				add_action( "after_plugin_row_{$this->_fs->get_plugin_basename()}", array(
75
					&$this,
76
					'edit_and_echo_plugin_update_row'
77
				), 11, 2 );
78
			}
79
80
			if ( ! WP_FS__IS_PRODUCTION_MODE ) {
81
				add_filter( 'http_request_host_is_external', array(
82
					$this,
83
					'http_request_host_is_external_filter'
84
				), 10, 3 );
85
			}
86
87
			if ( $this->_fs->is_premium() && $this->is_correct_folder_name() ) {
88
				add_filter( 'upgrader_post_install', array( &$this, '_maybe_update_folder_name' ), 10, 3 );
89
			}
90
		}
91
92
		/**
93
		 * Capture plugin update row by turning output buffering.
94
		 *
95
		 * @author Vova Feldman (@svovaf)
96
		 * @since  1.1.6
97
		 */
98
		function catch_plugin_update_row() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
99
			ob_start();
100
		}
101
102
		/**
103
		 * Overrides default update message format with "renew your license" message.
104
		 *
105
		 * @author Vova Feldman (@svovaf)
106
		 * @since  1.1.6
107
		 *
108
		 * @param string $file
109
		 * @param array  $plugin_data
110
		 */
111
		function edit_and_echo_plugin_update_row( $file, $plugin_data ) {
0 ignored issues
show
Unused Code introduced by
The parameter $plugin_data is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
112
			$plugin_update_row = ob_get_clean();
113
114
			$current = get_site_transient( 'update_plugins' );
115
			if ( ! isset( $current->response[ $file ] ) ) {
116
				echo $plugin_update_row;
117
118
				return;
119
			}
120
121
			$r = $current->response[ $file ];
122
123
			$plugin_update_row = preg_replace(
124
				'/(\<div.+>)(.+)(\<a.+\<a.+)\<\/div\>/is',
125
				'$1 $2 ' . sprintf(
126
					$this->_fs->get_text( 'renew-license-now' ),
127
					'<a href="' . $this->_fs->pricing_url() . '">', '</a>',
128
					$r->new_version ) .
129
				'$4',
130
				$plugin_update_row
131
			);
132
133
			echo $plugin_update_row;
134
		}
135
136
		/**
137
		 * Since WP version 3.6, a new security feature was added that denies access to repository with a local ip.
138
		 * During development mode we want to be able updating plugin versions via our localhost repository. This
139
		 * filter white-list all domains including "api.freemius".
140
		 *
141
		 * @link   http://www.emanueletessore.com/wordpress-download-failed-valid-url-provided/
142
		 *
143
		 * @author Vova Feldman (@svovaf)
144
		 * @since  1.0.4
145
		 *
146
		 * @param bool   $allow
147
		 * @param string $host
148
		 * @param string $url
149
		 *
150
		 * @return bool
151
		 */
152
		function http_request_host_is_external_filter( $allow, $host, $url ) {
0 ignored issues
show
Unused Code introduced by
The parameter $url is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
153
			return ( false !== strpos( $host, 'freemius' ) ) ? true : $allow;
154
		}
155
156
		/**
157
		 * Check for Updates at the defined API endpoint and modify the update array.
158
		 *
159
		 * This function dives into the update api just when WordPress creates its update array,
160
		 * then adds a custom API call and injects the custom plugin data retrieved from the API.
161
		 * It is reassembled from parts of the native WordPress plugin update code.
162
		 * See wp-includes/update.php line 121 for the original wp_update_plugins() function.
163
		 *
164
		 * @author Vova Feldman (@svovaf)
165
		 * @since  1.0.4
166
		 *
167
		 * @uses   FS_Api
168
		 *
169
		 * @param object $transient_data Update array build by WordPress.
170
		 *
171
		 * @return object Modified update array with custom plugin data.
172
		 */
173
		function pre_set_site_transient_update_plugins_filter( $transient_data ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
174
			$this->_logger->entrance();
175
176
			if ( empty( $transient_data ) ||
177
			     defined( 'WP_FS__UNINSTALL_MODE' )
178
			) {
179
				return $transient_data;
180
			}
181
182
			if ( ! isset( $this->_update_details ) ) {
183
				// Get plugin's newest update.
184
				$new_version = $this->_fs->get_update( false, false );
185
186
				$this->_update_details = false;
0 ignored issues
show
Documentation Bug introduced by
It seems like false of type false is incompatible with the declared type object of property $_update_details.

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...
187
188
				if ( is_object( $new_version ) ) {
189
					$this->_logger->log( 'Found newer plugin version ' . $new_version->version );
190
191
					$plugin_details              = new stdClass();
192
					$plugin_details->slug        = $this->_fs->get_slug();
193
					$plugin_details->new_version = $new_version->version;
194
					$plugin_details->url         = WP_FS__ADDRESS;
195
					$plugin_details->package     = $new_version->url;
196
					$plugin_details->plugin      = $this->_fs->get_plugin_basename();
197
198
					/**
199
					 * Cache plugin details locally since set_site_transient( 'update_plugins' )
200
					 * called multiple times and the non wp.org plugins are filtered after the
201
					 * call to .org.
202
					 *
203
					 * @since 1.1.8.1
204
					 */
205
					$this->_update_details = $plugin_details;
206
				}
207
			}
208
209
			if ( is_object( $this->_update_details ) ) {
210
				// Add plugin to transient data.
211
				$transient_data->response[ $this->_fs->get_plugin_basename() ] = $this->_update_details;
212
			}
213
214
			return $transient_data;
215
		}
216
217
		/**
218
		 * Try to fetch plugin's info from .org repository.
219
		 *
220
		 * @author Vova Feldman (@svovaf)
221
		 * @since  1.0.5
222
		 *
223
		 * @param string $action
224
		 * @param object $args
225
		 *
226
		 * @return bool|mixed
227
		 */
228
		static function _fetch_plugin_info_from_repository( $action, $args ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
229
			$url = $http_url = 'http://api.wordpress.org/plugins/info/1.0/';
0 ignored issues
show
Unused Code introduced by
$http_url is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
230
			if ( $ssl = wp_http_supports( array( 'ssl' ) ) ) {
0 ignored issues
show
Unused Code introduced by
$ssl is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
231
				$url = set_url_scheme( $url, 'https' );
232
			}
233
234
			$args = array(
235
				'timeout' => 15,
236
				'body'    => array(
237
					'action'  => $action,
238
					'request' => serialize( $args )
239
				)
240
			);
241
242
			$request = wp_remote_post( $url, $args );
243
244
			if ( is_wp_error( $request ) ) {
245
				return false;
246
			}
247
248
			$res = maybe_unserialize( wp_remote_retrieve_body( $request ) );
249
250
			if ( ! is_object( $res ) && ! is_array( $res ) ) {
251
				return false;
252
			}
253
254
			return $res;
255
		}
256
257
		/**
258
		 * Updates information on the "View version x.x details" page with custom data.
259
		 *
260
		 * @author Vova Feldman (@svovaf)
261
		 * @since  1.0.4
262
		 *
263
		 * @uses   FS_Api
264
		 *
265
		 * @param object $data
266
		 * @param string $action
267
		 * @param mixed  $args
268
		 *
269
		 * @return object
270
		 */
271
		function plugins_api_filter( $data, $action = '', $args = null ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
272
			$this->_logger->entrance();
273
274
			if ( ( 'plugin_information' !== $action ) ||
275
			     ! isset( $args->slug )
276
			) {
277
				return $data;
278
			}
279
280
			$addon    = false;
281
			$is_addon = false;
282
283
			if ( $this->_fs->get_slug() !== $args->slug ) {
284
				$addon = $this->_fs->get_addon_by_slug( $args->slug );
285
286
				if ( ! is_object( $addon ) ) {
287
					return $data;
288
				}
289
290
				$is_addon = true;
291
			}
292
293
			$plugin_in_repo = false;
294
			if ( ! $is_addon ) {
295
				// Try to fetch info from .org repository.
296
				$data = self::_fetch_plugin_info_from_repository( $action, $args );
297
298
				$plugin_in_repo = ( false !== $data );
299
			}
300
301
			if ( ! $plugin_in_repo ) {
302
				$data = $args;
303
304
				// Fetch as much as possible info from local files.
305
				$plugin_local_data = $this->_fs->get_plugin_data();
306
				$data->name        = $plugin_local_data['Name'];
307
				$data->author      = $plugin_local_data['Author'];
308
				$data->sections    = array(
309
					'description' => 'Upgrade ' . $plugin_local_data['Name'] . ' to latest.',
310
				);
311
312
				// @todo Store extra plugin info on Freemius or parse readme.txt markup.
313
				/*$info = $this->_fs->get_api_site_scope()->call('/information.json');
0 ignored issues
show
Unused Code Comprehensibility introduced by
59% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
314
315
if ( !isset($info->error) ) {
316
	$data = $info;
317
}*/
318
			}
319
320
			// Get plugin's newest update.
321
			$new_version = $this->get_latest_download_details( $is_addon ? $addon->id : false );
322
323
			if ( ! is_object( $new_version ) || empty( $new_version->version ) ) {
324
				$data->version = $this->_fs->get_plugin_version();
325
			} else {
326
				if ( $is_addon ) {
327
					$data->name    = $addon->title . ' ' . $this->_fs->get_text( 'addon' );
328
					$data->slug    = $addon->slug;
329
					$data->url     = WP_FS__ADDRESS;
330
					$data->package = $new_version->url;
331
				}
332
333
				if ( ! $plugin_in_repo ) {
334
					$data->last_updated = ! is_null( $new_version->updated ) ? $new_version->updated : $new_version->created;
335
					$data->requires     = $new_version->requires_platform_version;
336
					$data->tested       = $new_version->tested_up_to_version;
337
				}
338
339
				$data->version       = $new_version->version;
340
				$data->download_link = $new_version->url;
341
			}
342
343
			return $data;
344
		}
345
346
		/**
347
		 * @author Vova Feldman (@svovaf)
348
		 * @since  1.2.1.7
349
		 *
350
		 * @param number|bool $addon_id
351
		 *
352
		 * @return object
353
		 */
354
		private function get_latest_download_details( $addon_id = false ) {
355
			return $this->_fs->_fetch_latest_version( $addon_id );
356
		}
357
358
		/**
359
		 * Checks if a given basename has a matching folder name
360
		 * with the current context plugin.
361
		 *
362
		 * @author Vova Feldman (@svovaf)
363
		 * @since  1.2.1.6
364
		 *
365
		 * @param string $basename Current plugin's basename.
366
		 *
367
		 * @return bool
368
		 */
369
		private function is_correct_folder_name( $basename = '' ) {
370
			if ( empty( $basename ) ) {
371
				$basename = $this->_fs->get_plugin_basename();
372
			}
373
374
			return ( $this->_fs->get_target_folder_name() != trim( dirname( $basename ), '/\\' ) );
375
		}
376
377
		/**
378
		 * This is a special after upgrade handler for migrating modules
379
		 * that didn't use the '-premium' suffix folder structure before
380
		 * the migration.
381
		 *
382
		 * @author Vova Feldman (@svovaf)
383
		 * @since  1.2.1.6
384
		 *
385
		 * @param bool  $response   Install response.
386
		 * @param array $hook_extra Extra arguments passed to hooked filters.
387
		 * @param array $result     Installation result data.
388
		 *
389
		 * @return bool
390
		 */
391
		function _maybe_update_folder_name( $response, $hook_extra, $result ) {
0 ignored issues
show
Unused Code introduced by
The parameter $result is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
392
			$basename = $this->_fs->get_plugin_basename();
393
394
			if ( true !== $response ||
395
			     empty( $hook_extra ) ||
396
			     empty( $hook_extra['plugin'] ) ||
397
			     $basename !== $hook_extra['plugin']
398
			) {
399
				return $response;
400
			}
401
402
			$active_plugins_basenames = get_option( 'active_plugins' );
403
404
			for ( $i = 0, $len = count( $active_plugins_basenames ); $i < $len; $i ++ ) {
405
				if ( $basename === $active_plugins_basenames[ $i ] ) {
406
					// Get filename including extension.
407
					$filename = basename( $basename );
408
409
					$new_basename = plugin_basename(
410
						trailingslashit( $this->_fs->get_slug() . ( $this->_fs->is_premium() ? '-premium' : '' ) ) .
411
						$filename
412
					);
413
414
					// Verify that the expected correct path exists.
415
					if ( file_exists( fs_normalize_path( WP_PLUGIN_DIR . '/' . $new_basename ) ) ) {
416
						// Override active plugin name.
417
						$active_plugins_basenames[ $i ] = $new_basename;
418
						update_option( 'active_plugins', $active_plugins_basenames );
419
					}
420
421
					break;
422
				}
423
			}
424
425
			return $response;
426
		}
427
428
		#----------------------------------------------------------------------------------
429
		#region Auto Activation
430
		#----------------------------------------------------------------------------------
431
432
		/**
433
		 * Installs and active a plugin when explicitly requested that from a 3rd party service.
434
		 *
435
		 * This logic was inspired by the TGMPA GPL licensed library by Thomas Griffin.
436
		 *
437
		 * @link   http://tgmpluginactivation.com/
438
		 *
439
		 * @author Vova Feldman
440
		 * @since  1.2.1.7
441
		 *
442
		 * @link   https://make.wordpress.org/plugins/2017/03/16/clarification-of-guideline-8-executable-code-and-installs/
443
		 *
444
		 * @uses   WP_Filesystem
445
		 * @uses   WP_Error
446
		 * @uses   WP_Upgrader
447
		 * @uses   Plugin_Upgrader
448
		 * @uses   Plugin_Installer_Skin
449
		 * @uses   Plugin_Upgrader_Skin
450
		 *
451
		 * @param number|bool $plugin_id
452
		 *
453
		 * @return array
454
		 */
455
		function install_and_activate_plugin( $plugin_id = false ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
456
			if ( ! empty( $plugin_id ) && ! FS_Plugin::is_valid_id( $plugin_id ) ) {
457
				// Invalid plugin ID.
458
				return array(
459
					'message' => $this->_fs->get_text( 'auto-install-error-invalid-id' ),
460
					'code'    => 'invalid_module_id',
461
				);
462
			}
463
464
			$is_addon = false;
465
			if ( FS_Plugin::is_valid_id( $plugin_id ) &&
466
			     $plugin_id != $this->_fs->get_id()
467
			) {
468
				$addon = $this->_fs->get_addon( $plugin_id );
0 ignored issues
show
Bug introduced by
It seems like $plugin_id defined by parameter $plugin_id on line 455 can also be of type boolean; however, Freemius::get_addon() does only seem to accept integer|double, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
469
470
				if ( ! is_object( $addon ) ) {
471
					// Invalid add-on ID.
472
					return array(
473
						'message' => $this->_fs->get_text( 'auto-install-error-invalid-id' ),
474
						'code'    => 'invalid_module_id',
475
					);
476
				}
477
478
				$slug  = $addon->slug;
479
				$title = $addon->title . ' ' . $this->_fs->get_text( 'addon' );
480
481
				$is_addon = true;
482
			} else {
483
				$slug  = $this->_fs->get_slug();
484
				$title = $this->_fs->get_plugin_title() .
485
				         ( $this->_fs->is_addon() ? ' ' . $this->_fs->get_text( 'addon' ) : '' );
486
			}
487
488
			if ( $this->is_premium_plugin_active( $plugin_id ) ) {
489
				// Premium version already activated.
490
				return array(
491
					'message' => $this->_fs->get_text(
492
						$is_addon ?
493
							'auto-install-error-premium-addon-activated' :
494
							'auto-install-error-premium-activated'
495
					),
496
					'code'    => 'premium_installed',
497
				);
498
			}
499
500
			$latest_version = $this->get_latest_download_details( $plugin_id );
501
			$target_folder  = "{$slug}-premium";
502
503
			// Prep variables for Plugin_Installer_Skin class.
504
			$extra         = array();
505
			$extra['slug'] = $target_folder;
506
			$source        = $latest_version->url;
507
			$api           = null;
508
509
			$install_url = add_query_arg(
510
				array(
511
					'action' => 'install-plugin',
512
					'plugin' => urlencode( $slug ),
513
				),
514
				'update.php'
515
			);
516
517
			if ( ! class_exists( 'Plugin_Upgrader', false ) ) {
518
				// Include required resources for the installation.
519
				require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
520
			}
521
522
			$skin_args = array(
523
				'type'   => 'web',
524
				'title'  => sprintf( fs_text( 'installing-plugin-x', $slug ), $title ),
525
				'url'    => esc_url_raw( $install_url ),
526
				'nonce'  => 'install-plugin_' . $slug,
527
				'plugin' => '',
528
				'api'    => $api,
529
				'extra'  => $extra,
530
			);
531
532
//			$skin = new Automatic_Upgrader_Skin( $skin_args );
0 ignored issues
show
Unused Code Comprehensibility introduced by
42% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
533
//			$skin = new Plugin_Installer_Skin( $skin_args );
534
			$skin = new WP_Ajax_Upgrader_Skin( $skin_args );
535
536
			// Create a new instance of Plugin_Upgrader.
537
			$upgrader = new Plugin_Upgrader( $skin );
538
539
			// Perform the action and install the plugin from the $source urldecode().
540
			add_filter( 'upgrader_source_selection', array( &$this, '_maybe_adjust_source_dir' ), 1, 3 );
541
542
			$install_result = $upgrader->install( $source );
543
544
			remove_filter( 'upgrader_source_selection', array( &$this, '_maybe_adjust_source_dir' ), 1 );
545
546
			if ( is_wp_error( $install_result ) ) {
547
				return array(
548
					'message' => $install_result->get_error_message(),
549
					'code'    => $install_result->get_error_code(),
550
				);
551
			} elseif ( is_wp_error( $skin->result ) ) {
552
				return array(
553
					'message' => $skin->result->get_error_message(),
554
					'code'    => $skin->result->get_error_code(),
555
				);
556
			} elseif ( $skin->get_errors()->get_error_code() ) {
557
				return array(
558
					'message' => $skin->get_error_messages(),
559
					'code'    => 'unknown',
560
				);
561
			} elseif ( is_null( $install_result ) ) {
562
				global $wp_filesystem;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
563
564
				$error_code    = 'unable_to_connect_to_filesystem';
565
				$error_message = __( 'Unable to connect to the filesystem. Please confirm your credentials.' );
566
567
				// Pass through the error from WP_Filesystem if one was raised.
568
				if ( $wp_filesystem instanceof WP_Filesystem_Base &&
0 ignored issues
show
Bug introduced by
The class WP_Filesystem_Base does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
569
				     is_wp_error( $wp_filesystem->errors ) &&
570
				     $wp_filesystem->errors->get_error_code()
571
				) {
572
					$error_message = $wp_filesystem->errors->get_error_message();
573
				}
574
575
				return array(
576
					'message' => $error_message,
577
					'code'    => $error_code,
578
				);
579
			}
580
581
			// Grab the full path to the main plugin's file.
582
			$plugin_activate = $upgrader->plugin_info();
583
584
			// Try to activate the plugin.
585
			$activation_result = $this->try_activate_plugin( $plugin_activate );
586
587
			if ( is_wp_error( $activation_result ) ) {
588
				return array(
589
					'message' => $activation_result->get_error_message(),
590
					'code'    => $activation_result->get_error_code(),
591
				);
592
			}
593
594
			return $skin->get_upgrade_messages();
595
		}
596
597
		/**
598
		 * Tries to activate a plugin. If fails, returns the error.
599
		 *
600
		 * @author Vova Feldman
601
		 * @since  1.2.1.7
602
		 *
603
		 * @param string $file_path Path within wp-plugins/ to main plugin file.
604
		 *                          This determines the styling of the output messages.
605
		 *
606
		 * @return bool|WP_Error
607
		 */
608
		protected function try_activate_plugin( $file_path ) {
609
			$activate = activate_plugin( $file_path );
610
611
			return is_wp_error( $activate ) ?
612
				$activate :
613
				true;
614
		}
615
616
		/**
617
		 * Check if a premium module version is already active.
618
		 *
619
		 * @author Vova Feldman
620
		 * @since  1.2.1.7
621
		 *
622
		 * @param number|bool $plugin_id
623
		 *
624
		 * @return bool
625
		 */
626
		private function is_premium_plugin_active( $plugin_id = false ) {
627
			if ( $plugin_id != $this->_fs->get_id() ) {
628
				return $this->_fs->is_addon_activated( $plugin_id, true );
0 ignored issues
show
Bug introduced by
It seems like $plugin_id defined by parameter $plugin_id on line 626 can also be of type boolean; however, Freemius::is_addon_activated() does only seem to accept string|integer|double, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
629
			}
630
631
			return is_plugin_active( $this->_fs->premium_plugin_basename() );
632
		}
633
634
		/**
635
		 * Adjust the plugin directory name if necessary.
636
		 * Assumes plugin has a folder (not a single file plugin).
637
		 *
638
		 * The final destination directory of a plugin is based on the subdirectory name found in the
639
		 * (un)zipped source. In some cases this subdirectory name is not the same as the expected
640
		 * slug and the plugin will not be recognized as installed. This is fixed by adjusting
641
		 * the temporary unzipped source subdirectory name to the expected plugin slug.
642
		 *
643
		 * @author Vova Feldman
644
		 * @since  1.2.1.7
645
		 *
646
		 * @param string       $source        Path to upgrade/zip-file-name.tmp/subdirectory/.
647
		 * @param string       $remote_source Path to upgrade/zip-file-name.tmp.
648
		 * @param \WP_Upgrader $upgrader      Instance of the upgrader which installs the plugin.
649
		 *
650
		 * @return string|WP_Error
651
		 */
652
		function _maybe_adjust_source_dir( $source, $remote_source, $upgrader ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
Coding Style introduced by
_maybe_adjust_source_dir uses the super-global variable $GLOBALS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
653
			if ( ! is_object( $GLOBALS['wp_filesystem'] ) ) {
654
				return $source;
655
			}
656
657
			// Figure out what the slug is supposed to be.
658
			$desired_slug = $upgrader->skin->options['extra']['slug'];
659
660
			$subdir_name = untrailingslashit( str_replace( trailingslashit( $remote_source ), '', $source ) );
661
662
			if ( ! empty( $subdir_name ) && $subdir_name !== $desired_slug ) {
663
				$from_path = untrailingslashit( $source );
664
				$to_path   = trailingslashit( $remote_source ) . $desired_slug;
665
666
				if ( true === $GLOBALS['wp_filesystem']->move( $from_path, $to_path ) ) {
667
					return trailingslashit( $to_path );
668
				} else {
669
					return new WP_Error(
670
						'rename_failed',
671
						$this->_fs->get_text( 'module-package-rename-failure' ),
672
						array(
673
							'found'    => $subdir_name,
674
							'expected' => $desired_slug
675
						) );
676
				}
677
			}
678
679
			return $source;
680
		}
681
682
		#endregion
683
	}