Completed
Push — develop ( 487ebd...189ab7 )
by Zack
17:39
created

License_Handler::license_call()   D

Complexity

Conditions 18
Paths 312

Size

Total Lines 68
Code Lines 39

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 28
CRAP Score 18.6328

Importance

Changes 0
Metric Value
cc 18
eloc 39
nc 312
nop 2
dl 0
loc 68
ccs 28
cts 32
cp 0.875
crap 18.6328
rs 4.2723
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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 14 and the first side effect is on line 6.

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
namespace GV;
3
4
/** If this file is called directly, abort. */
5
if ( ! defined( 'GRAVITYVIEW_DIR' ) ) {
6
	die();
7
}
8
9
/**
10
 * The \GV\License_Handler class.
11
 *
12
 * Handles everything licensing. Ka-ching!
13
 */
14
class License_Handler {
0 ignored issues
show
Coding Style introduced by
Since you have declared the constructor as private, maybe you should also declare the class as final.
Loading history...
15
	/**
16
	 * @var \GV\Addon_Settings The global addon settings binding.
17
	 */
18
	private $settings;
19
20
	const name = 'GravityView';
21
	const author = 'Katz Web Services, Inc.';
22
	const url = 'https://gravityview.co';
23
24
	/**
25
	 * Post ID on gravityview.co
26
	 * @since 1.15
27
	 */
28
	const item_id = 17;
29
30
	/**
31
	 * Name of the transient used to store license status for GV
32
	 * @since 1.17
33
	 */
34
	const status_transient_key = 'gravityview_edd-activate_valid';
35
36
	/**
37
	 * @var string Key used to store active GravityView/Gravity Forms plugin data
38
	 * @since 1.15
39
	 */
40
	const related_plugins_key = 'gravityview_related_plugins';
41
42
	/** @var \GV\EDD_SL_Plugin_Updater */
43
	private $EDD_SL_Plugin_Updater;
44
45
	/**
46
	 * @var \GV\License_Handler
47
	 */
48
	private static $__instance;
49
50 1
	private function __construct( $settings ) {
51
52 1
		$this->settings = $settings;
53
		
54 1
		if ( ! $this->settings instanceof Addon_Settings ) {
55
			$this->settings = gravityview()->settings;
0 ignored issues
show
Documentation introduced by
The property settings does not exist on object<GV\Core>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
56
		}
57
58 1
		add_action( 'admin_init', array( $this, 'setup_edd' ), 0 );
59 1
		add_action( 'wp_ajax_gravityview_license', array( $this, 'license_call' ) );
60 1
		add_action( 'admin_init', array( $this, 'refresh_license_status' ) );
61 1
		add_action( 'admin_init', array( $this, 'check_license' ) );
62 1
		add_action( 'update_option_active_plugins', array( $this, 'flush_related_plugins_transient' ) );
63 1
		add_action( 'update_option_active_sitewide_plugins', array( $this, 'flush_related_plugins_transient' ) );
64 1
	}
65
66
	/**
67
	 * @return \GV\License_Handler The global instance.
68
	 */
69 2
	public static function get( $settings = null ) {
70 2
		if ( ! self::$__instance ) {
71 1
			self::$__instance = new self( $settings );
72
		}
73 2
		return self::$__instance;
74
	}
75
76
	/**
77
	 * Generate the array of settings passed to the EDD license call
78
	 *
79
	 * @since 1.7.4
80
	 *
81
	 * @param string $action The action to send to edd, such as `check_license`
82
	 * @param string $license The license key to have passed to EDD
83
	 *
84
	 * @return array
85
	 */
86 1
	private function _get_edd_settings( $action = '', $license = '' ) {
87
88
		// retrieve our license key from the DB
89 1
		$license_key = empty( $license ) ? trim( $this->settings->get( 'license_key' ) ) : $license;
90
91
		$settings = array(
92 1
			'version'   => Plugin::$version,
93 1
			'license'   => $license_key,
94 1
			'item_name' => self::name,
95 1
			'item_id'   => self::item_id,
96 1
			'author'    => self::author,
97 1
			'language'  => get_locale(),
98 1
			'url'       => home_url(),
99 1
		    'beta'      => $this->settings->get( 'beta' ),
100
		);
101
102 1
		if ( ! empty( $action ) ) {
103 1
			$settings['edd_action'] = esc_attr( $action );
104
		}
105
106 1
		return array_map( 'urlencode', $settings );
107
	}
108
109
	/**
110
	 * Include the EDD plugin updater class, if not exists
111
	 *
112
	 * @since 1.7.4
113
	 * @since 1.21.5.3 Changed visibility of method to public
114
	 *
115
	 * @return void
116
	 */
117 1
	public function setup_edd() {
118 1
		if ( ! class_exists( '\GV\EDD_SL_Plugin_Updater' ) ) {
119 1
			require_once gravityview()->plugin->dir( 'future/lib/EDD_SL_Plugin_Updater.php' );
120
		}
121
122
		// setup the updater
123 1
		$this->EDD_SL_Plugin_Updater = new EDD_SL_Plugin_Updater(
124 1
			self::url,
125 1
			GRAVITYVIEW_FILE,
126 1
			$this->_get_edd_settings()
127
		);
128 1
	}
129
130
	/**
131
	 * Perform the call to EDD based on the AJAX call or passed data
132
	 *
133
	 * @since 1.7.4
134
	 *
135
	 * @param array $array {
136
	 * @type string $license The license key
137
	 * @type string $edd_action The EDD action to perform, like `check_license`
138
	 * @type string $field_id The ID of the field to check
139
	 * @type boolean $update Whether to update plugin settings. Prevent updating the data by setting an `update` key to false
140
	 * @type string $format If `object`, return the object of the license data. Else, return the JSON-encoded object
141
	 * }
142
	 * @param boolean $cap_check Require `gravityview_edit_settings` capability from current user.
143
	 *
144
	 * @return mixed|string|void
145
	 */
146 1
	public function license_call( $array = array(), $cap_check = true ) {
147
148 1
		$is_ajax = ( defined( 'DOING_AJAX' ) && DOING_AJAX );
149 1
		$data = empty( $array ) ? Utils::_POST( 'data', array() ) : $array;
150
151 1
		$data = wp_parse_args( $data, array(
152 1
			'license' => '',
153
			'edd_action' => '',
154
			'field_id' => '',
155
			'update' => '',
156
			'format' => 'json',
157
		) );
158
159 1
		if ( $is_ajax && empty( $data['license'] ) ) {
160
			die( -1 );
0 ignored issues
show
Coding Style Compatibility introduced by
The method license_call() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
161
		}
162
163
		// If the user isn't allowed to edit settings, show an error message
164 1
		if ( $cap_check && ! \GVCommon::has_cap( 'gravityview_edit_settings' ) ) {
165 1
			$license_data = new \stdClass();
166 1
			$license_data->error = 'capability';
167 1
			$license_data->message = $this->get_license_message( $license_data );
168 1
			$json = json_encode( $license_data );
169
		} else {
170 1
			$license      = esc_attr( Utils::get( $data, 'license' ) );
171 1
			$license_data = $this->_license_get_remote_response( $data, $license );
172
173
			// Empty is returned when there's an error.
174 1
			if ( empty( $license_data ) ) {
175 1
				if ( $is_ajax ) {
176
					exit( json_encode( array() ) );
0 ignored issues
show
Coding Style Compatibility introduced by
The method license_call() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
177
				} else { // Non-ajax call
178 1
					return json_encode( array() );
179
				}
180
			}
181
182 1
			$license_data->details = $this->license_details( $license_data );
183 1
			$license_data->message = $this->get_license_message( $license_data );
184
185 1
			$json = json_encode( $license_data );
186
187 1
			$update_license = Utils::get( $data, 'update' ) || 'gravityview_license' === Utils::_POST('action');
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
188
189 1
			$is_check_action_button = ( 'check_license' === Utils::get( $data, 'edd_action' ) && defined( 'DOING_AJAX' ) && DOING_AJAX );
190
191 1
			if ( $is_check_action_button ) {
192
				delete_transient( self::status_transient_key );
193
194
			// Failed is the response from trying to de-activate a license and it didn't work.
195
			// This likely happened because people entered in a different key and clicked "Deactivate",
196
			// meaning to deactivate the original key. We don't want to save this response, since it is
197
			// most likely a mistake.
198 1
			} else if ( $license_data->license !== 'failed' && $update_license ) {
0 ignored issues
show
introduced by
Found "!== '". Use Yoda Condition checks, you must
Loading history...
199
200 1
				if ( ! empty( $data['field_id'] ) ) {
201 1
					set_transient( self::status_transient_key, $license_data, DAY_IN_SECONDS );
202
				}
203
204 1
				$this->license_call_update_settings( $license_data, $data );
205
			}
206
		}
207
208 1
		if ( $is_ajax ) {
209
			exit( $json );
0 ignored issues
show
Coding Style Compatibility introduced by
The method license_call() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
210
		} else { // Non-ajax call
211 1
			return ( Utils::_GET( 'format', Utils::get( $data, 'format' ) ) === 'object' ) ? $license_data : $json;
212
		}
213
	}
214
215
	/**
216
	 * Generate the status message displayed in the license field
217
	 *
218
	 * @since 1.7.4
219
	 * @param $license_data
220
	 *
221
	 * @return string
222
	 */
223 2
	private function get_license_message( $license_data ) {
224 2
		if ( empty( $license_data ) ) {
225 2
			$message = '';
226
		} else {
227 1
			if( ! empty( $license_data->error ) ) {
228 1
				$class = 'error';
229 1
				$string_key = $license_data->error;
230 1
			} else { $class = $license_data->license;
231 1
				$string_key = $license_data->license;
232
			}
233
234 1
			$message = sprintf( '<p><strong>%s: %s</strong></p>', $this->strings( 'status' ), $this->strings( $string_key, $license_data ) );
235
236 1
			$message = $this->generate_license_box( $message, $class );
237
		}
238
239 2
		return $message;
240
	}
241
242
	/**
243
	 * Allow pure HTML in settings fields
244
	 *
245
	 * @since 1.17
246
	 *
247
	 * @param array $response License response
248
	 *
249
	 * @return string `html` key of the $field
250
	 */
251 2
	public function license_details( $response = array() ) {
252
253 2
		$response = (array) $response;
254
255 2
		$return = '';
256 2
		$wrapper = '<span class="gv-license-details" aria-live="polite" aria-busy="false">%s</span>';
257
258 2
		if ( ! empty( $response['license_key'] ) ) {
259 1
			$return .= '<h3>' . esc_html__( 'License Details:', 'gravityview' ) . '</h3>';
260
261 1
			if ( in_array( Utils::get( $response, 'license' ), array( 'invalid', 'deactivated' ) ) ) {
262 1
				$return .= $this->strings( $response['license'], $response );
263 1
			} elseif ( ! empty( $response['license_name'] ) ) {
264
				$response_keys = array(
265 1
					'license_name'   => '',
266
					'license_limit'  => '',
267
					'customer_name'  => '',
268
					'customer_email' => '',
269
					'site_count'     => '',
270
					'expires'        => '',
271
					'upgrades'       => ''
0 ignored issues
show
introduced by
Each line in an array declaration must end in a comma
Loading history...
272
				);
273
274
				// Make sure all the keys are set
275 1
				$response = wp_parse_args( $response, $response_keys );
276
277 1
				$login_link = sprintf( '<a href="%s" class="howto" rel="external">%s</a>', esc_url( sprintf( 'https://gravityview.co/wp-login.php?username=%s', $response['customer_email'] ) ), esc_html__( 'Access your GravityView account', 'gravityview' ) );
278 1
				$local_text = ( ! empty( $response['is_local'] ) ? '<span class="howto">' . __( 'This development site does not count toward license activation limits', 'gravityview' ) . '</span>' : '' );
279
				$details    = array(
280 1
					'license'     => sprintf( esc_html__( 'License level: %s', 'gravityview' ), esc_html( $response['license_name'] ), esc_html( $response['license_limit'] ) ),
281 1
					'licensed_to' => sprintf( esc_html_x( 'Licensed to: %1$s (%2$s)', '1: Customer name; 2: Customer email', 'gravityview' ), esc_html__( $response['customer_name'], 'gravityview' ), esc_html__( $response['customer_email'], 'gravityview' ) ) . $login_link,
282 1
					'activations' => sprintf( esc_html__( 'Activations: %d of %s sites', 'gravityview' ), intval( $response['site_count'] ), esc_html( $response['license_limit'] ) ) . $local_text,
283 1
					'expires'     => 'lifetime' === $response['expires'] ? '' : sprintf( esc_html__( 'Renew on: %s', 'gravityview' ), date_i18n( get_option( 'date_format' ), strtotime( $response['expires'] ) - DAY_IN_SECONDS ) ),
284 1
					'upgrade'     => $this->get_upgrade_html( $response['upgrades'] ),
285
				);
286
287 1
				if ( ! empty( $response['error'] ) && 'expired' === $response['error'] ) {
288
					unset( $details['upgrade'] );
289
					$details['expires'] = '<div class="error inline"><p>' . $this->strings( 'expired', $response ) . '</p></div>';
290
				}
291
292 1
				$return .= '<ul><li>' . implode( '</li><li>', array_filter( $details ) ) . '</li></ul>';
293
			}
294
		}
295
296 2
		return sprintf( $wrapper, $return );
297
	}
298
299
	/**
300
	 * Display possible upgrades for a license
301
	 *
302
	 * @since 1.17
303
	 *
304
	 * @param array $upgrades Array of upgrade paths, returned from the GV website
305
	 *
306
	 * @return string HTML list of upgrades available for the current license
307
	 */
308 1
	private function get_upgrade_html( $upgrades ) {
309
310 1
		$output = '';
311
312 1
		if ( ! empty( $upgrades ) ) {
313
314 1
			$locale_parts = explode( '_', get_locale() );
315 1
			$is_english = ( 'en' === $locale_parts[0] );
316
317 1
			$output .= '<h4>' . esc_html__( 'Upgrades available:', 'gravityview' ) . '</h4>';
318 1
			$output .= '<ul class="ul-disc">';
319
320 1
			foreach ( $upgrades as $upgrade_id => $upgrade ) {
321 1
				$upgrade = (object) $upgrade;
322
323 1
				$anchor_text = sprintf( esc_html_x( 'Upgrade to %1$s for %2$s', '1: GravityView upgrade name, 2: Cost of upgrade', 'gravityview' ), esc_attr( $upgrade->name ), esc_attr( $upgrade->price ) );
324
325 1
				if ( $is_english && isset( $upgrade->description ) ) {
326 1
					$message = esc_html( $upgrade->description );
327
				} else {
328
					switch( $upgrade->price_id ) {
329
						// Interstellar
330
						case 1:
331
						default:
332
							$message = esc_html__( 'Get access to Extensions', 'gravityview' );
333
							break;
334
						// Galactic
335
						case 2:
0 ignored issues
show
Unused Code introduced by
case 2: $message = e...avityview'); break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
336
							$message = esc_html__( 'Get access to Entry Importer and other Premium plugins', 'gravityview' );
337
							break;
338
					}
339
				}
340
341 1
				$output .= sprintf( '<li><a href="%s">%s</a><span class="howto">%s</span></li>', esc_url( add_query_arg( array( 'utm_source' => 'settings', 'utm_medium' => 'admin', 'utm_content' => 'license-details', 'utm_campaign' => 'Upgrades' ), $upgrade->url ) ), $anchor_text, $message );
342
			}
343 1
			$output .= '</ul>';
344
		}
345
346 1
		return $output;
347
	}
348
349
	/**
350
	 * Generate the status message box HTML based on the current status
351
	 *
352
	 * @since 1.7.4
353
	 * @param $message
354
	 * @param string $class
355
	 *
356
	 * @return string
357
	 */
358 1
	private function generate_license_box( $message, $class = '' ) {
359 1
		$template = '<div id="gv-edd-status" aria-live="polite" aria-busy="false" class="gv-edd-message inline %s">%s</div>';
360
361 1
		$output = sprintf( $template, esc_attr( $class ), $message );
362
363 1
		return $output;
364
	}
365
366
	/**
367
	 * Override the text used in the GravityView EDD license Javascript
368
	 *
369
	 * @param  array|null $status Status to get. If empty, get all strings.
370
	 * @param  object|null $license_data Object with license data
371
	 * @return array          Modified array of content
372
	 */
373 1
	public function strings( $status = NULL, $license_data = null ) {
0 ignored issues
show
Coding Style introduced by
TRUE, FALSE and NULL must be lowercase; expected null, but found NULL.
Loading history...
374
		$strings = array(
375 1
			'status' => esc_html__( 'Status', 'gravityview' ),
376 1
			'error' => esc_html__( 'There was an error processing the request.', 'gravityview' ),
377 1
			'failed'  => esc_html__( 'Could not deactivate the license. The license key you attempted to deactivate may not be active or valid.', 'gravityview' ),
378 1
			'site_inactive' => esc_html__( 'The license key is valid, but it has not been activated for this site.', 'gravityview' ),
379 1
			'inactive' => esc_html__( 'The license key is valid, but it has not been activated for this site.', 'gravityview' ),
380 1
			'no_activations_left' => esc_html__( 'Invalid: this license has reached its activation limit.', 'gravityview' ) . ' ' . sprintf( esc_html__( 'You can manage license activations %son your GravityView account page%s.', 'gravityview' ), '<a href="https://gravityview.co/account/#licenses">', '</a>' ),
381 1
			'deactivated' => esc_html__( 'The license has been deactivated.', 'gravityview' ),
382 1
			'valid' => esc_html__( 'The license key is valid and active.', 'gravityview' ),
383 1
			'invalid' => esc_html__( 'The license key entered is invalid.', 'gravityview' ),
384 1
			'missing' => esc_html__( 'Invalid license key.', 'gravityview' ),
385 1
			'revoked' => esc_html__( 'This license key has been revoked.', 'gravityview' ),
386 1
			'expired' => sprintf( esc_html__( 'This license key has expired. %sRenew your license on the GravityView website%s to receive updates and support.', 'gravityview' ), '<a href="'. esc_url( $this->get_license_renewal_url( $license_data ) ) .'">', '</a>' ),
387 1
			'capability' => esc_html__( 'You don\'t have the ability to edit plugin settings.', 'gravityview' ),
388
389 1
			'verifying_license' => esc_html__( 'Verifying license&hellip;', 'gravityview' ),
390 1
			'activate_license' => esc_html__( 'Activate License', 'gravityview' ),
391 1
			'deactivate_license' => esc_html__( 'Deactivate License', 'gravityview' ),
392 1
			'check_license' => esc_html__( 'Verify License', 'gravityview' ),
393
		);
394
395 1
		return Utils::get( $strings, $status, null );
396
	}
397
398
	/**
399
	 * URL to direct license renewal, or if license key is not set, then just the account page
400
	 * @since 1.13.1
401
	 * @param  object|null $license_data Object with license data
402
	 * @return string Renewal or account URL
403
	 */
404 1
	private function get_license_renewal_url( $license_data ) {
405 1
		$license_data = is_array( $license_data ) ? (object)$license_data : $license_data;
0 ignored issues
show
introduced by
No space after closing casting parenthesis is prohibited
Loading history...
406
407 1
		if ( ! empty( $license_data->renewal_url ) ) {
408
			$renew_license_url = $license_data->renewal_url;
409 1
		} elseif( ! empty( $license_data->license_key ) ) {
410 1
			$renew_license_url = sprintf( 'https://gravityview.co/checkout/?download_id=17&edd_license_key=%s', $license_data->license_key );
411
		} else {
412 1
			$renew_license_url = 'https://gravityview.co/account/';
413
		}
414
415 1
		$renew_license_url = add_query_arg( wp_parse_args( 'utm_source=admin_notice&utm_medium=admin&utm_content=expired&utm_campaign=Activation&force_login=1' ), $renew_license_url );
416
417 1
		return $renew_license_url;
418
	}
419
420
	/**
421
	 * Perform the call
422
	 *
423
	 * @return array|\WP_Error
424
	 */
425 1
	private function _license_get_remote_response( $data, $license = '' ) {
426 1
		$api_params = $this->_get_edd_settings( $data['edd_action'], $license );
427
428 1
		$url = add_query_arg( $api_params, self::url );
429
430 1
		$response = wp_remote_get( $url, array(
0 ignored issues
show
introduced by
wp_remote_get is highly discouraged, please use vip_safe_wp_remote_get() instead.
Loading history...
431 1
			'timeout'   => 15,
432
			'sslverify' => false,
433
		) );
434
435 1
		if ( is_wp_error( $response ) ) {
436
			gravityview()->log->error( 'WP_Error response from license check. API params:', array( 'data' => $api_params ) );
437
			return array();
438
		}
439
440 1
		$license_data = json_decode( wp_remote_retrieve_body( $response ) );
441
442
		// Not JSON
443 1
		if ( empty( $license_data ) ) {
444 1
			gravityview()->log->error( 'Empty license data response from license check', array( 'data' => compact( 'response', 'url', 'api_params', 'data' ) ) );
445
446 1
			delete_transient( self::status_transient_key );
447
448
			// Change status
449 1
			return array();
450
		}
451
452
		// Store the license key inside the data array
453 1
		$license_data->license_key = $license;
454
455 1
		return $license_data;
456
	}
457
458
	/**
459
	 * Update the license after fetching it
460
	 * @param object $license_data
461
	 * @return void
462
	 */
463 1
	private function license_call_update_settings( $license_data, $data ) {
464 1
		$settings = array();
465
466 1
        $settings['license_key'] = $license_data->license_key = trim( $data['license'] );
467 1
		$settings['license_key_status'] = $license_data->license;
468 1
		$settings['license_key_response'] = (array)$license_data;
0 ignored issues
show
introduced by
No space after closing casting parenthesis is prohibited
Loading history...
469
470 1
		$this->settings->set( $settings );
471 1
	}
472
473 2
	public function settings_edd_license_activation( $field, $echo ) {
0 ignored issues
show
Unused Code introduced by
The parameter $field 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...
474 2
		$script_debug = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '' : '.min';
475
476 2
		wp_enqueue_script( 'gv-admin-edd-license', GRAVITYVIEW_URL . 'assets/js/admin-edd-license' . $script_debug . '.js', array( 'jquery' ) );
477
478 2
		$status = trim( $this->settings->get( 'license_key_status' ) );
479 2
		$key = trim( $this->settings->get( 'license_key' ) );
480
481 2
		if ( ! empty( $key ) ) {
482
			$response = $this->settings->get( 'license_key_response' );
483
			$response = is_array( $response ) ? (object) $response : json_decode( $response );
484
		} else {
485 2
			$response = array();
486
		}
487
488 2
		wp_localize_script( 'gv-admin-edd-license', 'GVGlobals', array(
489 2
			'license_box' => $this->get_license_message( $response )
490
		) );
491
492
		$fields = array(
493
			array(
494 2
				'name'  => 'edd-activate',
495 2
				'value' => __( 'Activate License', 'gravityview' ),
496 2
				'data-pending_text' => __( 'Verifying license&hellip;', 'gravityview' ),
497 2
				'data-edd_action' => 'activate_license',
498 2
				'class' => 'button-primary',
499
			),
500
			array(
501 2
				'name'  => 'edd-deactivate',
502 2
				'value' => __( 'Deactivate License', 'gravityview' ),
503 2
				'data-pending_text' => __( 'Deactivating license&hellip;', 'gravityview' ),
504 2
				'data-edd_action' => 'deactivate_license',
505 2
				'class' => ( empty( $status ) ? 'button-primary hide' : 'button-primary' ),
506
			),
507
			array(
508 2
				'name'  => 'edd-check',
509 2
				'value' => __( 'Check License', 'gravityview' ),
510 2
				'data-pending_text' => __( 'Verifying license&hellip;', 'gravityview' ),
511 2
				'title' => 'Check the license before saving it',
512 2
				'data-edd_action' => 'check_license',
513 2
				'class' => 'button-secondary',
514
			),
515
		);
516
517 2
		$class = 'button gv-edd-action';
518
519 2
		$class .= ( ! empty( $key ) && $status !== 'valid' ) ? '' : ' hide';
520
521 2
		$disabled_attribute = \GVCommon::has_cap( 'gravityview_edit_settings' ) ? false : 'disabled';
522
523 2
		$submit = '<div class="gv-edd-button-wrapper">';
524 2
		foreach ( $fields as $field ) {
525 2
			$field['type'] = 'button';
526 2
			$field['class'] = isset( $field['class'] ) ? $field['class'] . ' '. $class : $class;
527 2
			$field['style'] = 'margin-left: 10px;';
528 2
			if( $disabled_attribute ) {
529 1
				$field['disabled'] = $disabled_attribute;
530
			}
531 2
			$submit .= $this->settings->as_html( $field, $echo );
532
		}
533 2
		$submit .= '</div>';
534
535 2
		return $submit;
536
	}
537
538
	/**
539
	 * When the status transient expires (or is deleted on activation), re-check the status
540
	 *
541
	 * @since 1.17
542
	 *
543
	 * @return void
544
	 */
545 1
	public function refresh_license_status() {
546 1
		if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
547
			return;
548
		}
549
550
		// The transient is fresh; don't fetch.
551 1
		if ( $status = get_transient( self::status_transient_key ) ) {
552
			return;
553
		}
554
555
		$data = array(
556 1
			'edd_action' => 'check_license',
557 1
			'license' => trim( $this->settings->get( 'license_key' ) ),
558
			'update' => true,
559 1
			'format' => 'object',
560 1
			'field_id' => 'refresh_license_status', // Required to set the `status_transient_key` transient
561
		);
562
563 1
		$license_call = $this->license_call( $data, false );
564
565 1
		gravityview()->log->debug( 'Refreshed the license.', array( 'data' => $license_call ) );
566 1
	}
