PluginProbe ʕ •ᴥ•ʔ
TinyPNG – JPEG, PNG & WebP image compression / 2.2.0
TinyPNG – JPEG, PNG & WebP image compression v2.2.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
config 9 years ago css 9 years ago data 9 years ago images 9 years ago js 9 years ago vendor 9 years ago views 9 years ago class-tiny-compress-client.php 9 years ago class-tiny-compress-fopen.php 9 years ago class-tiny-compress.php 9 years ago class-tiny-exception.php 9 years ago class-tiny-image-size.php 9 years ago class-tiny-image.php 9 years ago class-tiny-notices.php 9 years ago class-tiny-php.php 9 years ago class-tiny-plugin.php 9 years ago class-tiny-settings.php 9 years ago class-tiny-wp-base.php 9 years ago
class-tiny-compress-fopen.php
253 lines
1 <?php
2 /*
3 * Tiny Compress Images - WordPress plugin.
4 * Copyright (C) 2015-2017 Voormedia 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 $api_key;
25
26 protected static function identifier() {
27 parent::identifier() . ' fopen';
28 }
29
30 protected function __construct( $api_key, $after_compress_callback ) {
31 parent::__construct( $after_compress_callback );
32
33 $this->api_key = $api_key;
34 }
35
36 public function can_create_key() {
37 return false;
38 }
39
40 public function get_compression_count() {
41 return $this->compression_count;
42 }
43
44 public function get_key() {
45 return $this->api_key;
46 }
47
48 public function limit_reached() {
49 return 429 == $this->last_error_code;
50 }
51
52 protected function validate() {
53 $params = $this->request_options( 'POST' );
54 list($details, $headers, $status_code) = $this->request( $params );
55
56 if ( 429 == $status_code || 400 == $status_code ) {
57 return true;
58 } elseif ( is_array( $details ) && isset( $details['error'] ) ) {
59 throw new Tiny_Exception(
60 $details['message'],
61 'Tinify\Exception',
62 $status_code
63 );
64 } else {
65 throw new Tiny_Exception(
66 'Unexpected error during validation',
67 'Tinify\Exception',
68 $status_code
69 );
70 }
71 }
72
73 protected function compress( $input, $resize_opts, $preserve_opts ) {
74 $params = $this->request_options( 'POST', $input );
75 list($details, $headers, $status_code) = $this->request( $params );
76
77 $output_url = isset( $headers['location'] ) ? $headers['location'] : null;
78 if ( $status_code >= 400 && is_array( $details ) && isset( $details['error'] ) ) {
79 throw new Tiny_Exception(
80 $details['message'],
81 'Tinify\Exception',
82 $status_code
83 );
84 } elseif ( $status_code >= 400 ) {
85 throw new Tiny_Exception(
86 'Unexpected error during compression',
87 'Tinify\Exception',
88 $status_code
89 );
90 } elseif ( null === $output_url ) {
91 throw new Tiny_Exception(
92 'Could not find output location',
93 'Tinify\Exception'
94 );
95 }
96
97 $params = $this->output_request_options( $resize_opts, $preserve_opts );
98 list($output, $headers, $status_code) = $this->request( $params, $output_url );
99
100 if ( $status_code >= 400 && is_array( $output ) && isset( $output['error'] ) ) {
101 throw new Tiny_Exception(
102 $output['message'],
103 'Tinify\Exception',
104 $status_code
105 );
106 } elseif ( $status_code >= 400 ) {
107 throw new Tiny_Exception(
108 'Unexpected error during output retrieval',
109 'Tinify\Exception',
110 $status_code
111 );
112 }
113
114 if ( is_string( $output ) && 0 == strlen( $output ) ) {
115 throw new Tiny_Exception(
116 'Could not download output',
117 'Tinify\Exception'
118 );
119 }
120
121 $meta = array(
122 'input' => array(
123 'size' => strlen( $input ),
124 'type' => $headers['content-type'],
125 ),
126 'output' => array(
127 'size' => strlen( $output ),
128 'type' => $headers['content-type'],
129 'width' => intval( $headers['image-width'] ),
130 'height' => intval( $headers['image-height'] ),
131 'ratio' => round( strlen( $output ) / strlen( $input ), 4 ),
132 ),
133 );
134
135 return array( $output, $meta );
136 }
137
138 private function request( $params, $url = Tiny_Config::URL ) {
139 $context = stream_context_create( $params );
140 $request = fopen( $url, 'rb', false, $context );
141
142 if ( ! $request ) {
143 throw new Tiny_Exception(
144 'Could not execute request, enable cURL for detailed errors',
145 'Tinify\FopenError'
146 );
147 }
148
149 $meta_data = stream_get_meta_data( $request );
150 $headers = $meta_data['wrapper_data'];
151 if ( ! is_array( $headers ) ) {
152 $headers = iterator_to_array( $headers );
153 }
154
155 $status_code = $this->parse_status_code( $headers );
156 $headers = $this->parse_headers( $headers );
157
158 if ( isset( $headers['compression-count'] ) ) {
159 $this->compression_count = intval( $headers['compression-count'] );
160 }
161
162 $this->last_error_code = $status_code;
163
164 $response = stream_get_contents( $request );
165 fclose( $request );
166
167 if ( isset( $headers['content-type'] ) &&
168 substr( 'application/json' == $headers['content-type'], 0, 16 ) ) {
169 $response = $this->decode( $response );
170 }
171
172 return array( $response, $headers, $status_code );
173 }
174
175 private function parse_status_code( $headers ) {
176 if ( $headers && count( $headers ) > 0 ) {
177 $http_code_values = explode( ' ', $headers[0] );
178 if ( count( $http_code_values ) > 1 ) {
179 return intval( $http_code_values[1] );
180 }
181 }
182 return null;
183 }
184
185 private function parse_headers( $headers ) {
186 $res = array();
187 foreach ( $headers as $header ) {
188 $split = explode( ':', $header, 2 );
189 if ( 2 === count( $split ) ) {
190 $res[ strtolower( $split[0] ) ] = trim( $split[1] );
191 }
192 }
193 return $res;
194 }
195
196 private function request_options( $method, $body = null, $content_type = 'image/png' ) {
197 return array(
198 'http' => array(
199 'method' => $method,
200 'header' => array(
201 'Content-type: ' . $content_type,
202 'Authorization: Basic ' . base64_encode( 'api:' . $this->api_key ),
203 'User-Agent: ' . self::identifier(),
204 ),
205 'content' => $body,
206 'follow_location' => 0,
207 'max_redirects' => 1, // Necessary for PHP 5.2
208 'ignore_errors' => true, // Apparently, a 201 is a failure
209 ),
210 'ssl' => array(
211 'cafile' => $this->get_ca_file(),
212 'verify_peer' => true,
213 ),
214 );
215 }
216
217 private function output_request_options( $resize_opts, $preserve_opts ) {
218 $body = array();
219
220 if ( $preserve_opts ) {
221 $body['preserve'] = $preserve_opts;
222 }
223
224 if ( $resize_opts ) {
225 $body['resize'] = $resize_opts;
226 }
227
228 if ( $resize_opts || $preserve_opts ) {
229 return $this->request_options( 'GET', json_encode( $body ), 'application/json' );
230 } else {
231 return $this->request_options( 'GET', null );
232 }
233 }
234
235 private static function get_ca_file() {
236 return dirname( __FILE__ ) . '/data/cacert.pem';
237 }
238
239 private static function decode( $text ) {
240 $result = json_decode( $text, true );
241 if ( null === $result ) {
242 $message = sprintf(
243 'JSON: %s [%d]',
244 (PHP_VERSION_ID >= 50500 ? json_last_error_msg() : 'Unknown error'),
245 (PHP_VERSION_ID >= 50300 ? json_last_error() : 'Error')
246 );
247
248 throw new Tiny_Exception( $message, 'JsonError' );
249 }
250 return $result;
251 }
252 }
253