Annotation of /trunk/lib/getid3/getid3.php
Parent Directory
|
Revision Log
Revision 2 - (view) (download)
| 1 : | andphe | 2 | <?php |
| 2 : | ///////////////////////////////////////////////////////////////// | ||
| 3 : | /// getID3() by James Heinrich <info@getid3.org> // | ||
| 4 : | // available at http://getid3.sourceforge.net // | ||
| 5 : | // or http://www.getid3.org // | ||
| 6 : | ///////////////////////////////////////////////////////////////// | ||
| 7 : | // // | ||
| 8 : | // Please see readme.txt for more information // | ||
| 9 : | // /// | ||
| 10 : | ///////////////////////////////////////////////////////////////// | ||
| 11 : | // MOS Intruder Alerts | ||
| 12 : | defined( '_VALID_MOS' ) or die( 'Direct Access to this location is not allowed.' ); | ||
| 13 : | |||
| 14 : | // Defines | ||
| 15 : | define('GETID3_VERSION', '1.7.7'); | ||
| 16 : | define('GETID3_FREAD_BUFFER_SIZE', 16384); // read buffer size in bytes | ||
| 17 : | |||
| 18 : | |||
| 19 : | |||
| 20 : | class getID3 | ||
| 21 : | { | ||
| 22 : | // public: Settings | ||
| 23 : | var $encoding = 'ISO-8859-1'; // CASE SENSITIVE! - i.e. (must be supported by iconv()) | ||
| 24 : | // Examples: ISO-8859-1 UTF-8 UTF-16 UTF-16BE | ||
| 25 : | |||
| 26 : | var $encoding_id3v1 = 'ISO-8859-1'; // Should always be 'ISO-8859-1', but some tags may be written in other encodings such as 'EUC-CN' | ||
| 27 : | |||
| 28 : | var $tempdir = '*'; // default '*' should use system temp dir | ||
| 29 : | |||
| 30 : | // public: Optional tag checks - disable for speed. | ||
| 31 : | var $option_tag_id3v1 = true; // Read and process ID3v1 tags | ||
| 32 : | var $option_tag_id3v2 = true; // Read and process ID3v2 tags | ||
| 33 : | var $option_tag_lyrics3 = true; // Read and process Lyrics3 tags | ||
| 34 : | var $option_tag_apetag = true; // Read and process APE tags | ||
| 35 : | var $option_tags_process = true; // Copy tags to root key 'tags' and encode to $this->encoding | ||
| 36 : | var $option_tags_html = true; // Copy tags to root key 'tags_html' properly translated from various encodings to HTML entities | ||
| 37 : | |||
| 38 : | // public: Optional tag/comment calucations | ||
| 39 : | var $option_extra_info = true; // Calculate additional info such as bitrate, channelmode etc | ||
| 40 : | |||
| 41 : | // public: Optional calculations | ||
| 42 : | var $option_md5_data = false; // Get MD5 sum of data part - slow | ||
| 43 : | var $option_md5_data_source = false; // Use MD5 of source file if availble - only FLAC and OptimFROG | ||
| 44 : | var $option_sha1_data = false; // Get SHA1 sum of data part - slow | ||
| 45 : | var $option_max_2gb_check = true; // Check whether file is larger than 2 Gb and thus not supported by PHP | ||
| 46 : | |||
| 47 : | // private | ||
| 48 : | var $filename; | ||
| 49 : | |||
| 50 : | |||
| 51 : | // public: constructor | ||
| 52 : | function getID3() | ||
| 53 : | { | ||
| 54 : | |||
| 55 : | $this->startup_error = ''; | ||
| 56 : | $this->startup_warning = ''; | ||
| 57 : | |||
| 58 : | // Check for PHP version >= 4.1.0 | ||
| 59 : | if (phpversion() < '4.1.0') { | ||
| 60 : | $this->startup_error .= 'getID3() requires PHP v4.1.0 or higher - you are running v'.phpversion(); | ||
| 61 : | } | ||
| 62 : | |||
| 63 : | // Check memory | ||
| 64 : | $memory_limit = ini_get('memory_limit'); | ||
| 65 : | if (eregi('([0-9]+)M', $memory_limit, $matches)) { | ||
| 66 : | // could be stored as "16M" rather than 16777216 for example | ||
| 67 : | $memory_limit = $matches[1] * 1048576; | ||
| 68 : | } | ||
| 69 : | if ($memory_limit <= 0) { | ||
| 70 : | // memory limits probably disabled | ||
| 71 : | } elseif ($memory_limit <= 3145728) { | ||
| 72 : | $this->startup_error .= 'PHP has less than 3MB available memory and will very likely run out. Increase memory_limit in php.ini'; | ||
| 73 : | } elseif ($memory_limit <= 12582912) { | ||
| 74 : | $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'; | ||
| 75 : | } | ||
| 76 : | |||
| 77 : | // Check safe_mode off | ||
| 78 : | if ((bool) ini_get('safe_mode')) { | ||
| 79 : | $this->warning('WARNING: Safe mode is on, shorten support disabled, md5data/sha1data for ogg vorbis disabled, ogg vorbos/flac tag writing disabled.'); | ||
| 80 : | } | ||
| 81 : | |||
| 82 : | |||
| 83 : | // define a constant rather than looking up every time it is needed | ||
| 84 : | if (!defined('GETID3_OS_ISWINDOWS')) { | ||
| 85 : | if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') { | ||
| 86 : | define('GETID3_OS_ISWINDOWS', true); | ||
| 87 : | } else { | ||
| 88 : | define('GETID3_OS_ISWINDOWS', false); | ||
| 89 : | } | ||
| 90 : | } | ||
| 91 : | |||
| 92 : | // Get base path of getID3() - ONCE | ||
| 93 : | if (!defined('GETID3_INCLUDEPATH')) { | ||
| 94 : | foreach (get_included_files() as $key => $val) { | ||
| 95 : | if (basename($val) == 'getid3.php') { | ||
| 96 : | define('GETID3_INCLUDEPATH', dirname($val).DIRECTORY_SEPARATOR); | ||
| 97 : | break; | ||
| 98 : | } | ||
| 99 : | } | ||
| 100 : | } | ||
| 101 : | |||
| 102 : | // Load support library | ||
| 103 : | if (!include_once(GETID3_INCLUDEPATH.'getid3.lib.php')) { | ||
| 104 : | $this->startup_error .= 'getid3.lib.php is missing or corrupt'; | ||
| 105 : | } | ||
| 106 : | |||
| 107 : | |||
| 108 : | // Needed for Windows only: | ||
| 109 : | // Define locations of helper applications for Shorten, VorbisComment, MetaFLAC | ||
| 110 : | // as well as other helper functions such as head, tail, md5sum, etc | ||
| 111 : | // IMPORTANT: This path cannot have spaces in it. If neccesary, use the 8dot3 equivalent | ||
| 112 : | // ie for "C:/Program Files/Apache/" put "C:/PROGRA~1/APACHE/" | ||
| 113 : | // IMPORTANT: This path must include the trailing slash | ||
| 114 : | if (GETID3_OS_ISWINDOWS && !defined('GETID3_HELPERAPPSDIR')) { | ||
| 115 : | $helperappsdir = GETID3_INCLUDEPATH.'..'.DIRECTORY_SEPARATOR.'helperapps'; // must not have any space in this path | ||
| 116 : | |||
| 117 : | if (!is_dir($helperappsdir)) { | ||
| 118 : | |||
| 119 : | $this->startup_error .= '"'.$helperappsdir.'" cannot be defined as GETID3_HELPERAPPSDIR because it does not exist'; | ||
| 120 : | |||
| 121 : | } elseif (strpos(realpath($helperappsdir), ' ') !== false) { | ||
| 122 : | |||
| 123 : | $DirPieces = explode(DIRECTORY_SEPARATOR, realpath($helperappsdir)); | ||
| 124 : | $DirPieces8 = $DirPieces; | ||
| 125 : | |||
| 126 : | $CLIdir = $DirPieces[0].' && cd \\'; | ||
| 127 : | for ($i = 1; $i < count($DirPieces); $i++) { | ||
| 128 : | if (strpos($DirPieces[$i], ' ') === false) { | ||
| 129 : | $CLIdir .= ' && cd '.$DirPieces[$i]; | ||
| 130 : | } else { | ||
| 131 : | ob_start(); | ||
| 132 : | system($CLIdir.' && dir /ad /x'); | ||
| 133 : | $subdirsraw = explode("\n", ob_get_contents()); | ||
| 134 : | ob_end_clean(); | ||
| 135 : | foreach ($subdirsraw as $dummy => $line) { | ||
| 136 : | if (eregi('^[0-9]{4}/[0-9]{2}/[0-9]{2} [0-9]{2}:[0-9]{2} [AP]M <DIR> ([^ ]{8}) '.preg_quote($DirPieces[$i]).'$', trim($line), $matches)) { | ||
| 137 : | $CLIdir .= ' && cd '.$matches[1]; | ||
| 138 : | break; | ||
| 139 : | } | ||
| 140 : | } | ||
| 141 : | $DirPieces8[$i] = $matches[1]; | ||
| 142 : | } | ||
| 143 : | } | ||
| 144 : | $helperappsdir = implode(DIRECTORY_SEPARATOR, $DirPieces8); | ||
| 145 : | |||
| 146 : | } | ||
| 147 : | define('GETID3_HELPERAPPSDIR', realpath($helperappsdir).DIRECTORY_SEPARATOR); | ||
| 148 : | |||
| 149 : | } | ||
| 150 : | |||
| 151 : | } | ||
| 152 : | |||
| 153 : | |||
| 154 : | // public: setOption | ||
| 155 : | function setOption($optArray) { | ||
| 156 : | if (!is_array($optArray) || empty($optArray)) { | ||
| 157 : | return false; | ||
| 158 : | } | ||
| 159 : | foreach ($optArray as $opt => $val) { | ||
| 160 : | if (isset($this, $opt) === false) { | ||
| 161 : | continue; | ||
| 162 : | } | ||
| 163 : | $this->$opt = $val; | ||
| 164 : | } | ||
| 165 : | return true; | ||
| 166 : | } | ||
| 167 : | |||
| 168 : | |||
| 169 : | // public: analyze file - replaces GetAllFileInfo() and GetTagOnly() | ||
| 170 : | function analyze($filename) { | ||
| 171 : | |||
| 172 : | if (!empty($this->startup_error)) { | ||
| 173 : | return $this->error($this->startup_error); | ||
| 174 : | } | ||
| 175 : | if (!empty($this->startup_warning)) { | ||
| 176 : | $this->warning($this->startup_warning); | ||
| 177 : | } | ||
| 178 : | |||
| 179 : | // init result array and set parameters | ||
| 180 : | $this->info = array(); | ||
| 181 : | $this->info['GETID3_VERSION'] = GETID3_VERSION; | ||
| 182 : | |||
| 183 : | // Check encoding/iconv support | ||
| 184 : | if (!function_exists('iconv') && !in_array($this->encoding, array('ISO-8859-1', 'UTF-8', 'UTF-16LE', 'UTF-16BE', 'UTF-16'))) { | ||
| 185 : | $errormessage = 'iconv() support is needed for encodings other than ISO-8859-1, UTF-8, UTF-16LE, UTF16-BE, UTF-16. '; | ||
| 186 : | if (GETID3_OS_ISWINDOWS) { | ||
| 187 : | $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'; | ||
| 188 : | } else { | ||
| 189 : | $errormessage .= 'PHP is not compiled with iconv() support. Please recompile with the --with-iconv switch'; | ||
| 190 : | } | ||
| 191 : | return $this->error($errormessage); | ||
| 192 : | } | ||
| 193 : | |||
| 194 : | // Disable magic_quotes_runtime, if neccesary | ||
| 195 : | $old_magic_quotes_runtime = get_magic_quotes_runtime(); // store current setting of magic_quotes_runtime | ||
| 196 : | if ($old_magic_quotes_runtime) { | ||
| 197 : | set_magic_quotes_runtime(0); // turn off magic_quotes_runtime | ||
| 198 : | if (get_magic_quotes_runtime()) { | ||
| 199 : | return $this->error('Could not disable magic_quotes_runtime - getID3() cannot work properly with this setting enabled'); | ||
| 200 : | } | ||
| 201 : | } | ||
| 202 : | |||
| 203 : | // remote files not supported | ||
| 204 : | if (preg_match('/^(ht|f)tp:\/\//', $filename)) { | ||
| 205 : | return $this->error('Remote files are not supported in this version of getID3() - please copy the file locally first'); | ||
| 206 : | } | ||
| 207 : | |||
| 208 : | // open local file | ||
| 209 : | if (!$fp = @fopen($filename, 'rb')) { | ||
| 210 : | return $this->error('Could not open file "'.$filename.'"'); | ||
| 211 : | } | ||
| 212 : | |||
| 213 : | // set parameters | ||
| 214 : | $this->info['filesize'] = filesize($filename); | ||
| 215 : | |||
| 216 : | // option_max_2gb_check | ||
| 217 : | if ($this->option_max_2gb_check) { | ||
| 218 : | // PHP doesn't support integers larger than 31-bit (~2GB) | ||
| 219 : | // filesize() simply returns (filesize % (pow(2, 32)), no matter the actual filesize | ||
| 220 : | // ftell() returns 0 if seeking to the end is beyond the range of unsigned integer | ||
| 221 : | fseek($fp, 0, SEEK_END); | ||
| 222 : | if ((($this->info['filesize'] != 0) && (ftell($fp) == 0)) || | ||
| 223 : | ($this->info['filesize'] < 0) || | ||
| 224 : | (ftell($fp) < 0)) { | ||
| 225 : | unset($this->info['filesize']); | ||
| 226 : | fclose($fp); | ||
| 227 : | return $this->error('File is most likely larger than 2GB and is not supported by PHP'); | ||
| 228 : | } | ||
| 229 : | } | ||
| 230 : | |||
| 231 : | // set more parameters | ||
| 232 : | $this->info['avdataoffset'] = 0; | ||
| 233 : | $this->info['avdataend'] = $this->info['filesize']; | ||
| 234 : | $this->info['fileformat'] = ''; // filled in later | ||
| 235 : | $this->info['audio']['dataformat'] = ''; // filled in later, unset if not used | ||
| 236 : | $this->info['video']['dataformat'] = ''; // filled in later, unset if not used | ||
| 237 : | $this->info['tags'] = array(); // filled in later, unset if not used | ||
| 238 : | $this->info['error'] = array(); // filled in later, unset if not used | ||
| 239 : | $this->info['warning'] = array(); // filled in later, unset if not used | ||
| 240 : | $this->info['comments'] = array(); // filled in later, unset if not used | ||
| 241 : | $this->info['encoding'] = $this->encoding; // required by id3v2 and iso modules - can be unset at the end if desired | ||
| 242 : | |||
| 243 : | // set redundant parameters - might be needed in some include file | ||
| 244 : | $this->info['filename'] = basename($filename); | ||
| 245 : | $this->info['filepath'] = str_replace('\\', '/', realpath(dirname($filename))); | ||
| 246 : | $this->info['filenamepath'] = $this->info['filepath'].'/'.$this->info['filename']; | ||
| 247 : | |||
| 248 : | |||
| 249 : | // handle ID3v2 tag - done first - already at beginning of file | ||
| 250 : | // ID3v2 detection (even if not parsing) is always done otherwise fileformat is much harder to detect | ||
| 251 : | if ($this->option_tag_id3v2) { | ||
| 252 : | |||
| 253 : | $GETID3_ERRORARRAY = &$this->info['warning']; | ||
| 254 : | if (getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, false)) { | ||
| 255 : | $tag = new getid3_id3v2($fp, $this->info); | ||
| 256 : | } | ||
| 257 : | |||
| 258 : | } else { | ||
| 259 : | |||
| 260 : | fseek($fp, 0, SEEK_SET); | ||
| 261 : | $header = fread($fp, 10); | ||
| 262 : | if (substr($header, 0, 3) == 'ID3') { | ||
| 263 : | $this->info['id3v2']['header'] = true; | ||
| 264 : | $this->info['id3v2']['majorversion'] = ord($header{3}); | ||
| 265 : | $this->info['id3v2']['minorversion'] = ord($header{4}); | ||
| 266 : | $this->info['id3v2']['headerlength'] = getid3_lib::BigEndian2Int(substr($header, 6, 4), 1) + 10; // length of ID3v2 tag in 10-byte header doesn't include 10-byte header length | ||
| 267 : | |||
| 268 : | $this->info['id3v2']['tag_offset_start'] = 0; | ||
| 269 : | $this->info['id3v2']['tag_offset_end'] = $this->info['id3v2']['tag_offset_start'] + $this->info['id3v2']['headerlength']; | ||
| 270 : | $this->info['avdataoffset'] = $this->info['id3v2']['tag_offset_end']; | ||
| 271 : | } | ||
| 272 : | |||
| 273 : | } | ||
| 274 : | |||
| 275 : | |||
| 276 : | // handle ID3v1 tag | ||
| 277 : | if ($this->option_tag_id3v1) { | ||
| 278 : | if (!@include_once(GETID3_INCLUDEPATH.'module.tag.id3v1.php')) { | ||
| 279 : | return $this->error('module.tag.id3v1.php is missing - you may disable option_tag_id3v1.'); | ||
| 280 : | } | ||
| 281 : | $tag = new getid3_id3v1($fp, $this->info); | ||
| 282 : | } | ||
| 283 : | |||
| 284 : | // handle APE tag | ||
| 285 : | if ($this->option_tag_apetag) { | ||
| 286 : | if (!@include_once(GETID3_INCLUDEPATH.'module.tag.apetag.php')) { | ||
| 287 : | return $this->error('module.tag.apetag.php is missing - you may disable option_tag_apetag.'); | ||
| 288 : | } | ||
| 289 : | $tag = new getid3_apetag($fp, $this->info); | ||
| 290 : | } | ||
| 291 : | |||
| 292 : | // handle lyrics3 tag | ||
| 293 : | if ($this->option_tag_lyrics3) { | ||
| 294 : | if (!@include_once(GETID3_INCLUDEPATH.'module.tag.lyrics3.php')) { | ||
| 295 : | return $this->error('module.tag.lyrics3.php is missing - you may disable option_tag_lyrics3.'); | ||
| 296 : | } | ||
| 297 : | $tag = new getid3_lyrics3($fp, $this->info); | ||
| 298 : | } | ||
| 299 : | |||
| 300 : | // read 32 kb file data | ||
| 301 : | fseek($fp, $this->info['avdataoffset'], SEEK_SET); | ||
| 302 : | $formattest = fread($fp, 32774); | ||
| 303 : | |||
| 304 : | // determine format | ||
| 305 : | $determined_format = $this->GetFileFormat($formattest, $filename); | ||
| 306 : | |||
| 307 : | // unable to determine file format | ||
| 308 : | if (!$determined_format) { | ||
| 309 : | fclose($fp); | ||
| 310 : | return $this->error('unable to determine file format'); | ||
| 311 : | } | ||
| 312 : | |||
| 313 : | // check for illegal ID3 tags | ||
| 314 : | if (isset($determined_format['fail_id3']) && (in_array('id3v1', $this->info['tags']) || in_array('id3v2', $this->info['tags']))) { | ||
| 315 : | if ($determined_format['fail_id3'] === 'ERROR') { | ||
| 316 : | fclose($fp); | ||
| 317 : | return $this->error('ID3 tags not allowed on this file type.'); | ||
| 318 : | } elseif ($determined_format['fail_id3'] === 'WARNING') { | ||
| 319 : | $this->info['warning'][] = 'ID3 tags not allowed on this file type.'; | ||
| 320 : | } | ||
| 321 : | } | ||
| 322 : | |||
| 323 : | // check for illegal APE tags | ||
| 324 : | if (isset($determined_format['fail_ape']) && in_array('ape', $this->info['tags'])) { | ||
| 325 : | if ($determined_format['fail_ape'] === 'ERROR') { | ||
| 326 : | fclose($fp); | ||
| 327 : | return $this->error('APE tags not allowed on this file type.'); | ||
| 328 : | } elseif ($determined_format['fail_ape'] === 'WARNING') { | ||
| 329 : | $this->info['warning'][] = 'APE tags not allowed on this file type.'; | ||
| 330 : | } | ||
| 331 : | } | ||
| 332 : | |||
| 333 : | // set mime type | ||
| 334 : | $this->info['mime_type'] = $determined_format['mime_type']; | ||
| 335 : | |||
| 336 : | // supported format signature pattern detected, but module deleted | ||
| 337 : | if (!file_exists(GETID3_INCLUDEPATH.$determined_format['include'])) { | ||
| 338 : | fclose($fp); | ||
| 339 : | return $this->error('Format not supported, module, '.$determined_format['include'].', was removed.'); | ||
| 340 : | } | ||
| 341 : | |||
| 342 : | // module requires iconv support | ||
| 343 : | if (!function_exists('iconv') && @$determined_format['iconv_req']) { | ||
| 344 : | return $this->error('iconv support is required for this module ('.$determined_format['include'].').'); | ||
| 345 : | } | ||
| 346 : | |||
| 347 : | // include module | ||
| 348 : | include_once(GETID3_INCLUDEPATH.$determined_format['include']); | ||
| 349 : | |||
| 350 : | // instantiate module class | ||
| 351 : | $class_name = 'getid3_'.$determined_format['module']; | ||
| 352 : | if (!class_exists($class_name)) { | ||
| 353 : | return $this->error('Format not supported, module, '.$determined_format['include'].', is corrupt.'); | ||
| 354 : | } | ||
| 355 : | if (isset($determined_format['option'])) { | ||
| 356 : | $class = new $class_name($fp, $this->info, $determined_format['option']); | ||
| 357 : | } else { | ||
| 358 : | $class = new $class_name($fp, $this->info); | ||
| 359 : | } | ||
| 360 : | |||
| 361 : | // close file | ||
| 362 : | fclose($fp); | ||
| 363 : | |||
| 364 : | // process all tags - copy to 'tags' and convert charsets | ||
| 365 : | if ($this->option_tags_process) { | ||
| 366 : | $this->HandleAllTags(); | ||
| 367 : | } | ||
| 368 : | |||
| 369 : | // perform more calculations | ||
| 370 : | if ($this->option_extra_info) { | ||
| 371 : | $this->ChannelsBitratePlaytimeCalculations(); | ||
| 372 : | $this->CalculateCompressionRatioVideo(); | ||
| 373 : | $this->CalculateCompressionRatioAudio(); | ||
| 374 : | $this->CalculateReplayGain(); | ||
| 375 : | $this->ProcessAudioStreams(); | ||
| 376 : | } | ||
| 377 : | |||
| 378 : | // get the MD5 sum of the audio/video portion of the file - without ID3/APE/Lyrics3/etc header/footer tags | ||
| 379 : | if ($this->option_md5_data) { | ||
| 380 : | // do not cald md5_data if md5_data_source is present - set by flac only - future MPC/SV8 too | ||
| 381 : | if (!$this->option_md5_data_source || empty($this->info['md5_data_source'])) { | ||
| 382 : | $this->getHashdata('md5'); | ||
| 383 : | } | ||
| 384 : | } | ||
| 385 : | |||
| 386 : | // get the SHA1 sum of the audio/video portion of the file - without ID3/APE/Lyrics3/etc header/footer tags | ||
| 387 : | if ($this->option_sha1_data) { | ||
| 388 : | $this->getHashdata('sha1'); | ||
| 389 : | } | ||
| 390 : | |||
| 391 : | // remove undesired keys | ||
| 392 : | $this->CleanUp(); | ||
| 393 : | |||
| 394 : | // restore magic_quotes_runtime setting | ||
| 395 : | set_magic_quotes_runtime($old_magic_quotes_runtime); | ||
| 396 : | |||
| 397 : | // return info array | ||
| 398 : | return $this->info; | ||
| 399 : | } | ||
| 400 : | |||
| 401 : | |||
| 402 : | // private: error handling | ||
| 403 : | function error($message) { | ||
| 404 : | |||
| 405 : | $this->CleanUp(); | ||
| 406 : | |||
| 407 : | $this->info['error'][] = $message; | ||
| 408 : | return $this->info; | ||
| 409 : | } | ||
| 410 : | |||
| 411 : | |||
| 412 : | // private: warning handling | ||
| 413 : | function warning($message) { | ||
| 414 : | $this->info['warning'][] = $message; | ||
| 415 : | return true; | ||
| 416 : | } | ||
| 417 : | |||
| 418 : | |||
| 419 : | // private: CleanUp | ||
| 420 : | function CleanUp() { | ||
| 421 : | |||
| 422 : | // remove possible empty keys | ||
| 423 : | $AVpossibleEmptyKeys = array('dataformat', 'bits_per_sample', 'encoder_options', 'streams'); | ||
| 424 : | foreach ($AVpossibleEmptyKeys as $dummy => $key) { | ||
| 425 : | if (empty($this->info['audio'][$key]) && isset($this->info['audio'][$key])) { | ||
| 426 : | unset($this->info['audio'][$key]); | ||
| 427 : | } | ||
| 428 : | if (empty($this->info['video'][$key]) && isset($this->info['video'][$key])) { | ||
| 429 : | unset($this->info['video'][$key]); | ||
| 430 : | } | ||
| 431 : | } | ||
| 432 : | |||
| 433 : | // remove empty root keys | ||
| 434 : | if (!empty($this->info)) { | ||
| 435 : | foreach ($this->info as $key => $value) { | ||
| 436 : | if (empty($this->info[$key]) && ($this->info[$key] !== 0) && ($this->info[$key] !== '0')) { | ||
| 437 : | unset($this->info[$key]); | ||
| 438 : | } | ||
| 439 : | } | ||
| 440 : | } | ||
| 441 : | |||
| 442 : | // remove meaningless entries from unknown-format files | ||
| 443 : | if (empty($this->info['fileformat'])) { | ||
| 444 : | if (isset($this->info['avdataoffset'])) { | ||
| 445 : | unset($this->info['avdataoffset']); | ||
| 446 : | } | ||
| 447 : | if (isset($this->info['avdataend'])) { | ||
| 448 : | unset($this->info['avdataend']); | ||
| 449 : | } | ||
| 450 : | } | ||
| 451 : | } | ||
| 452 : | |||
| 453 : | |||
| 454 : | // return array containing information about all supported formats | ||
| 455 : | function GetFileFormatArray() { | ||
| 456 : | static $format_info = array(); | ||
| 457 : | if (empty($format_info)) { | ||
| 458 : | $format_info = array( | ||
| 459 : | |||
| 460 : | // Audio formats | ||
| 461 : | |||
| 462 : | // AC-3 - audio - Dolby AC-3 / Dolby Digital | ||
| 463 : | 'ac3' => array( | ||
| 464 : | 'pattern' => '^\x0B\x77', | ||
| 465 : | 'group' => 'audio', | ||
| 466 : | 'module' => 'ac3', | ||
| 467 : | 'mime_type' => 'audio/ac3', | ||
| 468 : | ), | ||
| 469 : | |||
| 470 : | // AAC - audio - Advanced Audio Coding (AAC) - ADIF format | ||
| 471 : | 'adif' => array( | ||
| 472 : | 'pattern' => '^ADIF', | ||
| 473 : | 'group' => 'audio', | ||
| 474 : | 'module' => 'aac', | ||
| 475 : | 'option' => 'adif', | ||
| 476 : | 'mime_type' => 'application/octet-stream', | ||
| 477 : | 'fail_ape' => 'WARNING', | ||
| 478 : | ), | ||
| 479 : | |||
| 480 : | |||
| 481 : | // AAC - audio - Advanced Audio Coding (AAC) - ADTS format (very similar to MP3) | ||
| 482 : | 'adts' => array( | ||
| 483 : | 'pattern' => '^\xFF[\xF0-\xF1\xF8-\xF9]', | ||
| 484 : | 'group' => 'audio', | ||
| 485 : | 'module' => 'aac', | ||
| 486 : | 'option' => 'adts', | ||
| 487 : | 'mime_type' => 'application/octet-stream', | ||
| 488 : | 'fail_ape' => 'WARNING', | ||
| 489 : | ), | ||
| 490 : | |||
| 491 : | |||
| 492 : | // AU - audio - NeXT/Sun AUdio (AU) | ||
| 493 : | 'au' => array( | ||
| 494 : | 'pattern' => '^\.snd', | ||
| 495 : | 'group' => 'audio', | ||
| 496 : | 'module' => 'au', | ||
| 497 : | 'mime_type' => 'audio/basic', | ||
| 498 : | ), | ||
| 499 : | |||
| 500 : | // AVR - audio - Audio Visual Research | ||
| 501 : | 'avr' => array( | ||
| 502 : | 'pattern' => '^2BIT', | ||
| 503 : | 'group' => 'audio', | ||
| 504 : | 'module' => 'avr', | ||
| 505 : | 'mime_type' => 'application/octet-stream', | ||
| 506 : | ), | ||
| 507 : | |||
| 508 : | // BONK - audio - Bonk v0.9+ | ||
| 509 : | 'bonk' => array( | ||
| 510 : | 'pattern' => '^\x00(BONK|INFO|META| ID3)', | ||
| 511 : | 'group' => 'audio', | ||
| 512 : | 'module' => 'bonk', | ||
| 513 : | 'mime_type' => 'audio/xmms-bonk', | ||
| 514 : | ), | ||
| 515 : | |||
| 516 : | // FLAC - audio - Free Lossless Audio Codec | ||
| 517 : | 'flac' => array( | ||
| 518 : | 'pattern' => '^fLaC', | ||
| 519 : | 'group' => 'audio', | ||
| 520 : | 'module' => 'flac', | ||
| 521 : | 'mime_type' => 'audio/x-flac', | ||
| 522 : | ), | ||
| 523 : | |||
| 524 : | // LA - audio - Lossless Audio (LA) | ||
| 525 : | 'la' => array( | ||
| 526 : | 'pattern' => '^LA0[2-4]', | ||
| 527 : | 'group' => 'audio', | ||
| 528 : | 'module' => 'la', | ||
| 529 : | 'mime_type' => 'application/octet-stream', | ||
| 530 : | ), | ||
| 531 : | |||
| 532 : | // LPAC - audio - Lossless Predictive Audio Compression (LPAC) | ||
| 533 : | 'lpac' => array( | ||
| 534 : | 'pattern' => '^LPAC', | ||
| 535 : | 'group' => 'audio', | ||
| 536 : | 'module' => 'lpac', | ||
| 537 : | 'mime_type' => 'application/octet-stream', | ||
| 538 : | ), | ||
| 539 : | |||
| 540 : | // MIDI - audio - MIDI (Musical Instrument Digital Interface) | ||
| 541 : | 'midi' => array( | ||
| 542 : | 'pattern' => '^MThd', | ||
| 543 : | 'group' => 'audio', | ||
| 544 : | 'module' => 'midi', | ||
| 545 : | 'mime_type' => 'audio/midi', | ||
| 546 : | ), | ||
| 547 : | |||
| 548 : | // MAC - audio - Monkey's Audio Compressor | ||
| 549 : | 'mac' => array( | ||
| 550 : | 'pattern' => '^MAC ', | ||
| 551 : | 'group' => 'audio', | ||
| 552 : | 'module' => 'monkey', | ||
| 553 : | 'mime_type' => 'application/octet-stream', | ||
| 554 : | ), | ||
| 555 : | |||
| 556 : | // MOD - audio - MODule (assorted sub-formats) | ||
| 557 : | 'mod' => array( | ||
| 558 : | 'pattern' => '^.{1080}(M.K.|[5-9]CHN|[1-3][0-9]CH)', | ||
| 559 : | 'group' => 'audio', | ||
| 560 : | 'module' => 'mod', | ||
| 561 : | 'option' => 'mod', | ||
| 562 : | 'mime_type' => 'audio/mod', | ||
| 563 : | ), | ||
| 564 : | |||
| 565 : | // MOD - audio - MODule (Impulse Tracker) | ||
| 566 : | 'it' => array( | ||
| 567 : | 'pattern' => '^IMPM', | ||
| 568 : | 'group' => 'audio', | ||
| 569 : | 'module' => 'mod', | ||
| 570 : | 'option' => 'it', | ||
| 571 : | 'mime_type' => 'audio/it', | ||
| 572 : | ), | ||
| 573 : | |||
| 574 : | // MOD - audio - MODule (eXtended Module, various sub-formats) | ||
| 575 : | 'xm' => array( | ||
| 576 : | 'pattern' => '^Extended Module', | ||
| 577 : | 'group' => 'audio', | ||
| 578 : | 'module' => 'mod', | ||
| 579 : | 'option' => 'xm', | ||
| 580 : | 'mime_type' => 'audio/xm', | ||
| 581 : | ), | ||
| 582 : | |||
| 583 : | // MOD - audio - MODule (ScreamTracker) | ||
| 584 : | 's3m' => array( | ||
| 585 : | 'pattern' => '^.{44}SCRM', | ||
| 586 : | 'group' => 'audio', | ||
| 587 : | 'module' => 'mod', | ||
| 588 : | 'option' => 's3m', | ||
| 589 : | 'mime_type' => 'audio/s3m', | ||
| 590 : | ), | ||
| 591 : | |||
| 592 : | // MPC - audio - Musepack / MPEGplus | ||
| 593 : | 'mpc' => array( | ||
| 594 : | 'pattern' => '^(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])', | ||
| 595 : | 'group' => 'audio', | ||
| 596 : | 'module' => 'mpc', | ||
| 597 : | 'mime_type' => 'application/octet-stream', | ||
| 598 : | ), | ||
| 599 : | |||
| 600 : | // MP3 - audio - MPEG-audio Layer 3 (very similar to AAC-ADTS) | ||
| 601 : | 'mp3' => array( | ||
| 602 : | 'pattern' => '^\xFF[\xE2-\xE7\xF2-\xF7\xFA-\xFF][\x00-\xEB]', | ||
| 603 : | 'group' => 'audio', | ||
| 604 : | 'module' => 'mp3', | ||
| 605 : | 'mime_type' => 'audio/mpeg', | ||
| 606 : | ), | ||
| 607 : | |||
| 608 : | // OFR - audio - OptimFROG | ||
| 609 : | 'ofr' => array( | ||
| 610 : | 'pattern' => '^(\*RIFF|OFR)', | ||
| 611 : | 'group' => 'audio', | ||
| 612 : | 'module' => 'optimfrog', | ||
| 613 : | 'mime_type' => 'application/octet-stream', | ||
| 614 : | ), | ||
| 615 : | |||
| 616 : | // RKAU - audio - RKive AUdio compressor | ||
| 617 : | 'rkau' => array( | ||
| 618 : | 'pattern' => '^RKA', | ||
| 619 : | 'group' => 'audio', | ||
| 620 : | 'module' => 'rkau', | ||
| 621 : | 'mime_type' => 'application/octet-stream', | ||
| 622 : | ), | ||
| 623 : | |||
| 624 : | // SHN - audio - Shorten | ||
| 625 : | 'shn' => array( | ||
| 626 : | 'pattern' => '^ajkg', | ||
| 627 : | 'group' => 'audio', | ||
| 628 : | 'module' => 'shorten', | ||
| 629 : | 'mime_type' => 'audio/xmms-shn', | ||
| 630 : | 'fail_id3' => 'ERROR', | ||
| 631 : | 'fail_ape' => 'ERROR', | ||
| 632 : | ), | ||
| 633 : | |||
| 634 : | // TTA - audio - TTA Lossless Audio Compressor (http://tta.corecodec.org) | ||
| 635 : | 'tta' => array( | ||
| 636 : | 'pattern' => '^TTA', // could also be '^TTA(\x01|\x02|\x03|2|1)' | ||
| 637 : | 'group' => 'audio', | ||
| 638 : | 'module' => 'tta', | ||
| 639 : | 'mime_type' => 'application/octet-stream', | ||
| 640 : | ), | ||
| 641 : | |||
| 642 : | // VOC - audio - Creative Voice (VOC) | ||
| 643 : | 'voc' => array( | ||
| 644 : | 'pattern' => '^Creative Voice File', | ||
| 645 : | 'group' => 'audio', | ||
| 646 : | 'module' => 'voc', | ||
| 647 : | 'mime_type' => 'audio/voc', | ||
| 648 : | ), | ||
| 649 : | |||
| 650 : | // VQF - audio - transform-domain weighted interleave Vector Quantization Format (VQF) | ||
| 651 : | 'vqf' => array( | ||
| 652 : | 'pattern' => '^TWIN', | ||
| 653 : | 'group' => 'audio', | ||
| 654 : | 'module' => 'vqf', | ||
| 655 : | 'mime_type' => 'application/octet-stream', | ||
| 656 : | ), | ||
| 657 : | |||
| 658 : | // WV - audio - WavPack (v4.0+) | ||
| 659 : | 'wv' => array( | ||
| 660 : | 'pattern' => '^wvpk', | ||
| 661 : | 'group' => 'audio', | ||
| 662 : | 'module' => 'wavpack', | ||
| 663 : | 'mime_type' => 'application/octet-stream', | ||
| 664 : | ), | ||
| 665 : | |||
| 666 : | |||
| 667 : | // Audio-Video formats | ||
| 668 : | |||
| 669 : | // ASF - audio/video - Advanced Streaming Format, Windows Media Video, Windows Media Audio | ||
| 670 : | 'asf' => array( | ||
| 671 : | 'pattern' => '^\x30\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C', | ||
| 672 : | 'group' => 'audio-video', | ||
| 673 : | 'module' => 'asf', | ||
| 674 : | 'mime_type' => 'video/x-ms-asf', | ||
| 675 : | 'iconv_req' => false, | ||
| 676 : | ), | ||
| 677 : | |||
| 678 : | // BINK - audio/video - Bink / Smacker | ||
| 679 : | 'bink' => array( | ||
| 680 : | 'pattern' => '^(BIK|SMK)', | ||
| 681 : | 'group' => 'audio-video', | ||
| 682 : | 'module' => 'bink', | ||
| 683 : | 'mime_type' => 'application/octet-stream', | ||
| 684 : | ), | ||
| 685 : | |||
| 686 : | // FLV - audio/video - FLash Video | ||
| 687 : | 'flv' => array( | ||
| 688 : | 'pattern' => '^FLV\x01', | ||
| 689 : | 'group' => 'audio-video', | ||
| 690 : | 'module' => 'flv', | ||
| 691 : | 'mime_type' => 'video/x-flv', | ||
| 692 : | ), | ||
| 693 : | |||
| 694 : | // MKAV - audio/video - Mastroka | ||
| 695 : | 'matroska' => array( | ||
| 696 : | 'pattern' => '^\x1A\x45\xDF\xA3', | ||
| 697 : | 'group' => 'audio-video', | ||
| 698 : | 'module' => 'matroska', | ||
| 699 : | 'mime_type' => 'application/octet-stream', | ||
| 700 : | ), | ||
| 701 : | |||
| 702 : | // MPEG - audio/video - MPEG (Moving Pictures Experts Group) | ||
| 703 : | 'mpeg' => array( | ||
| 704 : | 'pattern' => '^\x00\x00\x01(\xBA|\xB3)', | ||
| 705 : | 'group' => 'audio-video', | ||
| 706 : | 'module' => 'mpeg', | ||
| 707 : | 'mime_type' => 'video/mpeg', | ||
| 708 : | ), | ||
| 709 : | |||
| 710 : | // NSV - audio/video - Nullsoft Streaming Video (NSV) | ||
| 711 : | 'nsv' => array( | ||
| 712 : | 'pattern' => '^NSV[sf]', | ||
| 713 : | 'group' => 'audio-video', | ||
| 714 : | 'module' => 'nsv', | ||
| 715 : | 'mime_type' => 'application/octet-stream', | ||
| 716 : | ), | ||
| 717 : | |||
| 718 : | // Ogg - audio/video - Ogg (Ogg-Vorbis, Ogg-FLAC, Speex, Ogg-Theora(*), Ogg-Tarkin(*)) | ||
| 719 : | 'ogg' => array( | ||
| 720 : | 'pattern' => '^OggS', | ||
| 721 : | 'group' => 'audio', | ||
| 722 : | 'module' => 'ogg', | ||
| 723 : | 'mime_type' => 'application/ogg', | ||
| 724 : | 'fail_id3' => 'WARNING', | ||
| 725 : | 'fail_ape' => 'WARNING', | ||
| 726 : | ), | ||
| 727 : | |||
| 728 : | // QT - audio/video - Quicktime | ||
| 729 : | 'quicktime' => array( | ||
| 730 : | 'pattern' => '^.{4}(cmov|free|ftyp|mdat|moov|pnot|skip|wide)', | ||
| 731 : | 'group' => 'audio-video', | ||
| 732 : | 'module' => 'quicktime', | ||
| 733 : | 'mime_type' => 'video/quicktime', | ||
| 734 : | ), | ||
| 735 : | |||
| 736 : | // 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) | ||
| 737 : | 'riff' => array( | ||
| 738 : | 'pattern' => '^(RIFF|SDSS|FORM)', | ||
| 739 : | 'group' => 'audio-video', | ||
| 740 : | 'module' => 'riff', | ||
| 741 : | 'mime_type' => 'audio/x-wave', | ||
| 742 : | 'fail_ape' => 'WARNING', | ||
| 743 : | ), | ||
| 744 : | |||
| 745 : | // Real - audio/video - RealAudio, RealVideo | ||
| 746 : | 'real' => array( | ||
| 747 : | 'pattern' => '^(\.RMF|.ra)', | ||
| 748 : | 'group' => 'audio-video', | ||
| 749 : | 'module' => 'real', | ||
| 750 : | 'mime_type' => 'audio/x-realaudio', | ||
| 751 : | ), | ||
| 752 : | |||
| 753 : | // SWF - audio/video - ShockWave Flash | ||
| 754 : | 'swf' => array( | ||
| 755 : | 'pattern' => '^(F|C)WS', | ||
| 756 : | 'group' => 'audio-video', | ||
| 757 : | 'module' => 'swf', | ||
| 758 : | 'mime_type' => 'application/x-shockwave-flash', | ||
| 759 : | ), | ||
| 760 : | |||
| 761 : | |||
| 762 : | // Still-Image formats | ||
| 763 : | |||
| 764 : | // BMP - still image - Bitmap (Windows, OS/2; uncompressed, RLE8, RLE4) | ||
| 765 : | 'bmp' => array( | ||
| 766 : | 'pattern' => '^BM', | ||
| 767 : | 'group' => 'graphic', | ||
| 768 : | 'module' => 'bmp', | ||
| 769 : | 'mime_type' => 'image/bmp', | ||
| 770 : | 'fail_id3' => 'ERROR', | ||
| 771 : | 'fail_ape' => 'ERROR', | ||
| 772 : | ), | ||
| 773 : | |||
| 774 : | // GIF - still image - Graphics Interchange Format | ||
| 775 : | 'gif' => array( | ||
| 776 : | 'pattern' => '^GIF', | ||
| 777 : | 'group' => 'graphic', | ||
| 778 : | 'module' => 'gif', | ||
| 779 : | 'mime_type' => 'image/gif', | ||
| 780 : | 'fail_id3' => 'ERROR', | ||
| 781 : | 'fail_ape' => 'ERROR', | ||
| 782 : | ), | ||
| 783 : | |||
| 784 : | // JPEG - still image - Joint Photographic Experts Group (JPEG) | ||
| 785 : | 'jpg' => array( | ||
| 786 : | 'pattern' => '^\xFF\xD8\xFF', | ||
| 787 : | 'group' => 'graphic', | ||
| 788 : | 'module' => 'jpg', | ||
| 789 : | 'mime_type' => 'image/jpeg', | ||
| 790 : | 'fail_id3' => 'ERROR', | ||
| 791 : | 'fail_ape' => 'ERROR', | ||
| 792 : | ), | ||
| 793 : | |||
| 794 : | // PCD - still image - Kodak Photo CD | ||
| 795 : | 'pcd' => array( | ||
| 796 : | 'pattern' => '^.{2048}PCD_IPI\x00', | ||
| 797 : | 'group' => 'graphic', | ||
| 798 : | 'module' => 'pcd', | ||
| 799 : | 'mime_type' => 'image/x-photo-cd', | ||
| 800 : | 'fail_id3' => 'ERROR', | ||
| 801 : | 'fail_ape' => 'ERROR', | ||
| 802 : | ), | ||
| 803 : | |||
| 804 : | |||
| 805 : | // PNG - still image - Portable Network Graphics (PNG) | ||
| 806 : | 'png' => array( | ||
| 807 : | 'pattern' => '^\x89\x50\x4E\x47\x0D\x0A\x1A\x0A', | ||
| 808 : | 'group' => 'graphic', | ||
| 809 : | 'module' => 'png', | ||
| 810 : | 'mime_type' => 'image/png', | ||
| 811 : | 'fail_id3' => 'ERROR', | ||
| 812 : | 'fail_ape' => 'ERROR', | ||
| 813 : | ), | ||
| 814 : | |||
| 815 : | |||
| 816 : | // TIFF - still image - Tagged Information File Format (TIFF) | ||
| 817 : | 'tiff' => array( | ||
| 818 : | 'pattern' => '^(II\x2A\x00|MM\x00\x2A)', | ||
| 819 : | 'group' => 'graphic', | ||
| 820 : | 'module' => 'tiff', | ||
| 821 : | 'mime_type' => 'image/tiff', | ||
| 822 : | 'fail_id3' => 'ERROR', | ||
| 823 : | 'fail_ape' => 'ERROR', | ||
| 824 : | ), | ||
| 825 : | |||
| 826 : | |||
| 827 : | // Data formats | ||
| 828 : | |||
| 829 : | // ISO - data - International Standards Organization (ISO) CD-ROM Image | ||
| 830 : | 'iso' => array( | ||
| 831 : | 'pattern' => '^.{32769}CD001', | ||
| 832 : | 'group' => 'misc', | ||
| 833 : | 'module' => 'iso', | ||
| 834 : | 'mime_type' => 'application/octet-stream', | ||
| 835 : | 'fail_id3' => 'ERROR', | ||
| 836 : | 'fail_ape' => 'ERROR', | ||
| 837 : | 'iconv_req' => false, | ||
| 838 : | ), | ||
| 839 : | |||
| 840 : | // RAR - data - RAR compressed data | ||
| 841 : | 'rar' => array( | ||
| 842 : | 'pattern' => '^Rar\!', | ||
| 843 : | 'group' => 'archive', | ||
| 844 : | 'module' => 'rar', | ||
| 845 : | 'mime_type' => 'application/octet-stream', | ||
| 846 : | 'fail_id3' => 'ERROR', | ||
| 847 : | 'fail_ape' => 'ERROR', | ||
| 848 : | ), | ||
| 849 : | |||
| 850 : | // SZIP - audio/data - SZIP compressed data | ||
| 851 : | 'szip' => array( | ||
| 852 : | 'pattern' => '^SZ\x0A\x04', | ||
| 853 : | 'group' => 'archive', | ||
| 854 : | 'module' => 'szip', | ||
| 855 : | 'mime_type' => 'application/octet-stream', | ||
| 856 : | 'fail_id3' => 'ERROR', | ||
| 857 : | 'fail_ape' => 'ERROR', | ||
| 858 : | ), | ||
| 859 : | |||
| 860 : | // TAR - data - TAR compressed data | ||
| 861 : | 'tar' => array( | ||
| 862 : | '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}', | ||
| 863 : | 'group' => 'archive', | ||
| 864 : | 'module' => 'tar', | ||
| 865 : | 'mime_type' => 'application/x-tar', | ||
| 866 : | 'fail_id3' => 'ERROR', | ||
| 867 : | 'fail_ape' => 'ERROR', | ||
| 868 : | ), | ||
| 869 : | |||
| 870 : | // GZIP - data - GZIP compressed data | ||
| 871 : | 'gz' => array( | ||
| 872 : | 'pattern' => '^\x1F\x8B\x08', | ||
| 873 : | 'group' => 'archive', | ||
| 874 : | 'module' => 'gzip', | ||
| 875 : | 'mime_type' => 'application/x-gzip', | ||
| 876 : | 'fail_id3' => 'ERROR', | ||
| 877 : | 'fail_ape' => 'ERROR', | ||
| 878 : | ), | ||
| 879 : | |||
| 880 : | // ZIP - data - ZIP compressed data | ||
| 881 : | 'zip' => array( | ||
| 882 : | 'pattern' => '^PK\x03\x04', | ||
| 883 : | 'group' => 'archive', | ||
| 884 : | 'module' => 'zip', | ||
| 885 : | 'mime_type' => 'application/zip', | ||
| 886 : | 'fail_id3' => 'ERROR', | ||
| 887 : | 'fail_ape' => 'ERROR', | ||
| 888 : | ), | ||
| 889 : | |||
| 890 : | |||
| 891 : | // Misc other formats | ||
| 892 : | |||
| 893 : | // PDF - data - ZIP compressed data | ||
| 894 : | 'pdf' => array( | ||
| 895 : | 'pattern' => '^\x25PDF', | ||
| 896 : | 'group' => 'misc', | ||
| 897 : | 'module' => 'pdf', | ||
| 898 : | 'mime_type' => 'application/pdf', | ||
| 899 : | 'fail_id3' => 'ERROR', | ||
| 900 : | 'fail_ape' => 'ERROR', | ||
| 901 : | ), | ||
| 902 : | |||
| 903 : | // MSOFFICE - data - ZIP compressed data | ||
| 904 : | 'msoffice' => array( | ||
| 905 : | 'pattern' => '^\xD0\xCF\x11\xE0', // D0CF11E == DOCFILE == Microsoft Office Document | ||
| 906 : | 'group' => 'misc', | ||
| 907 : | 'module' => 'msoffice', | ||
| 908 : | 'mime_type' => 'application/octet-stream', | ||
| 909 : | 'fail_id3' => 'ERROR', | ||
| 910 : | 'fail_ape' => 'ERROR', | ||
| 911 : | ), | ||
| 912 : | ); | ||
| 913 : | } | ||
| 914 : | |||
| 915 : | return $format_info; | ||
| 916 : | } | ||
| 917 : | |||
| 918 : | |||
| 919 : | |||
| 920 : | function GetFileFormat(&$filedata, $filename='') { | ||
| 921 : | // this function will determine the format of a file based on usually | ||
| 922 : | // the first 2-4 bytes of the file (8 bytes for PNG, 16 bytes for JPG, | ||
| 923 : | // and in the case of ISO CD image, 6 bytes offset 32kb from the start | ||
| 924 : | // of the file). | ||
| 925 : | |||
| 926 : | // Identify file format - loop through $format_info and detect with reg expr | ||
| 927 : | foreach ($this->GetFileFormatArray() as $format_name => $info) { | ||
| 928 : | // Using preg_match() instead of ereg() - much faster | ||
| 929 : | // The /s switch on preg_match() forces preg_match() NOT to treat | ||
| 930 : | // newline (0x0A) characters as special chars but do a binary match | ||
| 931 : | if (preg_match('/'.$info['pattern'].'/s', $filedata)) { | ||
| 932 : | $info['include'] = 'module.'.$info['group'].'.'.$info['module'].'.php'; | ||
| 933 : | return $info; | ||
| 934 : | } | ||
| 935 : | } | ||
| 936 : | |||
| 937 : | |||
| 938 : | if (preg_match('/\.mp[123a]$/i', $filename)) { | ||
| 939 : | // Too many mp3 encoders on the market put gabage in front of mpeg files | ||
| 940 : | // use assume format on these if format detection failed | ||
| 941 : | $GetFileFormatArray = $this->GetFileFormatArray(); | ||
| 942 : | $info = $GetFileFormatArray['mp3']; | ||
| 943 : | $info['include'] = 'module.'.$info['group'].'.'.$info['module'].'.php'; | ||
| 944 : | return $info; | ||
| 945 : | } | ||
| 946 : | |||
| 947 : | return false; | ||
| 948 : | } | ||
| 949 : | |||
| 950 : | |||
| 951 : | // converts array to $encoding charset from $this->encoding | ||
| 952 : | function CharConvert(&$array, $encoding) { | ||
| 953 : | |||
| 954 : | // identical encoding - end here | ||
| 955 : | if ($encoding == $this->encoding) { | ||
| 956 : | return; | ||
| 957 : | } | ||
| 958 : | |||
| 959 : | // loop thru array | ||
| 960 : | foreach ($array as $key => $value) { | ||
| 961 : | |||
| 962 : | // go recursive | ||
| 963 : | if (is_array($value)) { | ||
| 964 : | $this->CharConvert($array[$key], $encoding); | ||
| 965 : | } | ||
| 966 : | |||
| 967 : | // convert string | ||
| 968 : | elseif (is_string($value)) { | ||
| 969 : | $array[$key] = trim(getid3_lib::iconv_fallback($encoding, $this->encoding, $value)); | ||
| 970 : | } | ||
| 971 : | } | ||
| 972 : | } | ||
| 973 : | |||
| 974 : | |||
| 975 : | function HandleAllTags() { | ||
| 976 : | |||
| 977 : | // key name => array (tag name, character encoding) | ||
| 978 : | static $tags; | ||
| 979 : | if (empty($tags)) { | ||
| 980 : | $tags = array( | ||
| 981 : | 'asf' => array('asf' , 'UTF-16LE'), | ||
| 982 : | 'midi' => array('midi' , 'ISO-8859-1'), | ||
| 983 : | 'nsv' => array('nsv' , 'ISO-8859-1'), | ||
| 984 : | 'ogg' => array('vorbiscomment' , 'UTF-8'), | ||
| 985 : | 'png' => array('png' , 'UTF-8'), | ||
| 986 : | 'tiff' => array('tiff' , 'ISO-8859-1'), | ||
| 987 : | 'quicktime' => array('quicktime' , 'ISO-8859-1'), | ||
| 988 : | 'real' => array('real' , 'ISO-8859-1'), | ||
| 989 : | 'vqf' => array('vqf' , 'ISO-8859-1'), | ||
| 990 : | 'zip' => array('zip' , 'ISO-8859-1'), | ||
| 991 : | 'riff' => array('riff' , 'ISO-8859-1'), | ||
| 992 : | 'lyrics3' => array('lyrics3' , 'ISO-8859-1'), | ||
| 993 : | 'id3v1' => array('id3v1' , $this->encoding_id3v1), | ||
| 994 : | 'id3v2' => array('id3v2' , 'UTF-8'), // not according to the specs (every frame can have a different encoding), but getID3() force-converts all encodings to UTF-8 | ||
| 995 : | 'ape' => array('ape' , 'UTF-8') | ||
| 996 : | ); | ||
| 997 : | } | ||
| 998 : | |||
| 999 : | // loop thru comments array | ||
| 1000 : | foreach ($tags as $comment_name => $tagname_encoding_array) { | ||
| 1001 : | list($tag_name, $encoding) = $tagname_encoding_array; | ||
| 1002 : | |||
| 1003 : | // fill in default encoding type if not already present | ||
| 1004 : | if (isset($this->info[$comment_name]) && !isset($this->info[$comment_name]['encoding'])) { | ||
| 1005 : | $this->info[$comment_name]['encoding'] = $encoding; | ||
| 1006 : | } | ||
| 1007 : | |||
| 1008 : | // copy comments if key name set | ||
| 1009 : | if (!empty($this->info[$comment_name]['comments'])) { | ||
| 1010 : | |||
| 1011 : | foreach ($this->info[$comment_name]['comments'] as $tag_key => $valuearray) { | ||
| 1012 : | foreach ($valuearray as $key => $value) { | ||
| 1013 : | if (strlen(trim($value)) > 0) { | ||
| 1014 : | $this->info['tags'][trim($tag_name)][trim($tag_key)][] = $value; // do not trim!! Unicode characters will get mangled if trailing nulls are removed! | ||
| 1015 : | } | ||
| 1016 : | } | ||
| 1017 : | } | ||
| 1018 : | |||
| 1019 : | if (!isset($this->info['tags'][$tag_name])) { | ||
| 1020 : | // comments are set but contain nothing but empty strings, so skip | ||
| 1021 : | continue; | ||
| 1022 : | } | ||
| 1023 : | |||
| 1024 : | if ($this->option_tags_html) { | ||
| 1025 : | foreach ($this->info['tags'][$tag_name] as $tag_key => $valuearray) { | ||
| 1026 : | foreach ($valuearray as $key => $value) { | ||
| 1027 : | if (is_string($value)) { | ||
| 1028 : | //$this->info['tags_html'][$tag_name][$tag_key][$key] = getid3_lib::MultiByteCharString2HTML($value, $encoding); | ||
| 1029 : | $this->info['tags_html'][$tag_name][$tag_key][$key] = str_replace('�', '', getid3_lib::MultiByteCharString2HTML($value, $encoding)); | ||
| 1030 : | } else { | ||
| 1031 : | $this->info['tags_html'][$tag_name][$tag_key][$key] = $value; | ||
| 1032 : | } | ||
| 1033 : | } | ||
| 1034 : | } | ||
| 1035 : | } | ||
| 1036 : | |||
| 1037 : | $this->CharConvert($this->info['tags'][$tag_name], $encoding); // only copy gets converted! | ||
| 1038 : | } | ||
| 1039 : | |||
| 1040 : | } | ||
| 1041 : | return true; | ||
| 1042 : | } | ||
| 1043 : | |||
| 1044 : | |||
| 1045 : | function getHashdata($algorithm) { | ||
| 1046 : | switch ($algorithm) { | ||
| 1047 : | case 'md5': | ||
| 1048 : | case 'sha1': | ||
| 1049 : | break; | ||
| 1050 : | |||
| 1051 : | default: | ||
| 1052 : | return $this->error('bad algorithm "'.$algorithm.'" in getHashdata()'); | ||
| 1053 : | break; | ||
| 1054 : | } | ||
| 1055 : | |||
| 1056 : | if ((@$this->info['fileformat'] == 'ogg') && (@$this->info['audio']['dataformat'] == 'vorbis')) { | ||
| 1057 : | |||
| 1058 : | // We cannot get an identical md5_data value for Ogg files where the comments | ||
| 1059 : | // span more than 1 Ogg page (compared to the same audio data with smaller | ||
| 1060 : | // comments) using the normal getID3() method of MD5'ing the data between the | ||
| 1061 : | // end of the comments and the end of the file (minus any trailing tags), | ||
| 1062 : | // because the page sequence numbers of the pages that the audio data is on | ||
| 1063 : | // do not match. Under normal circumstances, where comments are smaller than | ||
| 1064 : | // the nominal 4-8kB page size, then this is not a problem, but if there are | ||
| 1065 : | // very large comments, the only way around it is to strip off the comment | ||
| 1066 : | // tags with vorbiscomment and MD5 that file. | ||
| 1067 : | // This procedure must be applied to ALL Ogg files, not just the ones with | ||
| 1068 : | // comments larger than 1 page, because the below method simply MD5's the | ||
| 1069 : | // whole file with the comments stripped, not just the portion after the | ||
| 1070 : | // comments block (which is the standard getID3() method. | ||
| 1071 : | |||
| 1072 : | // The above-mentioned problem of comments spanning multiple pages and changing | ||
| 1073 : | // page sequence numbers likely happens for OggSpeex and OggFLAC as well, but | ||
| 1074 : | // currently vorbiscomment only works on OggVorbis files. | ||
| 1075 : | |||
| 1076 : | if ((bool) ini_get('safe_mode')) { | ||
| 1077 : | |||
| 1078 : | $this->info['warning'][] = 'Failed making system call to vorbiscomment.exe - '.$algorithm.'_data is incorrect - error returned: PHP running in Safe Mode (backtick operator not available)'; | ||
| 1079 : | $this->info[$algorithm.'_data'] = false; | ||
| 1080 : | |||
| 1081 : | } else { | ||
| 1082 : | |||
| 1083 : | // Prevent user from aborting script | ||
| 1084 : | $old_abort = ignore_user_abort(true); | ||
| 1085 : | |||
| 1086 : | // Create empty file | ||
| 1087 : | $empty = tempnam('*', 'getID3'); | ||
| 1088 : | touch($empty); | ||
| 1089 : | |||
| 1090 : | |||
| 1091 : | // Use vorbiscomment to make temp file without comments | ||
| 1092 : | $temp = tempnam('*', 'getID3'); | ||
| 1093 : | $file = $this->info['filenamepath']; | ||
| 1094 : | |||
| 1095 : | if (GETID3_OS_ISWINDOWS) { | ||
| 1096 : | |||
| 1097 : | if (file_exists(GETID3_HELPERAPPSDIR.'vorbiscomment.exe')) { | ||
| 1098 : | |||
| 1099 : | $commandline = '"'.GETID3_HELPERAPPSDIR.'vorbiscomment.exe" -w -c "'.$empty.'" "'.$file.'" "'.$temp.'"'; | ||
| 1100 : | $VorbisCommentError = `$commandline`; | ||
| 1101 : | |||
| 1102 : | } else { | ||
| 1103 : | |||
| 1104 : | $VorbisCommentError = 'vorbiscomment.exe not found in '.GETID3_HELPERAPPSDIR; | ||
| 1105 : | |||
| 1106 : | } | ||
| 1107 : | |||
| 1108 : | } else { | ||
| 1109 : | |||
| 1110 : | $commandline = 'vorbiscomment -w -c "'.$empty.'" "'.$file.'" "'.$temp.'" 2>&1'; | ||
| 1111 : | $commandline = 'vorbiscomment -w -c '.escapeshellarg($empty).' '.escapeshellarg($file).' '.escapeshellarg($temp).' 2>&1'; | ||
| 1112 : | $VorbisCommentError = `$commandline`; | ||
| 1113 : | |||
| 1114 : | } | ||
| 1115 : | |||
| 1116 : | if (!empty($VorbisCommentError)) { | ||
| 1117 : | |||
| 1118 : | $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; | ||
| 1119 : | $this->info[$algorithm.'_data'] = false; | ||
| 1120 : | |||
| 1121 : | } else { | ||
| 1122 : | |||
| 1123 : | // Get hash of newly created file | ||
| 1124 : | switch ($algorithm) { | ||
| 1125 : | case 'md5': | ||
| 1126 : | $this->info[$algorithm.'_data'] = getid3_lib::md5_file($temp); | ||
| 1127 : | break; | ||
| 1128 : | |||
| 1129 : | case 'sha1': | ||
| 1130 : | $this->info[$algorithm.'_data'] = getid3_lib::sha1_file($temp); | ||
| 1131 : | break; | ||
| 1132 : | } | ||
| 1133 : | } | ||
| 1134 : | |||
| 1135 : | // Clean up | ||
| 1136 : | unlink($empty); | ||
| 1137 : | unlink($temp); | ||
| 1138 : | |||
| 1139 : | // Reset abort setting | ||
| 1140 : | ignore_user_abort($old_abort); | ||
| 1141 : | |||
| 1142 : | } | ||
| 1143 : | |||
| 1144 : | } else { | ||
| 1145 : | |||
| 1146 : | if (!empty($this->info['avdataoffset']) || (isset($this->info['avdataend']) && ($this->info['avdataend'] < $this->info['filesize']))) { | ||
| 1147 : | |||
| 1148 : | // get hash from part of file | ||
| 1149 : | $this->info[$algorithm.'_data'] = getid3_lib::hash_data($this->info['filenamepath'], $this->info['avdataoffset'], $this->info['avdataend'], $algorithm); | ||
| 1150 : | |||
| 1151 : | } else { | ||
| 1152 : | |||
| 1153 : | // get hash from whole file | ||
| 1154 : | switch ($algorithm) { | ||
| 1155 : | case 'md5': | ||
| 1156 : | $this->info[$algorithm.'_data'] = getid3_lib::md5_file($this->info['filenamepath']); | ||
| 1157 : | break; | ||
| 1158 : | |||
| 1159 : | case 'sha1': | ||
| 1160 : | $this->info[$algorithm.'_data'] = getid3_lib::sha1_file($this->info['filenamepath']); | ||
| 1161 : | break; | ||
| 1162 : | } | ||
| 1163 : | } | ||
| 1164 : | |||
| 1165 : | } | ||
| 1166 : | return true; | ||
| 1167 : | } | ||
| 1168 : | |||
| 1169 : | |||
| 1170 : | function ChannelsBitratePlaytimeCalculations() { | ||
| 1171 : | |||
| 1172 : | // set channelmode on audio | ||
| 1173 : | if (@$this->info['audio']['channels'] == '1') { | ||
| 1174 : | $this->info['audio']['channelmode'] = 'mono'; | ||
| 1175 : | } elseif (@$this->info['audio']['channels'] == '2') { | ||
| 1176 : | $this->info['audio']['channelmode'] = 'stereo'; | ||
| 1177 : | } | ||
| 1178 : | |||
| 1179 : | // Calculate combined bitrate - audio + video | ||
| 1180 : | $CombinedBitrate = 0; | ||
| 1181 : | $CombinedBitrate += (isset($this->info['audio']['bitrate']) ? $this->info['audio']['bitrate'] : 0); | ||
| 1182 : | $CombinedBitrate += (isset($this->info['video']['bitrate']) ? $this->info['video']['bitrate'] : 0); | ||
| 1183 : | if (($CombinedBitrate > 0) && empty($this->info['bitrate'])) { | ||
| 1184 : | $this->info['bitrate'] = $CombinedBitrate; | ||
| 1185 : | } | ||
| 1186 : | //if ((isset($this->info['video']) && !isset($this->info['video']['bitrate'])) || (isset($this->info['audio']) && !isset($this->info['audio']['bitrate']))) { | ||
| 1187 : | // // for example, VBR MPEG video files cannot determine video bitrate: | ||
| 1188 : | // // should not set overall bitrate and playtime from audio bitrate only | ||
| 1189 : | // unset($this->info['bitrate']); | ||
| 1190 : | //} | ||
| 1191 : | |||
| 1192 : | if (!isset($this->info['playtime_seconds']) && !empty($this->info['bitrate'])) { | ||
| 1193 : | $this->info['playtime_seconds'] = (($this->info['avdataend'] - $this->info['avdataoffset']) * 8) / $this->info['bitrate']; | ||
| 1194 : | } | ||
| 1195 : | |||
| 1196 : | // Set playtime string | ||
| 1197 : | if (!empty($this->info['playtime_seconds']) && empty($this->info['playtime_string'])) { | ||
| 1198 : | $this->info['playtime_string'] = getid3_lib::PlaytimeString($this->info['playtime_seconds']); | ||
| 1199 : | } | ||
| 1200 : | } | ||
| 1201 : | |||
| 1202 : | |||
| 1203 : | function CalculateCompressionRatioVideo() { | ||
| 1204 : | if (empty($this->info['video'])) { | ||
| 1205 : | return false; | ||
| 1206 : | } | ||
| 1207 : | if (empty($this->info['video']['resolution_x']) || empty($this->info['video']['resolution_y'])) { | ||
| 1208 : | return false; | ||
| 1209 : | } | ||
| 1210 : | if (empty($this->info['video']['bits_per_sample'])) { | ||
| 1211 : | return false; | ||
| 1212 : | } | ||
| 1213 : | |||
| 1214 : | switch ($this->info['video']['dataformat']) { | ||
| 1215 : | case 'bmp': | ||
| 1216 : | case 'gif': | ||
| 1217 : | case 'jpeg': | ||
| 1218 : | case 'jpg': | ||
| 1219 : | case 'png': | ||
| 1220 : | case 'tiff': | ||
| 1221 : | $FrameRate = 1; | ||
| 1222 : | $PlaytimeSeconds = 1; | ||
| 1223 : | $BitrateCompressed = $this->info['filesize'] * 8; | ||
| 1224 : | break; | ||
| 1225 : | |||
| 1226 : | default: | ||
| 1227 : | if (!empty($this->info['video']['frame_rate'])) { | ||
| 1228 : | $FrameRate = $this->info['video']['frame_rate']; | ||
| 1229 : | } else { | ||
| 1230 : | return false; | ||
| 1231 : | } | ||
| 1232 : | if (!empty($this->info['playtime_seconds'])) { | ||
| 1233 : | $PlaytimeSeconds = $this->info['playtime_seconds']; | ||
| 1234 : | } else { | ||
| 1235 : | return false; | ||
| 1236 : | } | ||
| 1237 : | if (!empty($this->info['video']['bitrate'])) { | ||
| 1238 : | $BitrateCompressed = $this->info['video']['bitrate']; | ||
| 1239 : | } else { | ||
| 1240 : | return false; | ||
| 1241 : | } | ||
| 1242 : | break; | ||
| 1243 : | } | ||
| 1244 : | $BitrateUncompressed = $this->info['video']['resolution_x'] * $this->info['video']['resolution_y'] * $this->info['video']['bits_per_sample'] * $FrameRate; | ||
| 1245 : | |||
| 1246 : | $this->info['video']['compression_ratio'] = $BitrateCompressed / $BitrateUncompressed; | ||
| 1247 : | return true; | ||
| 1248 : | } | ||
| 1249 : | |||
| 1250 : | |||
| 1251 : | function CalculateCompressionRatioAudio() { | ||
| 1252 : | if (empty($this->info['audio']['bitrate']) || empty($this->info['audio']['channels']) || empty($this->info['audio']['sample_rate'])) { | ||
| 1253 : | return false; | ||
| 1254 : | } | ||
| 1255 : | $this->info['audio']['compression_ratio'] = $this->info['audio']['bitrate'] / ($this->info['audio']['channels'] * $this->info['audio']['sample_rate'] * (!empty($this->info['audio']['bits_per_sample']) ? $this->info['audio']['bits_per_sample'] : 16)); | ||
| 1256 : | |||
| 1257 : | if (!empty($this->info['audio']['streams'])) { | ||
| 1258 : | foreach ($this->info['audio']['streams'] as $streamnumber => $streamdata) { | ||
| 1259 : | if (!empty($streamdata['bitrate']) && !empty($streamdata['channels']) && !empty($streamdata['sample_rate'])) { | ||
| 1260 : | $this->info['audio']['streams'][$streamnumber]['compression_ratio'] = $streamdata['bitrate'] / ($streamdata['channels'] * $streamdata['sample_rate'] * (!empty($streamdata['bits_per_sample']) ? $streamdata['bits_per_sample'] : 16)); | ||
| 1261 : | } | ||
| 1262 : | } | ||
| 1263 : | } | ||
| 1264 : | return true; | ||
| 1265 : | } | ||
| 1266 : | |||
| 1267 : | |||
| 1268 : | function CalculateReplayGain() { | ||
| 1269 : | if (isset($this->info['replay_gain'])) { | ||
| 1270 : | $this->info['replay_gain']['reference_volume'] = 89; | ||
| 1271 : | if (isset($this->info['replay_gain']['track']['adjustment'])) { | ||
| 1272 : | $this->info['replay_gain']['track']['volume'] = $this->info['replay_gain']['reference_volume'] - $this->info['replay_gain']['track']['adjustment']; | ||
| 1273 : | } | ||
| 1274 : | if (isset($this->info['replay_gain']['album']['adjustment'])) { | ||
| 1275 : | $this->info['replay_gain']['album']['volume'] = $this->info['replay_gain']['reference_volume'] - $this->info['replay_gain']['album']['adjustment']; | ||
| 1276 : | } | ||
| 1277 : | |||
| 1278 : | if (isset($this->info['replay_gain']['track']['peak'])) { | ||
| 1279 : | $this->info['replay_gain']['track']['max_noclip_gain'] = 0 - getid3_lib::RGADamplitude2dB($this->info['replay_gain']['track']['peak']); | ||
| 1280 : | } | ||
| 1281 : | if (isset($this->info['replay_gain']['album']['peak'])) { | ||
| 1282 : | $this->info['replay_gain']['album']['max_noclip_gain'] = 0 - getid3_lib::RGADamplitude2dB($this->info['replay_gain']['album']['peak']); | ||
| 1283 : | } | ||
| 1284 : | } | ||
| 1285 : | return true; | ||
| 1286 : | } | ||
| 1287 : | |||
| 1288 : | function ProcessAudioStreams() { | ||
| 1289 : | if (!empty($this->info['audio']['bitrate']) || !empty($this->info['audio']['channels']) || !empty($this->info['audio']['sample_rate'])) { | ||
| 1290 : | if (!isset($this->info['audio']['streams'])) { | ||
| 1291 : | foreach ($this->info['audio'] as $key => $value) { | ||
| 1292 : | if ($key != 'streams') { | ||
| 1293 : | $this->info['audio']['streams'][0][$key] = $value; | ||
| 1294 : | } | ||
| 1295 : | } | ||
| 1296 : | } | ||
| 1297 : | } | ||
| 1298 : | return true; | ||
| 1299 : | } | ||
| 1300 : | |||
| 1301 : | function getid3_tempnam() { | ||
| 1302 : | return tempnam($this->tempdir, 'gI3'); | ||
| 1303 : | } | ||
| 1304 : | |||
| 1305 : | } | ||
| 1306 : | |||
| 1307 : | ?> |
| ViewVC Help | |
| Powered by ViewVC 1.0.0 |
Web Hosting provided by Network Redux.

