<?php
-
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at https://github.com/JamesHeinrich/getID3 //
*/
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.
*/
*/
protected $startup_warning = '';
- const VERSION = '1.9.16-201810171314';
+ const VERSION = '1.9.20-202006061653';
const FREAD_BUFFER_SIZE = 32768;
const ATTACHMENTS_NONE = false;
}
// 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) {
$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)) {
+ 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.
$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')) {
+ 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')) {
+ 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";
+ }
}
}
// 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
}
/**
- * @param string $filename
- * @param int $filesize
+ * @param string $filename
+ * @param int $filesize
+ * @param resource $fp
*
* @return bool
*
* @throws getid3_exception
*/
- public function openfile($filename, $filesize=null) {
+ public function openfile($filename, $filesize=null, $fp=null) {
try {
if (!empty($this->startup_error)) {
throw new getid3_exception($this->startup_error);
// open local file
//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'))) {
+ 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();
/**
* analyze file
*
- * @param string $filename
- * @param int $filesize
- * @param string $original_filename
+ * @param string $filename
+ * @param int $filesize
+ * @param string $original_filename
+ * @param resource $fp
*
* @return array
*/
- public function analyze($filename, $filesize=null, $original_filename='') {
+ 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;
}
$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
}
}
// 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',
'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)'
'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',
'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
'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',
),
'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
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'];
'flac' => array('vorbiscomment' , 'UTF-8'),
'divxtag' => array('divx' , 'ISO-8859-1'),
'iptc' => array('iptc' , 'ISO-8859-1'),
+ 'dsdiff' => array('dsdiff' , 'ISO-8859-1'),
);
}
}
}
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]);
}
}
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']);
}
}
}
- // 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) {
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
*
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')) {
*
* @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;
- }
+ public static function is_writable ($filename) {
+ $ret = is_writable($filename);
+ if (!$ret) {
+ $perms = fileperms($filename);
+ $ret = ($perms & 0x0080) || ($perms & 0x0010) || ($perms & 0x0002);
+ }
+ return $ret;
+ }
}
*/
$contents = '';
do {
- if (($this->getid3->memory_limit > 0) && ($bytes > $this->getid3->memory_limit)) {
+ //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);
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
*/