PluginProbe ʕ •ᴥ•ʔ
Image Widget / 4.2
Image Widget v4.2
trunk 1.0 2.0 2.1 2.2 2.2.1 2.2.2 3.0 3.0.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1 3.1.1 3.1.2 3.1.3 3.1.4 3.1.5 3.1.6 3.2 3.2.1 3.2.10 3.2.11 3.2.2 3.2.3 3.2.4 3.2.5 3.2.7 3.2.8 3.2.9 3.3 3.3.1 3.3.2 3.3.3 3.3.4 3.3.5 3.3.6 3.3.7 4.0 4.0.1 4.0.2 4.0.3 4.0.4 4.0.5 4.0.6 4.0.7 4.0.8 4.0.9 4.1 4.1.1 4.1.2 4.2 4.2.1 4.2.2 4.3 4.3.1 4.4 4.4.1 4.4.11 4.4.12 4.4.2 4.4.3 4.4.4 4.4.5 4.4.6 4.4.7 4.4.8 4.4.9
image-widget / freemius / includes / class-fs-api.php
image-widget / freemius / includes Last commit date
entities 10 years ago managers 10 years ago sdk 10 years ago class-freemius-abstract.php 10 years ago class-freemius.php 10 years ago class-fs-api.php 10 years ago class-fs-logger.php 10 years ago class-fs-plugin-updater.php 10 years ago class-fs-security.php 10 years ago fs-core-functions.php 10 years ago fs-plugin-functions.php 10 years ago i18n.php 10 years ago
class-fs-api.php
350 lines
1 <?php
2 /**
3 * @package Freemius
4 * @copyright Copyright (c) 2015, Freemius, Inc.
5 * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
6 * @since 1.0.4
7 */
8
9 if ( ! defined( 'ABSPATH' ) ) {
10 exit;
11 }
12
13 /**
14 * Class FS_Api
15 *
16 * Wraps Freemius API SDK to handle:
17 * 1. Clock sync.
18 * 2. Fallback to HTTP when HTTPS fails.
19 * 3. Adds caching layer to GET requests.
20 * 4. Adds consistency for failed requests by using last cached version.
21 */
22 class FS_Api {
23 /**
24 * @var FS_Api[]
25 */
26 private static $_instances = array();
27
28 /**
29 * @var FS_Option_Manager Freemius options, options-manager.
30 */
31 private static $_options;
32
33 /**
34 * @var FS_Option_Manager API Caching layer
35 */
36 private static $_cache;
37
38 /**
39 * @var int Clock diff in seconds between current server to API server.
40 */
41 private static $_clock_diff;
42
43 /**
44 * @var Freemius_Api
45 */
46 private $_api;
47
48 /**
49 * @var string
50 */
51 private $_slug;
52
53 /**
54 * @var FS_Logger
55 * @since 1.0.4
56 */
57 private $_logger;
58
59 /**
60 * @param string $slug
61 * @param string $scope 'app', 'developer', 'user' or 'install'.
62 * @param number $id Element's id.
63 * @param string $public_key Public key.
64 * @param bool $is_sandbox
65 * @param bool|string $secret_key Element's secret key.
66 *
67 * @return FS_Api
68 */
69 static function instance( $slug, $scope, $id, $public_key, $is_sandbox, $secret_key = false ) {
70 $identifier = md5( $slug . $scope . $id . $public_key . ( is_string( $secret_key ) ? $secret_key : '' ) . json_encode( $is_sandbox ) );
71
72 if ( ! isset( self::$_instances[ $identifier ] ) ) {
73 if ( 0 === count( self::$_instances ) ) {
74 self::_init();
75 }
76
77 self::$_instances[ $identifier ] = new FS_Api( $slug, $scope, $id, $public_key, $secret_key, $is_sandbox );
78 }
79
80 return self::$_instances[ $identifier ];
81 }
82
83 private static function _init() {
84 if ( ! class_exists( 'Freemius_Api' ) ) {
85 require_once( WP_FS__DIR_SDK . '/Freemius.php' );
86 }
87
88 self::$_options = FS_Option_Manager::get_manager( WP_FS__OPTIONS_OPTION_NAME, true );
89 self::$_cache = FS_Option_Manager::get_manager( WP_FS__API_CACHE_OPTION_NAME, true );
90
91 self::$_clock_diff = self::$_options->get_option( 'api_clock_diff', 0 );
92 Freemius_Api::SetClockDiff( self::$_clock_diff );
93
94 if ( self::$_options->get_option( 'api_force_http', false ) ) {
95 Freemius_Api::SetHttp();
96 }
97 }
98
99 /**
100 * @param string $slug
101 * @param string $scope 'app', 'developer', 'user' or 'install'.
102 * @param number $id Element's id.
103 * @param string $public_key Public key.
104 * @param bool|string $secret_key Element's secret key.
105 * @param bool $is_sandbox
106 */
107 private function __construct( $slug, $scope, $id, $public_key, $secret_key, $is_sandbox ) {
108 $this->_api = new Freemius_Api( $scope, $id, $public_key, $secret_key, $is_sandbox );
109
110 $this->_slug = $slug;
111 $this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_' . $slug . '_api', WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );
112 }
113
114 /**
115 * Find clock diff between server and API server, and store the diff locally.
116 *
117 * @param bool|int $diff
118 *
119 * @return bool|int False if clock diff didn't change, otherwise returns the clock diff in seconds.
120 */
121 private function _sync_clock_diff( $diff = false ) {
122 $this->_logger->entrance();
123
124 // Sync clock and store.
125 $new_clock_diff = ( false === $diff ) ?
126 $this->_api->FindClockDiff() :
127 $diff;
128
129 if ( $new_clock_diff === self::$_clock_diff ) {
130 return false;
131 }
132
133 self::$_clock_diff = $new_clock_diff;
134
135 // Update API clock's diff.
136 $this->_api->SetClockDiff( self::$_clock_diff );
137
138 // Store new clock diff in storage.
139 self::$_options->set_option( 'api_clock_diff', self::$_clock_diff, true );
140
141 return $new_clock_diff;
142 }
143
144 /**
145 * Override API call to enable retry with servers' clock auto sync method.
146 *
147 * @param string $path
148 * @param string $method
149 * @param array $params
150 * @param bool $retry Is in retry or first call attempt.
151 *
152 * @return array|mixed|string|void
153 */
154 private function _call( $path, $method = 'GET', $params = array(), $retry = false ) {
155 $this->_logger->entrance();
156
157 $result = $this->_api->Api( $path, $method, $params );
158
159 if ( null !== $result &&
160 isset( $result->error ) &&
161 'request_expired' === $result->error->code
162 ) {
163 if ( ! $retry ) {
164 $diff = isset( $result->error->timestamp ) ?
165 ( time() - strtotime( $result->error->timestamp ) ) :
166 false;
167
168 // Try to sync clock diff.
169 if ( false !== $this->_sync_clock_diff( $diff ) ) {
170 // Retry call with new synced clock.
171 return $this->_call( $path, $method, $params, true );
172 }
173 }
174 }
175
176 if ( null !== $result && isset( $result->error ) ) {
177 // Log API errors.
178 $this->_logger->error( $result->error->message );
179 }
180
181 return $result;
182 }
183
184 /**
185 * Override API call to wrap it in servers' clock sync method.
186 *
187 * @param string $path
188 * @param string $method
189 * @param array $params
190 *
191 * @return array|mixed|string|void
192 * @throws Freemius_Exception
193 */
194 function call( $path, $method = 'GET', $params = array() ) {
195 return $this->_call( $path, $method, $params );
196 }
197
198 /**
199 * Get API request URL signed via query string.
200 *
201 * @param string $path
202 *
203 * @return string
204 */
205 function get_signed_url( $path ) {
206 return $this->_api->GetSignedUrl( $path );
207 }
208
209 /**
210 * @param string $path
211 * @param bool $flush
212 * @param int $expiration (optional) Time until expiration in seconds from now, defaults to 24 hours
213 *
214 * @return stdClass|mixed
215 */
216 function get( $path = '/', $flush = false, $expiration = WP_FS__TIME_24_HOURS_IN_SEC ) {
217 $cache_key = $this->get_cache_key( $path );
218
219 // Always flush during development.
220 if ( WP_FS__DEV_MODE || $this->_api->IsSandbox() ) {
221 $flush = true;
222 }
223
224 // Get result from cache.
225 $cache_entry = self::$_cache->get_option( $cache_key, false );
226
227 $fetch = false;
228 if ( $flush ||
229 false === $cache_entry ||
230 ! isset( $cache_entry->timestamp ) ||
231 ! is_numeric( $cache_entry->timestamp ) ||
232 $cache_entry->timestamp < WP_FS__SCRIPT_START_TIME
233 ) {
234 $fetch = true;
235 }
236
237 if ( $fetch ) {
238 $result = $this->call( $path );
239
240 if ( ! is_object( $result ) || isset( $result->error ) ) {
241 if ( is_object( $cache_entry ) &&
242 isset( $cache_entry->result ) &&
243 ! isset( $cache_entry->result->error )
244 ) {
245 // If there was an error during a newer data fetch,
246 // fallback to older data version.
247 $result = $cache_entry->result;
248 } else {
249 // If no older data version, return result without
250 // caching the error.
251 return $result;
252 }
253 }
254
255 $cache_entry = new stdClass();
256 $cache_entry->result = $result;
257 $cache_entry->timestamp = WP_FS__SCRIPT_START_TIME + $expiration;
258 self::$_cache->set_option( $cache_key, $cache_entry, true );
259 }
260
261 return $cache_entry->result;
262 }
263
264 private function get_cache_key( $path, $method = 'GET', $params = array() ) {
265 $canonized = $this->_api->CanonizePath( $path );
266 // $exploded = explode('/', $canonized);
267 // return $method . '_' . array_pop($exploded) . '_' . md5($canonized . json_encode($params));
268 return $method . ':' . $canonized . ( ! empty( $params ) ? '#' . md5( json_encode( $params ) ) : '' );
269 }
270
271 /**
272 * Test API connectivity.
273 *
274 * @since 1.0.9 If fails, try to fallback to HTTP.
275 *
276 * @param null|string $unique_anonymous_id
277 *
278 * @return bool True if successful connectivity to the API.
279 */
280 function test( $unique_anonymous_id = null ) {
281 $this->_logger->entrance();
282
283 if ( ! function_exists( 'curl_version' ) ) {
284 // cUrl extension is not active.
285 return false;
286 }
287
288 $test = is_null( $unique_anonymous_id ) ?
289 $this->_api->Test() :
290 $this->_api->Test( $this->_call( 'ping.json?uid=' . $unique_anonymous_id ) );
291
292 if ( false === $test && $this->_api->IsHttps() ) {
293 // Fallback to HTTP, since HTTPS fails.
294 $this->_api->SetHttp();
295
296 self::$_options->set_option( 'api_force_http', true, true );
297
298 $test = is_null( $unique_anonymous_id ) ?
299 $this->_api->Test() :
300 $this->_api->Test( $this->_call( 'ping.json?uid=' . $unique_anonymous_id ) );
301 }
302
303 return $test;
304 }
305
306 /**
307 * Ping API for connectivity test, and return result object.
308 *
309 * @author Vova Feldman (@svovaf)
310 * @since 1.0.9
311 *
312 * @param null|string $unique_anonymous_id
313 *
314 * @return object
315 */
316 function ping( $unique_anonymous_id = null ) {
317 return is_null( $unique_anonymous_id ) ?
318 $this->_api->Ping() :
319 $this->_call( 'ping.json?uid=' . $unique_anonymous_id );
320 }
321
322 /**
323 * Check if valid ping request result.
324 *
325 * @author Vova Feldman (@svovaf)
326 * @since 1.1.1
327 *
328 * @param mixed $pong
329 *
330 * @return bool
331 */
332 function is_valid_ping( $pong ) {
333 return $this->_api->Test( $pong );
334 }
335
336 function get_url( $path = '' ) {
337 return $this->_api->GetUrl( $path );
338 }
339
340 /**
341 * Clear API cache.
342 *
343 * @author Vova Feldman (@svovaf)
344 * @since 1.0.9
345 */
346 static function clear_cache() {
347 self::$_cache = FS_Option_Manager::get_manager( WP_FS__API_CACHE_OPTION_NAME, true );
348 self::$_cache->clear( true );
349 }
350 }