/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// 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 a constant rather than looking up every time it is needed
if (!defined('GETID3_OS_ISWINDOWS')) {
define('GETID3_OS_ISWINDOWS', (stripos(PHP_OS, 'WIN') === 0));
// Get base path of getID3() - ONCE
if (!defined('GETID3_INCLUDEPATH')) {
define('GETID3_INCLUDEPATH', dirname(__FILE__).DIRECTORY_SEPARATOR);
if (!defined('ENT_SUBSTITUTE')) { // PHP5.3 adds ENT_IGNORE, PHP5.4 adds ENT_SUBSTITUTE
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))) {
if (!$temp_dir && function_exists('sys_get_temp_dir')) { // sys_get_temp_dir added in PHP v5.2.1
// sys_get_temp_dir() may give inaccessible temp dir, e.g. with open_basedir on virtual hosts
$temp_dir = sys_get_temp_dir();
$temp_dir = @realpath($temp_dir); // see https://github.com/JamesHeinrich/getID3/pull/10
$open_basedir = ini_get('open_basedir');
// e.g. "/var/www/vhosts/getid3.org/httpdocs/:/tmp/"
$temp_dir = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $temp_dir);
$open_basedir = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $open_basedir);
if (substr($temp_dir, -1, 1) != DIRECTORY_SEPARATOR) {
$temp_dir .= DIRECTORY_SEPARATOR;
$found_valid_tempdir = false;
$open_basedirs = explode(PATH_SEPARATOR, $open_basedir);
foreach ($open_basedirs as $basedir) {
if (substr($basedir, -1, 1) != DIRECTORY_SEPARATOR) {
$basedir .= DIRECTORY_SEPARATOR;
if (strpos($temp_dir, $basedir) === 0) {
$found_valid_tempdir = true;
if (!$found_valid_tempdir) {
unset($open_basedirs, $found_valid_tempdir, $basedir);
$temp_dir = '*'; // invalid directory name should force tempnam() to use system default temp dir
// $temp_dir = '/something/else/'; // feel free to override temp dir here if it works better for your system
if (!defined('GETID3_TEMP_DIR')) {
define('GETID3_TEMP_DIR', $temp_dir);
unset($open_basedir, $temp_dir);
* CASE SENSITIVE! - i.e. (must be supported by iconv()). Examples: ISO-8859-1 UTF-8 UTF-16 UTF-16BE
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'
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
public $encoding_id3v1_autodetect = false;
* Optional tag checks - disable for speed.
* Read and process ID3v1 tags
public $option_tag_id3v1 = true;
* Read and process ID3v2 tags
public $option_tag_id3v2 = true;
* Read and process Lyrics3 tags
public $option_tag_lyrics3 = true;
* Read and process APE tags
public $option_tag_apetag = true;
* Copy tags to root key 'tags' and encode to $this->encoding
public $option_tags_process = true;
* Copy tags to root key 'tags_html' properly translated from various encodings to HTML entities
public $option_tags_html = true;
* Optional tag/comment calculations
* Calculate additional info such as bitrate, channelmode etc
public $option_extra_info = true;
* Optional handling of embedded attachments (e.g. images)
* Defaults to true (ATTACHMENTS_INLINE) for backward compatibility
public $option_save_attachments = true;
* Get MD5 sum of data part - slow
public $option_md5_data = false;
* Use MD5 of source file if available - only FLAC and OptimFROG
public $option_md5_data_source = false;
* Get SHA1 sum of data part - slow
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
public $option_max_2gb_check;
* Read buffer size in bytes
public $option_fread_buffer_size = 32768;
// module-specific options
* if true use PHP RarArchive extension, if false (non-extension parsing not yet written in getID3)
public $options_archive_rar_use_php_rar_extension = true;
* Optional file list - disable for speed.
* Decode gzipped files, if possible, and parse recursively (.tar.gz for example).
public $options_archive_gzip_parse_contents = false;
* if false only parse most basic information, much faster for some files but may be inaccurate
public $options_audio_midi_scanwholefile = true;
* Forces getID3() to scan the file byte-by-byte and log all the valid audio frame headers - extremely slow,
* unrecommended, but may provide data from otherwise-unusable files.
public $options_audio_mp3_allow_bruteforce = false;
* number of frames to scan to determine if MPEG-audio sequence is valid
* Lower this number to 5-20 for faster scanning
* Increase this number to 50+ for most accurate detection of valid VBR/CBR mpeg-audio streams
public $options_audio_mp3_mp3_valid_check_frames = 50;
* Avoid scanning all frames (break after finding ID_RIFF_HEADER and ID_CONFIG_BLOCK,
* significantly faster for very large files but other data may be missed
public $options_audio_wavpack_quick_parsing = false;
* Break out of the loop if too many frames have been scanned; only scan this
* many if meta frame does not contain useful duration.
public $options_audiovideo_flv_max_frames = 100000;
* If true, do not return information about CLUSTER chunks, since there's a lot of them
* and they're not usually useful [default: TRUE].
public $options_audiovideo_matroska_hide_clusters = true;
* True to parse the whole file, not only header [default: FALSE].
public $options_audiovideo_matroska_parse_whole_file = false;
/** audio-video.quicktime
* return all parsed data from all atoms if true, otherwise just returned parsed metadata
public $options_audiovideo_quicktime_ReturnAtomData = false;
/** audio-video.quicktime
* return all parsed data from all atoms if true, otherwise just returned parsed metadata
public $options_audiovideo_quicktime_ParseAllPossibleAtoms = false;
* return all parsed tags if true, otherwise do not return tags not parsed by getID3
public $options_audiovideo_swf_ReturnAllTagData = false;
public $options_graphic_bmp_ExtractPalette = false;
public $options_graphic_bmp_ExtractData = false;
* If data chunk is larger than this do not read it completely (getID3 only needs the first
* few dozen bytes for parsing).
public $options_graphic_png_max_data_bytes = 10000000;
* return full details of PDF Cross-Reference Table (XREF)
public $options_misc_pdf_returnXREF = false;
* Assume all .torrent files are less than 1MB and just read entire thing into memory for easy processing.
* Override this value if you need to process files larger than 1MB
public $options_misc_torrent_max_torrent_filesize = 1048576;
* Filename of file being analysed.
* Filepointer to file being analysed.
public $tempdir = GETID3_TEMP_DIR;
public $memory_limit = 0;
protected $startup_error = '';
protected $startup_warning = '';
const VERSION = '1.9.23-202310190849';
const FREAD_BUFFER_SIZE = 32768;
const ATTACHMENTS_NONE = false;
const ATTACHMENTS_INLINE = true;
* @throws getid3_exception
public function __construct() {
$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";
$memoryLimit = ini_get('memory_limit');
if (preg_match('#([0-9]+) ?M#i', $memoryLimit, $matches)) {
// could be stored as "16M" rather than 16777216 for example
$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
$memoryLimit = $matches[1] * 1073741824;
$this->memory_limit = $memoryLimit;
if ($this->memory_limit <= 0) {
// memory limits probably disabled
} elseif ($this->memory_limit <= 4194304) {
$this->startup_error .= 'PHP has less than 4MB available memory and will very likely run out. Increase memory_limit in php.ini'."\n";
} elseif ($this->memory_limit <= 12582912) {
$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'."\n";
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.');
// 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 in PHP < 5.4.0 (when these options were removed and getters always return false)
if (version_compare(PHP_VERSION, '5.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()) { // @phpstan-ignore-line
$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('get_magic_quotes_gpc')) {
// phpcs:ignore PHPCompatibility.FunctionUse.RemovedFunctions.get_magic_quotes_gpcDeprecated
if (get_magic_quotes_gpc()) { // @phpstan-ignore-line
$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";
if (!include_once(GETID3_INCLUDEPATH.'getid3.lib.php')) {
$this->startup_error .= 'getid3.lib.php is missing or corrupt'."\n";
if ($this->option_max_2gb_check === null) {
$this->option_max_2gb_check = (PHP_INT_MAX <= 2147483647);
// Needed for Windows only:
// Define locations of helper applications for Shorten, VorbisComment, MetaFLAC
// 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
if (GETID3_OS_ISWINDOWS && !defined('GETID3_HELPERAPPSDIR')) {
$helperappsdir = GETID3_INCLUDEPATH.'..'.DIRECTORY_SEPARATOR.'helperapps'; // must not have any space in this path
if (!is_dir($helperappsdir)) {
$this->startup_warning .= '"'.$helperappsdir.'" cannot be defined as GETID3_HELPERAPPSDIR because it does not exist'."\n";
} elseif (strpos(realpath($helperappsdir), ' ') !== false) {
$DirPieces = explode(DIRECTORY_SEPARATOR, realpath($helperappsdir));
foreach ($DirPieces as $key => $value) {
if (strpos($value, ' ') !== false) {
if (!empty($path_so_far)) {
$commandline = 'dir /x '.escapeshellarg(implode(DIRECTORY_SEPARATOR, $path_so_far));
$dir_listing = `$commandline`;
$lines = explode("\n", $dir_listing);
foreach ($lines as $line) {
if (preg_match('#^([0-9/]{10}) +([0-9:]{4,5}( [AP]M)?) +(<DIR>|[0-9,]+) +([^ ]{0,11}) +(.+)$#', $line, $matches)) {
list($dummy, $date, $time, $ampm, $filesize, $shortname, $filename) = $matches;
if ((strtoupper($filesize) == '<DIR>') && (strtolower($filename) == strtolower($value))) {
$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.'."\n";