Passed
Push — master ( 1ada49...6f88dc )
by Bjørn
02:29
created

Ewww::getOptionDefinitionsExtra()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace WebPConvert\Convert\Converters;
4
5
use WebPConvert\Convert\ConvertOptionDefinition;
0 ignored issues
show
Bug introduced by
The type WebPConvert\Convert\ConvertOptionDefinition was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
6
use WebPConvert\Convert\BaseConverters\AbstractCloudCurlConverter;
7
use WebPConvert\Convert\Exceptions\ConversionFailedException;
8
use WebPConvert\Convert\Exceptions\ConversionFailed\ConverterNotOperationalException;
9
use WebPConvert\Convert\Exceptions\ConversionFailed\ConverterNotOperational\SystemRequirementsNotMetException;
10
11
class Ewww extends AbstractCloudCurlConverter
12
{
13
    protected function getOptionDefinitionsExtra()
14
    {
15
        return [
16
            ['key', 'string', '', true, true]
17
        ];
18
    }
19
20
    /**
21
     * Check operationality of Ewww converter.
22
     *
23
     * @throws SystemRequirementsNotMetException  if system requirements are not met (curl)
24
     * @throws ConverterNotOperationalException   if key is missing or invalid, or quota has exceeded
25
     */
26
    protected function checkOperationality()
27
    {
28
        // First check for curl requirements
29
        parent::checkOperationality();
30
31
        $options = $this->options;
32
33
        if ($options['key'] == '') {
34
            throw new ConverterNotOperationalException('Missing API key.');
35
        }
36
        if (strlen($options['key']) < 20) {
37
            throw new ConverterNotOperationalException(
38
                'Key is invalid. Keys are supposed to be 32 characters long - your key is much shorter'
39
            );
40
        }
41
42
        $keyStatus = self::getKeyStatus($options['key']);
43
        switch ($keyStatus) {
44
            case 'great':
45
                break;
46
            case 'exceeded':
47
                throw new ConverterNotOperationalException('quota has exceeded');
48
                break;
49
            case 'invalid':
50
                throw new ConverterNotOperationalException('key is invalid');
51
                break;
52
        }
53
    }
54
55
    // Although this method is public, do not call directly.
56
    // You should rather call the static convert() function, defined in AbstractConverter, which
57
    // takes care of preparing stuff before calling doConvert, and validating after.
58
    protected function doActualConvert()
59
    {
60
61
        $options = $this->options;
62
63
        $ch = self::initCurl();
64
65
        $curlOptions = [
66
            'api_key' => $options['key'],
67
            'webp' => '1',
68
            'file' => curl_file_create($this->source),
69
            'domain' => $_SERVER['HTTP_HOST'],
70
            'quality' => $this->getCalculatedQuality(),
71
            'metadata' => ($options['metadata'] == 'none' ? '0' : '1')
72
        ];
73
74
        curl_setopt_array(
75
            $ch,
76
            [
77
            CURLOPT_URL => "https://optimize.exactlywww.com/v2/",
78
            CURLOPT_HTTPHEADER => [
79
                'User-Agent: WebPConvert',
80
                'Accept: image/*'
81
            ],
82
            CURLOPT_POSTFIELDS => $curlOptions,
83
            CURLOPT_BINARYTRANSFER => true,
84
            CURLOPT_RETURNTRANSFER => true,
85
            CURLOPT_HEADER => false,
86
            CURLOPT_SSL_VERIFYPEER => false
87
            ]
88
        );
89
90
        $response = curl_exec($ch);
91
92
        if (curl_errno($ch)) {
93
            throw new ConversionFailedException(curl_error($ch));
94
        }
95
96
        // The API does not always return images.
97
        // For example, it may return a message such as '{"error":"invalid","t":"exceeded"}
98
        // Messages has a http content type of ie 'text/html; charset=UTF-8
99
        // Images has application/octet-stream.
100
        // So verify that we got an image back.
101
        if (curl_getinfo($ch, CURLINFO_CONTENT_TYPE) != 'application/octet-stream') {
102
            //echo curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
103
            curl_close($ch);
104
105
            /* May return this: {"error":"invalid","t":"exceeded"} */
106
            $responseObj = json_decode($response);
107
            if (isset($responseObj->error)) {
108
                //echo 'error:' . $responseObj->error . '<br>';
109
                //echo $response;
110
                //self::blacklistKey($key);
111
                //throw new SystemRequirementsNotMetException('The key is invalid. Blacklisted it!');
112
                throw new ConverterNotOperationalException('The key is invalid');
113
            }
114
115
            throw new ConversionFailedException(
116
                'ewww api did not return an image. It could be that the key is invalid. Response: '
117
                . $response
118
            );
119
        }
120
121
        // Not sure this can happen. So just in case
122
        if ($response == '') {
123
            throw new ConversionFailedException('ewww api did not return anything');
124
        }
125
126
        $success = file_put_contents($this->destination, $response);
127
128
        if (!$success) {
129
            throw new ConversionFailedException('Error saving file');
130
        }
131
    }
132
133
    /**
134
     *  Keep subscription alive by optimizing a jpeg
135
     *  (ewww closes accounts after 6 months of inactivity - and webp conversions seems not to be counted? )
136
     */
137
    public static function keepSubscriptionAlive($source, $key)
138
    {
139
        try {
140
            $ch = curl_init();
141
        } catch (\Exception $e) {
142
            return 'curl is not installed';
143
        }
144
        if ($ch === false) {
145
            return 'curl could not be initialized';
146
        }
147
        curl_setopt_array(
148
            $ch,
149
            [
150
            CURLOPT_URL => "https://optimize.exactlywww.com/v2/",
151
            CURLOPT_HTTPHEADER => [
152
                'User-Agent: WebPConvert',
153
                'Accept: image/*'
154
            ],
155
            CURLOPT_POSTFIELDS => [
156
                'api_key' => $key,
157
                'webp' => '0',
158
                'file' => curl_file_create($source),
159
                'domain' => $_SERVER['HTTP_HOST'],
160
                'quality' => 60,
161
                'metadata' => 0
162
            ],
163
            CURLOPT_BINARYTRANSFER => true,
164
            CURLOPT_RETURNTRANSFER => true,
165
            CURLOPT_HEADER => false,
166
            CURLOPT_SSL_VERIFYPEER => false
167
            ]
168
        );
169
170
        $response = curl_exec($ch);
171
        if (curl_errno($ch)) {
172
            return 'curl error' . curl_error($ch);
173
        }
174
        if (curl_getinfo($ch, CURLINFO_CONTENT_TYPE) != 'application/octet-stream') {
175
            curl_close($ch);
176
177
            /* May return this: {"error":"invalid","t":"exceeded"} */
178
            $responseObj = json_decode($response);
179
            if (isset($responseObj->error)) {
180
                return 'The key is invalid';
181
            }
182
183
            return 'ewww api did not return an image. It could be that the key is invalid. Response: ' . $response;
184
        }
185
186
        // Not sure this can happen. So just in case
187
        if ($response == '') {
188
            return 'ewww api did not return anything';
189
        }
190
191
        return true;
192
    }
193
194
    /*
195
        public static function blacklistKey($key)
196
        {
197
        }
198
199
        public static function isKeyBlacklisted($key)
200
        {
201
        }*/
202
203
    /**
204
     *  Return "great", "exceeded" or "invalid"
205
     */
206
    public static function getKeyStatus($key)
207
    {
208
        $ch = self::initCurl();
209
210
        curl_setopt($ch, CURLOPT_URL, "https://optimize.exactlywww.com/verify/");
211
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
212
        curl_setopt(
213
            $ch,
214
            CURLOPT_POSTFIELDS,
215
            [
216
            'api_key' => $key
217
            ]
218
        );
219
220
        // The 403 forbidden is avoided with this line.
221
        curl_setopt(
222
            $ch,
223
            CURLOPT_USERAGENT,
224
            'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)'
225
        );
226
227
        $response = curl_exec($ch);
228
        // echo $response;
229
        if (curl_errno($ch)) {
230
            throw new \Exception(curl_error($ch));
231
        }
232
        curl_close($ch);
233
234
        // Possible responses:
235
        // “great” = verification successful
236
        // “exceeded” = indicates a valid key with no remaining image credits.
237
        // an empty response indicates that the key is not valid
238
239
        if ($response == '') {
240
            return 'invalid';
241
        }
242
        $responseObj = json_decode($response);
243
        if (isset($responseObj->error)) {
244
            if ($responseObj->error == 'invalid') {
245
                return 'invalid';
246
            } else {
247
                throw new \Exception('Ewww returned unexpected error: ' . $response);
248
            }
249
        }
250
        if (!isset($responseObj->status)) {
251
            throw new \Exception('Ewww returned unexpected response to verify request: ' . $response);
252
        }
253
        switch ($responseObj->status) {
254
            case 'great':
255
            case 'exceeded':
256
                return $responseObj->status;
257
        }
258
        throw new \Exception('Ewww returned unexpected status to verify request: "' . $responseObj->status . '"');
259
    }
260
261
    public static function isWorkingKey($key)
262
    {
263
        return (self::getKeyStatus($key) == 'great');
264
    }
265
266
    public static function isValidKey($key)
267
    {
268
        return (self::getKeyStatus($key) != 'invalid');
269
    }
270
271
    public static function getQuota($key)
272
    {
273
        $ch = self::initCurl();
274
275
        curl_setopt($ch, CURLOPT_URL, "https://optimize.exactlywww.com/quota/");
276
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
277
        curl_setopt(
278
            $ch,
279
            CURLOPT_POSTFIELDS,
280
            [
281
            'api_key' => $key
282
            ]
283
        );
284
        curl_setopt(
285
            $ch,
286
            CURLOPT_USERAGENT,
287
            'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)'
288
        );
289
290
        $response = curl_exec($ch);
291
        return $response; // ie -830 23. Seems to return empty for invalid keys
292
        // or empty
293
        //echo $response;
294
    }
295
}
296