1 <?php |
1 <?php |
2 ///////////////////////////////////////////////////////////////// |
2 ///////////////////////////////////////////////////////////////// |
3 /// getID3() by James Heinrich <info@getid3.org> // |
3 /// getID3() by James Heinrich <info@getid3.org> // |
4 // available at http://getid3.sourceforge.net // |
4 // available at http://getid3.sourceforge.net // |
5 // or http://www.getid3.org // |
5 // or http://www.getid3.org // |
|
6 // also https://github.com/JamesHeinrich/getID3 // |
6 ///////////////////////////////////////////////////////////////// |
7 ///////////////////////////////////////////////////////////////// |
7 // // |
8 // // |
8 // Please see readme.txt for more information // |
9 // Please see readme.txt for more information // |
9 // /// |
10 // /// |
10 ///////////////////////////////////////////////////////////////// |
11 ///////////////////////////////////////////////////////////////// |
15 } |
16 } |
16 // Get base path of getID3() - ONCE |
17 // Get base path of getID3() - ONCE |
17 if (!defined('GETID3_INCLUDEPATH')) { |
18 if (!defined('GETID3_INCLUDEPATH')) { |
18 define('GETID3_INCLUDEPATH', dirname(__FILE__).DIRECTORY_SEPARATOR); |
19 define('GETID3_INCLUDEPATH', dirname(__FILE__).DIRECTORY_SEPARATOR); |
19 } |
20 } |
|
21 // Workaround Bug #39923 (https://bugs.php.net/bug.php?id=39923) |
|
22 if (!defined('IMG_JPG') && defined('IMAGETYPE_JPEG')) { |
|
23 define('IMG_JPG', IMAGETYPE_JPEG); |
|
24 } |
20 |
25 |
21 // attempt to define temp dir as something flexible but reliable |
26 // attempt to define temp dir as something flexible but reliable |
22 $temp_dir = ini_get('upload_tmp_dir'); |
27 $temp_dir = ini_get('upload_tmp_dir'); |
23 if ($temp_dir && (!is_dir($temp_dir) || !is_readable($temp_dir))) { |
28 if ($temp_dir && (!is_dir($temp_dir) || !is_readable($temp_dir))) { |
24 $temp_dir = ''; |
29 $temp_dir = ''; |
25 } |
30 } |
26 if (!$temp_dir && function_exists('sys_get_temp_dir')) { |
31 if (!$temp_dir) { |
27 // PHP v5.2.1+ |
|
28 // sys_get_temp_dir() may give inaccessible temp dir, e.g. with open_basedir on virtual hosts |
32 // sys_get_temp_dir() may give inaccessible temp dir, e.g. with open_basedir on virtual hosts |
29 $temp_dir = sys_get_temp_dir(); |
33 $temp_dir = sys_get_temp_dir(); |
30 } |
34 } |
31 $temp_dir = realpath($temp_dir); |
35 $temp_dir = @realpath($temp_dir); // see https://github.com/JamesHeinrich/getID3/pull/10 |
32 $open_basedir = ini_get('open_basedir'); |
36 $open_basedir = ini_get('open_basedir'); |
33 if ($open_basedir) { |
37 if ($open_basedir) { |
34 // e.g. "/var/www/vhosts/getid3.org/httpdocs/:/tmp/" |
38 // e.g. "/var/www/vhosts/getid3.org/httpdocs/:/tmp/" |
35 $temp_dir = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $temp_dir); |
39 $temp_dir = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $temp_dir); |
36 $open_basedir = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $open_basedir); |
40 $open_basedir = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $open_basedir); |
55 } |
59 } |
56 if (!$temp_dir) { |
60 if (!$temp_dir) { |
57 $temp_dir = '*'; // invalid directory name should force tempnam() to use system default temp dir |
61 $temp_dir = '*'; // invalid directory name should force tempnam() to use system default temp dir |
58 } |
62 } |
59 // $temp_dir = '/something/else/'; // feel free to override temp dir here if it works better for your system |
63 // $temp_dir = '/something/else/'; // feel free to override temp dir here if it works better for your system |
60 define('GETID3_TEMP_DIR', $temp_dir); |
64 if (!defined('GETID3_TEMP_DIR')) { |
|
65 define('GETID3_TEMP_DIR', $temp_dir); |
|
66 } |
61 unset($open_basedir, $temp_dir); |
67 unset($open_basedir, $temp_dir); |
62 |
68 |
63 // End: Defines |
69 // End: Defines |
64 |
70 |
65 |
71 |
95 // Public variables |
101 // Public variables |
96 public $filename; // Filename of file being analysed. |
102 public $filename; // Filename of file being analysed. |
97 public $fp; // Filepointer to file being analysed. |
103 public $fp; // Filepointer to file being analysed. |
98 public $info; // Result array. |
104 public $info; // Result array. |
99 public $tempdir = GETID3_TEMP_DIR; |
105 public $tempdir = GETID3_TEMP_DIR; |
|
106 public $memory_limit = 0; |
100 |
107 |
101 // Protected variables |
108 // Protected variables |
102 protected $startup_error = ''; |
109 protected $startup_error = ''; |
103 protected $startup_warning = ''; |
110 protected $startup_warning = ''; |
104 protected $memory_limit = 0; |
111 |
105 |
112 const VERSION = '1.9.8-20140511'; |
106 const VERSION = '1.9.7-20130705'; |
|
107 const FREAD_BUFFER_SIZE = 32768; |
113 const FREAD_BUFFER_SIZE = 32768; |
108 |
114 |
109 const ATTACHMENTS_NONE = false; |
115 const ATTACHMENTS_NONE = false; |
110 const ATTACHMENTS_INLINE = true; |
116 const ATTACHMENTS_INLINE = true; |
111 |
117 |
112 // public: constructor |
118 // public: constructor |
113 public function __construct() { |
119 public function __construct() { |
114 |
|
115 // Check for PHP version |
|
116 $required_php_version = '5.0.5'; |
|
117 if (version_compare(PHP_VERSION, $required_php_version, '<')) { |
|
118 $this->startup_error .= 'getID3() requires PHP v'.$required_php_version.' or higher - you are running v'.PHP_VERSION; |
|
119 return false; |
|
120 } |
|
121 |
120 |
122 // Check memory |
121 // Check memory |
123 $this->memory_limit = ini_get('memory_limit'); |
122 $this->memory_limit = ini_get('memory_limit'); |
124 if (preg_match('#([0-9]+)M#i', $this->memory_limit, $matches)) { |
123 if (preg_match('#([0-9]+)M#i', $this->memory_limit, $matches)) { |
125 // could be stored as "16M" rather than 16777216 for example |
124 // could be stored as "16M" rather than 16777216 for example |
259 |
258 |
260 $filename = str_replace('/', DIRECTORY_SEPARATOR, $filename); |
259 $filename = str_replace('/', DIRECTORY_SEPARATOR, $filename); |
261 $filename = preg_replace('#(.+)'.preg_quote(DIRECTORY_SEPARATOR).'{2,}#U', '\1'.DIRECTORY_SEPARATOR, $filename); |
260 $filename = preg_replace('#(.+)'.preg_quote(DIRECTORY_SEPARATOR).'{2,}#U', '\1'.DIRECTORY_SEPARATOR, $filename); |
262 |
261 |
263 // open local file |
262 // open local file |
264 if (is_readable($filename) && is_file($filename) && ($this->fp = fopen($filename, 'rb'))) { |
263 //if (is_readable($filename) && is_file($filename) && ($this->fp = fopen($filename, 'rb'))) { // see http://www.getid3.org/phpBB3/viewtopic.php?t=1720 |
|
264 if ((is_readable($filename) || file_exists($filename)) && is_file($filename) && ($this->fp = fopen($filename, 'rb'))) { |
265 // great |
265 // great |
266 } else { |
266 } else { |
267 throw new getid3_exception('Could not open "'.$filename.'" (does not exist, or is not a file)'); |
267 $errormessagelist = array(); |
|
268 if (!is_readable($filename)) { |
|
269 $errormessagelist[] = '!is_readable'; |
|
270 } |
|
271 if (!is_file($filename)) { |
|
272 $errormessagelist[] = '!is_file'; |
|
273 } |
|
274 if (!file_exists($filename)) { |
|
275 $errormessagelist[] = '!file_exists'; |
|
276 } |
|
277 if (empty($errormessagelist)) { |
|
278 $errormessagelist[] = 'fopen failed'; |
|
279 } |
|
280 throw new getid3_exception('Could not open "'.$filename.'" ('.implode('; ', $errormessagelist).')'); |
268 } |
281 } |
269 |
282 |
270 $this->info['filesize'] = filesize($filename); |
283 $this->info['filesize'] = filesize($filename); |
271 // set redundant parameters - might be needed in some include file |
284 // set redundant parameters - might be needed in some include file |
272 $this->info['filename'] = basename($filename); |
285 // filenames / filepaths in getID3 are always expressed with forward slashes (unix-style) for both Windows and other to try and minimize confusion |
|
286 $filename = str_replace('\\', '/', $filename); |
273 $this->info['filepath'] = str_replace('\\', '/', realpath(dirname($filename))); |
287 $this->info['filepath'] = str_replace('\\', '/', realpath(dirname($filename))); |
|
288 $this->info['filename'] = getid3_lib::mb_basename($filename); |
274 $this->info['filenamepath'] = $this->info['filepath'].'/'.$this->info['filename']; |
289 $this->info['filenamepath'] = $this->info['filepath'].'/'.$this->info['filename']; |
275 |
290 |
276 |
291 |
277 // option_max_2gb_check |
292 // option_max_2gb_check |
278 if ($this->option_max_2gb_check) { |
293 if ($this->option_max_2gb_check) { |
350 } |
365 } |
351 } |
366 } |
352 |
367 |
353 // ID3v2 detection (NOT parsing), even if ($this->option_tag_id3v2 == false) done to make fileformat easier |
368 // ID3v2 detection (NOT parsing), even if ($this->option_tag_id3v2 == false) done to make fileformat easier |
354 if (!$this->option_tag_id3v2) { |
369 if (!$this->option_tag_id3v2) { |
355 fseek($this->fp, 0, SEEK_SET); |
370 fseek($this->fp, 0); |
356 $header = fread($this->fp, 10); |
371 $header = fread($this->fp, 10); |
357 if ((substr($header, 0, 3) == 'ID3') && (strlen($header) == 10)) { |
372 if ((substr($header, 0, 3) == 'ID3') && (strlen($header) == 10)) { |
358 $this->info['id3v2']['header'] = true; |
373 $this->info['id3v2']['header'] = true; |
359 $this->info['id3v2']['majorversion'] = ord($header{3}); |
374 $this->info['id3v2']['majorversion'] = ord($header{3}); |
360 $this->info['id3v2']['minorversion'] = ord($header{4}); |
375 $this->info['id3v2']['minorversion'] = ord($header{4}); |
361 $this->info['avdataoffset'] += getid3_lib::BigEndian2Int(substr($header, 6, 4), 1) + 10; // length of ID3v2 tag in 10-byte header doesn't include 10-byte header length |
376 $this->info['avdataoffset'] += getid3_lib::BigEndian2Int(substr($header, 6, 4), 1) + 10; // length of ID3v2 tag in 10-byte header doesn't include 10-byte header length |
362 } |
377 } |
363 } |
378 } |
364 |
379 |
365 // read 32 kb file data |
380 // read 32 kb file data |
366 fseek($this->fp, $this->info['avdataoffset'], SEEK_SET); |
381 fseek($this->fp, $this->info['avdataoffset']); |
367 $formattest = fread($this->fp, 32774); |
382 $formattest = fread($this->fp, 32774); |
368 |
383 |
369 // determine format |
384 // determine format |
370 $determined_format = $this->GetFileFormat($formattest, $filename); |
385 $determined_format = $this->GetFileFormat($formattest, $filename); |
371 |
386 |
584 'au' => array( |
599 'au' => array( |
585 'pattern' => '^\.snd', |
600 'pattern' => '^\.snd', |
586 'group' => 'audio', |
601 'group' => 'audio', |
587 'module' => 'au', |
602 'module' => 'au', |
588 'mime_type' => 'audio/basic', |
603 'mime_type' => 'audio/basic', |
|
604 ), |
|
605 |
|
606 // AMR - audio - Adaptive Multi Rate |
|
607 'amr' => array( |
|
608 'pattern' => '^\x23\x21AMR\x0A', // #!AMR[0A] |
|
609 'group' => 'audio', |
|
610 'module' => 'amr', |
|
611 'mime_type' => 'audio/amr', |
589 ), |
612 ), |
590 |
613 |
591 // AVR - audio - Audio Visual Research |
614 // AVR - audio - Audio Visual Research |
592 'avr' => array( |
615 'avr' => array( |
593 'pattern' => '^2BIT', |
616 'pattern' => '^2BIT', |
1159 'ape' => array('ape' , 'UTF-8'), |
1182 'ape' => array('ape' , 'UTF-8'), |
1160 'cue' => array('cue' , 'ISO-8859-1'), |
1183 'cue' => array('cue' , 'ISO-8859-1'), |
1161 'matroska' => array('matroska' , 'UTF-8'), |
1184 'matroska' => array('matroska' , 'UTF-8'), |
1162 'flac' => array('vorbiscomment' , 'UTF-8'), |
1185 'flac' => array('vorbiscomment' , 'UTF-8'), |
1163 'divxtag' => array('divx' , 'ISO-8859-1'), |
1186 'divxtag' => array('divx' , 'ISO-8859-1'), |
|
1187 'iptc' => array('iptc' , 'ISO-8859-1'), |
1164 ); |
1188 ); |
1165 } |
1189 } |
1166 |
1190 |
1167 // loop through comments array |
1191 // loop through comments array |
1168 foreach ($tags as $comment_name => $tagname_encoding_array) { |
1192 foreach ($tags as $comment_name => $tagname_encoding_array) { |
1179 foreach ($valuearray as $key => $value) { |
1203 foreach ($valuearray as $key => $value) { |
1180 if (is_string($value)) { |
1204 if (is_string($value)) { |
1181 $value = trim($value, " \r\n\t"); // do not trim nulls from $value!! Unicode characters will get mangled if trailing nulls are removed! |
1205 $value = trim($value, " \r\n\t"); // do not trim nulls from $value!! Unicode characters will get mangled if trailing nulls are removed! |
1182 } |
1206 } |
1183 if ($value) { |
1207 if ($value) { |
1184 $this->info['tags'][trim($tag_name)][trim($tag_key)][] = $value; |
1208 if (!is_numeric($key)) { |
|
1209 $this->info['tags'][trim($tag_name)][trim($tag_key)][$key] = $value; |
|
1210 } else { |
|
1211 $this->info['tags'][trim($tag_name)][trim($tag_key)][] = $value; |
|
1212 } |
1185 } |
1213 } |
1186 } |
1214 } |
1187 if ($tag_key == 'picture') { |
1215 if ($tag_key == 'picture') { |
1188 unset($this->info[$comment_name]['comments'][$tag_key]); |
1216 unset($this->info[$comment_name]['comments'][$tag_key]); |
1189 } |
1217 } |
1194 continue; |
1222 continue; |
1195 } |
1223 } |
1196 |
1224 |
1197 if ($this->option_tags_html) { |
1225 if ($this->option_tags_html) { |
1198 foreach ($this->info['tags'][$tag_name] as $tag_key => $valuearray) { |
1226 foreach ($this->info['tags'][$tag_name] as $tag_key => $valuearray) { |
1199 foreach ($valuearray as $key => $value) { |
1227 $this->info['tags_html'][$tag_name][$tag_key] = getid3_lib::recursiveMultiByteCharString2HTML($valuearray, $encoding); |
1200 if (is_string($value)) { |
|
1201 //$this->info['tags_html'][$tag_name][$tag_key][$key] = getid3_lib::MultiByteCharString2HTML($value, $encoding); |
|
1202 $this->info['tags_html'][$tag_name][$tag_key][$key] = str_replace('�', '', trim(getid3_lib::MultiByteCharString2HTML($value, $encoding))); |
|
1203 } else { |
|
1204 $this->info['tags_html'][$tag_name][$tag_key][$key] = $value; |
|
1205 } |
|
1206 } |
|
1207 } |
1228 } |
1208 } |
1229 } |
1209 |
1230 |
1210 $this->CharConvert($this->info['tags'][$tag_name], $encoding); // only copy gets converted! |
1231 $this->CharConvert($this->info['tags'][$tag_name], $encoding); // only copy gets converted! |
1211 } |
1232 } |
1563 } |
1583 } |
1564 |
1584 |
1565 } |
1585 } |
1566 |
1586 |
1567 |
1587 |
1568 abstract class getid3_handler |
1588 abstract class getid3_handler { |
1569 { |
1589 |
|
1590 /** |
|
1591 * @var getID3 |
|
1592 */ |
1570 protected $getid3; // pointer |
1593 protected $getid3; // pointer |
1571 |
1594 |
1572 protected $data_string_flag = false; // analyzing filepointer or string |
1595 protected $data_string_flag = false; // analyzing filepointer or string |
1573 protected $data_string = ''; // string to analyze |
1596 protected $data_string = ''; // string to analyze |
1574 protected $data_string_position = 0; // seek position in string |
1597 protected $data_string_position = 0; // seek position in string |
1591 |
1614 |
1592 |
1615 |
1593 // Analyze from string instead |
1616 // Analyze from string instead |
1594 public function AnalyzeString($string) { |
1617 public function AnalyzeString($string) { |
1595 // Enter string mode |
1618 // Enter string mode |
1596 $this->setStringMode($string); |
1619 $this->setStringMode($string); |
1597 |
1620 |
1598 // Save info |
1621 // Save info |
1599 $saved_avdataoffset = $this->getid3->info['avdataoffset']; |
1622 $saved_avdataoffset = $this->getid3->info['avdataoffset']; |
1600 $saved_avdataend = $this->getid3->info['avdataend']; |
1623 $saved_avdataend = $this->getid3->info['avdataend']; |
1601 $saved_filesize = (isset($this->getid3->info['filesize']) ? $this->getid3->info['filesize'] : null); // may be not set if called as dependency without openfile() call |
1624 $saved_filesize = (isset($this->getid3->info['filesize']) ? $this->getid3->info['filesize'] : null); // may be not set if called as dependency without openfile() call |
1632 protected function fread($bytes) { |
1655 protected function fread($bytes) { |
1633 if ($this->data_string_flag) { |
1656 if ($this->data_string_flag) { |
1634 $this->data_string_position += $bytes; |
1657 $this->data_string_position += $bytes; |
1635 return substr($this->data_string, $this->data_string_position - $bytes, $bytes); |
1658 return substr($this->data_string, $this->data_string_position - $bytes, $bytes); |
1636 } |
1659 } |
1637 $pos = $this->ftell() + $bytes; |
1660 $pos = $this->ftell() + $bytes; |
1638 if (!getid3_lib::intValueSupported($pos)) { |
1661 if (!getid3_lib::intValueSupported($pos)) { |
1639 throw new getid3_exception('cannot fread('.$bytes.' from '.$this->ftell().') because beyond PHP filesystem limit', 10); |
1662 throw new getid3_exception('cannot fread('.$bytes.' from '.$this->ftell().') because beyond PHP filesystem limit', 10); |
1640 } |
1663 } |
1641 return fread($this->getid3->fp, $bytes); |
1664 return fread($this->getid3->fp, $bytes); |
1642 } |
1665 } |
1643 |
1666 |
1644 protected function fseek($bytes, $whence=SEEK_SET) { |
1667 protected function fseek($bytes, $whence=SEEK_SET) { |
1645 if ($this->data_string_flag) { |
1668 if ($this->data_string_flag) { |
1655 case SEEK_END: |
1678 case SEEK_END: |
1656 $this->data_string_position = $this->data_string_length + $bytes; |
1679 $this->data_string_position = $this->data_string_length + $bytes; |
1657 break; |
1680 break; |
1658 } |
1681 } |
1659 return 0; |
1682 return 0; |
1660 } else { |
1683 } else { |
1661 $pos = $bytes; |
1684 $pos = $bytes; |
1662 if ($whence == SEEK_CUR) { |
1685 if ($whence == SEEK_CUR) { |
1663 $pos = $this->ftell() + $bytes; |
1686 $pos = $this->ftell() + $bytes; |
1664 } elseif ($whence == SEEK_END) { |
1687 } elseif ($whence == SEEK_END) { |
1665 $pos = $this->info['filesize'] + $bytes; |
1688 $pos = $this->getid3->info['filesize'] + $bytes; |
1666 } |
1689 } |
1667 if (!getid3_lib::intValueSupported($pos)) { |
1690 if (!getid3_lib::intValueSupported($pos)) { |
1668 throw new getid3_exception('cannot fseek('.$pos.') because beyond PHP filesystem limit', 10); |
1691 throw new getid3_exception('cannot fseek('.$pos.') because beyond PHP filesystem limit', 10); |
1669 } |
1692 } |
1670 } |
1693 } |
1671 return fseek($this->getid3->fp, $bytes, $whence); |
1694 return fseek($this->getid3->fp, $bytes, $whence); |
1672 } |
1695 } |
1680 |
1703 |
1681 final protected function isDependencyFor($module) { |
1704 final protected function isDependencyFor($module) { |
1682 return $this->dependency_to == $module; |
1705 return $this->dependency_to == $module; |
1683 } |
1706 } |
1684 |
1707 |
1685 protected function error($text) |
1708 protected function error($text) { |
1686 { |
|
1687 $this->getid3->info['error'][] = $text; |
1709 $this->getid3->info['error'][] = $text; |
1688 |
1710 |
1689 return false; |
1711 return false; |
1690 } |
1712 } |
1691 |
1713 |
1692 protected function warning($text) |
1714 protected function warning($text) { |
1693 { |
|
1694 return $this->getid3->warning($text); |
1715 return $this->getid3->warning($text); |
1695 } |
1716 } |
1696 |
1717 |
1697 protected function notice($text) |
1718 protected function notice($text) { |
1698 { |
|
1699 // does nothing for now |
1719 // does nothing for now |
1700 } |
1720 } |
1701 |
1721 |
1702 public function saveAttachment($name, $offset, $length, $image_mime=null) { |
1722 public function saveAttachment($name, $offset, $length, $image_mime=null) { |
1703 try { |
1723 try { |