PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.9
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.9
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
formidable / classes / models / FrmAddon.php

FrmAddon.php in Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More 6.9, at classes/models/FrmAddon.php

885 lines 25.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if ( ! defined( 'ABSPATH' ) ) {
3 die( 'You are not allowed to call this page directly.' );
4 }
5
6 /** @phpstan-consistent-constructor */
7 class FrmAddon {
8 public $store_url = 'https://formidableforms.com';
9 public $download_id;
10 public $plugin_file;
11 public $plugin_folder;
12 public $plugin_name;
13 public $plugin_slug;
14 public $option_name;
15 public $version;
16 public $author = 'Strategy11';
17 public $is_parent_licence = false;
18 public $needs_license = true;
19 private $is_expired_addon = false;
20 public $license;
21 protected $get_beta = false;
22 protected $save_status;
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
51 public function __construct() {
52
53 if ( empty( $this->plugin_slug ) ) {
54 $this->plugin_slug = preg_replace( '/[^a-zA-Z0-9_\s]/', '', str_replace( ' ', '_', strtolower( $this->plugin_name ) ) );
55 }
56 if ( empty( $this->option_name ) ) {
57 $this->option_name = 'edd_' . $this->plugin_slug . '_license_';
58 }
59
60 $this->plugin_folder = plugin_basename( $this->plugin_file );
61 $this->license = $this->get_license();
62
63 add_filter( 'frm_installed_addons', array( &$this, 'insert_installed_addon' ) );
64 $this->edd_plugin_updater();
65 }
66
67 public static function load_hooks() {
68 add_filter( 'frm_include_addon_page', '__return_true' );
69 new static();
70 }
71
72 public function insert_installed_addon( $plugins ) {
73 $plugins[ $this->plugin_slug ] = $this;
74
75 return $plugins;
76 }
77
78 public static function get_addon( $plugin_slug ) {
79 $plugins = apply_filters( 'frm_installed_addons', array() );
80 $plugin = false;
81 if ( isset( $plugins[ $plugin_slug ] ) ) {
82 $plugin = $plugins[ $plugin_slug ];
83 }
84
85 return $plugin;
86 }
87
88 public function edd_plugin_updater() {
89
90 $this->is_license_revoked();
91 $license = $this->license;
92
93 add_action( 'after_plugin_row_' . plugin_basename( $this->plugin_file ), array( $this, 'maybe_show_license_message' ), 10, 2 );
94
95 if ( ! empty( $license ) ) {
96
97 if ( 'formidable/formidable.php' !== $this->plugin_folder ) {
98 add_filter( 'plugins_api', array( &$this, 'plugins_api_filter' ), 10, 3 );
99 }
100
101 add_filter( 'site_transient_update_plugins', array( &$this, 'clear_expired_download' ) );
102 }
103 }
104
105 /**
106 * Updates information on the "View version x.x details" page with custom data.
107 *
108 * @uses api_request()
109 *
110 * @param mixed $_data
111 * @param string $_action
112 * @param object $_args
113 *
114 * @return object $_data
115 */
116 public function plugins_api_filter( $_data, $_action = '', $_args = null ) {
117
118 if ( $_action != 'plugin_information' ) {
119 return $_data;
120 }
121
122 $slug = basename( $this->plugin_file, '.php' );
123 $slug2 = str_replace( '/' . $slug . '.php', '', $this->plugin_folder );
124 if ( empty( $_args->slug ) || ( $_args->slug != $slug && $_args->slug !== $slug2 ) ) {
125 return $_data;
126 }
127
128 $item_id = $this->download_id;
129 if ( empty( $item_id ) ) {
130 $_data = array(
131 'name' => $this->plugin_name,
132 'excerpt' => '',
133 'changelog' => 'See the full changelog at <a href="' . esc_url( $this->store_url . '/changelog/' ) . '"></a>',
134 'banners' => array(
135 'high' => '',
136 'low' => 'https://ps.w.org/formidable/assets/banner-1544x500.png',
137 ),
138 );
139 } else {
140 $api = new FrmFormApi( $this->license );
141 $plugins = $api->get_api_info();
142 $_data = $plugins[ $item_id ];
143 }
144
145 $_data['sections'] = array(
146 'description' => $_data['excerpt'],
147 'changelog' => $_data['changelog'],
148 );
149 $_data['author'] = '<a href="' . esc_url( $this->store_url ) . '">' . esc_html( $this->author ) . '</a>';
150 $_data['homepage'] = $this->store_url;
151
152 return (object) $_data;
153 }
154
155 public function get_license() {
156 $license = $this->maybe_get_pro_license();
157 if ( ! empty( $license ) ) {
158 return $license;
159 }
160
161 $license = trim( get_option( $this->option_name . 'key' ) );
162 if ( empty( $license ) ) {
163 $license = $this->activate_defined_license();
164 }
165
166 return $license;
167 }
168
169 /**
170 * @since 3.04.03
171 */
172 protected function maybe_get_pro_license() {
173 // prevent a loop if $this is the pro plugin
174 $get_license = FrmAppHelper::pro_is_installed() && is_callable( 'FrmProAppHelper::get_updater' ) && $this->plugin_name != 'Formidable Pro';
175
176 if ( ! $get_license ) {
177 return false;
178 }
179
180 $api = new FrmFormApi();
181 $api->get_pro_updater();
182 $license = $api->get_license();
183 if ( empty( $license ) ) {
184 return false;
185 }
186
187 $this->get_api_info( $license );
188 if ( ! $this->is_parent_licence ) {
189 $license = false;
190 }
191
192 return $license;
193 }
194
195 /**
196 * Activate the license in wp-config.php
197 *
198 * @since 2.04
199 */
200 public function activate_defined_license() {
201 $license = $this->get_defined_license();
202 if ( ! empty( $license ) && ! $this->is_active() && ! $this->checked_recently( '1 day' ) ) {
203 $response = $this->activate_license( $license );
204 if ( ! $response['success'] ) {
205 $license = '';
206 }
207 }
208
209 return $license;
210 }
211
212 /**
213 * Check the wp-config.php for the license key
214 *
215 * @since 2.04
216 */
217 public function get_defined_license() {
218 $consant_name = 'FRM_' . strtoupper( $this->plugin_slug ) . '_LICENSE';
219
220 return defined( $consant_name ) ? constant( $consant_name ) : false;
221 }
222
223 public function set_license( $license ) {
224 update_option( $this->option_name . 'key', $license );
225 }
226
227 public function is_active() {
228 return get_option( $this->option_name . 'active' );
229 }
230
231 /**
232 * @since 3.04.03
233 *
234 * @param array|string $error
235 */
236 public function maybe_clear_license( $error ) {
237 if ( is_array( $error ) && $error['code'] === 'disabled' && $error['license'] === $this->license ) {
238 $this->clear_license();
239 }
240 }
241
242 public function clear_license() {
243 delete_option( $this->option_name . 'active' );
244 delete_option( $this->option_name . 'key' );
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 }
252 }
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
277 public function set_active( $is_active ) {
278 $this->delete_cache();
279 FrmAppHelper::save_combined_js();
280 $this->update_pro_capabilities();
281 }
282
283 /**
284 * Updates roles capabilities after pro license is active.
285 *
286 * @since 5.0
287 */
288 protected function update_pro_capabilities() {
289 global $wp_roles;
290
291 if ( ! function_exists( 'get_editable_roles' ) ) {
292 require_once ABSPATH . 'wp-admin/includes/user.php';
293 }
294
295 $caps = FrmAppHelper::frm_capabilities( 'pro_only' );
296 $roles = get_editable_roles();
297 $settings = new FrmSettings();
298 foreach ( $caps as $cap => $cap_desc ) {
299 $cap_roles = (array) ( isset( $settings->$cap ) ? $settings->$cap : 'administrator' );
300
301 // Make sure administrators always have permissions.
302 if ( ! in_array( 'administrator', $cap_roles ) ) {
303 array_push( $cap_roles, 'administrator' );
304 }
305
306 foreach ( $roles as $role => $details ) {
307 if ( in_array( $role, $cap_roles ) ) {
308 $wp_roles->add_cap( $role, $cap );
309 } else {
310 $wp_roles->remove_cap( $role, $cap );
311 }
312 }
313 }
314 }
315
316 /**
317 * @since 3.04.03
318 */
319 protected function delete_cache() {
320 delete_transient( 'frm_api_licence' );
321
322 // Cleanup option that has been removed.
323 delete_option( $this->option_name . 'last_activate' );
324
325 $api = new FrmFormApi( $this->license );
326 $api->reset_cached();
327
328 $api = new FrmFormTemplateApi( $this->license );
329 $api->reset_cached();
330
331 $api = new FrmApplicationApi( $this->license );
332 $api->reset_cached();
333 }
334
335 /**
336 * The Pro version includes the show_license_message function.
337 * We need an extra check before we allow it to show a message.
338 *
339 * @since 3.04.03
340 */
341 public function maybe_show_license_message( $file, $plugin ) {
342 if ( $this->is_expired_addon || isset( $plugin['package'] ) ) {
343 // let's not show a ton of duplicate messages
344 return;
345 }
346
347 $this->show_license_message( $file, $plugin );
348 }
349
350 public function show_license_message( $file, $plugin ) {
351 $message = '';
352 if ( empty( $this->license ) ) {
353 /* translators: %1$s: Plugin name, %2$s: Start link HTML, %3$s: end link HTML */
354 $message = sprintf( esc_html__( 'Your %1$s license key is missing. Please add it on the %2$slicenses page%3$s.', 'formidable' ), esc_html( $this->plugin_name ), '<a href="' . esc_url( admin_url( 'admin.php?page=formidable-settings' ) ) . '">', '</a>' );
355 } else {
356 $api = new FrmFormApi( $this->license );
357 $errors = $api->error_for_license();
358 if ( ! empty( $errors ) ) {
359 $message = reset( $errors );
360 }
361 }
362
363 if ( empty( $message ) ) {
364 return;
365 }
366
367 $wp_list_table = _get_list_table( 'WP_Plugins_List_Table' );
368 $id = sanitize_title( $plugin['Name'] ) . '-next';
369
370 echo '<tr class="plugin-update-tr active" id="' . esc_attr( $id ) . '"><td colspan="' . esc_attr( $wp_list_table->get_column_count() ) . '" class="plugin-update colspanchange"><div class="update-message notice error inline notice-error notice-alt"><p>';
371 echo FrmAppHelper::kses( $message, 'a' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
372 echo '<script type="text/javascript">var d = document.getElementById("' . esc_attr( $id ) . '").previousSibling;if ( d !== null ){ d.className = d.className + " update"; }</script>';
373 echo '</p></div></td></tr>';
374 }
375
376 public function clear_expired_download( $transient ) {
377 if ( ! is_object( $transient ) ) {
378 return $transient;
379 }
380
381 if ( $this->is_current_version( $transient ) ) {
382 // Make sure it doesn't show there is an update if plugin is up-to-date.
383 if ( isset( $transient->response[ $this->plugin_folder ] ) ) {
384 unset( $transient->response[ $this->plugin_folder ] );
385 }
386 } elseif ( isset( $transient->response ) && isset( $transient->response[ $this->plugin_folder ] ) ) {
387 $this->prepare_update_details( $transient->response[ $this->plugin_folder ] );
388
389 // if the transient has expired, clear the update and trigger it again
390 if ( $transient->response[ $this->plugin_folder ] === false ) {
391 if ( ! $this->has_been_cleared() ) {
392 $this->cleared_plugins();
393 $this->manually_queue_update();
394 }
395 unset( $transient->response[ $this->plugin_folder ] );
396 }
397 }
398
399 return $transient;
400 }
401
402 /**
403 * Check if the plugin information is correct to allow an update
404 *
405 * @since 3.04.03
406 *
407 * @param object $transient The current plugin info saved for update.
408 */
409 private function prepare_update_details( &$transient ) {
410 $version_info = $transient;
411 $has_beta_url = isset( $version_info->beta ) && ! empty( $version_info->beta );
412 if ( $this->get_beta && ! $has_beta_url ) {
413 $version_info = (object) $this->get_api_info( $this->license );
414 }
415
416 if ( isset( $version_info->new_version ) && ! empty( $version_info->new_version ) ) {
417 $this->clear_old_plugin_version( $version_info );
418 if ( $version_info === false ) {
419 // Was cleared with timeout.
420 $transient = false;
421 } else {
422 $this->maybe_use_beta_url( $version_info );
423
424 if ( version_compare( $version_info->new_version, $this->version, '>' ) ) {
425 $transient = $version_info;
426 }
427 }
428 }
429 }
430
431 /**
432 * Get the API info for this plugin
433 *
434 * @since 3.04.03
435 */
436 protected function get_api_info( $license ) {
437 $api = new FrmFormApi( $license );
438 $addon = $api->get_addon_for_license( $this );
439
440 // if there is no download url, this license does not apply to the addon
441 if ( isset( $addon['package'] ) ) {
442 $this->is_parent_licence = true;
443 } elseif ( isset( $addon['error'] ) ) {
444 // if the license is expired, we must assume all add-ons were packaged
445 $this->is_parent_licence = true;
446 $this->is_expired_addon = true;
447 }
448
449 return $addon;
450 }
451
452 /**
453 * Make sure transients don't stick around on sites that
454 * don't save the transient expiration
455 *
456 * @since 2.05.05
457 */
458 private function clear_old_plugin_version( &$version_info ) {
459 $timeout = ( isset( $version_info->timeout ) && ! empty( $version_info->timeout ) ) ? $version_info->timeout : 0;
460 if ( ! empty( $timeout ) && time() > $timeout ) {
461 // Cache is expired.
462 $version_info = false;
463 $api = new FrmFormApi( $this->license );
464 $api->reset_cached();
465 }
466 }
467
468 /**
469 * The beta url is always included if the download has a beta.
470 * Check if the beta should be downloaded.
471 *
472 * @since 3.04.03
473 */
474 private function maybe_use_beta_url( &$version_info ) {
475 if ( $this->get_beta && isset( $version_info->beta ) && ! empty( $version_info->beta ) ) {
476 $version_info->new_version = $version_info->beta['version'];
477 $version_info->package = $version_info->beta['package'];
478 if ( isset( $version_info->plugin ) && ! empty( $version_info->plugin ) ) {
479 $version_info->plugin = $version_info->beta['plugin'];
480 }
481 }
482 }
483
484 private function is_current_version( $transient ) {
485 if ( empty( $transient->checked ) || ! isset( $transient->checked[ $this->plugin_folder ] ) ) {
486 return false;
487 }
488
489 $response = ! isset( $transient->response ) || empty( $transient->response );
490 if ( $response ) {
491 return true;
492 }
493
494 return isset( $transient->response ) && isset( $transient->response[ $this->plugin_folder ] ) && $transient->checked[ $this->plugin_folder ] === $transient->response[ $this->plugin_folder ]->new_version;
495 }
496
497 private function has_been_cleared() {
498 $last_cleared = get_option( 'frm_last_cleared' );
499
500 return ( $last_cleared && $last_cleared > gmdate( 'Y-m-d H:i:s', strtotime( '-5 minutes' ) ) );
501 }
502
503 private function cleared_plugins() {
504 update_option( 'frm_last_cleared', gmdate( 'Y-m-d H:i:s' ) );
505 }
506
507 private function is_license_revoked() {
508 if ( empty( $this->license ) || empty( $this->plugin_slug ) || isset( $_POST['license'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
509 return;
510 }
511
512 if ( $this->get_defined_license() ) {
513 // Don't check if the license is defined in wp-config.php since we can't remove it.
514 return;
515 }
516
517 // Only check weekly.
518 if ( $this->checked_recently( '7 days', 'valid' ) || $this->is_running() ) {
519 return;
520 }
521
522 $response = $this->get_license_status();
523 if ( 'revoked' === $response['status'] || 'blocked' === $response['status'] || 'disabled' === $response['status'] || 'missing' === $response['status'] ) {
524 $this->clear_license();
525 }
526 }
527
528 /**
529 * Has this been checked too recently?
530 *
531 * @param string $time ie. '1 day'.
532 * @param string $required_status Return false if the last check does not match. ie 'valid'.
533 *
534 * @return bool
535 */
536 private function checked_recently( $time, $required_status = '' ) {
537 $last_checked = $this->last_checked();
538 $is_429 = isset( $last_checked['response_code'] ) && 429 === $last_checked['response_code'];
539 if ( $is_429 ) {
540 // If the last check was a a rate limit, we'll need to check again sooner.
541 $time = '5 minutes';
542 $required_status = '';
543 }
544
545 if ( $required_status && ( ! isset( $last_checked['status'] ) || $last_checked['status'] !== $required_status ) ) {
546 // If the last check was invalid, we don't need to check again.
547 return true;
548 }
549
550 $checked_time = isset( $last_checked['time'] ) ? $last_checked['time'] : false;
551 $time_ago = gmdate( 'Y-m-d H:i:s', strtotime( '-' . $time ) );
552 return $checked_time && $checked_time > $time_ago;
553 }
554
555 /**
556 * @since 6.8.3 Switched to an array to store extra response info.
557 *
558 * @return array
559 */
560 private function last_checked() {
561 if ( is_multisite() ) {
562 $last_checked = get_site_option( $this->transient_key() );
563 } else {
564 $last_checked = get_option( $this->transient_key() );
565 }
566 if ( $last_checked && ! is_array( $last_checked ) ) {
567 // Get string into array for existing values.
568 $last_checked = array( 'time' => $last_checked );
569 }
570 return $last_checked ? (array) $last_checked : array();
571 }
572
573 /**
574 * @return void
575 */
576 private function update_last_checked() {
577 $this->save_response['time'] = gmdate( 'Y-m-d H:i:s' );
578 if ( is_multisite() ) {
579 update_site_option( $this->transient_key(), $this->save_response );
580 } else {
581 update_option( $this->transient_key(), $this->save_response );
582 }
583 }
584
585 /**
586 * Use a new cache after the license is changed, or Formidable is updated.
587 */
588 private function transient_key() {
589 return 'frm_' . md5( sanitize_key( $this->license . '_' . $this->plugin_slug ) );
590 }
591
592 public static function activate() {
593 FrmAppHelper::permission_check( 'frm_change_settings' );
594 check_ajax_referer( 'frm_ajax', 'nonce' );
595
596 $license = stripslashes( FrmAppHelper::get_param( 'license', '', 'post', 'sanitize_text_field' ) );
597 if ( empty( $license ) ) {
598 wp_send_json(
599 array(
600 'message' => __( 'Oops! You forgot to enter your license number.', 'formidable' ),
601 'success' => false,
602 )
603 );
604 }
605
606 $plugin_slug = FrmAppHelper::get_param( 'plugin', '', 'post', 'sanitize_text_field' );
607 $response = self::activate_license_for_plugin( $license, $plugin_slug );
608
609 wp_send_json( $response );
610 }
611
612 /**
613 * @since 4.08
614 */
615 public static function activate_license_for_plugin( $license, $plugin_slug ) {
616 $this_plugin = self::get_addon( $plugin_slug );
617 return $this_plugin->activate_license( $license );
618 }
619
620 private function activate_license( $license ) {
621 $this->set_license( $license );
622 $this->license = $license;
623
624 $this->die_if_not_allowed();
625
626 $response = $this->get_license_status();
627 $response['message'] = '';
628 $response['success'] = false;
629
630 if ( $response['error'] ) {
631 $response['message'] = $response['status'];
632 } else {
633 $messages = $this->get_messages();
634 if ( is_string( $response['status'] ) && isset( $messages[ $response['status'] ] ) ) {
635 $response['message'] = $messages[ $response['status'] ];
636 } else {
637 $response['message'] = FrmAppHelper::kses( $response['status'], array( 'a' ) );
638 }
639
640 $is_valid = false;
641 if ( 'valid' === $response['status'] ) {
642 $is_valid = 'valid';
643 $response['success'] = true;
644 }
645 $this->maybe_set_active( $is_valid );
646 }
647
648 $this->update_last_checked();
649
650 return $response;
651 }
652
653 /**
654 * Prevent this check from happening more than once per minute with the same license.
655 *
656 * @return void
657 */
658 private function die_if_not_allowed() {
659 if ( ! $this->checked_recently( '2 minutes' ) ) {
660 return;
661 }
662
663 // Don't check more than once per minute.
664 wp_send_json(
665 array(
666 'message' => __( 'Please wait two minutes before trying again.', 'formidable' ),
667 'success' => false,
668 )
669 );
670 }
671
672 private function get_license_status() {
673 $this->set_running();
674
675 $response = array(
676 'status' => 'missing',
677 'error' => true,
678 );
679 if ( empty( $this->license ) ) {
680 $response['error'] = false;
681
682 return $response;
683 }
684
685 try {
686 $response['error'] = false;
687 $license_data = $this->send_mothership_request( 'activate_license' );
688
689 // $license_data->license will be either "valid" or "invalid"
690 if ( is_array( $license_data ) ) {
691 if ( ! empty( $license_data['license'] ) && in_array( $license_data['license'], array( 'valid', 'invalid' ), true ) ) {
692 $response['status'] = $license_data['license'];
693 $this->save_status['status'] = $license_data['license'];
694 }
695 } else {
696 $response['status'] = $license_data;
697 }
698 } catch ( Exception $e ) {
699 $response['status'] = $e->getMessage();
700 }
701
702 $this->update_last_checked();
703 $this->done_running();
704 return $response;
705 }
706
707 private function get_messages() {
708 return array(
709 'valid' => __( 'Your license has been activated. Enjoy!', 'formidable' ),
710 'invalid' => __( 'That license key is invalid', 'formidable' ),
711 'expired' => __( 'That license is expired', 'formidable' ),
712 'revoked' => __( 'That license has been refunded', 'formidable' ),
713 'no_activations_left' => __( 'That license has been used on too many sites', 'formidable' ),
714 'invalid_item_id' => __( 'Oops! That is the wrong license key for this plugin.', 'formidable' ),
715 'missing' => __( 'That license key is invalid', 'formidable' ),
716 );
717 }
718
719 /**
720 * @since 4.03
721 */
722 public static function reset_cache() {
723 FrmAppHelper::permission_check( 'frm_change_settings' );
724 check_ajax_referer( 'frm_ajax', 'nonce' );
725
726 $this_plugin = self::set_license_from_post();
727 $this_plugin->delete_cache();
728
729 $response = array(
730 'success' => true,
731 'message' => __( 'Cache cleared', 'formidable' ),
732 );
733
734 wp_send_json( $response );
735 }
736
737 public static function deactivate() {
738 FrmAppHelper::permission_check( 'frm_change_settings' );
739 check_ajax_referer( 'frm_ajax', 'nonce' );
740
741 $this_plugin = self::set_license_from_post();
742
743 $response = array(
744 'success' => false,
745 'message' => '',
746 );
747 try {
748 // $license_data->license will be either "deactivated" or "failed"
749 $license_data = $this_plugin->send_mothership_request( 'deactivate_license' );
750 if ( is_array( $license_data ) && 'deactivated' === $license_data['license'] ) {
751 $response['success'] = true;
752 $response['message'] = __( 'That license was removed successfully', 'formidable' );
753 } else {
754 $response['message'] = __( 'There was an error deactivating your license.', 'formidable' );
755 }
756 } catch ( Exception $e ) {
757 $response['message'] = $e->getMessage();
758 }
759
760 $this_plugin->clear_license();
761
762 wp_send_json( $response );
763 }
764
765 /**
766 * @since 4.03
767 */
768 private static function set_license_from_post() {
769 $plugin_slug = FrmAppHelper::get_param( 'plugin', '', 'post', 'sanitize_text_field' );
770 $this_plugin = self::get_addon( $plugin_slug );
771 $license = $this_plugin->get_license();
772 $this_plugin->license = $license;
773 return $this_plugin;
774 }
775
776 /**
777 * @return string
778 */
779 public function send_mothership_request( $action ) {
780 $api_params = array(
781 'edd_action' => $action,
782 'license' => $this->license,
783 'url' => home_url(),
784 );
785 if ( is_numeric( $this->download_id ) ) {
786 $api_params['item_id'] = absint( $this->download_id );
787 } else {
788 $api_params['item_name'] = rawurlencode( $this->plugin_name );
789 }
790
791 $arg_array = array(
792 'body' => $api_params,
793 'timeout' => 25,
794 'user-agent' => $this->plugin_slug . '/' . $this->version . '; ' . get_bloginfo( 'url' ),
795 );
796
797 $resp = wp_remote_post(
798 $this->store_url . '?l=' . urlencode( base64_encode( $this->license ) ),
799 $arg_array
800 );
801 $body = wp_remote_retrieve_body( $resp );
802 $this->save_status = array( 'response_code' => wp_remote_retrieve_response_code( $resp ) );
803
804 $message = __( 'Your License Key was invalid', 'formidable' );
805 if ( is_wp_error( $resp ) ) {
806 $link = FrmAppHelper::admin_upgrade_link( 'api', 'knowledgebase/why-cant-i-activate-formidable-pro/' );
807 /* translators: %1$s: Start link HTML, %2$s: End link HTML */
808 $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>' );
809 $message .= ' ' . $resp->get_error_message();
810 } elseif ( 'error' === $body || is_wp_error( $body ) ) {
811 $message = __( 'You had an HTTP error connecting to the Formidable API', 'formidable' );
812 } else {
813 $json_res = json_decode( $body, true );
814 if ( null !== $json_res ) {
815 if ( is_array( $json_res ) && isset( $json_res['error'] ) ) {
816 $message = $json_res['error'];
817 } else {
818 $message = $json_res;
819 }
820 } elseif ( ! empty( $resp['response'] ) && ! empty( $resp['response']['code'] ) ) {
821 $resp['body'] = wp_strip_all_tags( $resp['body'] );
822
823 $message = sprintf(
824 /* translators: %1$s: Error code, %2$s: Error message */
825 esc_html__( 'There was a %1$s error: %2$s', 'formidable' ),
826 esc_html( $resp['response']['code'] ),
827 $resp['response']['message'] . ' ' . $resp['body']
828 );
829 }
830 }//end if
831
832 return $message;
833 }
834
835 public function manually_queue_update() {
836 $updates = new stdClass();
837 $updates->last_checked = 0;
838 $updates->response = array();
839 $updates->translations = array();
840 $updates->no_update = array();
841 $updates->checked = array();
842 set_site_transient( 'update_plugins', $updates );
843 }
844
845 /**
846 * Set the transient key for the lock. It should be unique to the license.
847 *
848 * @since 6.8.3
849 *
850 * @return bool
851 */
852 protected function lock_key() {
853 return $this->transient_lock_key . '_' . $this->license;
854 }
855
856 /**
857 * Prevent multiple requests from running at the same time.
858 *
859 * @since 6.8.3
860 *
861 * @return bool
862 */
863 protected function is_running() {
864 return get_transient( $this->lock_key() );
865 }
866
867 /**
868 * @since 6.8.3
869 *
870 * @return void
871 */
872 protected function set_running() {
873 set_transient( $this->lock_key(), true, 2 * MINUTE_IN_SECONDS );
874 }
875
876 /**
877 * @since 6.8.3
878 *
879 * @return void
880 */
881 protected function done_running() {
882 delete_transient( $this->lock_key() );
883 }
884 }
885