<?php
+
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
-// available at http://getid3.sourceforge.net //
-// or http://www.getid3.org //
-// also https://github.com/JamesHeinrich/getID3 //
-/////////////////////////////////////////////////////////////////
+// available at https://github.com/JamesHeinrich/getID3 //
+// or https://www.getid3.org //
+// or http://getid3.sourceforge.net //
// //
// Please see readme.txt for more information //
// ///
define('ENT_SUBSTITUTE', (defined('ENT_IGNORE') ? ENT_IGNORE : 8));
}
+/*
+https://www.getid3.org/phpBB3/viewtopic.php?t=2114
+If you are running into a the problem where filenames with special characters are being handled
+incorrectly by external helper programs (e.g. metaflac), notably with the special characters removed,
+and you are passing in the filename in UTF8 (typically via a HTML form), try uncommenting this line:
+*/
+//setlocale(LC_CTYPE, 'en_US.UTF-8');
+
// attempt to define temp dir as something flexible but reliable
$temp_dir = ini_get('upload_tmp_dir');
if ($temp_dir && (!is_dir($temp_dir) || !is_readable($temp_dir))) {
class getID3
{
- // public: Settings
- public $encoding = 'UTF-8'; // CASE SENSITIVE! - i.e. (must be supported by iconv()). Examples: ISO-8859-1 UTF-8 UTF-16 UTF-16BE
- public $encoding_id3v1 = 'ISO-8859-1'; // Should always be 'ISO-8859-1', but some tags may be written in other encodings such as 'EUC-CN' or 'CP1252'
-
- // public: Optional tag checks - disable for speed.
- public $option_tag_id3v1 = true; // Read and process ID3v1 tags
- public $option_tag_id3v2 = true; // Read and process ID3v2 tags
- public $option_tag_lyrics3 = true; // Read and process Lyrics3 tags
- public $option_tag_apetag = true; // Read and process APE tags
- public $option_tags_process = true; // Copy tags to root key 'tags' and encode to $this->encoding
- public $option_tags_html = true; // Copy tags to root key 'tags_html' properly translated from various encodings to HTML entities
-
- // public: Optional tag/comment calucations
- public $option_extra_info = true; // Calculate additional info such as bitrate, channelmode etc
-
- // public: Optional handling of embedded attachments (e.g. images)
- public $option_save_attachments = true; // defaults to true (ATTACHMENTS_INLINE) for backward compatibility
-
- // public: Optional calculations
- public $option_md5_data = false; // Get MD5 sum of data part - slow
- public $option_md5_data_source = false; // Use MD5 of source file if availble - only FLAC and OptimFROG
- public $option_sha1_data = false; // Get SHA1 sum of data part - slow
- public $option_max_2gb_check = null; // Check whether file is larger than 2GB and thus not supported by 32-bit PHP (null: auto-detect based on PHP_INT_MAX)
-
- // public: Read buffer size in bytes
+ /*
+ * Settings
+ */
+
+ /**
+ * CASE SENSITIVE! - i.e. (must be supported by iconv()). Examples: ISO-8859-1 UTF-8 UTF-16 UTF-16BE
+ *
+ * @var string
+ */
+ public $encoding = 'UTF-8';
+
+ /**
+ * Should always be 'ISO-8859-1', but some tags may be written in other encodings such as 'EUC-CN' or 'CP1252'
+ *
+ * @var string
+ */
+ public $encoding_id3v1 = 'ISO-8859-1';
+
+ /*
+ * Optional tag checks - disable for speed.
+ */
+
+ /**
+ * Read and process ID3v1 tags
+ *
+ * @var bool
+ */
+ public $option_tag_id3v1 = true;
+
+ /**
+ * Read and process ID3v2 tags
+ *
+ * @var bool
+ */
+ public $option_tag_id3v2 = true;
+
+ /**
+ * Read and process Lyrics3 tags
+ *
+ * @var bool
+ */
+ public $option_tag_lyrics3 = true;
+
+ /**
+ * Read and process APE tags
+ *
+ * @var bool
+ */
+ public $option_tag_apetag = true;
+
+ /**
+ * Copy tags to root key 'tags' and encode to $this->encoding
+ *
+ * @var bool
+ */
+ public $option_tags_process = true;
+
+ /**
+ * Copy tags to root key 'tags_html' properly translated from various encodings to HTML entities
+ *
+ * @var bool
+ */
+ public $option_tags_html = true;
+
+ /*
+ * Optional tag/comment calculations
+ */
+
+ /**
+ * Calculate additional info such as bitrate, channelmode etc
+ *
+ * @var bool
+ */
+ public $option_extra_info = true;
+
+ /*
+ * Optional handling of embedded attachments (e.g. images)
+ */
+
+ /**
+ * Defaults to true (ATTACHMENTS_INLINE) for backward compatibility
+ *
+ * @var bool|string
+ */
+ public $option_save_attachments = true;
+
+ /*
+ * Optional calculations
+ */
+
+ /**
+ * Get MD5 sum of data part - slow
+ *
+ * @var bool
+ */
+ public $option_md5_data = false;
+
+ /**
+ * Use MD5 of source file if availble - only FLAC and OptimFROG
+ *
+ * @var bool
+ */
+ public $option_md5_data_source = false;
+
+ /**
+ * Get SHA1 sum of data part - slow
+ *
+ * @var bool
+ */
+ public $option_sha1_data = false;
+
+ /**
+ * Check whether file is larger than 2GB and thus not supported by 32-bit PHP (null: auto-detect based on
+ * PHP_INT_MAX)
+ *
+ * @var bool|null
+ */
+ public $option_max_2gb_check;
+
+ /**
+ * Read buffer size in bytes
+ *
+ * @var int
+ */
public $option_fread_buffer_size = 32768;
// Public variables
- public $filename; // Filename of file being analysed.
- public $fp; // Filepointer to file being analysed.
- public $info; // Result array.
+
+ /**
+ * Filename of file being analysed.
+ *
+ * @var string
+ */
+ public $filename;
+
+ /**
+ * Filepointer to file being analysed.
+ *
+ * @var resource
+ */
+ public $fp;
+
+ /**
+ * Result array.
+ *
+ * @var array
+ */
+ public $info;
+
+ /**
+ * @var string
+ */
public $tempdir = GETID3_TEMP_DIR;
+
+ /**
+ * @var int
+ */
public $memory_limit = 0;
- // Protected variables
+ /**
+ * @var string
+ */
protected $startup_error = '';
+
+ /**
+ * @var string
+ */
protected $startup_warning = '';
- const VERSION = '1.9.14-201703261440';
+ const VERSION = '1.9.16-201810171314';
const FREAD_BUFFER_SIZE = 32768;
const ATTACHMENTS_NONE = false;
const ATTACHMENTS_INLINE = true;
- // public: constructor
public function __construct() {
// Check for PHP version
$required_php_version = '5.3.0';
if (version_compare(PHP_VERSION, $required_php_version, '<')) {
$this->startup_error .= 'getID3() requires PHP v'.$required_php_version.' or higher - you are running v'.PHP_VERSION."\n";
- return false;
+ return;
}
// Check memory
$this->memory_limit = ini_get('memory_limit');
- if (preg_match('#([0-9]+)M#i', $this->memory_limit, $matches)) {
+ if (preg_match('#([0-9]+) ?M#i', $this->memory_limit, $matches)) {
// could be stored as "16M" rather than 16777216 for example
$this->memory_limit = $matches[1] * 1048576;
- } elseif (preg_match('#([0-9]+)G#i', $this->memory_limit, $matches)) { // The 'G' modifier is available since PHP 5.1.0
+ } elseif (preg_match('#([0-9]+) ?G#i', $this->memory_limit, $matches)) { // The 'G' modifier is available since PHP 5.1.0
// could be stored as "2G" rather than 2147483648 for example
$this->memory_limit = $matches[1] * 1073741824;
}
echo $this->startup_error;
throw new getid3_exception($this->startup_error);
}
-
- return true;
}
+ /**
+ * @return string
+ */
public function version() {
return self::VERSION;
}
+ /**
+ * @return int
+ */
public function fread_buffer_size() {
return $this->option_fread_buffer_size;
}
-
- // public: setOption
+ /**
+ * @param array $optArray
+ *
+ * @return bool
+ */
public function setOption($optArray) {
if (!is_array($optArray) || empty($optArray)) {
return false;
return true;
}
-
+ /**
+ * @param string $filename
+ * @param int $filesize
+ *
+ * @return bool
+ *
+ * @throws getid3_exception
+ */
public function openfile($filename, $filesize=null) {
try {
if (!empty($this->startup_error)) {
}
$filename = str_replace('/', DIRECTORY_SEPARATOR, $filename);
- $filename = preg_replace('#(.+)'.preg_quote(DIRECTORY_SEPARATOR).'{2,}#U', '\1'.DIRECTORY_SEPARATOR, $filename);
+ //$filename = preg_replace('#(?<!gs:)('.preg_quote(DIRECTORY_SEPARATOR).'{2,})#', DIRECTORY_SEPARATOR, $filename);
// open local file
- //if (is_readable($filename) && is_file($filename) && ($this->fp = fopen($filename, 'rb'))) { // see http://www.getid3.org/phpBB3/viewtopic.php?t=1720
+ //if (is_readable($filename) && is_file($filename) && ($this->fp = fopen($filename, 'rb'))) { // see https://www.getid3.org/phpBB3/viewtopic.php?t=1720
if ((is_readable($filename) || file_exists($filename)) && is_file($filename) && ($this->fp = fopen($filename, 'rb'))) {
// great
} else {
} elseif (getid3_lib::intValueSupported($real_filesize)) {
unset($this->info['filesize']);
fclose($this->fp);
- 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');
+ 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 / 1073741824, 3).'GB, please report to info@getid3.org');
}
$this->info['filesize'] = $real_filesize;
- $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.');
+ $this->warning('File is larger than '.round(PHP_INT_MAX / 1073741824).'GB (filesystem reports it as '.number_format($real_filesize / 1073741824, 3).'GB) and is not properly supported by PHP.');
}
}
return false;
}
- // public: analyze file
+ /**
+ * analyze file
+ *
+ * @param string $filename
+ * @param int $filesize
+ * @param string $original_filename
+ *
+ * @return array
+ */
public function analyze($filename, $filesize=null, $original_filename='') {
try {
if (!$this->openfile($filename, $filesize)) {
}
- // private: error handling
+ /**
+ * Error handling.
+ *
+ * @param string $message
+ *
+ * @return array
+ */
public function error($message) {
$this->CleanUp();
if (!isset($this->info['error'])) {
}
- // private: warning handling
+ /**
+ * Warning handling.
+ *
+ * @param string $message
+ *
+ * @return bool
+ */
public function warning($message) {
$this->info['warning'][] = $message;
return true;
}
- // private: CleanUp
+ /**
+ * @return bool
+ */
private function CleanUp() {
// remove possible empty keys
return true;
}
-
- // return array containing information about all supported formats
+ /**
+ * Return array containing information about all supported formats.
+ *
+ * @return array
+ */
public function GetFileFormatArray() {
static $format_info = array();
if (empty($format_info)) {
'pattern' => '^ADIF',
'group' => 'audio',
'module' => 'aac',
- 'mime_type' => 'application/octet-stream',
+ 'mime_type' => 'audio/aac',
'fail_ape' => 'WARNING',
),
'pattern' => '^\\xFF[\\xF0-\\xF1\\xF8-\\xF9]',
'group' => 'audio',
'module' => 'aac',
- 'mime_type' => 'application/octet-stream',
+ 'mime_type' => 'audio/aac',
'fail_ape' => 'WARNING',
),
'pattern' => '^fLaC',
'group' => 'audio',
'module' => 'flac',
- 'mime_type' => 'audio/x-flac',
+ 'mime_type' => 'audio/flac',
),
// LA - audio - Lossless Audio (LA)
'pattern' => '^MAC ',
'group' => 'audio',
'module' => 'monkey',
- 'mime_type' => 'application/octet-stream',
+ 'mime_type' => 'audio/x-monkeys-audio',
),
// has been known to produce false matches in random files (e.g. JPEGs), leave out until more precise matching available
'pattern' => '^(RIFF|SDSS|FORM)',
'group' => 'audio-video',
'module' => 'riff',
- 'mime_type' => 'audio/x-wav',
+ 'mime_type' => 'audio/wav',
'fail_ape' => 'WARNING',
),
'pattern' => '^\\x1F\\x8B\\x08',
'group' => 'archive',
'module' => 'gzip',
- 'mime_type' => 'application/x-gzip',
+ 'mime_type' => 'application/gzip',
'fail_id3' => 'ERROR',
'fail_ape' => 'ERROR',
),
return $format_info;
}
-
-
+ /**
+ * @param string $filedata
+ * @param string $filename
+ *
+ * @return mixed|false
+ */
public function GetFileFormat(&$filedata, $filename='') {
// this function will determine the format of a file based on usually
// the first 2-4 bytes of the file (8 bytes for PNG, 16 bytes for JPG,
return false;
}
-
- // converts array to $encoding charset from $this->encoding
+ /**
+ * Converts array to $encoding charset from $this->encoding.
+ *
+ * @param array $array
+ * @param string $encoding
+ */
public function CharConvert(&$array, $encoding) {
// identical encoding - end here
}
}
-
+ /**
+ * @return bool
+ */
public function HandleAllTags() {
// key name => array (tag name, character encoding)
return true;
}
+ /**
+ * @param string $algorithm
+ *
+ * @return array|bool
+ */
public function getHashdata($algorithm) {
switch ($algorithm) {
case 'md5':
} else {
- $commandline = 'vorbiscomment -w -c "'.$empty.'" "'.$file.'" "'.$temp.'" 2>&1';
$commandline = 'vorbiscomment -w -c '.escapeshellarg($empty).' '.escapeshellarg($file).' '.escapeshellarg($temp).' 2>&1';
$VorbisCommentError = `$commandline`;
return true;
}
-
public function ChannelsBitratePlaytimeCalculations() {
// set channelmode on audio
}
}
-
+ /**
+ * @return bool
+ */
public function CalculateCompressionRatioVideo() {
if (empty($this->info['video'])) {
return false;
return true;
}
-
+ /**
+ * @return bool
+ */
public function CalculateCompressionRatioAudio() {
if (empty($this->info['audio']['bitrate']) || empty($this->info['audio']['channels']) || empty($this->info['audio']['sample_rate']) || !is_numeric($this->info['audio']['sample_rate'])) {
return false;
return true;
}
-
+ /**
+ * @return bool
+ */
public function CalculateReplayGain() {
if (isset($this->info['replay_gain'])) {
if (!isset($this->info['replay_gain']['reference_volume'])) {
- $this->info['replay_gain']['reference_volume'] = (double) 89.0;
+ $this->info['replay_gain']['reference_volume'] = 89.0;
}
if (isset($this->info['replay_gain']['track']['adjustment'])) {
$this->info['replay_gain']['track']['volume'] = $this->info['replay_gain']['reference_volume'] - $this->info['replay_gain']['track']['adjustment'];
return true;
}
+ /**
+ * @return bool
+ */
public function ProcessAudioStreams() {
if (!empty($this->info['audio']['bitrate']) || !empty($this->info['audio']['channels']) || !empty($this->info['audio']['sample_rate'])) {
if (!isset($this->info['audio']['streams'])) {
return true;
}
+ /**
+ * @return string|bool
+ */
public function getid3_tempnam() {
return tempnam($this->tempdir, 'gI3');
}
+ /**
+ * @param string $name
+ *
+ * @return bool
+ *
+ * @throws getid3_exception
+ */
public function include_module($name) {
//if (!file_exists($this->include_path.'module.'.$name.'.php')) {
if (!file_exists(GETID3_INCLUDEPATH.'module.'.$name.'.php')) {
return true;
}
+ /**
+ * @param string $filename
+ *
+ * @return bool
+ */
+ public static function is_writable ($filename) {
+ $ret = is_writable($filename);
+
+ if (!$ret) {
+ $perms = fileperms($filename);
+ $ret = ($perms & 0x0080) || ($perms & 0x0010) || ($perms & 0x0002);
+ }
+
+ return $ret;
+ }
+
}
-abstract class getid3_handler {
+abstract class getid3_handler
+{
/**
* @var getID3
*/
protected $getid3; // pointer
- protected $data_string_flag = false; // analyzing filepointer or string
- protected $data_string = ''; // string to analyze
- protected $data_string_position = 0; // seek position in string
- protected $data_string_length = 0; // string length
+ /**
+ * Analyzing filepointer or string.
+ *
+ * @var bool
+ */
+ protected $data_string_flag = false;
- private $dependency_to = null;
+ /**
+ * String to analyze.
+ *
+ * @var string
+ */
+ protected $data_string = '';
+ /**
+ * Seek position in string.
+ *
+ * @var int
+ */
+ protected $data_string_position = 0;
+ /**
+ * String length.
+ *
+ * @var int
+ */
+ protected $data_string_length = 0;
+
+ /**
+ * @var string
+ */
+ private $dependency_to;
+
+ /**
+ * getid3_handler constructor.
+ *
+ * @param getID3 $getid3
+ * @param string $call_module
+ */
public function __construct(getID3 $getid3, $call_module=null) {
$this->getid3 = $getid3;
}
}
-
- // Analyze from file pointer
+ /**
+ * Analyze from file pointer.
+ *
+ * @return bool
+ */
abstract public function Analyze();
-
- // Analyze from string instead
+ /**
+ * Analyze from string instead.
+ *
+ * @param string $string
+ */
public function AnalyzeString($string) {
// Enter string mode
$this->setStringMode($string);
$this->data_string_flag = false;
}
+ /**
+ * @param string $string
+ */
public function setStringMode($string) {
$this->data_string_flag = true;
$this->data_string = $string;
$this->data_string_length = strlen($string);
}
+ /**
+ * @return int|bool
+ */
protected function ftell() {
if ($this->data_string_flag) {
return $this->data_string_position;
return ftell($this->getid3->fp);
}
+ /**
+ * @param int $bytes
+ *
+ * @return string|false
+ *
+ * @throws getid3_exception
+ */
protected function fread($bytes) {
if ($this->data_string_flag) {
$this->data_string_position += $bytes;
//return fread($this->getid3->fp, $bytes);
/*
- * http://www.getid3.org/phpBB3/viewtopic.php?t=1930
+ * https://www.getid3.org/phpBB3/viewtopic.php?t=1930
* "I found out that the root cause for the problem was how getID3 uses the PHP system function fread().
* It seems to assume that fread() would always return as many bytes as were requested.
* However, according the PHP manual (http://php.net/manual/en/function.fread.php), this is the case only with regular local files, but not e.g. with Linux pipes.
*/
$contents = '';
do {
+ if (($this->getid3->memory_limit > 0) && ($bytes > $this->getid3->memory_limit)) {
+ throw new getid3_exception('cannot fread('.$bytes.' from '.$this->ftell().') that is more than available PHP memory ('.$this->getid3->memory_limit.')', 10);
+ }
$part = fread($this->getid3->fp, $bytes);
$partLength = strlen($part);
$bytes -= $partLength;
return $contents;
}
+ /**
+ * @param int $bytes
+ * @param int $whence
+ *
+ * @return int
+ *
+ * @throws getid3_exception
+ */
protected function fseek($bytes, $whence=SEEK_SET) {
if ($this->data_string_flag) {
switch ($whence) {
return fseek($this->getid3->fp, $bytes, $whence);
}
+ /**
+ * @return bool
+ */
protected function feof() {
if ($this->data_string_flag) {
return $this->data_string_position >= $this->data_string_length;
return feof($this->getid3->fp);
}
+ /**
+ * @param string $module
+ *
+ * @return bool
+ */
final protected function isDependencyFor($module) {
return $this->dependency_to == $module;
}
+ /**
+ * @param string $text
+ *
+ * @return bool
+ */
protected function error($text) {
$this->getid3->info['error'][] = $text;
return false;
}
+ /**
+ * @param string $text
+ *
+ * @return bool
+ */
protected function warning($text) {
return $this->getid3->warning($text);
}
+ /**
+ * @param string $text
+ */
protected function notice($text) {
// does nothing for now
}
+ /**
+ * @param string $name
+ * @param int $offset
+ * @param int $length
+ * @param string $image_mime
+ *
+ * @return string|null
+ *
+ * @throws Exception
+ * @throws getid3_exception
+ */
public function saveAttachment($name, $offset, $length, $image_mime=null) {
try {
// set up destination path
$dir = rtrim(str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $this->getid3->option_save_attachments), DIRECTORY_SEPARATOR);
- if (!is_dir($dir) || !is_writable($dir)) { // check supplied directory
+ if (!is_dir($dir) || !getID3::is_writable($dir)) { // check supplied directory
throw new Exception('supplied path ('.$dir.') does not exist, or is not writable');
}
$dest = $dir.DIRECTORY_SEPARATOR.$name.($image_mime ? '.'.getid3_lib::ImageExtFromMime($image_mime) : '');
// close and remove dest file if created
if (isset($fp_dest) && is_resource($fp_dest)) {
fclose($fp_dest);
+ }
+
+ if (isset($dest) && file_exists($dest)) {
unlink($dest);
}