PluginProbe
BlockSpare – Gutenberg Blocks for News, Magazine, Blog & Business Websites / 3.1.4
BlockSpare – Gutenberg Blocks for News, Magazine, Blog & Business Websites v3.1.4
4.1.0 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.1.0 1.1.1 1.1.2 1.2.0 1.2.1 1.2.2 1.2.3 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 2.1.2 2.5.0 2.5.3 2.6.1 All 38 releases
← All changes | freemius/includes/class-fs-api.php +178 -123 1.2.23.1.4 View file →
@@ -64,8 +64,16 @@
64 64 */
65 65 private $_sdk_version;
66 66
67 67 /**
68 + * @author Leo Fajardo (@leorw)
69 + * @since 2.5.0
70 + *
71 + * @var string
72 + */
73 + private $_url;
74 +
75 + /**
68 76 * @param string $slug
69 77 * @param string $scope 'app', 'developer', 'user' or 'install'.
70 78 * @param number $id Element's id.
71 79 * @param string $public_key Public key.
@@ -71,8 +79,9 @@
71 79 * @param string $public_key Public key.
72 80 * @param bool $is_sandbox
73 81 * @param bool|string $secret_key Element's secret key.
74 82 * @param null|string $sdk_version
83 + * @param null|string $url
75 84 *
76 85 * @return FS_Api
77 86 */
78 87 static function instance(
@@ -81,9 +90,10 @@
81 90 $id,
82 91 $public_key,
83 92 $is_sandbox,
84 93 $secret_key = false,
85 - $sdk_version = null
94 + $sdk_version = null,
95 + $url = null
86 96 ) {
87 97 $identifier = md5( $slug . $scope . $id . $public_key . ( is_string( $secret_key ) ? $secret_key : '' ) . json_encode( $is_sandbox ) );
88 98
89 99 if ( ! isset( self::$_instances[ $identifier ] ) ) {
@@ -88,9 +98,9 @@
88 98
89 99 if ( ! isset( self::$_instances[ $identifier ] ) ) {
90 100 self::_init();
91 101
92 - self::$_instances[ $identifier ] = new FS_Api( $slug, $scope, $id, $public_key, $secret_key, $is_sandbox, $sdk_version );
102 + self::$_instances[ $identifier ] = new FS_Api( $slug, $scope, $id, $public_key, $secret_key, $is_sandbox, $sdk_version, $url );
93 103 }
94 104
95 105 return self::$_instances[ $identifier ];
96 106 }
@@ -122,8 +132,9 @@
122 132 * @param string $public_key Public key.
123 133 * @param bool|string $secret_key Element's secret key.
124 134 * @param bool $is_sandbox
125 135 * @param null|string $sdk_version
136 + * @param null|string $url
126 137 */
127 138 private function __construct(
128 139 $slug,
129 140 $scope,
@@ -130,14 +141,16 @@
130 141 $id,
131 142 $public_key,
132 143 $secret_key,
133 144 $is_sandbox,
134 - $sdk_version
145 + $sdk_version,
146 + $url
135 147 ) {
136 148 $this->_api = new Freemius_Api_WordPress( $scope, $id, $public_key, $secret_key, $is_sandbox );
137 149
138 150 $this->_slug = $slug;
139 151 $this->_sdk_version = $sdk_version;
152 + $this->_url = $url;
140 153 $this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_' . $slug . '_api', WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );
141 154 }
142 155
143 156 /**
@@ -175,15 +188,17 @@
175 188 *
176 189 * @param string $path
177 190 * @param string $method
178 191 * @param array $params
179 - * @param bool $retry Is in retry or first call attempt.
192 + * @param bool $in_retry Is in retry or first call attempt.
180 193 *
181 194 * @return array|mixed|string|void
182 195 */
183 - private function _call( $path, $method = 'GET', $params = array(), $retry = false ) {
196 + private function _call( $path, $method = 'GET', $params = array(), $in_retry = false ) {
184 197 $this->_logger->entrance( $method . ':' . $path );
185 198
199 + $force_http = ( ! $in_retry && self::$_options->get_option( 'api_force_http', false ) );
200 +
186 201 if ( self::is_temporary_down() ) {
187 202 $result = $this->get_temporary_unavailable_error();
188 203 } else {
189 204 /**
@@ -197,16 +212,30 @@
197 212 $path = add_query_arg( 'sdk_version', $this->_sdk_version, $path );
198 213 }
199 214 }
200 215
216 + /**
217 + * @since 2.5.0 Include the site's URL, if available, in all API requests that are going through the API manager.
218 + */
219 + if ( ! empty( $this->_url ) ) {
220 + if ( false === strpos( $path, 'url=' ) &&
221 + ! isset( $params['url'] )
222 + ) {
223 + $path = add_query_arg( 'url', $this->_url, $path );
224 + }
225 + }
226 +
201 227 $result = $this->_api->Api( $path, $method, $params );
202 228
203 - if ( null !== $result &&
204 - isset( $result->error ) &&
205 - isset( $result->error->code ) &&
206 - 'request_expired' === $result->error->code
229 + if (
230 + ! $in_retry &&
231 + null !== $result &&
232 + isset( $result->error ) &&
233 + isset( $result->error->code )
207 234 ) {
208 - if ( ! $retry ) {
235 + $retry = false;
236 +
237 + if ( 'request_expired' === $result->error->code ) {
209 238 $diff = isset( $result->error->timestamp ) ?
210 239 ( time() - strtotime( $result->error->timestamp ) ) :
211 240 false;
212 241
@@ -212,17 +241,37 @@
212 241
213 242 // Try to sync clock diff.
214 243 if ( false !== $this->_sync_clock_diff( $diff ) ) {
215 244 // Retry call with new synced clock.
216 - return $this->_call( $path, $method, $params, true );
245 + $retry = true;
217 246 }
247 + } else if (
248 + Freemius_Api_WordPress::IsHttps() &&
249 + FS_Api::is_ssl_error_response( $result )
250 + ) {
251 + $force_http = true;
252 + $retry = true;
218 253 }
254 +
255 + if ( $retry ) {
256 + if ( $force_http ) {
257 + $this->toggle_force_http( true );
258 + }
259 +
260 + $result = $this->_call( $path, $method, $params, true );
261 + }
219 262 }
220 263 }
221 264
222 - if ( $this->_logger->is_on() && self::is_api_error( $result ) ) {
223 - // Log API errors.
224 - $this->_logger->api_error( $result );
265 + if ( self::is_api_error( $result ) ) {
266 + if ( $this->_logger->is_on() ) {
267 + // Log API errors.
268 + $this->_logger->api_error( $result );
269 + }
270 +
271 + if ( $force_http ) {
272 + $this->toggle_force_http( false );
273 + }
225 274 }
226 275
227 276 return $result;
228 277 }
@@ -286,9 +335,9 @@
286 335 if ( $this->_logger->is_on() ) {
287 336 $this->_logger->warn( 'Fallback to cached API result: ' . var_export( $cached_result, true ) );
288 337 }
289 338 } else {
290 - if ( is_object( $result ) && 404 == $result->error->http ) {
339 + if ( is_object( $result ) && isset( $result->error->http ) && 404 == $result->error->http ) {
291 340 /**
292 341 * If the response code is 404, cache the result for half of the `$expiration`.
293 342 *
294 343 * @author Leo Fajardo (@leorw)
@@ -312,8 +361,45 @@
312 361
313 362 return $cached_result;
314 363 }
315 364
365 + /**
366 + * @todo Remove this method after migrating Freemius::safe_remote_post() to FS_Api::call().
367 + *
368 + * @author Leo Fajardo (@leorw)
369 + * @since 2.5.4
370 + *
371 + * @param string $url
372 + * @param array $remote_args
373 + *
374 + * @return array|WP_Error The response array or a WP_Error on failure.
375 + */
376 + static function remote_request( $url, $remote_args ) {
377 + if ( ! class_exists( 'Freemius_Api_WordPress' ) ) {
378 + require_once WP_FS__DIR_SDK . '/FreemiusWordPress.php';
379 + }
380 +
381 + if ( method_exists( 'Freemius_Api_WordPress', 'RemoteRequest' ) ) {
382 + return Freemius_Api_WordPress::RemoteRequest( $url, $remote_args );
383 + }
384 +
385 + // The following is for backward compatibility when a modified PHP SDK version is in use and the `Freemius_Api_WordPress:RemoteRequest()` method doesn't exist.
386 + $response = wp_remote_request( $url, $remote_args );
387 +
388 + if (
389 + is_array( $response ) &&
390 + (
391 + empty( $response['headers'] ) ||
392 + empty( $response['headers']['x-api-server'] )
393 + )
394 + ) {
395 + // API is considered blocked if the response doesn't include the `x-api-server` header. When there's no error but this header doesn't exist, the response is usually not in the expected form (e.g., cannot be JSON-decoded).
396 + $response = new WP_Error( 'api_blocked', htmlentities( $response['body'] ) );
397 + }
398 +
399 + return $response;
400 + }
401 +
316 402 /**
317 403 * Check if there's a cached version of the API request.
318 404 *
319 405 * @author Vova Feldman (@svovaf)
@@ -382,53 +468,40 @@
382 468 // return $method . '_' . array_pop($exploded) . '_' . md5($canonized . json_encode($params));
383 469 return strtolower( $method . ':' . $canonized ) . ( ! empty( $params ) ? '#' . md5( json_encode( $params ) ) : '' );
384 470 }
385 471
386 - /**
387 - * Test API connectivity.
388 - *
389 - * @author Vova Feldman (@svovaf)
390 - * @since 1.0.9 If fails, try to fallback to HTTP.
391 - * @since 1.1.6 Added a 5-min caching mechanism, to prevent from overloading the server if the API if
392 - * temporary down.
393 - *
394 - * @return bool True if successful connectivity to the API.
395 - */
396 - static function test() {
397 - self::_init();
472 + /**
473 + * @author Leo Fajardo (@leorw)
474 + * @since 2.5.4
475 + *
476 + * @param bool $is_http
477 + */
478 + private function toggle_force_http( $is_http ) {
479 + self::$_options->set_option( 'api_force_http', $is_http, true );
398 480
399 - $cache_key = 'ping_test';
481 + if ( $is_http ) {
482 + Freemius_Api_WordPress::SetHttp();
483 + } else if ( method_exists( 'Freemius_Api_WordPress', 'SetHttps' ) ) {
484 + Freemius_Api_WordPress::SetHttps();
485 + }
486 + }
400 487
401 - $test = self::$_cache->get_valid( $cache_key, null );
488 + /**
489 + * @author Leo Fajardo (@leorw)
490 + * @since 2.5.4
491 + *
492 + * @param mixed $response
493 + *
494 + * @return bool
495 + */
496 + static function is_blocked( $response ) {
497 + return (
498 + self::is_api_error_object( $response, true ) &&
499 + isset( $response->error->code ) &&
500 + 'api_blocked' === $response->error->code
501 + );
502 + }
402 503
403 - if ( is_null( $test ) ) {
404 - $test = Freemius_Api_WordPress::Test();
405 -
406 - if ( false === $test && Freemius_Api_WordPress::IsHttps() ) {
407 - // Fallback to HTTP, since HTTPS fails.
408 - Freemius_Api_WordPress::SetHttp();
409 -
410 - self::$_options->set_option( 'api_force_http', true, true );
411 -
412 - $test = Freemius_Api_WordPress::Test();
413 -
414 - if ( false === $test ) {
415 - /**
416 - * API connectivity test fail also in HTTP request, therefore,
417 - * fallback to HTTPS to keep connection secure.
418 - *
419 - * @since 1.1.6
420 - */
421 - self::$_options->set_option( 'api_force_http', false, true );
422 - }
423 - }
424 -
425 - self::$_cache->set( $cache_key, $test, WP_FS__TIME_5_MIN_IN_SEC );
426 - }
427 -
428 - return $test;
429 - }
430 -
431 504 /**
432 505 * Check if API is temporary down.
433 506 *
434 507 * @author Vova Feldman (@svovaf)
@@ -461,58 +534,8 @@
461 534 );
462 535 }
463 536
464 537 /**
465 - * Ping API for connectivity test, and return result object.
466 - *
467 - * @author Vova Feldman (@svovaf)
468 - * @since 1.0.9
469 - *
470 - * @param null|string $unique_anonymous_id
471 - * @param array $params
472 - *
473 - * @return object
474 - */
475 - function ping( $unique_anonymous_id = null, $params = array() ) {
476 - $this->_logger->entrance();
477 -
478 - if ( self::is_temporary_down() ) {
479 - return $this->get_temporary_unavailable_error();
480 - }
481 -
482 - $pong = is_null( $unique_anonymous_id ) ?
483 - Freemius_Api_WordPress::Ping() :
484 - $this->_call( 'ping.json?' . http_build_query( array_merge(
485 - array( 'uid' => $unique_anonymous_id ),
486 - $params
487 - ) ) );
488 -
489 - if ( $this->is_valid_ping( $pong ) ) {
490 - return $pong;
491 - }
492 -
493 - if ( self::should_try_with_http( $pong ) ) {
494 - // Fallback to HTTP, since HTTPS fails.
495 - Freemius_Api_WordPress::SetHttp();
496 -
497 - self::$_options->set_option( 'api_force_http', true, true );
498 -
499 - $pong = is_null( $unique_anonymous_id ) ?
500 - Freemius_Api_WordPress::Ping() :
501 - $this->_call( 'ping.json?' . http_build_query( array_merge(
502 - array( 'uid' => $unique_anonymous_id ),
503 - $params
504 - ) ) );
505 -
506 - if ( ! $this->is_valid_ping( $pong ) ) {
507 - self::$_options->set_option( 'api_force_http', false, true );
508 - }
509 - }
510 -
511 - return $pong;
512 - }
513 -
514 - /**
515 538 * Check if based on the API result we should try
516 539 * to re-run the same request with HTTP instead of HTTPS.
517 540 *
518 541 * @author Vova Feldman (@svovaf)
@@ -539,22 +562,8 @@
539 562 ) ) );
540 563
541 564 }
542 565
543 - /**
544 - * Check if valid ping request result.
545 - *
546 - * @author Vova Feldman (@svovaf)
547 - * @since 1.1.1
548 - *
549 - * @param mixed $pong
550 - *
551 - * @return bool
552 - */
553 - function is_valid_ping( $pong ) {
554 - return Freemius_Api_WordPress::Test( $pong );
555 - }
556 -
557 566 function get_url( $path = '' ) {
558 567 return Freemius_Api_WordPress::GetUrl( $path, $this->_api->IsSandbox() );
559 568 }
560 569
@@ -570,8 +579,16 @@
570 579 self::$_cache = FS_Cache_Manager::get_manager( WP_FS__API_CACHE_OPTION_NAME );
571 580 self::$_cache->clear();
572 581 }
573 582
583 + /**
584 + * @author Leo Fajardo (@leorw)
585 + * @since 2.5.4
586 + */
587 + static function clear_force_http_flag() {
588 + self::$_options->unset_option( 'api_force_http' );
589 + }
590 +
574 591 #----------------------------------------------------------------------------------
575 592 #region Error Handling
576 593 #----------------------------------------------------------------------------------
577 594
@@ -592,16 +609,54 @@
592 609 * @author Vova Feldman (@svovaf)
593 610 * @since 2.0.0
594 611 *
595 612 * @param mixed $result
613 + * @param bool $ignore_message
596 614 *
597 615 * @return bool Is API result contains an error.
598 616 */
599 - static function is_api_error_object( $result ) {
617 + static function is_api_error_object( $result, $ignore_message = false ) {
600 618 return (
601 619 is_object( $result ) &&
602 620 isset( $result->error ) &&
603 - isset( $result->error->message )
621 + ( $ignore_message || isset( $result->error->message ) )
622 + );
623 + }
624 +
625 + /**
626 + * @author Leo Fajardo (@leorw)
627 + * @since 2.5.4
628 + *
629 + * @param WP_Error|object|string $response
630 + *
631 + * @return bool
632 + */
633 + static function is_ssl_error_response( $response ) {
634 + $http_error = null;
635 +
636 + if ( $response instanceof WP_Error ) {
637 + if (
638 + isset( $response->errors ) &&
639 + isset( $response->errors['http_request_failed'] )
640 + ) {
641 + $http_error = strtolower( $response->errors['http_request_failed'][0] );
642 + }
643 + } else if (
644 + self::is_api_error_object( $response ) &&
645 + ! empty( $response->error->message )
646 + ) {
647 + $http_error = $response->error->message;
648 + }
649 +
650 + return (
651 + ! empty( $http_error ) &&
652 + (
653 + false !== strpos( $http_error, 'curl error 35' ) ||
654 + (
655 + false === strpos( $http_error, '</html>' ) &&
656 + false !== strpos( $http_error, 'ssl' )
657 + )
658 + )
604 659 );
605 660 }
606 661
607 662 /**