PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.16
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.16
6.35 6.34 6.33.1 6.33 6.32.1 6.32 6.31 6.25 6.25.1 6.26 6.26.1 6.27 6.28 6.29 6.3 6.3.1 6.3.2 6.30 6.4 6.4.1 6.4.2 6.5 6.5.1 6.5.2 6.5.3 All 141 releases
← All changes | classes/models/FrmAddon.php +174 -59 6.46.16 View file →
@@ -12,15 +12,43 @@
12 12 public $plugin_name;
13 13 public $plugin_slug;
14 14 public $option_name;
15 15 public $version;
16 - public $author = 'Strategy11';
16 + public $author = 'Strategy11';
17 17 public $is_parent_licence = false;
18 - public $needs_license = true;
18 + public $needs_license = true;
19 19 private $is_expired_addon = false;
20 20 public $license;
21 21 protected $get_beta = false;
22 + protected $save_status;
22 23
24 + /**
25 + * This is used to decide whether the license checks should continue.
26 + * The point is to avoid license issues when a site url changes.
27 + *
28 + * @since 6.8.3
29 + *
30 + * @var array
31 + */
32 + private $save_response = array();
33 +
34 + /**
35 + * This is used to flag other add ons not to send a request.
36 + * We only want to send a single API request per page load.
37 + *
38 + * @since 6.8.3
39 + *
40 + * @var string
41 + */
42 + private $transient_lock_key = 'frm_activate_request_lock';
43 +
44 + /**
45 + * @since 6.8.3
46 + *
47 + * @var bool
48 + */
49 + protected $should_clear_cache = true;
50 +
23 51 public function __construct() {
24 52
25 53 if ( empty( $this->plugin_slug ) ) {
26 54 $this->plugin_slug = preg_replace( '/[^a-zA-Z0-9_\s]/', '', str_replace( ' ', '_', strtolower( $this->plugin_name ) ) );
@@ -74,13 +102,13 @@
74 102 }
75 103 }
76 104
77 105 /**
78 - * Updates information on the "View version x.x details" page with custom data.
106 + * Updates information on the "View version 6.15 details" page with custom data.
79 107 *
80 108 * @uses api_request()
81 109 *
82 - * @param mixed $_data
110 + * @param mixed $_data
83 111 * @param string $_action
84 112 * @param object $_args
85 113 *
86 114 * @return object $_data
@@ -170,11 +198,10 @@
170 198 * @since 2.04
171 199 */
172 200 public function activate_defined_license() {
173 201 $license = $this->get_defined_license();
174 - if ( ! empty( $license ) && ! $this->is_active() && $this->is_time_to_auto_activate() ) {
202 + if ( ! empty( $license ) && ! $this->is_active() && ! $this->checked_recently( '1 day' ) ) {
175 203 $response = $this->activate_license( $license );
176 - $this->set_auto_activate_time();
177 204 if ( ! $response['success'] ) {
178 205 $license = '';
179 206 }
180 207 }
@@ -196,24 +223,8 @@
196 223 public function set_license( $license ) {
197 224 update_option( $this->option_name . 'key', $license );
198 225 }
199 226
200 - /**
201 - * If the license is in the config, limit the frequency of checks.
202 - * The license may be entered incorrectly, so we don't want to check on every page load.
203 - *
204 - * @since 2.04
205 - */
206 - private function is_time_to_auto_activate() {
207 - $last_try = get_option( $this->option_name . 'last_activate' );
208 -
209 - return ( ! $last_try || $last_try < strtotime( '-1 day' ) );
210 - }
211 -
212 - private function set_auto_activate_time() {
213 - update_option( $this->option_name . 'last_activate', time() );
214 - }
215 -
216 227 public function is_active() {
217 228 return get_option( $this->option_name . 'active' );
218 229 }
219 230
@@ -219,12 +230,12 @@
219 230
220 231 /**
221 232 * @since 3.04.03
222 233 *
223 - * @param array error
234 + * @param array|string $error
224 235 */
225 236 public function maybe_clear_license( $error ) {
226 - if ( $error['code'] === 'disabled' && $error['license'] === $this->license ) {
237 + if ( is_array( $error ) && $error['code'] === 'disabled' && $error['license'] === $this->license ) {
227 238 $this->clear_license();
228 239 }
229 240 }
230 241
@@ -230,15 +241,41 @@
230 241
231 242 public function clear_license() {
232 243 delete_option( $this->option_name . 'active' );
233 244 delete_option( $this->option_name . 'key' );
234 - delete_site_option( $this->transient_key() );
235 - delete_option( $this->transient_key() );
236 - $this->delete_cache();
245 +
246 + if ( $this->should_clear_cache ) {
247 + delete_site_option( $this->transient_key() );
248 + delete_option( $this->transient_key() );
249 + $this->delete_cache();
250 + $this->should_clear_cache = true;
251 + }
237 252 }
238 253
254 + /**
255 + * Don't save an invalid license.
256 + *
257 + * @since 6.8.3
258 + *
259 + * @param bool $is_valid If license activation was successful.
260 + *
261 + * @return void
262 + */
263 + protected function maybe_set_active( $is_valid ) {
264 + update_option( $this->option_name . 'active', $is_valid );
265 + if ( $is_valid ) {
266 + $this->set_active( $is_valid );
267 + return;
268 + }
269 +
270 + // Don't save the license if it's invalid.
271 + $this->should_clear_cache = false;
272 + $this->clear_license();
273 + delete_option( $this->option_name . 'key' );
274 + $this->license = '';
275 + }
276 +
239 277 public function set_active( $is_active ) {
240 - update_option( $this->option_name . 'active', $is_active );
241 278 $this->delete_cache();
242 279 FrmAppHelper::save_combined_js();
243 280 $this->update_pro_capabilities();
244 281 }
@@ -261,9 +298,9 @@
261 298 foreach ( $caps as $cap => $cap_desc ) {
262 299 $cap_roles = (array) ( isset( $settings->$cap ) ? $settings->$cap : 'administrator' );
263 300
264 301 // Make sure administrators always have permissions.
265 - if ( ! in_array( 'administrator', $cap_roles ) ) {
302 + if ( ! in_array( 'administrator', $cap_roles, true ) ) {
266 303 array_push( $cap_roles, 'administrator' );
267 304 }
268 305
269 306 foreach ( $roles as $role => $details ) {
@@ -281,8 +318,11 @@
281 318 */
282 319 protected function delete_cache() {
283 320 delete_transient( 'frm_api_licence' );
284 321
322 + // Cleanup option that has been removed.
323 + delete_option( $this->option_name . 'last_activate' );
324 +
285 325 $api = new FrmFormApi( $this->license );
286 326 $api->reset_cached();
287 327
288 328 $api = new FrmFormTemplateApi( $this->license );
@@ -338,9 +378,9 @@
338 378 return $transient;
339 379 }
340 380
341 381 if ( $this->is_current_version( $transient ) ) {
342 - //make sure it doesn't show there is an update if plugin is up-to-date
382 + // Make sure it doesn't show there is an update if plugin is up-to-date.
343 383 if ( isset( $transient->response[ $this->plugin_folder ] ) ) {
344 384 unset( $transient->response[ $this->plugin_folder ] );
345 385 }
346 386 } elseif ( isset( $transient->response ) && isset( $transient->response[ $this->plugin_folder ] ) ) {
@@ -363,20 +403,21 @@
363 403 * Check if the plugin information is correct to allow an update
364 404 *
365 405 * @since 3.04.03
366 406 *
367 - * @param object $transient - the current plugin info saved for update
407 + * @param object $transient The current plugin info saved for update.
368 408 */
369 409 private function prepare_update_details( &$transient ) {
370 410 $version_info = $transient;
371 - $has_beta_url = isset( $version_info->beta ) && ! empty( $version_info->beta );
411 + $has_beta_url = ! empty( $version_info->beta );
372 412 if ( $this->get_beta && ! $has_beta_url ) {
373 413 $version_info = (object) $this->get_api_info( $this->license );
374 414 }
375 415
376 - if ( isset( $version_info->new_version ) && ! empty( $version_info->new_version ) ) {
416 + if ( ! empty( $version_info->new_version ) ) {
377 417 $this->clear_old_plugin_version( $version_info );
378 - if ( $version_info === false ) { // was cleared with timeout
418 + if ( $version_info === false ) {
419 + // Was cleared with timeout.
379 420 $transient = false;
380 421 } else {
381 422 $this->maybe_use_beta_url( $version_info );
382 423
@@ -414,11 +455,12 @@
414 455 *
415 456 * @since 2.05.05
416 457 */
417 458 private function clear_old_plugin_version( &$version_info ) {
418 - $timeout = ( isset( $version_info->timeout ) && ! empty( $version_info->timeout ) ) ? $version_info->timeout : 0;
459 + $timeout = ! empty( $version_info->timeout ) ? $version_info->timeout : 0;
419 460 if ( ! empty( $timeout ) && time() > $timeout ) {
420 - $version_info = false; // Cache is expired
461 + // Cache is expired.
462 + $version_info = false;
421 463 $api = new FrmFormApi( $this->license );
422 464 $api->reset_cached();
423 465 }
424 466 }
@@ -429,12 +471,12 @@
429 471 *
430 472 * @since 3.04.03
431 473 */
432 474 private function maybe_use_beta_url( &$version_info ) {
433 - if ( $this->get_beta && isset( $version_info->beta ) && ! empty( $version_info->beta ) ) {
475 + if ( $this->get_beta && ! empty( $version_info->beta ) ) {
434 476 $version_info->new_version = $version_info->beta['version'];
435 477 $version_info->package = $version_info->beta['package'];
436 - if ( isset( $version_info->plugin ) && ! empty( $version_info->plugin ) ) {
478 + if ( ! empty( $version_info->plugin ) ) {
437 479 $version_info->plugin = $version_info->beta['plugin'];
438 480 }
439 481 }
440 482 }
@@ -443,9 +485,9 @@
443 485 if ( empty( $transient->checked ) || ! isset( $transient->checked[ $this->plugin_folder ] ) ) {
444 486 return false;
445 487 }
446 488
447 - $response = ! isset( $transient->response ) || empty( $transient->response );
489 + $response = empty( $transient->response );
448 490 if ( $response ) {
449 491 return true;
450 492 }
451 493
@@ -451,12 +493,14 @@
451 493
452 494 return isset( $transient->response ) && isset( $transient->response[ $this->plugin_folder ] ) && $transient->checked[ $this->plugin_folder ] === $transient->response[ $this->plugin_folder ]->new_version;
453 495 }
454 496
497 + /**
498 + * @return bool
499 + */
455 500 private function has_been_cleared() {
456 501 $last_cleared = get_option( 'frm_last_cleared' );
457 -
458 - return ( $last_cleared && $last_cleared > gmdate( 'Y-m-d H:i:s', strtotime( '-5 minutes' ) ) );
502 + return $last_cleared && $last_cleared > gmdate( 'Y-m-d H:i:s', strtotime( '-5 minutes' ) );
459 503 }
460 504
461 505 private function cleared_plugins() {
462 506 update_option( 'frm_last_cleared', gmdate( 'Y-m-d H:i:s' ) );
@@ -466,15 +510,18 @@
466 510 if ( empty( $this->license ) || empty( $this->plugin_slug ) || isset( $_POST['license'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
467 511 return;
468 512 }
469 513
514 + if ( $this->get_defined_license() ) {
515 + // Don't check if the license is defined in wp-config.php since we can't remove it.
516 + return;
517 + }
518 +
470 519 // Only check weekly.
471 - if ( $this->checked_recently( '7 days' ) ) {
520 + if ( $this->checked_recently( '7 days', 'valid' ) || $this->is_running() ) {
472 521 return;
473 522 }
474 523
475 - $this->update_last_checked();
476 -
477 524 $response = $this->get_license_status();
478 525 if ( 'revoked' === $response['status'] || 'blocked' === $response['status'] || 'disabled' === $response['status'] || 'missing' === $response['status'] ) {
479 526 $this->clear_license();
480 527 }
@@ -482,19 +529,36 @@
482 529
483 530 /**
484 531 * Has this been checked too recently?
485 532 *
486 - * @param string $time ie. '1 day'
533 + * @param string $time ie. '1 day'.
534 + * @param string $required_status Return false if the last check does not match. ie 'valid'.
535 + *
487 536 * @return bool
488 537 */
489 - private function checked_recently( $time ) {
538 + private function checked_recently( $time, $required_status = '' ) {
490 539 $last_checked = $this->last_checked();
540 + $is_429 = isset( $last_checked['response_code'] ) && 429 === $last_checked['response_code'];
541 + if ( $is_429 ) {
542 + // If the last check was a a rate limit, we'll need to check again sooner.
543 + $time = '5 minutes';
544 + $required_status = '';
545 + }
546 +
547 + if ( $required_status && ( ! isset( $last_checked['status'] ) || $last_checked['status'] !== $required_status ) ) {
548 + // If the last check was invalid, we don't need to check again.
549 + return true;
550 + }
551 +
552 + $checked_time = isset( $last_checked['time'] ) ? $last_checked['time'] : false;
491 553 $time_ago = gmdate( 'Y-m-d H:i:s', strtotime( '-' . $time ) );
492 - return $last_checked && $last_checked > $time_ago;
554 + return $checked_time && $checked_time > $time_ago;
493 555 }
494 556
495 557 /**
496 - * @return bool|string
558 + * @since 6.8.3 Switched to an array to store extra response info.
559 + *
560 + * @return array
497 561 */
498 562 private function last_checked() {
499 563 if ( is_multisite() ) {
500 564 $last_checked = get_site_option( $this->transient_key() );
@@ -500,9 +564,13 @@
500 564 $last_checked = get_site_option( $this->transient_key() );
501 565 } else {
502 566 $last_checked = get_option( $this->transient_key() );
503 567 }
504 - return $last_checked;
568 + if ( $last_checked && ! is_array( $last_checked ) ) {
569 + // Get string into array for existing values.
570 + $last_checked = array( 'time' => $last_checked );
571 + }
572 + return $last_checked ? (array) $last_checked : array();
505 573 }
506 574
507 575 /**
508 576 * @return void
@@ -507,12 +575,13 @@
507 575 /**
508 576 * @return void
509 577 */
510 578 private function update_last_checked() {
579 + $this->save_response['time'] = gmdate( 'Y-m-d H:i:s' );
511 580 if ( is_multisite() ) {
512 - update_site_option( $this->transient_key(), gmdate( 'Y-m-d H:i:s' ) );
581 + update_site_option( $this->transient_key(), $this->save_response );
513 582 } else {
514 - update_option( $this->transient_key(), gmdate( 'Y-m-d H:i:s' ) );
583 + update_option( $this->transient_key(), $this->save_response );
515 584 }
516 585 }
517 586
518 587 /**
@@ -574,9 +643,9 @@
574 643 if ( 'valid' === $response['status'] ) {
575 644 $is_valid = 'valid';
576 645 $response['success'] = true;
577 646 }
578 - $this->set_active( $is_valid );
647 + $this->maybe_set_active( $is_valid );
579 648 }
580 649
581 650 $this->update_last_checked();
582 651
@@ -602,8 +671,10 @@
602 671 );
603 672 }
604 673
605 674 private function get_license_status() {
675 + $this->set_running();
676 +
606 677 $response = array(
607 678 'status' => 'missing',
608 679 'error' => true,
609 680 );
@@ -618,10 +689,11 @@
618 689 $license_data = $this->send_mothership_request( 'activate_license' );
619 690
620 691 // $license_data->license will be either "valid" or "invalid"
621 692 if ( is_array( $license_data ) ) {
622 - if ( isset( $license_data['license'] ) && in_array( $license_data['license'], array( 'valid', 'invalid' ), true ) ) {
623 - $response['status'] = $license_data['license'];
693 + if ( ! empty( $license_data['license'] ) && in_array( $license_data['license'], array( 'valid', 'invalid' ), true ) ) {
694 + $response['status'] = $license_data['license'];
695 + $this->save_status['status'] = $license_data['license'];
624 696 }
625 697 } else {
626 698 $response['status'] = $license_data;
627 699 }
@@ -628,8 +700,10 @@
628 700 } catch ( Exception $e ) {
629 701 $response['status'] = $e->getMessage();
630 702 }
631 703
704 + $this->update_last_checked();
705 + $this->done_running();
632 706 return $response;
633 707 }
634 708
635 709 private function get_messages() {
@@ -721,19 +795,20 @@
721 795 'timeout' => 25,
722 796 'user-agent' => $this->plugin_slug . '/' . $this->version . '; ' . get_bloginfo( 'url' ),
723 797 );
724 798
725 - $resp = wp_remote_post(
799 + $resp = wp_remote_post(
726 800 $this->store_url . '?l=' . urlencode( base64_encode( $this->license ) ),
727 801 $arg_array
728 802 );
729 - $body = wp_remote_retrieve_body( $resp );
803 + $body = wp_remote_retrieve_body( $resp );
804 + $this->save_status = array( 'response_code' => wp_remote_retrieve_response_code( $resp ) );
730 805
731 806 $message = __( 'Your License Key was invalid', 'formidable' );
732 807 if ( is_wp_error( $resp ) ) {
733 808 $link = FrmAppHelper::admin_upgrade_link( 'api', 'knowledgebase/why-cant-i-activate-formidable-pro/' );
734 809 /* translators: %1$s: Start link HTML, %2$s: End link HTML */
735 - $message = sprintf( __( 'You had an error communicating with the Formidable API. %1$sClick here%2$s for more information.', 'formidable' ), '<a href="' . esc_url( $link ) . '" target="_blank">', '</a>' );
810 + $message = sprintf( __( 'You had an error communicating with the Formidable API. %1$sClick here%2$s for more information.', 'formidable' ), '<a href="' . esc_url( $link ) . '" target="_blank">', '</a>' );
736 811 $message .= ' ' . $resp->get_error_message();
737 812 } elseif ( 'error' === $body || is_wp_error( $body ) ) {
738 813 $message = __( 'You had an HTTP error connecting to the Formidable API', 'formidable' );
739 814 } else {
@@ -743,9 +818,9 @@
743 818 $message = $json_res['error'];
744 819 } else {
745 820 $message = $json_res;
746 821 }
747 - } elseif ( isset( $resp['response'] ) && isset( $resp['response']['code'] ) ) {
822 + } elseif ( ! empty( $resp['response'] ) && ! empty( $resp['response']['code'] ) ) {
748 823 $resp['body'] = wp_strip_all_tags( $resp['body'] );
749 824
750 825 $message = sprintf(
751 826 /* translators: %1$s: Error code, %2$s: Error message */
@@ -753,9 +828,9 @@
753 828 esc_html( $resp['response']['code'] ),
754 829 $resp['response']['message'] . ' ' . $resp['body']
755 830 );
756 831 }
757 - }
832 + }//end if
758 833
759 834 return $message;
760 835 }
761 836
@@ -766,6 +841,46 @@
766 841 $updates->translations = array();
767 842 $updates->no_update = array();
768 843 $updates->checked = array();
769 844 set_site_transient( 'update_plugins', $updates );
845 + }
846 +
847 + /**
848 + * Set the transient key for the lock. It should be unique to the license.
849 + *
850 + * @since 6.8.3
851 + *
852 + * @return bool
853 + */
854 + protected function lock_key() {
855 + return $this->transient_lock_key . '_' . $this->license;
856 + }
857 +
858 + /**
859 + * Prevent multiple requests from running at the same time.
860 + *
861 + * @since 6.8.3
862 + *
863 + * @return bool
864 + */
865 + protected function is_running() {
866 + return get_transient( $this->lock_key() );
867 + }
868 +
869 + /**
870 + * @since 6.8.3
871 + *
872 + * @return void
873 + */
874 + protected function set_running() {
875 + set_transient( $this->lock_key(), true, 2 * MINUTE_IN_SECONDS );
876 + }
877 +
878 + /**
879 + * @since 6.8.3
880 + *
881 + * @return void
882 + */
883 + protected function done_running() {
884 + delete_transient( $this->lock_key() );
770 885 }
771 886 }