567
568
	/**
569
	 * Check the GravityView license information
570
	 *
571
	 * @since 1.19.3
572
	 * @param bool $force Whether to force checking license, even if AJAX
0 ignored issues
show
Bug introduced by
There is no parameter named $force. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
573
	 *
574
	 * @return void
575
	 */
576 1
	public function check_license() {
577 1
		if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
578
			return; // Don't fire when saving settings or AJAX
579
		}
580
581 1
		if ( ! apply_filters( 'gv_send_site_data', true ) ) {
582
			return;
583
		}
584
585
		// Send checkins once per week
586 1
		$last_checked = get_option( 'gv_last_checkin', false );
587
588 1
		if ( is_numeric( $last_checked ) && $last_checked > strtotime( '-1 week', current_time( 'timestamp' ) ) ) {
589
			return; // checked within a week
590
		}
591
592 1
		$status = get_transient( 'gv_license_check' );
593
594
		// Run the license check a maximum of once per day, and not on GV website
595 1
		if ( false === $status && site_url() !== self::url ) {
596
597
			// Call the custom API.
598 1
			$response = wp_remote_post( self::url, array(
599 1
				'timeout'   => 15,
600
			    'sslverify' => false,
601
			    'body'      =>  array(
0 ignored issues
show
introduced by
Expected 1 space after "=>"; 2 found
Loading history...
602 1
				    'edd_action' => 'check_license',
603 1
				    'license'    => trim( $this->settings->get( 'license_key' ) ),
604 1
				    'item_name'  => self::name,
605 1
				    'url'        => home_url(),
606 1
				    'site_data'  => $this->get_site_data(),
607
			    ),
608
			));
609
610
			// make sure the response came back okay
611 1
			if ( is_wp_error( $response ) ) {
612
613
				// Connection failed, try again in three hours
614
				set_transient( 'gv_license_check', 1, 3 * HOUR_IN_SECONDS );
615
616
				return;
617
			}
618
619 1
			set_transient( 'gv_license_check', 1, DAY_IN_SECONDS );
620
621 1
			update_option( 'gv_last_checkin', current_time( 'timestamp' ) );
622
		}
