PageRenderTime 61ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/wp-content/plugins/w3-total-cache/lib/Minify/HTTP/Encoder.php

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