wp/wp-includes/ID3/getid3.php
changeset 7 cf61fcea0001
parent 5 5e2f62d02dcd
child 16 a86126ab1dd4
equal deleted inserted replaced
6:490d5cc509ed 7:cf61fcea0001
    20 }
    20 }
    21 // Workaround Bug #39923 (https://bugs.php.net/bug.php?id=39923)
    21 // Workaround Bug #39923 (https://bugs.php.net/bug.php?id=39923)
    22 if (!defined('IMG_JPG') && defined('IMAGETYPE_JPEG')) {
    22 if (!defined('IMG_JPG') && defined('IMAGETYPE_JPEG')) {
    23 	define('IMG_JPG', IMAGETYPE_JPEG);
    23 	define('IMG_JPG', IMAGETYPE_JPEG);
    24 }
    24 }
       
    25 if (!defined('ENT_SUBSTITUTE')) { // PHP5.3 adds ENT_IGNORE, PHP5.4 adds ENT_SUBSTITUTE
       
    26 	define('ENT_SUBSTITUTE', (defined('ENT_IGNORE') ? ENT_IGNORE : 8));
       
    27 }
    25 
    28 
    26 // attempt to define temp dir as something flexible but reliable
    29 // attempt to define temp dir as something flexible but reliable
    27 $temp_dir = ini_get('upload_tmp_dir');
    30 $temp_dir = ini_get('upload_tmp_dir');
    28 if ($temp_dir && (!is_dir($temp_dir) || !is_readable($temp_dir))) {
    31 if ($temp_dir && (!is_dir($temp_dir) || !is_readable($temp_dir))) {
    29 	$temp_dir = '';
    32 	$temp_dir = '';
    30 }
    33 }
    31 if (!$temp_dir) {
    34 if (!$temp_dir && function_exists('sys_get_temp_dir')) { // sys_get_temp_dir added in PHP v5.2.1
    32 	// sys_get_temp_dir() may give inaccessible temp dir, e.g. with open_basedir on virtual hosts
    35 	// sys_get_temp_dir() may give inaccessible temp dir, e.g. with open_basedir on virtual hosts
    33 	$temp_dir = sys_get_temp_dir();
    36 	$temp_dir = sys_get_temp_dir();
    34 }
    37 }
    35 $temp_dir = @realpath($temp_dir); // see https://github.com/JamesHeinrich/getID3/pull/10
    38 $temp_dir = @realpath($temp_dir); // see https://github.com/JamesHeinrich/getID3/pull/10
    36 $open_basedir = ini_get('open_basedir');
    39 $open_basedir = ini_get('open_basedir');
   107 
   110 
   108 	// Protected variables
   111 	// Protected variables
   109 	protected $startup_error   = '';
   112 	protected $startup_error   = '';
   110 	protected $startup_warning = '';
   113 	protected $startup_warning = '';
   111 
   114 
   112 	const VERSION           = '1.9.8-20140511';
   115 	const VERSION           = '1.9.14-201706111222';
   113 	const FREAD_BUFFER_SIZE = 32768;
   116 	const FREAD_BUFFER_SIZE = 32768;
   114 
   117 
   115 	const ATTACHMENTS_NONE   = false;
   118 	const ATTACHMENTS_NONE   = false;
   116 	const ATTACHMENTS_INLINE = true;
   119 	const ATTACHMENTS_INLINE = true;
   117 
   120 
   118 	// public: constructor
   121 	// public: constructor
   119 	public function __construct() {
   122 	public function __construct() {
   120 
   123 
   121 		// Check memory
   124 		// Check memory
   122 		$this->memory_limit = ini_get('memory_limit');
   125 		$this->memory_limit = ini_get('memory_limit');
   123 		if (preg_match('#([0-9]+)M#i', $this->memory_limit, $matches)) {
   126 		if (preg_match('#([0-9]+) ?M#i', $this->memory_limit, $matches)) {
   124 			// could be stored as "16M" rather than 16777216 for example
   127 			// could be stored as "16M" rather than 16777216 for example
   125 			$this->memory_limit = $matches[1] * 1048576;
   128 			$this->memory_limit = $matches[1] * 1048576;
   126 		} elseif (preg_match('#([0-9]+)G#i', $this->memory_limit, $matches)) { // The 'G' modifier is available since PHP 5.1.0
   129 		} elseif (preg_match('#([0-9]+) ?G#i', $this->memory_limit, $matches)) { // The 'G' modifier is available since PHP 5.1.0
   127 			// could be stored as "2G" rather than 2147483648 for example
   130 			// could be stored as "2G" rather than 2147483648 for example
   128 			$this->memory_limit = $matches[1] * 1073741824;
   131 			$this->memory_limit = $matches[1] * 1073741824;
   129 		}
   132 		}
   130 		if ($this->memory_limit <= 0) {
   133 		if ($this->memory_limit <= 0) {
   131 			// memory limits probably disabled
   134 			// memory limits probably disabled
   132 		} elseif ($this->memory_limit <= 4194304) {
   135 		} elseif ($this->memory_limit <= 4194304) {
   133 			$this->startup_error .= 'PHP has less than 4MB available memory and will very likely run out. Increase memory_limit in php.ini';
   136 			$this->startup_error .= 'PHP has less than 4MB available memory and will very likely run out. Increase memory_limit in php.ini'."\n";
   134 		} elseif ($this->memory_limit <= 12582912) {
   137 		} elseif ($this->memory_limit <= 12582912) {
   135 			$this->startup_warning .= 'PHP has less than 12MB available memory and might run out if all modules are loaded. Increase memory_limit in php.ini';
   138 			$this->startup_warning .= 'PHP has less than 12MB available memory and might run out if all modules are loaded. Increase memory_limit in php.ini'."\n";
   136 		}
   139 		}
   137 
   140 
   138 		// Check safe_mode off
   141 		// Check safe_mode off
   139 		if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) {
   142 		if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) {
   140 			$this->warning('WARNING: Safe mode is on, shorten support disabled, md5data/sha1data for ogg vorbis disabled, ogg vorbos/flac tag writing disabled.');
   143 			$this->warning('WARNING: Safe mode is on, shorten support disabled, md5data/sha1data for ogg vorbis disabled, ogg vorbos/flac tag writing disabled.');
   141 		}
   144 		}
   142 
   145 
   143 		if (intval(ini_get('mbstring.func_overload')) > 0) {
   146 		if (($mbstring_func_overload = ini_get('mbstring.func_overload')) && ($mbstring_func_overload & 0x02)) {
   144 			$this->warning('WARNING: php.ini contains "mbstring.func_overload = '.ini_get('mbstring.func_overload').'", this may break things.');
   147 			// http://php.net/manual/en/mbstring.overload.php
       
   148 			// "mbstring.func_overload in php.ini is a positive value that represents a combination of bitmasks specifying the categories of functions to be overloaded. It should be set to 1 to overload the mail() function. 2 for string functions, 4 for regular expression functions"
       
   149 			// getID3 cannot run when string functions are overloaded. It doesn't matter if mail() or ereg* functions are overloaded since getID3 does not use those.
       
   150 			$this->startup_error .= 'WARNING: php.ini contains "mbstring.func_overload = '.ini_get('mbstring.func_overload').'", getID3 cannot run with this setting (bitmask 2 (string functions) cannot be set). Recommended to disable entirely.'."\n";
   145 		}
   151 		}
   146 
   152 
   147 		// Check for magic_quotes_runtime
   153 		// Check for magic_quotes_runtime
   148 		if (function_exists('get_magic_quotes_runtime')) {
   154 		if (function_exists('get_magic_quotes_runtime')) {
   149 			if (get_magic_quotes_runtime()) {
   155 			if (get_magic_quotes_runtime()) {
   150 				return $this->startup_error('magic_quotes_runtime must be disabled before running getID3(). Surround getid3 block by set_magic_quotes_runtime(0) and set_magic_quotes_runtime(1).');
   156 				$this->startup_error .= 'magic_quotes_runtime must be disabled before running getID3(). Surround getid3 block by set_magic_quotes_runtime(0) and set_magic_quotes_runtime(1).'."\n";
   151 			}
   157 			}
   152 		}
   158 		}
   153 
   159 
   154 		// Check for magic_quotes_gpc
   160 		// Check for magic_quotes_gpc
   155 		if (function_exists('magic_quotes_gpc')) {
   161 		if (function_exists('magic_quotes_gpc')) {
   156 			if (get_magic_quotes_gpc()) {
   162 			if (get_magic_quotes_gpc()) {
   157 				return $this->startup_error('magic_quotes_gpc must be disabled before running getID3(). Surround getid3 block by set_magic_quotes_gpc(0) and set_magic_quotes_gpc(1).');
   163 				$this->startup_error .= 'magic_quotes_gpc must be disabled before running getID3(). Surround getid3 block by set_magic_quotes_gpc(0) and set_magic_quotes_gpc(1).'."\n";
   158 			}
   164 			}
   159 		}
   165 		}
   160 
   166 
   161 		// Load support library
   167 		// Load support library
   162 		if (!include_once(GETID3_INCLUDEPATH.'getid3.lib.php')) {
   168 		if (!include_once(GETID3_INCLUDEPATH.'getid3.lib.php')) {
   163 			$this->startup_error .= 'getid3.lib.php is missing or corrupt';
   169 			$this->startup_error .= 'getid3.lib.php is missing or corrupt'."\n";
   164 		}
   170 		}
   165 
   171 
   166 		if ($this->option_max_2gb_check === null) {
   172 		if ($this->option_max_2gb_check === null) {
   167 			$this->option_max_2gb_check = (PHP_INT_MAX <= 2147483647);
   173 			$this->option_max_2gb_check = (PHP_INT_MAX <= 2147483647);
   168 		}
   174 		}
   177 		if (GETID3_OS_ISWINDOWS && !defined('GETID3_HELPERAPPSDIR')) {
   183 		if (GETID3_OS_ISWINDOWS && !defined('GETID3_HELPERAPPSDIR')) {
   178 
   184 
   179 			$helperappsdir = GETID3_INCLUDEPATH.'..'.DIRECTORY_SEPARATOR.'helperapps'; // must not have any space in this path
   185 			$helperappsdir = GETID3_INCLUDEPATH.'..'.DIRECTORY_SEPARATOR.'helperapps'; // must not have any space in this path
   180 
   186 
   181 			if (!is_dir($helperappsdir)) {
   187 			if (!is_dir($helperappsdir)) {
   182 				$this->startup_warning .= '"'.$helperappsdir.'" cannot be defined as GETID3_HELPERAPPSDIR because it does not exist';
   188 				$this->startup_warning .= '"'.$helperappsdir.'" cannot be defined as GETID3_HELPERAPPSDIR because it does not exist'."\n";
   183 			} elseif (strpos(realpath($helperappsdir), ' ') !== false) {
   189 			} elseif (strpos(realpath($helperappsdir), ' ') !== false) {
   184 				$DirPieces = explode(DIRECTORY_SEPARATOR, realpath($helperappsdir));
   190 				$DirPieces = explode(DIRECTORY_SEPARATOR, realpath($helperappsdir));
   185 				$path_so_far = array();
   191 				$path_so_far = array();
   186 				foreach ($DirPieces as $key => $value) {
   192 				foreach ($DirPieces as $key => $value) {
   187 					if (strpos($value, ' ') !== false) {
   193 					if (strpos($value, ' ') !== false) {
   197 										$value = $shortname;
   203 										$value = $shortname;
   198 									}
   204 									}
   199 								}
   205 								}
   200 							}
   206 							}
   201 						} else {
   207 						} else {
   202 							$this->startup_warning .= 'GETID3_HELPERAPPSDIR must not have any spaces in it - use 8dot3 naming convention if neccesary. You can run "dir /x" from the commandline to see the correct 8.3-style names.';
   208 							$this->startup_warning .= 'GETID3_HELPERAPPSDIR must not have any spaces in it - use 8dot3 naming convention if neccesary. You can run "dir /x" from the commandline to see the correct 8.3-style names.'."\n";
   203 						}
   209 						}
   204 					}
   210 					}
   205 					$path_so_far[] = $value;
   211 					$path_so_far[] = $value;
   206 				}
   212 				}
   207 				$helperappsdir = implode(DIRECTORY_SEPARATOR, $path_so_far);
   213 				$helperappsdir = implode(DIRECTORY_SEPARATOR, $path_so_far);
   208 			}
   214 			}
   209 			define('GETID3_HELPERAPPSDIR', $helperappsdir.DIRECTORY_SEPARATOR);
   215 			define('GETID3_HELPERAPPSDIR', $helperappsdir.DIRECTORY_SEPARATOR);
       
   216 		}
       
   217 
       
   218 		if (!empty($this->startup_error)) {
       
   219 			echo $this->startup_error;
       
   220 			throw new getid3_exception($this->startup_error);
   210 		}
   221 		}
   211 
   222 
   212 		return true;
   223 		return true;
   213 	}
   224 	}
   214 
   225 
   234 		}
   245 		}
   235 		return true;
   246 		return true;
   236 	}
   247 	}
   237 
   248 
   238 
   249 
   239 	public function openfile($filename) {
   250 	public function openfile($filename, $filesize=null) {
   240 		try {
   251 		try {
   241 			if (!empty($this->startup_error)) {
   252 			if (!empty($this->startup_error)) {
   242 				throw new getid3_exception($this->startup_error);
   253 				throw new getid3_exception($this->startup_error);
   243 			}
   254 			}
   244 			if (!empty($this->startup_warning)) {
   255 			if (!empty($this->startup_warning)) {
   245 				$this->warning($this->startup_warning);
   256 				foreach (explode("\n", $this->startup_warning) as $startup_warning) {
       
   257 					$this->warning($startup_warning);
       
   258 				}
   246 			}
   259 			}
   247 
   260 
   248 			// init result array and set parameters
   261 			// init result array and set parameters
   249 			$this->filename = $filename;
   262 			$this->filename = $filename;
   250 			$this->info = array();
   263 			$this->info = array();
   251 			$this->info['GETID3_VERSION']   = $this->version();
   264 			$this->info['GETID3_VERSION']   = $this->version();
   252 			$this->info['php_memory_limit'] = $this->memory_limit;
   265 			$this->info['php_memory_limit'] = (($this->memory_limit > 0) ? $this->memory_limit : false);
   253 
   266 
   254 			// remote files not supported
   267 			// remote files not supported
   255 			if (preg_match('/^(ht|f)tp:\/\//', $filename)) {
   268 			if (preg_match('#^(ht|f)tp://#', $filename)) {
   256 				throw new getid3_exception('Remote files are not supported - please copy the file locally first');
   269 				throw new getid3_exception('Remote files are not supported - please copy the file locally first');
   257 			}
   270 			}
   258 
   271 
   259 			$filename = str_replace('/', DIRECTORY_SEPARATOR, $filename);
   272 			$filename = str_replace('/', DIRECTORY_SEPARATOR, $filename);
   260 			$filename = preg_replace('#(.+)'.preg_quote(DIRECTORY_SEPARATOR).'{2,}#U', '\1'.DIRECTORY_SEPARATOR, $filename);
   273 			$filename = preg_replace('#(?<!gs:)('.preg_quote(DIRECTORY_SEPARATOR).'{2,})#', DIRECTORY_SEPARATOR, $filename);
   261 
   274 
   262 			// open local file
   275 			// open local file
   263 			//if (is_readable($filename) && is_file($filename) && ($this->fp = fopen($filename, 'rb'))) { // see http://www.getid3.org/phpBB3/viewtopic.php?t=1720
   276 			//if (is_readable($filename) && is_file($filename) && ($this->fp = fopen($filename, 'rb'))) { // see http://www.getid3.org/phpBB3/viewtopic.php?t=1720
   264 			if ((is_readable($filename) || file_exists($filename)) && is_file($filename) && ($this->fp = fopen($filename, 'rb'))) {
   277 			if ((is_readable($filename) || file_exists($filename)) && is_file($filename) && ($this->fp = fopen($filename, 'rb'))) {
   265 				// great
   278 				// great
   278 					$errormessagelist[] = 'fopen failed';
   291 					$errormessagelist[] = 'fopen failed';
   279 				}
   292 				}
   280 				throw new getid3_exception('Could not open "'.$filename.'" ('.implode('; ', $errormessagelist).')');
   293 				throw new getid3_exception('Could not open "'.$filename.'" ('.implode('; ', $errormessagelist).')');
   281 			}
   294 			}
   282 
   295 
   283 			$this->info['filesize'] = filesize($filename);
   296 			$this->info['filesize'] = (!is_null($filesize) ? $filesize : filesize($filename));
   284 			// set redundant parameters - might be needed in some include file
   297 			// set redundant parameters - might be needed in some include file
   285 			// filenames / filepaths in getID3 are always expressed with forward slashes (unix-style) for both Windows and other to try and minimize confusion
   298 			// filenames / filepaths in getID3 are always expressed with forward slashes (unix-style) for both Windows and other to try and minimize confusion
   286 			$filename = str_replace('\\', '/', $filename);
   299 			$filename = str_replace('\\', '/', $filename);
   287 			$this->info['filepath']     = str_replace('\\', '/', realpath(dirname($filename)));
   300 			$this->info['filepath']     = str_replace('\\', '/', realpath(dirname($filename)));
   288 			$this->info['filename']     = getid3_lib::mb_basename($filename);
   301 			$this->info['filename']     = getid3_lib::mb_basename($filename);
   289 			$this->info['filenamepath'] = $this->info['filepath'].'/'.$this->info['filename'];
   302 			$this->info['filenamepath'] = $this->info['filepath'].'/'.$this->info['filename'];
   290 
   303 
       
   304 			// set more parameters
       
   305 			$this->info['avdataoffset']        = 0;
       
   306 			$this->info['avdataend']           = $this->info['filesize'];
       
   307 			$this->info['fileformat']          = '';                // filled in later
       
   308 			$this->info['audio']['dataformat'] = '';                // filled in later, unset if not used
       
   309 			$this->info['video']['dataformat'] = '';                // filled in later, unset if not used
       
   310 			$this->info['tags']                = array();           // filled in later, unset if not used
       
   311 			$this->info['error']               = array();           // filled in later, unset if not used
       
   312 			$this->info['warning']             = array();           // filled in later, unset if not used
       
   313 			$this->info['comments']            = array();           // filled in later, unset if not used
       
   314 			$this->info['encoding']            = $this->encoding;   // required by id3v2 and iso modules - can be unset at the end if desired
   291 
   315 
   292 			// option_max_2gb_check
   316 			// option_max_2gb_check
   293 			if ($this->option_max_2gb_check) {
   317 			if ($this->option_max_2gb_check) {
   294 				// PHP (32-bit all, and 64-bit Windows) doesn't support integers larger than 2^31 (~2GB)
   318 				// PHP (32-bit all, and 64-bit Windows) doesn't support integers larger than 2^31 (~2GB)
   295 				// filesize() simply returns (filesize % (pow(2, 32)), no matter the actual filesize
   319 				// filesize() simply returns (filesize % (pow(2, 32)), no matter the actual filesize
   312 						$this->info['filesize'] = $real_filesize;
   336 						$this->info['filesize'] = $real_filesize;
   313 						$this->warning('File is larger than '.round(PHP_INT_MAX / 1073741824).'GB (filesystem reports it as '.number_format($real_filesize, 3).'GB) and is not properly supported by PHP.');
   337 						$this->warning('File is larger than '.round(PHP_INT_MAX / 1073741824).'GB (filesystem reports it as '.number_format($real_filesize, 3).'GB) and is not properly supported by PHP.');
   314 				}
   338 				}
   315 			}
   339 			}
   316 
   340 
   317 			// set more parameters
       
   318 			$this->info['avdataoffset']        = 0;
       
   319 			$this->info['avdataend']           = $this->info['filesize'];
       
   320 			$this->info['fileformat']          = '';                // filled in later
       
   321 			$this->info['audio']['dataformat'] = '';                // filled in later, unset if not used
       
   322 			$this->info['video']['dataformat'] = '';                // filled in later, unset if not used
       
   323 			$this->info['tags']                = array();           // filled in later, unset if not used
       
   324 			$this->info['error']               = array();           // filled in later, unset if not used
       
   325 			$this->info['warning']             = array();           // filled in later, unset if not used
       
   326 			$this->info['comments']            = array();           // filled in later, unset if not used
       
   327 			$this->info['encoding']            = $this->encoding;   // required by id3v2 and iso modules - can be unset at the end if desired
       
   328 
       
   329 			return true;
   341 			return true;
   330 
   342 
   331 		} catch (Exception $e) {
   343 		} catch (Exception $e) {
   332 			$this->error($e->getMessage());
   344 			$this->error($e->getMessage());
   333 		}
   345 		}
   334 		return false;
   346 		return false;
   335 	}
   347 	}
   336 
   348 
   337 	// public: analyze file
   349 	// public: analyze file
   338 	public function analyze($filename) {
   350 	public function analyze($filename, $filesize=null, $original_filename='') {
   339 		try {
   351 		try {
   340 			if (!$this->openfile($filename)) {
   352 			if (!$this->openfile($filename, $filesize)) {
   341 				return $this->info;
   353 				return $this->info;
   342 			}
   354 			}
   343 
   355 
   344 			// Handle tags
   356 			// Handle tags
   345 			foreach (array('id3v2'=>'id3v2', 'id3v1'=>'id3v1', 'apetag'=>'ape', 'lyrics3'=>'lyrics3') as $tag_name => $tag_key) {
   357 			foreach (array('id3v2'=>'id3v2', 'id3v1'=>'id3v1', 'apetag'=>'ape', 'lyrics3'=>'lyrics3') as $tag_name => $tag_key) {
   380 			// read 32 kb file data
   392 			// read 32 kb file data
   381 			fseek($this->fp, $this->info['avdataoffset']);
   393 			fseek($this->fp, $this->info['avdataoffset']);
   382 			$formattest = fread($this->fp, 32774);
   394 			$formattest = fread($this->fp, 32774);
   383 
   395 
   384 			// determine format
   396 			// determine format
   385 			$determined_format = $this->GetFileFormat($formattest, $filename);
   397 			$determined_format = $this->GetFileFormat($formattest, ($original_filename ? $original_filename : $filename));
   386 
   398 
   387 			// unable to determine file format
   399 			// unable to determine file format
   388 			if (!$determined_format) {
   400 			if (!$determined_format) {
   389 				fclose($this->fp);
   401 				fclose($this->fp);
   390 				return $this->error('unable to determine file format');
   402 				return $this->error('unable to determine file format');
   417 			if (!file_exists(GETID3_INCLUDEPATH.$determined_format['include'])) {
   429 			if (!file_exists(GETID3_INCLUDEPATH.$determined_format['include'])) {
   418 				fclose($this->fp);
   430 				fclose($this->fp);
   419 				return $this->error('Format not supported, module "'.$determined_format['include'].'" was removed.');
   431 				return $this->error('Format not supported, module "'.$determined_format['include'].'" was removed.');
   420 			}
   432 			}
   421 
   433 
   422 			// module requires iconv support
   434 			// module requires mb_convert_encoding/iconv support
   423 			// Check encoding/iconv support
   435 			// Check encoding/iconv support
   424 			if (!empty($determined_format['iconv_req']) && !function_exists('iconv') && !in_array($this->encoding, array('ISO-8859-1', 'UTF-8', 'UTF-16LE', 'UTF-16BE', 'UTF-16'))) {
   436 			if (!empty($determined_format['iconv_req']) && !function_exists('mb_convert_encoding') && !function_exists('iconv') && !in_array($this->encoding, array('ISO-8859-1', 'UTF-8', 'UTF-16LE', 'UTF-16BE', 'UTF-16'))) {
   425 				$errormessage = 'iconv() support is required for this module ('.$determined_format['include'].') for encodings other than ISO-8859-1, UTF-8, UTF-16LE, UTF16-BE, UTF-16. ';
   437 				$errormessage = 'mb_convert_encoding() or iconv() support is required for this module ('.$determined_format['include'].') for encodings other than ISO-8859-1, UTF-8, UTF-16LE, UTF16-BE, UTF-16. ';
   426 				if (GETID3_OS_ISWINDOWS) {
   438 				if (GETID3_OS_ISWINDOWS) {
   427 					$errormessage .= 'PHP does not have iconv() support. Please enable php_iconv.dll in php.ini, and copy iconv.dll from c:/php/dlls to c:/windows/system32';
   439 					$errormessage .= 'PHP does not have mb_convert_encoding() or iconv() support. Please enable php_mbstring.dll / php_iconv.dll in php.ini, and copy php_mbstring.dll / iconv.dll from c:/php/dlls to c:/windows/system32';
   428 				} else {
   440 				} else {
   429 					$errormessage .= 'PHP is not compiled with iconv() support. Please recompile with the --with-iconv switch';
   441 					$errormessage .= 'PHP is not compiled with mb_convert_encoding() or iconv() support. Please recompile with the --enable-mbstring / --with-iconv switch';
   430 				}
   442 				}
   431 				return $this->error($errormessage);
   443 				return $this->error($errormessage);
   432 			}
   444 			}
   433 
   445 
   434 			// include module
   446 			// include module
   559 
   571 
   560 				// Audio formats
   572 				// Audio formats
   561 
   573 
   562 				// AC-3   - audio      - Dolby AC-3 / Dolby Digital
   574 				// AC-3   - audio      - Dolby AC-3 / Dolby Digital
   563 				'ac3'  => array(
   575 				'ac3'  => array(
   564 							'pattern'   => '^\x0B\x77',
   576 							'pattern'   => '^\\x0B\\x77',
   565 							'group'     => 'audio',
   577 							'group'     => 'audio',
   566 							'module'    => 'ac3',
   578 							'module'    => 'ac3',
   567 							'mime_type' => 'audio/ac3',
   579 							'mime_type' => 'audio/ac3',
   568 						),
   580 						),
   569 
   581 
   577 						),
   589 						),
   578 
   590 
   579 /*
   591 /*
   580 				// AA   - audio       - Audible Audiobook
   592 				// AA   - audio       - Audible Audiobook
   581 				'aa'   => array(
   593 				'aa'   => array(
   582 							'pattern'   => '^.{4}\x57\x90\x75\x36',
   594 							'pattern'   => '^.{4}\\x57\\x90\\x75\\x36',
   583 							'group'     => 'audio',
   595 							'group'     => 'audio',
   584 							'module'    => 'aa',
   596 							'module'    => 'aa',
   585 							'mime_type' => 'audio/audible',
   597 							'mime_type' => 'audio/audible',
   586 						),
   598 						),
   587 */
   599 */
   588 				// AAC  - audio       - Advanced Audio Coding (AAC) - ADTS format (very similar to MP3)
   600 				// AAC  - audio       - Advanced Audio Coding (AAC) - ADTS format (very similar to MP3)
   589 				'adts' => array(
   601 				'adts' => array(
   590 							'pattern'   => '^\xFF[\xF0-\xF1\xF8-\xF9]',
   602 							'pattern'   => '^\\xFF[\\xF0-\\xF1\\xF8-\\xF9]',
   591 							'group'     => 'audio',
   603 							'group'     => 'audio',
   592 							'module'    => 'aac',
   604 							'module'    => 'aac',
   593 							'mime_type' => 'application/octet-stream',
   605 							'mime_type' => 'application/octet-stream',
   594 							'fail_ape'  => 'WARNING',
   606 							'fail_ape'  => 'WARNING',
   595 						),
   607 						),
   596 
   608 
   597 
   609 
   598 				// AU   - audio       - NeXT/Sun AUdio (AU)
   610 				// AU   - audio       - NeXT/Sun AUdio (AU)
   599 				'au'   => array(
   611 				'au'   => array(
   600 							'pattern'   => '^\.snd',
   612 							'pattern'   => '^\\.snd',
   601 							'group'     => 'audio',
   613 							'group'     => 'audio',
   602 							'module'    => 'au',
   614 							'module'    => 'au',
   603 							'mime_type' => 'audio/basic',
   615 							'mime_type' => 'audio/basic',
   604 						),
   616 						),
   605 
   617 
   606 				// AMR  - audio       - Adaptive Multi Rate
   618 				// AMR  - audio       - Adaptive Multi Rate
   607 				'amr'  => array(
   619 				'amr'  => array(
   608 							'pattern'   => '^\x23\x21AMR\x0A', // #!AMR[0A]
   620 							'pattern'   => '^\\x23\\x21AMR\\x0A', // #!AMR[0A]
   609 							'group'     => 'audio',
   621 							'group'     => 'audio',
   610 							'module'    => 'amr',
   622 							'module'    => 'amr',
   611 							'mime_type' => 'audio/amr',
   623 							'mime_type' => 'audio/amr',
   612 						),
   624 						),
   613 
   625 
   619 							'mime_type' => 'application/octet-stream',
   631 							'mime_type' => 'application/octet-stream',
   620 						),
   632 						),
   621 
   633 
   622 				// BONK - audio       - Bonk v0.9+
   634 				// BONK - audio       - Bonk v0.9+
   623 				'bonk' => array(
   635 				'bonk' => array(
   624 							'pattern'   => '^\x00(BONK|INFO|META| ID3)',
   636 							'pattern'   => '^\\x00(BONK|INFO|META| ID3)',
   625 							'group'     => 'audio',
   637 							'group'     => 'audio',
   626 							'module'    => 'bonk',
   638 							'module'    => 'bonk',
   627 							'mime_type' => 'audio/xmms-bonk',
   639 							'mime_type' => 'audio/xmms-bonk',
   628 						),
   640 						),
   629 
   641 
       
   642 				// DSF  - audio       - Direct Stream Digital (DSD) Storage Facility files (DSF) - https://en.wikipedia.org/wiki/Direct_Stream_Digital
       
   643 				'dsf'  => array(
       
   644 							'pattern'   => '^DSD ',  // including trailing space: 44 53 44 20
       
   645 							'group'     => 'audio',
       
   646 							'module'    => 'dsf',
       
   647 							'mime_type' => 'audio/dsd',
       
   648 						),
       
   649 
   630 				// DSS  - audio       - Digital Speech Standard
   650 				// DSS  - audio       - Digital Speech Standard
   631 				'dss'  => array(
   651 				'dss'  => array(
   632 							'pattern'   => '^[\x02-\x03]ds[s2]',
   652 							'pattern'   => '^[\\x02-\\x06]ds[s2]',
   633 							'group'     => 'audio',
   653 							'group'     => 'audio',
   634 							'module'    => 'dss',
   654 							'module'    => 'dss',
   635 							'mime_type' => 'application/octet-stream',
   655 							'mime_type' => 'application/octet-stream',
   636 						),
   656 						),
   637 
   657 
   638 				// DTS  - audio       - Dolby Theatre System
   658 				// DTS  - audio       - Dolby Theatre System
   639 				'dts'  => array(
   659 				'dts'  => array(
   640 							'pattern'   => '^\x7F\xFE\x80\x01',
   660 							'pattern'   => '^\\x7F\\xFE\\x80\\x01',
   641 							'group'     => 'audio',
   661 							'group'     => 'audio',
   642 							'module'    => 'dts',
   662 							'module'    => 'dts',
   643 							'mime_type' => 'audio/dts',
   663 							'mime_type' => 'audio/dts',
   644 						),
   664 						),
   645 
   665 
   720 							'mime_type' => 'audio/s3m',
   740 							'mime_type' => 'audio/s3m',
   721 						),
   741 						),
   722 
   742 
   723 				// MPC  - audio       - Musepack / MPEGplus
   743 				// MPC  - audio       - Musepack / MPEGplus
   724 				'mpc'  => array(
   744 				'mpc'  => array(
   725 							'pattern'   => '^(MPCK|MP\+|[\x00\x01\x10\x11\x40\x41\x50\x51\x80\x81\x90\x91\xC0\xC1\xD0\xD1][\x20-37][\x00\x20\x40\x60\x80\xA0\xC0\xE0])',
   745 							'pattern'   => '^(MPCK|MP\\+|[\\x00\\x01\\x10\\x11\\x40\\x41\\x50\\x51\\x80\\x81\\x90\\x91\\xC0\\xC1\\xD0\\xD1][\\x20-\\x37][\\x00\\x20\\x40\\x60\\x80\\xA0\\xC0\\xE0])',
   726 							'group'     => 'audio',
   746 							'group'     => 'audio',
   727 							'module'    => 'mpc',
   747 							'module'    => 'mpc',
   728 							'mime_type' => 'audio/x-musepack',
   748 							'mime_type' => 'audio/x-musepack',
   729 						),
   749 						),
   730 
   750 
   731 				// MP3  - audio       - MPEG-audio Layer 3 (very similar to AAC-ADTS)
   751 				// MP3  - audio       - MPEG-audio Layer 3 (very similar to AAC-ADTS)
   732 				'mp3'  => array(
   752 				'mp3'  => array(
   733 							'pattern'   => '^\xFF[\xE2-\xE7\xF2-\xF7\xFA-\xFF][\x00-\x0B\x10-\x1B\x20-\x2B\x30-\x3B\x40-\x4B\x50-\x5B\x60-\x6B\x70-\x7B\x80-\x8B\x90-\x9B\xA0-\xAB\xB0-\xBB\xC0-\xCB\xD0-\xDB\xE0-\xEB\xF0-\xFB]',
   753 							'pattern'   => '^\\xFF[\\xE2-\\xE7\\xF2-\\xF7\\xFA-\\xFF][\\x00-\\x0B\\x10-\\x1B\\x20-\\x2B\\x30-\\x3B\\x40-\\x4B\\x50-\\x5B\\x60-\\x6B\\x70-\\x7B\\x80-\\x8B\\x90-\\x9B\\xA0-\\xAB\\xB0-\\xBB\\xC0-\\xCB\\xD0-\\xDB\\xE0-\\xEB\\xF0-\\xFB]',
   734 							'group'     => 'audio',
   754 							'group'     => 'audio',
   735 							'module'    => 'mp3',
   755 							'module'    => 'mp3',
   736 							'mime_type' => 'audio/mpeg',
   756 							'mime_type' => 'audio/mpeg',
   737 						),
   757 						),
   738 
   758 
   739 				// OFR  - audio       - OptimFROG
   759 				// OFR  - audio       - OptimFROG
   740 				'ofr'  => array(
   760 				'ofr'  => array(
   741 							'pattern'   => '^(\*RIFF|OFR)',
   761 							'pattern'   => '^(\\*RIFF|OFR)',
   742 							'group'     => 'audio',
   762 							'group'     => 'audio',
   743 							'module'    => 'optimfrog',
   763 							'module'    => 'optimfrog',
   744 							'mime_type' => 'application/octet-stream',
   764 							'mime_type' => 'application/octet-stream',
   745 						),
   765 						),
   746 
   766 
   762 							'fail_ape'  => 'ERROR',
   782 							'fail_ape'  => 'ERROR',
   763 						),
   783 						),
   764 
   784 
   765 				// TTA  - audio       - TTA Lossless Audio Compressor (http://tta.corecodec.org)
   785 				// TTA  - audio       - TTA Lossless Audio Compressor (http://tta.corecodec.org)
   766 				'tta'  => array(
   786 				'tta'  => array(
   767 							'pattern'   => '^TTA',  // could also be '^TTA(\x01|\x02|\x03|2|1)'
   787 							'pattern'   => '^TTA',  // could also be '^TTA(\\x01|\\x02|\\x03|2|1)'
   768 							'group'     => 'audio',
   788 							'group'     => 'audio',
   769 							'module'    => 'tta',
   789 							'module'    => 'tta',
   770 							'mime_type' => 'application/octet-stream',
   790 							'mime_type' => 'application/octet-stream',
   771 						),
   791 						),
   772 
   792 
   797 
   817 
   798 				// Audio-Video formats
   818 				// Audio-Video formats
   799 
   819 
   800 				// ASF  - audio/video - Advanced Streaming Format, Windows Media Video, Windows Media Audio
   820 				// ASF  - audio/video - Advanced Streaming Format, Windows Media Video, Windows Media Audio
   801 				'asf'  => array(
   821 				'asf'  => array(
   802 							'pattern'   => '^\x30\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C',
   822 							'pattern'   => '^\\x30\\x26\\xB2\\x75\\x8E\\x66\\xCF\\x11\\xA6\\xD9\\x00\\xAA\\x00\\x62\\xCE\\x6C',
   803 							'group'     => 'audio-video',
   823 							'group'     => 'audio-video',
   804 							'module'    => 'asf',
   824 							'module'    => 'asf',
   805 							'mime_type' => 'video/x-ms-asf',
   825 							'mime_type' => 'video/x-ms-asf',
   806 							'iconv_req' => false,
   826 							'iconv_req' => false,
   807 						),
   827 						),
   814 							'mime_type' => 'application/octet-stream',
   834 							'mime_type' => 'application/octet-stream',
   815 						),
   835 						),
   816 
   836 
   817 				// FLV  - audio/video - FLash Video
   837 				// FLV  - audio/video - FLash Video
   818 				'flv' => array(
   838 				'flv' => array(
   819 							'pattern'   => '^FLV\x01',
   839 							'pattern'   => '^FLV[\\x01]',
   820 							'group'     => 'audio-video',
   840 							'group'     => 'audio-video',
   821 							'module'    => 'flv',
   841 							'module'    => 'flv',
   822 							'mime_type' => 'video/x-flv',
   842 							'mime_type' => 'video/x-flv',
   823 						),
   843 						),
   824 
   844 
   825 				// MKAV - audio/video - Mastroka
   845 				// MKAV - audio/video - Mastroka
   826 				'matroska' => array(
   846 				'matroska' => array(
   827 							'pattern'   => '^\x1A\x45\xDF\xA3',
   847 							'pattern'   => '^\\x1A\\x45\\xDF\\xA3',
   828 							'group'     => 'audio-video',
   848 							'group'     => 'audio-video',
   829 							'module'    => 'matroska',
   849 							'module'    => 'matroska',
   830 							'mime_type' => 'video/x-matroska', // may also be audio/x-matroska
   850 							'mime_type' => 'video/x-matroska', // may also be audio/x-matroska
   831 						),
   851 						),
   832 
   852 
   833 				// MPEG - audio/video - MPEG (Moving Pictures Experts Group)
   853 				// MPEG - audio/video - MPEG (Moving Pictures Experts Group)
   834 				'mpeg' => array(
   854 				'mpeg' => array(
   835 							'pattern'   => '^\x00\x00\x01(\xBA|\xB3)',
   855 							'pattern'   => '^\\x00\\x00\\x01[\\xB3\\xBA]',
   836 							'group'     => 'audio-video',
   856 							'group'     => 'audio-video',
   837 							'module'    => 'mpeg',
   857 							'module'    => 'mpeg',
   838 							'mime_type' => 'video/mpeg',
   858 							'mime_type' => 'video/mpeg',
   839 						),
   859 						),
   840 
   860 
   867 				// RIFF - audio/video - Resource Interchange File Format (RIFF) / WAV / AVI / CD-audio / SDSS = renamed variant used by SmartSound QuickTracks (www.smartsound.com) / FORM = Audio Interchange File Format (AIFF)
   887 				// RIFF - audio/video - Resource Interchange File Format (RIFF) / WAV / AVI / CD-audio / SDSS = renamed variant used by SmartSound QuickTracks (www.smartsound.com) / FORM = Audio Interchange File Format (AIFF)
   868 				'riff' => array(
   888 				'riff' => array(
   869 							'pattern'   => '^(RIFF|SDSS|FORM)',
   889 							'pattern'   => '^(RIFF|SDSS|FORM)',
   870 							'group'     => 'audio-video',
   890 							'group'     => 'audio-video',
   871 							'module'    => 'riff',
   891 							'module'    => 'riff',
   872 							'mime_type' => 'audio/x-wave',
   892 							'mime_type' => 'audio/x-wav',
   873 							'fail_ape'  => 'WARNING',
   893 							'fail_ape'  => 'WARNING',
   874 						),
   894 						),
   875 
   895 
   876 				// Real - audio/video - RealAudio, RealVideo
   896 				// Real - audio/video - RealAudio, RealVideo
   877 				'real' => array(
   897 				'real' => array(
   878 							'pattern'   => '^(\\.RMF|\\.ra)',
   898 							'pattern'   => '^\\.(RMF|ra)',
   879 							'group'     => 'audio-video',
   899 							'group'     => 'audio-video',
   880 							'module'    => 'real',
   900 							'module'    => 'real',
   881 							'mime_type' => 'audio/x-realaudio',
   901 							'mime_type' => 'audio/x-realaudio',
   882 						),
   902 						),
   883 
   903 
   889 							'mime_type' => 'application/x-shockwave-flash',
   909 							'mime_type' => 'application/x-shockwave-flash',
   890 						),
   910 						),
   891 
   911 
   892 				// TS - audio/video - MPEG-2 Transport Stream
   912 				// TS - audio/video - MPEG-2 Transport Stream
   893 				'ts' => array(
   913 				'ts' => array(
   894 							'pattern'   => '^(\x47.{187}){10,}', // packets are 188 bytes long and start with 0x47 "G".  Check for at least 10 packets matching this pattern
   914 							'pattern'   => '^(\\x47.{187}){10,}', // packets are 188 bytes long and start with 0x47 "G".  Check for at least 10 packets matching this pattern
   895 							'group'     => 'audio-video',
   915 							'group'     => 'audio-video',
   896 							'module'    => 'ts',
   916 							'module'    => 'ts',
   897 							'mime_type' => 'video/MP2T',
   917 							'mime_type' => 'video/MP2T',
   898 						),
   918 						),
   899 
   919 
   920 							'fail_ape'  => 'ERROR',
   940 							'fail_ape'  => 'ERROR',
   921 						),
   941 						),
   922 
   942 
   923 				// JPEG - still image - Joint Photographic Experts Group (JPEG)
   943 				// JPEG - still image - Joint Photographic Experts Group (JPEG)
   924 				'jpg'  => array(
   944 				'jpg'  => array(
   925 							'pattern'   => '^\xFF\xD8\xFF',
   945 							'pattern'   => '^\\xFF\\xD8\\xFF',
   926 							'group'     => 'graphic',
   946 							'group'     => 'graphic',
   927 							'module'    => 'jpg',
   947 							'module'    => 'jpg',
   928 							'mime_type' => 'image/jpeg',
   948 							'mime_type' => 'image/jpeg',
   929 							'fail_id3'  => 'ERROR',
   949 							'fail_id3'  => 'ERROR',
   930 							'fail_ape'  => 'ERROR',
   950 							'fail_ape'  => 'ERROR',
   931 						),
   951 						),
   932 
   952 
   933 				// PCD  - still image - Kodak Photo CD
   953 				// PCD  - still image - Kodak Photo CD
   934 				'pcd'  => array(
   954 				'pcd'  => array(
   935 							'pattern'   => '^.{2048}PCD_IPI\x00',
   955 							'pattern'   => '^.{2048}PCD_IPI\\x00',
   936 							'group'     => 'graphic',
   956 							'group'     => 'graphic',
   937 							'module'    => 'pcd',
   957 							'module'    => 'pcd',
   938 							'mime_type' => 'image/x-photo-cd',
   958 							'mime_type' => 'image/x-photo-cd',
   939 							'fail_id3'  => 'ERROR',
   959 							'fail_id3'  => 'ERROR',
   940 							'fail_ape'  => 'ERROR',
   960 							'fail_ape'  => 'ERROR',
   941 						),
   961 						),
   942 
   962 
   943 
   963 
   944 				// PNG  - still image - Portable Network Graphics (PNG)
   964 				// PNG  - still image - Portable Network Graphics (PNG)
   945 				'png'  => array(
   965 				'png'  => array(
   946 							'pattern'   => '^\x89\x50\x4E\x47\x0D\x0A\x1A\x0A',
   966 							'pattern'   => '^\\x89\\x50\\x4E\\x47\\x0D\\x0A\\x1A\\x0A',
   947 							'group'     => 'graphic',
   967 							'group'     => 'graphic',
   948 							'module'    => 'png',
   968 							'module'    => 'png',
   949 							'mime_type' => 'image/png',
   969 							'mime_type' => 'image/png',
   950 							'fail_id3'  => 'ERROR',
   970 							'fail_id3'  => 'ERROR',
   951 							'fail_ape'  => 'ERROR',
   971 							'fail_ape'  => 'ERROR',
   952 						),
   972 						),
   953 
   973 
   954 
   974 
   955 				// SVG  - still image - Scalable Vector Graphics (SVG)
   975 				// SVG  - still image - Scalable Vector Graphics (SVG)
   956 				'svg'  => array(
   976 				'svg'  => array(
   957 							'pattern'   => '(<!DOCTYPE svg PUBLIC |xmlns="http:\/\/www\.w3\.org\/2000\/svg")',
   977 							'pattern'   => '(<!DOCTYPE svg PUBLIC |xmlns="http://www\\.w3\\.org/2000/svg")',
   958 							'group'     => 'graphic',
   978 							'group'     => 'graphic',
   959 							'module'    => 'svg',
   979 							'module'    => 'svg',
   960 							'mime_type' => 'image/svg+xml',
   980 							'mime_type' => 'image/svg+xml',
   961 							'fail_id3'  => 'ERROR',
   981 							'fail_id3'  => 'ERROR',
   962 							'fail_ape'  => 'ERROR',
   982 							'fail_ape'  => 'ERROR',
   963 						),
   983 						),
   964 
   984 
   965 
   985 
   966 				// TIFF - still image - Tagged Information File Format (TIFF)
   986 				// TIFF - still image - Tagged Information File Format (TIFF)
   967 				'tiff' => array(
   987 				'tiff' => array(
   968 							'pattern'   => '^(II\x2A\x00|MM\x00\x2A)',
   988 							'pattern'   => '^(II\\x2A\\x00|MM\\x00\\x2A)',
   969 							'group'     => 'graphic',
   989 							'group'     => 'graphic',
   970 							'module'    => 'tiff',
   990 							'module'    => 'tiff',
   971 							'mime_type' => 'image/tiff',
   991 							'mime_type' => 'image/tiff',
   972 							'fail_id3'  => 'ERROR',
   992 							'fail_id3'  => 'ERROR',
   973 							'fail_ape'  => 'ERROR',
   993 							'fail_ape'  => 'ERROR',
   974 						),
   994 						),
   975 
   995 
   976 
   996 
   977 				// EFAX - still image - eFax (TIFF derivative)
   997 				// EFAX - still image - eFax (TIFF derivative)
   978 				'efax'  => array(
   998 				'efax'  => array(
   979 							'pattern'   => '^\xDC\xFE',
   999 							'pattern'   => '^\\xDC\\xFE',
   980 							'group'     => 'graphic',
  1000 							'group'     => 'graphic',
   981 							'module'    => 'efax',
  1001 							'module'    => 'efax',
   982 							'mime_type' => 'image/efax',
  1002 							'mime_type' => 'image/efax',
   983 							'fail_id3'  => 'ERROR',
  1003 							'fail_id3'  => 'ERROR',
   984 							'fail_ape'  => 'ERROR',
  1004 							'fail_ape'  => 'ERROR',
   998 							'iconv_req' => false,
  1018 							'iconv_req' => false,
   999 						),
  1019 						),
  1000 
  1020 
  1001 				// RAR  - data        - RAR compressed data
  1021 				// RAR  - data        - RAR compressed data
  1002 				'rar'  => array(
  1022 				'rar'  => array(
  1003 							'pattern'   => '^Rar\!',
  1023 							'pattern'   => '^Rar\\!',
  1004 							'group'     => 'archive',
  1024 							'group'     => 'archive',
  1005 							'module'    => 'rar',
  1025 							'module'    => 'rar',
  1006 							'mime_type' => 'application/octet-stream',
  1026 							'mime_type' => 'application/octet-stream',
  1007 							'fail_id3'  => 'ERROR',
  1027 							'fail_id3'  => 'ERROR',
  1008 							'fail_ape'  => 'ERROR',
  1028 							'fail_ape'  => 'ERROR',
  1009 						),
  1029 						),
  1010 
  1030 
  1011 				// SZIP - audio/data  - SZIP compressed data
  1031 				// SZIP - audio/data  - SZIP compressed data
  1012 				'szip' => array(
  1032 				'szip' => array(
  1013 							'pattern'   => '^SZ\x0A\x04',
  1033 							'pattern'   => '^SZ\\x0A\\x04',
  1014 							'group'     => 'archive',
  1034 							'group'     => 'archive',
  1015 							'module'    => 'szip',
  1035 							'module'    => 'szip',
  1016 							'mime_type' => 'application/octet-stream',
  1036 							'mime_type' => 'application/octet-stream',
  1017 							'fail_id3'  => 'ERROR',
  1037 							'fail_id3'  => 'ERROR',
  1018 							'fail_ape'  => 'ERROR',
  1038 							'fail_ape'  => 'ERROR',
  1019 						),
  1039 						),
  1020 
  1040 
  1021 				// TAR  - data        - TAR compressed data
  1041 				// TAR  - data        - TAR compressed data
  1022 				'tar'  => array(
  1042 				'tar'  => array(
  1023 							'pattern'   => '^.{100}[0-9\x20]{7}\x00[0-9\x20]{7}\x00[0-9\x20]{7}\x00[0-9\x20\x00]{12}[0-9\x20\x00]{12}',
  1043 							'pattern'   => '^.{100}[0-9\\x20]{7}\\x00[0-9\\x20]{7}\\x00[0-9\\x20]{7}\\x00[0-9\\x20\\x00]{12}[0-9\\x20\\x00]{12}',
  1024 							'group'     => 'archive',
  1044 							'group'     => 'archive',
  1025 							'module'    => 'tar',
  1045 							'module'    => 'tar',
  1026 							'mime_type' => 'application/x-tar',
  1046 							'mime_type' => 'application/x-tar',
  1027 							'fail_id3'  => 'ERROR',
  1047 							'fail_id3'  => 'ERROR',
  1028 							'fail_ape'  => 'ERROR',
  1048 							'fail_ape'  => 'ERROR',
  1029 						),
  1049 						),
  1030 
  1050 
  1031 				// GZIP  - data        - GZIP compressed data
  1051 				// GZIP  - data        - GZIP compressed data
  1032 				'gz'  => array(
  1052 				'gz'  => array(
  1033 							'pattern'   => '^\x1F\x8B\x08',
  1053 							'pattern'   => '^\\x1F\\x8B\\x08',
  1034 							'group'     => 'archive',
  1054 							'group'     => 'archive',
  1035 							'module'    => 'gzip',
  1055 							'module'    => 'gzip',
  1036 							'mime_type' => 'application/x-gzip',
  1056 							'mime_type' => 'application/x-gzip',
  1037 							'fail_id3'  => 'ERROR',
  1057 							'fail_id3'  => 'ERROR',
  1038 							'fail_ape'  => 'ERROR',
  1058 							'fail_ape'  => 'ERROR',
  1039 						),
  1059 						),
  1040 
  1060 
  1041 				// ZIP  - data         - ZIP compressed data
  1061 				// ZIP  - data         - ZIP compressed data
  1042 				'zip'  => array(
  1062 				'zip'  => array(
  1043 							'pattern'   => '^PK\x03\x04',
  1063 							'pattern'   => '^PK\\x03\\x04',
  1044 							'group'     => 'archive',
  1064 							'group'     => 'archive',
  1045 							'module'    => 'zip',
  1065 							'module'    => 'zip',
  1046 							'mime_type' => 'application/zip',
  1066 							'mime_type' => 'application/zip',
  1047 							'fail_id3'  => 'ERROR',
  1067 							'fail_id3'  => 'ERROR',
  1048 							'fail_ape'  => 'ERROR',
  1068 							'fail_ape'  => 'ERROR',
  1051 
  1071 
  1052 				// Misc other formats
  1072 				// Misc other formats
  1053 
  1073 
  1054 				// PAR2 - data        - Parity Volume Set Specification 2.0
  1074 				// PAR2 - data        - Parity Volume Set Specification 2.0
  1055 				'par2' => array (
  1075 				'par2' => array (
  1056 							'pattern'   => '^PAR2\x00PKT',
  1076 							'pattern'   => '^PAR2\\x00PKT',
  1057 							'group'     => 'misc',
  1077 							'group'     => 'misc',
  1058 							'module'    => 'par2',
  1078 							'module'    => 'par2',
  1059 							'mime_type' => 'application/octet-stream',
  1079 							'mime_type' => 'application/octet-stream',
  1060 							'fail_id3'  => 'ERROR',
  1080 							'fail_id3'  => 'ERROR',
  1061 							'fail_ape'  => 'ERROR',
  1081 							'fail_ape'  => 'ERROR',
  1062 						),
  1082 						),
  1063 
  1083 
  1064 				// PDF  - data        - Portable Document Format
  1084 				// PDF  - data        - Portable Document Format
  1065 				'pdf'  => array(
  1085 				'pdf'  => array(
  1066 							'pattern'   => '^\x25PDF',
  1086 							'pattern'   => '^\\x25PDF',
  1067 							'group'     => 'misc',
  1087 							'group'     => 'misc',
  1068 							'module'    => 'pdf',
  1088 							'module'    => 'pdf',
  1069 							'mime_type' => 'application/pdf',
  1089 							'mime_type' => 'application/pdf',
  1070 							'fail_id3'  => 'ERROR',
  1090 							'fail_id3'  => 'ERROR',
  1071 							'fail_ape'  => 'ERROR',
  1091 							'fail_ape'  => 'ERROR',
  1072 						),
  1092 						),
  1073 
  1093 
  1074 				// MSOFFICE  - data   - ZIP compressed data
  1094 				// MSOFFICE  - data   - ZIP compressed data
  1075 				'msoffice' => array(
  1095 				'msoffice' => array(
  1076 							'pattern'   => '^\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1', // D0CF11E == DOCFILE == Microsoft Office Document
  1096 							'pattern'   => '^\\xD0\\xCF\\x11\\xE0\\xA1\\xB1\\x1A\\xE1', // D0CF11E == DOCFILE == Microsoft Office Document
  1077 							'group'     => 'misc',
  1097 							'group'     => 'misc',
  1078 							'module'    => 'msoffice',
  1098 							'module'    => 'msoffice',
  1079 							'mime_type' => 'application/octet-stream',
  1099 							'mime_type' => 'application/octet-stream',
  1080 							'fail_id3'  => 'ERROR',
  1100 							'fail_id3'  => 'ERROR',
  1081 							'fail_ape'  => 'ERROR',
  1101 							'fail_ape'  => 'ERROR',
  1112 				return $info;
  1132 				return $info;
  1113 			}
  1133 			}
  1114 		}
  1134 		}
  1115 
  1135 
  1116 
  1136 
  1117 		if (preg_match('#\.mp[123a]$#i', $filename)) {
  1137 		if (preg_match('#\\.mp[123a]$#i', $filename)) {
  1118 			// Too many mp3 encoders on the market put gabage in front of mpeg files
  1138 			// Too many mp3 encoders on the market put gabage in front of mpeg files
  1119 			// use assume format on these if format detection failed
  1139 			// use assume format on these if format detection failed
  1120 			$GetFileFormatArray = $this->GetFileFormatArray();
  1140 			$GetFileFormatArray = $this->GetFileFormatArray();
  1121 			$info = $GetFileFormatArray['mp3'];
  1141 			$info = $GetFileFormatArray['mp3'];
  1122 			$info['include'] = 'module.'.$info['group'].'.'.$info['module'].'.php';
  1142 			$info['include'] = 'module.'.$info['group'].'.'.$info['module'].'.php';
  1123 			return $info;
  1143 			return $info;
  1124 		} elseif (preg_match('/\.cue$/i', $filename) && preg_match('#FILE "[^"]+" (BINARY|MOTOROLA|AIFF|WAVE|MP3)#', $filedata)) {
  1144 		} elseif (preg_match('#\\.cue$#i', $filename) && preg_match('#FILE "[^"]+" (BINARY|MOTOROLA|AIFF|WAVE|MP3)#', $filedata)) {
  1125 			// there's not really a useful consistent "magic" at the beginning of .cue files to identify them
  1145 			// there's not really a useful consistent "magic" at the beginning of .cue files to identify them
  1126 			// so until I think of something better, just go by filename if all other format checks fail
  1146 			// so until I think of something better, just go by filename if all other format checks fail
  1127 			// and verify there's at least one instance of "TRACK xx AUDIO" in the file
  1147 			// and verify there's at least one instance of "TRACK xx AUDIO" in the file
  1128 			$GetFileFormatArray = $this->GetFileFormatArray();
  1148 			$GetFileFormatArray = $this->GetFileFormatArray();
  1129 			$info = $GetFileFormatArray['cue'];
  1149 			$info = $GetFileFormatArray['cue'];
  1220 				if (!isset($this->info['tags'][$tag_name])) {
  1240 				if (!isset($this->info['tags'][$tag_name])) {
  1221 					// comments are set but contain nothing but empty strings, so skip
  1241 					// comments are set but contain nothing but empty strings, so skip
  1222 					continue;
  1242 					continue;
  1223 				}
  1243 				}
  1224 
  1244 
       
  1245 				$this->CharConvert($this->info['tags'][$tag_name], $this->info[$comment_name]['encoding']);           // only copy gets converted!
       
  1246 
  1225 				if ($this->option_tags_html) {
  1247 				if ($this->option_tags_html) {
  1226 					foreach ($this->info['tags'][$tag_name] as $tag_key => $valuearray) {
  1248 					foreach ($this->info['tags'][$tag_name] as $tag_key => $valuearray) {
  1227 						$this->info['tags_html'][$tag_name][$tag_key] = getid3_lib::recursiveMultiByteCharString2HTML($valuearray, $encoding);
  1249 						$this->info['tags_html'][$tag_name][$tag_key] = getid3_lib::recursiveMultiByteCharString2HTML($valuearray, $this->info[$comment_name]['encoding']);
  1228 					}
  1250 					}
  1229 				}
  1251 				}
  1230 
  1252 
  1231 				$this->CharConvert($this->info['tags'][$tag_name], $encoding);           // only copy gets converted!
       
  1232 			}
  1253 			}
  1233 
  1254 
  1234 		}
  1255 		}
  1235 
  1256 
  1236 		// pictures can take up a lot of space, and we don't need multiple copies of them
  1257 		// pictures can take up a lot of space, and we don't need multiple copies of them
  1350 
  1371 
  1351 				}
  1372 				}
  1352 
  1373 
  1353 				if (!empty($VorbisCommentError)) {
  1374 				if (!empty($VorbisCommentError)) {
  1354 
  1375 
  1355 					$this->info['warning'][]         = 'Failed making system call to vorbiscomment(.exe) - '.$algorithm.'_data will be incorrect. If vorbiscomment is unavailable, please download from http://www.vorbis.com/download.psp and put in the getID3() directory. Error returned: '.$VorbisCommentError;
  1376 					$this->warning('Failed making system call to vorbiscomment(.exe) - '.$algorithm.'_data will be incorrect. If vorbiscomment is unavailable, please download from http://www.vorbis.com/download.psp and put in the getID3() directory. Error returned: '.$VorbisCommentError);
  1356 					$this->info[$algorithm.'_data']  = false;
  1377 					$this->info[$algorithm.'_data'] = false;
  1357 
  1378 
  1358 				} else {
  1379 				} else {
  1359 
  1380 
  1360 					// Get hash of newly created file
  1381 					// Get hash of newly created file
  1361 					switch ($algorithm) {
  1382 					switch ($algorithm) {
  1580 		}
  1601 		}
  1581 		include_once(GETID3_INCLUDEPATH.'module.'.$name.'.php');
  1602 		include_once(GETID3_INCLUDEPATH.'module.'.$name.'.php');
  1582 		return true;
  1603 		return true;
  1583 	}
  1604 	}
  1584 
  1605 
       
  1606     public static function is_writable ($filename) {
       
  1607         $ret = is_writable($filename);
       
  1608 
       
  1609         if (!$ret) {
       
  1610             $perms = fileperms($filename);
       
  1611             $ret = ($perms & 0x0080) || ($perms & 0x0010) || ($perms & 0x0002);
       
  1612         }
       
  1613 
       
  1614         return $ret;
       
  1615     }
       
  1616 
  1585 }
  1617 }
  1586 
  1618 
  1587 
  1619 
  1588 abstract class getid3_handler {
  1620 abstract class getid3_handler {
  1589 
  1621 
  1659 		}
  1691 		}
  1660 		$pos = $this->ftell() + $bytes;
  1692 		$pos = $this->ftell() + $bytes;
  1661 		if (!getid3_lib::intValueSupported($pos)) {
  1693 		if (!getid3_lib::intValueSupported($pos)) {
  1662 			throw new getid3_exception('cannot fread('.$bytes.' from '.$this->ftell().') because beyond PHP filesystem limit', 10);
  1694 			throw new getid3_exception('cannot fread('.$bytes.' from '.$this->ftell().') because beyond PHP filesystem limit', 10);
  1663 		}
  1695 		}
  1664 		return fread($this->getid3->fp, $bytes);
  1696 
       
  1697 		//return fread($this->getid3->fp, $bytes);
       
  1698 		/*
       
  1699 		* http://www.getid3.org/phpBB3/viewtopic.php?t=1930
       
  1700 		* "I found out that the root cause for the problem was how getID3 uses the PHP system function fread().
       
  1701 		* It seems to assume that fread() would always return as many bytes as were requested.
       
  1702 		* However, according the PHP manual (http://php.net/manual/en/function.fread.php), this is the case only with regular local files, but not e.g. with Linux pipes.
       
  1703 		* The call may return only part of the requested data and a new call is needed to get more."
       
  1704 		*/
       
  1705 		$contents = '';
       
  1706 		do {
       
  1707 			$part = fread($this->getid3->fp, $bytes);
       
  1708 			$partLength  = strlen($part);
       
  1709 			$bytes      -= $partLength;
       
  1710 			$contents   .= $part;
       
  1711 		} while (($bytes > 0) && ($partLength > 0));
       
  1712 		return $contents;
  1665 	}
  1713 	}
  1666 
  1714 
  1667 	protected function fseek($bytes, $whence=SEEK_SET) {
  1715 	protected function fseek($bytes, $whence=SEEK_SET) {
  1668 		if ($this->data_string_flag) {
  1716 		if ($this->data_string_flag) {
  1669 			switch ($whence) {
  1717 			switch ($whence) {
  1739 			// assume directory path is given
  1787 			// assume directory path is given
  1740 			} else {
  1788 			} else {
  1741 
  1789 
  1742 				// set up destination path
  1790 				// set up destination path
  1743 				$dir = rtrim(str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $this->getid3->option_save_attachments), DIRECTORY_SEPARATOR);
  1791 				$dir = rtrim(str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $this->getid3->option_save_attachments), DIRECTORY_SEPARATOR);
  1744 				if (!is_dir($dir) || !is_writable($dir)) { // check supplied directory
  1792 				if (!is_dir($dir) || !getID3::is_writable($dir)) { // check supplied directory
  1745 					throw new Exception('supplied path ('.$dir.') does not exist, or is not writable');
  1793 					throw new Exception('supplied path ('.$dir.') does not exist, or is not writable');
  1746 				}
  1794 				}
  1747 				$dest = $dir.DIRECTORY_SEPARATOR.$name.($image_mime ? '.'.getid3_lib::ImageExtFromMime($image_mime) : '');
  1795 				$dest = $dir.DIRECTORY_SEPARATOR.$name.($image_mime ? '.'.getid3_lib::ImageExtFromMime($image_mime) : '');
  1748 
  1796 
  1749 				// create dest file
  1797 				// create dest file