623 1
	}
624
625
	/**
626
	 * Retrieves site data (plugin versions, integrations, etc) to be sent along with the license check.
627
	 *
628
	 * @since 1.9
629
	 * @access public
630
	 *
631
	 * @return array
632
	 */
633 1
	public function get_site_data() {
634 1
		$data = array();
635
636 1
		$theme_data = wp_get_theme();
637 1
		$theme      = $theme_data->Name . ' ' . $theme_data->Version;
638
639 1
		$data['gv_version']  = Plugin::$version;
640 1
		$data['php_version']  = phpversion();
641 1
		$data['wp_version']   = get_bloginfo( 'version' );
642 1
		$data['gf_version']  = \GFForms::$version;
643 1
		$data['server']       = Utils::get( $_SERVER, 'SERVER_SOFTWARE' );
644 1
		$data['multisite']    = is_multisite();
645 1
		$data['theme']        = $theme;
646 1
		$data['url']          = home_url();
647 1
		$data['license_key']  = $this->settings->get( 'license_key' );
648 1
		$data['beta']         = $this->settings->get( 'beta' );
649
650
		// View Data
651 1
		$gravityview_posts = wp_count_posts( 'gravityview', 'readable' );
652
653 1
		$data['view_count'] = null;
654 1
		$data['view_first'] = null;
655 1
		$data['view_latest'] = null;
656
657 1
		if ( $gravityview_posts->publish ) {
658 1
			$data['view_count'] = $gravityview_posts->publish;
659
660 1
			$first = get_posts( 'numberposts=1&post_type=gravityview&post_status=publish&order=ASC' );
661 1
			$latest = get_posts( 'numberposts=1&post_type=gravityview&post_status=publish&order=DESC' );
662
663 1
			if ( $first = array_shift( $first ) ) {
664 1
				$data['view_first'] = $first->post_date;
665
			}
666 1
			if ( $latest = array_pop( $latest ) ) {
667 1
				$data['view_latest'] = $latest->post_date;
668
			}
669
		}
670
671
		// Form counts
672 1
		if ( class_exists( 'GFFormsModel' ) ) {
673 1
			$form_data = \GFFormsModel::get_form_count();
674 1
			$data['forms_total'] = Utils::get( $form_data, 'total', 0 );
675 1
			$data['forms_active'] = Utils::get( $form_data, 'active', 0 );
676 1
			$data['forms_inactive'] = Utils::get( $form_data, 'inactive', 0 );
677 1
			$data['forms_trash'] = Utils::get( $form_data, 'inactive', 0 );
678
		}
679
680
		// Retrieve current plugin information
681 1
		if ( ! function_exists( 'get_plugins' ) ) {
682
			include ABSPATH . '/wp-admin/includes/plugin.php';
683
		}
684
685 1
		$data['integrations']     = self::get_related_plugins_and_extensions();
686 1
		$data['active_plugins']   = get_option( 'active_plugins', array() );
687 1
		$data['inactive_plugins'] = array();
688 1
		$data['locale']           = get_locale();
689
690
		// Validate request on the GV server
691 1
		$data['hash']             = 'gv_version.url.locale:' . sha1( $data['gv_version'] . $data['url'] . $data['locale'] );
692
693 1
		return $data;
694
	}
