PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 5.0.09
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v5.0.09
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 5.0.09, at classes/models/FrmAddon.php

702 lines 20.6 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 class FrmAddon {
7 public $store_url = 'https://formidableforms.com';
8 public $download_id;
9 public $plugin_file;
10 public $plugin_folder;
11 public $plugin_name;
12 public $plugin_slug;
13 public $option_name;
14 public $version;
15 public $author = 'Strategy11';
16 public $is_parent_licence = false;
17 public $needs_license = true;
18 private $is_expired_addon = false;
19 public $license;
20 protected $get_beta = false;
21
22 public function __construct() {
23
24 if ( empty( $this->plugin_slug ) ) {
25 $this->plugin_slug = preg_replace( '/[^a-zA-Z0-9_\s]/', '', str_replace( ' ', '_', strtolower( $this->plugin_name ) ) );
26 }
27 if ( empty( $this->option_name ) ) {
28 $this->option_name = 'edd_' . $this->plugin_slug . '_license_';
29 }
30
31 $this->plugin_folder = plugin_basename( $this->plugin_file );
32 $this->license = $this->get_license();
33
34 add_filter( 'frm_installed_addons', array( &$this, 'insert_installed_addon' ) );
35 $this->edd_plugin_updater();
36 }
37
38 public static function load_hooks() {
39 add_filter( 'frm_include_addon_page', '__return_true' );
40 //new static();
41 }
42
43 public function insert_installed_addon( $plugins ) {
44 $plugins[ $this->plugin_slug ] = $this;
45
46 return $plugins;
47 }
48
49 public static function get_addon( $plugin_slug ) {
50 $plugins = apply_filters( 'frm_installed_addons', array() );
51 $plugin = false;
52 if ( isset( $plugins[ $plugin_slug ] ) ) {
53 $plugin = $plugins[ $plugin_slug ];
54 }
55
56 return $plugin;
57 }
58
59 public function edd_plugin_updater() {
60
61 $this->is_license_revoked();
62 $license = $this->license;
63
64 add_action( 'after_plugin_row_' . plugin_basename( $this->plugin_file ), array( $this, 'maybe_show_license_message' ), 10, 2 );
65
66 if ( ! empty( $license ) ) {
67
68 if ( 'formidable/formidable.php' !== $this->plugin_folder ) {
69 add_filter( 'plugins_api', array( &$this, 'plugins_api_filter' ), 10, 3 );
70 }
71
72 add_filter( 'site_transient_update_plugins', array( &$this, 'clear_expired_download' ) );
73 }
74 }
75
76 /**
77 * Updates information on the "View version x.x details" page with custom data.
78 *
79 * @uses api_request()
80 *
81 * @param mixed $_data
82 * @param string $_action
83 * @param object $_args
84 *
85 * @return object $_data
86 */
87 public function plugins_api_filter( $_data, $_action = '', $_args = null ) {
88
89 if ( $_action != 'plugin_information' ) {
90 return $_data;
91 }
92
93 $slug = basename( $this->plugin_file, '.php' );
94 if ( ! isset( $_args->slug ) || $_args->slug != $slug ) {
95 return $_data;
96 }
97
98 $item_id = $this->download_id;
99 if ( empty( $item_id ) ) {
100 $_data = array(
101 'name' => $this->plugin_name,
102 'excerpt' => '',
103 'changelog' => 'See the full changelog at <a href="' . esc_url( $this->store_url . '/changelog/' ) . '"></a>',
104 'banners' => array(
105 'high' => '',
106 'low' => 'https://ps.w.org/formidable/assets/banner-1544x500.png',
107 ),
108 );
109 } else {
110 $api = new FrmFormApi( $this->license );
111 $plugins = $api->get_api_info();
112 $_data = $plugins[ $item_id ];
113 }
114
115 $_data['sections'] = array(
116 'description' => $_data['excerpt'],
117 'changelog' => $_data['changelog'],
118 );
119 $_data['author'] = '<a href="' . esc_url( $this->store_url ) . '">' . esc_html( $this->author ) . '</a>';
120 $_data['homepage'] = $this->store_url;
121
122 return (object) $_data;
123 }
124
125 public function get_license() {
126 $license = $this->maybe_get_pro_license();
127 if ( ! empty( $license ) ) {
128 return $license;
129 }
130
131 $license = trim( get_option( $this->option_name . 'key' ) );
132 if ( empty( $license ) ) {
133 $license = $this->activate_defined_license();
134 }
135
136 return $license;
137 }
138
139 /**
140 * @since 3.04.03
141 */
142 protected function maybe_get_pro_license() {
143 // prevent a loop if $this is the pro plugin
144 $get_license = FrmAppHelper::pro_is_installed() && is_callable( 'FrmProAppHelper::get_updater' ) && $this->plugin_name != 'Formidable Pro';
145
146 if ( ! $get_license ) {
147 return false;
148 }
149
150 $api = new FrmFormApi();
151 $api->get_pro_updater();
152 $license = $api->get_license();
153 if ( empty( $license ) ) {
154 return false;
155 }
156
157 $this->get_api_info( $license );
158 if ( ! $this->is_parent_licence ) {
159 $license = false;
160 }
161
162 return $license;
163 }
164
165 /**
166 * Activate the license in wp-config.php
167 *
168 * @since 2.04
169 */
170 public function activate_defined_license() {
171 $license = $this->get_defined_license();
172 if ( ! empty( $license ) && ! $this->is_active() && $this->is_time_to_auto_activate() ) {
173 $response = $this->activate_license( $license );
174 $this->set_auto_activate_time();
175 if ( ! $response['success'] ) {
176 $license = '';
177 }
178 }
179
180 return $license;
181 }
182
183 /**
184 * Check the wp-config.php for the license key
185 *
186 * @since 2.04
187 */
188 public function get_defined_license() {
189 $consant_name = 'FRM_' . strtoupper( $this->plugin_slug ) . '_LICENSE';
190
191 return defined( $consant_name ) ? constant( $consant_name ) : false;
192 }
193
194 public function set_license( $license ) {
195 update_option( $this->option_name . 'key', $license );
196 }
197
198 /**
199 * If the license is in the config, limit the frequency of checks.
200 * The license may be entered incorrectly, so we don't want to check on every page load.
201 *
202 * @since 2.04
203 */
204 private function is_time_to_auto_activate() {
205 $last_try = get_option( $this->option_name . 'last_activate' );
206
207 return ( ! $last_try || $last_try < strtotime( '-1 day' ) );
208 }
209
210 private function set_auto_activate_time() {
211 update_option( $this->option_name . 'last_activate', time() );
212 }
213
214 public function is_active() {
215 return get_option( $this->option_name . 'active' );
216 }
217
218 /**
219 * @since 3.04.03
220 *
221 * @param array error
222 */
223 public function maybe_clear_license( $error ) {
224 if ( $error['code'] === 'disabled' && $error['license'] === $this->license ) {
225 $this->clear_license();
226 }
227 }
228
229 public function clear_license() {
230 delete_option( $this->option_name . 'active' );
231 delete_option( $this->option_name . 'key' );
232 delete_site_option( $this->transient_key() );
233 delete_option( $this->transient_key() );
234 $this->delete_cache();
235 }
236
237 public function set_active( $is_active ) {
238 update_option( $this->option_name . 'active', $is_active );
239 $this->delete_cache();
240 FrmAppHelper::save_combined_js();
241 $this->update_pro_capabilities();
242 }
243
244 /**
245 * Updates roles capabilities after pro license is active.
246 *
247 * @since 5.0
248 */
249 protected function update_pro_capabilities() {
250 global $wp_roles;
251
252 $caps = FrmAppHelper::frm_capabilities( 'pro_only' );
253 $roles = get_editable_roles();
254 $settings = new FrmSettings();
255 foreach ( $caps as $cap => $cap_desc ) {
256 $cap_roles = (array) ( isset( $settings->$cap ) ? $settings->$cap : 'administrator' );
257
258 // Make sure administrators always have permissions.
259 if ( ! in_array( 'administrator', $cap_roles ) ) {
260 array_push( $cap_roles, 'administrator' );
261 }
262
263 foreach ( $roles as $role => $details ) {
264 if ( in_array( $role, $cap_roles ) ) {
265 $wp_roles->add_cap( $role, $cap );
266 } else {
267 $wp_roles->remove_cap( $role, $cap );
268 }
269 }
270 }
271 }
272
273 /**
274 * @since 3.04.03
275 */
276 protected function delete_cache() {
277 delete_transient( 'frm_api_licence' );
278
279 $api = new FrmFormApi( $this->license );
280 $api->reset_cached();
281
282 $api = new FrmFormTemplateApi( $this->license );
283 $api->reset_cached();
284 }
285
286 /**
287 * The Pro version includes the show_license_message function.
288 * We need an extra check before we allow it to show a message.
289 *
290 * @since 3.04.03
291 */
292 public function maybe_show_license_message( $file, $plugin ) {
293 if ( $this->is_expired_addon || isset( $plugin['package'] ) ) {
294 // let's not show a ton of duplicate messages
295 return;
296 }
297
298 $this->show_license_message( $file, $plugin );
299 }
300
301 public function show_license_message( $file, $plugin ) {
302 $message = '';
303 if ( empty( $this->license ) ) {
304 /* translators: %1$s: Plugin name, %2$s: Start link HTML, %3$s: end link HTML */
305 $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>' );
306 } else {
307 $api = new FrmFormApi( $this->license );
308 $errors = $api->error_for_license();
309 if ( ! empty( $errors ) ) {
310 $message = reset( $errors );
311 }
312 }
313
314 if ( empty( $message ) ) {
315 return;
316 }
317
318 $wp_list_table = _get_list_table( 'WP_Plugins_List_Table' );
319 $id = sanitize_title( $plugin['Name'] ) . '-next';
320
321 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>';
322 echo FrmAppHelper::kses( $message, 'a' ); // WPCS: XSS ok.
323 echo '<script type="text/javascript">var d = document.getElementById("' . esc_attr( $id ) . '").previousSibling;if ( d !== null ){ d.className = d.className + " update"; }</script>';
324 echo '</p></div></td></tr>';
325 }
326
327 public function clear_expired_download( $transient ) {
328 if ( ! is_object( $transient ) ) {
329 return $transient;
330 }
331
332 if ( $this->is_current_version( $transient ) ) {
333 //make sure it doesn't show there is an update if plugin is up-to-date
334 if ( isset( $transient->response[ $this->plugin_folder ] ) ) {
335 unset( $transient->response[ $this->plugin_folder ] );
336 }
337 } elseif ( isset( $transient->response ) && isset( $transient->response[ $this->plugin_folder ] ) ) {
338 $this->prepare_update_details( $transient->response[ $this->plugin_folder ] );
339
340 // if the transient has expired, clear the update and trigger it again
341 if ( $transient->response[ $this->plugin_folder ] === false ) {
342 if ( ! $this->has_been_cleared() ) {
343 $this->cleared_plugins();
344 $this->manually_queue_update();
345 }
346 unset( $transient->response[ $this->plugin_folder ] );
347 }
348 }
349
350 return $transient;
351 }
352
353 /**
354 * Check if the plugin information is correct to allow an update
355 *
356 * @since 3.04.03
357 *
358 * @param object $transient - the current plugin info saved for update
359 */
360 private function prepare_update_details( &$transient ) {
361 $version_info = $transient;
362 $has_beta_url = isset( $version_info->beta ) && ! empty( $version_info->beta );
363 if ( $this->get_beta && ! $has_beta_url ) {
364 $version_info = (object) $this->get_api_info( $this->license );
365 }
366
367 if ( isset( $version_info->new_version ) && ! empty( $version_info->new_version ) ) {
368 $this->clear_old_plugin_version( $version_info );
369 if ( $version_info === false ) { // was cleared with timeout
370 $transient = false;
371 } else {
372 $this->maybe_use_beta_url( $version_info );
373
374 if ( version_compare( $version_info->new_version, $this->version, '>' ) ) {
375 $transient = $version_info;
376 }
377 }
378 }
379 }
380
381 /**
382 * Get the API info for this plugin
383 *
384 * @since 3.04.03
385 */
386 protected function get_api_info( $license ) {
387 $api = new FrmFormApi( $license );
388 $addon = $api->get_addon_for_license( $this );
389
390 // if there is no download url, this license does not apply to the addon
391 if ( isset( $addon['package'] ) ) {
392 $this->is_parent_licence = true;
393 } elseif ( isset( $addon['error'] ) ) {
394 // if the license is expired, we must assume all add-ons were packaged
395 $this->is_parent_licence = true;
396 $this->is_expired_addon = true;
397 }
398
399 return $addon;
400 }
401
402 /**
403 * Make sure transients don't stick around on sites that
404 * don't save the transient expiration
405 *
406 * @since 2.05.05
407 */
408 private function clear_old_plugin_version( &$version_info ) {
409 $timeout = ( isset( $version_info->timeout ) && ! empty( $version_info->timeout ) ) ? $version_info->timeout : 0;
410 if ( ! empty( $timeout ) && time() > $timeout ) {
411 $version_info = false; // Cache is expired
412 $api = new FrmFormApi( $this->license );
413 $api->reset_cached();
414 }
415 }
416
417 /**
418 * The beta url is always included if the download has a beta.
419 * Check if the beta should be downloaded.
420 *
421 * @since 3.04.03
422 */
423 private function maybe_use_beta_url( &$version_info ) {
424 if ( $this->get_beta && isset( $version_info->beta ) && ! empty( $version_info->beta ) ) {
425 $version_info->new_version = $version_info->beta['version'];
426 $version_info->package = $version_info->beta['package'];
427 if ( isset( $version_info->plugin ) && ! empty( $version_info->plugin ) ) {
428 $version_info->plugin = $version_info->beta['plugin'];
429 }
430 }
431 }
432
433 private function is_current_version( $transient ) {
434 if ( empty( $transient->checked ) || ! isset( $transient->checked[ $this->plugin_folder ] ) ) {
435 return false;
436 }
437
438 $response = ! isset( $transient->response ) || empty( $transient->response );
439 if ( $response ) {
440 return true;
441 }
442
443 return isset( $transient->response ) && isset( $transient->response[ $this->plugin_folder ] ) && $transient->checked[ $this->plugin_folder ] === $transient->response[ $this->plugin_folder ]->new_version;
444 }
445
446 private function has_been_cleared() {
447 $last_cleared = get_option( 'frm_last_cleared' );
448
449 return ( $last_cleared && $last_cleared > gmdate( 'Y-m-d H:i:s', strtotime( '-5 minutes' ) ) );
450 }
451
452 private function cleared_plugins() {
453 update_option( 'frm_last_cleared', gmdate( 'Y-m-d H:i:s' ) );
454 }
455
456 private function is_license_revoked() {
457 if ( empty( $this->license ) || empty( $this->plugin_slug ) || isset( $_POST['license'] ) ) { // WPCS: CSRF ok.
458 return;
459 }
460
461 if ( is_multisite() ) {
462 $last_checked = get_site_option( $this->transient_key() );
463 } else {
464 $last_checked = get_option( $this->transient_key() );
465 }
466
467 $seven_days_ago = gmdate( 'Y-m-d H:i:s', strtotime( '-7 days' ) );
468
469 if ( ! $last_checked || $last_checked < $seven_days_ago ) {
470 // check weekly
471 if ( is_multisite() ) {
472 update_site_option( $this->transient_key(), gmdate( 'Y-m-d H:i:s' ) );
473 } else {
474 update_option( $this->transient_key(), gmdate( 'Y-m-d H:i:s' ) );
475 }
476
477 $response = $this->get_license_status();
478 if ( 'revoked' === $response['status'] || 'blocked' === $response['status'] || 'disabled' === $response['status'] ) {
479 $this->clear_license();
480 }
481 }
482 }
483
484 /**
485 * Use a new cache after the license is changed, or Formidable is updated.
486 */
487 private function transient_key() {
488 return 'frm_' . md5( sanitize_key( $this->license . '_' . $this->plugin_slug ) );
489 }
490
491 public static function activate() {
492 FrmAppHelper::permission_check( 'frm_change_settings' );
493 check_ajax_referer( 'frm_ajax', 'nonce' );
494
495 $license = stripslashes( FrmAppHelper::get_param( 'license', '', 'post', 'sanitize_text_field' ) );
496 if ( empty( $license ) ) {
497 wp_die(
498 json_encode(
499 array(
500 'message' => __( 'Oops! You forgot to enter your license number.', 'formidable' ),
501 'success' => false,
502 )
503 )
504 );
505 }
506
507 $plugin_slug = FrmAppHelper::get_param( 'plugin', '', 'post', 'sanitize_text_field' );
508 $response = self::activate_license_for_plugin( $license, $plugin_slug );
509
510 echo json_encode( $response );
511 wp_die();
512 }
513
514 /**
515 * @since 4.08
516 */
517 public static function activate_license_for_plugin( $license, $plugin_slug ) {
518 $this_plugin = self::get_addon( $plugin_slug );
519 return $this_plugin->activate_license( $license );
520 }
521
522 private function activate_license( $license ) {
523 $this->set_license( $license );
524 $this->license = $license;
525
526 $response = $this->get_license_status();
527 $response['message'] = '';
528 $response['success'] = false;
529
530 if ( $response['error'] ) {
531 $response['message'] = $response['status'];
532 } else {
533 $messages = $this->get_messages();
534 if ( is_string( $response['status'] ) && isset( $messages[ $response['status'] ] ) ) {
535 $response['message'] = $messages[ $response['status'] ];
536 } else {
537 $response['message'] = FrmAppHelper::kses( $response['status'], array( 'a' ) );
538 }
539
540 $is_valid = false;
541 if ( 'valid' === $response['status'] ) {
542 $is_valid = 'valid';
543 $response['success'] = true;
544 }
545 $this->set_active( $is_valid );
546 }
547
548 return $response;
549 }
550
551 private function get_license_status() {
552 $response = array(
553 'status' => 'missing',
554 'error' => true,
555 );
556 if ( empty( $this->license ) ) {
557 $response['error'] = false;
558
559 return $response;
560 }
561
562 try {
563 $response['error'] = false;
564 $license_data = $this->send_mothership_request( 'activate_license' );
565
566 // $license_data->license will be either "valid" or "invalid"
567 if ( is_array( $license_data ) ) {
568 if ( in_array( $license_data['license'], array( 'valid', 'invalid' ), true ) ) {
569 $response['status'] = $license_data['license'];
570 }
571 } else {
572 $response['status'] = $license_data;
573 }
574 } catch ( Exception $e ) {
575 $response['status'] = $e->getMessage();
576 }
577
578 return $response;
579 }
580
581 private function get_messages() {
582 return array(
583 'valid' => __( 'Your license has been activated. Enjoy!', 'formidable' ),
584 'invalid' => __( 'That license key is invalid', 'formidable' ),
585 'expired' => __( 'That license is expired', 'formidable' ),
586 'revoked' => __( 'That license has been refunded', 'formidable' ),
587 'no_activations_left' => __( 'That license has been used on too many sites', 'formidable' ),
588 'invalid_item_id' => __( 'Oops! That is the wrong license key for this plugin.', 'formidable' ),
589 'missing' => __( 'That license key is invalid', 'formidable' ),
590 );
591 }
592
593 /**
594 * @since 4.03
595 */
596 public static function reset_cache() {
597 FrmAppHelper::permission_check( 'frm_change_settings' );
598 check_ajax_referer( 'frm_ajax', 'nonce' );
599
600 $this_plugin = self::set_license_from_post();
601 $this_plugin->delete_cache();
602
603 $response = array(
604 'success' => true,
605 'message' => __( 'Cache cleared', 'formidable' ),
606 );
607
608 echo json_encode( $response );
609 wp_die();
610 }
611
612 public static function deactivate() {
613 FrmAppHelper::permission_check( 'frm_change_settings' );
614 check_ajax_referer( 'frm_ajax', 'nonce' );
615
616 $this_plugin = self::set_license_from_post();
617
618 $response = array(
619 'success' => false,
620 'message' => '',
621 );
622 try {
623 // $license_data->license will be either "deactivated" or "failed"
624 $license_data = $this_plugin->send_mothership_request( 'deactivate_license' );
625 if ( is_array( $license_data ) && 'deactivated' === $license_data['license'] ) {
626 $response['success'] = true;
627 $response['message'] = __( 'That license was removed successfully', 'formidable' );
628 } else {
629 $response['message'] = __( 'There was an error deactivating your license.', 'formidable' );
630 }
631 } catch ( Exception $e ) {
632 $response['message'] = $e->getMessage();
633 }
634
635 $this_plugin->clear_license();
636
637 echo json_encode( $response );
638 wp_die();
639 }
640
641 /**
642 * @since 4.03
643 */
644 private static function set_license_from_post() {
645 $plugin_slug = FrmAppHelper::get_param( 'plugin', '', 'post', 'sanitize_text_field' );
646 $this_plugin = self::get_addon( $plugin_slug );
647 $license = $this_plugin->get_license();
648 $this_plugin->license = $license;
649 return $this_plugin;
650 }
651
652 public function send_mothership_request( $action ) {
653 $api_params = array(
654 'edd_action' => $action,
655 'license' => $this->license,
656 'url' => home_url(),
657 );
658 if ( is_numeric( $this->download_id ) ) {
659 $api_params['item_id'] = absint( $this->download_id );
660 } else {
661 $api_params['item_name'] = rawurlencode( $this->plugin_name );
662 }
663
664 $arg_array = array(
665 'body' => $api_params,
666 'timeout' => 25,
667 'user-agent' => $this->plugin_slug . '/' . $this->version . '; ' . get_bloginfo( 'url' ),
668 );
669
670 $resp = wp_remote_post( $this->store_url, $arg_array );
671 $body = wp_remote_retrieve_body( $resp );
672
673 $message = __( 'Your License Key was invalid', 'formidable' );
674 if ( is_wp_error( $resp ) ) {
675 $link = FrmAppHelper::admin_upgrade_link( 'api', 'knowledgebase/why-cant-i-activate-formidable-pro/' );
676 /* translators: %1$s: Start link HTML, %2$s: End link HTML */
677 $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>' );
678 $message .= ' ' . $resp->get_error_message();
679 } elseif ( 'error' === $body || is_wp_error( $body ) ) {
680 $message = __( 'You had an HTTP error connecting to the Formidable API', 'formidable' );
681 } else {
682 $json_res = json_decode( $body, true );
683 if ( null !== $json_res ) {
684 if ( is_array( $json_res ) && isset( $json_res['error'] ) ) {
685 $message = $json_res['error'];
686 } else {
687 $message = $json_res;
688 }
689 } elseif ( isset( $resp['response'] ) && isset( $resp['response']['code'] ) ) {
690 /* translators: %1$s: Error code, %2$s: Error message */
691 $message = sprintf( __( 'There was a %1$s error: %2$s', 'formidable' ), $resp['response']['code'], $resp['response']['message'] . ' ' . $resp['body'] );
692 }
693 }
694
695 return $message;
696 }
697
698 public function manually_queue_update() {
699 set_site_transient( 'update_plugins', null );
700 }
701 }
702