PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / 3.3.0
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance v3.3.0
4.7.0 4.6.1 4.6.0 4.5.5 4.5.4 4.5.3 4.5.2 3.2.20 3.2.21 3.2.22 3.2.3 3.2.5 3.2.6 3.2.7 3.2.9 3.3.0 3.3.1 3.3.2 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.7.0 3.7.1 All 111 releases
wp-optimize / vendor / rosell-dk / webp-convert / src / Convert / Converters / Ewww.php

Ewww.php in WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance 3.3.0, at vendor/rosell-dk/webp-convert/src/Convert/Converters/Ewww.php

394 lines 13.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace WebPConvert\Convert\Converters;
4
5 use WebPConvert\Convert\Converters\AbstractConverter;
6 use WebPConvert\Convert\Converters\ConverterTraits\CloudConverterTrait;
7 use WebPConvert\Convert\Converters\ConverterTraits\CurlTrait;
8 use WebPConvert\Convert\Exceptions\ConversionFailedException;
9 use WebPConvert\Convert\Exceptions\ConversionFailed\ConverterNotOperationalException;
10 use WebPConvert\Convert\Exceptions\ConversionFailed\ConverterNotOperational\InvalidApiKeyException;
11 use WebPConvert\Convert\Exceptions\ConversionFailed\ConverterNotOperational\SystemRequirementsNotMetException;
12 use WebPConvert\Options\BooleanOption;
13 use WebPConvert\Options\SensitiveStringOption;
14 use WebPConvert\Options\OptionFactory;
15
16 /**
17 * Convert images to webp using ewww cloud service.
18 *
19 * @package WebPConvert
20 * @author Bjørn Rosell <[email protected]>
21 * @since Class available since Release 2.0.0
22 */
23 class Ewww extends AbstractConverter
24 {
25 use CloudConverterTrait;
26 use CurlTrait;
27
28 /** @var array|null Array of invalid or exceeded api keys discovered during conversions (during the request) */
29 public static $nonFunctionalApiKeysDiscoveredDuringConversion;
30
31 public function getUniqueOptions($imageType)
32 {
33 return OptionFactory::createOptions([
34 ['api-key', 'string', [
35 'title' => 'Ewww API key',
36 'description' => 'ewww API key. ' .
37 'If you choose "auto", webp-convert will ' .
38 'convert to both lossy and lossless and pick the smallest result',
39 'default' => '',
40 'sensitive' => true,
41 'ui' => [
42 'component' => 'password',
43 ]
44 ]],
45 ['check-key-status-before-converting', 'boolean', [
46 'title' => 'Check key status before converting',
47 'description' =>
48 'If enabled, the api key will be validated (relative inexpensive) before trying ' .
49 'to convert. For automatic conversions, you should enable it. Otherwise you run the ' .
50 'risk that the same files will be uploaded to ewww cloud service over and over again, ' .
51 'in case the key has expired. For manually triggered conversions, you can safely disable ' .
52 'the option.',
53 'default' => true,
54 'ui' => [
55 'component' => 'checkbox',
56 ]
57 ]],
58 ]);
59 }
60
61 protected function getUnsupportedDefaultOptions()
62 {
63 return [
64 'alpha-quality',
65 'auto-filter',
66 'encoding',
67 'low-memory',
68 'method',
69 'near-lossless',
70 'preset',
71 'sharp-yuv',
72 'size-in-percentage',
73 ];
74 }
75
76 /**
77 * Get api key from options or environment variable
78 *
79 * @return string|false api key or false if none is set
80 */
81 private function getKey()
82 {
83 if (!empty($this->options['api-key'])) {
84 return $this->options['api-key'];
85 }
86 if (defined('WEBPCONVERT_EWWW_API_KEY')) {
87 return constant('WEBPCONVERT_EWWW_API_KEY');
88 }
89 if (!empty(getenv('WEBPCONVERT_EWWW_API_KEY'))) {
90 return getenv('WEBPCONVERT_EWWW_API_KEY');
91 }
92 return false;
93 }
94
95
96 /**
97 * Check operationality of Ewww converter.
98 *
99 * @throws SystemRequirementsNotMetException if system requirements are not met (curl)
100 * @throws ConverterNotOperationalException if key is missing or invalid, or quota has exceeded
101 */
102 public function checkOperationality()
103 {
104
105 $apiKey = $this->getKey();
106
107 if ($apiKey === false) {
108 if (isset($this->options['key'])) {
109 throw new InvalidApiKeyException(
110 'The "key" option has been renamed to "api-key" in webp-convert 2.0. ' .
111 'You must change the configuration accordingly.'
112 );
113 }
114
115 throw new InvalidApiKeyException('Missing API key.');
116 }
117
118 if (strlen($apiKey) < 20) {
119 throw new InvalidApiKeyException(
120 'Api key is invalid. Api keys are supposed to be 32 characters long - ' .
121 'the provided api key is much shorter'
122 );
123 }
124
125 // Check for curl requirements
126 $this->checkOperationalityForCurlTrait();
127
128 if ($this->options['check-key-status-before-converting']) {
129 $keyStatus = self::getKeyStatus($apiKey);
130 switch ($keyStatus) {
131 case 'great':
132 break;
133 case 'exceeded':
134 throw new ConverterNotOperationalException('Quota has exceeded');
135 //break;
136 case 'invalid':
137 throw new InvalidApiKeyException('Api key is invalid');
138 //break;
139 }
140 }
141 }
142
143 /*
144 public function checkConvertability()
145 {
146 // check upload limits
147 $this->checkConvertabilityCloudConverterTrait();
148 }
149 */
150
151 // Although this method is public, do not call directly.
152 // You should rather call the static convert() function, defined in AbstractConverter, which
153 // takes care of preparing stuff before calling doConvert, and validating after.
154 protected function doActualConvert()
155 {
156
157 $options = $this->options;
158
159 $ch = self::initCurl();
160
161 //$this->logLn('api key:' . $this->getKey());
162
163 $postData = [
164 'api_key' => $this->getKey(),
165 'webp' => '1',
166 'file' => curl_file_create($this->source),
167 'quality' => $this->getCalculatedQuality(),
168 'metadata' => ($options['metadata'] == 'none' ? '0' : '1')
169 ];
170
171 curl_setopt_array(
172 $ch,
173 [
174 CURLOPT_URL => "https://optimize.exactlywww.com/v2/",
175 CURLOPT_HTTPHEADER => [
176 'User-Agent: WebPConvert',
177 'Accept: image/*'
178 ],
179 CURLOPT_POSTFIELDS => $postData,
180 CURLOPT_BINARYTRANSFER => true,
181 CURLOPT_RETURNTRANSFER => true,
182 CURLOPT_HEADER => false,
183 CURLOPT_SSL_VERIFYPEER => false
184 ]
185 );
186
187 $response = curl_exec($ch);
188
189 if (curl_errno($ch)) {
190 throw new ConversionFailedException(curl_error($ch));
191 }
192
193 // The API does not always return images.
194 // For example, it may return a message such as '{"error":"invalid","t":"exceeded"}
195 // Messages has a http content type of ie 'text/html; charset=UTF-8
196 // Images has application/octet-stream.
197 // So verify that we got an image back.
198 if (curl_getinfo($ch, CURLINFO_CONTENT_TYPE) != 'application/octet-stream') {
199 //echo curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
200 curl_close($ch);
201
202 /*
203 For bogus or expired key it returns: {"error":"invalid","t":"exceeded"}
204 For exceeded key it returns: {"error":"exceeded"}
205 */
206 $responseObj = json_decode($response);
207 if (isset($responseObj->error)) {
208 $this->logLn('We received the following error response: ' . $responseObj->error);
209 $this->logLn('Complete response: ' . json_encode($responseObj));
210
211 // Store the invalid key in array so it can be received once the Stack is completed
212 // (even when stack succeeds)
213 if (!isset(self::$nonFunctionalApiKeysDiscoveredDuringConversion)) {
214 self::$nonFunctionalApiKeysDiscoveredDuringConversion = [];
215 }
216 if (!in_array($options['api-key'], self::$nonFunctionalApiKeysDiscoveredDuringConversion)) {
217 self::$nonFunctionalApiKeysDiscoveredDuringConversion[] = $options['api-key'];
218 }
219 if ($responseObj->error == "invalid") {
220 throw new InvalidApiKeyException('The api key is invalid (or expired)');
221 } else {
222 throw new InvalidApiKeyException('The quota is exceeded for the api-key');
223 }
224 }
225
226 throw new ConversionFailedException(
227 'ewww api did not return an image. It could be that the key is invalid. Response: '
228 . $response
229 );
230 }
231
232 // Not sure this can happen. So just in case
233 if ($response == '') {
234 throw new ConversionFailedException('ewww api did not return anything');
235 }
236
237 $success = file_put_contents($this->destination, $response);
238
239 if (!$success) {
240 throw new ConversionFailedException('Error saving file');
241 }
242 }
243
244 /**
245 * Keep subscription alive by optimizing a jpeg
246 * (ewww closes accounts after 6 months of inactivity - and webp conversions seems not to be counted? )
247 */
248 public static function keepSubscriptionAlive($source, $key)
249 {
250 try {
251 $ch = curl_init();
252 } catch (\Exception $e) {
253 return 'curl is not installed';
254 }
255 if ($ch === false) {
256 return 'curl could not be initialized';
257 }
258 curl_setopt_array(
259 $ch,
260 [
261 CURLOPT_URL => "https://optimize.exactlywww.com/v2/",
262 CURLOPT_HTTPHEADER => [
263 'User-Agent: WebPConvert',
264 'Accept: image/*'
265 ],
266 CURLOPT_POSTFIELDS => [
267 'api_key' => $key,
268 'webp' => '0',
269 'file' => curl_file_create($source),
270 'domain' => $_SERVER['HTTP_HOST'],
271 'quality' => 60,
272 'metadata' => 0
273 ],
274 CURLOPT_BINARYTRANSFER => true,
275 CURLOPT_RETURNTRANSFER => true,
276 CURLOPT_HEADER => false,
277 CURLOPT_SSL_VERIFYPEER => false
278 ]
279 );
280
281 $response = curl_exec($ch);
282 if (curl_errno($ch)) {
283 return 'curl error' . curl_error($ch);
284 }
285 if (curl_getinfo($ch, CURLINFO_CONTENT_TYPE) != 'application/octet-stream') {
286 curl_close($ch);
287
288 /* May return this: {"error":"invalid","t":"exceeded"} */
289 $responseObj = json_decode($response);
290 if (isset($responseObj->error)) {
291 return 'The key is invalid';
292 }
293
294 return 'ewww api did not return an image. It could be that the key is invalid. Response: ' . $response;
295 }
296
297 // Not sure this can happen. So just in case
298 if ($response == '') {
299 return 'ewww api did not return anything';
300 }
301
302 return true;
303 }
304
305 /*
306 public static function blacklistKey($key)
307 {
308 }
309
310 public static function isKeyBlacklisted($key)
311 {
312 }*/
313
314 /**
315 * Return "great", "exceeded" or "invalid"
316 */
317 public static function getKeyStatus($key)
318 {
319 $ch = self::initCurl();
320
321 curl_setopt($ch, CURLOPT_URL, "https://optimize.exactlywww.com/verify/");
322 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
323 curl_setopt($ch, CURLOPT_POSTFIELDS, [
324 'api_key' => $key
325 ]);
326
327 curl_setopt($ch, CURLOPT_USERAGENT, 'WebPConvert');
328
329 $response = curl_exec($ch);
330 // echo $response;
331 if (curl_errno($ch)) {
332 throw new \Exception(curl_error($ch));
333 }
334 curl_close($ch);
335
336 // Possible responses:
337 // “great” = verification successful
338 // “exceeded” = indicates a valid key with no remaining image credits.
339 // an empty response indicates that the key is not valid
340
341 if ($response == '') {
342 return 'invalid';
343 }
344 $responseObj = json_decode($response);
345 if (isset($responseObj->error)) {
346 if ($responseObj->error == 'invalid') {
347 return 'invalid';
348 } else {
349 if ($responseObj->error == 'bye invalid') {
350 return 'invalid';
351 } else {
352 throw new \Exception('Ewww returned unexpected error: ' . $response);
353 }
354 }
355 }
356 if (!isset($responseObj->status)) {
357 throw new \Exception('Ewww returned unexpected response to verify request: ' . $response);
358 }
359 switch ($responseObj->status) {
360 case 'great':
361 case 'exceeded':
362 return $responseObj->status;
363 }
364 throw new \Exception('Ewww returned unexpected status to verify request: "' . $responseObj->status . '"');
365 }
366
367 public static function isWorkingKey($key)
368 {
369 return (self::getKeyStatus($key) == 'great');
370 }
371
372 public static function isValidKey($key)
373 {
374 return (self::getKeyStatus($key) != 'invalid');
375 }
376
377 public static function getQuota($key)
378 {
379 $ch = self::initCurl();
380
381 curl_setopt($ch, CURLOPT_URL, "https://optimize.exactlywww.com/quota/");
382 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
383 curl_setopt($ch, CURLOPT_POSTFIELDS, [
384 'api_key' => $key
385 ]);
386 curl_setopt($ch, CURLOPT_USERAGENT, 'WebPConvert');
387
388 $response = curl_exec($ch);
389 return $response; // ie -830 23. Seems to return empty for invalid keys
390 // or empty
391 //echo $response;
392 }
393 }
394