Mercurial > judyates
diff e2gallerypro/e2upload/Backend/Assets/getid3/getid3.php @ 3:3f6b44aa6b35 judyates
[svn r4] added ability to buy stuff, from a Prints page, but it doesn't work well with the css, and it also has not been fitted into the perl make system.
author | rlm |
---|---|
date | Mon, 22 Feb 2010 08:02:39 -0500 |
parents | |
children |
line wrap: on
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/e2gallerypro/e2upload/Backend/Assets/getid3/getid3.php Mon Feb 22 08:02:39 2010 -0500 1.3 @@ -0,0 +1,1598 @@ 1.4 +<?php 1.5 +// +----------------------------------------------------------------------+ 1.6 +// | PHP version 5 | 1.7 +// +----------------------------------------------------------------------+ 1.8 +// | Copyright (c) 2002-2006 James Heinrich, Allan Hansen | 1.9 +// +----------------------------------------------------------------------+ 1.10 +// | This source file is subject to version 2 of the GPL license, | 1.11 +// | that is bundled with this package in the file license.txt and is | 1.12 +// | available through the world-wide-web at the following url: | 1.13 +// | http://www.gnu.org/copyleft/gpl.html | 1.14 +// +----------------------------------------------------------------------+ 1.15 +// | getID3() - http://getid3.sourceforge.net or http://www.getid3.org | 1.16 +// +----------------------------------------------------------------------+ 1.17 +// | Authors: James Heinrich <infogetid3*org> | 1.18 +// | Allan Hansen <ahartemis*dk> | 1.19 +// +----------------------------------------------------------------------+ 1.20 +// | getid3.php | 1.21 +// | Main getID3() file. | 1.22 +// | dependencies: modules. | 1.23 +// +----------------------------------------------------------------------+ 1.24 +// 1.25 +// $Id: getid3.php,v 1.26 2006/12/25 23:44:23 ah Exp $ 1.26 + 1.27 + 1.28 +class getid3 1.29 +{ 1.30 + //// Settings Section - do NOT modify this file - change setting after newing getid3! 1.31 + 1.32 + // Encoding 1.33 + public $encoding = 'ISO-8859-1'; // CASE SENSITIVE! - i.e. (must be supported by iconv() - see http://www.gnu.org/software/libiconv/). Examples: ISO-8859-1 UTF-8 UTF-16 UTF-16BE. 1.34 + public $encoding_id3v1 = 'ISO-8859-1'; // Override SPECIFICATION encoding for broken ID3v1 tags caused by bad tag programs. Examples: 'EUC-CN' for "Chinese MP3s" and 'CP1251' for "Cyrillic". 1.35 + public $encoding_id3v2 = 'ISO-8859-1'; // Override ISO-8859-1 encoding for broken ID3v2 tags caused by BRAINDEAD tag programs that writes system codepage as 'ISO-8859-1' instead of UTF-8. 1.36 + 1.37 + // Tags - disable for speed 1.38 + public $option_tag_id3v1 = true; // Read and process ID3v1 tags. 1.39 + public $option_tag_id3v2 = true; // Read and process ID3v2 tags. 1.40 + public $option_tag_lyrics3 = true; // Read and process Lyrics3 tags. 1.41 + public $option_tag_apetag = true; // Read and process APE tags. 1.42 + 1.43 + // Misc calucations - disable for speed 1.44 + public $option_analyze = true; // Analyze file - disable if you only need to detect file format. 1.45 + public $option_accurate_results = true; // Disable to greatly speed up parsing of some file formats at the cost of accuracy. 1.46 + public $option_tags_process = true; // Copy tags to root key 'tags' and 'comments' and encode to $this->encoding. 1.47 + public $option_tags_images = false; // Scan tags for binary image data - ID3v2 and vorbiscomments only. 1.48 + public $option_extra_info = true; // Calculate/return additional info such as bitrate, channelmode etc. 1.49 + public $option_max_2gb_check = false; // Check whether file is larger than 2 Gb and thus not supported by PHP. 1.50 + 1.51 + // Misc data hashes - slow - require hash module 1.52 + public $option_md5_data = false; // Get MD5 sum of data part - slow. 1.53 + public $option_md5_data_source = false; // Use MD5 of source file if available - only FLAC, MAC, OptimFROG and Wavpack4. 1.54 + public $option_sha1_data = false; // Get SHA1 sum of data part - slow. 1.55 + 1.56 + // Public variables 1.57 + public $filename; // Filename of file being analysed. 1.58 + public $fp; // Filepointer to file being analysed. 1.59 + public $info; // Result array. 1.60 + 1.61 + // Protected variables 1.62 + protected $include_path; // getid3 include path. 1.63 + protected $warnings = array (); 1.64 + protected $iconv_present; 1.65 + 1.66 + // Class constants 1.67 + const VERSION = '2.0.0b4'; 1.68 + const FREAD_BUFFER_SIZE = 16384; // Read buffer size in bytes. 1.69 + const ICONV_TEST_STRING = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ '; 1.70 + 1.71 + 1.72 + 1.73 + // Constructor - check PHP enviroment and load library. 1.74 + public function __construct() { 1.75 + 1.76 + // Static varibles - no need to recalc every time we new getid3. 1.77 + static $include_path; 1.78 + static $iconv_present; 1.79 + 1.80 + 1.81 + static $initialized; 1.82 + if ($initialized) { 1.83 + 1.84 + // Import static variables 1.85 + $this->include_path = $include_path; 1.86 + $this->iconv_present = $iconv_present; 1.87 + 1.88 + // Run init checks only on first instance. 1.89 + return; 1.90 + } 1.91 + 1.92 + // Get include_path 1.93 + $this->include_path = $include_path = dirname(__FILE__) . '/'; 1.94 + 1.95 + // Check for presence of iconv() and make sure it works (simpel test only). 1.96 + if (function_exists('iconv') && @iconv('UTF-16LE', 'ISO-8859-1', @iconv('ISO-8859-1', 'UTF-16LE', getid3::ICONV_TEST_STRING)) == getid3::ICONV_TEST_STRING) { 1.97 + $this->iconv_present = $iconv_present = true; 1.98 + } 1.99 + 1.100 + // iconv() not present - load replacement module. 1.101 + else { 1.102 + $this->include_module('lib.iconv_replacement'); 1.103 + $this->iconv_present = $iconv_present = false; 1.104 + } 1.105 + 1.106 + 1.107 + // Require magic_quotes_runtime off 1.108 + if (get_magic_quotes_runtime()) { 1.109 + throw new getid3_exception('magic_quotes_runtime must be disabled before running getID3(). Surround getid3 block by set_magic_quotes_runtime(0) and set_magic_quotes_runtime(1).'); 1.110 + } 1.111 + 1.112 + 1.113 + // Check memory limit. 1.114 + $memory_limit = ini_get('memory_limit'); 1.115 + if (eregi('([0-9]+)M', $memory_limit, $matches)) { 1.116 + // could be stored as "16M" rather than 16777216 for example 1.117 + $memory_limit = $matches[1] * 1048576; 1.118 + } 1.119 + if ($memory_limit <= 0) { 1.120 + // Should not happen. 1.121 + } elseif ($memory_limit <= 4194304) { 1.122 + $this->warning('[SERIOUS] PHP has less than 4 Mb available memory and will very likely run out. Increase memory_limit in php.ini.'); 1.123 + } elseif ($memory_limit <= 12582912) { 1.124 + $this->warning('PHP has less than 12 Mb available memory and might run out if all modules are loaded. Increase memory_limit in php.ini if needed.'); 1.125 + } 1.126 + 1.127 + 1.128 + // Check safe_mode off 1.129 + if ((bool)ini_get('safe_mode')) { 1.130 + $this->warning('Safe mode is on, shorten support disabled, md5data/sha1data for ogg vorbis disabled, ogg vorbis/flac tag writing disabled.'); 1.131 + } 1.132 + 1.133 + $initialized = true; 1.134 + } 1.135 + 1.136 + 1.137 + 1.138 + // Analyze file by name 1.139 + public function Analyze($filename) { 1.140 + 1.141 + // Init and save values 1.142 + $this->filename = $filename; 1.143 + $this->warnings = array (); 1.144 + 1.145 + // Init result array and set parameters 1.146 + $this->info = array (); 1.147 + $this->info['GETID3_VERSION'] = getid3::VERSION; 1.148 + 1.149 + // Remote files not supported 1.150 + if (preg_match('/^(ht|f)tp:\/\//', $filename)) { 1.151 + throw new getid3_exception('Remote files are not supported - please copy the file locally first.'); 1.152 + } 1.153 + 1.154 + // Open local file 1.155 + if (!$this->fp = @fopen($filename, 'rb')) { 1.156 + throw new getid3_exception('Could not open file "'.$filename.'"'); 1.157 + } 1.158 + 1.159 + // Set filesize related parameters 1.160 + $this->info['filesize'] = filesize($filename); 1.161 + $this->info['avdataoffset'] = 0; 1.162 + $this->info['avdataend'] = $this->info['filesize']; 1.163 + 1.164 + // Option_max_2gb_check 1.165 + if ($this->option_max_2gb_check) { 1.166 + // PHP doesn't support integers larger than 31-bit (~2GB) 1.167 + // filesize() simply returns (filesize % (pow(2, 32)), no matter the actual filesize 1.168 + // ftell() returns 0 if seeking to the end is beyond the range of unsigned integer 1.169 + fseek($this->fp, 0, SEEK_END); 1.170 + if ((($this->info['filesize'] != 0) && (ftell($this->fp) == 0)) || 1.171 + ($this->info['filesize'] < 0) || 1.172 + (ftell($this->fp) < 0)) { 1.173 + unset($this->info['filesize']); 1.174 + fclose($this->fp); 1.175 + throw new getid3_exception('File is most likely larger than 2GB and is not supported by PHP.'); 1.176 + } 1.177 + } 1.178 + 1.179 + 1.180 + // ID3v2 detection (NOT parsing) done to make fileformat easier. 1.181 + if (!$this->option_tag_id3v2) { 1.182 + 1.183 + fseek($this->fp, 0, SEEK_SET); 1.184 + $header = fread($this->fp, 10); 1.185 + if (substr($header, 0, 3) == 'ID3' && strlen($header) == 10) { 1.186 + $this->info['id3v2']['header'] = true; 1.187 + $this->info['id3v2']['majorversion'] = ord($header{3}); 1.188 + $this->info['id3v2']['minorversion'] = ord($header{4}); 1.189 + $this->info['avdataoffset'] += getid3_lib::BigEndian2Int(substr($header, 6, 4), 1) + 10; // length of ID3v2 tag in 10-byte header doesn't include 10-byte header length 1.190 + } 1.191 + } 1.192 + 1.193 + 1.194 + // Handle tags 1.195 + foreach (array ("id3v2", "id3v1", "apetag", "lyrics3") as $tag_name) { 1.196 + 1.197 + $option_tag = 'option_tag_' . $tag_name; 1.198 + if ($this->$option_tag) { 1.199 + $this->include_module('tag.'.$tag_name); 1.200 + try { 1.201 + $tag_class = 'getid3_' . $tag_name; 1.202 + $tag = new $tag_class($this); 1.203 + $tag->Analyze(); 1.204 + } 1.205 + catch (getid3_exception $e) { 1.206 + throw $e; 1.207 + } 1.208 + } 1.209 + } 1.210 + 1.211 + 1.212 + 1.213 + //// Determine file format by magic bytes in file header. 1.214 + 1.215 + // Read 32 kb file data 1.216 + fseek($this->fp, $this->info['avdataoffset'], SEEK_SET); 1.217 + $filedata = fread($this->fp, 32774); 1.218 + 1.219 + // Get huge FileFormatArray 1.220 + $file_format_array = getid3::GetFileFormatArray(); 1.221 + 1.222 + // Identify file format - loop through $format_info and detect with reg expr 1.223 + foreach ($file_format_array as $name => $info) { 1.224 + 1.225 + if (preg_match('/'.$info['pattern'].'/s', $filedata)) { // The /s switch on preg_match() forces preg_match() NOT to treat newline (0x0A) characters as special chars but do a binary match 1.226 + 1.227 + // Format detected but not supported 1.228 + if (!@$info['module'] || !@$info['group']) { 1.229 + fclose($this->fp); 1.230 + $this->info['fileformat'] = $name; 1.231 + $this->info['mime_type'] = $info['mime_type']; 1.232 + $this->warning('Format only detected. Parsing not available yet.'); 1.233 + $this->info['warning'] = $this->warnings; 1.234 + return $this->info; 1.235 + } 1.236 + 1.237 + $determined_format = $info; // copy $info deleted by foreach() 1.238 + continue; 1.239 + } 1.240 + } 1.241 + 1.242 + // Unable to determine file format 1.243 + if (!@$determined_format) { 1.244 + 1.245 + // Too many mp3 encoders on the market put gabage in front of mpeg files 1.246 + // use assume format on these if format detection failed 1.247 + if (preg_match('/\.mp[123a]$/i', $filename)) { 1.248 + $determined_format = $file_format_array['mp3']; 1.249 + } 1.250 + 1.251 + else { 1.252 + fclose($this->fp); 1.253 + throw new getid3_exception('Unable to determine file format'); 1.254 + } 1.255 + } 1.256 + 1.257 + // Free memory 1.258 + unset($file_format_array); 1.259 + 1.260 + // Check for illegal ID3 tags 1.261 + if (@$determined_format['fail_id3'] && (@$this->info['id3v1'] || @$this->info['id3v2'])) { 1.262 + if ($determined_format['fail_id3'] === 'ERROR') { 1.263 + fclose($this->fp); 1.264 + throw new getid3_exception('ID3 tags not allowed on this file type.'); 1.265 + } 1.266 + elseif ($determined_format['fail_id3'] === 'WARNING') { 1.267 + @$this->info['id3v1'] and $this->warning('ID3v1 tags not allowed on this file type.'); 1.268 + @$this->info['id3v2'] and $this->warning('ID3v2 tags not allowed on this file type.'); 1.269 + } 1.270 + } 1.271 + 1.272 + // Check for illegal APE tags 1.273 + if (@$determined_format['fail_ape'] && @$this->info['tags']['ape']) { 1.274 + if ($determined_format['fail_ape'] === 'ERROR') { 1.275 + fclose($this->fp); 1.276 + throw new getid3_exception('APE tags not allowed on this file type.'); 1.277 + } elseif ($determined_format['fail_ape'] === 'WARNING') { 1.278 + $this->warning('APE tags not allowed on this file type.'); 1.279 + } 1.280 + } 1.281 + 1.282 + 1.283 + // Set mime type 1.284 + $this->info['mime_type'] = $determined_format['mime_type']; 1.285 + 1.286 + // Calc module file name 1.287 + $determined_format['include'] = 'module.'.$determined_format['group'].'.'.$determined_format['module'].'.php'; 1.288 + 1.289 + // Supported format signature pattern detected, but module deleted. 1.290 + if (!file_exists($this->include_path.$determined_format['include'])) { 1.291 + fclose($this->fp); 1.292 + throw new getid3_exception('Format not supported, module, '.$determined_format['include'].', was removed.'); 1.293 + } 1.294 + 1.295 + // Include module 1.296 + $this->include_module($determined_format['group'].'.'.$determined_format['module']); 1.297 + 1.298 + // Instantiate module class and analyze 1.299 + $class_name = 'getid3_'.$determined_format['module']; 1.300 + if (!class_exists($class_name)) { 1.301 + throw new getid3_exception('Format not supported, module, '.$determined_format['include'].', is corrupt.'); 1.302 + } 1.303 + $class = new $class_name($this); 1.304 + 1.305 + try { 1.306 + $this->option_analyze and $class->Analyze(); 1.307 + } 1.308 + catch (getid3_exception $e) { 1.309 + throw $e; 1.310 + } 1.311 + catch (Exception $e) { 1.312 + throw new getid3_exception('Corrupt file.'); 1.313 + } 1.314 + 1.315 + // Close file 1.316 + fclose($this->fp); 1.317 + 1.318 + // Optional - Process all tags - copy to 'tags' and convert charsets 1.319 + if ($this->option_tags_process) { 1.320 + $this->HandleAllTags(); 1.321 + } 1.322 + 1.323 + 1.324 + //// Optional - perform more calculations 1.325 + if ($this->option_extra_info) { 1.326 + 1.327 + // Set channelmode on audio 1.328 + if (@$this->info['audio']['channels'] == '1') { 1.329 + $this->info['audio']['channelmode'] = 'mono'; 1.330 + } elseif (@$this->info['audio']['channels'] == '2') { 1.331 + $this->info['audio']['channelmode'] = 'stereo'; 1.332 + } 1.333 + 1.334 + // Calculate combined bitrate - audio + video 1.335 + $combined_bitrate = 0; 1.336 + $combined_bitrate += (isset($this->info['audio']['bitrate']) ? $this->info['audio']['bitrate'] : 0); 1.337 + $combined_bitrate += (isset($this->info['video']['bitrate']) ? $this->info['video']['bitrate'] : 0); 1.338 + if (($combined_bitrate > 0) && empty($this->info['bitrate'])) { 1.339 + $this->info['bitrate'] = $combined_bitrate; 1.340 + } 1.341 + if (!isset($this->info['playtime_seconds']) && !empty($this->info['bitrate'])) { 1.342 + $this->info['playtime_seconds'] = (($this->info['avdataend'] - $this->info['avdataoffset']) * 8) / $this->info['bitrate']; 1.343 + } 1.344 + 1.345 + // Set playtime string 1.346 + if (!empty($this->info['playtime_seconds']) && empty($this->info['playtime_string'])) { 1.347 + $this->info['playtime_string'] = floor(round($this->info['playtime_seconds']) / 60) . ':' . str_pad(floor(round($this->info['playtime_seconds']) % 60), 2, 0, STR_PAD_LEFT);; 1.348 + } 1.349 + 1.350 + 1.351 + // CalculateCompressionRatioVideo() { 1.352 + if (@$this->info['video'] && @$this->info['video']['resolution_x'] && @$this->info['video']['resolution_y'] && @$this->info['video']['bits_per_sample']) { 1.353 + 1.354 + // From static image formats 1.355 + if (in_array($this->info['video']['dataformat'], array ('bmp', 'gif', 'jpeg', 'jpg', 'png', 'tiff'))) { 1.356 + $frame_rate = 1; 1.357 + $bitrate_compressed = $this->info['filesize'] * 8; 1.358 + } 1.359 + 1.360 + // From video formats 1.361 + else { 1.362 + $frame_rate = @$this->info['video']['frame_rate']; 1.363 + $bitrate_compressed = @$this->info['video']['bitrate']; 1.364 + } 1.365 + 1.366 + if ($frame_rate && $bitrate_compressed) { 1.367 + $this->info['video']['compression_ratio'] = $bitrate_compressed / ($this->info['video']['resolution_x'] * $this->info['video']['resolution_y'] * $this->info['video']['bits_per_sample'] * $frame_rate); 1.368 + } 1.369 + } 1.370 + 1.371 + 1.372 + // CalculateCompressionRatioAudio() { 1.373 + if (@$this->info['audio']['bitrate'] && @$this->info['audio']['channels'] && @$this->info['audio']['sample_rate']) { 1.374 + $this->info['audio']['compression_ratio'] = $this->info['audio']['bitrate'] / ($this->info['audio']['channels'] * $this->info['audio']['sample_rate'] * (@$this->info['audio']['bits_per_sample'] ? $this->info['audio']['bits_per_sample'] : 16)); 1.375 + } 1.376 + 1.377 + if (@$this->info['audio']['streams']) { 1.378 + foreach ($this->info['audio']['streams'] as $stream_number => $stream_data) { 1.379 + if (@$stream_data['bitrate'] && @$stream_data['channels'] && @$stream_data['sample_rate']) { 1.380 + $this->info['audio']['streams'][$stream_number]['compression_ratio'] = $stream_data['bitrate'] / ($stream_data['channels'] * $stream_data['sample_rate'] * (@$stream_data['bits_per_sample'] ? $stream_data['bits_per_sample'] : 16)); 1.381 + } 1.382 + } 1.383 + } 1.384 + 1.385 + 1.386 + // CalculateReplayGain() { 1.387 + if (@$this->info['replay_gain']) { 1.388 + if (!@$this->info['replay_gain']['reference_volume']) { 1.389 + $this->info['replay_gain']['reference_volume'] = 89; 1.390 + } 1.391 + if (isset($this->info['replay_gain']['track']['adjustment'])) { 1.392 + $this->info['replay_gain']['track']['volume'] = $this->info['replay_gain']['reference_volume'] - $this->info['replay_gain']['track']['adjustment']; 1.393 + } 1.394 + if (isset($this->info['replay_gain']['album']['adjustment'])) { 1.395 + $this->info['replay_gain']['album']['volume'] = $this->info['replay_gain']['reference_volume'] - $this->info['replay_gain']['album']['adjustment']; 1.396 + } 1.397 + 1.398 + if (isset($this->info['replay_gain']['track']['peak'])) { 1.399 + $this->info['replay_gain']['track']['max_noclip_gain'] = 0 - 20 * log10($this->info['replay_gain']['track']['peak']); 1.400 + } 1.401 + if (isset($this->info['replay_gain']['album']['peak'])) { 1.402 + $this->info['replay_gain']['album']['max_noclip_gain'] = 0 - 20 * log10($this->info['replay_gain']['album']['peak']); 1.403 + } 1.404 + } 1.405 + 1.406 + 1.407 + // ProcessAudioStreams() { 1.408 + if (@!$this->info['audio']['streams'] && (@$this->info['audio']['bitrate'] || @$this->info['audio']['channels'] || @$this->info['audio']['sample_rate'])) { 1.409 + foreach ($this->info['audio'] as $key => $value) { 1.410 + if ($key != 'streams') { 1.411 + $this->info['audio']['streams'][0][$key] = $value; 1.412 + } 1.413 + } 1.414 + } 1.415 + } 1.416 + 1.417 + 1.418 + // Get the md5/sha1sum of the audio/video portion of the file - without ID3/APE/Lyrics3/etc header/footer tags. 1.419 + if ($this->option_md5_data || $this->option_sha1_data) { 1.420 + 1.421 + // Load data-hash library if needed 1.422 + $this->include_module('lib.data_hash'); 1.423 + 1.424 + if ($this->option_sha1_data) { 1.425 + new getid3_lib_data_hash($this, 'sha1'); 1.426 + } 1.427 + 1.428 + if ($this->option_md5_data) { 1.429 + 1.430 + // no md5_data_source or option disabled -- md5_data_source supported by FLAC, MAC, OptimFROG, Wavpack4 1.431 + if (!$this->option_md5_data_source || !@$this->info['md5_data_source']) { 1.432 + new getid3_lib_data_hash($this, 'md5'); 1.433 + } 1.434 + 1.435 + // copy md5_data_source to md5_data if option set to true 1.436 + elseif ($this->option_md5_data_source && @$this->info['md5_data_source']) { 1.437 + $this->info['md5_data'] = $this->info['md5_data_source']; 1.438 + } 1.439 + } 1.440 + } 1.441 + 1.442 + // Set warnings 1.443 + if ($this->warnings) { 1.444 + $this->info['warning'] = $this->warnings; 1.445 + } 1.446 + 1.447 + // Return result 1.448 + return $this->info; 1.449 + } 1.450 + 1.451 + 1.452 + 1.453 + // Return array of warnings 1.454 + public function warnings() { 1.455 + 1.456 + return $this->warnings; 1.457 + } 1.458 + 1.459 + 1.460 + 1.461 + // Add warning(s) to $this->warnings[] 1.462 + public function warning($message) { 1.463 + 1.464 + if (is_array($message)) { 1.465 + $this->warnings = array_merge($this->warnings, $message); 1.466 + } 1.467 + else { 1.468 + $this->warnings[] = $message; 1.469 + } 1.470 + } 1.471 + 1.472 + 1.473 + 1.474 + // Clear all warnings when cloning 1.475 + public function __clone() { 1.476 + 1.477 + $this->warnings = array (); 1.478 + 1.479 + // Copy info array, otherwise it will be a reference. 1.480 + $temp = $this->info; 1.481 + unset($this->info); 1.482 + $this->info = $temp; 1.483 + } 1.484 + 1.485 + 1.486 + 1.487 + // Convert string between charsets -- iconv() wrapper 1.488 + public function iconv($in_charset, $out_charset, $string, $drop01 = false) { 1.489 + 1.490 + if ($drop01 && ($string === "\x00" || $string === "\x01")) { 1.491 + return ''; 1.492 + } 1.493 + 1.494 + 1.495 + if (!$this->iconv_present) { 1.496 + return getid3_iconv_replacement::iconv($in_charset, $out_charset, $string); 1.497 + } 1.498 + 1.499 + 1.500 + // iconv() present 1.501 + if ($result = @iconv($in_charset, $out_charset.'//TRANSLIT', $string)) { 1.502 + 1.503 + if ($out_charset == 'ISO-8859-1') { 1.504 + return rtrim($result, "\x00"); 1.505 + } 1.506 + return $result; 1.507 + } 1.508 + 1.509 + $this->warning('iconv() was unable to convert the string: "' . $string . '" from ' . $in_charset . ' to ' . $out_charset); 1.510 + return $string; 1.511 + } 1.512 + 1.513 + 1.514 + 1.515 + public function include_module($name) { 1.516 + 1.517 + if (!file_exists($this->include_path.'module.'.$name.'.php')) { 1.518 + throw new getid3_exception('Required module.'.$name.'.php is missing.'); 1.519 + } 1.520 + 1.521 + include_once($this->include_path.'module.'.$name.'.php'); 1.522 + } 1.523 + 1.524 + 1.525 + 1.526 + public function include_module_optional($name) { 1.527 + 1.528 + if (!file_exists($this->include_path.'module.'.$name.'.php')) { 1.529 + return; 1.530 + } 1.531 + 1.532 + include_once($this->include_path.'module.'.$name.'.php'); 1.533 + return true; 1.534 + } 1.535 + 1.536 + 1.537 + // Return array containing information about all supported formats 1.538 + public static function GetFileFormatArray() { 1.539 + 1.540 + static $format_info = array ( 1.541 + 1.542 + // Audio formats 1.543 + 1.544 + // AC-3 - audio - Dolby AC-3 / Dolby Digital 1.545 + 'ac3' => array ( 1.546 + 'pattern' => '^\x0B\x77', 1.547 + 'group' => 'audio', 1.548 + 'module' => 'ac3', 1.549 + 'mime_type' => 'audio/ac3', 1.550 + ), 1.551 + 1.552 + // AAC - audio - Advanced Audio Coding (AAC) - ADIF format 1.553 + 'adif' => array ( 1.554 + 'pattern' => '^ADIF', 1.555 + 'group' => 'audio', 1.556 + 'module' => 'aac_adif', 1.557 + 'mime_type' => 'application/octet-stream', 1.558 + 'fail_ape' => 'WARNING', 1.559 + ), 1.560 + 1.561 + 1.562 + // AAC - audio - Advanced Audio Coding (AAC) - ADTS format (very similar to MP3) 1.563 + 'adts' => array ( 1.564 + 'pattern' => '^\xFF[\xF0-\xF1\xF8-\xF9]', 1.565 + 'group' => 'audio', 1.566 + 'module' => 'aac_adts', 1.567 + 'mime_type' => 'application/octet-stream', 1.568 + 'fail_ape' => 'WARNING', 1.569 + ), 1.570 + 1.571 + 1.572 + // AU - audio - NeXT/Sun AUdio (AU) 1.573 + 'au' => array ( 1.574 + 'pattern' => '^\.snd', 1.575 + 'group' => 'audio', 1.576 + 'module' => 'au', 1.577 + 'mime_type' => 'audio/basic', 1.578 + ), 1.579 + 1.580 + // AVR - audio - Audio Visual Research 1.581 + 'avr' => array ( 1.582 + 'pattern' => '^2BIT', 1.583 + 'group' => 'audio', 1.584 + 'module' => 'avr', 1.585 + 'mime_type' => 'application/octet-stream', 1.586 + ), 1.587 + 1.588 + // BONK - audio - Bonk v0.9+ 1.589 + 'bonk' => array ( 1.590 + 'pattern' => '^\x00(BONK|INFO|META| ID3)', 1.591 + 'group' => 'audio', 1.592 + 'module' => 'bonk', 1.593 + 'mime_type' => 'audio/xmms-bonk', 1.594 + ), 1.595 + 1.596 + // DTS - audio - Dolby Theatre System 1.597 + 'dts' => array( 1.598 + 'pattern' => '^\x7F\xFE\x80\x01', 1.599 + 'group' => 'audio', 1.600 + 'module' => 'dts', 1.601 + 'mime_type' => 'audio/dts', 1.602 + ), 1.603 + 1.604 + // FLAC - audio - Free Lossless Audio Codec 1.605 + 'flac' => array ( 1.606 + 'pattern' => '^fLaC', 1.607 + 'group' => 'audio', 1.608 + 'module' => 'xiph', 1.609 + 'mime_type' => 'audio/x-flac', 1.610 + ), 1.611 + 1.612 + // LA - audio - Lossless Audio (LA) 1.613 + 'la' => array ( 1.614 + 'pattern' => '^LA0[2-4]', 1.615 + 'group' => 'audio', 1.616 + 'module' => 'la', 1.617 + 'mime_type' => 'application/octet-stream', 1.618 + ), 1.619 + 1.620 + // LPAC - audio - Lossless Predictive Audio Compression (LPAC) 1.621 + 'lpac' => array ( 1.622 + 'pattern' => '^LPAC', 1.623 + 'group' => 'audio', 1.624 + 'module' => 'lpac', 1.625 + 'mime_type' => 'application/octet-stream', 1.626 + ), 1.627 + 1.628 + // MIDI - audio - MIDI (Musical Instrument Digital Interface) 1.629 + 'midi' => array ( 1.630 + 'pattern' => '^MThd', 1.631 + 'group' => 'audio', 1.632 + 'module' => 'midi', 1.633 + 'mime_type' => 'audio/midi', 1.634 + ), 1.635 + 1.636 + // MAC - audio - Monkey's Audio Compressor 1.637 + 'mac' => array ( 1.638 + 'pattern' => '^MAC ', 1.639 + 'group' => 'audio', 1.640 + 'module' => 'monkey', 1.641 + 'mime_type' => 'application/octet-stream', 1.642 + ), 1.643 + 1.644 + // MOD - audio - MODule (assorted sub-formats) 1.645 + 'mod' => array ( 1.646 + 'pattern' => '^.{1080}(M.K.|[5-9]CHN|[1-3][0-9]CH)', 1.647 + 'mime_type' => 'audio/mod', 1.648 + ), 1.649 + 1.650 + // MOD - audio - MODule (Impulse Tracker) 1.651 + 'it' => array ( 1.652 + 'pattern' => '^IMPM', 1.653 + 'mime_type' => 'audio/it', 1.654 + ), 1.655 + 1.656 + // MOD - audio - MODule (eXtended Module, various sub-formats) 1.657 + 'xm' => array ( 1.658 + 'pattern' => '^Extended Module', 1.659 + 'mime_type' => 'audio/xm', 1.660 + ), 1.661 + 1.662 + // MOD - audio - MODule (ScreamTracker) 1.663 + 's3m' => array ( 1.664 + 'pattern' => '^.{44}SCRM', 1.665 + 'mime_type' => 'audio/s3m', 1.666 + ), 1.667 + 1.668 + // MPC - audio - Musepack / MPEGplus SV7+ 1.669 + 'mpc' => array ( 1.670 + 'pattern' => '^(MP\+)', 1.671 + 'group' => 'audio', 1.672 + 'module' => 'mpc', 1.673 + 'mime_type' => 'audio/x-musepack', 1.674 + ), 1.675 + 1.676 + // MPC - audio - Musepack / MPEGplus SV4-6 1.677 + 'mpc_old' => array ( 1.678 + 'pattern' => '^([\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])', 1.679 + 'group' => 'audio', 1.680 + 'module' => 'mpc_old', 1.681 + 'mime_type' => 'application/octet-stream', 1.682 + ), 1.683 + 1.684 + 1.685 + // MP3 - audio - MPEG-audio Layer 3 (very similar to AAC-ADTS) 1.686 + 'mp3' => array ( 1.687 + 'pattern' => '^\xFF[\xE2-\xE7\xF2-\xF7\xFA-\xFF][\x00-\xEB]', 1.688 + 'group' => 'audio', 1.689 + 'module' => 'mp3', 1.690 + 'mime_type' => 'audio/mpeg', 1.691 + ), 1.692 + 1.693 + // OFR - audio - OptimFROG 1.694 + 'ofr' => array ( 1.695 + 'pattern' => '^(\*RIFF|OFR)', 1.696 + 'group' => 'audio', 1.697 + 'module' => 'optimfrog', 1.698 + 'mime_type' => 'application/octet-stream', 1.699 + ), 1.700 + 1.701 + // RKAU - audio - RKive AUdio compressor 1.702 + 'rkau' => array ( 1.703 + 'pattern' => '^RKA', 1.704 + 'group' => 'audio', 1.705 + 'module' => 'rkau', 1.706 + 'mime_type' => 'application/octet-stream', 1.707 + ), 1.708 + 1.709 + // SHN - audio - Shorten 1.710 + 'shn' => array ( 1.711 + 'pattern' => '^ajkg', 1.712 + 'group' => 'audio', 1.713 + 'module' => 'shorten', 1.714 + 'mime_type' => 'audio/xmms-shn', 1.715 + 'fail_id3' => 'ERROR', 1.716 + 'fail_ape' => 'ERROR', 1.717 + ), 1.718 + 1.719 + // TTA - audio - TTA Lossless Audio Compressor (http://tta.corecodec.org) 1.720 + 'tta' => array ( 1.721 + 'pattern' => '^TTA', // could also be '^TTA(\x01|\x02|\x03|2|1)' 1.722 + 'group' => 'audio', 1.723 + 'module' => 'tta', 1.724 + 'mime_type' => 'application/octet-stream', 1.725 + ), 1.726 + 1.727 + // VOC - audio - Creative Voice (VOC) 1.728 + 'voc' => array ( 1.729 + 'pattern' => '^Creative Voice File', 1.730 + 'group' => 'audio', 1.731 + 'module' => 'voc', 1.732 + 'mime_type' => 'audio/voc', 1.733 + ), 1.734 + 1.735 + // VQF - audio - transform-domain weighted interleave Vector Quantization Format (VQF) 1.736 + 'vqf' => array ( 1.737 + 'pattern' => '^TWIN', 1.738 + 'group' => 'audio', 1.739 + 'module' => 'vqf', 1.740 + 'mime_type' => 'application/octet-stream', 1.741 + ), 1.742 + 1.743 + // WV - audio - WavPack (v4.0+) 1.744 + 'vw' => array( 1.745 + 'pattern' => '^wvpk', 1.746 + 'group' => 'audio', 1.747 + 'module' => 'wavpack', 1.748 + 'mime_type' => 'application/octet-stream', 1.749 + ), 1.750 + 1.751 + 1.752 + // Audio-Video formats 1.753 + 1.754 + // ASF - audio/video - Advanced Streaming Format, Windows Media Video, Windows Media Audio 1.755 + 'asf' => array ( 1.756 + 'pattern' => '^\x30\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C', 1.757 + 'group' => 'audio-video', 1.758 + 'module' => 'asf', 1.759 + 'mime_type' => 'video/x-ms-asf', 1.760 + ), 1.761 + 1.762 + // BINK - audio/video - Bink / Smacker 1.763 + 'bink' => array( 1.764 + 'pattern' => '^(BIK|SMK)', 1.765 + 'mime_type' => 'application/octet-stream', 1.766 + ), 1.767 + 1.768 + // FLV - audio/video - FLash Video 1.769 + 'flv' => array( 1.770 + 'pattern' => '^FLV\x01', 1.771 + 'group' => 'audio-video', 1.772 + 'module' => 'flv', 1.773 + 'mime_type' => 'video/x-flv', 1.774 + ), 1.775 + 1.776 + // MKAV - audio/video - Mastroka 1.777 + 'matroska' => array ( 1.778 + 'pattern' => '^\x1A\x45\xDF\xA3', 1.779 + 'mime_type' => 'application/octet-stream', 1.780 + ), 1.781 + 1.782 + // MPEG - audio/video - MPEG (Moving Pictures Experts Group) 1.783 + 'mpeg' => array ( 1.784 + 'pattern' => '^\x00\x00\x01(\xBA|\xB3)', 1.785 + 'group' => 'audio-video', 1.786 + 'module' => 'mpeg', 1.787 + 'mime_type' => 'video/mpeg', 1.788 + ), 1.789 + 1.790 + // NSV - audio/video - Nullsoft Streaming Video (NSV) 1.791 + 'nsv' => array ( 1.792 + 'pattern' => '^NSV[sf]', 1.793 + 'group' => 'audio-video', 1.794 + 'module' => 'nsv', 1.795 + 'mime_type' => 'application/octet-stream', 1.796 + ), 1.797 + 1.798 + // Ogg - audio/video - Ogg (Ogg Vorbis, OggFLAC, Speex, Ogg Theora(*), Ogg Tarkin(*)) 1.799 + 'ogg' => array ( 1.800 + 'pattern' => '^OggS', 1.801 + 'group' => 'audio', 1.802 + 'module' => 'xiph', 1.803 + 'mime_type' => 'application/ogg', 1.804 + 'fail_id3' => 'WARNING', 1.805 + 'fail_ape' => 'WARNING', 1.806 + ), 1.807 + 1.808 + // QT - audio/video - Quicktime 1.809 + 'quicktime' => array ( 1.810 + 'pattern' => '^.{4}(cmov|free|ftyp|mdat|moov|pnot|skip|wide)', 1.811 + 'group' => 'audio-video', 1.812 + 'module' => 'quicktime', 1.813 + 'mime_type' => 'video/quicktime', 1.814 + ), 1.815 + 1.816 + // 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) 1.817 + 'riff' => array ( 1.818 + 'pattern' => '^(RIFF|SDSS|FORM)', 1.819 + 'group' => 'audio-video', 1.820 + 'module' => 'riff', 1.821 + 'mime_type' => 'audio/x-wave', 1.822 + 'fail_ape' => 'WARNING', 1.823 + ), 1.824 + 1.825 + // Real - audio/video - RealAudio, RealVideo 1.826 + 'real' => array ( 1.827 + 'pattern' => '^(\.RMF|.ra)', 1.828 + 'group' => 'audio-video', 1.829 + 'module' => 'real', 1.830 + 'mime_type' => 'audio/x-realaudio', 1.831 + ), 1.832 + 1.833 + // SWF - audio/video - ShockWave Flash 1.834 + 'swf' => array ( 1.835 + 'pattern' => '^(F|C)WS', 1.836 + 'group' => 'audio-video', 1.837 + 'module' => 'swf', 1.838 + 'mime_type' => 'application/x-shockwave-flash', 1.839 + ), 1.840 + 1.841 + 1.842 + // Still-Image formats 1.843 + 1.844 + // BMP - still image - Bitmap (Windows, OS/2; uncompressed, RLE8, RLE4) 1.845 + 'bmp' => array ( 1.846 + 'pattern' => '^BM', 1.847 + 'group' => 'graphic', 1.848 + 'module' => 'bmp', 1.849 + 'mime_type' => 'image/bmp', 1.850 + 'fail_id3' => 'ERROR', 1.851 + 'fail_ape' => 'ERROR', 1.852 + ), 1.853 + 1.854 + // GIF - still image - Graphics Interchange Format 1.855 + 'gif' => array ( 1.856 + 'pattern' => '^GIF', 1.857 + 'group' => 'graphic', 1.858 + 'module' => 'gif', 1.859 + 'mime_type' => 'image/gif', 1.860 + 'fail_id3' => 'ERROR', 1.861 + 'fail_ape' => 'ERROR', 1.862 + ), 1.863 + 1.864 + // JPEG - still image - Joint Photographic Experts Group (JPEG) 1.865 + 'jpeg' => array ( 1.866 + 'pattern' => '^\xFF\xD8\xFF', 1.867 + 'group' => 'graphic', 1.868 + 'module' => 'jpeg', 1.869 + 'mime_type' => 'image/jpeg', 1.870 + 'fail_id3' => 'ERROR', 1.871 + 'fail_ape' => 'ERROR', 1.872 + ), 1.873 + 1.874 + // PCD - still image - Kodak Photo CD 1.875 + 'pcd' => array ( 1.876 + 'pattern' => '^.{2048}PCD_IPI\x00', 1.877 + 'group' => 'graphic', 1.878 + 'module' => 'pcd', 1.879 + 'mime_type' => 'image/x-photo-cd', 1.880 + 'fail_id3' => 'ERROR', 1.881 + 'fail_ape' => 'ERROR', 1.882 + ), 1.883 + 1.884 + 1.885 + // PNG - still image - Portable Network Graphics (PNG) 1.886 + 'png' => array ( 1.887 + 'pattern' => '^\x89\x50\x4E\x47\x0D\x0A\x1A\x0A', 1.888 + 'group' => 'graphic', 1.889 + 'module' => 'png', 1.890 + 'mime_type' => 'image/png', 1.891 + 'fail_id3' => 'ERROR', 1.892 + 'fail_ape' => 'ERROR', 1.893 + ), 1.894 + 1.895 + 1.896 + // SVG - still image - Scalable Vector Graphics (SVG) 1.897 + 'svg' => array( 1.898 + 'pattern' => '<!DOCTYPE svg PUBLIC ', 1.899 + 'mime_type' => 'image/svg+xml', 1.900 + 'fail_id3' => 'ERROR', 1.901 + 'fail_ape' => 'ERROR', 1.902 + ), 1.903 + 1.904 + 1.905 + // TIFF - still image - Tagged Information File Format (TIFF) 1.906 + 'tiff' => array ( 1.907 + 'pattern' => '^(II\x2A\x00|MM\x00\x2A)', 1.908 + 'group' => 'graphic', 1.909 + 'module' => 'tiff', 1.910 + 'mime_type' => 'image/tiff', 1.911 + 'fail_id3' => 'ERROR', 1.912 + 'fail_ape' => 'ERROR', 1.913 + ), 1.914 + 1.915 + 1.916 + // Data formats 1.917 + 1.918 + 'exe' => array( 1.919 + 'pattern' => '^MZ', 1.920 + 'mime_type' => 'application/octet-stream', 1.921 + 'fail_id3' => 'ERROR', 1.922 + 'fail_ape' => 'ERROR', 1.923 + ), 1.924 + 1.925 + // ISO - data - International Standards Organization (ISO) CD-ROM Image 1.926 + 'iso' => array ( 1.927 + 'pattern' => '^.{32769}CD001', 1.928 + 'group' => 'misc', 1.929 + 'module' => 'iso', 1.930 + 'mime_type' => 'application/octet-stream', 1.931 + 'fail_id3' => 'ERROR', 1.932 + 'fail_ape' => 'ERROR', 1.933 + ), 1.934 + 1.935 + // RAR - data - RAR compressed data 1.936 + 'rar' => array( 1.937 + 'pattern' => '^Rar\!', 1.938 + 'mime_type' => 'application/octet-stream', 1.939 + 'fail_id3' => 'ERROR', 1.940 + 'fail_ape' => 'ERROR', 1.941 + ), 1.942 + 1.943 + // SZIP - audio - SZIP compressed data 1.944 + 'szip' => array ( 1.945 + 'pattern' => '^SZ\x0A\x04', 1.946 + 'group' => 'archive', 1.947 + 'module' => 'szip', 1.948 + 'mime_type' => 'application/octet-stream', 1.949 + 'fail_id3' => 'ERROR', 1.950 + 'fail_ape' => 'ERROR', 1.951 + ), 1.952 + 1.953 + // TAR - data - TAR compressed data 1.954 + 'tar' => array( 1.955 + '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}', 1.956 + 'group' => 'archive', 1.957 + 'module' => 'tar', 1.958 + 'mime_type' => 'application/x-tar', 1.959 + 'fail_id3' => 'ERROR', 1.960 + 'fail_ape' => 'ERROR', 1.961 + ), 1.962 + 1.963 + // GZIP - data - GZIP compressed data 1.964 + 'gz' => array( 1.965 + 'pattern' => '^\x1F\x8B\x08', 1.966 + 'group' => 'archive', 1.967 + 'module' => 'gzip', 1.968 + 'mime_type' => 'application/x-gzip', 1.969 + 'fail_id3' => 'ERROR', 1.970 + 'fail_ape' => 'ERROR', 1.971 + ), 1.972 + 1.973 + 1.974 + // ZIP - data - ZIP compressed data 1.975 + 'zip' => array ( 1.976 + 'pattern' => '^PK\x03\x04', 1.977 + 'group' => 'archive', 1.978 + 'module' => 'zip', 1.979 + 'mime_type' => 'application/zip', 1.980 + 'fail_id3' => 'ERROR', 1.981 + 'fail_ape' => 'ERROR', 1.982 + ), 1.983 + 1.984 + 1.985 + // PAR2 - data - Parity Volume Set Specification 2.0 1.986 + 'par2' => array ( 1.987 + 'pattern' => '^PAR2\x00PKT', 1.988 + 'mime_type' => 'application/octet-stream', 1.989 + 'fail_id3' => 'ERROR', 1.990 + 'fail_ape' => 'ERROR', 1.991 + ), 1.992 + 1.993 + 1.994 + // PDF - data - Portable Document Format 1.995 + 'pdf' => array( 1.996 + 'pattern' => '^\x25PDF', 1.997 + 'mime_type' => 'application/pdf', 1.998 + 'fail_id3' => 'ERROR', 1.999 + 'fail_ape' => 'ERROR', 1.1000 + ), 1.1001 + 1.1002 + // DOC - data - Microsoft Word 1.1003 + 'msoffice' => array( 1.1004 + 'pattern' => '^\xD0\xCF\x11\xE0', // D0CF11E == DOCFILE == Microsoft Office Document 1.1005 + 'mime_type' => 'application/octet-stream', 1.1006 + 'fail_id3' => 'ERROR', 1.1007 + 'fail_ape' => 'ERROR', 1.1008 + ), 1.1009 + ); 1.1010 + 1.1011 + return $format_info; 1.1012 + } 1.1013 + 1.1014 + 1.1015 + 1.1016 + // Recursive over array - converts array to $encoding charset from $this->encoding 1.1017 + function CharConvert(&$array, $encoding) { 1.1018 + 1.1019 + // Identical encoding - end here 1.1020 + if ($encoding == $this->encoding) { 1.1021 + return; 1.1022 + } 1.1023 + 1.1024 + // Loop thru array 1.1025 + foreach ($array as $key => $value) { 1.1026 + 1.1027 + // Go recursive 1.1028 + if (is_array($value)) { 1.1029 + $this->CharConvert($array[$key], $encoding); 1.1030 + } 1.1031 + 1.1032 + // Convert string 1.1033 + elseif (is_string($value)) { 1.1034 + $array[$key] = $this->iconv($encoding, $this->encoding, $value); 1.1035 + } 1.1036 + } 1.1037 + } 1.1038 + 1.1039 + 1.1040 + 1.1041 + // Convert and copy tags 1.1042 + protected function HandleAllTags() { 1.1043 + 1.1044 + // Key name => array (tag name, character encoding) 1.1045 + static $tags = array ( 1.1046 + 'asf' => array ('asf', 'UTF-16LE'), 1.1047 + 'midi' => array ('midi', 'ISO-8859-1'), 1.1048 + 'nsv' => array ('nsv', 'ISO-8859-1'), 1.1049 + 'ogg' => array ('vorbiscomment', 'UTF-8'), 1.1050 + 'png' => array ('png', 'UTF-8'), 1.1051 + 'tiff' => array ('tiff', 'ISO-8859-1'), 1.1052 + 'quicktime' => array ('quicktime', 'ISO-8859-1'), 1.1053 + 'real' => array ('real', 'ISO-8859-1'), 1.1054 + 'vqf' => array ('vqf', 'ISO-8859-1'), 1.1055 + 'zip' => array ('zip', 'ISO-8859-1'), 1.1056 + 'riff' => array ('riff', 'ISO-8859-1'), 1.1057 + 'lyrics3' => array ('lyrics3', 'ISO-8859-1'), 1.1058 + 'id3v1' => array ('id3v1', ''), // change below - cannot assign variable to static array 1.1059 + 'id3v2' => array ('id3v2', 'UTF-8'), // module converts all frames to UTF-8 1.1060 + 'ape' => array ('ape', 'UTF-8') 1.1061 + ); 1.1062 + $tags['id3v1'][1] = $this->encoding_id3v1; 1.1063 + 1.1064 + // Loop thru tags array 1.1065 + foreach ($tags as $comment_name => $tag_name_encoding_array) { 1.1066 + list($tag_name, $encoding) = $tag_name_encoding_array; 1.1067 + 1.1068 + // Fill in default encoding type if not already present 1.1069 + @$this->info[$comment_name] and $this->info[$comment_name]['encoding'] = $encoding; 1.1070 + 1.1071 + // Copy comments if key name set 1.1072 + if (@$this->info[$comment_name]['comments']) { 1.1073 + 1.1074 + foreach ($this->info[$comment_name]['comments'] as $tag_key => $value_array) { 1.1075 + foreach ($value_array as $key => $value) { 1.1076 + if (strlen(trim($value)) > 0) { 1.1077 + $this->info['tags'][$tag_name][trim($tag_key)][] = $value; // do not trim!! Unicode characters will get mangled if trailing nulls are removed! 1.1078 + } 1.1079 + } 1.1080 + 1.1081 + } 1.1082 + 1.1083 + if (!@$this->info['tags'][$tag_name]) { 1.1084 + // comments are set but contain nothing but empty strings, so skip 1.1085 + continue; 1.1086 + } 1.1087 + 1.1088 + $this->CharConvert($this->info['tags'][$tag_name], $encoding); 1.1089 + } 1.1090 + } 1.1091 + 1.1092 + 1.1093 + // Merge comments from ['tags'] into common ['comments'] 1.1094 + if (@$this->info['tags']) { 1.1095 + 1.1096 + foreach ($this->info['tags'] as $tag_type => $tag_array) { 1.1097 + 1.1098 + foreach ($tag_array as $tag_name => $tagdata) { 1.1099 + 1.1100 + foreach ($tagdata as $key => $value) { 1.1101 + 1.1102 + if (!empty($value)) { 1.1103 + 1.1104 + if (empty($this->info['comments'][$tag_name])) { 1.1105 + 1.1106 + // fall through and append value 1.1107 + } 1.1108 + elseif ($tag_type == 'id3v1') { 1.1109 + 1.1110 + $new_value_length = strlen(trim($value)); 1.1111 + foreach ($this->info['comments'][$tag_name] as $existing_key => $existing_value) { 1.1112 + $old_value_length = strlen(trim($existing_value)); 1.1113 + if (($new_value_length <= $old_value_length) && (substr($existing_value, 0, $new_value_length) == trim($value))) { 1.1114 + // new value is identical but shorter-than (or equal-length to) one already in comments - skip 1.1115 + break 2; 1.1116 + } 1.1117 + } 1.1118 + } 1.1119 + else { 1.1120 + 1.1121 + $new_value_length = strlen(trim($value)); 1.1122 + foreach ($this->info['comments'][$tag_name] as $existing_key => $existing_value) { 1.1123 + $old_value_length = strlen(trim($existing_value)); 1.1124 + if (($new_value_length > $old_value_length) && (substr(trim($value), 0, strlen($existing_value)) == $existing_value)) { 1.1125 + $this->info['comments'][$tag_name][$existing_key] = trim($value); 1.1126 + break 2; 1.1127 + } 1.1128 + } 1.1129 + } 1.1130 + 1.1131 + if (empty($this->info['comments'][$tag_name]) || !in_array(trim($value), $this->info['comments'][$tag_name])) { 1.1132 + $this->info['comments'][$tag_name][] = trim($value); 1.1133 + } 1.1134 + } 1.1135 + } 1.1136 + } 1.1137 + } 1.1138 + } 1.1139 + 1.1140 + return true; 1.1141 + } 1.1142 +} 1.1143 + 1.1144 + 1.1145 +abstract class getid3_handler 1.1146 +{ 1.1147 + 1.1148 + protected $getid3; // pointer 1.1149 + 1.1150 + protected $data_string_flag = false; // analyzing filepointer or string 1.1151 + protected $data_string; // string to analyze 1.1152 + protected $data_string_position = 0; // seek position in string 1.1153 + 1.1154 + 1.1155 + public function __construct(getID3 $getid3) { 1.1156 + 1.1157 + $this->getid3 = $getid3; 1.1158 + } 1.1159 + 1.1160 + 1.1161 + // Analyze from file pointer 1.1162 + abstract public function Analyze(); 1.1163 + 1.1164 + 1.1165 + 1.1166 + // Analyze from string instead 1.1167 + public function AnalyzeString(&$string) { 1.1168 + 1.1169 + // Enter string mode 1.1170 + $this->data_string_flag = true; 1.1171 + $this->data_string = $string; 1.1172 + 1.1173 + // Save info 1.1174 + $saved_avdataoffset = $this->getid3->info['avdataoffset']; 1.1175 + $saved_avdataend = $this->getid3->info['avdataend']; 1.1176 + $saved_filesize = $this->getid3->info['filesize']; 1.1177 + 1.1178 + // Reset some info 1.1179 + $this->getid3->info['avdataoffset'] = 0; 1.1180 + $this->getid3->info['avdataend'] = $this->getid3->info['filesize'] = strlen($string); 1.1181 + 1.1182 + // Analyze 1.1183 + $this->Analyze(); 1.1184 + 1.1185 + // Restore some info 1.1186 + $this->getid3->info['avdataoffset'] = $saved_avdataoffset; 1.1187 + $this->getid3->info['avdataend'] = $saved_avdataend; 1.1188 + $this->getid3->info['filesize'] = $saved_filesize; 1.1189 + 1.1190 + // Exit string mode 1.1191 + $this->data_string_flag = false; 1.1192 + } 1.1193 + 1.1194 + 1.1195 + protected function ftell() { 1.1196 + 1.1197 + if ($this->data_string_flag) { 1.1198 + return $this->data_string_position; 1.1199 + } 1.1200 + return ftell($this->getid3->fp); 1.1201 + } 1.1202 + 1.1203 + 1.1204 + protected function fread($bytes) { 1.1205 + 1.1206 + if ($this->data_string_flag) { 1.1207 + $this->data_string_position += $bytes; 1.1208 + return substr($this->data_string, $this->data_string_position - $bytes, $bytes); 1.1209 + } 1.1210 + return fread($this->getid3->fp, $bytes); 1.1211 + } 1.1212 + 1.1213 + 1.1214 + protected function fseek($bytes, $whence = SEEK_SET) { 1.1215 + 1.1216 + if ($this->data_string_flag) { 1.1217 + switch ($whence) { 1.1218 + case SEEK_SET: 1.1219 + $this->data_string_position = $bytes; 1.1220 + return; 1.1221 + 1.1222 + case SEEK_CUR: 1.1223 + $this->data_string_position += $bytes; 1.1224 + return; 1.1225 + 1.1226 + case SEEK_END: 1.1227 + $this->data_string_position = strlen($this->data_string) + $bytes; 1.1228 + return; 1.1229 + } 1.1230 + } 1.1231 + return fseek($this->getid3->fp, $bytes, $whence); 1.1232 + } 1.1233 + 1.1234 +} 1.1235 + 1.1236 + 1.1237 + 1.1238 + 1.1239 +abstract class getid3_handler_write 1.1240 +{ 1.1241 + protected $filename; 1.1242 + protected $user_abort; 1.1243 + 1.1244 + private $fp_lock; 1.1245 + private $owner; 1.1246 + private $group; 1.1247 + private $perms; 1.1248 + 1.1249 + 1.1250 + public function __construct($filename) { 1.1251 + 1.1252 + if (!file_exists($filename)) { 1.1253 + throw new getid3_exception('File does not exist: "' . $filename . '"'); 1.1254 + } 1.1255 + 1.1256 + if (!is_writeable($filename)) { 1.1257 + throw new getid3_exception('File is not writeable: "' . $filename . '"'); 1.1258 + } 1.1259 + 1.1260 + if (!is_writeable(dirname($filename))) { 1.1261 + throw new getid3_exception('Directory is not writeable: ' . dirname($filename) . ' (need to write lock file).'); 1.1262 + } 1.1263 + 1.1264 + $this->user_abort = ignore_user_abort(true); 1.1265 + 1.1266 + $this->fp_lock = fopen($filename . '.getid3.lock', 'w'); 1.1267 + flock($this->fp_lock, LOCK_EX); 1.1268 + 1.1269 + $this->filename = $filename; 1.1270 + } 1.1271 + 1.1272 + 1.1273 + public function __destruct() { 1.1274 + 1.1275 + flock($this->fp_lock, LOCK_UN); 1.1276 + fclose($this->fp_lock); 1.1277 + unlink($this->filename . '.getid3.lock'); 1.1278 + 1.1279 + ignore_user_abort($this->user_abort); 1.1280 + } 1.1281 + 1.1282 + 1.1283 + protected function save_permissions() { 1.1284 + 1.1285 + $this->owner = fileowner($this->filename); 1.1286 + $this->group = filegroup($this->filename); 1.1287 + $this->perms = fileperms($this->filename); 1.1288 + } 1.1289 + 1.1290 + 1.1291 + protected function restore_permissions() { 1.1292 + 1.1293 + @chown($this->filename, $this->owner); 1.1294 + @chgrp($this->filename, $this->group); 1.1295 + @chmod($this->filename, $this->perms); 1.1296 + } 1.1297 + 1.1298 + 1.1299 + abstract public function read(); 1.1300 + 1.1301 + abstract public function write(); 1.1302 + 1.1303 + abstract public function remove(); 1.1304 + 1.1305 +} 1.1306 + 1.1307 + 1.1308 + 1.1309 + 1.1310 +class getid3_exception extends Exception 1.1311 +{ 1.1312 + public $message; 1.1313 + 1.1314 +} 1.1315 + 1.1316 + 1.1317 + 1.1318 + 1.1319 +class getid3_lib 1.1320 +{ 1.1321 + 1.1322 + // Convert Little Endian byte string to int - max 32 bits 1.1323 + public static function LittleEndian2Int($byte_word, $signed = false) { 1.1324 + 1.1325 + return getid3_lib::BigEndian2Int(strrev($byte_word), $signed); 1.1326 + } 1.1327 + 1.1328 + 1.1329 + 1.1330 + // Convert number to Little Endian byte string 1.1331 + public static function LittleEndian2String($number, $minbytes=1, $synchsafe=false) { 1.1332 + $intstring = ''; 1.1333 + while ($number > 0) { 1.1334 + if ($synchsafe) { 1.1335 + $intstring = $intstring.chr($number & 127); 1.1336 + $number >>= 7; 1.1337 + } else { 1.1338 + $intstring = $intstring.chr($number & 255); 1.1339 + $number >>= 8; 1.1340 + } 1.1341 + } 1.1342 + return str_pad($intstring, $minbytes, "\x00", STR_PAD_RIGHT); 1.1343 + } 1.1344 + 1.1345 + 1.1346 + 1.1347 + // Convert Big Endian byte string to int - max 32 bits 1.1348 + public static function BigEndian2Int($byte_word, $signed = false) { 1.1349 + 1.1350 + $int_value = 0; 1.1351 + $byte_wordlen = strlen($byte_word); 1.1352 + 1.1353 + for ($i = 0; $i < $byte_wordlen; $i++) { 1.1354 + $int_value += ord($byte_word{$i}) * pow(256, ($byte_wordlen - 1 - $i)); 1.1355 + } 1.1356 + 1.1357 + if ($signed) { 1.1358 + $sign_mask_bit = 0x80 << (8 * ($byte_wordlen - 1)); 1.1359 + if ($int_value & $sign_mask_bit) { 1.1360 + $int_value = 0 - ($int_value & ($sign_mask_bit - 1)); 1.1361 + } 1.1362 + } 1.1363 + 1.1364 + return $int_value; 1.1365 + } 1.1366 + 1.1367 + 1.1368 + 1.1369 + // Convert Big Endian byte sybc safe string to int - max 32 bits 1.1370 + public static function BigEndianSyncSafe2Int($byte_word) { 1.1371 + 1.1372 + $int_value = 0; 1.1373 + $byte_wordlen = strlen($byte_word); 1.1374 + 1.1375 + // disregard MSB, effectively 7-bit bytes 1.1376 + for ($i = 0; $i < $byte_wordlen; $i++) { 1.1377 + $int_value = $int_value | (ord($byte_word{$i}) & 0x7F) << (($byte_wordlen - 1 - $i) * 7); 1.1378 + } 1.1379 + return $int_value; 1.1380 + } 1.1381 + 1.1382 + 1.1383 + 1.1384 + // Convert Big Endian byte string to bit string 1.1385 + public static function BigEndian2Bin($byte_word) { 1.1386 + 1.1387 + $bin_value = ''; 1.1388 + $byte_wordlen = strlen($byte_word); 1.1389 + for ($i = 0; $i < $byte_wordlen; $i++) { 1.1390 + $bin_value .= str_pad(decbin(ord($byte_word{$i})), 8, '0', STR_PAD_LEFT); 1.1391 + } 1.1392 + return $bin_value; 1.1393 + } 1.1394 + 1.1395 + 1.1396 + 1.1397 + public static function BigEndian2Float($byte_word) { 1.1398 + 1.1399 + // ANSI/IEEE Standard 754-1985, Standard for Binary Floating Point Arithmetic 1.1400 + // http://www.psc.edu/general/software/packages/ieee/ieee.html 1.1401 + // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee.html 1.1402 + 1.1403 + $bit_word = getid3_lib::BigEndian2Bin($byte_word); 1.1404 + if (!$bit_word) { 1.1405 + return 0; 1.1406 + } 1.1407 + $sign_bit = $bit_word{0}; 1.1408 + 1.1409 + switch (strlen($byte_word) * 8) { 1.1410 + case 32: 1.1411 + $exponent_bits = 8; 1.1412 + $fraction_bits = 23; 1.1413 + break; 1.1414 + 1.1415 + case 64: 1.1416 + $exponent_bits = 11; 1.1417 + $fraction_bits = 52; 1.1418 + break; 1.1419 + 1.1420 + case 80: 1.1421 + // 80-bit Apple SANE format 1.1422 + // http://www.mactech.com/articles/mactech/Vol.06/06.01/SANENormalized/ 1.1423 + $exponent_string = substr($bit_word, 1, 15); 1.1424 + $is_normalized = intval($bit_word{16}); 1.1425 + $fraction_string = substr($bit_word, 17, 63); 1.1426 + $exponent = pow(2, getid3_lib::Bin2Dec($exponent_string) - 16383); 1.1427 + $fraction = $is_normalized + getid3_lib::DecimalBinary2Float($fraction_string); 1.1428 + $float_value = $exponent * $fraction; 1.1429 + if ($sign_bit == '1') { 1.1430 + $float_value *= -1; 1.1431 + } 1.1432 + return $float_value; 1.1433 + break; 1.1434 + 1.1435 + default: 1.1436 + return false; 1.1437 + break; 1.1438 + } 1.1439 + $exponent_string = substr($bit_word, 1, $exponent_bits); 1.1440 + $fraction_string = substr($bit_word, $exponent_bits + 1, $fraction_bits); 1.1441 + $exponent = bindec($exponent_string); 1.1442 + $fraction = bindec($fraction_string); 1.1443 + 1.1444 + if (($exponent == (pow(2, $exponent_bits) - 1)) && ($fraction != 0)) { 1.1445 + // Not a Number 1.1446 + $float_value = false; 1.1447 + } elseif (($exponent == (pow(2, $exponent_bits) - 1)) && ($fraction == 0)) { 1.1448 + if ($sign_bit == '1') { 1.1449 + $float_value = '-infinity'; 1.1450 + } else { 1.1451 + $float_value = '+infinity'; 1.1452 + } 1.1453 + } elseif (($exponent == 0) && ($fraction == 0)) { 1.1454 + if ($sign_bit == '1') { 1.1455 + $float_value = -0; 1.1456 + } else { 1.1457 + $float_value = 0; 1.1458 + } 1.1459 + $float_value = ($sign_bit ? 0 : -0); 1.1460 + } elseif (($exponent == 0) && ($fraction != 0)) { 1.1461 + // These are 'unnormalized' values 1.1462 + $float_value = pow(2, (-1 * (pow(2, $exponent_bits - 1) - 2))) * getid3_lib::DecimalBinary2Float($fraction_string); 1.1463 + if ($sign_bit == '1') { 1.1464 + $float_value *= -1; 1.1465 + } 1.1466 + } elseif ($exponent != 0) { 1.1467 + $float_value = pow(2, ($exponent - (pow(2, $exponent_bits - 1) - 1))) * (1 + getid3_lib::DecimalBinary2Float($fraction_string)); 1.1468 + if ($sign_bit == '1') { 1.1469 + $float_value *= -1; 1.1470 + } 1.1471 + } 1.1472 + return (float) $float_value; 1.1473 + } 1.1474 + 1.1475 + 1.1476 + 1.1477 + public static function LittleEndian2Float($byte_word) { 1.1478 + 1.1479 + return getid3_lib::BigEndian2Float(strrev($byte_word)); 1.1480 + } 1.1481 + 1.1482 + 1.1483 + 1.1484 + public static function DecimalBinary2Float($binary_numerator) { 1.1485 + $numerator = bindec($binary_numerator); 1.1486 + $denominator = bindec('1'.str_repeat('0', strlen($binary_numerator))); 1.1487 + return ($numerator / $denominator); 1.1488 + } 1.1489 + 1.1490 + 1.1491 + public static function PrintHexBytes($string, $hex=true, $spaces=true, $html_safe=true) { 1.1492 + 1.1493 + $return_string = ''; 1.1494 + for ($i = 0; $i < strlen($string); $i++) { 1.1495 + if ($hex) { 1.1496 + $return_string .= str_pad(dechex(ord($string{$i})), 2, '0', STR_PAD_LEFT); 1.1497 + } else { 1.1498 + $return_string .= ' '.(ereg("[\x20-\x7E]", $string{$i}) ? $string{$i} : ''); 1.1499 + } 1.1500 + if ($spaces) { 1.1501 + $return_string .= ' '; 1.1502 + } 1.1503 + } 1.1504 + if ($html_safe) { 1.1505 + $return_string = htmlentities($return_string); 1.1506 + } 1.1507 + return $return_string; 1.1508 + } 1.1509 + 1.1510 + 1.1511 + 1.1512 + // Process header data string - read several values with algorithm and add to target 1.1513 + // algorithm is one one the getid3_lib::Something2Something() function names 1.1514 + // parts_array is index => length - $target[index] = algorithm(substring(data)) 1.1515 + // - OR just substring(data) if length is negative! 1.1516 + // indexes == 'IGNORE**' are ignored 1.1517 + 1.1518 + public static function ReadSequence($algorithm, &$target, &$data, $offset, $parts_array) { 1.1519 + 1.1520 + // Loop thru $parts_array 1.1521 + foreach ($parts_array as $target_string => $length) { 1.1522 + 1.1523 + // Add to target 1.1524 + if (!strstr($target_string, 'IGNORE')) { 1.1525 + 1.1526 + // substr(....length) 1.1527 + if ($length < 0) { 1.1528 + $target[$target_string] = substr($data, $offset, -$length); 1.1529 + } 1.1530 + 1.1531 + // algorithm(substr(...length)) 1.1532 + else { 1.1533 + $target[$target_string] = getid3_lib::$algorithm(substr($data, $offset, $length)); 1.1534 + } 1.1535 + } 1.1536 + 1.1537 + // Move pointer 1.1538 + $offset += abs($length); 1.1539 + } 1.1540 + } 1.1541 + 1.1542 +} 1.1543 + 1.1544 + 1.1545 + 1.1546 +class getid3_lib_replaygain 1.1547 +{ 1.1548 + 1.1549 + public static function NameLookup($name_code) { 1.1550 + 1.1551 + static $lookup = array ( 1.1552 + 0 => 'not set', 1.1553 + 1 => 'Track Gain Adjustment', 1.1554 + 2 => 'Album Gain Adjustment' 1.1555 + ); 1.1556 + 1.1557 + return @$lookup[$name_code]; 1.1558 + } 1.1559 + 1.1560 + 1.1561 + 1.1562 + public static function OriginatorLookup($originator_code) { 1.1563 + 1.1564 + static $lookup = array ( 1.1565 + 0 => 'unspecified', 1.1566 + 1 => 'pre-set by artist/producer/mastering engineer', 1.1567 + 2 => 'set by user', 1.1568 + 3 => 'determined automatically' 1.1569 + ); 1.1570 + 1.1571 + return @$lookup[$originator_code]; 1.1572 + } 1.1573 + 1.1574 + 1.1575 + 1.1576 + public static function AdjustmentLookup($raw_adjustment, $sign_bit) { 1.1577 + 1.1578 + return (float)$raw_adjustment / 10 * ($sign_bit == 1 ? -1 : 1); 1.1579 + } 1.1580 + 1.1581 + 1.1582 + 1.1583 + public static function GainString($name_code, $originator_code, $replaygain) { 1.1584 + 1.1585 + $sign_bit = $replaygain < 0 ? 1 : 0; 1.1586 + 1.1587 + $stored_replaygain = intval(round($replaygain * 10)); 1.1588 + $gain_string = str_pad(decbin($name_code), 3, '0', STR_PAD_LEFT); 1.1589 + $gain_string .= str_pad(decbin($originator_code), 3, '0', STR_PAD_LEFT); 1.1590 + $gain_string .= $sign_bit; 1.1591 + $gain_string .= str_pad(decbin($stored_replaygain), 9, '0', STR_PAD_LEFT); 1.1592 + 1.1593 + return $gain_string; 1.1594 + } 1.1595 + 1.1596 +} 1.1597 + 1.1598 + 1.1599 + 1.1600 + 1.1601 +?> 1.1602 \ No newline at end of file