PageRenderTime 84ms CodeModel.GetById 40ms app.highlight 17ms RepoModel.GetById 23ms app.codeStats 1ms

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