PageRenderTime 56ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/common/libraries/plugin/osflvplayer/flash/getid3.php

https://bitbucket.org/cbenelug/chamilo
PHP | 1182 lines | 801 code | 206 blank | 175 comment | 129 complexity | 878cd42ed3be08a759889694ab82ce28 MD5 | raw file
Possible License(s): GPL-3.0, MIT, GPL-2.0, BSD-3-Clause, LGPL-2.1, LGPL-3.0

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /////////////////////////////////////////////////////////////////
  3. /// getID3() by James Heinrich <info@getid3.org> //
  4. // available at http://getid3.sourceforge.net //
  5. // or http://www.getid3.org //
  6. /////////////////////////////////////////////////////////////////
  7. // //
  8. // Please see readme.txt for more information //
  9. // ///
  10. /////////////////////////////////////////////////////////////////
  11. // Defines
  12. define('GETID3_VERSION', '1.7.7');
  13. define('GETID3_FREAD_BUFFER_SIZE', 16384); // read buffer size in bytes
  14. class getID3
  15. {
  16. // public: Settings
  17. var $encoding = 'ISO-8859-1'; // CASE SENSITIVE! - i.e. (must be supported by iconv())
  18. // Examples: ISO-8859-1 UTF-8 UTF-16 UTF-16BE
  19. 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'
  20. var $tempdir = '*'; // default '*' should use system temp dir
  21. // public: Optional tag checks - disable for speed.
  22. var $option_tag_id3v1 = true; // Read and process ID3v1 tags
  23. var $option_tag_id3v2 = true; // Read and process ID3v2 tags
  24. var $option_tag_lyrics3 = true; // Read and process Lyrics3 tags
  25. var $option_tag_apetag = true; // Read and process APE tags
  26. var $option_tags_process = true; // Copy tags to root key 'tags' and encode to $this->encoding
  27. var $option_tags_html = true; // Copy tags to root key 'tags_html' properly translated from various encodings to HTML entities
  28. // public: Optional tag/comment calucations
  29. var $option_extra_info = true; // Calculate additional info such as bitrate, channelmode etc
  30. // public: Optional calculations
  31. var $option_md5_data = false; // Get MD5 sum of data part - slow
  32. var $option_md5_data_source = false; // Use MD5 of source file if availble - only FLAC and OptimFROG
  33. var $option_sha1_data = false; // Get SHA1 sum of data part - slow
  34. var $option_max_2gb_check = true; // Check whether file is larger than 2 Gb and thus not supported by PHP
  35. // private
  36. var $filename;
  37. // public: constructor
  38. function getID3()
  39. {
  40. $this->startup_error = '';
  41. $this->startup_warning = '';
  42. // Check for PHP version >= 4.1.0
  43. if (phpversion() < '4.1.0')
  44. {
  45. $this->startup_error .= 'getID3() requires PHP v4.1.0 or higher - you are running v' . phpversion();
  46. }
  47. // Check memory
  48. $memory_limit = ini_get('memory_limit');
  49. if (eregi('([0-9]+)M', $memory_limit, $matches))
  50. {
  51. // could be stored as "16M" rather than 16777216 for example
  52. $memory_limit = $matches[1] * 1048576;
  53. }
  54. if ($memory_limit <= 0)
  55. {
  56. // memory limits probably disabled
  57. }
  58. elseif ($memory_limit <= 3145728)
  59. {
  60. $this->startup_error .= 'PHP has less than 3MB available memory and will very likely run out. Increase memory_limit in php.ini';
  61. }
  62. elseif ($memory_limit <= 12582912)
  63. {
  64. $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';
  65. }
  66. // Check safe_mode off
  67. if ((bool) ini_get('safe_mode'))
  68. {
  69. $this->warning('WARNING: Safe mode is on, shorten support disabled, md5data/sha1data for ogg vorbis disabled, ogg vorbos/flac tag writing disabled.');
  70. }
  71. // define a constant rather than looking up every time it is needed
  72. if (! defined('GETID3_OS_ISWINDOWS'))
  73. {
  74. if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN')
  75. {
  76. define('GETID3_OS_ISWINDOWS', true);
  77. }
  78. else
  79. {
  80. define('GETID3_OS_ISWINDOWS', false);
  81. }
  82. }
  83. // Get base path of getID3() - ONCE
  84. if (! defined('GETID3_INCLUDEPATH'))
  85. {
  86. foreach (get_included_files() as $key => $val)
  87. {
  88. if (basename($val) == 'getid3.php')
  89. {
  90. define('GETID3_INCLUDEPATH', dirname($val) . DIRECTORY_SEPARATOR);
  91. break;
  92. }
  93. }
  94. }
  95. // Load support library
  96. if (! include_once (GETID3_INCLUDEPATH . 'getid3.lib.php'))
  97. {
  98. $this->startup_error .= 'getid3.lib.php is missing or corrupt';
  99. }
  100. }
  101. // public: setOption
  102. function setOption($optArray)
  103. {
  104. if (! is_array($optArray) || empty($optArray))
  105. {
  106. return false;
  107. }
  108. foreach ($optArray as $opt => $val)
  109. {
  110. if (isset($this, $opt) === false)
  111. {
  112. continue;
  113. }
  114. $this->$opt = $val;
  115. }
  116. return true;
  117. }
  118. // public: analyze file - replaces GetAllFileInfo() and GetTagOnly()
  119. function analyze($filename)
  120. {
  121. if (! empty($this->startup_error))
  122. {
  123. return $this->error($this->startup_error);
  124. }
  125. if (! empty($this->startup_warning))
  126. {
  127. $this->warning($this->startup_warning);
  128. }
  129. // init result array and set parameters
  130. $this->info = array();
  131. $this->info['GETID3_VERSION'] = GETID3_VERSION;
  132. // Check encoding/iconv support
  133. if (! function_exists('iconv') && ! in_array($this->encoding, array('ISO-8859-1', 'UTF-8', 'UTF-16LE',
  134. 'UTF-16BE', 'UTF-16')))
  135. {
  136. $errormessage = 'iconv() support is needed for encodings other than ISO-8859-1, UTF-8, UTF-16LE, UTF16-BE, UTF-16. ';
  137. if (GETID3_OS_ISWINDOWS)
  138. {
  139. $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';
  140. }
  141. else
  142. {
  143. $errormessage .= 'PHP is not compiled with iconv() support. Please recompile with the --with-iconv switch';
  144. }
  145. return $this->error($errormessage);
  146. }
  147. // Disable magic_quotes_runtime, if neccesary
  148. $old_magic_quotes_runtime = get_magic_quotes_runtime(); // store current setting of magic_quotes_runtime
  149. if ($old_magic_quotes_runtime)
  150. {
  151. set_magic_quotes_runtime(0); // turn off magic_quotes_runtime
  152. if (get_magic_quotes_runtime())
  153. {
  154. return $this->error('Could not disable magic_quotes_runtime - getID3() cannot work properly with this setting enabled');
  155. }
  156. }
  157. // remote files not supported
  158. if (preg_match('/^(ht|f)tp:\/\//', $filename))
  159. {
  160. return $this->error('Remote files are not supported in this version of getID3() - please copy the file locally first');
  161. }
  162. // open local file
  163. if (! $fp = @fopen($filename, 'rb'))
  164. {
  165. return $this->error('Could not open file "' . $filename . '"');
  166. }
  167. // set parameters
  168. $this->info['filesize'] = filesize($filename);
  169. // option_max_2gb_check
  170. if ($this->option_max_2gb_check)
  171. {
  172. // PHP doesn't support integers larger than 31-bit (~2GB)
  173. // filesize() simply returns (filesize % (pow(2, 32)), no matter the actual filesize
  174. // ftell() returns 0 if seeking to the end is beyond the range of unsigned integer
  175. fseek($fp, 0, SEEK_END);
  176. if ((($this->info['filesize'] != 0) && (ftell($fp) == 0)) || ($this->info['filesize'] < 0) || (ftell($fp) < 0))
  177. {
  178. unset($this->info['filesize']);
  179. fclose($fp);
  180. return $this->error('File is most likely larger than 2GB and is not supported by PHP');
  181. }
  182. }
  183. // set more parameters
  184. $this->info['avdataoffset'] = 0;
  185. $this->info['avdataend'] = $this->info['filesize'];
  186. $this->info['fileformat'] = ''; // filled in later
  187. $this->info['audio']['dataformat'] = ''; // filled in later, unset if not used
  188. $this->info['video']['dataformat'] = ''; // filled in later, unset if not used
  189. $this->info['tags'] = array(); // filled in later, unset if not used
  190. $this->info['error'] = array(); // filled in later, unset if not used
  191. $this->info['warning'] = array(); // filled in later, unset if not used
  192. $this->info['comments'] = array(); // filled in later, unset if not used
  193. $this->info['encoding'] = $this->encoding; // required by id3v2 and iso modules - can be unset at the end if desired
  194. // set redundant parameters - might be needed in some include file
  195. $this->info['filename'] = basename($filename);
  196. $this->info['filepath'] = str_replace('\\', '/', realpath(dirname($filename)));
  197. $this->info['filenamepath'] = $this->info['filepath'] . '/' . $this->info['filename'];
  198. // handle ID3v2 tag - done first - already at beginning of file
  199. // ID3v2 detection (even if not parsing) is always done otherwise fileformat is much harder to detect
  200. if ($this->option_tag_id3v2)
  201. {
  202. $GETID3_ERRORARRAY = &$this->info['warning'];
  203. if (getid3_lib :: IncludeDependency(GETID3_INCLUDEPATH . 'module.tag.id3v2.php', __FILE__, false))
  204. {
  205. $tag = new getid3_id3v2($fp, $this->info);
  206. }
  207. }
  208. else
  209. {
  210. fseek($fp, 0, SEEK_SET);
  211. $header = fread($fp, 10);
  212. if (substr($header, 0, 3) == 'ID3')
  213. {
  214. $this->info['id3v2']['header'] = true;
  215. $this->info['id3v2']['majorversion'] = ord($header{3});
  216. $this->info['id3v2']['minorversion'] = ord($header{4});
  217. $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
  218. $this->info['id3v2']['tag_offset_start'] = 0;
  219. $this->info['id3v2']['tag_offset_end'] = $this->info['id3v2']['tag_offset_start'] + $this->info['id3v2']['headerlength'];
  220. $this->info['avdataoffset'] = $this->info['id3v2']['tag_offset_end'];
  221. }
  222. }
  223. // handle ID3v1 tag
  224. if ($this->option_tag_id3v1)
  225. {
  226. if (! @include_once (GETID3_INCLUDEPATH . 'module.tag.id3v1.php'))
  227. {
  228. return $this->error('module.tag.id3v1.php is missing - you may disable option_tag_id3v1.');
  229. }
  230. $tag = new getid3_id3v1($fp, $this->info);
  231. }
  232. // handle APE tag
  233. if ($this->option_tag_apetag)
  234. {
  235. if (! @include_once (GETID3_INCLUDEPATH . 'module.tag.apetag.php'))
  236. {
  237. return $this->error('module.tag.apetag.php is missing - you may disable option_tag_apetag.');
  238. }
  239. $tag = new getid3_apetag($fp, $this->info);
  240. }
  241. // handle lyrics3 tag
  242. if ($this->option_tag_lyrics3)
  243. {
  244. if (! @include_once (GETID3_INCLUDEPATH . 'module.tag.lyrics3.php'))
  245. {
  246. return $this->error('module.tag.lyrics3.php is missing - you may disable option_tag_lyrics3.');
  247. }
  248. $tag = new getid3_lyrics3($fp, $this->info);
  249. }
  250. // read 32 kb file data
  251. fseek($fp, $this->info['avdataoffset'], SEEK_SET);
  252. $formattest = fread($fp, 32774);
  253. // determine format
  254. $determined_format = $this->GetFileFormat($formattest, $filename);
  255. // unable to determine file format
  256. if (! $determined_format)
  257. {
  258. fclose($fp);
  259. return $this->error('unable to determine file format');
  260. }
  261. // check for illegal ID3 tags
  262. if (isset($determined_format['fail_id3']) && (in_array('id3v1', $this->info['tags']) || in_array('id3v2', $this->info['tags'])))
  263. {
  264. if ($determined_format['fail_id3'] === 'ERROR')
  265. {
  266. fclose($fp);
  267. return $this->error('ID3 tags not allowed on this file type.');
  268. }
  269. elseif ($determined_format['fail_id3'] === 'WARNING')
  270. {
  271. $this->info['warning'][] = 'ID3 tags not allowed on this file type.';
  272. }
  273. }
  274. // check for illegal APE tags
  275. if (isset($determined_format['fail_ape']) && in_array('ape', $this->info['tags']))
  276. {
  277. if ($determined_format['fail_ape'] === 'ERROR')
  278. {
  279. fclose($fp);
  280. return $this->error('APE tags not allowed on this file type.');
  281. }
  282. elseif ($determined_format['fail_ape'] === 'WARNING')
  283. {
  284. $this->info['warning'][] = 'APE tags not allowed on this file type.';
  285. }
  286. }
  287. // set mime type
  288. $this->info['mime_type'] = $determined_format['mime_type'];
  289. // supported format signature pattern detected, but module deleted
  290. if (! file_exists(GETID3_INCLUDEPATH . $determined_format['include']))
  291. {
  292. fclose($fp);
  293. return $this->error('Format not supported, module, ' . $determined_format['include'] . ', was removed.');
  294. }
  295. // module requires iconv support
  296. if (! function_exists('iconv') && @$determined_format['iconv_req'])
  297. {
  298. return $this->error('iconv support is required for this module (' . $determined_format['include'] . ').');
  299. }
  300. // include module
  301. include_once (GETID3_INCLUDEPATH . $determined_format['include']);
  302. // instantiate module class
  303. $class_name = 'getid3_' . $determined_format['module'];
  304. if (! class_exists($class_name))
  305. {
  306. return $this->error('Format not supported, module, ' . $determined_format['include'] . ', is corrupt.');
  307. }
  308. if (isset($determined_format['option']))
  309. {
  310. $class = new $class_name($fp, $this->info, $determined_format['option']);
  311. }
  312. else
  313. {
  314. $class = new $class_name($fp, $this->info);
  315. }
  316. // close file
  317. fclose($fp);
  318. // process all tags - copy to 'tags' and convert charsets
  319. if ($this->option_tags_process)
  320. {
  321. $this->HandleAllTags();
  322. }
  323. // perform more calculations
  324. if ($this->option_extra_info)
  325. {
  326. $this->ChannelsBitratePlaytimeCalculations();
  327. $this->CalculateCompressionRatioVideo();
  328. $this->CalculateCompressionRatioAudio();
  329. $this->CalculateReplayGain();
  330. $this->ProcessAudioStreams();
  331. }
  332. // get the MD5 sum of the audio/video portion of the file - without ID3/APE/Lyrics3/etc header/footer tags
  333. if ($this->option_md5_data)
  334. {
  335. // do not cald md5_data if md5_data_source is present - set by flac only - future MPC/SV8 too
  336. if (! $this->option_md5_data_source || empty($this->info['md5_data_source']))
  337. {
  338. $this->getHashdata('md5');
  339. }
  340. }
  341. // get the SHA1 sum of the audio/video portion of the file - without ID3/APE/Lyrics3/etc header/footer tags
  342. if ($this->option_sha1_data)
  343. {
  344. $this->getHashdata('sha1');
  345. }
  346. // remove undesired keys
  347. $this->CleanUp();
  348. // restore magic_quotes_runtime setting
  349. set_magic_quotes_runtime($old_magic_quotes_runtime);
  350. // return info array
  351. return $this->info;
  352. }
  353. // private: error handling
  354. function error($message)
  355. {
  356. $this->CleanUp();
  357. $this->info['error'][] = $message;
  358. return $this->info;
  359. }
  360. // private: warning handling
  361. function warning($message)
  362. {
  363. $this->info['warning'][] = $message;
  364. return true;
  365. }
  366. // private: CleanUp
  367. function CleanUp()
  368. {
  369. // remove possible empty keys
  370. $AVpossibleEmptyKeys = array('dataformat', 'bits_per_sample', 'encoder_options', 'streams');
  371. foreach ($AVpossibleEmptyKeys as $dummy => $key)
  372. {
  373. if (empty($this->info['audio'][$key]) && isset($this->info['audio'][$key]))
  374. {
  375. unset($this->info['audio'][$key]);
  376. }
  377. if (empty($this->info['video'][$key]) && isset($this->info['video'][$key]))
  378. {
  379. unset($this->info['video'][$key]);
  380. }
  381. }
  382. // remove empty root keys
  383. if (! empty($this->info))
  384. {
  385. foreach ($this->info as $key => $value)
  386. {
  387. if (empty($this->info[$key]) && ($this->info[$key] !== 0) && ($this->info[$key] !== '0'))
  388. {
  389. unset($this->info[$key]);
  390. }
  391. }
  392. }
  393. // remove meaningless entries from unknown-format files
  394. if (empty($this->info['fileformat']))
  395. {
  396. if (isset($this->info['avdataoffset']))
  397. {
  398. unset($this->info['avdataoffset']);
  399. }
  400. if (isset($this->info['avdataend']))
  401. {
  402. unset($this->info['avdataend']);
  403. }
  404. }
  405. }
  406. // return array containing information about all supported formats
  407. function GetFileFormatArray()
  408. {
  409. static $format_info = array();
  410. if (empty($format_info))
  411. {
  412. $format_info = array(
  413. // Audio formats
  414. // AC-3 - audio - Dolby AC-3 / Dolby Digital
  415. 'ac3' => array('pattern' => '^\x0B\x77', 'group' => 'audio',
  416. 'module' => 'ac3', 'mime_type' => 'audio/ac3'),
  417. // AAC - audio - Advanced Audio Coding (AAC) - ADIF format
  418. 'adif' => array('pattern' => '^ADIF', 'group' => 'audio', 'module' => 'aac',
  419. 'option' => 'adif', 'mime_type' => 'application/octet-stream', 'fail_ape' => 'WARNING'),
  420. // AAC - audio - Advanced Audio Coding (AAC) - ADTS format (very similar to MP3)
  421. 'adts' => array('pattern' => '^\xFF[\xF0-\xF1\xF8-\xF9]',
  422. 'group' => 'audio', 'module' => 'aac', 'option' => 'adts',
  423. 'mime_type' => 'application/octet-stream', 'fail_ape' => 'WARNING'),
  424. // AU - audio - NeXT/Sun AUdio (AU)
  425. 'au' => array('pattern' => '^\.snd', 'group' => 'audio', 'module' => 'au',
  426. 'mime_type' => 'audio/basic'),
  427. // AVR - audio - Audio Visual Research
  428. 'avr' => array('pattern' => '^2BIT', 'group' => 'audio', 'module' => 'avr',
  429. 'mime_type' => 'application/octet-stream'),
  430. // BONK - audio - Bonk v0.9+
  431. 'bonk' => array('pattern' => '^\x00(BONK|INFO|META| ID3)',
  432. 'group' => 'audio', 'module' => 'bonk', 'mime_type' => 'audio/xmms-bonk'),
  433. // FLAC - audio - Free Lossless Audio Codec
  434. 'flac' => array('pattern' => '^fLaC', 'group' => 'audio', 'module' => 'flac',
  435. 'mime_type' => 'audio/x-flac'),
  436. // LA - audio - Lossless Audio (LA)
  437. 'la' => array('pattern' => '^LA0[2-4]', 'group' => 'audio', 'module' => 'la',
  438. 'mime_type' => 'application/octet-stream'),
  439. // LPAC - audio - Lossless Predictive Audio Compression (LPAC)
  440. 'lpac' => array('pattern' => '^LPAC', 'group' => 'audio', 'module' => 'lpac',
  441. 'mime_type' => 'application/octet-stream'),
  442. // MIDI - audio - MIDI (Musical Instrument Digital Interface)
  443. 'midi' => array('pattern' => '^MThd', 'group' => 'audio', 'module' => 'midi',
  444. 'mime_type' => 'audio/midi'),
  445. // MAC - audio - Monkey's Audio Compressor
  446. 'mac' => array('pattern' => '^MAC ', 'group' => 'audio',
  447. 'module' => 'monkey', 'mime_type' => 'application/octet-stream'),
  448. // MOD - audio - MODule (assorted sub-formats)
  449. 'mod' => array('pattern' => '^.{1080}(M.K.|[5-9]CHN|[1-3][0-9]CH)',
  450. 'group' => 'audio', 'module' => 'mod', 'option' => 'mod', 'mime_type' => 'audio/mod'),
  451. // MOD - audio - MODule (Impulse Tracker)
  452. 'it' => array('pattern' => '^IMPM', 'group' => 'audio', 'module' => 'mod',
  453. 'option' => 'it', 'mime_type' => 'audio/it'),
  454. // MOD - audio - MODule (eXtended Module, various sub-formats)
  455. 'xm' => array('pattern' => '^Extended Module', 'group' => 'audio',
  456. 'module' => 'mod', 'option' => 'xm', 'mime_type' => 'audio/xm'),
  457. // MOD - audio - MODule (ScreamTracker)
  458. 's3m' => array('pattern' => '^.{44}SCRM', 'group' => 'audio',
  459. 'module' => 'mod', 'option' => 's3m', 'mime_type' => 'audio/s3m'),
  460. // MPC - audio - Musepack / MPEGplus
  461. 'mpc' => array(
  462. '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])',
  463. 'group' => 'audio', 'module' => 'mpc', 'mime_type' => 'application/octet-stream'),
  464. // MP3 - audio - MPEG-audio Layer 3 (very similar to AAC-ADTS)
  465. 'mp3' => array('pattern' => '^\xFF[\xE2-\xE7\xF2-\xF7\xFA-\xFF][\x00-\xEB]',
  466. 'group' => 'audio', 'module' => 'mp3', 'mime_type' => 'audio/mpeg'),
  467. // OFR - audio - OptimFROG
  468. 'ofr' => array('pattern' => '^(\*RIFF|OFR)', 'group' => 'audio',
  469. 'module' => 'optimfrog', 'mime_type' => 'application/octet-stream'),
  470. // RKAU - audio - RKive AUdio compressor
  471. 'rkau' => array('pattern' => '^RKA', 'group' => 'audio', 'module' => 'rkau',
  472. 'mime_type' => 'application/octet-stream'),
  473. // SHN - audio - Shorten
  474. 'shn' => array('pattern' => '^ajkg', 'group' => 'audio',
  475. 'module' => 'shorten', 'mime_type' => 'audio/xmms-shn', 'fail_id3' => 'ERROR',
  476. 'fail_ape' => 'ERROR'),
  477. // TTA - audio - TTA Lossless Audio Compressor (http://tta.corecodec.org)
  478. 'tta' => array('pattern' => '^TTA', // could also be '^TTA(\x01|\x02|\x03|2|1)'
  479. 'group' => 'audio', 'module' => 'tta',
  480. 'mime_type' => 'application/octet-stream'),
  481. // VOC - audio - Creative Voice (VOC)
  482. 'voc' => array('pattern' => '^Creative Voice File', 'group' => 'audio',
  483. 'module' => 'voc', 'mime_type' => 'audio/voc'),
  484. // VQF - audio - transform-domain weighted interleave Vector Quantization Format (VQF)
  485. 'vqf' => array('pattern' => '^TWIN', 'group' => 'audio', 'module' => 'vqf',
  486. 'mime_type' => 'application/octet-stream'),
  487. // WV - audio - WavPack (v4.0+)
  488. 'wv' => array('pattern' => '^wvpk', 'group' => 'audio',
  489. 'module' => 'wavpack', 'mime_type' => 'application/octet-stream'),
  490. // Audio-Video formats
  491. // ASF - audio/video - Advanced Streaming Format, Windows Media Video, Windows Media Audio
  492. 'asf' => array(
  493. 'pattern' => '^\x30\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C',
  494. 'group' => 'audio-video', 'module' => 'asf', 'mime_type' => 'video/x-ms-asf',
  495. 'iconv_req' => false),
  496. // BINK - audio/video - Bink / Smacker
  497. 'bink' => array('pattern' => '^(BIK|SMK)', 'group' => 'audio-video',
  498. 'module' => 'bink', 'mime_type' => 'application/octet-stream'),
  499. // FLV - audio/video - FLash Video
  500. 'flv' => array('pattern' => '^FLV\x01', 'group' => 'audio-video',
  501. 'module' => 'flv', 'mime_type' => 'video/x-flv'),
  502. // MKAV - audio/video - Mastroka
  503. 'matroska' => array('pattern' => '^\x1A\x45\xDF\xA3',
  504. 'group' => 'audio-video', 'module' => 'matroska', 'mime_type' => 'application/octet-stream'),
  505. // MPEG - audio/video - MPEG (Moving Pictures Experts Group)
  506. 'mpeg' => array('pattern' => '^\x00\x00\x01(\xBA|\xB3)',
  507. 'group' => 'audio-video', 'module' => 'mpeg', 'mime_type' => 'video/mpeg'),
  508. // NSV - audio/video - Nullsoft Streaming Video (NSV)
  509. 'nsv' => array('pattern' => '^NSV[sf]', 'group' => 'audio-video',
  510. 'module' => 'nsv', 'mime_type' => 'application/octet-stream'),
  511. // Ogg - audio/video - Ogg (Ogg-Vorbis, Ogg-FLAC, Speex, Ogg-Theora(*), Ogg-Tarkin(*))
  512. 'ogg' => array('pattern' => '^OggS', 'group' => 'audio', 'module' => 'ogg',
  513. 'mime_type' => 'application/ogg', 'fail_id3' => 'WARNING', 'fail_ape' => 'WARNING'),
  514. // QT - audio/video - Quicktime
  515. 'quicktime' => array(
  516. 'pattern' => '^.{4}(cmov|free|ftyp|mdat|moov|pnot|skip|wide)', 'group' => 'audio-video',
  517. 'module' => 'quicktime', 'mime_type' => 'video/quicktime'),
  518. // 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)
  519. 'riff' => array('pattern' => '^(RIFF|SDSS|FORM)', 'group' => 'audio-video',
  520. 'module' => 'riff', 'mime_type' => 'audio/x-wave', 'fail_ape' => 'WARNING'),
  521. // Real - audio/video - RealAudio, RealVideo
  522. 'real' => array('pattern' => '^(\.RMF|.ra)', 'group' => 'audio-video',
  523. 'module' => 'real', 'mime_type' => 'audio/x-realaudio'),
  524. // SWF - audio/video - ShockWave Flash
  525. 'swf' => array('pattern' => '^(F|C)WS', 'group' => 'audio-video',
  526. 'module' => 'swf', 'mime_type' => 'application/x-shockwave-flash'),
  527. // Still-Image formats
  528. // BMP - still image - Bitmap (Windows, OS/2; uncompressed, RLE8, RLE4)
  529. 'bmp' => array('pattern' => '^BM', 'group' => 'graphic', 'module' => 'bmp',
  530. 'mime_type' => 'image/bmp', 'fail_id3' => 'ERROR', 'fail_ape' => 'ERROR'),
  531. // GIF - still image - Graphics Interchange Format
  532. 'gif' => array('pattern' => '^GIF', 'group' => 'graphic', 'module' => 'gif',
  533. 'mime_type' => 'image/gif', 'fail_id3' => 'ERROR', 'fail_ape' => 'ERROR'),
  534. // JPEG - still image - Joint Photographic Experts Group (JPEG)
  535. 'jpg' => array('pattern' => '^\xFF\xD8\xFF', 'group' => 'graphic',
  536. 'module' => 'jpg', 'mime_type' => 'image/jpeg', 'fail_id3' => 'ERROR',
  537. 'fail_ape' => 'ERROR'),
  538. // PCD - still image - Kodak Photo CD
  539. 'pcd' => array('pattern' => '^.{2048}PCD_IPI\x00', 'group' => 'graphic',
  540. 'module' => 'pcd', 'mime_type' => 'image/x-photo-cd', 'fail_id3' => 'ERROR',
  541. 'fail_ape' => 'ERROR'),
  542. // PNG - still image - Portable Network Graphics (PNG)
  543. 'png' => array('pattern' => '^\x89\x50\x4E\x47\x0D\x0A\x1A\x0A',
  544. 'group' => 'graphic', 'module' => 'png', 'mime_type' => 'image/png', 'fail_id3' => 'ERROR',
  545. 'fail_ape' => 'ERROR'),
  546. // TIFF - still image - Tagged Information File Format (TIFF)
  547. 'tiff' => array('pattern' => '^(II\x2A\x00|MM\x00\x2A)',
  548. 'group' => 'graphic', 'module' => 'tiff', 'mime_type' => 'image/tiff',
  549. 'fail_id3' => 'ERROR', 'fail_ape' => 'ERROR'),
  550. // Data formats
  551. // ISO - data - International Standards Organization (ISO) CD-ROM Image
  552. 'iso' => array('pattern' => '^.{32769}CD001', 'group' => 'misc',
  553. 'module' => 'iso', 'mime_type' => 'application/octet-stream', 'fail_id3' => 'ERROR',
  554. 'fail_ape' => 'ERROR', 'iconv_req' => false),
  555. // RAR - data - RAR compressed data
  556. 'rar' => array('pattern' => '^Rar\!', 'group' => 'archive',
  557. 'module' => 'rar', 'mime_type' => 'application/octet-stream', 'fail_id3' => 'ERROR',
  558. 'fail_ape' => 'ERROR'),
  559. // SZIP - audio/data - SZIP compressed data
  560. 'szip' => array('pattern' => '^SZ\x0A\x04', 'group' => 'archive',
  561. 'module' => 'szip', 'mime_type' => 'application/octet-stream', 'fail_id3' => 'ERROR',
  562. 'fail_ape' => 'ERROR'),
  563. // TAR - data - TAR compressed data
  564. 'tar' => array(
  565. '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}',
  566. 'group' => 'archive', 'module' => 'tar', 'mime_type' => 'application/x-tar',
  567. 'fail_id3' => 'ERROR', 'fail_ape' => 'ERROR'),
  568. // GZIP - data - GZIP compressed data
  569. 'gz' => array('pattern' => '^\x1F\x8B\x08', 'group' => 'archive',
  570. 'module' => 'gzip', 'mime_type' => 'application/x-gzip', 'fail_id3' => 'ERROR',
  571. 'fail_ape' => 'ERROR'),
  572. // ZIP - data - ZIP compressed data
  573. 'zip' => array('pattern' => '^PK\x03\x04', 'group' => 'archive',
  574. 'module' => 'zip', 'mime_type' => 'application/zip', 'fail_id3' => 'ERROR',
  575. 'fail_ape' => 'ERROR'),
  576. // Misc other formats
  577. // PDF - data - ZIP compressed data
  578. 'pdf' => array('pattern' => '^\x25PDF', 'group' => 'misc', 'module' => 'pdf',
  579. 'mime_type' => 'application/pdf', 'fail_id3' => 'ERROR', 'fail_ape' => 'ERROR'),
  580. // MSOFFICE - data - ZIP compressed data
  581. 'msoffice' => array('pattern' => '^\xD0\xCF\x11\xE0', // D0CF11E == DOCFILE == Microsoft Office Document
  582. 'group' => 'misc',
  583. 'module' => 'msoffice', 'mime_type' => 'application/octet-stream', 'fail_id3' => 'ERROR',
  584. 'fail_ape' => 'ERROR'));
  585. }
  586. return $format_info;
  587. }
  588. function GetFileFormat(&$filedata, $filename = '')
  589. {
  590. // this function will determine the format of a file based on usually
  591. // the first 2-4 bytes of the file (8 bytes for PNG, 16 bytes for JPG,
  592. // and in the case of ISO CD image, 6 bytes offset 32kb from the start
  593. // of the file).
  594. // Identify file format - loop through $format_info and detect with reg expr
  595. foreach ($this->GetFileFormatArray() as $format_name => $info)
  596. {
  597. // Using preg_match() instead of ereg() - much faster
  598. // The /s switch on preg_match() forces preg_match() NOT to treat
  599. // newline (0x0A) characters as special chars but do a binary match
  600. if (preg_match('/' . $info['pattern'] . '/s', $filedata))
  601. {
  602. $info['include'] = 'module.' . $info['group'] . '.' . $info['module'] . '.php';
  603. return $info;
  604. }
  605. }
  606. if (preg_match('/\.mp[123a]$/i', $filename))
  607. {
  608. // Too many mp3 encoders on the market put gabage in front of mpeg files
  609. // use assume format on these if format detection failed
  610. $GetFileFormatArray = $this->GetFileFormatArray();
  611. $info = $GetFileFormatArray['mp3'];
  612. $info['include'] = 'module.' . $info['group'] . '.' . $info['module'] . '.php';
  613. return $info;
  614. }
  615. return false;
  616. }
  617. // converts array to $encoding charset from $this->encoding
  618. function CharConvert(&$array, $encoding)
  619. {
  620. // identical encoding - end here
  621. if ($encoding == $this->encoding)
  622. {
  623. return;
  624. }
  625. // loop thru array
  626. foreach ($array as $key => $value)
  627. {
  628. // go recursive
  629. if (is_array($value))
  630. {
  631. $this->CharConvert($array[$key], $encoding);
  632. }
  633. // convert string
  634. elseif (is_string($value))
  635. {
  636. $array[$key] = trim(getid3_lib :: iconv_fallback($encoding, $this->encoding, $value));
  637. }
  638. }
  639. }
  640. function HandleAllTags()
  641. {
  642. // key name => array (tag name, character encoding)
  643. static $tags;
  644. if (empty($tags))
  645. {
  646. $tags = array('asf' => array('asf', 'UTF-16LE'), 'midi' => array('midi', 'ISO-8859-1'),
  647. 'nsv' => array('nsv', 'ISO-8859-1'), 'ogg' => array('vorbiscomment', 'UTF-8'),
  648. 'png' => array('png', 'UTF-8'), 'tiff' => array('tiff', 'ISO-8859-1'),
  649. 'quicktime' => array('quicktime', 'ISO-8859-1'),
  650. 'real' => array('real', 'ISO-8859-1'), 'vqf' => array('vqf', 'ISO-8859-1'),
  651. 'zip' => array('zip', 'ISO-8859-1'), 'riff' => array('riff', 'ISO-8859-1'),
  652. 'lyrics3' => array('lyrics3', 'ISO-8859-1'),
  653. 'id3v1' => array('id3v1', $this->encoding_id3v1), '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
  654. 'ape' => array('ape', 'UTF-8'));
  655. }
  656. // loop thru comments array
  657. foreach ($tags as $comment_name => $tagname_encoding_array)
  658. {
  659. list($tag_name, $encoding) = $tagname_encoding_array;
  660. // fill in default encoding type if not already present
  661. if (isset($this->info[$comment_name]) && ! isset($this->info[$comment_name]['encoding']))
  662. {
  663. $this->info[$comment_name]['encoding'] = $encoding;
  664. }
  665. // copy comments if key name set
  666. if (! empty($this->info[$comment_name]['comments']))
  667. {
  668. foreach ($this->info[$comment_name]['comments'] as $tag_key => $valuearray)
  669. {
  670. foreach ($valuearray as $key => $value)
  671. {
  672. if (strlen(trim($value)) > 0)
  673. {
  674. $this->info['tags'][trim($tag_name)][trim($tag_key)][] = $value; // do not trim!! Unicode characters will get mangled if trailing nulls are removed!
  675. }
  676. }
  677. }
  678. if (! isset($this->info['tags'][$tag_name]))
  679. {
  680. // comments are set but contain nothing but empty strings, so skip
  681. continue;
  682. }
  683. if ($this->option_tags_html)
  684. {
  685. foreach ($this->info['tags'][$tag_name] as $tag_key => $valuearray)
  686. {
  687. foreach ($valuearray as $key => $value)
  688. {
  689. if (is_string($value))
  690. {
  691. //$this->info['tags_html'][$tag_name][$tag_key][$key] = getid3_lib::MultiByteCharString2HTML($value, $encoding);
  692. $this->info['tags_html'][$tag_name][$tag_key][$key] = str_replace('&#0;', '', getid3_lib :: MultiByteCharString2HTML($value, $encoding));
  693. }
  694. else
  695. {
  696. $this->info['tags_html'][$tag_name][$tag_key][$key] = $value;
  697. }
  698. }
  699. }
  700. }
  701. $this->CharConvert($this->info['tags'][$tag_name], $encoding); // only copy gets converted!
  702. }
  703. }
  704. return true;
  705. }
  706. function getHashdata($algorithm)
  707. {
  708. switch ($algorithm)
  709. {
  710. case 'md5' :
  711. case 'sha1' :
  712. break;
  713. default :
  714. return $this->error('bad algorithm "' . $algorithm . '" in getHashdata()');
  715. break;
  716. }
  717. if ((@$this->info['fileformat'] == 'ogg') && (@$this->info['audio']['dataformat'] == 'vorbis'))
  718. {
  719. // We cannot get an identical md5_data value for Ogg files where the comments
  720. // span more than 1 Ogg page (compared to the same audio data with smaller
  721. // comments) using the normal getID3() method of MD5'ing the data between the
  722. // end of the comments and the end of the file (minus any trailing tags),
  723. // because the page sequence numbers of the pages that the audio data is on
  724. // do not match. Under normal circumstances, where comments are smaller than
  725. // the nominal 4-8kB page size, then this is not a problem, but if there are
  726. // very large comments, the only way around it is to strip off the comment
  727. // tags with vorbiscomment and MD5 that file.
  728. // This procedure must be applied to ALL Ogg files, not just the ones with
  729. // comments larger than 1 page, because the below method simply MD5's the
  730. // whole file with the comments stripped, not just the portion after the
  731. // comments block (which is the standard getID3() method.
  732. // The above-mentioned problem of comments spanning multiple pages and changing
  733. // page sequence numbers likely happens for OggSpeex and OggFLAC as well, but
  734. // currently vorbiscomment only works on OggVorbis files.
  735. if ((bool) ini_get('safe_mode'))
  736. {
  737. $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)';
  738. $this->info[$algorithm . '_data'] = false;
  739. }
  740. else
  741. {
  742. // Prevent user from aborting script
  743. $old_abort = ignore_user_abort(true);
  744. // Create empty file
  745. $empty = tempnam('*', 'getID3');
  746. touch($empty);
  747. // Use vorbiscomment to make temp file without comments
  748. $temp = tempnam('*', 'getID3');
  749. $file = $this->info['filenamepath'];
  750. if (GETID3_OS_ISWINDOWS)
  751. {
  752. if (file_exists(GETID3_HELPERAPPSDIR . 'vorbiscomment.exe'))
  753. {
  754. $commandline = '"' . GETID3_HELPERAPPSDIR . 'vorbiscomment.exe" -w -c "' . $empty . '" "' . $file . '" "' . $temp . '"';
  755. $VorbisCommentError = `$commandline`;
  756. }
  757. else
  758. {
  759. $VorbisCommentError = 'vorbiscomment.exe not found in ' . GETID3_HELPERAPPSDIR;
  760. }
  761. }
  762. else
  763. {
  764. $commandline = 'vorbiscomment -w -c "' . $empty . '" "' . $file . '" "' . $temp . '" 2>&1';
  765. $commandline = 'vorbiscomment -w -c ' . escapeshellarg($empty) . ' ' . escapeshellarg($file) . ' ' . escapeshellarg($temp) . ' 2>&1';
  766. $VorbisCommentError = `$commandline`;
  767. }
  768. if (! empty($VorbisCommentError))
  769. {
  770. $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;
  771. $this->info[$algorithm . '_data'] = false;
  772. }
  773. else
  774. {
  775. // Get hash of newly created file
  776. switch ($algorithm)
  777. {
  778. case 'md5' :
  779. $this->info[$algorithm . '_data'] = getid3_lib :: md5_file($temp);
  780. break;
  781. case 'sha1' :
  782. $this->info[$algorithm . '_data'] = getid3_lib :: sha1_file($temp);
  783. break;
  784. }
  785. }
  786. // Clean up
  787. unlink($empty);
  788. unlink($temp);
  789. // Reset abort setting
  790. ignore_user_abort($old_abort);
  791. }
  792. }
  793. else
  794. {
  795. if (! empty($this->info['avdataoffset']) || (isset($this->info['avdataend']) && ($this->info['avdataend'] < $this->info['filesize'])))
  796. {
  797. // get hash from part of file
  798. $this->info[$algorithm . '_data'] = getid3_lib :: hash_data($this->info['filenamepath'], $this->info['avdataoffset'], $this->info['avdataend'], $algorithm);
  799. }
  800. else
  801. {
  802. // get hash from whole file
  803. switch ($algorithm)
  804. {
  805. case 'md5' :
  806. $this->info[$algorithm . '_data'] = getid3_lib :: md5_file($this->info['filenamepath']);
  807. break;
  808. case 'sha1' :
  809. $this->info[$algorithm . '_data'] = getid3_lib :: sha1_file($this->info['filenamepath']);
  810. break;
  811. }
  812. }
  813. }
  814. return true;
  815. }
  816. function ChannelsBitratePlaytimeCalculations()
  817. {
  818. // set channelmode on audio
  819. if (@$this->info['audio']['channels'] == '1')
  820. {
  821. $this->info['audio']['channelmode'] = 'mono';
  822. }
  823. elseif (@$this->info['audio']['channels'] == '2')
  824. {
  825. $this->info['audio']['channelmode'] = 'stereo';
  826. }
  827. // Calculate combined bitrate - audio + video
  828. $CombinedBitrate = 0;
  829. $CombinedBitrate += (isset($this->info['audio']['bitrate']) ? $this->info['audio']['bitrate'] : 0);
  830. $CombinedBitrate += (isset($this->info['video']['bitrate']) ? $this->info['video']['bitrate'] : 0);
  831. if (($CombinedBitrate > 0) && empty($this->info['bitrate']))
  832. {
  833. $this->info['bitrate'] = $CombinedBitrate;
  834. }
  835. //if ((isset($this->info['video']) && !isset($this->info['video']['bitrate'])) || (isset($this->info['audio']) && !isset($this->info['audio']['bitrate']))) {
  836. // // for example, VBR MPEG video files cannot determine video bitrate:
  837. // // should not set overall bitrate and playtime from audio bitrate only
  838. // unset($this->info['bitrate']);
  839. //}
  840. if (! isset($this->info['playtime_seconds']) && ! empty($this->info['bitrate']))
  841. {
  842. $this->info['playtime_seconds'] = (($this->info['avdataend'] - $this->info['avdataoffset']) * 8) / $this->info['bitrate'];
  843. }
  844. // Set playtime string
  845. if (! empty($this->info['playtime_seconds']) && empty($this->info['playtime_string']))
  846. {
  847. $this->info['playtime_string'] = getid3_lib :: PlaytimeString($this->info['playtime_seconds']);
  848. }
  849. }
  850. function CalculateCompressionRatioVideo()
  851. {
  852. if (empty($this->info['video']))
  853. {
  854. return false;
  855. }
  856. if (empty($this->info['video']['resolution_x']) || empty($this->info['video']['resolution_y']))
  857. {
  858. return false;
  859. }
  860. if (empty($this->info['video']['bits_per_sample']))
  861. {
  862. return false;
  863. }
  864. switch ($this->info['video']['dataformat'])
  865. {
  866. case 'bmp' :
  867. case 'gif' :
  868. case 'jpeg' :
  869. case 'jpg' :
  870. case 'png' :
  871. case 'tiff' :
  872. $FrameRate = 1;
  873. $PlaytimeSeconds = 1;
  874. $BitrateCompressed = $this->info['filesize'] * 8;
  875. break;
  876. default :
  877. if (! empty($this->info['video']['frame_rate']))
  878. {
  879. $FrameRate = $this->info['video']['frame_rate'];
  880. }
  881. else
  882. {
  883. return false;
  884. }
  885. if (! empty($this->info['playtime_seconds']))
  886. {
  887. $PlaytimeSeconds = $this->info['playtime_seconds'];
  888. }
  889. else
  890. {
  891. return false;
  892. }
  893. if (! empty($this->info['video']['bitrate']))
  894. {
  895. $BitrateCompressed = $this->info['video']['bitrate'];
  896. }
  897. else
  898. {
  899. return false;
  900. }
  901. break;
  902. }
  903. $BitrateUnc

Large files files are truncated, but you can click here to view the full file