akashop/volumes/wp/wp-content/plugins/optimole-wp/inc/api.php

562 lines
15 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/**
* The class defines way of connecting this user to the Optimole Dashboard.
*
* @codeCoverageIgnore
* @package \Optimole\Inc
* @author Optimole <friends@optimole.com>
*/
final class Optml_Api {
/**
* Optimole root api url.
*
* @var string Api root.
*/
private $api_root = 'https://dashboard.optimole.com/api/';
/**
* Optimole upload api root url.
*
* @var string Api root.
*/
private $upload_api_root = 'https://generateurls-prod.i.optimole.com/upload';
/**
* Optimole onboard api root url.
*
* @var string Api root.
*/
private $onboard_api_root = 'https://onboard.i.optimole.com/onboard_api/';
/**
* Optimole offload conflicts api root url.
*
* @var string Api root.
*/
private $upload_conflicts_api = 'https://conflicts.i.optimole.com/offload_api/';
/**
* Hold the user api key.
*
* @var string Api key.
*/
private $api_key;
/**
* Optml_Api constructor.
*/
public function __construct() {
$settings = new Optml_Settings();
$this->api_key = $settings->get( 'api_key' );
if ( defined( 'OPTIML_API_ROOT' ) ) {
$this->api_root = constant( 'OPTIML_API_ROOT' );
}
if ( defined( 'OPTIML_UPLOAD_API_ROOT' ) ) {
$this->upload_api_root = constant( 'OPTIML_UPLOAD_API_ROOT' );
}
if ( defined( 'OPTIML_ONBOARD_API_ROOT' ) ) {
$this->onboard_api_root = constant( 'OPTIML_ONBOARD_API_ROOT' );
}
if ( defined( 'OPTIML_UPLOAD_CONFLICTS_API_ROOT' ) ) {
$this->upload_conflicts_api = constant( 'OPTIML_UPLOAD_CONFLICTS_API_ROOT' );
}
}
/**
* Connect to the service.
*
* @param string $api_key Api key.
*
* @return array|bool|WP_Error
*/
public function connect( $api_key = '' ) {
if ( ! empty( $api_key ) ) {
$this->api_key = $api_key;
}
return $this->request( '/optml/v2/account/connect', 'POST', [ 'sample_image' => $this->get_sample_image() ] );
}
/**
* Get sample image.
*
* @return string
*/
private function get_sample_image() {
$accepted_mimes = [ 'image/jpeg', 'image/png', 'image/webp' ];
$args = [
'post_type' => 'attachment',
'post_status' => 'any',
'number' => '1',
'no_found_rows' => true,
'fields' => 'ids',
'post_mime_type' => $accepted_mimes,
'post_parent__not_in' => [ 0 ],
];
$image_result = new WP_Query( $args );
$original_image_url = 'none';
if ( ! empty( $image_result->posts ) ) {
$original_image_url = wp_get_attachment_image_url( $image_result->posts[0], 'full' );
}
return $original_image_url;
}
/**
* Get user data from service.
*
* @return array|string|bool|WP_Error User data.
*/
public function get_user_data( $api_key = '', $application = '' ) {
if ( ! empty( $api_key ) ) {
$this->api_key = $api_key;
}
return $this->request( '/optml/v2/account/details', 'POST', [ 'application' => $application ] );
}
/**
* Toggle the extra visits.
*
* @param string $api_key Api key.
* @param string $status Status of the visits toggle.
*
* @return array|bool|string
*/
public function update_extra_visits( $api_key = '', $status = 'enabled', $application = '' ) {
if ( ! empty( $api_key ) ) {
$this->api_key = $api_key;
}
return $this->request( '/optml/v2/account/extra_visits', 'POST', [ 'extra_visits' => $status, 'application' => $application ] );
}
/**
* Get cache token from service.
*
* @return array|bool|WP_Error User data.
*/
public function get_cache_token( $token = '', $type = '', $api_key = '' ) {
if ( ! empty( $api_key ) ) {
$this->api_key = $api_key;
}
$lock = get_transient( 'optml_cache_lock' );
if ( ! empty( $type ) && $type === 'assets' ) {
$lock = get_transient( 'optml_cache_lock_assets' );
}
if ( $lock === 'yes' ) {
return new WP_Error( 'cache_throttle', __( 'You can clear cache only once per 5 minutes.', 'optimole-wp' ) );
}
return $this->request( '/optml/v1/cache/tokens', 'POST', [ 'token' => $token, 'type' => $type ] );
}
/**
* Request constructor.
*
* @param string $path The request url.
* @param string $method The request method type.
* @param array|string $params The request method type.
*
* @return array|string|boolean|WP_Error Api data.
*/
private function request( $path, $method = 'GET', $params = [], $extra_headers = [] ) {
$headers = [
'Optml-Site' => get_home_url(),
];
if ( ! empty( $this->api_key ) ) {
$headers['Authorization'] = 'Bearer ' . $this->api_key;
}
if ( is_array( $headers ) ) {
$headers = array_merge( $headers, $extra_headers );
}
$url = trailingslashit( $this->api_root ) . ltrim( $path, '/' );
// If there is a extra, add that as a url var.
if ( 'GET' === $method && ! empty( $params ) ) {
foreach ( $params as $key => $val ) {
$url = add_query_arg( [ $key => $val ], $url );
}
}
$args = $this->build_args( $method, $url, $headers, $params );
$response = wp_remote_request( $url, $args );
if ( is_wp_error( $response ) ) {
return $response;
}
$response = wp_remote_retrieve_body( $response );
if ( empty( $response ) ) {
return false;
}
$response = json_decode( $response, true );
if ( isset( $response['id'] ) && is_numeric( $response['id'] ) ) {
return true;
}
if ( ! isset( $response['code'] ) ) {
return false;
}
if ( intval( $response['code'] ) !== 200 ) {
if ( isset( $response['error'] ) && $response['error'] === 'domain_not_accessible' ) {
return new WP_Error( 'domain_not_accessible', sprintf( __( 'It seems Optimole is having trouble reaching your website. This issue often occurs if your website is private, local, or protected by a firewall. But don\'t stress it\'s an easy fix! Ensure your website is live and accessible to the public. If a firewall is in place, just tweak the settings to allow the %1$sOptimole(1.0)%2$s user agent access to your website. %3$sLearn More%4$s', 'optimole-wp' ), '<i>', '</i>', '<a href="https://docs.optimole.com/article/1976-resolving-optimole-access-to-your-website" target="_blank">', '</a>' ) );
}
if ( $path === 'optml/v2/account/complete_register_remote' && isset( $response['error'] ) ) {
if ( strpos( $response['error'], 'This email address is already registered.' ) !== false ) {
return 'email_registered';
}
if ( $response['error'] === 'ERROR: Site already whitelisted.' ) {
return 'site_exists';
}
}
if ( $path === '/optml/v2/account/details'
&& isset( $response['code'] ) && $response['code'] === 'not_allowed' ) {
return 'disconnect';
}
return false;
}
return $response['data'];
}
/**
* Builds Request arguments array.
*
* @param string $method Request method (GET | POST | PUT | UPDATE | DELETE).
* @param string $url Request URL.
* @param array $headers Headers Array.
* @param array|string $params Additional params for the Request.
*
* @return array
*/
private function build_args( $method, $url, $headers, $params ) {
$args = [
'method' => $method,
'timeout' => 45,
'user-agent' => 'Optimle WP (v' . OPTML_VERSION . ') ',
'sslverify' => false,
'headers' => $headers,
];
if ( $method !== 'GET' ) {
$args['body'] = $params;
}
return $args;
}
/**
* Upload image to our servers using the generated signed url.
*
* @param string $upload_url The signed to url to upload the image to.
* @param string $content_type Image mime type, it must match the actual mime type of the image.
* @param string $image Image data from file_get_contents.
* @return mixed
*/
public function upload_image( $upload_url, $content_type, $image ) {
$args = $this->build_args( 'PUT', '', ['content-type' => $content_type], $image );
return wp_remote_request( $upload_url, $args );
}
/**
* Check if the optimized url is available.
*
* @param string $url The optimized url to check.
* @return bool Whether or not the url is valid.
*/
public function check_optimized_url( $url ) {
$response = wp_remote_get( $url, ['timeout' => 30] );
if ( is_wp_error( $response ) || wp_remote_retrieve_response_code( $response ) !== 200 || ! empty( wp_remote_retrieve_header( $response, 'x-not-found-o' ) ) ) {
$this->log_offload_error( $response );
return false;
}
return true;
}
/**
* Get options for the signed urls api call.
*
* @param string $original_url Image original url.
* @param string $delete Whether to delete a bucket object or not(ie. generate signed upload url).
* @param string $table_id Remote id used on our servers.
* @param string $update_table False or success.
* @param string $get_url Whether to return a get url or not.
* @param string $width Original image width.
* @param string $height Original image height.
* @param int $file_size Original file size.
* @return array|WP_Error
*/
public function call_upload_api( $original_url = '', $delete = 'false', $table_id = '', $update_table = 'false', $get_url = 'false', $width = 'auto', $height = 'auto', $file_size = 0 ) {
$body = [
'secret' => Optml_Config::$secret,
'userKey' => Optml_Config::$key,
'originalUrl' => $original_url,
'deleteUrl' => $delete,
'id' => $table_id,
'updateDynamo' => $update_table,
'getUrl' => $get_url,
'width' => $width,
'height' => $height,
'originalFileSize' => $file_size,
];
$body = wp_json_encode( $body );
$options = [
'body' => $body,
'headers' => [
'Content-Type' => 'application/json',
],
'timeout' => 60,
'blocking' => true,
'sslverify' => false,
'data_format' => 'body',
];
return wp_remote_post( $this->upload_api_root, $options );
}
/**
* Send a list of images to upload.
*
* @param array $images List of Images.
* @return array
*/
public function call_onboard_api( $images = [] ) {
$settings = new Optml_Settings();
$token_images = $settings->get( 'cache_buster_images' );
$body = [
'secret' => Optml_Config::$secret,
'userKey' => Optml_Config::$key,
'images' => $images,
'cache_buster' => $token_images,
];
$body = wp_json_encode( $body );
$options = [
'body' => $body,
'headers' => [
'Content-Type' => 'application/json',
],
'timeout' => 60,
'blocking' => true,
'sslverify' => false,
'data_format' => 'body',
];
return wp_remote_post( $this->onboard_api_root, $options );
}
/**
* Send a list of images with alt/title values to update.
*
* @param array $images List of images.
* @return array
*/
public function call_data_enrich_api( $images = [] ) {
return $this->request( 'optml/v2/media/add_data', 'POST', ['images' => $images, 'key' => Optml_Config::$key] );
}
/**
* Register user remotely on optimole.com.
*
* @param string $email User email.
*
* @return array|bool|string|WP_Error Api response.
*/
public function create_account( $email ) {
return $this->request(
'optml/v2/account/complete_register_remote',
'POST',
[
'email' => $email,
'version' => OPTML_VERSION,
'sample_image' => $this->get_sample_image(),
'site' => get_home_url(),
]
);
}
/**
* Get the optimized images from API.
*
* @param string $api_key the api key.
*
* @return array|bool|WP_Error
*/
public function get_optimized_images( $api_key = '' ) {
if ( ! empty( $api_key ) ) {
$this->api_key = $api_key;
}
$app_key = '';
$settings = new Optml_Settings();
$service_data = $settings->get( 'service_data' );
if ( isset( $service_data['cdn_key'] ) ) {
$app_key = $service_data['cdn_key'];
}
return $this->request( '/optml/v1/stats/images', 'GET', [], ['application' => $app_key] );
}
/**
* Get the watermarks from API.
*
* @param string $api_key The API key.
*
* @return array|bool|WP_Error
*/
public function get_watermarks( $api_key = '' ) {
if ( ! empty( $api_key ) ) {
$this->api_key = $api_key;
}
return $this->request( '/optml/v1/settings/watermark' );
}
/**
* Remove the watermark from the API.
*
* @param integer $post_id The watermark post ID.
* @param string $api_key The API key.
*
* @return array|bool|WP_Error
*/
public function remove_watermark( $post_id, $api_key = '' ) {
if ( ! empty( $api_key ) ) {
$this->api_key = $api_key;
}
return $this->request( '/optml/v1/settings/watermark', 'DELETE', [ 'watermark' => $post_id ] );
}
/**
* Add watermark.
*
* @param array $file The file to be uploaded.
*
* @return array|bool|mixed|object
*/
public function add_watermark( $file ) {
$headers = [
'Content-Disposition' => 'attachment; filename=' . $file['file']['name'],
];
$response = $this->request( 'wp/v2/media', 'POST', file_get_contents( $file['file']['tmp_name'] ), $headers );
if ( $response === false ) {
return false;
}
return $response;
}
/**
* Call the images endpoint.
*
* @param integer $page Page used to advance the search.
* @param array $domains Domains to filter by.
* @param string $search The string to search inside the originURL.
* @return mixed The decoded json response from the api.
*/
public function get_cloud_images( $page = 0, $domains = [], $search = '' ) {
$params = ['key' => Optml_Config::$key ];
$params['page'] = $page;
$params['size'] = 40;
if ( $search !== '' ) {
$params['search'] = $search;
}
if ( ! empty( $domains ) ) {
$params['domains'] = implode( ',', $domains );
}
return $this->request( 'optml/v2/media/browser', 'GET', $params );
}
/**
* Get offload conflicts.
*
* @return array The decoded conflicts list.
*/
public function get_offload_conflicts() {
$conflicts_list = wp_remote_retrieve_body( wp_remote_get( $this->upload_conflicts_api ) );
return json_decode( $conflicts_list, true );
}
/**
* Get offload conflicts.
*
* @param array $error_response The error to send as a string.
*/
public function log_offload_error( $error_response ) {
$headers = wp_remote_retrieve_headers( $error_response );
$body = wp_remote_retrieve_body( $error_response );
$headers_to_log = 'no_headers_returned';
if ( ! empty( $headers ) ) {
$headers_to_log = wp_json_encode( $headers->getAll() );
}
wp_remote_post(
$this->upload_conflicts_api,
[
'headers' => [ 'Content-Type' => 'application/json' ],
'timeout' => 15,
'blocking' => true,
'sslverify' => false,
'data_format' => 'body',
'body' => [
'error_body' => wp_json_encode( $body ),
'error_headers' => $headers_to_log,
'error_site' => wp_json_encode( get_home_url() ),
],
]
);
}
/**
* Send Offloading Logs
*
* @param string $type Type of log (offload/rollback).
* @param string $message Log message.
*
* @return mixed
*/
public function send_log( $type, $message ) {
return $this->request(
'optml/v2/logs',
'POST',
[
'type' => $type,
'message' => $message,
'site' => get_home_url(),
]
);
}
/**
* Throw error on object clone
*
* The whole idea of the singleton design pattern is that there is a single
* object therefore, we don't want the object to be cloned.
*
* @access public
* @return void
* @since 1.0.0
*/
public function __clone() {
// Cloning instances of the class is forbidden.
_doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin&#8217; huh?', 'optimole-wp' ), '1.0.0' );
}
/**
* Disable unserializing of the class
*
* @access public
* @return void
* @since 1.0.0
*/
public function __wakeup() {
// Unserializing instances of the class is forbidden.
_doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin&#8217; huh?', 'optimole-wp' ), '1.0.0' );
}
}