PluginProbe
Content Control – The Ultimate Content Restriction Plugin! Restrict Content, Create Conditional Blocks & More / 2.0.12
Content Control – The Ultimate Content Restriction Plugin! Restrict Content, Create Conditional Blocks & More v2.0.12
trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.1.10 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 1.1.8 2.0.0 2.0.1 2.0.10 2.0.11 2.0.12 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 All 47 releases
content-control / classes / Plugin / License.php

License.php in Content Control – The Ultimate Content Restriction Plugin! Restrict Content, Create Conditional Blocks & More 2.0.12, at classes/Plugin/License.php

495 lines 11.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Upgrade management.
4 *
5 * @copyright (c) 2023, Code Atlantic LLC.
6 *
7 * @package ContentControl
8 */
9
10 namespace ContentControl\Plugin;
11
12 defined( 'ABSPATH' ) || exit;
13
14 /**
15 * License management.
16 *
17 * NOTE: For wordpress.org admins: This is only used if:
18 * - The user explicitly entered a license key.
19 *
20 * @package ContentControl
21 */
22 class License {
23
24 /**
25 * EDD API URL.
26 *
27 * @var string
28 */
29 const API_URL = 'https://contentcontrolplugin.com/edd-sl-api/';
30
31 /**
32 * Item ID.
33 *
34 * @var int
35 */
36 const ID = 45;
37
38 /**
39 * Option key.
40 *
41 * @var string
42 */
43 const OPTION_KEY = 'content_control_license';
44
45 /**
46 * License data
47 *
48 * @var array<string,mixed>|null
49 */
50 private $license_data;
51
52 /**
53 * Initialize license management.
54 */
55 public function __construct() {
56 $this->register_hooks();
57 }
58
59 /**
60 * Register hooks.
61 *
62 * @return void
63 */
64 public function register_hooks() {
65 add_action( 'init', [ $this, 'autoregister' ] );
66 add_action( 'content_control_license_status_check', [ $this, 'refresh_license_status' ] );
67 add_action( 'admin_init', [ $this, 'schedule_crons' ] );
68 }
69
70 /**
71 * Autoregister license.
72 *
73 * @return void
74 */
75 public function autoregister() {
76 $key = defined( '\CONTENT_CONTROL_LICENSE_KEY' ) && '' !== \CONTENT_CONTROL_LICENSE_KEY ? \CONTENT_CONTROL_LICENSE_KEY : false;
77
78 if ( $key && '' === $this->get_license_key() ) {
79 try {
80 $this->activate_license( \CONTENT_CONTROL_LICENSE_KEY );
81 // phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedCatch
82 } catch ( \Exception $e ) {
83 // Do nothing.
84 }
85 }
86 }
87
88 /**
89 * Schedule cron jobs.
90 *
91 * @return void
92 */
93 public function schedule_crons() {
94 if ( ! wp_next_scheduled( 'content_control_license_status_check' ) ) {
95 wp_schedule_event( time(), 'daily', 'content_control_license_status_check' );
96 }
97 }
98
99 /**
100 * Get license data.
101 *
102 * @return array{key:string|null,status:array<string,mixed>|null}
103 */
104 public function get_license_data() {
105 if ( ! isset( $this->license_data ) ) {
106 $this->license_data = \get_option( self::OPTION_KEY, [
107 'key' => '',
108 'status' => [
109 'success' => false, // bool.
110 'license' => 'invalid', // valid or invalid.
111 'item_id' => self::ID, // int or false.
112 'item_name' => '', // string.
113 'license_limit' => 1, // int. 0 = unlimited.
114 'site_count' => 0,
115 'expires' => '', // date or 'lifetime'.
116 'activations_left' => 0, // int or 'unlimited'.
117 'checksum' => '', // string.
118 'payment_id' => 0, // int.
119 'customer_name' => '', // string.
120 'customer_email' => '', // string.
121 'price_id' => 0, // string or int.
122 'error' => null, // string. expired, missing, invalid, item_name_mismatch, no_activations_left etc.
123 ],
124 ] );
125 }
126
127 return $this->license_data;
128 }
129
130 /**
131 * Get license key.
132 *
133 * @return string
134 */
135 public function get_license_key() {
136 $license_data = $this->get_license_data();
137 return ! empty( $license_data['key'] ) ? $license_data['key'] : '';
138 }
139
140 /**
141 * Get license status.
142 *
143 * @param bool $refresh Whether to refresh license status.
144 *
145 * @return array<string,mixed> Array of license status data.
146 */
147 public function get_license_status( $refresh = false ) {
148 if ( $refresh ) {
149 $this->refresh_license_status();
150 }
151
152 $license_data = $this->get_license_data();
153
154 $license_status = isset( $license_data['status'] ) ? $license_data['status'] : [];
155
156 return $license_status;
157 }
158
159 /**
160 * Update license data.
161 *
162 * @param array{key:string|null,status:array<string,mixed>|null} $license_data License data.
163 *
164 * @return bool
165 */
166 public function udpate_license_data( $license_data ) {
167 if ( \update_option( self::OPTION_KEY, $license_data ) ) {
168 $this->license_data = $license_data;
169 return true;
170 }
171
172 return false;
173 }
174
175 /**
176 * Update license key.
177 *
178 * @param string $key License key.
179 *
180 * @return void
181 */
182 public function update_license_key( $key ) {
183 $license_data = $this->get_license_data();
184
185 $old_key = isset( $license_data['key'] ) ? $license_data['key'] : '';
186
187 $license_data['key'] = trim( $key );
188
189 $this->udpate_license_data( $license_data );
190
191 /**
192 * Fires when license key is changed.
193 *
194 * @param string $key License key.
195 * @param string $old_key Old license key.
196 */
197 \do_action( 'content_control_license_key_changed', $key, $old_key );
198 }
199
200 /**
201 * Update license status.
202 *
203 * @param array<string,mixed> $license_status License status data.
204 *
205 * @return void
206 */
207 public function update_license_status( $license_status ) {
208 $license_data = $this->get_license_data();
209
210 $previous_status = isset( $license_data['status'] ) ? $license_data['status'] : [];
211
212 if ( ! empty( $license_status['error'] ) ) {
213 $license_status['error_message'] = $this->get_license_error_message( $license_status );
214 }
215
216 $license_data['status'] = $license_status;
217
218 $this->udpate_license_data( $license_data );
219
220 /**
221 * Fires when license status is updated.
222 *
223 * @param array $license_status License status data.
224 * @param array $previous_status Previous license status data.
225 */
226 \do_action( 'content_control_license_status_updated', $license_status, $previous_status );
227 }
228
229 /**
230 * Get license expiration from license status data.
231 *
232 * @param bool $as_datetime Whether to return as DateTime object.
233 *
234 * @return \DateTime|false|null
235 */
236 public function get_license_expiration( $as_datetime = false ) {
237 $status = $this->get_license_status();
238
239 $expiration = isset( $status['expires'] ) ? $status['expires'] : null;
240
241 return $as_datetime ?
242 \DateTime::createFromFormat( 'Y-m-d H:i:s', $expiration ) :
243 $expiration;
244 }
245
246 /**
247 * Fetch license status from remote server.
248 * This is a blocking request.
249 *
250 * @return void
251 */
252 public function refresh_license_status() {
253 $key = $this->get_license_key();
254
255 if ( empty( $key ) ) {
256 return;
257 }
258
259 try {
260 $status = $this->check_license();
261 } catch ( \Exception $e ) {
262 $status = [];
263 }
264
265 $this->update_license_status( $status );
266 }
267
268 /**
269 * Get license status from remote server.
270 *
271 * @return array<string,mixed> License status data.
272 *
273 * @throws \Exception If there is an error.
274 */
275 private function check_license() {
276 $api_params = [
277 'edd_action' => 'check_license',
278 'license' => $this->get_license_key(),
279 'item_id' => self::ID,
280 'item_name' => rawurlencode( 'Content Control Pro' ),
281 'url' => home_url(),
282 'environment' => function_exists( 'wp_get_environment_type' ) ? wp_get_environment_type() : 'production',
283 ];
284
285 // Call the custom API.
286 $response = wp_remote_post(
287 self::API_URL,
288 [
289 'timeout' => 15,
290 'sslverify' => false,
291 'body' => $api_params,
292 ]
293 );
294
295 if ( is_wp_error( $response ) ) {
296 throw new \Exception( esc_html( $response->get_error_message() ) );
297 }
298
299 $license_status = json_decode( wp_remote_retrieve_body( $response ), true );
300
301 if ( empty( $license_status ) ) {
302 return [];
303 }
304
305 return $license_status;
306 }
307
308 /**
309 * Activate license.
310 *
311 * @param string $key License key.
312 *
313 * @return array<string,mixed> License status data.
314 *
315 * @throws \Exception If there is an error.
316 */
317 public function activate_license( $key = null ) {
318 if ( ! empty( $key ) ) {
319 $this->update_license_key( $key );
320 } else {
321 $key = $this->get_license_key();
322 }
323
324 $api_params = [
325 'edd_action' => 'activate_license',
326 'license' => $key,
327 'item_id' => self::ID,
328 'item_name' => rawurlencode( 'Content Control' ),
329 'url' => home_url(),
330 'environment' => function_exists( 'wp_get_environment_type' ) ? wp_get_environment_type() : 'production',
331 ];
332
333 // Call the custom API.
334 $response = wp_remote_post(
335 self::API_URL,
336 [
337 'timeout' => 15,
338 'sslverify' => false,
339 'body' => $api_params,
340 ]
341 );
342
343 // Make sure the response came back okay.
344 if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) {
345 if ( is_wp_error( $response ) ) {
346 $message = $response->get_error_message();
347 } else {
348 $message = __( 'An error occurred, please try again.', 'content-control' );
349 }
350
351 throw new \Exception( esc_html( $message ) );
352 }
353
354 $license_status = json_decode( wp_remote_retrieve_body( $response ), true );
355
356 $this->update_license_status( $license_status );
357
358 if ( $this->is_license_active() ) {
359 if ( ! \get_option( 'content_control_pro_activation_date', false ) ) {
360 \update_option( 'content_control_pro_activation_date', time() );
361 }
362 }
363
364 return $this->get_license_status();
365 }
366
367 /**
368 * Deactivate license.
369 *
370 * @return array<string,mixed> License status data.
371 *
372 * @throws \Exception If there is an error.
373 */
374 public function deactivate_license() {
375 $api_params = [
376 'edd_action' => 'deactivate_license',
377 'license' => $this->get_license_key(),
378 'item_id' => self::ID,
379 'item_name' => rawurlencode( 'Content Control' ),
380 'url' => home_url(),
381 'environment' => function_exists( 'wp_get_environment_type' ) ? wp_get_environment_type() : 'production',
382 ];
383
384 // Call the custom API.
385 $response = wp_remote_post(
386 self::API_URL,
387 [
388 'timeout' => 15,
389 'sslverify' => false,
390 'body' => $api_params,
391 ]
392 );
393
394 // Make sure the response came back okay.
395 if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) {
396 if ( is_wp_error( $response ) ) {
397 $message = $response->get_error_message();
398 } else {
399 $message = __( 'An error occurred, please try again.', 'content-control' );
400 }
401
402 throw new \Exception( esc_html( $message ) );
403 }
404
405 $license_status = json_decode( wp_remote_retrieve_body( $response ), true );
406
407 $this->update_license_status( $license_status );
408
409 return $license_status;
410 }
411
412 /**
413 * Convert license error to human readable message.
414 *
415 * @param array<string,mixed> $license_status License status data.
416 *
417 * @return string
418 */
419 public function get_license_error_message( $license_status ) {
420 switch ( $license_status['error'] ) {
421 case 'expired':
422 $message = sprintf(
423 /* translators: the license key expiration date */
424 __( 'Your license key expired on %s.', 'content-control' ),
425 date_i18n( \get_option( 'date_format' ), strtotime( $license_status['expires'], time() ) )
426 );
427 break;
428
429 case 'disabled':
430 case 'revoked':
431 $message = __( 'Your license key has been disabled.', 'content-control' );
432 break;
433
434 case 'missing':
435 $message = __( 'Invalid license.', 'content-control' );
436 break;
437
438 case 'invalid':
439 case 'site_inactive':
440 $message = __( 'Your license is not active for this URL.', 'content-control' );
441 break;
442
443 case 'item_name_mismatch':
444 $message = sprintf(
445 /* translators: the plugin name */
446 __( 'This appears to be an invalid license key for %s.', 'content-control' ),
447 __( 'Content Control', 'content-control' )
448 );
449 break;
450
451 case 'no_activations_left':
452 $message = __( 'Your license key has reached its activation limit.', 'content-control' );
453 break;
454
455 default:
456 $message = __( 'An error occurred, please try again.', 'content-control' );
457 break;
458 }
459
460 return $message;
461 }
462
463 /**
464 * Remove license.
465 *
466 * @return void
467 */
468 public function remove_license() {
469 try {
470 $deactivated = $this->deactivate_license();
471 } catch ( \Exception $e ) {
472 $deactivated = [];
473 }
474
475 if ( ! empty( $deactivated['license'] ) && 'active' !== $deactivated['license'] ) {
476 \delete_option( self::OPTION_KEY );
477 }
478 }
479
480 /**
481 * Check if license is active.
482 *
483 * @return bool
484 */
485 public function is_license_active() {
486 $license_status = $this->get_license_status();
487
488 if ( empty( $license_status ) ) {
489 return false;
490 }
491
492 return 'valid' === $license_status['license'];
493 }
494 }
495