PageRenderTime 50ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/getid3/module.archive.gzip.php

https://bitbucket.org/holyfield/getid3
PHP | 261 lines | 173 code | 30 blank | 58 comment | 38 complexity | 246e7185ffc62c04d42022bfc813af2f MD5 | raw file
Possible License(s): GPL-2.0
  1. <?php
  2. /////////////////////////////////////////////////////////////////
  3. /// getID3() by James Heinrich <info@getid3.org> //
  4. // available at http://getid3.sourceforge.net //
  5. // or http://www.getid3.org //
  6. /////////////////////////////////////////////////////////////////
  7. // See readme.txt for more details //
  8. /////////////////////////////////////////////////////////////////
  9. // //
  10. // module.archive.gzip.php //
  11. // module for analyzing GZIP files //
  12. // dependencies: NONE //
  13. // ///
  14. /////////////////////////////////////////////////////////////////
  15. // //
  16. // Module originally written by //
  17. // Mike Mozolin <teddybearØmail*ru> //
  18. // //
  19. /////////////////////////////////////////////////////////////////
  20. class getid3_gzip extends getid3_handler {
  21. // public: Optional file list - disable for speed.
  22. var $option_gzip_parse_contents = false; // decode gzipped files, if possible, and parse recursively (.tar.gz for example)
  23. function Analyze() {
  24. $info = &$this->getid3->info;
  25. $info ['fileformat'] = 'gzip';
  26. $start_length = 10;
  27. $unpack_header = 'a1id1/a1id2/a1cmethod/a1flags/a4mtime/a1xflags/a1os';
  28. //+---+---+---+---+---+---+---+---+---+---+
  29. //|ID1|ID2|CM |FLG| MTIME |XFL|OS |
  30. //+---+---+---+---+---+---+---+---+---+---+
  31. if ($info ['filesize'] > $info ['php_memory_limit']) {
  32. $info ['error'] [] = 'File is too large (' . number_format ( $info ['filesize'] ) . ' bytes) to read into memory (limit: ' . number_format ( $info ['php_memory_limit'] / 1048576 ) . 'MB)';
  33. return false;
  34. }
  35. fseek ( $this->getid3->fp, 0 );
  36. $buffer = fread ( $this->getid3->fp, $info ['filesize'] );
  37. $arr_members = explode ( "\x1F\x8B\x08", $buffer );
  38. while ( true ) {
  39. $is_wrong_members = false;
  40. $num_members = intval ( count ( $arr_members ) );
  41. for($i = 0; $i < $num_members; $i ++) {
  42. if (strlen ( $arr_members [$i] ) == 0) {
  43. continue;
  44. }
  45. $buf = "\x1F\x8B\x08" . $arr_members [$i];
  46. $attr = unpack ( $unpack_header, substr ( $buf, 0, $start_length ) );
  47. if (! $this->get_os_type ( ord ( $attr ['os'] ) )) {
  48. // Merge member with previous if wrong OS type
  49. $arr_members [$i - 1] .= $buf;
  50. $arr_members [$i] = '';
  51. $is_wrong_members = true;
  52. continue;
  53. }
  54. }
  55. if (! $is_wrong_members) {
  56. break;
  57. }
  58. }
  59. $info ['gzip'] ['files'] = array ();
  60. $fpointer = 0;
  61. $idx = 0;
  62. for($i = 0; $i < $num_members; $i ++) {
  63. if (strlen ( $arr_members [$i] ) == 0) {
  64. continue;
  65. }
  66. $thisInfo = &$info ['gzip'] ['member_header'] [++ $idx];
  67. $buff = "\x1F\x8B\x08" . $arr_members [$i];
  68. $attr = unpack ( $unpack_header, substr ( $buff, 0, $start_length ) );
  69. $thisInfo ['filemtime'] = getid3_lib::LittleEndian2Int ( $attr ['mtime'] );
  70. $thisInfo ['raw'] ['id1'] = ord ( $attr ['cmethod'] );
  71. $thisInfo ['raw'] ['id2'] = ord ( $attr ['cmethod'] );
  72. $thisInfo ['raw'] ['cmethod'] = ord ( $attr ['cmethod'] );
  73. $thisInfo ['raw'] ['os'] = ord ( $attr ['os'] );
  74. $thisInfo ['raw'] ['xflags'] = ord ( $attr ['xflags'] );
  75. $thisInfo ['raw'] ['flags'] = ord ( $attr ['flags'] );
  76. $thisInfo ['flags'] ['crc16'] = ( bool ) ($thisInfo ['raw'] ['flags'] & 0x02);
  77. $thisInfo ['flags'] ['extra'] = ( bool ) ($thisInfo ['raw'] ['flags'] & 0x04);
  78. $thisInfo ['flags'] ['filename'] = ( bool ) ($thisInfo ['raw'] ['flags'] & 0x08);
  79. $thisInfo ['flags'] ['comment'] = ( bool ) ($thisInfo ['raw'] ['flags'] & 0x10);
  80. $thisInfo ['compression'] = $this->get_xflag_type ( $thisInfo ['raw'] ['xflags'] );
  81. $thisInfo ['os'] = $this->get_os_type ( $thisInfo ['raw'] ['os'] );
  82. if (! $thisInfo ['os']) {
  83. $info ['error'] [] = 'Read error on gzip file';
  84. return false;
  85. }
  86. $fpointer = 10;
  87. $arr_xsubfield = array ();
  88. // bit 2 - FLG.FEXTRA
  89. //+---+---+=================================+
  90. //| XLEN |...XLEN bytes of "extra field"...|
  91. //+---+---+=================================+
  92. if ($thisInfo ['flags'] ['extra']) {
  93. $w_xlen = substr ( $buff, $fpointer, 2 );
  94. $xlen = getid3_lib::LittleEndian2Int ( $w_xlen );
  95. $fpointer += 2;
  96. $thisInfo ['raw'] ['xfield'] = substr ( $buff, $fpointer, $xlen );
  97. // Extra SubFields
  98. //+---+---+---+---+==================================+
  99. //|SI1|SI2| LEN |... LEN bytes of subfield data ...|
  100. //+---+---+---+---+==================================+
  101. $idx = 0;
  102. while ( true ) {
  103. if ($idx >= $xlen) {
  104. break;
  105. }
  106. $si1 = ord ( substr ( $buff, $fpointer + $idx ++, 1 ) );
  107. $si2 = ord ( substr ( $buff, $fpointer + $idx ++, 1 ) );
  108. if (($si1 == 0x41) && ($si2 == 0x70)) {
  109. $w_xsublen = substr ( $buff, $fpointer + $idx, 2 );
  110. $xsublen = getid3_lib::LittleEndian2Int ( $w_xsublen );
  111. $idx += 2;
  112. $arr_xsubfield [] = substr ( $buff, $fpointer + $idx, $xsublen );
  113. $idx += $xsublen;
  114. } else {
  115. break;
  116. }
  117. }
  118. $fpointer += $xlen;
  119. }
  120. // bit 3 - FLG.FNAME
  121. //+=========================================+
  122. //|...original file name, zero-terminated...|
  123. //+=========================================+
  124. // GZIP files may have only one file, with no filename, so assume original filename is current filename without .gz
  125. $thisInfo ['filename'] = preg_replace ( '#\.gz$#i', '', $info ['filename'] );
  126. if ($thisInfo ['flags'] ['filename']) {
  127. while ( true ) {
  128. if (ord ( $buff [$fpointer] ) == 0) {
  129. $fpointer ++;
  130. break;
  131. }
  132. $thisInfo ['filename'] .= $buff [$fpointer];
  133. $fpointer ++;
  134. }
  135. }
  136. // bit 4 - FLG.FCOMMENT
  137. //+===================================+
  138. //|...file comment, zero-terminated...|
  139. //+===================================+
  140. if ($thisInfo ['flags'] ['comment']) {
  141. while ( true ) {
  142. if (ord ( $buff [$fpointer] ) == 0) {
  143. $fpointer ++;
  144. break;
  145. }
  146. $thisInfo ['comment'] .= $buff [$fpointer];
  147. $fpointer ++;
  148. }
  149. }
  150. // bit 1 - FLG.FHCRC
  151. //+---+---+
  152. //| CRC16 |
  153. //+---+---+
  154. if ($thisInfo ['flags'] ['crc16']) {
  155. $w_crc = substr ( $buff, $fpointer, 2 );
  156. $thisInfo ['crc16'] = getid3_lib::LittleEndian2Int ( $w_crc );
  157. $fpointer += 2;
  158. }
  159. // bit 0 - FLG.FTEXT
  160. //if ($thisInfo['raw']['flags'] & 0x01) {
  161. // Ignored...
  162. //}
  163. // bits 5, 6, 7 - reserved
  164. $thisInfo ['crc32'] = getid3_lib::LittleEndian2Int ( substr ( $buff, strlen ( $buff ) - 8, 4 ) );
  165. $thisInfo ['filesize'] = getid3_lib::LittleEndian2Int ( substr ( $buff, strlen ( $buff ) - 4 ) );
  166. $info ['gzip'] ['files'] = getid3_lib::array_merge_clobber ( $info ['gzip'] ['files'], getid3_lib::CreateDeepArray ( $thisInfo ['filename'], '/', $thisInfo ['filesize'] ) );
  167. if ($this->option_gzip_parse_contents) {
  168. // Try to inflate GZip
  169. $csize = 0;
  170. $inflated = '';
  171. $chkcrc32 = '';
  172. if (function_exists ( 'gzinflate' )) {
  173. $cdata = substr ( $buff, $fpointer );
  174. $cdata = substr ( $cdata, 0, strlen ( $cdata ) - 8 );
  175. $csize = strlen ( $cdata );
  176. $inflated = gzinflate ( $cdata );
  177. // Calculate CRC32 for inflated content
  178. $thisInfo ['crc32_valid'] = ( bool ) (sprintf ( '%u', crc32 ( $inflated ) ) == $thisInfo ['crc32']);
  179. // determine format
  180. $formattest = substr ( $inflated, 0, 32774 );
  181. $getid3_temp = new getID3 ();
  182. $determined_format = $getid3_temp->GetFileFormat ( $formattest );
  183. unset ( $getid3_temp );
  184. // file format is determined
  185. $determined_format ['module'] = (isset ( $determined_format ['module'] ) ? $determined_format ['module'] : '');
  186. switch ($determined_format ['module']) {
  187. case 'tar' :
  188. // view TAR-file info
  189. if (file_exists ( GETID3_INCLUDEPATH . $determined_format ['include'] ) && include_once (GETID3_INCLUDEPATH . $determined_format ['include'])) {
  190. if (($temp_tar_filename = tempnam ( GETID3_TEMP_DIR, 'getID3' )) === false) {
  191. // can't find anywhere to create a temp file, abort
  192. $info ['error'] [] = 'Unable to create temp file to parse TAR inside GZIP file';
  193. break;
  194. }
  195. if (($fp_temp_tar = fopen ( $temp_tar_filename, 'w+b' )) != false) {
  196. fwrite ( $fp_temp_tar, $inflated );
  197. fclose ( $fp_temp_tar );
  198. $getid3_temp = new getID3 ();
  199. $getid3_temp->openfile ( $temp_tar_filename );
  200. $getid3_tar = new getid3_tar ( $getid3_temp );
  201. $getid3_tar->Analyze ();
  202. $info ['gzip'] ['member_header'] [$idx] ['tar'] = $getid3_temp->info ['tar'];
  203. unset ( $getid3_temp, $getid3_tar );
  204. unlink ( $temp_tar_filename );
  205. } else {
  206. $info ['error'] [] = 'Unable to fopen() temp file to parse TAR inside GZIP file';
  207. break;
  208. }
  209. }
  210. break;
  211. case '' :
  212. default :
  213. // unknown or unhandled format
  214. break;
  215. }
  216. }
  217. }
  218. }
  219. return true;
  220. }
  221. // Converts the OS type
  222. function get_os_type($key) {
  223. static $os_type = array ('0' => 'FAT filesystem (MS-DOS, OS/2, NT/Win32)', '1' => 'Amiga', '2' => 'VMS (or OpenVMS)', '3' => 'Unix', '4' => 'VM/CMS', '5' => 'Atari TOS', '6' => 'HPFS filesystem (OS/2, NT)', '7' => 'Macintosh', '8' => 'Z-System', '9' => 'CP/M', '10' => 'TOPS-20', '11' => 'NTFS filesystem (NT)', '12' => 'QDOS', '13' => 'Acorn RISCOS', '255' => 'unknown' );
  224. return (isset ( $os_type [$key] ) ? $os_type [$key] : '');
  225. }
  226. // Converts the eXtra FLags
  227. function get_xflag_type($key) {
  228. static $xflag_type = array ('0' => 'unknown', '2' => 'maximum compression', '4' => 'fastest algorithm' );
  229. return (isset ( $xflag_type [$key] ) ? $xflag_type [$key] : '');
  230. }
  231. }