PluginProbe ʕ •ᴥ•ʔ
SureCart – Ecommerce Made Easy For Selling Physical Products, Digital Downloads, Subscriptions, Donations, & Payments / 3.8.2
SureCart – Ecommerce Made Easy For Selling Physical Products, Digital Downloads, Subscriptions, Donations, & Payments v3.8.2
4.4.1 4.4.0 4.3.3 4.3.2 4.3.1 4.3.0 4.2.3 4.2.2 4.2.1 1.0.3 1.0.4 1.0.5 1.0.6 1.1.0 1.1.1 1.1.10 1.1.11 1.1.12 1.1.13 1.1.14 1.1.15 1.1.16 1.1.17 1.1.18 1.1.19 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 1.1.8 1.1.9 1.10.0 1.10.1 1.10.2 1.10.3 1.10.4 1.11.0 1.11.1 1.11.2 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.4.0 1.4.1 1.4.2 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.7.0 1.7.1 1.7.2 1.8.0 1.8.1 1.8.2 1.8.3 1.8.4 1.8.5 1.9.0 1.9.1 1.9.2 1.9.3 1.9.4 1.9.5 2.0.0 2.0.1 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.10.0 2.10.1 2.11.0 2.11.1 2.11.2 2.11.3 2.11.4 2.12.0 2.13.0 2.14.0 2.14.1 2.15.0 2.15.1 2.16.0 2.16.1 2.16.2 2.16.3 2.17.0 2.17.1 2.17.2 2.18.0 2.19.0 2.19.2 2.19.3 2.19.4 2.2.0 2.2.1 2.20.0 2.20.1 2.20.2 2.20.3 2.20.4 2.20.5 2.20.6 2.21.0 2.22.0 2.22.1 2.23.0 2.24.0 2.25.0 2.25.1 2.25.2 2.26.0 2.27.0 2.27.1 2.28.0 2.29.0 2.29.1 2.29.2 2.29.3 2.29.4 2.3.0 2.3.1 2.30.0 2.31.0 2.31.1 2.31.2 2.31.3 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.40.0 2.40.1 2.5.0 2.5.1 2.5.2 2.6.0 2.6.1 2.6.2 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.8.0 2.8.1 2.8.2 2.8.3 2.8.4 2.9.0 3.0.0 3.0.0-RC1 3.0.0-RC2 3.0.0-beta1 3.0.0-beta2 3.0.1 3.0.2 3.0.3 3.0.4 3.0.5 3.1.0 3.1.1 3.1.2 3.1.3 3.1.4 3.1.5 3.1.6 3.10.0 3.10.1 3.11.0 3.12.0 3.13.0 3.13.1 3.13.2 3.13.3 3.13.4 3.14.0 3.15.0 3.15.1 3.15.2 3.15.3 3.15.4 3.15.5 3.16.0 3.16.1 3.16.2 3.16.3 3.16.4 3.16.5 3.16.6 3.16.7 3.16.8 3.17.0 3.17.1 3.17.2 3.17.3 3.17.4 3.17.5 3.17.6 3.18.0 3.19.0 3.19.1 3.19.2 3.2.0 3.2.1 3.2.2 3.20.0 3.20.1 3.3.0 3.3.1 3.4.0 3.4.1 3.4.2 3.4.3 3.5.0 3.5.1 3.5.2 3.5.3 3.6.0 3.6.1 3.6.2 3.7.0 3.7.1 3.7.2 3.7.3 3.8.0 3.8.1 3.8.2 3.8.3 3.8.4 3.8.5 3.9.0 4.0.0 4.0.1 4.0.2 4.0.3 trunk 4.1.0 0.2.19.1 4.1.1 1.0.0 4.2.0 1.0.1 1.0.2
surecart / app / src / Request / RequestService.php
surecart / app / src / Request Last commit date
RequestCacheService.php 1 year ago RequestService.php 1 year ago RequestServiceProvider.php 1 year ago
RequestService.php
487 lines
1 <?php
2
3 namespace SureCart\Request;
4
5 use SureCart\Models\ApiToken;
6 use SureCart\Support\Errors\ErrorsService;
7
8 /**
9 * Provide api request functionality.
10 */
11 class RequestService {
12 /**
13 * Has this been cached yet for the request?
14 *
15 * @var boolean
16 */
17 protected static $cached = false;
18
19 /**
20 * Undocumented variable
21 *
22 * @var string
23 */
24 protected $token = '';
25
26 /**
27 * The base path for the request.
28 *
29 * @var string
30 */
31 protected $base_path;
32
33 /**
34 * What type of cached request is this.
35 *
36 * @var string|null
37 */
38 protected $cache_status = 'none';
39
40 /**
41 * Is this request authorized?
42 *
43 * @var boolean
44 */
45 protected $authorized = true;
46
47 /**
48 * Number of retries.
49 *
50 * @var integer
51 */
52 protected $current_retries = 0;
53
54 /**
55 * Total number of retries.
56 *
57 * @var integer
58 */
59 protected $total_retries = 1;
60
61 /**
62 * Status codes to retry.
63 *
64 * @var array
65 */
66 protected $retry_status_codes = [ 409 ];
67
68 /**
69 * Container.
70 *
71 * @var \Pimple\Container
72 */
73 protected $container;
74
75 /**
76 * Constructor.
77 *
78 * @param \Pimple\Container $container The container.
79 * @param string $token The rest api base path.
80 * @param string $base_path The rest api base path.
81 * @param boolean $authorized Is this request authorized.
82 *
83 * @return void
84 */
85 public function __construct( $container, $token = '', $base_path = '/v1', $authorized = true ) {
86 // set the token.
87 $this->token = $token;
88 // set the base path and url.
89 $this->base_path = $base_path;
90 $this->authorized = $authorized;
91 $this->container = $container;
92 }
93
94 /**
95 * Get the cache service.
96 *
97 * @param string $endpoint The endpoint to cache.
98 * @param array $args The args to cache.
99 * @param string $account_cache_key The account cache key.
100 *
101 * @return \SureCart\Request\RequestCacheService
102 */
103 public function cache( $endpoint, $args, $account_cache_key ) {
104 return $this->container['requests.cache']( $endpoint, $args, $account_cache_key );
105 }
106
107 /**
108 * Get the errors service.
109 *
110 * @return \SureCart\Support\Errors\ErrorsService
111 */
112 public function errors() {
113 return $this->container['requests.errors'];
114 }
115
116 /**
117 * Set the API token on the fly.
118 *
119 * @param string $token API token.
120 *
121 * @return $this
122 */
123 public function setToken( $token ) {
124 $this->token = $token;
125 return $this;
126 }
127
128 /**
129 * Get the base url.
130 */
131 public function getBaseUrl() {
132 return untrailingslashit( SURECART_API_URL ) . trailingslashit( $this->base_path );
133 }
134
135 /**
136 * Should we get a cached request?
137 *
138 * @return boolean
139 */
140 public function shouldFindCache( $cachable, $cache_key, $args = [] ) {
141 // only for fetch requests.
142 if ( isset( $args['method'] ) && 'GET' !== $args['method'] ) {
143 return false;
144 }
145
146 // if the args are set, then do what they say.
147 if ( isset( $args['query']['cached'] ) ) {
148 return (bool) $args['query']['cached'];
149 }
150
151 // don't cache edit context.
152 if ( isset( $args['query']['context'] ) && 'edit' === $args['query']['context'] ) {
153 return false;
154 }
155
156 return (bool) $cachable && $cache_key;
157 }
158
159 /**
160 * Respond to the request.
161 *
162 * @param array $response Reponse data.
163 * @param array $args Request arguments.
164 * @param string $endpoint The endpoint to request.
165 *
166 * @return array Response data.
167 */
168 public function respond( $response, $args, $endpoint ) {
169 if ( is_array( $response ) ) {
170 foreach ( $response as $item ) {
171 $item->cache_status = $this->cache_status;
172 }
173 }
174
175 if ( is_object( $response ) ) {
176 $response->cache_status = $this->cache_status;
177 }
178
179 return apply_filters( 'surecart/request/response', $response, $args, $endpoint );
180 }
181
182 /**
183 * Set the response cache status.
184 *
185 * @param object $response Response object.
186 * @param string $status The response status.
187 *
188 * @return void
189 */
190 public function setResponseCacheStatus( $response, $status ) {
191 if ( is_array( $response ) ) {
192 foreach ( $response as $item ) {
193 $item->cached = $status;
194 }
195 } elseif ( is_object( $response ) ) {
196 $response->cached = $status;
197 }
198
199 return $response;
200 }
201
202 /**
203 * Make the request
204 *
205 * @param string $endpoint Endpoint to request.
206 * @param array $args Arguments for request.
207 * @param boolean $cachable Should this request be cached.
208 * @param string $cache_key The cache key to use.
209 * @param boolean $optimized_caching Should we use optimized caching.
210 *
211 * @return mixed
212 */
213 public function makeRequest( $endpoint, $args = [], $cachable = false, $cache_key = '', $optimized_caching = false ) {
214 $cache = $this->cache( $endpoint, $args, $cache_key );
215
216 // check if we should get a cached version of this.
217 if ( $this->shouldFindCache( $cachable, $cache_key, $args ) ) {
218 // get from cache.
219 $response_body = $cache->getTransientCache();
220 // we have a cached response.
221 if ( false !== $response_body ) {
222 $this->cache_status = 'transient';
223 return $this->respond( $response_body, $args, $endpoint );
224 }
225 }
226
227 if ( $optimized_caching && $cache->getPreviousCacheUpdatingState() === 'updating' ) {
228 $previous_cache = $cache->getPreviousCache();
229 if ( false !== $previous_cache ) {
230 $this->cache_status = 'previous';
231 return $this->respond( $previous_cache, $args, $endpoint );
232 }
233 }
234
235 // make the uncached request.
236 $response_body = $this->makeUncachedRequest( $endpoint, $args, $cache, $optimized_caching );
237
238 if ( is_wp_error( $response_body ) ) {
239 return $response_body;
240 }
241
242 // set in object cache.
243 $cache->setCache( $response_body, 'object' );
244 if ( (bool) $cachable && $cache_key ) {
245 $cache->setCache( $response_body, 'transient' );
246 }
247
248 if ( $optimized_caching ) {
249 $cache->setPreviousCache( $response_body );
250 $cache->setPreviousCacheUpdatingState( 'updated' );
251 }
252
253 // return response.
254 return $this->respond( $response_body, $args, $endpoint );
255 }
256
257 /**
258 * Make the uncached request.
259 *
260 * @param string $endpoint Endpoint to request.
261 * @param array $args Arguments for request.
262 *
263 * @return mixed
264 */
265 public function makeUncachedRequest( $endpoint, $args = [], $cache = null, $optimized_caching = false ) {
266 if ( $optimized_caching ) {
267 $cache->setPreviousCacheUpdatingState( 'updating' );
268 }
269
270 // must have a token for the request.
271 if ( $this->authorized && empty( $this->token ) ) {
272 return new \WP_Error( 'missing_token', __( 'Please connect your site to SureCart.', 'surecart' ) );
273 }
274
275 // make sure we send json.
276 if ( empty( $args['headers']['Content-Type'] ) ) {
277 $args['headers']['Content-Type'] = 'application/json';
278 }
279
280 // add auth.
281 if ( $this->authorized && ! empty( $this->token ) && empty( $args['headers']['Authorization'] ) ) {
282 $args['headers']['Authorization'] = "Bearer $this->token";
283 }
284
285 // add version header.
286 $args['headers']['X-SURECART-WP-PLUGIN-VERSION'] = \SureCart::plugin()->version();
287
288 // add referer header.
289 if ( isset( $_SERVER['HTTP_REFERER'] ) ) {
290 $args['headers']['X-SURECART-REFERRER'] = esc_url_raw( $_SERVER['HTTP_REFERER'] );
291 }
292
293 // parse args.
294 $args = wp_parse_args(
295 $args,
296 [
297 'timeout' => 20,
298 'sslverify' => true,
299 ]
300 );
301
302 // filter args and endpoint.
303 $args = apply_filters( 'surecart/request/args', $args, $endpoint );
304 $endpoint = apply_filters( 'surecart/request/endpoint', $endpoint, $args );
305
306 // make url.
307 $url = trailingslashit( $this->getBaseUrl() ) . untrailingslashit( $endpoint );
308
309 // add query args.
310 if ( ! empty( $args['query'] ) ) {
311 $url = add_query_arg( $this->parseArgs( $args['query'] ), $url );
312 $url = preg_replace( '/%5B[0-9]+%5D/', '%5B%5D', $url );
313 unset( $args['query'] );
314 }
315
316 // json encode body.
317 if ( ! empty( $args['body'] ) ) {
318 if ( 'application/json' === $args['headers']['Content-Type'] ) {
319 $args['body'] = wp_json_encode( $this->parseArgs( $args['body'] ) );
320 }
321 }
322
323 // make request.
324 $response = $this->remoteRequest( $url, $args );
325
326 // bail early if it's a wp_error.
327 if ( is_wp_error( $response ) ) {
328 return $response;
329 }
330
331 $response_code = wp_remote_retrieve_response_code( $response );
332
333 // handle handle retries.
334 if ( in_array( $response_code, $this->retry_status_codes ) ) {
335 ++$this->current_retries;
336 if ( $this->current_retries <= $this->total_retries ) {
337 call_user_func_array( [ $this, __METHOD__ ], func_get_args() );
338 }
339 }
340
341 $response_body = wp_remote_retrieve_body( $response );
342 $admin_notice = (array) wp_remote_retrieve_header( $response, 'X-SURECART-WP-ADMIN-NOTICE' );
343
344 if ( ! $this->authorized ) {
345 $api_token = (string) wp_remote_retrieve_header( $response, 'X-SURECART-API-TOKEN' );
346 ApiToken::save( $api_token );
347 }
348
349 if ( $admin_notice ) {
350 // we don't care if this fails.
351 try {
352 \SureCart::notices()->showResponseNotice( $admin_notice );
353 } catch ( \Exception $e ) {
354 error_log( $e->getMessage() );
355 }
356 }
357
358 // Handle invalid token first.
359 if ( $this->authorized && 401 === $response_code ) {
360 ApiToken::clear();
361 return new \WP_Error( 'invalid_token', __( 'Invalid API token.', 'surecart' ) );
362 }
363
364 // check for errors.
365 if ( ! in_array( $response_code, [ 200, 201 ], true ) ) {
366 $body = json_decode( $response_body, true );
367 if ( is_string( $body ) ) {
368 return new \WP_Error( 'error', $response_body );
369 }
370 return $this->errors()->translate( $body, $response_code );
371 }
372
373 return json_decode( $response_body );
374 }
375
376 /**
377 * Make the remote request.
378 *
379 * @param string $url The url to request.
380 * @param array $args The args to pass to the request.
381 *
382 * @return mixed
383 */
384 public function remoteRequest( $url, $args = [] ) {
385 return wp_remote_request( esc_url_raw( $url ), $args );
386 }
387
388 /**
389 * Make a get request
390 *
391 * @param string $endpoint Endpoint for the request.
392 * @param array $args Request arguments.
393 *
394 * @return mixed
395 */
396 public function get( $endpoint, $args = [] ) {
397 $args['method'] = 'GET';
398 return $this->makeRequest( $endpoint, $args );
399 }
400
401 /**
402 * Make a post request
403 *
404 * @param string $endpoint Endpoint for the request.
405 * @param array $args Request arguments.
406 *
407 * @return mixed
408 */
409 public function post( $endpoint, $args = [] ) {
410 $args['method'] = 'POST';
411 return $this->makeRequest( $endpoint, $args );
412 }
413
414 /**
415 * Make a put request
416 *
417 * @param string $endpoint Endpoint for the request.
418 * @param array $args Request arguments.
419 *
420 * @return mixed
421 */
422 public function put( $endpoint, $args = [] ) {
423 $args['method'] = 'PUT';
424 return $this->makeRequest( $endpoint, $args );
425 }
426
427 /**
428 * Make a patch request
429 *
430 * @param string $endpoint Endpoint for the request.
431 * @param array $args Request arguments.
432 *
433 * @return mixed
434 */
435 public function patch( $endpoint, $args = [] ) {
436 $args['method'] = 'PATCH';
437 return $this->makeRequest( $endpoint, $args );
438 }
439
440 /**
441 * Make a delete request
442 *
443 * @param string $endpoint Endpoint for the request.
444 * @param array $args Request arguments.
445 *
446 * @return mixed
447 */
448 public function delete( $endpoint, $args = [] ) {
449 $args['method'] = 'DELETE';
450 return $this->makeRequest( $endpoint, $args );
451 }
452
453 /**
454 * Removes empty args
455 *
456 * @param array $args Array of arguments.
457 */
458 protected function parseArgs( $args = [] ) {
459 if ( ! is_array( $args ) ) {
460 return $args;
461 }
462 foreach ( $args as $key => $arg ) {
463 // unset null.
464 if ( null === $arg ) {
465 unset( $args[ $key ] );
466 }
467
468 // filter out wp params.
469 if ( in_array( $key, [ 'locale', 'rest_route' ], true ) ) {
470 unset( $args[ $key ] );
471 }
472
473 // convert bool to int to prevent getting unset.
474 if ( is_bool( $arg ) ) {
475 $args[ $key ] = $arg ? 1 : 0;
476 }
477
478 // url encode any strings.
479 if ( is_string( $arg ) ) {
480 $args[ $key ] = urlencode( $arg );
481 }
482 }
483
484 return $args;
485 }
486 }
487