PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 5.2
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v5.2
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 / deprecated / FrmEDD_SL_Plugin_Updater.php

FrmEDD_SL_Plugin_Updater.php in Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More 5.2, at deprecated/FrmEDD_SL_Plugin_Updater.php

405 lines 11.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 // Exit if accessed directly
4 if ( ! defined( 'ABSPATH' ) ) {
5 exit;
6 }
7
8 /**
9 * Allows plugins to use their own update API.
10 *
11 * @author Easy Digital Downloads
12 * @version 1.6.15
13 */
14 class FrmEDD_SL_Plugin_Updater {
15
16 private $api_url = '';
17 private $api_data = array();
18 private $name = '';
19 private $slug = '';
20 private $version = '';
21 private $wp_override = false;
22 private $beta = false;
23 private $cache_key = '';
24
25 /**
26 * Class constructor.
27 *
28 * @uses plugin_basename()
29 * @uses hook()
30 *
31 * @param string $_api_url The URL pointing to the custom API endpoint.
32 * @param string $_plugin_file Path to the plugin file.
33 * @param array $_api_data Optional data to send with API calls.
34 */
35 public function __construct( $_api_url, $_plugin_file, $_api_data = array() ) {
36 global $frm_edd_plugin_data;
37
38 $this->api_url = trailingslashit( $_api_url );
39 $this->api_data = $_api_data;
40 $this->name = plugin_basename( $_plugin_file );
41 $this->slug = basename( $_plugin_file, '.php' );
42 $this->version = $_api_data['version'];
43 $this->wp_override = isset( $_api_data['wp_override'] ) ? (bool) $_api_data['wp_override'] : false;
44 $this->beta = ! empty( $this->api_data['beta'] ) ? true : false;
45 $this->cache_key = md5( serialize( $this->slug . $this->version . $this->api_data['license'] . $this->beta ) );
46
47 $frm_edd_plugin_data[ $this->slug ] = $this->api_data;
48
49 /**
50 * Fires after the $frm_edd_plugin_data is setup.
51 *
52 * @since x.x.x
53 *
54 * @param array $frm_edd_plugin_data Array of EDD SL plugin data.
55 */
56 do_action( 'post_edd_sl_plugin_updater_setup', $frm_edd_plugin_data );
57
58 // Set up hooks.
59 $this->init();
60 }
61
62 /**
63 * Set up WordPress filters to hook into WP's update process.
64 *
65 * @uses add_filter()
66 *
67 * @return void
68 */
69 public function init() {
70 add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'check_update' ) );
71 add_filter( 'plugins_api', array( $this, 'plugins_api_filter' ), 10, 3 );
72 add_action( 'admin_init', array( $this, 'show_changelog' ) );
73 }
74
75 /**
76 * Check for Updates at the defined API endpoint and modify the update array.
77 *
78 * This function dives into the update API just when WordPress creates its update array,
79 * then adds a custom API call and injects the custom plugin data retrieved from the API.
80 * It is reassembled from parts of the native WordPress plugin update code.
81 * See wp-includes/update.php line 121 for the original wp_update_plugins() function.
82 *
83 * @uses api_request()
84 *
85 * @param array $_transient_data Update array build by WordPress.
86 * @return array Modified update array with custom plugin data.
87 */
88 public function check_update( $_transient_data ) {
89
90 global $pagenow;
91
92 if ( ! is_object( $_transient_data ) ) {
93 $_transient_data = new stdClass();
94 }
95
96 if ( ! empty( $_transient_data->response ) && ! empty( $_transient_data->response[ $this->name ] ) && false === $this->wp_override ) {
97 return $_transient_data;
98 }
99
100 $version_info = $this->get_cached_version_info( $this->cache_key );
101
102 if ( false === $version_info ) {
103 $version_info = $this->api_request(
104 'plugin_latest_version',
105 array(
106 'slug' => $this->slug,
107 'beta' => $this->beta,
108 )
109 );
110
111 $this->set_version_info_cache( $version_info, $this->cache_key );
112
113 }
114
115 if ( false !== $version_info && is_object( $version_info ) && isset( $version_info->new_version ) ) {
116
117 if ( version_compare( $this->version, $version_info->new_version, '<' ) ) {
118
119 if ( empty( $version_info->plugin ) ) {
120 $version_info->plugin = $this->name;
121 }
122
123 $_transient_data->response[ $this->name ] = $version_info;
124
125 }
126
127 $_transient_data->last_checked = time();
128 $_transient_data->checked[ $this->name ] = $this->version;
129
130 }
131
132 return $_transient_data;
133 }
134
135 /**
136 * Updates information on the "View version x.x details" page with custom data.
137 *
138 * @uses api_request()
139 *
140 * @param mixed $_data
141 * @param string $_action
142 * @param object $_args
143 * @return object $_data
144 */
145 public function plugins_api_filter( $_data, $_action = '', $_args = null ) {
146
147 if ( $_action != 'plugin_information' ) {
148
149 return $_data;
150
151 }
152
153 if ( ! isset( $_args->slug ) || ( $_args->slug != $this->slug ) ) {
154
155 return $_data;
156
157 }
158
159 $to_send = array(
160 'slug' => $this->slug,
161 'is_ssl' => is_ssl(),
162 'fields' => array(
163 'banners' => array(),
164 'reviews' => false,
165 ),
166 );
167
168 $cache_key = 'edd_api_request_' . $this->cache_key;
169
170 // Get the transient where we store the api request for this plugin for 24 hours
171 $edd_api_request_transient = $this->get_cached_version_info( $cache_key );
172
173 //If we have no transient-saved value, run the API, set a fresh transient with the API value, and return that value too right now.
174 if ( empty( $edd_api_request_transient ) ) {
175
176 $api_response = $this->api_request( 'plugin_information', $to_send );
177
178 // Expires in 3 hours
179 $this->set_version_info_cache( $api_response, $cache_key );
180
181 if ( false !== $api_response ) {
182 $_data = $api_response;
183 }
184 } else {
185 $_data = $edd_api_request_transient;
186 }
187
188 // Convert sections into an associative array, since we're getting an object, but Core expects an array.
189 if ( isset( $_data->sections ) && ! is_array( $_data->sections ) ) {
190 $new_sections = array();
191 foreach ( $_data->sections as $key => $value ) {
192 $new_sections[ $key ] = $value;
193 }
194
195 $_data->sections = $new_sections;
196 }
197
198 // Convert banners into an associative array, since we're getting an object, but Core expects an array.
199 if ( isset( $_data->banners ) && ! is_array( $_data->banners ) ) {
200 $new_banners = array();
201 foreach ( $_data->banners as $key => $value ) {
202 $new_banners[ $key ] = $value;
203 }
204
205 $_data->banners = $new_banners;
206 }
207
208 return $_data;
209 }
210
211 /**
212 * Disable SSL verification in order to prevent download update failures
213 *
214 * @param array $args
215 * @param string $url
216 * @return object $array
217 */
218 public function http_request_args( $args, $url ) {
219
220 $verify_ssl = $this->verify_ssl();
221 if ( strpos( $url, 'https://' ) !== false && strpos( $url, 'edd_action=package_download' ) ) {
222 $args['sslverify'] = $verify_ssl;
223 }
224 return $args;
225
226 }
227
228 /**
229 * Calls the API and, if successfull, returns the object delivered by the API.
230 *
231 * @uses get_bloginfo()
232 * @uses wp_remote_post()
233 * @uses is_wp_error()
234 *
235 * @param string $_action The requested action.
236 * @param array $_data Parameters for the API action.
237 * @return false|object
238 */
239 private function api_request( $_action, $_data ) {
240
241 global $wp_version;
242
243 $data = array_merge( $this->api_data, $_data );
244
245 if ( $data['slug'] != $this->slug ) {
246 return;
247 }
248
249 if ( $this->api_url == trailingslashit( home_url() ) ) {
250 return false; // Don't allow a plugin to ping itself
251 }
252
253 $api_params = array(
254 'edd_action' => 'get_version',
255 'license' => ! empty( $data['license'] ) ? $data['license'] : '',
256 'item_name' => isset( $data['item_name'] ) ? $data['item_name'] : false,
257 'item_id' => isset( $data['item_id'] ) ? $data['item_id'] : false,
258 'version' => isset( $data['version'] ) ? $data['version'] : false,
259 'slug' => $data['slug'],
260 'author' => $data['author'],
261 'url' => home_url(),
262 'beta' => ! empty( $data['beta'] ),
263 );
264
265 $verify_ssl = $this->verify_ssl();
266 $request = wp_remote_post(
267 $this->api_url,
268 array(
269 'timeout' => 15,
270 'sslverify' => $verify_ssl,
271 'body' => $api_params,
272 )
273 );
274
275 if ( ! is_wp_error( $request ) ) {
276 $request = json_decode( wp_remote_retrieve_body( $request ) );
277 }
278
279 $this->prepare_response( $request );
280
281 return $request;
282 }
283
284 private function prepare_response( &$request ) {
285 if ( $request && isset( $request->sections ) ) {
286 $request->sections = maybe_unserialize( $request->sections );
287 } else {
288 $request = false;
289 }
290
291 if ( $request && isset( $request->banners ) ) {
292 $request->banners = maybe_unserialize( $request->banners );
293 }
294
295 if ( ! empty( $request->sections ) ) {
296 foreach ( $request->sections as $key => $section ) {
297 $request->$key = (array) $section;
298 }
299 }
300 }
301
302 public function show_changelog() {
303
304 global $frm_edd_plugin_data;
305
306 if ( empty( $_REQUEST['edd_sl_action'] ) || 'view_plugin_changelog' !== $_REQUEST['edd_sl_action'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
307 return;
308 }
309
310 if ( empty( $_REQUEST['plugin'] ) || empty( $_REQUEST['slug'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
311 return;
312 }
313
314 if ( ! current_user_can( 'update_plugins' ) ) {
315 wp_die( esc_html__( 'You do not have permission to install plugin updates', 'formidable' ), esc_html__( 'Error', 'formidable' ), array( 'response' => 403 ) );
316 }
317
318 $slug = sanitize_text_field( $_REQUEST['slug'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
319 $data = $frm_edd_plugin_data[ $slug ];
320 $beta = ! empty( $data['beta'] ) ? true : false;
321 $cache_key = md5( 'edd_plugin_' . sanitize_key( $_REQUEST['plugin'] ) . '_' . $beta . '_version_info' ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
322 $version_info = $this->get_cached_version_info( $cache_key );
323
324 if ( false === $version_info ) {
325
326 $api_params = array(
327 'edd_action' => 'get_version',
328 'item_name' => isset( $data['item_name'] ) ? $data['item_name'] : false,
329 'item_id' => isset( $data['item_id'] ) ? $data['item_id'] : false,
330 'slug' => $slug,
331 'author' => $data['author'],
332 'url' => home_url(),
333 'beta' => $beta,
334 );
335
336 $verify_ssl = $this->verify_ssl();
337 $request = wp_remote_post(
338 $this->api_url,
339 array(
340 'timeout' => 15,
341 'sslverify' => $verify_ssl,
342 'body' => $api_params,
343 )
344 );
345
346 if ( ! is_wp_error( $request ) ) {
347 $version_info = json_decode( wp_remote_retrieve_body( $request ) );
348 }
349
350 if ( ! empty( $version_info ) && isset( $version_info->sections ) ) {
351 $version_info->sections = maybe_unserialize( $version_info->sections );
352 } else {
353 $version_info = false;
354 }
355
356 if ( ! empty( $version_info ) ) {
357 foreach ( $version_info->sections as $key => $section ) {
358 $version_info->$key = (array) $section;
359 }
360 }
361
362 $this->set_version_info_cache( $version_info, $cache_key );
363
364 }
365
366 if ( ! empty( $version_info ) && isset( $version_info->sections['changelog'] ) ) {
367 echo '<div style="background:#fff;padding:10px;">' . FrmAppHelper::kses( $version_info->sections['changelog'], 'all' ) . '</div>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
368 }
369
370 exit;
371 }
372
373 public function get_cached_version_info( $cache_key = '' ) {
374 $cache = get_option( $cache_key );
375
376 if ( empty( $cache['timeout'] ) || current_time( 'timestamp' ) > $cache['timeout'] ) {
377 return false; // Cache is expired
378 }
379
380 return json_decode( $cache['value'] );
381
382 }
383
384 public function set_version_info_cache( $value = '', $cache_key = '' ) {
385 $data = array(
386 'timeout' => strtotime( '+24 hours', current_time( 'timestamp' ) ),
387 'value' => json_encode( $value ),
388 );
389
390 update_option( $cache_key, $data, 'no' );
391
392 }
393
394 /**
395 * Returns if the SSL of the store should be verified.
396 *
397 * @since 1.6.13
398 * @return bool
399 */
400 private function verify_ssl() {
401 return (bool) apply_filters( 'edd_sl_api_request_verify_ssl', true, $this );
402 }
403
404 }
405