gzipdecode.class.php 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. <?php
  2. /*
  3. * Copyright 2011-2012 Amazon.com, Inc. or its affiliates. All Rights Reserved.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License").
  6. * You may not use this file except in compliance with the License.
  7. * A copy of the License is located at
  8. *
  9. * http://aws.amazon.com/apache2.0
  10. *
  11. * or in the "license" file accompanying this file. This file is distributed
  12. * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
  13. * express or implied. See the License for the specific language governing
  14. * permissions and limitations under the License.
  15. */
  16. /**
  17. * SimplePie
  18. *
  19. * A PHP-Based RSS and Atom Feed Framework.
  20. * Takes the hard work out of managing a complete RSS/Atom solution.
  21. *
  22. * Copyright (c) 2004-2010, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
  23. * All rights reserved.
  24. *
  25. * Redistribution and use in source and binary forms, with or without modification, are
  26. * permitted provided that the following conditions are met:
  27. *
  28. * * Redistributions of source code must retain the above copyright notice, this list of
  29. * conditions and the following disclaimer.
  30. *
  31. * * Redistributions in binary form must reproduce the above copyright notice, this list
  32. * of conditions and the following disclaimer in the documentation and/or other materials
  33. * provided with the distribution.
  34. *
  35. * * Neither the name of the SimplePie Team nor the names of its contributors may be used
  36. * to endorse or promote products derived from this software without specific prior
  37. * written permission.
  38. *
  39. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
  40. * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
  41. * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
  42. * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  43. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  44. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  45. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  46. * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  47. * POSSIBILITY OF SUCH DAMAGE.
  48. *
  49. * @package SimplePie
  50. * @version 1.3-dev
  51. * @copyright 2004-2010 Ryan Parman, Geoffrey Sneddon, Ryan McCue
  52. * @author Ryan Parman
  53. * @author Geoffrey Sneddon
  54. * @author Ryan McCue
  55. * @link http://simplepie.org/ SimplePie
  56. * @license http://www.opensource.org/licenses/bsd-license.php BSD License
  57. * @todo phpDoc comments
  58. */
  59. /*%******************************************************************************************%*/
  60. // CLASS
  61. /**
  62. * Handles a variety of primary and edge cases around gzip/deflate decoding in PHP.
  63. *
  64. * @version 2011.02.21
  65. * @license See the included NOTICE.md file for more information.
  66. * @copyright See the included NOTICE.md file for more information.
  67. * @link http://aws.amazon.com/php/ PHP Developer Center
  68. * @link https://github.com/simplepie/simplepie/blob/master/SimplePie/gzdecode.php SimplePie_gzdecode
  69. */
  70. class CFGzipDecode
  71. {
  72. /**
  73. * Compressed data
  74. *
  75. * @access private
  76. * @see gzdecode::$data
  77. */
  78. public $compressed_data;
  79. /**
  80. * Size of compressed data
  81. *
  82. * @access private
  83. */
  84. public $compressed_size;
  85. /**
  86. * Minimum size of a valid gzip string
  87. *
  88. * @access private
  89. */
  90. public $min_compressed_size = 18;
  91. /**
  92. * Current position of pointer
  93. *
  94. * @access private
  95. */
  96. public $position = 0;
  97. /**
  98. * Flags (FLG)
  99. *
  100. * @access private
  101. */
  102. public $flags;
  103. /**
  104. * Uncompressed data
  105. *
  106. * @access public
  107. * @see gzdecode::$compressed_data
  108. */
  109. public $data;
  110. /**
  111. * Modified time
  112. *
  113. * @access public
  114. */
  115. public $MTIME;
  116. /**
  117. * Extra Flags
  118. *
  119. * @access public
  120. */
  121. public $XFL;
  122. /**
  123. * Operating System
  124. *
  125. * @access public
  126. */
  127. public $OS;
  128. /**
  129. * Subfield ID 1
  130. *
  131. * @access public
  132. * @see gzdecode::$extra_field
  133. * @see gzdecode::$SI2
  134. */
  135. public $SI1;
  136. /**
  137. * Subfield ID 2
  138. *
  139. * @access public
  140. * @see gzdecode::$extra_field
  141. * @see gzdecode::$SI1
  142. */
  143. public $SI2;
  144. /**
  145. * Extra field content
  146. *
  147. * @access public
  148. * @see gzdecode::$SI1
  149. * @see gzdecode::$SI2
  150. */
  151. public $extra_field;
  152. /**
  153. * Original filename
  154. *
  155. * @access public
  156. */
  157. public $filename;
  158. /**
  159. * Human readable comment
  160. *
  161. * @access public
  162. */
  163. public $comment;
  164. /**
  165. * Don't allow anything to be set
  166. *
  167. * @access public
  168. */
  169. public function __set($name, $value)
  170. {
  171. trigger_error("Cannot write property $name", E_USER_ERROR);
  172. }
  173. /**
  174. * Set the compressed string and related properties
  175. *
  176. * @access public
  177. */
  178. public function __construct($data)
  179. {
  180. $this->compressed_data = $data;
  181. $this->compressed_size = strlen($data);
  182. }
  183. /**
  184. * Decode the GZIP stream
  185. *
  186. * @access public
  187. */
  188. public function parse()
  189. {
  190. if ($this->compressed_size >= $this->min_compressed_size)
  191. {
  192. // Check ID1, ID2, and CM
  193. if (substr($this->compressed_data, 0, 3) !== "\x1F\x8B\x08")
  194. {
  195. return false;
  196. }
  197. // Get the FLG (FLaGs)
  198. $this->flags = ord($this->compressed_data[3]);
  199. // FLG bits above (1 << 4) are reserved
  200. if ($this->flags > 0x1F)
  201. {
  202. return false;
  203. }
  204. // Advance the pointer after the above
  205. $this->position += 4;
  206. // MTIME
  207. $mtime = substr($this->compressed_data, $this->position, 4);
  208. // Reverse the string if we're on a big-endian arch because l is the only signed long and is machine endianness
  209. if (current(unpack('S', "\x00\x01")) === 1)
  210. {
  211. $mtime = strrev($mtime);
  212. }
  213. $this->MTIME = current(unpack('l', $mtime));
  214. $this->position += 4;
  215. // Get the XFL (eXtra FLags)
  216. $this->XFL = ord($this->compressed_data[$this->position++]);
  217. // Get the OS (Operating System)
  218. $this->OS = ord($this->compressed_data[$this->position++]);
  219. // Parse the FEXTRA
  220. if ($this->flags & 4)
  221. {
  222. // Read subfield IDs
  223. $this->SI1 = $this->compressed_data[$this->position++];
  224. $this->SI2 = $this->compressed_data[$this->position++];
  225. // SI2 set to zero is reserved for future use
  226. if ($this->SI2 === "\x00")
  227. {
  228. return false;
  229. }
  230. // Get the length of the extra field
  231. $len = current(unpack('v', substr($this->compressed_data, $this->position, 2)));
  232. $position += 2;
  233. // Check the length of the string is still valid
  234. $this->min_compressed_size += $len + 4;
  235. if ($this->compressed_size >= $this->min_compressed_size)
  236. {
  237. // Set the extra field to the given data
  238. $this->extra_field = substr($this->compressed_data, $this->position, $len);
  239. $this->position += $len;
  240. }
  241. else
  242. {
  243. return false;
  244. }
  245. }
  246. // Parse the FNAME
  247. if ($this->flags & 8)
  248. {
  249. // Get the length of the filename
  250. $len = strcspn($this->compressed_data, "\x00", $this->position);
  251. // Check the length of the string is still valid
  252. $this->min_compressed_size += $len + 1;
  253. if ($this->compressed_size >= $this->min_compressed_size)
  254. {
  255. // Set the original filename to the given string
  256. $this->filename = substr($this->compressed_data, $this->position, $len);
  257. $this->position += $len + 1;
  258. }
  259. else
  260. {
  261. return false;
  262. }
  263. }
  264. // Parse the FCOMMENT
  265. if ($this->flags & 16)
  266. {
  267. // Get the length of the comment
  268. $len = strcspn($this->compressed_data, "\x00", $this->position);
  269. // Check the length of the string is still valid
  270. $this->min_compressed_size += $len + 1;
  271. if ($this->compressed_size >= $this->min_compressed_size)
  272. {
  273. // Set the original comment to the given string
  274. $this->comment = substr($this->compressed_data, $this->position, $len);
  275. $this->position += $len + 1;
  276. }
  277. else
  278. {
  279. return false;
  280. }
  281. }
  282. // Parse the FHCRC
  283. if ($this->flags & 2)
  284. {
  285. // Check the length of the string is still valid
  286. $this->min_compressed_size += $len + 2;
  287. if ($this->compressed_size >= $this->min_compressed_size)
  288. {
  289. // Read the CRC
  290. $crc = current(unpack('v', substr($this->compressed_data, $this->position, 2)));
  291. // Check the CRC matches
  292. if ((crc32(substr($this->compressed_data, 0, $this->position)) & 0xFFFF) === $crc)
  293. {
  294. $this->position += 2;
  295. }
  296. else
  297. {
  298. return false;
  299. }
  300. }
  301. else
  302. {
  303. return false;
  304. }
  305. }
  306. // Decompress the actual data
  307. if (($this->data = gzinflate(substr($this->compressed_data, $this->position, -8))) === false)
  308. {
  309. return false;
  310. }
  311. else
  312. {
  313. $this->position = $this->compressed_size - 8;
  314. }
  315. // Check CRC of data
  316. $crc = current(unpack('V', substr($this->compressed_data, $this->position, 4)));
  317. $this->position += 4;
  318. /*if (extension_loaded('hash') && sprintf('%u', current(unpack('V', hash('crc32b', $this->data)))) !== sprintf('%u', $crc))
  319. {
  320. return false;
  321. }*/
  322. // Check ISIZE of data
  323. $isize = current(unpack('V', substr($this->compressed_data, $this->position, 4)));
  324. $this->position += 4;
  325. if (sprintf('%u', strlen($this->data) & 0xFFFFFFFF) !== sprintf('%u', $isize))
  326. {
  327. return false;
  328. }
  329. // Wow, against all odds, we've actually got a valid gzip string
  330. return true;
  331. }
  332. else
  333. {
  334. return false;
  335. }
  336. }
  337. }