PluginProbe
Optimole – Optimize Images | Convert WebP & AVIF | CDN & Lazy Load | Image Optimization / 3.11.2
Optimole – Optimize Images | Convert WebP & AVIF | CDN & Lazy Load | Image Optimization v3.11.2
4.2.13 4.2.12 4.2.11 4.2.10 4.2.9 4.2.8 4.2.7 4.2.6 4.2.5 2.5.5 2.5.6 2.5.7 3.0.0 3.0.1 3.1.0 3.1.1 3.1.2 3.1.3 3.10.0 3.11.0 3.11.1 3.11.2 3.11.3 3.12.0 3.12.1 All 134 releases
optimole-wp / inc / api.php

api.php in Optimole – Optimize Images | Convert WebP & AVIF | CDN & Lazy Load | Image Optimization 3.11.2, at inc/api.php

534 lines 14.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * The class defines way of connecting this user to the Optimole Dashboard.
5 *
6 * @codeCoverageIgnore
7 * @package \Optimole\Inc
8 * @author Optimole <friends@optimole.com>
9 */
10 final class Optml_Api {
11
12 /**
13 * Optimole root api url.
14 *
15 * @var string Api root.
16 */
17 private $api_root = 'https://dashboard.optimole.com/api/';
18 /**
19 * Optimole upload api root url.
20 *
21 * @var string Api root.
22 */
23 private $upload_api_root = 'https://generateurls-prod.i.optimole.com/upload';
24 /**
25 * Optimole onboard api root url.
26 *
27 * @var string Api root.
28 */
29 private $onboard_api_root = 'https://onboard.i.optimole.com/onboard_api/';
30 /**
31 * Optimole offload conflicts api root url.
32 *
33 * @var string Api root.
34 */
35 private $upload_conflicts_api = 'https://conflicts.i.optimole.com/offload_api/';
36 /**
37 * Hold the user api key.
38 *
39 * @var string Api key.
40 */
41 private $api_key;
42 /**
43 * Optml_Api constructor.
44 */
45 public function __construct() {
46 $settings = new Optml_Settings();
47 $this->api_key = $settings->get( 'api_key' );
48 if ( defined( 'OPTIML_API_ROOT' ) && constant( 'OPTIML_API_ROOT' ) ) {
49 $this->api_root = constant( 'OPTIML_API_ROOT' );
50 }
51 if ( defined( 'OPTIML_UPLOAD_API_ROOT' ) && constant( 'OPTIML_UPLOAD_API_ROOT' ) ) {
52 $this->upload_api_root = constant( 'OPTIML_UPLOAD_API_ROOT' );
53 }
54 if ( defined( 'OPTIML_ONBOARD_API_ROOT' ) && constant( 'OPTIML_ONBOARD_API_ROOT' ) ) {
55 $this->onboard_api_root = constant( 'OPTIML_ONBOARD_API_ROOT' );
56 }
57 if ( defined( 'OPTIML_UPLOAD_CONFLICTS_API_ROOT' ) && constant( 'OPTIML_UPLOAD_CONFLICTS_API_ROOT' ) ) {
58 $this->upload_conflicts_api = constant( 'OPTIML_UPLOAD_CONFLICTS_API_ROOT' );
59 }
60 }
61
62 /**
63 * Connect to the service.
64 *
65 * @param string $api_key Api key.
66 *
67 * @return array|bool|WP_Error
68 */
69 public function connect( $api_key = '' ) {
70 if ( ! empty( $api_key ) ) {
71 $this->api_key = $api_key;
72 }
73
74 return $this->request( '/optml/v2/account/connect', 'POST' );
75 }
76
77 /**
78 * Get user data from service.
79 *
80 * @return array|string|bool|WP_Error User data.
81 */
82 public function get_user_data( $api_key = '', $application = '' ) {
83 if ( ! empty( $api_key ) ) {
84 $this->api_key = $api_key;
85 }
86
87 return $this->request( '/optml/v2/account/details', 'POST', [ 'application' => $application ] );
88 }
89
90 /**
91 * Toggle the extra visits.
92 *
93 * @param string $api_key Api key.
94 * @param string $status Status of the visits toggle.
95 *
96 * @return array|bool|string
97 */
98 public function update_extra_visits( $api_key = '', $status = 'enabled', $application = '' ) {
99 if ( ! empty( $api_key ) ) {
100 $this->api_key = $api_key;
101 }
102
103 return $this->request( '/optml/v2/account/extra_visits', 'POST', [ 'extra_visits' => $status, 'application' => $application ] );
104 }
105
106 /**
107 * Get cache token from service.
108 *
109 * @return array|bool|WP_Error User data.
110 */
111 public function get_cache_token( $token = '', $type = '', $api_key = '' ) {
112 if ( ! empty( $api_key ) ) {
113 $this->api_key = $api_key;
114 }
115 $lock = get_transient( 'optml_cache_lock' );
116 if ( ! empty( $type ) && $type === 'assets' ) {
117 $lock = get_transient( 'optml_cache_lock_assets' );
118 }
119
120 if ( $lock === 'yes' ) {
121 return new WP_Error( 'cache_throttle', __( 'You can clear cache only once per 5 minutes.', 'optimole-wp' ) );
122 }
123 return $this->request( '/optml/v1/cache/tokens', 'POST', [ 'token' => $token, 'type' => $type ] );
124 }
125
126 /**
127 * Request constructor.
128 *
129 * @param string $path The request url.
130 * @param string $method The request method type.
131 * @param array|string $params The request method type.
132 *
133 * @return array|string|boolean|WP_Error Api data.
134 */
135 private function request( $path, $method = 'GET', $params = [], $extra_headers = [] ) {
136
137 $headers = [
138 'Optml-Site' => get_home_url(),
139 ];
140 if ( ! empty( $this->api_key ) ) {
141 $headers['Authorization'] = 'Bearer ' . $this->api_key;
142 }
143 if ( is_array( $headers ) ) {
144 $headers = array_merge( $headers, $extra_headers );
145 }
146 $url = trailingslashit( $this->api_root ) . ltrim( $path, '/' );
147 // If there is a extra, add that as a url var.
148 if ( 'GET' === $method && ! empty( $params ) ) {
149 foreach ( $params as $key => $val ) {
150 $url = add_query_arg( [ $key => $val ], $url );
151 }
152 }
153 $args = $this->build_args( $method, $url, $headers, $params );
154
155 $response = wp_remote_request( $url, $args );
156
157 if ( is_wp_error( $response ) ) {
158 return $response;
159 }
160
161 $response = wp_remote_retrieve_body( $response );
162
163 if ( empty( $response ) ) {
164 return false;
165 }
166 $response = json_decode( $response, true );
167
168 if ( isset( $response['id'] ) && is_numeric( $response['id'] ) ) {
169 return true;
170 }
171 if ( ! isset( $response['code'] ) ) {
172 return false;
173 }
174
175 if ( intval( $response['code'] ) !== 200 ) {
176 if ( $path === 'optml/v2/account/complete_register_remote' && isset( $response['error'] ) ) {
177 if ( strpos( $response['error'], 'This email address is already registered.' ) !== false ) {
178 return 'email_registered';
179 }
180
181 if ( $response['error'] === 'ERROR: Site already whitelisted.' ) {
182 return 'site_exists';
183 }
184 }
185
186 if ( $path === '/optml/v2/account/details'
187 && isset( $response['code'] ) && $response['code'] === 'not_allowed' ) {
188 return 'disconnect';
189 }
190 return false;
191 }
192
193 return $response['data'];
194
195 }
196
197 /**
198 * Builds Request arguments array.
199 *
200 * @param string $method Request method (GET | POST | PUT | UPDATE | DELETE).
201 * @param string $url Request URL.
202 * @param array $headers Headers Array.
203 * @param array|string $params Additional params for the Request.
204 *
205 * @return array
206 */
207 private function build_args( $method, $url, $headers, $params ) {
208 $args = [
209 'method' => $method,
210 'timeout' => 45,
211 'user-agent' => 'Optimle WP (v' . OPTML_VERSION . ') ',
212 'sslverify' => false,
213 'headers' => $headers,
214 ];
215 if ( $method !== 'GET' ) {
216 $args['body'] = $params;
217 }
218
219 return $args;
220 }
221
222 /**
223 * Upload image to our servers using the generated signed url.
224 *
225 * @param string $upload_url The signed to url to upload the image to.
226 * @param string $content_type Image mime type, it must match the actual mime type of the image.
227 * @param string $image Image data from file_get_contents.
228 * @return mixed
229 */
230 public function upload_image( $upload_url, $content_type, $image ) {
231 $args = $this->build_args( 'PUT', '', ['content-type' => $content_type], $image );
232 return wp_remote_request( $upload_url, $args );
233 }
234
235 /**
236 * Check if the optimized url is available.
237 *
238 * @param string $url The optimized url to check.
239 * @return bool Whether or not the url is valid.
240 */
241 public function check_optimized_url( $url ) {
242 $response = wp_remote_get( $url, ['timeout' => 30] );
243
244 if ( is_wp_error( $response ) || wp_remote_retrieve_response_code( $response ) !== 200 || ! empty( wp_remote_retrieve_header( $response, 'x-not-found-o' ) ) ) {
245 $this->log_offload_error( $response );
246 return false;
247 }
248 return true;
249 }
250
251 /**
252 * Get options for the signed urls api call.
253 *
254 * @param string $original_url Image original url.
255 * @param string $delete Whether to delete a bucket object or not(ie. generate signed upload url).
256 * @param string $table_id Remote id used on our servers.
257 * @param string $update_table False or success.
258 * @param string $get_url Whether to return a get url or not.
259 * @param string $width Original image width.
260 * @param string $height Original image height.
261 * @param int $file_size Original file size.
262 * @return array|WP_Error
263 */
264 public function call_upload_api( $original_url = '', $delete = 'false', $table_id = '', $update_table = 'false', $get_url = 'false', $width = 'auto', $height = 'auto', $file_size = 0 ) {
265 $body = [
266 'secret' => Optml_Config::$secret,
267 'userKey' => Optml_Config::$key,
268 'originalUrl' => $original_url,
269 'deleteUrl' => $delete,
270 'id' => $table_id,
271 'updateDynamo' => $update_table,
272 'getUrl' => $get_url,
273 'width' => $width,
274 'height' => $height,
275 'originalFileSize' => $file_size,
276 ];
277 $body = wp_json_encode( $body );
278
279 $options = [
280 'body' => $body,
281 'headers' => [
282 'Content-Type' => 'application/json',
283 ],
284 'timeout' => 60,
285 'blocking' => true,
286 'sslverify' => false,
287 'data_format' => 'body',
288 ];
289 return wp_remote_post( $this->upload_api_root, $options );
290 }
291
292 /**
293 * Send a list of images to upload.
294 *
295 * @param array $images List of Images.
296 * @return array
297 */
298 public function call_onboard_api( $images = [] ) {
299 $settings = new Optml_Settings();
300 $token_images = $settings->get( 'cache_buster_images' );
301
302 $body = [
303 'secret' => Optml_Config::$secret,
304 'userKey' => Optml_Config::$key,
305 'images' => $images,
306 'cache_buster' => $token_images,
307 ];
308 $body = wp_json_encode( $body );
309
310 $options = [
311 'body' => $body,
312 'headers' => [
313 'Content-Type' => 'application/json',
314 ],
315 'timeout' => 60,
316 'blocking' => true,
317 'sslverify' => false,
318 'data_format' => 'body',
319 ];
320 return wp_remote_post( $this->onboard_api_root, $options );
321 }
322
323
324 /**
325 * Send a list of images with alt/title values to update.
326 *
327 * @param array $images List of images.
328 * @return array
329 */
330 public function call_data_enrich_api( $images = [] ) {
331 return $this->request( 'optml/v2/media/add_data', 'POST', ['images' => $images, 'key' => Optml_Config::$key] );
332 }
333 /**
334 * Register user remotely on optimole.com.
335 *
336 * @param string $email User email.
337 *
338 * @return array|bool|string|WP_Error Api response.
339 */
340 public function create_account( $email ) {
341 return $this->request(
342 'optml/v2/account/complete_register_remote',
343 'POST',
344 [
345 'email' => $email,
346 'version' => OPTML_VERSION,
347 'site' => get_home_url(),
348 ]
349 );
350 }
351
352 /**
353 * Get the optimized images from API.
354 *
355 * @param string $api_key the api key.
356 *
357 * @return array|bool|WP_Error
358 */
359 public function get_optimized_images( $api_key = '' ) {
360 if ( ! empty( $api_key ) ) {
361 $this->api_key = $api_key;
362 }
363 $app_key = '';
364 $settings = new Optml_Settings();
365 $service_data = $settings->get( 'service_data' );
366 if ( isset( $service_data['cdn_key'] ) ) {
367 $app_key = $service_data['cdn_key'];
368 }
369 return $this->request( '/optml/v1/stats/images', 'GET', [], ['application' => $app_key] );
370 }
371
372 /**
373 * Get the watermarks from API.
374 *
375 * @param string $api_key The API key.
376 *
377 * @return array|bool|WP_Error
378 */
379 public function get_watermarks( $api_key = '' ) {
380 if ( ! empty( $api_key ) ) {
381 $this->api_key = $api_key;
382 }
383
384 return $this->request( '/optml/v1/settings/watermark' );
385 }
386
387 /**
388 * Remove the watermark from the API.
389 *
390 * @param integer $post_id The watermark post ID.
391 * @param string $api_key The API key.
392 *
393 * @return array|bool|WP_Error
394 */
395 public function remove_watermark( $post_id, $api_key = '' ) {
396 if ( ! empty( $api_key ) ) {
397 $this->api_key = $api_key;
398 }
399
400 return $this->request( '/optml/v1/settings/watermark', 'DELETE', [ 'watermark' => $post_id ] );
401 }
402
403 /**
404 * Add watermark.
405 *
406 * @param array $file The file to be uploaded.
407 *
408 * @return array|bool|mixed|object
409 */
410 public function add_watermark( $file ) {
411
412 $headers = [
413 'Content-Disposition' => 'attachment; filename=' . $file['file']['name'],
414 ];
415
416 $response = $this->request( 'wp/v2/media', 'POST', file_get_contents( $file['file']['tmp_name'] ), $headers );
417
418 if ( $response === false ) {
419 return false;
420 }
421
422 return $response;
423 }
424
425 /**
426 * Call the images endpoint.
427 *
428 * @param integer $page Page used to advance the search.
429 * @param array $domains Domains to filter by.
430 * @param string $search The string to search inside the originURL.
431 * @return mixed The decoded json response from the api.
432 */
433 public function get_cloud_images( $page = 0, $domains = [], $search = '' ) {
434
435 $params = ['key' => Optml_Config::$key ];
436 $params['page'] = $page;
437 $params['size'] = 40;
438 if ( $search !== '' ) {
439 $params['search'] = $search;
440 }
441
442 if ( ! empty( $domains ) ) {
443 $params['domains'] = implode( ',', $domains );
444 }
445 return $this->request( 'optml/v2/media/browser', 'GET', $params );
446 }
447 /**
448 * Get offload conflicts.
449 *
450 * @return array The decoded conflicts list.
451 */
452 public function get_offload_conflicts() {
453 $conflicts_list = wp_remote_retrieve_body( wp_remote_get( $this->upload_conflicts_api ) );
454 return json_decode( $conflicts_list, true );
455 }
456 /**
457 * Get offload conflicts.
458 *
459 * @param array $error_response The error to send as a string.
460 */
461 public function log_offload_error( $error_response ) {
462
463 $headers = wp_remote_retrieve_headers( $error_response );
464 $body = wp_remote_retrieve_body( $error_response );
465
466 $headers_to_log = 'no_headers_returned';
467 if ( ! empty( $headers ) ) {
468 $headers_to_log = wp_json_encode( $headers->getAll() );
469 }
470 wp_remote_post(
471 $this->upload_conflicts_api,
472 [
473 'headers' => [ 'Content-Type' => 'application/json' ],
474 'timeout' => 15,
475 'blocking' => true,
476 'sslverify' => false,
477 'data_format' => 'body',
478 'body' => [
479 'error_body' => wp_json_encode( $body ),
480 'error_headers' => $headers_to_log,
481 'error_site' => wp_json_encode( get_home_url() ),
482 ],
483 ]
484 );
485 }
486
487 /**
488 * Send Offloading Logs
489 *
490 * @param string $type Type of log (offload/rollback).
491 * @param string $message Log message.
492 *
493 * @return mixed
494 */
495 public function send_log( $type, $message ) {
496 return $this->request(
497 'optml/v2/logs',
498 'POST',
499 [
500 'type' => $type,
501 'message' => $message,
502 'site' => get_home_url(),
503 ]
504 );
505 }
506
507 /**
508 * Throw error on object clone
509 *
510 * The whole idea of the singleton design pattern is that there is a single
511 * object therefore, we don't want the object to be cloned.
512 *
513 * @access public
514 * @return void
515 * @since 1.0.0
516 */
517 public function __clone() {
518 // Cloning instances of the class is forbidden.
519 _doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin&#8217; huh?', 'optimole-wp' ), '1.0.0' );
520 }
521
522 /**
523 * Disable unserializing of the class
524 *
525 * @access public
526 * @return void
527 * @since 1.0.0
528 */
529 public function __wakeup() {
530 // Unserializing instances of the class is forbidden.
531 _doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin&#8217; huh?', 'optimole-wp' ), '1.0.0' );
532 }
533 }
534