14 if (!defined(
'GETID3_OS_ISWINDOWS')) {
15 define(
'GETID3_OS_ISWINDOWS', (stripos(PHP_OS,
'WIN') === 0));
18 if (!defined(
'GETID3_INCLUDEPATH')) {
19 define(
'GETID3_INCLUDEPATH', dirname(__FILE__).DIRECTORY_SEPARATOR);
22 if (!defined(
'IMG_JPG') && defined(
'IMAGETYPE_JPEG')) {
23 define(
'IMG_JPG', IMAGETYPE_JPEG);
31 if (!
$temp_dir && function_exists(
'sys_get_temp_dir')) {
41 if (substr(
$temp_dir, -1, 1) != DIRECTORY_SEPARATOR) {
44 $found_valid_tempdir =
false;
46 foreach ($open_basedirs as $basedir) {
47 if (substr($basedir, -1, 1) != DIRECTORY_SEPARATOR) {
48 $basedir .= DIRECTORY_SEPARATOR;
50 if (preg_match(
'#^'.preg_quote($basedir).
'#',
$temp_dir)) {
51 $found_valid_tempdir =
true;
55 if (!$found_valid_tempdir) {
58 unset($open_basedirs, $found_valid_tempdir, $basedir);
64 if (!defined(
'GETID3_TEMP_DIR')) {
122 $required_php_version =
'5.3.0';
123 if (version_compare(PHP_VERSION, $required_php_version,
'<')) {
124 $this->startup_error .=
'getID3() requires PHP v'.$required_php_version.
' or higher - you are running v'.PHP_VERSION;
129 $this->memory_limit = ini_get(
'memory_limit');
130 if (preg_match(
'#([0-9]+)M#i', $this->memory_limit, $matches)) {
132 $this->memory_limit = $matches[1] * 1048576;
133 } elseif (preg_match(
'#([0-9]+)G#i', $this->memory_limit, $matches)) {
135 $this->memory_limit = $matches[1] * 1073741824;
137 if ($this->memory_limit <= 0) {
139 } elseif ($this->memory_limit <= 4194304) {
140 $this->startup_error .=
'PHP has less than 4MB available memory and will very likely run out. Increase memory_limit in php.ini';
141 } elseif ($this->memory_limit <= 12582912) {
142 $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';
146 if (preg_match(
'#(1|ON)#i', ini_get(
'safe_mode'))) {
147 $this->
warning(
'WARNING: Safe mode is on, shorten support disabled, md5data/sha1data for ogg vorbis disabled, ogg vorbos/flac tag writing disabled.');
150 if (intval(ini_get(
'mbstring.func_overload')) > 0) {
151 $this->
warning(
'WARNING: php.ini contains "mbstring.func_overload = '.ini_get(
'mbstring.func_overload').
'", this may break things.');
155 if (function_exists(
'get_magic_quotes_runtime')) {
156 if (get_magic_quotes_runtime()) {
157 return $this->startup_error(
'magic_quotes_runtime must be disabled before running getID3(). Surround getid3 block by set_magic_quotes_runtime(0) and set_magic_quotes_runtime(1).');
162 if (function_exists(
'magic_quotes_gpc')) {
163 if (get_magic_quotes_gpc()) {
164 return $this->startup_error(
'magic_quotes_gpc must be disabled before running getID3(). Surround getid3 block by set_magic_quotes_gpc(0) and set_magic_quotes_gpc(1).');
169 if (!include_once(GETID3_INCLUDEPATH.
'getid3.lib.php')) {
170 $this->startup_error .=
'getid3.lib.php is missing or corrupt';
173 if ($this->option_max_2gb_check === null) {
174 $this->option_max_2gb_check = (PHP_INT_MAX <= 2147483647);
184 if (GETID3_OS_ISWINDOWS && !defined(
'GETID3_HELPERAPPSDIR')) {
186 $helperappsdir = GETID3_INCLUDEPATH.
'..'.DIRECTORY_SEPARATOR.
'helperapps';
188 if (!is_dir($helperappsdir)) {
189 $this->startup_warning .=
'"'.$helperappsdir.
'" cannot be defined as GETID3_HELPERAPPSDIR because it does not exist';
190 } elseif (strpos(realpath($helperappsdir),
' ') !==
false) {
191 $DirPieces = explode(DIRECTORY_SEPARATOR, realpath($helperappsdir));
192 $path_so_far = array();
193 foreach ($DirPieces as $key => $value) {
194 if (strpos($value,
' ') !==
false) {
195 if (!empty($path_so_far)) {
196 $commandline =
'dir /x '.escapeshellarg(implode(DIRECTORY_SEPARATOR, $path_so_far));
197 $dir_listing = `$commandline`;
198 $lines = explode(
"\n", $dir_listing);
199 foreach ($lines as $line) {
201 if (preg_match(
'#^([0-9/]{10}) +([0-9:]{4,5}( [AP]M)?) +(<DIR>|[0-9,]+) +([^ ]{0,11}) +(.+)$#', $line, $matches)) {
202 list($dummy, $date, $time, $ampm, $filesize, $shortname,
$filename) = $matches;
203 if ((strtoupper($filesize) ==
'<DIR>') && (strtolower(
$filename) == strtolower($value))) {
209 $this->startup_warning .=
'GETID3_HELPERAPPSDIR must not have any spaces in it - use 8dot3 naming convention if neccesary. You can run "dir /x" from the commandline to see the correct 8.3-style names.';
212 $path_so_far[] = $value;
214 $helperappsdir = implode(DIRECTORY_SEPARATOR, $path_so_far);
216 define(
'GETID3_HELPERAPPSDIR', $helperappsdir.DIRECTORY_SEPARATOR);
223 return self::VERSION;
233 if (!is_array($optArray) || empty($optArray)) {
236 foreach ($optArray as $opt => $val) {
237 if (isset($this->$opt) ===
false) {
248 if (!empty($this->startup_error)) {
251 if (!empty($this->startup_warning)) {
252 $this->
warning($this->startup_warning);
257 $this->info = array();
258 $this->info[
'GETID3_VERSION'] = $this->
version();
259 $this->info[
'php_memory_limit'] = (($this->memory_limit > 0) ? $this->memory_limit :
false);
262 if (preg_match(
'/^(ht|f)tp:\/\//',
$filename)) {
263 throw new getid3_exception(
'Remote files are not supported - please copy the file locally first');
267 $filename = preg_replace(
'#(.+)'.preg_quote(DIRECTORY_SEPARATOR).
'{2,}#U',
'\1'.DIRECTORY_SEPARATOR,
$filename);
274 $errormessagelist = array();
276 $errormessagelist[] =
'!is_readable';
279 $errormessagelist[] =
'!is_file';
282 $errormessagelist[] =
'!file_exists';
284 if (empty($errormessagelist)) {
285 $errormessagelist[] =
'fopen failed';
290 $this->info[
'filesize'] = (!is_null($filesize) ? $filesize : filesize(
$filename));
294 $this->info[
'filepath'] = str_replace(
'\\',
'/', realpath(dirname(
$filename)));
296 $this->info[
'filenamepath'] = $this->info[
'filepath'].
'/'.$this->info[
'filename'];
300 if ($this->option_max_2gb_check) {
304 $fseek = fseek($this->fp, 0, SEEK_END);
305 if (($fseek < 0) || (($this->info[
'filesize'] != 0) && (ftell($this->fp) == 0)) ||
306 ($this->info[
'filesize'] < 0) ||
307 (ftell($this->fp) < 0)) {
310 if ($real_filesize ===
false) {
311 unset($this->info[
'filesize']);
313 throw new getid3_exception(
'Unable to determine actual filesize. File is most likely larger than '.round(PHP_INT_MAX / 1073741824).
'GB and is not supported by PHP.');
315 unset($this->info[
'filesize']);
317 throw new getid3_exception(
'PHP seems to think the file is larger than '.round(PHP_INT_MAX / 1073741824).
'GB, but filesystem reports it as '.number_format($real_filesize, 3).
'GB, please report to info@getid3.org');
319 $this->info[
'filesize'] = $real_filesize;
320 $this->
warning(
'File is larger than '.round(PHP_INT_MAX / 1073741824).
'GB (filesystem reports it as '.number_format($real_filesize, 3).
'GB) and is not properly supported by PHP.');
325 $this->info[
'avdataoffset'] = 0;
326 $this->info[
'avdataend'] = $this->info[
'filesize'];
327 $this->info[
'fileformat'] =
'';
328 $this->info[
'audio'][
'dataformat'] =
'';
329 $this->info[
'video'][
'dataformat'] =
'';
330 $this->info[
'tags'] = array();
331 $this->info[
'error'] = array();
332 $this->info[
'warning'] = array();
333 $this->info[
'comments'] = array();
339 $this->
error($e->getMessage());
352 foreach (array(
'id3v2'=>
'id3v2',
'id3v1'=>
'id3v1',
'apetag'=>
'ape',
'lyrics3'=>
'lyrics3') as $tag_name => $tag_key) {
353 $option_tag =
'option_tag_'.$tag_name;
354 if ($this->$option_tag) {
357 $tag_class =
'getid3_'.$tag_name;
358 $tag =
new $tag_class($this);
366 if (isset($this->info[
'id3v2'][
'tag_offset_start'])) {
367 $this->info[
'avdataoffset'] = max($this->info[
'avdataoffset'], $this->info[
'id3v2'][
'tag_offset_end']);
369 foreach (array(
'id3v1'=>
'id3v1',
'apetag'=>
'ape',
'lyrics3'=>
'lyrics3') as $tag_name => $tag_key) {
370 if (isset($this->info[$tag_key][
'tag_offset_start'])) {
371 $this->info[
'avdataend'] = min($this->info[
'avdataend'], $this->info[$tag_key][
'tag_offset_start']);
376 if (!$this->option_tag_id3v2) {
378 $header = fread($this->fp, 10);
379 if ((substr(
$header, 0, 3) ==
'ID3') && (strlen(
$header) == 10)) {
380 $this->info[
'id3v2'][
'header'] =
true;
381 $this->info[
'id3v2'][
'majorversion'] = ord(
$header{3});
382 $this->info[
'id3v2'][
'minorversion'] = ord(
$header{4});
388 fseek($this->fp, $this->info[
'avdataoffset']);
389 $formattest = fread($this->fp, 32774);
392 $determined_format = $this->
GetFileFormat($formattest, ($original_filename ? $original_filename :
$filename));
395 if (!$determined_format) {
397 return $this->
error(
'unable to determine file format');
401 if (isset($determined_format[
'fail_id3']) && (in_array(
'id3v1', $this->info[
'tags']) || in_array(
'id3v2', $this->info[
'tags']))) {
402 if ($determined_format[
'fail_id3'] ===
'ERROR') {
404 return $this->
error(
'ID3 tags not allowed on this file type.');
405 } elseif ($determined_format[
'fail_id3'] ===
'WARNING') {
406 $this->
warning(
'ID3 tags not allowed on this file type.');
411 if (isset($determined_format[
'fail_ape']) && in_array(
'ape', $this->info[
'tags'])) {
412 if ($determined_format[
'fail_ape'] ===
'ERROR') {
414 return $this->
error(
'APE tags not allowed on this file type.');
415 } elseif ($determined_format[
'fail_ape'] ===
'WARNING') {
416 $this->
warning(
'APE tags not allowed on this file type.');
421 $this->info[
'mime_type'] = $determined_format[
'mime_type'];
424 if (!file_exists(GETID3_INCLUDEPATH.$determined_format[
'include'])) {
426 return $this->
error(
'Format not supported, module "'.$determined_format[
'include'].
'" was removed.');
431 if (!empty($determined_format[
'iconv_req']) && !function_exists(
'iconv') && !in_array($this->encoding, array(
'ISO-8859-1',
'UTF-8',
'UTF-16LE',
'UTF-16BE',
'UTF-16'))) {
432 $errormessage =
'iconv() support is required for this module ('.$determined_format[
'include'].
') for encodings other than ISO-8859-1, UTF-8, UTF-16LE, UTF16-BE, UTF-16. ';
433 if (GETID3_OS_ISWINDOWS) {
434 $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';
436 $errormessage .=
'PHP is not compiled with iconv() support. Please recompile with the --with-iconv switch';
438 return $this->
error($errormessage);
442 include_once(GETID3_INCLUDEPATH.$determined_format[
'include']);
445 $class_name =
'getid3_'.$determined_format[
'module'];
446 if (!class_exists($class_name)) {
447 return $this->
error(
'Format not supported, module "'.$determined_format[
'include'].
'" is corrupt.');
449 $class =
new $class_name($this);
457 if ($this->option_tags_process) {
462 if ($this->option_extra_info) {
471 if ($this->option_md5_data) {
473 if (!$this->option_md5_data_source || empty($this->info[
'md5_data_source'])) {
479 if ($this->option_sha1_data) {
487 $this->
error(
'Caught exception: '.$e->getMessage());
498 if (!isset($this->info[
'error'])) {
499 $this->info[
'error'] = array();
501 $this->info[
'error'][] = $message;
508 $this->info[
'warning'][] = $message;
517 $AVpossibleEmptyKeys = array(
'dataformat',
'bits_per_sample',
'encoder_options',
'streams',
'bitrate');
518 foreach ($AVpossibleEmptyKeys as $dummy => $key) {
519 if (empty($this->info[
'audio'][$key]) && isset($this->info[
'audio'][$key])) {
520 unset($this->info[
'audio'][$key]);
522 if (empty($this->info[
'video'][$key]) && isset($this->info[
'video'][$key])) {
523 unset($this->info[
'video'][$key]);
528 if (!empty($this->info)) {
529 foreach ($this->info as $key => $value) {
530 if (empty($this->info[$key]) && ($this->info[$key] !== 0) && ($this->info[$key] !==
'0')) {
531 unset($this->info[$key]);
537 if (empty($this->info[
'fileformat'])) {
538 if (isset($this->info[
'avdataoffset'])) {
539 unset($this->info[
'avdataoffset']);
541 if (isset($this->info[
'avdataend'])) {
542 unset($this->info[
'avdataend']);
547 if (!empty($this->info[
'error'])) {
548 $this->info[
'error'] = array_values(array_unique($this->info[
'error']));
550 if (!empty($this->info[
'warning'])) {
551 $this->info[
'warning'] = array_values(array_unique($this->info[
'warning']));
555 unset($this->info[
'php_memory_limit']);
563 static $format_info = array();
564 if (empty($format_info)) {
565 $format_info = array(
571 'pattern' =>
'^\x0B\x77',
574 'mime_type' =>
'audio/ac3',
579 'pattern' =>
'^ADIF',
582 'mime_type' =>
'application/octet-stream',
583 'fail_ape' =>
'WARNING',
597 'pattern' =>
'^\xFF[\xF0-\xF1\xF8-\xF9]',
600 'mime_type' =>
'application/octet-stream',
601 'fail_ape' =>
'WARNING',
607 'pattern' =>
'^\.snd',
610 'mime_type' =>
'audio/basic',
615 'pattern' =>
'^\x23\x21AMR\x0A',
618 'mime_type' =>
'audio/amr',
623 'pattern' =>
'^2BIT',
626 'mime_type' =>
'application/octet-stream',
631 'pattern' =>
'^\x00(BONK|INFO|META| ID3)',
634 'mime_type' =>
'audio/xmms-bonk',
639 'pattern' =>
'^[\x02-\x03]ds[s2]',
642 'mime_type' =>
'application/octet-stream',
647 'pattern' =>
'^\x7F\xFE\x80\x01',
650 'mime_type' =>
'audio/dts',
655 'pattern' =>
'^fLaC',
658 'mime_type' =>
'audio/x-flac',
663 'pattern' =>
'^LA0[2-4]',
666 'mime_type' =>
'application/octet-stream',
671 'pattern' =>
'^LPAC',
674 'mime_type' =>
'application/octet-stream',
679 'pattern' =>
'^MThd',
682 'mime_type' =>
'audio/midi',
687 'pattern' =>
'^MAC ',
689 'module' =>
'monkey',
690 'mime_type' =>
'application/octet-stream',
705 'pattern' =>
'^IMPM',
709 'mime_type' =>
'audio/it',
714 'pattern' =>
'^Extended Module',
718 'mime_type' =>
'audio/xm',
723 'pattern' =>
'^.{44}SCRM',
727 'mime_type' =>
'audio/s3m',
732 'pattern' =>
'^(MPCK|MP\+|[\x00\x01\x10\x11\x40\x41\x50\x51\x80\x81\x90\x91\xC0\xC1\xD0\xD1][\x20-37][\x00\x20\x40\x60\x80\xA0\xC0\xE0])',
735 'mime_type' =>
'audio/x-musepack',
740 'pattern' =>
'^\xFF[\xE2-\xE7\xF2-\xF7\xFA-\xFF][\x00-\x0B\x10-\x1B\x20-\x2B\x30-\x3B\x40-\x4B\x50-\x5B\x60-\x6B\x70-\x7B\x80-\x8B\x90-\x9B\xA0-\xAB\xB0-\xBB\xC0-\xCB\xD0-\xDB\xE0-\xEB\xF0-\xFB]',
743 'mime_type' =>
'audio/mpeg',
748 'pattern' =>
'^(\*RIFF|OFR)',
750 'module' =>
'optimfrog',
751 'mime_type' =>
'application/octet-stream',
759 'mime_type' =>
'application/octet-stream',
764 'pattern' =>
'^ajkg',
766 'module' =>
'shorten',
767 'mime_type' =>
'audio/xmms-shn',
768 'fail_id3' =>
'ERROR',
769 'fail_ape' =>
'ERROR',
777 'mime_type' =>
'application/octet-stream',
782 'pattern' =>
'^Creative Voice File',
785 'mime_type' =>
'audio/voc',
790 'pattern' =>
'^TWIN',
793 'mime_type' =>
'application/octet-stream',
798 'pattern' =>
'^wvpk',
800 'module' =>
'wavpack',
801 'mime_type' =>
'application/octet-stream',
809 'pattern' =>
'^\x30\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C',
810 'group' =>
'audio-video',
812 'mime_type' =>
'video/x-ms-asf',
813 'iconv_req' =>
false,
818 'pattern' =>
'^(BIK|SMK)',
819 'group' =>
'audio-video',
821 'mime_type' =>
'application/octet-stream',
826 'pattern' =>
'^FLV\x01',
827 'group' =>
'audio-video',
829 'mime_type' =>
'video/x-flv',
834 'pattern' =>
'^\x1A\x45\xDF\xA3',
835 'group' =>
'audio-video',
836 'module' =>
'matroska',
837 'mime_type' =>
'video/x-matroska',
842 'pattern' =>
'^\x00\x00\x01(\xBA|\xB3)',
843 'group' =>
'audio-video',
845 'mime_type' =>
'video/mpeg',
850 'pattern' =>
'^NSV[sf]',
851 'group' =>
'audio-video',
853 'mime_type' =>
'application/octet-stream',
858 'pattern' =>
'^OggS',
861 'mime_type' =>
'application/ogg',
862 'fail_id3' =>
'WARNING',
863 'fail_ape' =>
'WARNING',
867 'quicktime' => array(
868 'pattern' =>
'^.{4}(cmov|free|ftyp|mdat|moov|pnot|skip|wide)',
869 'group' =>
'audio-video',
870 'module' =>
'quicktime',
871 'mime_type' =>
'video/quicktime',
876 'pattern' =>
'^(RIFF|SDSS|FORM)',
877 'group' =>
'audio-video',
879 'mime_type' =>
'audio/x-wave',
880 'fail_ape' =>
'WARNING',
885 'pattern' =>
'^(\\.RMF|\\.ra)',
886 'group' =>
'audio-video',
888 'mime_type' =>
'audio/x-realaudio',
893 'pattern' =>
'^(F|C)WS',
894 'group' =>
'audio-video',
896 'mime_type' =>
'application/x-shockwave-flash',
901 'pattern' =>
'^(\x47.{187}){10,}',
902 'group' =>
'audio-video',
904 'mime_type' =>
'video/MP2T',
913 'group' =>
'graphic',
915 'mime_type' =>
'image/bmp',
916 'fail_id3' =>
'ERROR',
917 'fail_ape' =>
'ERROR',
923 'group' =>
'graphic',
925 'mime_type' =>
'image/gif',
926 'fail_id3' =>
'ERROR',
927 'fail_ape' =>
'ERROR',
932 'pattern' =>
'^\xFF\xD8\xFF',
933 'group' =>
'graphic',
935 'mime_type' =>
'image/jpeg',
936 'fail_id3' =>
'ERROR',
937 'fail_ape' =>
'ERROR',
942 'pattern' =>
'^.{2048}PCD_IPI\x00',
943 'group' =>
'graphic',
945 'mime_type' =>
'image/x-photo-cd',
946 'fail_id3' =>
'ERROR',
947 'fail_ape' =>
'ERROR',
953 'pattern' =>
'^\x89\x50\x4E\x47\x0D\x0A\x1A\x0A',
954 'group' =>
'graphic',
956 'mime_type' =>
'image/png',
957 'fail_id3' =>
'ERROR',
958 'fail_ape' =>
'ERROR',
964 'pattern' =>
'(<!DOCTYPE svg PUBLIC |xmlns="http:\/\/www\.w3\.org\/2000\/svg")',
965 'group' =>
'graphic',
967 'mime_type' =>
'image/svg+xml',
968 'fail_id3' =>
'ERROR',
969 'fail_ape' =>
'ERROR',
975 'pattern' =>
'^(II\x2A\x00|MM\x00\x2A)',
976 'group' =>
'graphic',
978 'mime_type' =>
'image/tiff',
979 'fail_id3' =>
'ERROR',
980 'fail_ape' =>
'ERROR',
986 'pattern' =>
'^\xDC\xFE',
987 'group' =>
'graphic',
989 'mime_type' =>
'image/efax',
990 'fail_id3' =>
'ERROR',
991 'fail_ape' =>
'ERROR',
999 'pattern' =>
'^.{32769}CD001',
1002 'mime_type' =>
'application/octet-stream',
1003 'fail_id3' =>
'ERROR',
1004 'fail_ape' =>
'ERROR',
1005 'iconv_req' =>
false,
1010 'pattern' =>
'^Rar\!',
1011 'group' =>
'archive',
1013 'mime_type' =>
'application/octet-stream',
1014 'fail_id3' =>
'ERROR',
1015 'fail_ape' =>
'ERROR',
1020 'pattern' =>
'^SZ\x0A\x04',
1021 'group' =>
'archive',
1023 'mime_type' =>
'application/octet-stream',
1024 'fail_id3' =>
'ERROR',
1025 'fail_ape' =>
'ERROR',
1030 '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}',
1031 'group' =>
'archive',
1033 'mime_type' =>
'application/x-tar',
1034 'fail_id3' =>
'ERROR',
1035 'fail_ape' =>
'ERROR',
1040 'pattern' =>
'^\x1F\x8B\x08',
1041 'group' =>
'archive',
1043 'mime_type' =>
'application/x-gzip',
1044 'fail_id3' =>
'ERROR',
1045 'fail_ape' =>
'ERROR',
1050 'pattern' =>
'^PK\x03\x04',
1051 'group' =>
'archive',
1053 'mime_type' =>
'application/zip',
1054 'fail_id3' =>
'ERROR',
1055 'fail_ape' =>
'ERROR',
1063 'pattern' =>
'^PAR2\x00PKT',
1066 'mime_type' =>
'application/octet-stream',
1067 'fail_id3' =>
'ERROR',
1068 'fail_ape' =>
'ERROR',
1073 'pattern' =>
'^\x25PDF',
1076 'mime_type' =>
'application/pdf',
1077 'fail_id3' =>
'ERROR',
1078 'fail_ape' =>
'ERROR',
1082 'msoffice' => array(
1083 'pattern' =>
'^\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1',
1085 'module' =>
'msoffice',
1086 'mime_type' =>
'application/octet-stream',
1087 'fail_id3' =>
'ERROR',
1088 'fail_ape' =>
'ERROR',
1096 'mime_type' =>
'application/octet-stream',
1102 return $format_info;
1117 if (!empty(
$info[
'pattern']) && preg_match(
'#'.
$info[
'pattern'].
'#s', $filedata)) {
1118 $info[
'include'] =
'module.'.$info[
'group'].
'.'.
$info[
'module'].
'.php';
1124 if (preg_match(
'#\.mp[123a]$#i',
$filename)) {
1128 $info = $GetFileFormatArray[
'mp3'];
1129 $info[
'include'] =
'module.'.$info[
'group'].
'.'.
$info[
'module'].
'.php';
1131 } elseif (preg_match(
'/\.cue$/i',
$filename) && preg_match(
'#FILE "[^"]+" (BINARY|MOTOROLA|AIFF|WAVE|MP3)#', $filedata)) {
1136 $info = $GetFileFormatArray[
'cue'];
1137 $info[
'include'] =
'module.'.$info[
'group'].
'.'.
$info[
'module'].
'.php';
1154 foreach ($array as $key => $value) {
1157 if (is_array($value)) {
1162 elseif (is_string($value)) {
1175 'asf' => array(
'asf' ,
'UTF-16LE'),
1176 'midi' => array(
'midi' ,
'ISO-8859-1'),
1177 'nsv' => array(
'nsv' ,
'ISO-8859-1'),
1178 'ogg' => array(
'vorbiscomment' ,
'UTF-8'),
1179 'png' => array(
'png' ,
'UTF-8'),
1180 'tiff' => array(
'tiff' ,
'ISO-8859-1'),
1181 'quicktime' => array(
'quicktime' ,
'UTF-8'),
1182 'real' => array(
'real' ,
'ISO-8859-1'),
1183 'vqf' => array(
'vqf' ,
'ISO-8859-1'),
1184 'zip' => array(
'zip' ,
'ISO-8859-1'),
1185 'riff' => array(
'riff' ,
'ISO-8859-1'),
1186 'lyrics3' => array(
'lyrics3' ,
'ISO-8859-1'),
1187 'id3v1' => array(
'id3v1' , $this->encoding_id3v1),
1188 'id3v2' => array(
'id3v2' ,
'UTF-8'),
1189 'ape' => array(
'ape' ,
'UTF-8'),
1190 'cue' => array(
'cue' ,
'ISO-8859-1'),
1191 'matroska' => array(
'matroska' ,
'UTF-8'),
1192 'flac' => array(
'vorbiscomment' ,
'UTF-8'),
1193 'divxtag' => array(
'divx' ,
'ISO-8859-1'),
1194 'iptc' => array(
'iptc' ,
'ISO-8859-1'),
1199 foreach ($tags as $comment_name => $tagname_encoding_array) {
1200 list($tag_name,
$encoding) = $tagname_encoding_array;
1203 if (isset($this->info[$comment_name]) && !isset($this->info[$comment_name][
'encoding'])) {
1204 $this->info[$comment_name][
'encoding'] =
$encoding;
1208 if (!empty($this->info[$comment_name][
'comments'])) {
1209 foreach ($this->info[$comment_name][
'comments'] as $tag_key => $valuearray) {
1210 foreach ($valuearray as $key => $value) {
1211 if (is_string($value)) {
1212 $value = trim($value,
" \r\n\t");
1215 if (!is_numeric($key)) {
1216 $this->info[
'tags'][trim($tag_name)][trim($tag_key)][$key] = $value;
1218 $this->info[
'tags'][trim($tag_name)][trim($tag_key)][] = $value;
1222 if ($tag_key ==
'picture') {
1223 unset($this->info[$comment_name][
'comments'][$tag_key]);
1227 if (!isset($this->info[
'tags'][$tag_name])) {
1232 if ($this->option_tags_html) {
1233 foreach ($this->info[
'tags'][$tag_name] as $tag_key => $valuearray) {
1241 if ($comment_name ==
'id3v1') {
1243 if (function_exists(
'iconv')) {
1244 foreach ($this->info[
'tags'][$tag_name] as $tag_key => $valuearray) {
1245 foreach ($valuearray as $key => $value) {
1246 if (preg_match(
'#^[\\x80-\\xFF]+$#', $value)) {
1247 foreach (array(
'windows-1251',
'KOI8-R') as $id3v1_bad_encoding) {
1248 if (@iconv($id3v1_bad_encoding, $id3v1_bad_encoding, $value) === $value) {
1268 if (!empty($this->info[
'tags'])) {
1269 $unset_keys = array(
'tags',
'tags_html');
1270 foreach ($this->info[
'tags'] as $tagtype => $tagarray) {
1271 foreach ($tagarray as $tagname => $tagdata) {
1272 if ($tagname ==
'picture') {
1273 foreach ($tagdata as $key => $tagarray) {
1274 $this->info[
'comments'][
'picture'][] = $tagarray;
1275 if (isset($tagarray[
'data']) && isset($tagarray[
'image_mime'])) {
1276 if (isset($this->info[
'tags'][$tagtype][$tagname][$key])) {
1277 unset($this->info[
'tags'][$tagtype][$tagname][$key]);
1279 if (isset($this->info[
'tags_html'][$tagtype][$tagname][$key])) {
1280 unset($this->info[
'tags_html'][$tagtype][$tagname][$key]);
1286 foreach ($unset_keys as $unset_key) {
1288 if (empty($this->info[$unset_key][$tagtype][
'picture'])) {
1289 unset($this->info[$unset_key][$tagtype][
'picture']);
1291 if (empty($this->info[$unset_key][$tagtype])) {
1292 unset($this->info[$unset_key][$tagtype]);
1294 if (empty($this->info[$unset_key])) {
1295 unset($this->info[$unset_key]);
1299 if (isset($this->info[$tagtype][
'comments'][
'picture'])) {
1300 unset($this->info[$tagtype][
'comments'][
'picture']);
1302 if (empty($this->info[$tagtype][
'comments'])) {
1303 unset($this->info[$tagtype][
'comments']);
1305 if (empty($this->info[$tagtype])) {
1306 unset($this->info[$tagtype]);
1314 switch ($algorithm) {
1320 return $this->
error(
'bad algorithm "'.$algorithm.
'" in getHashdata()');
1324 if (!empty($this->info[
'fileformat']) && !empty($this->info[
'dataformat']) && ($this->info[
'fileformat'] ==
'ogg') && ($this->info[
'audio'][
'dataformat'] ==
'vorbis')) {
1344 if (preg_match(
'#(1|ON)#i', ini_get(
'safe_mode'))) {
1346 $this->
warning(
'Failed making system call to vorbiscomment.exe - '.$algorithm.
'_data is incorrect - error returned: PHP running in Safe Mode (backtick operator not available)');
1347 $this->info[$algorithm.
'_data'] =
false;
1352 $old_abort = ignore_user_abort(
true);
1355 $empty = tempnam(GETID3_TEMP_DIR,
'getID3');
1359 $temp = tempnam(GETID3_TEMP_DIR,
'getID3');
1360 $file = $this->info[
'filenamepath'];
1362 if (GETID3_OS_ISWINDOWS) {
1364 if (file_exists(GETID3_HELPERAPPSDIR.
'vorbiscomment.exe')) {
1366 $commandline =
'"'.GETID3_HELPERAPPSDIR.
'vorbiscomment.exe" -w -c "'.$empty.
'" "'.
$file.
'" "'.$temp.
'"';
1367 $VorbisCommentError = `$commandline`;
1371 $VorbisCommentError =
'vorbiscomment.exe not found in '.GETID3_HELPERAPPSDIR;
1377 $commandline =
'vorbiscomment -w -c "'.$empty.
'" "'.
$file.
'" "'.$temp.
'" 2>&1';
1378 $commandline =
'vorbiscomment -w -c '.escapeshellarg($empty).
' '.escapeshellarg(
$file).
' '.escapeshellarg($temp).
' 2>&1';
1379 $VorbisCommentError = `$commandline`;
1383 if (!empty($VorbisCommentError)) {
1385 $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;
1386 $this->info[$algorithm.
'_data'] =
false;
1391 switch ($algorithm) {
1393 $this->info[$algorithm.
'_data'] = md5_file($temp);
1397 $this->info[$algorithm.
'_data'] = sha1_file($temp);
1407 ignore_user_abort($old_abort);
1413 if (!empty($this->info[
'avdataoffset']) || (isset($this->info[
'avdataend']) && ($this->info[
'avdataend'] < $this->info[
'filesize']))) {
1416 $this->info[$algorithm.
'_data'] =
getid3_lib::hash_data($this->info[
'filenamepath'], $this->info[
'avdataoffset'], $this->info[
'avdataend'], $algorithm);
1421 switch ($algorithm) {
1423 $this->info[$algorithm.
'_data'] = md5_file($this->info[
'filenamepath']);
1427 $this->info[$algorithm.
'_data'] = sha1_file($this->info[
'filenamepath']);
1440 if (!empty($this->info[
'audio'][
'channelmode']) || !isset($this->info[
'audio'][
'channels'])) {
1442 } elseif ($this->info[
'audio'][
'channels'] == 1) {
1443 $this->info[
'audio'][
'channelmode'] =
'mono';
1444 } elseif ($this->info[
'audio'][
'channels'] == 2) {
1445 $this->info[
'audio'][
'channelmode'] =
'stereo';
1449 $CombinedBitrate = 0;
1450 $CombinedBitrate += (isset($this->info[
'audio'][
'bitrate']) ? $this->info[
'audio'][
'bitrate'] : 0);
1451 $CombinedBitrate += (isset($this->info[
'video'][
'bitrate']) ? $this->info[
'video'][
'bitrate'] : 0);
1452 if (($CombinedBitrate > 0) && empty($this->info[
'bitrate'])) {
1453 $this->info[
'bitrate'] = $CombinedBitrate;
1462 if (isset($this->info[
'video'][
'dataformat']) && $this->info[
'video'][
'dataformat'] && (!isset($this->info[
'video'][
'bitrate']) || ($this->info[
'video'][
'bitrate'] == 0))) {
1464 if (isset($this->info[
'audio'][
'bitrate']) && ($this->info[
'audio'][
'bitrate'] > 0) && ($this->info[
'audio'][
'bitrate'] == $this->info[
'bitrate'])) {
1466 if (isset($this->info[
'playtime_seconds']) && ($this->info[
'playtime_seconds'] > 0)) {
1468 if (isset($this->info[
'avdataend']) && isset($this->info[
'avdataoffset'])) {
1471 $this->info[
'bitrate'] = round((($this->info[
'avdataend'] - $this->info[
'avdataoffset']) * 8) / $this->info[
'playtime_seconds']);
1472 $this->info[
'video'][
'bitrate'] = $this->info[
'bitrate'] - $this->info[
'audio'][
'bitrate'];
1478 if ((!isset($this->info[
'playtime_seconds']) || ($this->info[
'playtime_seconds'] <= 0)) && !empty($this->info[
'bitrate'])) {
1479 $this->info[
'playtime_seconds'] = (($this->info[
'avdataend'] - $this->info[
'avdataoffset']) * 8) / $this->info[
'bitrate'];
1482 if (!isset($this->info[
'bitrate']) && !empty($this->info[
'playtime_seconds'])) {
1483 $this->info[
'bitrate'] = (($this->info[
'avdataend'] - $this->info[
'avdataoffset']) * 8) / $this->info[
'playtime_seconds'];
1485 if (isset($this->info[
'bitrate']) && empty($this->info[
'audio'][
'bitrate']) && empty($this->info[
'video'][
'bitrate'])) {
1486 if (isset($this->info[
'audio'][
'dataformat']) && empty($this->info[
'video'][
'resolution_x'])) {
1488 $this->info[
'audio'][
'bitrate'] = $this->info[
'bitrate'];
1489 } elseif (isset($this->info[
'video'][
'resolution_x']) && empty($this->info[
'audio'][
'dataformat'])) {
1491 $this->info[
'video'][
'bitrate'] = $this->info[
'bitrate'];
1496 if (!empty($this->info[
'playtime_seconds']) && empty($this->info[
'playtime_string'])) {
1503 if (empty($this->info[
'video'])) {
1506 if (empty($this->info[
'video'][
'resolution_x']) || empty($this->info[
'video'][
'resolution_y'])) {
1509 if (empty($this->info[
'video'][
'bits_per_sample'])) {
1513 switch ($this->info[
'video'][
'dataformat']) {
1521 $PlaytimeSeconds = 1;
1522 $BitrateCompressed = $this->info[
'filesize'] * 8;
1526 if (!empty($this->info[
'video'][
'frame_rate'])) {
1527 $FrameRate = $this->info[
'video'][
'frame_rate'];
1531 if (!empty($this->info[
'playtime_seconds'])) {
1532 $PlaytimeSeconds = $this->info[
'playtime_seconds'];
1536 if (!empty($this->info[
'video'][
'bitrate'])) {
1537 $BitrateCompressed = $this->info[
'video'][
'bitrate'];
1543 $BitrateUncompressed = $this->info[
'video'][
'resolution_x'] * $this->info[
'video'][
'resolution_y'] * $this->info[
'video'][
'bits_per_sample'] * $FrameRate;
1545 $this->info[
'video'][
'compression_ratio'] = $BitrateCompressed / $BitrateUncompressed;
1551 if (empty($this->info[
'audio'][
'bitrate']) || empty($this->info[
'audio'][
'channels']) || empty($this->info[
'audio'][
'sample_rate']) || !is_numeric($this->info[
'audio'][
'sample_rate'])) {
1554 $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));
1556 if (!empty($this->info[
'audio'][
'streams'])) {
1557 foreach ($this->info[
'audio'][
'streams'] as $streamnumber => $streamdata) {
1558 if (!empty($streamdata[
'bitrate']) && !empty($streamdata[
'channels']) && !empty($streamdata[
'sample_rate'])) {
1559 $this->info[
'audio'][
'streams'][$streamnumber][
'compression_ratio'] = $streamdata[
'bitrate'] / ($streamdata[
'channels'] * $streamdata[
'sample_rate'] * (!empty($streamdata[
'bits_per_sample']) ? $streamdata[
'bits_per_sample'] : 16));
1568 if (isset($this->info[
'replay_gain'])) {
1569 if (!isset($this->info[
'replay_gain'][
'reference_volume'])) {
1570 $this->info[
'replay_gain'][
'reference_volume'] = (double) 89.0;
1572 if (isset($this->info[
'replay_gain'][
'track'][
'adjustment'])) {
1573 $this->info[
'replay_gain'][
'track'][
'volume'] = $this->info[
'replay_gain'][
'reference_volume'] - $this->info[
'replay_gain'][
'track'][
'adjustment'];
1575 if (isset($this->info[
'replay_gain'][
'album'][
'adjustment'])) {
1576 $this->info[
'replay_gain'][
'album'][
'volume'] = $this->info[
'replay_gain'][
'reference_volume'] - $this->info[
'replay_gain'][
'album'][
'adjustment'];
1579 if (isset($this->info[
'replay_gain'][
'track'][
'peak'])) {
1580 $this->info[
'replay_gain'][
'track'][
'max_noclip_gain'] = 0 -
getid3_lib::RGADamplitude2dB($this->info[
'replay_gain'][
'track'][
'peak']);
1582 if (isset($this->info[
'replay_gain'][
'album'][
'peak'])) {
1583 $this->info[
'replay_gain'][
'album'][
'max_noclip_gain'] = 0 -
getid3_lib::RGADamplitude2dB($this->info[
'replay_gain'][
'album'][
'peak']);
1590 if (!empty($this->info[
'audio'][
'bitrate']) || !empty($this->info[
'audio'][
'channels']) || !empty($this->info[
'audio'][
'sample_rate'])) {
1591 if (!isset($this->info[
'audio'][
'streams'])) {
1592 foreach ($this->info[
'audio'] as $key => $value) {
1593 if ($key !=
'streams') {
1594 $this->info[
'audio'][
'streams'][0][$key] = $value;
1603 return tempnam($this->tempdir,
'gI3');
1608 if (!file_exists(GETID3_INCLUDEPATH.
'module.'.$name.
'.php')) {
1611 include_once(GETID3_INCLUDEPATH.
'module.'.$name.
'.php');
1625 protected $data_string_flag =
false;
1626 protected $data_string =
'';
1627 protected $data_string_position = 0;
1628 protected $data_string_length = 0;
1630 private $dependency_to = null;
1634 $this->getid3 = $getid3;
1637 $this->dependency_to = str_replace(
'getid3_',
'', $call_module);
1643 abstract public function Analyze();
1649 $this->setStringMode($string);
1652 $saved_avdataoffset = $this->getid3->info[
'avdataoffset'];
1653 $saved_avdataend = $this->getid3->info[
'avdataend'];
1654 $saved_filesize = (isset($this->getid3->info[
'filesize']) ? $this->getid3->info[
'filesize'] : null);
1657 $this->getid3->info[
'avdataoffset'] = 0;
1658 $this->getid3->info[
'avdataend'] = $this->getid3->info[
'filesize'] = $this->data_string_length;
1664 $this->getid3->info[
'avdataoffset'] = $saved_avdataoffset;
1665 $this->getid3->info[
'avdataend'] = $saved_avdataend;
1666 $this->getid3->info[
'filesize'] = $saved_filesize;
1669 $this->data_string_flag =
false;
1673 $this->data_string_flag =
true;
1674 $this->data_string = $string;
1675 $this->data_string_length = strlen($string);
1679 if ($this->data_string_flag) {
1680 return $this->data_string_position;
1682 return ftell($this->getid3->fp);
1686 if ($this->data_string_flag) {
1687 $this->data_string_position += $bytes;
1688 return substr($this->data_string, $this->data_string_position - $bytes, $bytes);
1690 $pos = $this->ftell() + $bytes;
1692 throw new getid3_exception(
'cannot fread('.$bytes.
' from '.$this->ftell().
') because beyond PHP filesystem limit', 10);
1694 return fread($this->getid3->fp, $bytes);
1697 protected function fseek($bytes, $whence=SEEK_SET) {
1698 if ($this->data_string_flag) {
1701 $this->data_string_position = $bytes;
1705 $this->data_string_position += $bytes;
1709 $this->data_string_position = $this->data_string_length + $bytes;
1715 if ($whence == SEEK_CUR) {
1716 $pos = $this->ftell() + $bytes;
1717 } elseif ($whence == SEEK_END) {
1718 $pos = $this->getid3->info[
'filesize'] + $bytes;
1721 throw new getid3_exception(
'cannot fseek('.$pos.
') because beyond PHP filesystem limit', 10);
1724 return fseek($this->getid3->fp, $bytes, $whence);
1728 if ($this->data_string_flag) {
1729 return $this->data_string_position >= $this->data_string_length;
1731 return feof($this->getid3->fp);
1735 return $this->dependency_to == $module;
1739 $this->getid3->info[
'error'][] =
$text;
1745 return $this->getid3->warning(
$text);
1763 $this->fseek($offset);
1764 $attachment = $this->fread($length);
1765 if ($attachment ===
false || strlen($attachment) != $length) {
1766 throw new Exception(
'failed to read attachment data');
1773 $dir = rtrim(str_replace(array(
'/',
'\\'), DIRECTORY_SEPARATOR, $this->getid3->option_save_attachments), DIRECTORY_SEPARATOR);
1774 if (!is_dir($dir) || !is_writable($dir)) {
1775 throw new Exception(
'supplied path ('.$dir.
') does not exist, or is not writable');
1777 $dest = $dir.DIRECTORY_SEPARATOR.$name.($image_mime ?
'.'.getid3_lib::ImageExtFromMime($image_mime) :
'');
1780 if (($fp_dest = fopen($dest,
'wb')) ==
false) {
1781 throw new Exception(
'failed to create file '.$dest);
1785 $this->fseek($offset);
1786 $buffersize = ($this->data_string_flag ? $length : $this->getid3->fread_buffer_size());
1787 $bytesleft = $length;
1788 while ($bytesleft > 0) {
1789 if (($buffer = $this->fread(min($buffersize, $bytesleft))) ===
false || ($byteswritten = fwrite($fp_dest, $buffer)) ===
false || ($byteswritten === 0)) {
1790 throw new Exception($buffer ===
false ?
'not enough data to read' :
'failed to write to destination file, may be not enough disk space');
1792 $bytesleft -= $byteswritten;
1796 $attachment = $dest;
1803 if (isset($fp_dest) && is_resource($fp_dest)) {
1810 $this->
warning(
'Failed to extract attachment '.$name.
': '.$e->getMessage());
1815 $this->fseek($offset + $length);
analyze($filename, $filesize=null, $original_filename='')
$option_fread_buffer_size
GetFileFormat(&$filedata, $filename='')
if(!defined('GETID3_OS_ISWINDOWS')) if(!defined('GETID3_INCLUDEPATH')) if(!defined('IMG_JPG') &&defined('IMAGETYPE_JPEG')) $temp_dir
getID3() by James Heinrich info@getid3.org //
static intValueSupported($num)
saveAttachment($name, $offset, $length, $image_mime=null)
PlaytimeString($playtimeseconds)
CalculateCompressionRatioAudio()
CharConvert(&$array, $encoding)
static getFileSizeSyscall($path)
hash_data($file, $offset, $end, $algorithm)
RGADamplitude2dB($amplitude)
iconv_fallback($in_charset, $out_charset, $string)
BigEndian2Int($byteword, $synchsafe=false, $signed=false)
__construct(getID3 $getid3, $call_module=null)
CalculateCompressionRatioVideo()
static recursiveMultiByteCharString2HTML($data, $charset='ISO-8859-1')
fseek($bytes, $whence=SEEK_SET)
openfile($filename, $filesize=null)
static mb_basename($path, $suffix=null)
Workaround for Bug #37268 (https://bugs.php.net/bug.php?id=37268)
ChannelsBitratePlaytimeCalculations()