File "Ewww.php"
Full Path: /var/www/html/wordpress/wp-content/plugins/wp-optimize/vendor/rosell-dk/webp-convert/src/Convert/Converters/Ewww.php
File size: 13.3 KB
MIME-type: text/x-php
Charset: utf-8
<?php
namespace WebPConvert\Convert\Converters;
use WebPConvert\Convert\Converters\AbstractConverter;
use WebPConvert\Convert\Converters\ConverterTraits\CloudConverterTrait;
use WebPConvert\Convert\Converters\ConverterTraits\CurlTrait;
use WebPConvert\Convert\Exceptions\ConversionFailedException;
use WebPConvert\Convert\Exceptions\ConversionFailed\ConverterNotOperationalException;
use WebPConvert\Convert\Exceptions\ConversionFailed\ConverterNotOperational\InvalidApiKeyException;
use WebPConvert\Convert\Exceptions\ConversionFailed\ConverterNotOperational\SystemRequirementsNotMetException;
use WebPConvert\Options\BooleanOption;
use WebPConvert\Options\SensitiveStringOption;
use WebPConvert\Options\OptionFactory;
/**
* Convert images to webp using ewww cloud service.
*
* @package WebPConvert
* @author Bjørn Rosell <[email protected]>
* @since Class available since Release 2.0.0
*/
class Ewww extends AbstractConverter
{
use CloudConverterTrait;
use CurlTrait;
/** @var array|null Array of invalid or exceeded api keys discovered during conversions (during the request) */
public static $nonFunctionalApiKeysDiscoveredDuringConversion;
public function getUniqueOptions($imageType)
{
return OptionFactory::createOptions([
['api-key', 'string', [
'title' => 'Ewww API key',
'description' => 'ewww API key. ' .
'If you choose "auto", webp-convert will ' .
'convert to both lossy and lossless and pick the smallest result',
'default' => '',
'sensitive' => true,
'ui' => [
'component' => 'password',
]
]],
['check-key-status-before-converting', 'boolean', [
'title' => 'Check key status before converting',
'description' =>
'If enabled, the api key will be validated (relative inexpensive) before trying ' .
'to convert. For automatic conversions, you should enable it. Otherwise you run the ' .
'risk that the same files will be uploaded to ewww cloud service over and over again, ' .
'in case the key has expired. For manually triggered conversions, you can safely disable ' .
'the option.',
'default' => true,
'ui' => [
'component' => 'checkbox',
]
]],
]);
}
protected function getUnsupportedDefaultOptions()
{
return [
'alpha-quality',
'auto-filter',
'encoding',
'low-memory',
'method',
'near-lossless',
'preset',
'sharp-yuv',
'size-in-percentage',
];
}
/**
* Get api key from options or environment variable
*
* @return string|false api key or false if none is set
*/
private function getKey()
{
if (!empty($this->options['api-key'])) {
return $this->options['api-key'];
}
if (defined('WEBPCONVERT_EWWW_API_KEY')) {
return constant('WEBPCONVERT_EWWW_API_KEY');
}
if (!empty(getenv('WEBPCONVERT_EWWW_API_KEY'))) {
return getenv('WEBPCONVERT_EWWW_API_KEY');
}
return false;
}
/**
* Check operationality of Ewww converter.
*
* @throws SystemRequirementsNotMetException if system requirements are not met (curl)
* @throws ConverterNotOperationalException if key is missing or invalid, or quota has exceeded
*/
public function checkOperationality()
{
$apiKey = $this->getKey();
if ($apiKey === false) {
if (isset($this->options['key'])) {
throw new InvalidApiKeyException(
'The "key" option has been renamed to "api-key" in webp-convert 2.0. ' .
'You must change the configuration accordingly.'
);
}
throw new InvalidApiKeyException('Missing API key.');
}
if (strlen($apiKey) < 20) {
throw new InvalidApiKeyException(
'Api key is invalid. Api keys are supposed to be 32 characters long - ' .
'the provided api key is much shorter'
);
}
// Check for curl requirements
$this->checkOperationalityForCurlTrait();
if ($this->options['check-key-status-before-converting']) {
$keyStatus = self::getKeyStatus($apiKey);
switch ($keyStatus) {
case 'great':
break;
case 'exceeded':
throw new ConverterNotOperationalException('Quota has exceeded');
//break;
case 'invalid':
throw new InvalidApiKeyException('Api key is invalid');
//break;
}
}
}
/*
public function checkConvertability()
{
// check upload limits
$this->checkConvertabilityCloudConverterTrait();
}
*/
// Although this method is public, do not call directly.
// You should rather call the static convert() function, defined in AbstractConverter, which
// takes care of preparing stuff before calling doConvert, and validating after.
protected function doActualConvert()
{
$options = $this->options;
$ch = self::initCurl();
//$this->logLn('api key:' . $this->getKey());
$postData = [
'api_key' => $this->getKey(),
'webp' => '1',
'file' => curl_file_create($this->source),
'quality' => $this->getCalculatedQuality(),
'metadata' => ($options['metadata'] == 'none' ? '0' : '1')
];
curl_setopt_array(
$ch,
[
CURLOPT_URL => "https://optimize.exactlywww.com/v2/",
CURLOPT_HTTPHEADER => [
'User-Agent: WebPConvert',
'Accept: image/*'
],
CURLOPT_POSTFIELDS => $postData,
CURLOPT_BINARYTRANSFER => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HEADER => false,
CURLOPT_SSL_VERIFYPEER => false
]
);
$response = curl_exec($ch);
if (curl_errno($ch)) {
throw new ConversionFailedException(curl_error($ch));
}
// The API does not always return images.
// For example, it may return a message such as '{"error":"invalid","t":"exceeded"}
// Messages has a http content type of ie 'text/html; charset=UTF-8
// Images has application/octet-stream.
// So verify that we got an image back.
if (curl_getinfo($ch, CURLINFO_CONTENT_TYPE) != 'application/octet-stream') {
//echo curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
curl_close($ch);
/*
For bogus or expired key it returns: {"error":"invalid","t":"exceeded"}
For exceeded key it returns: {"error":"exceeded"}
*/
$responseObj = json_decode($response);
if (isset($responseObj->error)) {
$this->logLn('We received the following error response: ' . $responseObj->error);
$this->logLn('Complete response: ' . json_encode($responseObj));
// Store the invalid key in array so it can be received once the Stack is completed
// (even when stack succeeds)
if (!isset(self::$nonFunctionalApiKeysDiscoveredDuringConversion)) {
self::$nonFunctionalApiKeysDiscoveredDuringConversion = [];
}
if (!in_array($options['api-key'], self::$nonFunctionalApiKeysDiscoveredDuringConversion)) {
self::$nonFunctionalApiKeysDiscoveredDuringConversion[] = $options['api-key'];
}
if ($responseObj->error == "invalid") {
throw new InvalidApiKeyException('The api key is invalid (or expired)');
} else {
throw new InvalidApiKeyException('The quota is exceeded for the api-key');
}
}
throw new ConversionFailedException(
'ewww api did not return an image. It could be that the key is invalid. Response: '
. $response
);
}
// Not sure this can happen. So just in case
if ($response == '') {
throw new ConversionFailedException('ewww api did not return anything');
}
$success = file_put_contents($this->destination, $response);
if (!$success) {
throw new ConversionFailedException('Error saving file');
}
}
/**
* Keep subscription alive by optimizing a jpeg
* (ewww closes accounts after 6 months of inactivity - and webp conversions seems not to be counted? )
*/
public static function keepSubscriptionAlive($source, $key)
{
try {
$ch = curl_init();
} catch (\Exception $e) {
return 'curl is not installed';
}
if ($ch === false) {
return 'curl could not be initialized';
}
curl_setopt_array(
$ch,
[
CURLOPT_URL => "https://optimize.exactlywww.com/v2/",
CURLOPT_HTTPHEADER => [
'User-Agent: WebPConvert',
'Accept: image/*'
],
CURLOPT_POSTFIELDS => [
'api_key' => $key,
'webp' => '0',
'file' => curl_file_create($source),
'domain' => $_SERVER['HTTP_HOST'],
'quality' => 60,
'metadata' => 0
],
CURLOPT_BINARYTRANSFER => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HEADER => false,
CURLOPT_SSL_VERIFYPEER => false
]
);
$response = curl_exec($ch);
if (curl_errno($ch)) {
return 'curl error' . curl_error($ch);
}
if (curl_getinfo($ch, CURLINFO_CONTENT_TYPE) != 'application/octet-stream') {
curl_close($ch);
/* May return this: {"error":"invalid","t":"exceeded"} */
$responseObj = json_decode($response);
if (isset($responseObj->error)) {
return 'The key is invalid';
}
return 'ewww api did not return an image. It could be that the key is invalid. Response: ' . $response;
}
// Not sure this can happen. So just in case
if ($response == '') {
return 'ewww api did not return anything';
}
return true;
}
/*
public static function blacklistKey($key)
{
}
public static function isKeyBlacklisted($key)
{
}*/
/**
* Return "great", "exceeded" or "invalid"
*/
public static function getKeyStatus($key)
{
$ch = self::initCurl();
curl_setopt($ch, CURLOPT_URL, "https://optimize.exactlywww.com/verify/");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, [
'api_key' => $key
]);
curl_setopt($ch, CURLOPT_USERAGENT, 'WebPConvert');
$response = curl_exec($ch);
// echo $response;
if (curl_errno($ch)) {
throw new \Exception(curl_error($ch));
}
curl_close($ch);
// Possible responses:
// “great” = verification successful
// “exceeded” = indicates a valid key with no remaining image credits.
// an empty response indicates that the key is not valid
if ($response == '') {
return 'invalid';
}
$responseObj = json_decode($response);
if (isset($responseObj->error)) {
if ($responseObj->error == 'invalid') {
return 'invalid';
} else {
if ($responseObj->error == 'bye invalid') {
return 'invalid';
} else {
throw new \Exception('Ewww returned unexpected error: ' . $response);
}
}
}
if (!isset($responseObj->status)) {
throw new \Exception('Ewww returned unexpected response to verify request: ' . $response);
}
switch ($responseObj->status) {
case 'great':
case 'exceeded':
return $responseObj->status;
}
throw new \Exception('Ewww returned unexpected status to verify request: "' . $responseObj->status . '"');
}
public static function isWorkingKey($key)
{
return (self::getKeyStatus($key) == 'great');
}
public static function isValidKey($key)
{
return (self::getKeyStatus($key) != 'invalid');
}
public static function getQuota($key)
{
$ch = self::initCurl();
curl_setopt($ch, CURLOPT_URL, "https://optimize.exactlywww.com/quota/");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, [
'api_key' => $key
]);
curl_setopt($ch, CURLOPT_USERAGENT, 'WebPConvert');
$response = curl_exec($ch);
return $response; // ie -830 23. Seems to return empty for invalid keys
// or empty
//echo $response;
}
}