695
696
	/**
697
	 * Get active GravityView Extensions and Gravity Forms Add-ons to help debug issues.
698
	 *
699
	 * @since 1.15
700
	 * @return string List of active extensions related to GravityView or Gravity Forms, separated by HTML line breaks
701
	 */
702 1
	static public function get_related_plugins_and_extensions( $implode = '<br />' ) {
0 ignored issues
show
Coding Style introduced by
As per PSR2, the static declaration should come after the visibility declaration.
Loading history...
703 1
		if ( ! function_exists( 'wp_get_active_and_valid_plugins' ) ) {
704
			return 'Running < WP 3.0';
705
		}
706
707 1
		$extensions = get_site_transient( self::related_plugins_key );
708
709 1
		if ( empty( $extensions ) ) {
710
711 1
			$active_plugins = wp_get_active_and_valid_plugins();
712 1
			$extensions = array();
713 1
			foreach ( $active_plugins as $active_plugin ) {
714
				// Match gravityview, gravity-forms, gravityforms, gravitate
715
				if ( ! preg_match( '/(gravityview|gravity-?forms|gravitate)/ism', $active_plugin ) ) {
716
					continue;
717
				}
718
719
				$plugin_data = get_plugin_data( $active_plugin );
720
721
				$extensions[] = sprintf( '%s %s', $plugin_data['Name'], $plugin_data['Version'] );
722
			}
723
724 1
			if ( ! empty( $extensions ) ) {
725
				set_site_transient( self::related_plugins_key, $extensions, HOUR_IN_SECONDS );
726
			} else {
727 1
				return 'There was an error fetching related plugins.';
728
			}
729
		}
730
731
		return $implode ? implode( $implode, $extensions ) : $extensions;
732
	}
733
734
	/**
735
	 * When a plugin is activated or deactivated, delete the cached extensions/plugins used by get_related_plugins_and_extensions()
736
	 *
737
	 * @see get_related_plugins_and_extensions()
738
	 * @since 1.15
739
	 */
740 1
	public function flush_related_plugins_transient() {
741 1
		if ( function_exists( 'delete_site_transient' ) ) {
742 1
			delete_site_transient( self::related_plugins_key );
743
		}
744 1
	}
745
}
746