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

672 lines 19.8 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 }
242
243 /**
244 * @since 3.04.03
245 */
246 protected function delete_cache() {
247 delete_transient( 'frm_api_licence' );
248
249 $api = new FrmFormApi( $this->license );
250 $api->reset_cached();
251
252 $api = new FrmFormTemplateApi( $this->license );
253 $api->reset_cached();
254 }
255
256 /**
257 * The Pro version includes the show_license_message function.
258 * We need an extra check before we allow it to show a message.
259 *
260 * @since 3.04.03
261 */
262 public function maybe_show_license_message( $file, $plugin ) {
263 if ( $this->is_expired_addon || isset( $plugin['package'] ) ) {
264 // let's not show a ton of duplicate messages
265 return;
266 }
267
268 $this->show_license_message( $file, $plugin );
269 }
270
271 public function show_license_message( $file, $plugin ) {
272 $message = '';
273 if ( empty( $this->license ) ) {
274 /* translators: %1$s: Plugin name, %2$s: Start link HTML, %3$s: end link HTML */
275 $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>' );
276 } else {
277 $api = new FrmFormApi( $this->license );
278 $errors = $api->error_for_license();
279 if ( ! empty( $errors ) ) {
280 $message = reset( $errors );
281 }
282 }
283
284 if ( empty( $message ) ) {
285 return;
286 }
287
288 $wp_list_table = _get_list_table( 'WP_Plugins_List_Table' );
289 $id = sanitize_title( $plugin['Name'] ) . '-next';
290
291 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>';
292 echo FrmAppHelper::kses( $message, 'a' ); // WPCS: XSS ok.
293 echo '<script type="text/javascript">var d = document.getElementById("' . esc_attr( $id ) . '").previousSibling;if ( d !== null ){ d.className = d.className + " update"; }</script>';
294 echo '</p></div></td></tr>';
295 }
296
297 public function clear_expired_download( $transient ) {
298 if ( ! is_object( $transient ) ) {
299 return $transient;
300 }
301
302 if ( $this->is_current_version( $transient ) ) {
303 //make sure it doesn't show there is an update if plugin is up-to-date
304 if ( isset( $transient->response[ $this->plugin_folder ] ) ) {
305 unset( $transient->response[ $this->plugin_folder ] );
306 }
307 } elseif ( isset( $transient->response ) && isset( $transient->response[ $this->plugin_folder ] ) ) {
308 $this->prepare_update_details( $transient->response[ $this->plugin_folder ] );
309
310 // if the transient has expired, clear the update and trigger it again
311 if ( $transient->response[ $this->plugin_folder ] === false ) {
312 if ( ! $this->has_been_cleared() ) {
313 $this->cleared_plugins();
314 $this->manually_queue_update();
315 }
316 unset( $transient->response[ $this->plugin_folder ] );
317 }
318 }
319
320 return $transient;
321 }
322
323 /**
324 * Check if the plugin information is correct to allow an update
325 *
326 * @since 3.04.03
327 *
328 * @param object $transient - the current plugin info saved for update
329 */
330 private function prepare_update_details( &$transient ) {
331 $version_info = $transient;
332 $has_beta_url = isset( $version_info->beta ) && ! empty( $version_info->beta );
333 if ( $this->get_beta && ! $has_beta_url ) {
334 $version_info = (object) $this->get_api_info( $this->license );
335 }
336
337 if ( isset( $version_info->new_version ) && ! empty( $version_info->new_version ) ) {
338 $this->clear_old_plugin_version( $version_info );
339 if ( $version_info === false ) { // was cleared with timeout
340 $transient = false;
341 } else {
342 $this->maybe_use_beta_url( $version_info );
343
344 if ( version_compare( $version_info->new_version, $this->version, '>' ) ) {
345 $transient = $version_info;
346 }
347 }
348 }
349 }
350
351 /**
352 * Get the API info for this plugin
353 *
354 * @since 3.04.03
355 */
356 protected function get_api_info( $license ) {
357 $api = new FrmFormApi( $license );
358 $addon = $api->get_addon_for_license( $this );
359
360 // if there is no download url, this license does not apply to the addon
361 if ( isset( $addon['package'] ) ) {
362 $this->is_parent_licence = true;
363 } elseif ( isset( $addon['error'] ) ) {
364 // if the license is expired, we must assume all add-ons were packaged
365 $this->is_parent_licence = true;
366 $this->is_expired_addon = true;
367 }
368
369 return $addon;
370 }
371
372 /**
373 * Make sure transients don't stick around on sites that
374 * don't save the transient expiration
375 *
376 * @since 2.05.05
377 */
378 private function clear_old_plugin_version( &$version_info ) {
379 $timeout = ( isset( $version_info->timeout ) && ! empty( $version_info->timeout ) ) ? $version_info->timeout : 0;
380 if ( ! empty( $timeout ) && time() > $timeout ) {
381 $version_info = false; // Cache is expired
382 $api = new FrmFormApi( $this->license );
383 $api->reset_cached();
384 }
385 }
386
387 /**
388 * The beta url is always included if the download has a beta.
389 * Check if the beta should be downloaded.
390 *
391 * @since 3.04.03
392 */
393 private function maybe_use_beta_url( &$version_info ) {
394 if ( $this->get_beta && isset( $version_info->beta ) && ! empty( $version_info->beta ) ) {
395 $version_info->new_version = $version_info->beta['version'];
396 $version_info->package = $version_info->beta['package'];
397 if ( isset( $version_info->plugin ) && ! empty( $version_info->plugin ) ) {
398 $version_info->plugin = $version_info->beta['plugin'];
399 }
400 }
401 }
402
403 private function is_current_version( $transient ) {
404 if ( empty( $transient->checked ) || ! isset( $transient->checked[ $this->plugin_folder ] ) ) {
405 return false;
406 }
407
408 $response = ! isset( $transient->response ) || empty( $transient->response );
409 if ( $response ) {
410 return true;
411 }
412
413 return isset( $transient->response ) && isset( $transient->response[ $this->plugin_folder ] ) && $transient->checked[ $this->plugin_folder ] === $transient->response[ $this->plugin_folder ]->new_version;
414 }
415
416 private function has_been_cleared() {
417 $last_cleared = get_option( 'frm_last_cleared' );
418
419 return ( $last_cleared && $last_cleared > gmdate( 'Y-m-d H:i:s', strtotime( '-5 minutes' ) ) );
420 }
421
422 private function cleared_plugins() {
423 update_option( 'frm_last_cleared', gmdate( 'Y-m-d H:i:s' ) );
424 }
425
426 private function is_license_revoked() {
427 if ( empty( $this->license ) || empty( $this->plugin_slug ) || isset( $_POST['license'] ) ) { // WPCS: CSRF ok.
428 return;
429 }
430
431 if ( is_multisite() ) {
432 $last_checked = get_site_option( $this->transient_key() );
433 } else {
434 $last_checked = get_option( $this->transient_key() );
435 }
436
437 $seven_days_ago = gmdate( 'Y-m-d H:i:s', strtotime( '-7 days' ) );
438
439 if ( ! $last_checked || $last_checked < $seven_days_ago ) {
440 // check weekly
441 if ( is_multisite() ) {
442 update_site_option( $this->transient_key(), gmdate( 'Y-m-d H:i:s' ) );
443 } else {
444 update_option( $this->transient_key(), gmdate( 'Y-m-d H:i:s' ) );
445 }
446
447 $response = $this->get_license_status();
448 if ( 'revoked' === $response['status'] || 'blocked' === $response['status'] || 'disabled' === $response['status'] ) {
449 $this->clear_license();
450 }
451 }
452 }
453
454 /**
455 * Use a new cache after the license is changed, or Formidable is updated.
456 */
457 private function transient_key() {
458 return 'frm_' . md5( sanitize_key( $this->license . '_' . $this->plugin_slug ) );
459 }
460
461 public static function activate() {
462 FrmAppHelper::permission_check( 'frm_change_settings' );
463 check_ajax_referer( 'frm_ajax', 'nonce' );
464
465 $license = stripslashes( FrmAppHelper::get_param( 'license', '', 'post', 'sanitize_text_field' ) );
466 if ( empty( $license ) ) {
467 wp_die(
468 json_encode(
469 array(
470 'message' => __( 'Oops! You forgot to enter your license number.', 'formidable' ),
471 'success' => false,
472 )
473 )
474 );
475 }
476
477 $plugin_slug = FrmAppHelper::get_param( 'plugin', '', 'post', 'sanitize_text_field' );
478 $response = self::activate_license_for_plugin( $license, $plugin_slug );
479
480 echo json_encode( $response );
481 wp_die();
482 }
483
484 /**
485 * @since 4.08
486 */
487 public static function activate_license_for_plugin( $license, $plugin_slug ) {
488 $this_plugin = self::get_addon( $plugin_slug );
489 return $this_plugin->activate_license( $license );
490 }
491
492 private function activate_license( $license ) {
493 $this->set_license( $license );
494 $this->license = $license;
495
496 $response = $this->get_license_status();
497 $response['message'] = '';
498 $response['success'] = false;
499
500 if ( $response['error'] ) {
501 $response['message'] = $response['status'];
502 } else {
503 $messages = $this->get_messages();
504 if ( is_string( $response['status'] ) && isset( $messages[ $response['status'] ] ) ) {
505 $response['message'] = $messages[ $response['status'] ];
506 } else {
507 $response['message'] = FrmAppHelper::kses( $response['status'], array( 'a' ) );
508 }
509
510 $is_valid = false;
511 if ( 'valid' === $response['status'] ) {
512 $is_valid = 'valid';
513 $response['success'] = true;
514 }
515 $this->set_active( $is_valid );
516 }
517
518 return $response;
519 }
520
521 private function get_license_status() {
522 $response = array(
523 'status' => 'missing',
524 'error' => true,
525 );
526 if ( empty( $this->license ) ) {
527 $response['error'] = false;
528
529 return $response;
530 }
531
532 try {
533 $response['error'] = false;
534 $license_data = $this->send_mothership_request( 'activate_license' );
535
536 // $license_data->license will be either "valid" or "invalid"
537 if ( is_array( $license_data ) ) {
538 if ( in_array( $license_data['license'], array( 'valid', 'invalid' ), true ) ) {
539 $response['status'] = $license_data['license'];
540 }
541 } else {
542 $response['status'] = $license_data;
543 }
544 } catch ( Exception $e ) {
545 $response['status'] = $e->getMessage();
546 }
547
548 return $response;
549 }
550
551 private function get_messages() {
552 return array(
553 'valid' => __( 'Your license has been activated. Enjoy!', 'formidable' ),
554 'invalid' => __( 'That license key is invalid', 'formidable' ),
555 'expired' => __( 'That license is expired', 'formidable' ),
556 'revoked' => __( 'That license has been refunded', 'formidable' ),
557 'no_activations_left' => __( 'That license has been used on too many sites', 'formidable' ),
558 'invalid_item_id' => __( 'Oops! That is the wrong license key for this plugin.', 'formidable' ),
559 'missing' => __( 'That license key is invalid', 'formidable' ),
560 );
561 }
562
563 /**
564 * @since 4.03
565 */
566 public static function reset_cache() {
567 FrmAppHelper::permission_check( 'frm_change_settings' );
568 check_ajax_referer( 'frm_ajax', 'nonce' );
569
570 $this_plugin = self::set_license_from_post();
571 $this_plugin->delete_cache();
572
573 $response = array(
574 'success' => true,
575 'message' => __( 'Cache cleared', 'formidable' ),
576 );
577
578 echo json_encode( $response );
579 wp_die();
580 }
581
582 public static function deactivate() {
583 FrmAppHelper::permission_check( 'frm_change_settings' );
584 check_ajax_referer( 'frm_ajax', 'nonce' );
585
586 $this_plugin = self::set_license_from_post();
587
588 $response = array(
589 'success' => false,
590 'message' => '',
591 );
592 try {
593 // $license_data->license will be either "deactivated" or "failed"
594 $license_data = $this_plugin->send_mothership_request( 'deactivate_license' );
595 if ( is_array( $license_data ) && 'deactivated' === $license_data['license'] ) {
596 $response['success'] = true;
597 $response['message'] = __( 'That license was removed successfully', 'formidable' );
598 } else {
599 $response['message'] = __( 'There was an error deactivating your license.', 'formidable' );
600 }
601 } catch ( Exception $e ) {
602 $response['message'] = $e->getMessage();
603 }
604
605 $this_plugin->clear_license();
606
607 echo json_encode( $response );
608 wp_die();
609 }
610
611 /**
612 * @since 4.03
613 */
614 private static function set_license_from_post() {
615 $plugin_slug = FrmAppHelper::get_param( 'plugin', '', 'post', 'sanitize_text_field' );
616 $this_plugin = self::get_addon( $plugin_slug );
617 $license = $this_plugin->get_license();
618 $this_plugin->license = $license;
619 return $this_plugin;
620 }
621
622 public function send_mothership_request( $action ) {
623 $api_params = array(
624 'edd_action' => $action,
625 'license' => $this->license,
626 'url' => home_url(),
627 );
628 if ( is_numeric( $this->download_id ) ) {
629 $api_params['item_id'] = absint( $this->download_id );
630 } else {
631 $api_params['item_name'] = rawurlencode( $this->plugin_name );
632 }
633
634 $arg_array = array(
635 'body' => $api_params,
636 'timeout' => 25,
637 'user-agent' => $this->plugin_slug . '/' . $this->version . '; ' . get_bloginfo( 'url' ),
638 );
639
640 $resp = wp_remote_post( $this->store_url, $arg_array );
641 $body = wp_remote_retrieve_body( $resp );
642
643 $message = __( 'Your License Key was invalid', 'formidable' );
644 if ( is_wp_error( $resp ) ) {
645 $link = FrmAppHelper::admin_upgrade_link( 'api', 'knowledgebase/why-cant-i-activate-formidable-pro/' );
646 /* translators: %1$s: Start link HTML, %2$s: End link HTML */
647 $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>' );
648 $message .= ' ' . $resp->get_error_message();
649 } elseif ( 'error' === $body || is_wp_error( $body ) ) {
650 $message = __( 'You had an HTTP error connecting to the Formidable API', 'formidable' );
651 } else {
652 $json_res = json_decode( $body, true );
653 if ( null !== $json_res ) {
654 if ( is_array( $json_res ) && isset( $json_res['error'] ) ) {
655 $message = $json_res['error'];
656 } else {
657 $message = $json_res;
658 }
659 } elseif ( isset( $resp['response'] ) && isset( $resp['response']['code'] ) ) {
660 /* translators: %1$s: Error code, %2$s: Error message */
661 $message = sprintf( __( 'There was a %1$s error: %2$s', 'formidable' ), $resp['response']['code'], $resp['response']['message'] . ' ' . $resp['body'] );
662 }
663 }
664
665 return $message;
666 }
667
668 public function manually_queue_update() {
669 set_site_transient( 'update_plugins', null );
670 }
671 }
672