PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / 4.7.0
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance v4.7.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 / mrclay / minify / lib / HTTP / Encoder.php

Encoder.php in WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance 4.7.0, at vendor/mrclay/minify/lib/HTTP/Encoder.php

340 lines 10.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Class HTTP_Encoder
4 * @package Minify
5 * @subpackage HTTP
6 */
7
8 /**
9 * Encode and send gzipped/deflated content
10 *
11 * The "Vary: Accept-Encoding" header is sent. If the client allows encoding,
12 * Content-Encoding and Content-Length are added.
13 *
14 * <code>
15 * // Send a CSS file, compressed if possible
16 * $he = new HTTP_Encoder(array(
17 * 'content' => file_get_contents($cssFile)
18 * ,'type' => 'text/css'
19 * ));
20 * $he->encode();
21 * $he->sendAll();
22 * </code>
23 *
24 * <code>
25 * // Shortcut to encoding output
26 * header('Content-Type: text/css'); // needed if not HTML
27 * HTTP_Encoder::output($css);
28 * </code>
29 *
30 * <code>
31 * // Just sniff for the accepted encoding
32 * $encoding = HTTP_Encoder::getAcceptedEncoding();
33 * </code>
34 *
35 * For more control over headers, use getHeaders() and getData() and send your
36 * own output.
37 *
38 * Note: If you don't need header mgmt, use PHP's native gzencode, gzdeflate,
39 * and gzcompress functions for gzip, deflate, and compress-encoding
40 * respectively.
41 *
42 * @package Minify
43 * @subpackage HTTP
44 * @author Stephen Clay <[email protected]>
45 */
46 class HTTP_Encoder
47 {
48
49 /**
50 * Should the encoder allow HTTP encoding to IE6?
51 *
52 * If you have many IE6 users and the bandwidth savings is worth troubling
53 * some of them, set this to true.
54 *
55 * By default, encoding is only offered to IE7+. When this is true,
56 * getAcceptedEncoding() will return an encoding for IE6 if its user agent
57 * string contains "SV1". This has been documented in many places as "safe",
58 * but there seem to be remaining, intermittent encoding bugs in patched
59 * IE6 on the wild web.
60 *
61 * @var bool
62 */
63 public static $encodeToIe6 = true;
64
65 /**
66 * Default compression level for zlib operations
67 *
68 * This level is used if encode() is not given a $compressionLevel
69 *
70 * @var int
71 */
72 public static $compressionLevel = 6;
73
74 /**
75 * Get an HTTP Encoder object
76 *
77 * @param array $spec options
78 *
79 * 'content': (string required) content to be encoded
80 *
81 * 'type': (string) if set, the Content-Type header will have this value.
82 *
83 * 'method: (string) only set this if you are forcing a particular encoding
84 * method. If not set, the best method will be chosen by getAcceptedEncoding()
85 * The available methods are 'gzip', 'deflate', 'compress', and '' (no
86 * encoding)
87 */
88 public function __construct($spec)
89 {
90 $this->_useMbStrlen = (function_exists('mb_strlen')
91 && (ini_get('mbstring.func_overload') !== '')
92 && ((int)ini_get('mbstring.func_overload') & 2));
93 $this->_content = $spec['content'];
94 $this->_headers['Content-Length'] = $this->_useMbStrlen
95 ? (string)mb_strlen($this->_content, '8bit')
96 : (string)strlen($this->_content);
97 if (isset($spec['type'])) {
98 $this->_headers['Content-Type'] = $spec['type'];
99 }
100 if (isset($spec['method'])
101 && in_array($spec['method'], array('gzip', 'deflate', 'compress', ''))) {
102 $this->_encodeMethod = array($spec['method'], $spec['method']);
103 } else {
104 $this->_encodeMethod = self::getAcceptedEncoding();
105 }
106 }
107
108 /**
109 * Get content in current form
110 *
111 * Call after encode() for encoded content.
112 *
113 * @return string
114 */
115 public function getContent()
116 {
117 return $this->_content;
118 }
119
120 /**
121 * Get array of output headers to be sent
122 *
123 * E.g.
124 * <code>
125 * array(
126 * 'Content-Length' => '615'
127 * ,'Content-Encoding' => 'x-gzip'
128 * ,'Vary' => 'Accept-Encoding'
129 * )
130 * </code>
131 *
132 * @return array
133 */
134 public function getHeaders()
135 {
136 return $this->_headers;
137 }
138
139 /**
140 * Send output headers
141 *
142 * You must call this before headers are sent and it probably cannot be
143 * used in conjunction with zlib output buffering / mod_gzip. Errors are
144 * not handled purposefully.
145 *
146 * @see getHeaders()
147 */
148 public function sendHeaders()
149 {
150 foreach ($this->_headers as $name => $val) {
151 header($name . ': ' . $val);
152 }
153 }
154
155 /**
156 * Send output headers and content
157 *
158 * A shortcut for sendHeaders() and echo getContent()
159 *
160 * You must call this before headers are sent and it probably cannot be
161 * used in conjunction with zlib output buffering / mod_gzip. Errors are
162 * not handled purposefully.
163 */
164 public function sendAll()
165 {
166 $this->sendHeaders();
167 echo $this->_content;
168 }
169
170 /**
171 * Determine the client's best encoding method from the HTTP Accept-Encoding
172 * header.
173 *
174 * If no Accept-Encoding header is set, or the browser is IE before v6 SP2,
175 * this will return ('', ''), the "identity" encoding.
176 *
177 * A syntax-aware scan is done of the Accept-Encoding, so the method must
178 * be non 0. The methods are favored in order of gzip, deflate, then
179 * compress. Deflate is always smallest and generally faster, but is
180 * rarely sent by servers, so client support could be buggier.
181 *
182 * @param bool $allowCompress allow the older compress encoding
183 *
184 * @param bool $allowDeflate allow the more recent deflate encoding
185 *
186 * @return array two values, 1st is the actual encoding method, 2nd is the
187 * alias of that method to use in the Content-Encoding header (some browsers
188 * call gzip "x-gzip" etc.)
189 */
190 public static function getAcceptedEncoding($allowCompress = true, $allowDeflate = true)
191 {
192 // @link http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
193
194 if (! isset($_SERVER['HTTP_ACCEPT_ENCODING'])
195 || self::isBuggyIe()) {
196 return array('', '');
197 }
198 $ae = $_SERVER['HTTP_ACCEPT_ENCODING'];
199 // gzip checks (quick)
200 if (0 === strpos($ae, 'gzip,') // most browsers
201 || 0 === strpos($ae, 'deflate, gzip,') // opera
202 ) {
203 return array('gzip', 'gzip');
204 }
205 // gzip checks (slow)
206 if (preg_match(
207 '@(?:^|,)\\s*((?:x-)?gzip)\\s*(?:$|,|;\\s*q=(?:0\\.|1))@',
208 $ae,
209 $m
210 )) {
211 return array('gzip', $m[1]);
212 }
213 if ($allowDeflate) {
214 // deflate checks
215 $aeRev = strrev($ae);
216 if (0 === strpos($aeRev, 'etalfed ,') // ie, webkit
217 || 0 === strpos($aeRev, 'etalfed,') // gecko
218 || 0 === strpos($ae, 'deflate,') // opera
219 // slow parsing
220 || preg_match(
221 '@(?:^|,)\\s*deflate\\s*(?:$|,|;\\s*q=(?:0\\.|1))@',
222 $ae
223 )) {
224 return array('deflate', 'deflate');
225 }
226 }
227 if ($allowCompress && preg_match(
228 '@(?:^|,)\\s*((?:x-)?compress)\\s*(?:$|,|;\\s*q=(?:0\\.|1))@',
229 $ae,
230 $m
231 )) {
232 return array('compress', $m[1]);
233 }
234
235 return array('', '');
236 }
237
238 /**
239 * Encode (compress) the content
240 *
241 * If the encode method is '' (none) or compression level is 0, or the 'zlib'
242 * extension isn't loaded, we return false.
243 *
244 * Then the appropriate gz_* function is called to compress the content. If
245 * this fails, false is returned.
246 *
247 * The header "Vary: Accept-Encoding" is added. If encoding is successful,
248 * the Content-Length header is updated, and Content-Encoding is also added.
249 *
250 * @param int $compressionLevel given to zlib functions. If not given, the
251 * class default will be used.
252 *
253 * @return bool success true if the content was actually compressed
254 */
255 public function encode($compressionLevel = null)
256 {
257 if (! self::isBuggyIe()) {
258 $this->_headers['Vary'] = 'Accept-Encoding';
259 }
260 if (null === $compressionLevel) {
261 $compressionLevel = self::$compressionLevel;
262 }
263 if ('' === $this->_encodeMethod[0]
264 || ($compressionLevel == 0)
265 || !extension_loaded('zlib')) {
266 return false;
267 }
268 if ($this->_encodeMethod[0] === 'deflate') {
269 $encoded = gzdeflate($this->_content, $compressionLevel);
270 } elseif ($this->_encodeMethod[0] === 'gzip') {
271 $encoded = gzencode($this->_content, $compressionLevel);
272 } else {
273 $encoded = gzcompress($this->_content, $compressionLevel);
274 }
275 if (false === $encoded) {
276 return false;
277 }
278 $this->_headers['Content-Length'] = $this->_useMbStrlen
279 ? (string)mb_strlen($encoded, '8bit')
280 : (string)strlen($encoded);
281 $this->_headers['Content-Encoding'] = $this->_encodeMethod[1];
282 $this->_content = $encoded;
283
284 return true;
285 }
286
287 /**
288 * Encode and send appropriate headers and content
289 *
290 * This is a convenience method for common use of the class
291 *
292 * @param string $content
293 *
294 * @param int $compressionLevel given to zlib functions. If not given, the
295 * class default will be used.
296 *
297 * @return bool success true if the content was actually compressed
298 */
299 public static function output($content, $compressionLevel = null)
300 {
301 if (null === $compressionLevel) {
302 $compressionLevel = self::$compressionLevel;
303 }
304 $he = new HTTP_Encoder(array('content' => $content));
305 $ret = $he->encode($compressionLevel);
306 $he->sendAll();
307
308 return $ret;
309 }
310
311 /**
312 * Is the browser an IE version earlier than 6 SP2?
313 *
314 * @return bool
315 */
316 public static function isBuggyIe()
317 {
318 if (empty($_SERVER['HTTP_USER_AGENT'])) {
319 return false;
320 }
321 $ua = $_SERVER['HTTP_USER_AGENT'];
322 // quick escape for non-IEs
323 if (0 !== strpos($ua, 'Mozilla/4.0 (compatible; MSIE ')
324 || false !== strpos($ua, 'Opera')) {
325 return false;
326 }
327 // no regex = faaast
328 $version = (float)substr($ua, 30);
329
330 return self::$encodeToIe6
331 ? ($version < 6 || ($version == 6 && false === strpos($ua, 'SV1')))
332 : ($version < 7);
333 }
334
335 protected $_content = '';
336 protected $_headers = array();
337 protected $_encodeMethod = array('', '');
338 protected $_useMbStrlen = false;
339 }
340