diff -r 3d4e9c994f10 -r a86126ab1dd4 wp/wp-includes/ID3/getid3.php --- a/wp/wp-includes/ID3/getid3.php Tue Oct 22 16:11:46 2019 +0200 +++ b/wp/wp-includes/ID3/getid3.php Tue Dec 15 13:49:49 2020 +0100 @@ -1,10 +1,9 @@ // -// 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 // // /// @@ -26,6 +25,14 @@ 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))) { @@ -74,62 +81,208 @@ 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' + /* + * 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'; + + /** + * ID3v1 should always be 'ISO-8859-1', but some tags may be written in other encodings such as 'Windows-1251' or 'KOI8-R'. If true attempt to detect these encodings, but may return incorrect values for some tags actually in ISO-8859-1 encoding + * + * @var bool + */ + public $encoding_id3v1_autodetect = false; + + /* + * Optional tag checks - disable for speed. + */ - // 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 + /** + * 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; - // public: Optional tag/comment calucations - public $option_extra_info = true; // Calculate additional info such as bitrate, channelmode etc + /** + * 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 + */ - // public: Optional handling of embedded attachments (e.g. images) - public $option_save_attachments = true; // defaults to true (ATTACHMENTS_INLINE) for backward compatibility + /** + * 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 + */ - // 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) + /** + * 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; - // public: Read buffer size in bytes + /** + * 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-201706111222'; + const VERSION = '1.9.20-202006061653'; 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; + } + // Check memory - $this->memory_limit = ini_get('memory_limit'); - if (preg_match('#([0-9]+) ?M#i', $this->memory_limit, $matches)) { + $memoryLimit = ini_get('memory_limit'); + if (preg_match('#([0-9]+) ?M#i', $memoryLimit, $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 + $memoryLimit = $matches[1] * 1048576; + } elseif (preg_match('#([0-9]+) ?G#i', $memoryLimit, $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; + $memoryLimit = $matches[1] * 1073741824; } + $this->memory_limit = $memoryLimit; + if ($this->memory_limit <= 0) { // memory limits probably disabled } elseif ($this->memory_limit <= 4194304) { @@ -139,28 +292,34 @@ } // Check safe_mode off - if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) { + if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) { // phpcs:ignore PHPCompatibility.IniDirectives.RemovedIniDirectives.safe_modeDeprecatedRemoved $this->warning('WARNING: Safe mode is on, shorten support disabled, md5data/sha1data for ogg vorbis disabled, ogg vorbos/flac tag writing disabled.'); } - if (($mbstring_func_overload = ini_get('mbstring.func_overload')) && ($mbstring_func_overload & 0x02)) { + // phpcs:ignore PHPCompatibility.IniDirectives.RemovedIniDirectives.mbstring_func_overloadDeprecated + if (($mbstring_func_overload = (int) ini_get('mbstring.func_overload')) && ($mbstring_func_overload & 0x02)) { // http://php.net/manual/en/mbstring.overload.php // "mbstring.func_overload in php.ini is a positive value that represents a combination of bitmasks specifying the categories of functions to be overloaded. It should be set to 1 to overload the mail() function. 2 for string functions, 4 for regular expression functions" // getID3 cannot run when string functions are overloaded. It doesn't matter if mail() or ereg* functions are overloaded since getID3 does not use those. + // phpcs:ignore PHPCompatibility.IniDirectives.RemovedIniDirectives.mbstring_func_overloadDeprecated $this->startup_error .= 'WARNING: php.ini contains "mbstring.func_overload = '.ini_get('mbstring.func_overload').'", getID3 cannot run with this setting (bitmask 2 (string functions) cannot be set). Recommended to disable entirely.'."\n"; } - // Check for magic_quotes_runtime - if (function_exists('get_magic_quotes_runtime')) { - if (get_magic_quotes_runtime()) { - $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).'."\n"; + // check for magic quotes in PHP < 7.4.0 (when these functions became deprecated) + if (version_compare(PHP_VERSION, '7.4.0', '<')) { + // Check for magic_quotes_runtime + if (function_exists('get_magic_quotes_runtime')) { + // phpcs:ignore PHPCompatibility.FunctionUse.RemovedFunctions.get_magic_quotes_runtimeDeprecated + if (get_magic_quotes_runtime()) { + $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).'."\n"; + } } - } - - // Check for magic_quotes_gpc - if (function_exists('magic_quotes_gpc')) { - if (get_magic_quotes_gpc()) { - $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).'."\n"; + // Check for magic_quotes_gpc + if (function_exists('get_magic_quotes_gpc')) { + // phpcs:ignore PHPCompatibility.FunctionUse.RemovedFunctions.get_magic_quotes_gpcDeprecated + if (get_magic_quotes_gpc()) { + $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).'."\n"; + } } } @@ -176,7 +335,7 @@ // Needed for Windows only: // Define locations of helper applications for Shorten, VorbisComment, MetaFLAC - // as well as other helper functions such as head, tail, md5sum, etc + // as well as other helper functions such as head, etc // This path cannot contain spaces, but the below code will attempt to get the // 8.3-equivalent path automatically // IMPORTANT: This path must include the trailing slash @@ -219,20 +378,27 @@ 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; @@ -246,8 +412,16 @@ return true; } - - public function openfile($filename, $filesize=null) { + /** + * @param string $filename + * @param int $filesize + * @param resource $fp + * + * @return bool + * + * @throws getid3_exception + */ + public function openfile($filename, $filesize=null, $fp=null) { try { if (!empty($this->startup_error)) { throw new getid3_exception($this->startup_error); @@ -270,11 +444,13 @@ } $filename = str_replace('/', DIRECTORY_SEPARATOR, $filename); - $filename = preg_replace('#(?fp = fopen($filename, 'rb'))) { // see http://www.getid3.org/phpBB3/viewtopic.php?t=1720 - if ((is_readable($filename) || file_exists($filename)) && is_file($filename) && ($this->fp = fopen($filename, 'rb'))) { + //if (is_readable($filename) && is_file($filename) && ($this->fp = fopen($filename, 'rb'))) { // see https://www.getid3.org/phpBB3/viewtopic.php?t=1720 + if (($fp != null) && ((get_resource_type($fp) == 'file') || (get_resource_type($fp) == 'stream'))) { + $this->fp = $fp; + } elseif ((is_readable($filename) || file_exists($filename)) && is_file($filename) && ($this->fp = fopen($filename, 'rb'))) { // great } else { $errormessagelist = array(); @@ -331,10 +507,10 @@ } 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.'); } } @@ -346,10 +522,19 @@ return false; } - // public: analyze file - public function analyze($filename, $filesize=null, $original_filename='') { + /** + * analyze file + * + * @param string $filename + * @param int $filesize + * @param string $original_filename + * @param resource $fp + * + * @return array + */ + public function analyze($filename, $filesize=null, $original_filename='', $fp=null) { try { - if (!$this->openfile($filename, $filesize)) { + if (!$this->openfile($filename, $filesize, $fp)) { return $this->info; } @@ -383,8 +568,8 @@ $header = fread($this->fp, 10); if ((substr($header, 0, 3) == 'ID3') && (strlen($header) == 10)) { $this->info['id3v2']['header'] = true; - $this->info['id3v2']['majorversion'] = ord($header{3}); - $this->info['id3v2']['minorversion'] = ord($header{4}); + $this->info['id3v2']['majorversion'] = ord($header[3]); + $this->info['id3v2']['minorversion'] = ord($header[4]); $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 } } @@ -497,7 +682,13 @@ } - // private: error handling + /** + * Error handling. + * + * @param string $message + * + * @return array + */ public function error($message) { $this->CleanUp(); if (!isset($this->info['error'])) { @@ -508,14 +699,22 @@ } - // 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 @@ -562,8 +761,11 @@ 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)) { @@ -584,7 +786,7 @@ 'pattern' => '^ADIF', 'group' => 'audio', 'module' => 'aac', - 'mime_type' => 'application/octet-stream', + 'mime_type' => 'audio/aac', 'fail_ape' => 'WARNING', ), @@ -602,7 +804,7 @@ 'pattern' => '^\\xFF[\\xF0-\\xF1\\xF8-\\xF9]', 'group' => 'audio', 'module' => 'aac', - 'mime_type' => 'application/octet-stream', + 'mime_type' => 'audio/aac', 'fail_ape' => 'WARNING', ), @@ -649,12 +851,20 @@ // DSS - audio - Digital Speech Standard 'dss' => array( - 'pattern' => '^[\\x02-\\x06]ds[s2]', + 'pattern' => '^[\\x02-\\x08]ds[s2]', 'group' => 'audio', 'module' => 'dss', 'mime_type' => 'application/octet-stream', ), + // DSDIFF - audio - Direct Stream Digital Interchange File Format + 'dsdiff' => array( + 'pattern' => '^FRM8', + 'group' => 'audio', + 'module' => 'dsdiff', + 'mime_type' => 'audio/dsd', + ), + // DTS - audio - Dolby Theatre System 'dts' => array( 'pattern' => '^\\x7F\\xFE\\x80\\x01', @@ -668,7 +878,7 @@ 'pattern' => '^fLaC', 'group' => 'audio', 'module' => 'flac', - 'mime_type' => 'audio/x-flac', + 'mime_type' => 'audio/flac', ), // LA - audio - Lossless Audio (LA) @@ -700,7 +910,7 @@ '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 @@ -782,6 +992,14 @@ 'fail_ape' => 'ERROR', ), + // TAK - audio - Tom's lossless Audio Kompressor + 'tak' => array( + 'pattern' => '^tBaK', + 'group' => 'audio', + 'module' => 'tak', + 'mime_type' => 'application/octet-stream', + ), + // TTA - audio - TTA Lossless Audio Compressor (http://tta.corecodec.org) 'tta' => array( 'pattern' => '^TTA', // could also be '^TTA(\\x01|\\x02|\\x03|2|1)' @@ -842,6 +1060,14 @@ 'mime_type' => 'video/x-flv', ), + // IVF - audio/video - IVF + 'ivf' => array( + 'pattern' => '^DKIF', + 'group' => 'audio-video', + 'module' => 'ivf', + 'mime_type' => 'video/x-ivf', + ), + // MKAV - audio/video - Mastroka 'matroska' => array( 'pattern' => '^\\x1A\\x45\\xDF\\xA3', @@ -889,7 +1115,7 @@ 'pattern' => '^(RIFF|SDSS|FORM)', 'group' => 'audio-video', 'module' => 'riff', - 'mime_type' => 'audio/x-wav', + 'mime_type' => 'audio/wav', 'fail_ape' => 'WARNING', ), @@ -917,6 +1143,14 @@ 'mime_type' => 'video/MP2T', ), + // WTV - audio/video - Windows Recorded TV Show + 'wtv' => array( + 'pattern' => '^\\xB7\\xD8\\x00\\x20\\x37\\x49\\xDA\\x11\\xA6\\x4E\\x00\\x07\\xE9\\x5E\\xAD\\x8D', + 'group' => 'audio-video', + 'module' => 'wtv', + 'mime_type' => 'video/x-ms-wtv', + ), + // Still-Image formats @@ -1018,12 +1252,22 @@ 'iconv_req' => false, ), + // HPK - data - HPK compressed data + 'hpk' => array( + 'pattern' => '^BPUL', + 'group' => 'archive', + 'module' => 'hpk', + 'mime_type' => 'application/octet-stream', + 'fail_id3' => 'ERROR', + 'fail_ape' => 'ERROR', + ), + // RAR - data - RAR compressed data 'rar' => array( 'pattern' => '^Rar\\!', 'group' => 'archive', 'module' => 'rar', - 'mime_type' => 'application/octet-stream', + 'mime_type' => 'application/vnd.rar', 'fail_id3' => 'ERROR', 'fail_ape' => 'ERROR', ), @@ -1053,7 +1297,7 @@ 'pattern' => '^\\x1F\\x8B\\x08', 'group' => 'archive', 'module' => 'gzip', - 'mime_type' => 'application/x-gzip', + 'mime_type' => 'application/gzip', 'fail_id3' => 'ERROR', 'fail_ape' => 'ERROR', ), @@ -1068,6 +1312,16 @@ 'fail_ape' => 'ERROR', ), + // XZ - data - XZ compressed data + 'xz' => array( + 'pattern' => '^\\xFD7zXZ\\x00', + 'group' => 'archive', + 'module' => 'xz', + 'mime_type' => 'application/x-xz', + 'fail_id3' => 'ERROR', + 'fail_ape' => 'ERROR', + ), + // Misc other formats @@ -1115,8 +1369,12 @@ 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, @@ -1135,7 +1393,7 @@ if (preg_match('#\\.mp[123a]$#i', $filename)) { - // Too many mp3 encoders on the market put gabage in front of mpeg files + // Too many mp3 encoders on the market put garbage in front of mpeg files // use assume format on these if format detection failed $GetFileFormatArray = $this->GetFileFormatArray(); $info = $GetFileFormatArray['mp3']; @@ -1154,8 +1412,12 @@ 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 @@ -1178,7 +1440,9 @@ } } - + /** + * @return bool + */ public function HandleAllTags() { // key name => array (tag name, character encoding) @@ -1205,6 +1469,7 @@ 'flac' => array('vorbiscomment' , 'UTF-8'), 'divxtag' => array('divx' , 'ISO-8859-1'), 'iptc' => array('iptc' , 'ISO-8859-1'), + 'dsdiff' => array('dsdiff' , 'ISO-8859-1'), ); } @@ -1233,6 +1498,7 @@ } } if ($tag_key == 'picture') { + // pictures can take up a lot of space, and we don't need multiple copies of them; let there be a single copy in [comments][picture], and not elsewhere unset($this->info[$comment_name]['comments'][$tag_key]); } } @@ -1246,6 +1512,11 @@ if ($this->option_tags_html) { foreach ($this->info['tags'][$tag_name] as $tag_key => $valuearray) { + if ($tag_key == 'picture') { + // Do not to try to convert binary picture data to HTML + // https://github.com/JamesHeinrich/getID3/issues/178 + continue; + } $this->info['tags_html'][$tag_name][$tag_key] = getid3_lib::recursiveMultiByteCharString2HTML($valuearray, $this->info[$comment_name]['encoding']); } } @@ -1254,8 +1525,7 @@ } - // pictures can take up a lot of space, and we don't need multiple copies of them - // let there be a single copy in [comments][picture], and not elsewhere + // pictures can take up a lot of space, and we don't need multiple copies of them; let there be a single copy in [comments][picture], and not elsewhere if (!empty($this->info['tags'])) { $unset_keys = array('tags', 'tags_html'); foreach ($this->info['tags'] as $tagtype => $tagarray) { @@ -1301,6 +1571,22 @@ return true; } + /** + * Calls getid3_lib::CopyTagsToComments() but passes in the option_tags_html setting from this instance of getID3 + * + * @param array $ThisFileInfo + * + * @return bool + */ + public function CopyTagsToComments(&$ThisFileInfo) { + return getid3_lib::CopyTagsToComments($ThisFileInfo, $this->option_tags_html); + } + + /** + * @param string $algorithm + * + * @return array|bool + */ public function getHashdata($algorithm) { switch ($algorithm) { case 'md5': @@ -1309,7 +1595,6 @@ default: return $this->error('bad algorithm "'.$algorithm.'" in getHashdata()'); - break; } if (!empty($this->info['fileformat']) && !empty($this->info['dataformat']) && ($this->info['fileformat'] == 'ogg') && ($this->info['audio']['dataformat'] == 'vorbis')) { @@ -1332,6 +1617,7 @@ // page sequence numbers likely happens for OggSpeex and OggFLAC as well, but // currently vorbiscomment only works on OggVorbis files. + // phpcs:ignore PHPCompatibility.IniDirectives.RemovedIniDirectives.safe_modeDeprecatedRemoved if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) { $this->warning('Failed making system call to vorbiscomment.exe - '.$algorithm.'_data is incorrect - error returned: PHP running in Safe Mode (backtick operator not available)'); @@ -1365,7 +1651,6 @@ } else { - $commandline = 'vorbiscomment -w -c "'.$empty.'" "'.$file.'" "'.$temp.'" 2>&1'; $commandline = 'vorbiscomment -w -c '.escapeshellarg($empty).' '.escapeshellarg($file).' '.escapeshellarg($temp).' 2>&1'; $VorbisCommentError = `$commandline`; @@ -1424,7 +1709,6 @@ return true; } - public function ChannelsBitratePlaytimeCalculations() { // set channelmode on audio @@ -1489,7 +1773,9 @@ } } - + /** + * @return bool + */ public function CalculateCompressionRatioVideo() { if (empty($this->info['video'])) { return false; @@ -1537,7 +1823,9 @@ 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; @@ -1554,11 +1842,13 @@ 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']; @@ -1577,6 +1867,9 @@ 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'])) { @@ -1590,10 +1883,20 @@ 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')) { @@ -1603,35 +1906,70 @@ return true; } - public static function is_writable ($filename) { - $ret = is_writable($filename); - - if (!$ret) { - $perms = fileperms($filename); - $ret = ($perms & 0x0080) || ($perms & 0x0010) || ($perms & 0x0002); - } - - return $ret; - } + /** + * @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; + + /** + * String to analyze. + * + * @var string + */ + protected $data_string = ''; - private $dependency_to = null; + /** + * 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; @@ -1640,12 +1978,18 @@ } } - - // 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); @@ -1671,12 +2015,18 @@ $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; @@ -1684,6 +2034,13 @@ 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; @@ -1696,7 +2053,7 @@ //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. @@ -1704,6 +2061,10 @@ */ $contents = ''; do { + //if (($this->getid3->memory_limit > 0) && ($bytes > $this->getid3->memory_limit)) { + if (($this->getid3->memory_limit > 0) && (($bytes / $this->getid3->memory_limit) > 0.99)) { // enable a more-fuzzy match to prevent close misses generating errors like "PHP Fatal error: Allowed memory size of 33554432 bytes exhausted (tried to allocate 33554464 bytes)" + 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; @@ -1712,6 +2073,14 @@ 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) { @@ -1742,6 +2111,64 @@ return fseek($this->getid3->fp, $bytes, $whence); } + /** + * @return string|false + * + * @throws getid3_exception + */ + protected function fgets() { + // must be able to handle CR/LF/CRLF but not read more than one lineend + $buffer = ''; // final string we will return + $prevchar = ''; // save previously-read character for end-of-line checking + if ($this->data_string_flag) { + while (true) { + $thischar = substr($this->data_string, $this->data_string_position++, 1); + if (($prevchar == "\r") && ($thischar != "\n")) { + // read one byte too many, back up + $this->data_string_position--; + break; + } + $buffer .= $thischar; + if ($thischar == "\n") { + break; + } + if ($this->data_string_position >= $this->data_string_length) { + // EOF + break; + } + $prevchar = $thischar; + } + + } else { + + // Ideally we would just use PHP's fgets() function, however... + // it does not behave consistently with regards to mixed line endings, may be system-dependent + // and breaks entirely when given a file with mixed \r vs \n vs \r\n line endings (e.g. some PDFs) + //return fgets($this->getid3->fp); + while (true) { + $thischar = fgetc($this->getid3->fp); + if (($prevchar == "\r") && ($thischar != "\n")) { + // read one byte too many, back up + fseek($this->getid3->fp, -1, SEEK_CUR); + break; + } + $buffer .= $thischar; + if ($thischar == "\n") { + break; + } + if (feof($this->getid3->fp)) { + break; + } + $prevchar = $thischar; + } + + } + return $buffer; + } + + /** + * @return bool + */ protected function feof() { if ($this->data_string_flag) { return $this->data_string_position >= $this->data_string_length; @@ -1749,24 +2176,53 @@ 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 { @@ -1820,6 +2276,9 @@ // 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); }