PluginProbe ʕ •ᴥ•ʔ
TinyPNG – JPEG, PNG & WebP image compression / 3.8.0
TinyPNG – JPEG, PNG & WebP image compression v3.8.0
3.8.0 3.7.0 3.6.14 trunk 1.0.0 1.1.0 1.2.0 1.2.1 1.3.0 1.3.1 1.3.2 1.4.0 1.5.0 1.6.0 1.7.0 1.7.1 1.7.2 2.0.0 2.0.1 2.0.2 2.1.0 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 3.0.0 3.0.1 3.1.0 3.2.0 3.2.1 3.3 3.4 3.4.1 3.4.2 3.4.4 3.4.5 3.4.6 3.5.0 3.5.1 3.5.2 3.6.0 3.6.1 3.6.10 3.6.11 3.6.12 3.6.13 3.6.2 3.6.3 3.6.4 3.6.5 3.6.6 3.6.7 3.6.8 3.6.9
tiny-compress-images / src / class-tiny-compress-fopen.php
tiny-compress-images / src Last commit date
compatibility 2 months ago config 2 months ago css 7 months ago data 4 years ago images 4 years ago js 1 week ago vendor 6 months ago views 1 week ago class-tiny-apache-rewrite.php 2 months ago class-tiny-bulk-optimization.php 2 months ago class-tiny-cli.php 2 months ago class-tiny-compress-client.php 1 week ago class-tiny-compress-fopen.php 2 months ago class-tiny-compress.php 1 week ago class-tiny-conversion.php 4 months ago class-tiny-diagnostics.php 7 months ago class-tiny-exception.php 7 months ago class-tiny-helpers.php 2 months ago class-tiny-image-size.php 1 week ago class-tiny-image.php 1 week ago class-tiny-logger.php 2 months ago class-tiny-migrate.php 2 months ago class-tiny-notices.php 2 months ago class-tiny-php.php 2 months ago class-tiny-picture.php 2 months ago class-tiny-plugin.php 1 week ago class-tiny-settings.php 1 week ago class-tiny-source-base.php 1 week ago class-tiny-source-image.php 7 months ago class-tiny-source-picture.php 7 months ago class-tiny-wp-base.php 2 months ago
class-tiny-compress-fopen.php
324 lines
1 <?php
2 // phpcs:disable WordPress.Security.EscapeOutput.ExceptionNotEscaped
3 /*
4 * Tiny Compress Images - WordPress plugin.
5 * Copyright (C) 2015-2018 Tinify B.V.
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc., 51
19 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 */
21
22 class Tiny_Compress_Fopen extends Tiny_Compress {
23 private $last_error_code = 0;
24 private $compression_count;
25 private $remaining_credits;
26 private $paying_state;
27 private $email_address;
28 private $api_key;
29
30 protected static function identifier() {
31 return parent::identifier() . ' fopen';
32 }
33
34 protected function __construct( $api_key, $after_compress_callback ) {
35 parent::__construct( $after_compress_callback );
36
37 $this->api_key = $api_key;
38 }
39
40 public function can_create_key() {
41 return false;
42 }
43
44 public function get_compression_count() {
45 return $this->compression_count;
46 }
47
48 public function get_remaining_credits() {
49 return $this->remaining_credits;
50 }
51
52 public function get_paying_state() {
53 return $this->paying_state;
54 }
55
56 public function get_email_address() {
57 return $this->email_address;
58 }
59
60 public function get_key() {
61 return $this->api_key;
62 }
63
64 protected function validate() {
65 $params = $this->request_options( 'GET' );
66 $url = Tiny_Config::KEYS_URL . '/' . $this->get_key();
67 list($details, $headers, $status_code) = $this->request( $params, $url );
68
69 if ( 429 == $status_code || 400 == $status_code || 200 == $status_code ) {
70 return true;
71 } elseif ( is_array( $details ) && isset( $details['error'] ) ) {
72 throw new Tiny_Exception(
73 $details['message'],
74 'Tinify\Exception',
75 $status_code
76 );
77 } else {
78 throw new Tiny_Exception(
79 'Unexpected error during validation',
80 'Tinify\Exception',
81 $status_code
82 );
83 }
84 }
85
86 protected function compress( $input, $resize_opts, $preserve_opts, $convert_to ) {
87 $params = $this->request_options( 'POST', $input );
88 list($details, $headers, $status_code) = $this->request( $params );
89
90 Tiny_Logger::debug(
91 'client fopen compress out',
92 array(
93 'details' => $details,
94 'status' => $status_code,
95 )
96 );
97
98 $output_url = isset( $headers['location'] ) ? $headers['location'] : null;
99 if ( $status_code >= 400 && is_array( $details ) && isset( $details['error'] ) ) {
100 throw new Tiny_Exception(
101 $details['message'],
102 'Tinify\Exception',
103 $status_code
104 );
105 } elseif ( $status_code >= 400 ) {
106 throw new Tiny_Exception(
107 'Unexpected error during compression',
108 'Tinify\Exception',
109 $status_code
110 );
111 } elseif ( null === $output_url ) {
112 throw new Tiny_Exception(
113 'Could not find output location',
114 'Tinify\Exception'
115 );
116 }
117
118 $params = $this->output_request_options(
119 $resize_opts,
120 $preserve_opts
121 );
122 list($output, $headers, $status_code) = $this->request( $params, $output_url );
123
124 if ( $status_code >= 400 && is_array( $output ) && isset( $output['error'] ) ) {
125 throw new Tiny_Exception(
126 $output['message'],
127 'Tinify\Exception',
128 $status_code
129 );
130 } elseif ( $status_code >= 400 ) {
131 throw new Tiny_Exception(
132 'Unexpected error during output retrieval',
133 'Tinify\Exception',
134 $status_code
135 );
136 }
137
138 if ( is_string( $output ) && 0 == strlen( $output ) ) {
139 throw new Tiny_Exception(
140 'Could not download output',
141 'Tinify\Exception'
142 );
143 }
144
145 $meta = array(
146 'input' => array(
147 'size' => strlen( $input ),
148 'type' => Tiny_Helpers::get_mimetype( $input ),
149 ),
150 'output' => array(
151 'size' => strlen( $output ),
152 'type' => $headers['content-type'],
153 'width' => intval( $headers['image-width'] ),
154 'height' => intval( $headers['image-height'] ),
155 'ratio' => round(
156 strlen( $output ) / strlen( $input ),
157 4
158 ),
159 ),
160 );
161
162 $convert = null;
163
164 if ( count( $convert_to ) > 0 ) {
165 $convert_params = $this->request_options(
166 'POST',
167 array(
168 'convert' => array(
169 'type' => $convert_to,
170 ),
171 ),
172 array( 'Content-Type: application/json' )
173 );
174
175 list($convert_output, $convert_headers) = $this->request(
176 $convert_params,
177 $output_url
178 );
179 $meta['convert'] = array(
180 'type' => $convert_headers['content-type'],
181 'size' => strlen( $convert_output ),
182 );
183 $convert = $convert_output;
184
185 }
186
187 $result = array( $output, $meta, $convert );
188
189 return $result;
190 }
191 private function request( $params, $url = Tiny_Config::SHRINK_URL ) {
192 $context = stream_context_create( $params );
193 $request = fopen( $url, 'rb', false, $context );
194
195 if ( ! $request ) {
196 throw new Tiny_Exception(
197 'Could not execute fopen request',
198 'Tinify\FopenError'
199 );
200 }
201
202 $meta_data = stream_get_meta_data( $request );
203 $headers = $meta_data['wrapper_data'];
204 if ( ! is_array( $headers ) ) {
205 $headers = iterator_to_array( $headers );
206 }
207
208 $status_code = $this->parse_status_code( $headers );
209 $headers = $this->parse_headers( $headers );
210
211 if ( isset( $headers['compression-count'] ) ) {
212 $this->compression_count = intval( $headers['compression-count'] );
213 }
214
215 if ( isset( $headers['compression-count-remaining'] ) ) {
216 $this->remaining_credits = intval( $headers['compression-count-remaining'] );
217 }
218
219 if ( isset( $headers['paying-state'] ) ) {
220 $this->paying_state = $headers['paying-state'];
221 }
222
223 if ( isset( $headers['email-address'] ) ) {
224 $this->email_address = $headers['email-address'];
225 }
226
227 $this->last_error_code = $status_code;
228
229 $response = stream_get_contents( $request );
230 fclose( $request );
231
232 if (
233 isset( $headers['content-type'] ) &&
234 substr( 'application/json' == $headers['content-type'], 0, 16 )
235 ) {
236 $response = $this->decode( $response );
237 }
238
239 return array( $response, $headers, $status_code );
240 }
241
242 private function parse_status_code( $headers ) {
243 if ( $headers && count( $headers ) > 0 ) {
244 $http_code_values = explode( ' ', $headers[0] );
245 if ( count( $http_code_values ) > 1 ) {
246 return intval( $http_code_values[1] );
247 }
248 }
249 return null;
250 }
251
252 private function parse_headers( $headers ) {
253 $res = array();
254 foreach ( $headers as $header ) {
255 $split = explode( ':', $header, 2 );
256 if ( 2 === count( $split ) ) {
257 $res[ strtolower( $split[0] ) ] = trim( $split[1] );
258 }
259 }
260 return $res;
261 }
262
263 private function request_options( $method, $body = null, $headers = array() ) {
264 return array(
265 'http' => array(
266 'method' => $method,
267 'header' => array_merge(
268 $headers,
269 array(
270 'Authorization: Basic ' . base64_encode( 'api:' . $this->api_key ), // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode -- Base64 encoding is required.
271 'User-Agent: ' . self::identifier(),
272 'Content-Type: multipart/form-data',
273 )
274 ),
275 'content' => $body,
276 'follow_location' => 0,
277 'max_redirects' => 1, // Necessary for PHP 5.2
278 'ignore_errors' => true, // Apparently, a 201 is a failure
279 ),
280 'ssl' => array(
281 'cafile' => $this->get_ca_file(),
282 'verify_peer' => true,
283 ),
284 );
285 }
286
287 private function output_request_options( $resize_opts, $preserve_opts ) {
288 $body = array();
289
290 if ( $preserve_opts ) {
291 $body['preserve'] = $preserve_opts;
292 }
293
294 if ( $resize_opts ) {
295 $body['resize'] = $resize_opts;
296 }
297
298 if ( $resize_opts || $preserve_opts ) {
299 $headers = array( 'Content-Type: application/json' );
300 return $this->request_options( 'GET', json_encode( $body ), $headers );
301 } else {
302 return $this->request_options( 'GET' );
303 }
304 }
305
306 private static function get_ca_file() {
307 return __DIR__ . '/data/cacert.pem';
308 }
309
310 private static function decode( $text ) {
311 $result = json_decode( $text, true );
312 if ( null === $result ) {
313 $message = sprintf(
314 'JSON: %s [%d]',
315 ( PHP_VERSION_ID >= 50500 ? json_last_error_msg() : 'Unknown error' ),
316 ( PHP_VERSION_ID >= 50300 ? json_last_error() : 'Error' )
317 );
318
319 throw new Tiny_Exception( $message, 'JsonError' );
320 }
321 return $result;
322 }
323 }
324