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