wp/wp-includes/ID3/getid3.php
changeset 16 a86126ab1dd4
parent 7 cf61fcea0001
child 19 3d72ae0968f4
equal deleted inserted replaced
15:3d4e9c994f10 16:a86126ab1dd4
     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 https://github.com/JamesHeinrich/getID3       //
     5 //            or http://www.getid3.org                         //
     5 //            or https://www.getid3.org                        //
     6 //          also https://github.com/JamesHeinrich/getID3       //
     6 //            or http://getid3.sourceforge.net                 //
     7 /////////////////////////////////////////////////////////////////
       
     8 //                                                             //
     7 //                                                             //
     9 // Please see readme.txt for more information                  //
     8 // Please see readme.txt for more information                  //
    10 //                                                            ///
     9 //                                                            ///
    11 /////////////////////////////////////////////////////////////////
    10 /////////////////////////////////////////////////////////////////
    12 
    11 
    23 	define('IMG_JPG', IMAGETYPE_JPEG);
    22 	define('IMG_JPG', IMAGETYPE_JPEG);
    24 }
    23 }
    25 if (!defined('ENT_SUBSTITUTE')) { // PHP5.3 adds ENT_IGNORE, PHP5.4 adds ENT_SUBSTITUTE
    24 if (!defined('ENT_SUBSTITUTE')) { // PHP5.3 adds ENT_IGNORE, PHP5.4 adds ENT_SUBSTITUTE
    26 	define('ENT_SUBSTITUTE', (defined('ENT_IGNORE') ? ENT_IGNORE : 8));
    25 	define('ENT_SUBSTITUTE', (defined('ENT_IGNORE') ? ENT_IGNORE : 8));
    27 }
    26 }
       
    27 
       
    28 /*
       
    29 https://www.getid3.org/phpBB3/viewtopic.php?t=2114
       
    30 If you are running into a the problem where filenames with special characters are being handled
       
    31 incorrectly by external helper programs (e.g. metaflac), notably with the special characters removed,
       
    32 and you are passing in the filename in UTF8 (typically via a HTML form), try uncommenting this line:
       
    33 */
       
    34 //setlocale(LC_CTYPE, 'en_US.UTF-8');
    28 
    35 
    29 // attempt to define temp dir as something flexible but reliable
    36 // attempt to define temp dir as something flexible but reliable
    30 $temp_dir = ini_get('upload_tmp_dir');
    37 $temp_dir = ini_get('upload_tmp_dir');
    31 if ($temp_dir && (!is_dir($temp_dir) || !is_readable($temp_dir))) {
    38 if ($temp_dir && (!is_dir($temp_dir) || !is_readable($temp_dir))) {
    32 	$temp_dir = '';
    39 	$temp_dir = '';
    72 // End: Defines
    79 // End: Defines
    73 
    80 
    74 
    81 
    75 class getID3
    82 class getID3
    76 {
    83 {
    77 	// public: Settings
    84 	/*
    78 	public $encoding        = 'UTF-8';        // CASE SENSITIVE! - i.e. (must be supported by iconv()). Examples:  ISO-8859-1  UTF-8  UTF-16  UTF-16BE
    85 	 * Settings
    79 	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'
    86 	 */
    80 
    87 
    81 	// public: Optional tag checks - disable for speed.
    88 	/**
    82 	public $option_tag_id3v1         = true;  // Read and process ID3v1 tags
    89 	 * CASE SENSITIVE! - i.e. (must be supported by iconv()). Examples:  ISO-8859-1  UTF-8  UTF-16  UTF-16BE
    83 	public $option_tag_id3v2         = true;  // Read and process ID3v2 tags
    90 	 *
    84 	public $option_tag_lyrics3       = true;  // Read and process Lyrics3 tags
    91 	 * @var string
    85 	public $option_tag_apetag        = true;  // Read and process APE tags
    92 	 */
    86 	public $option_tags_process      = true;  // Copy tags to root key 'tags' and encode to $this->encoding
    93 	public $encoding        = 'UTF-8';
    87 	public $option_tags_html         = true;  // Copy tags to root key 'tags_html' properly translated from various encodings to HTML entities
    94 
    88 
    95 	/**
    89 	// public: Optional tag/comment calucations
    96 	 * Should always be 'ISO-8859-1', but some tags may be written in other encodings such as 'EUC-CN' or 'CP1252'
    90 	public $option_extra_info        = true;  // Calculate additional info such as bitrate, channelmode etc
    97 	 *
    91 
    98 	 * @var string
    92 	// public: Optional handling of embedded attachments (e.g. images)
    99 	 */
    93 	public $option_save_attachments  = true; // defaults to true (ATTACHMENTS_INLINE) for backward compatibility
   100 	public $encoding_id3v1  = 'ISO-8859-1';
    94 
   101 
    95 	// public: Optional calculations
   102 	/**
    96 	public $option_md5_data          = false; // Get MD5 sum of data part - slow
   103 	 * 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
    97 	public $option_md5_data_source   = false; // Use MD5 of source file if availble - only FLAC and OptimFROG
   104 	 *
    98 	public $option_sha1_data         = false; // Get SHA1 sum of data part - slow
   105 	 * @var bool
    99 	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)
   106 	 */
   100 
   107 	public $encoding_id3v1_autodetect  = false;
   101 	// public: Read buffer size in bytes
   108 
       
   109 	/*
       
   110 	 * Optional tag checks - disable for speed.
       
   111 	 */
       
   112 
       
   113 	/**
       
   114 	 * Read and process ID3v1 tags
       
   115 	 *
       
   116 	 * @var bool
       
   117 	 */
       
   118 	public $option_tag_id3v1         = true;
       
   119 
       
   120 	/**
       
   121 	 * Read and process ID3v2 tags
       
   122 	 *
       
   123 	 * @var bool
       
   124 	 */
       
   125 	public $option_tag_id3v2         = true;
       
   126 
       
   127 	/**
       
   128 	 * Read and process Lyrics3 tags
       
   129 	 *
       
   130 	 * @var bool
       
   131 	 */
       
   132 	public $option_tag_lyrics3       = true;
       
   133 
       
   134 	/**
       
   135 	 * Read and process APE tags
       
   136 	 *
       
   137 	 * @var bool
       
   138 	 */
       
   139 	public $option_tag_apetag        = true;
       
   140 
       
   141 	/**
       
   142 	 * Copy tags to root key 'tags' and encode to $this->encoding
       
   143 	 *
       
   144 	 * @var bool
       
   145 	 */
       
   146 	public $option_tags_process      = true;
       
   147 
       
   148 	/**
       
   149 	 * Copy tags to root key 'tags_html' properly translated from various encodings to HTML entities
       
   150 	 *
       
   151 	 * @var bool
       
   152 	 */
       
   153 	public $option_tags_html         = true;
       
   154 
       
   155 	/*
       
   156 	 * Optional tag/comment calculations
       
   157 	 */
       
   158 
       
   159 	/**
       
   160 	 * Calculate additional info such as bitrate, channelmode etc
       
   161 	 *
       
   162 	 * @var bool
       
   163 	 */
       
   164 	public $option_extra_info        = true;
       
   165 
       
   166 	/*
       
   167 	 * Optional handling of embedded attachments (e.g. images)
       
   168 	 */
       
   169 
       
   170 	/**
       
   171 	 * Defaults to true (ATTACHMENTS_INLINE) for backward compatibility
       
   172 	 *
       
   173 	 * @var bool|string
       
   174 	 */
       
   175 	public $option_save_attachments  = true;
       
   176 
       
   177 	/*
       
   178 	 * Optional calculations
       
   179 	 */
       
   180 
       
   181 	/**
       
   182 	 * Get MD5 sum of data part - slow
       
   183 	 *
       
   184 	 * @var bool
       
   185 	 */
       
   186 	public $option_md5_data          = false;
       
   187 
       
   188 	/**
       
   189 	 * Use MD5 of source file if availble - only FLAC and OptimFROG
       
   190 	 *
       
   191 	 * @var bool
       
   192 	 */
       
   193 	public $option_md5_data_source   = false;
       
   194 
       
   195 	/**
       
   196 	 * Get SHA1 sum of data part - slow
       
   197 	 *
       
   198 	 * @var bool
       
   199 	 */
       
   200 	public $option_sha1_data         = false;
       
   201 
       
   202 	/**
       
   203 	 * Check whether file is larger than 2GB and thus not supported by 32-bit PHP (null: auto-detect based on
       
   204 	 * PHP_INT_MAX)
       
   205 	 *
       
   206 	 * @var bool|null
       
   207 	 */
       
   208 	public $option_max_2gb_check;
       
   209 
       
   210 	/**
       
   211 	 * Read buffer size in bytes
       
   212 	 *
       
   213 	 * @var int
       
   214 	 */
   102 	public $option_fread_buffer_size = 32768;
   215 	public $option_fread_buffer_size = 32768;
   103 
   216 
   104 	// Public variables
   217 	// Public variables
   105 	public $filename;                         // Filename of file being analysed.
   218 
   106 	public $fp;                               // Filepointer to file being analysed.
   219 	/**
   107 	public $info;                             // Result array.
   220 	 * Filename of file being analysed.
       
   221 	 *
       
   222 	 * @var string
       
   223 	 */
       
   224 	public $filename;
       
   225 
       
   226 	/**
       
   227 	 * Filepointer to file being analysed.
       
   228 	 *
       
   229 	 * @var resource
       
   230 	 */
       
   231 	public $fp;
       
   232 
       
   233 	/**
       
   234 	 * Result array.
       
   235 	 *
       
   236 	 * @var array
       
   237 	 */
       
   238 	public $info;
       
   239 
       
   240 	/**
       
   241 	 * @var string
       
   242 	 */
   108 	public $tempdir = GETID3_TEMP_DIR;
   243 	public $tempdir = GETID3_TEMP_DIR;
       
   244 
       
   245 	/**
       
   246 	 * @var int
       
   247 	 */
   109 	public $memory_limit = 0;
   248 	public $memory_limit = 0;
   110 
   249 
   111 	// Protected variables
   250 	/**
       
   251 	 * @var string
       
   252 	 */
   112 	protected $startup_error   = '';
   253 	protected $startup_error   = '';
       
   254 
       
   255 	/**
       
   256 	 * @var string
       
   257 	 */
   113 	protected $startup_warning = '';
   258 	protected $startup_warning = '';
   114 
   259 
   115 	const VERSION           = '1.9.14-201706111222';
   260 	const VERSION           = '1.9.20-202006061653';
   116 	const FREAD_BUFFER_SIZE = 32768;
   261 	const FREAD_BUFFER_SIZE = 32768;
   117 
   262 
   118 	const ATTACHMENTS_NONE   = false;
   263 	const ATTACHMENTS_NONE   = false;
   119 	const ATTACHMENTS_INLINE = true;
   264 	const ATTACHMENTS_INLINE = true;
   120 
   265 
   121 	// public: constructor
       
   122 	public function __construct() {
   266 	public function __construct() {
   123 
   267 
       
   268 		// Check for PHP version
       
   269 		$required_php_version = '5.3.0';
       
   270 		if (version_compare(PHP_VERSION, $required_php_version, '<')) {
       
   271 			$this->startup_error .= 'getID3() requires PHP v'.$required_php_version.' or higher - you are running v'.PHP_VERSION."\n";
       
   272 			return;
       
   273 		}
       
   274 
   124 		// Check memory
   275 		// Check memory
   125 		$this->memory_limit = ini_get('memory_limit');
   276 		$memoryLimit = ini_get('memory_limit');
   126 		if (preg_match('#([0-9]+) ?M#i', $this->memory_limit, $matches)) {
   277 		if (preg_match('#([0-9]+) ?M#i', $memoryLimit, $matches)) {
   127 			// could be stored as "16M" rather than 16777216 for example
   278 			// could be stored as "16M" rather than 16777216 for example
   128 			$this->memory_limit = $matches[1] * 1048576;
   279 			$memoryLimit = $matches[1] * 1048576;
   129 		} elseif (preg_match('#([0-9]+) ?G#i', $this->memory_limit, $matches)) { // The 'G' modifier is available since PHP 5.1.0
   280 		} elseif (preg_match('#([0-9]+) ?G#i', $memoryLimit, $matches)) { // The 'G' modifier is available since PHP 5.1.0
   130 			// could be stored as "2G" rather than 2147483648 for example
   281 			// could be stored as "2G" rather than 2147483648 for example
   131 			$this->memory_limit = $matches[1] * 1073741824;
   282 			$memoryLimit = $matches[1] * 1073741824;
   132 		}
   283 		}
       
   284 		$this->memory_limit = $memoryLimit;
       
   285 
   133 		if ($this->memory_limit <= 0) {
   286 		if ($this->memory_limit <= 0) {
   134 			// memory limits probably disabled
   287 			// memory limits probably disabled
   135 		} elseif ($this->memory_limit <= 4194304) {
   288 		} elseif ($this->memory_limit <= 4194304) {
   136 			$this->startup_error .= 'PHP has less than 4MB available memory and will very likely run out. Increase memory_limit in php.ini'."\n";
   289 			$this->startup_error .= 'PHP has less than 4MB available memory and will very likely run out. Increase memory_limit in php.ini'."\n";
   137 		} elseif ($this->memory_limit <= 12582912) {
   290 		} elseif ($this->memory_limit <= 12582912) {
   138 			$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";
   291 			$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";
   139 		}
   292 		}
   140 
   293 
   141 		// Check safe_mode off
   294 		// Check safe_mode off
   142 		if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) {
   295 		if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) { // phpcs:ignore PHPCompatibility.IniDirectives.RemovedIniDirectives.safe_modeDeprecatedRemoved
   143 			$this->warning('WARNING: Safe mode is on, shorten support disabled, md5data/sha1data for ogg vorbis disabled, ogg vorbos/flac tag writing disabled.');
   296 			$this->warning('WARNING: Safe mode is on, shorten support disabled, md5data/sha1data for ogg vorbis disabled, ogg vorbos/flac tag writing disabled.');
   144 		}
   297 		}
   145 
   298 
   146 		if (($mbstring_func_overload = ini_get('mbstring.func_overload')) && ($mbstring_func_overload & 0x02)) {
   299 		// phpcs:ignore PHPCompatibility.IniDirectives.RemovedIniDirectives.mbstring_func_overloadDeprecated
       
   300 		if (($mbstring_func_overload = (int) ini_get('mbstring.func_overload')) && ($mbstring_func_overload & 0x02)) {
   147 			// http://php.net/manual/en/mbstring.overload.php
   301 			// http://php.net/manual/en/mbstring.overload.php
   148 			// "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"
   302 			// "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"
   149 			// 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.
   303 			// 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.
       
   304 			// phpcs:ignore PHPCompatibility.IniDirectives.RemovedIniDirectives.mbstring_func_overloadDeprecated
   150 			$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";
   305 			$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";
   151 		}
   306 		}
   152 
   307 
   153 		// Check for magic_quotes_runtime
   308 		// check for magic quotes in PHP < 7.4.0 (when these functions became deprecated)
   154 		if (function_exists('get_magic_quotes_runtime')) {
   309 		if (version_compare(PHP_VERSION, '7.4.0', '<')) {
   155 			if (get_magic_quotes_runtime()) {
   310 			// Check for magic_quotes_runtime
   156 				$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";
   311 			if (function_exists('get_magic_quotes_runtime')) {
   157 			}
   312 				// phpcs:ignore PHPCompatibility.FunctionUse.RemovedFunctions.get_magic_quotes_runtimeDeprecated
   158 		}
   313 				if (get_magic_quotes_runtime()) {
   159 
   314 					$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";
   160 		// Check for magic_quotes_gpc
   315 				}
   161 		if (function_exists('magic_quotes_gpc')) {
   316 			}
   162 			if (get_magic_quotes_gpc()) {
   317 			// Check for magic_quotes_gpc
   163 				$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";
   318 			if (function_exists('get_magic_quotes_gpc')) {
       
   319 				// phpcs:ignore PHPCompatibility.FunctionUse.RemovedFunctions.get_magic_quotes_gpcDeprecated
       
   320 				if (get_magic_quotes_gpc()) {
       
   321 					$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";
       
   322 				}
   164 			}
   323 			}
   165 		}
   324 		}
   166 
   325 
   167 		// Load support library
   326 		// Load support library
   168 		if (!include_once(GETID3_INCLUDEPATH.'getid3.lib.php')) {
   327 		if (!include_once(GETID3_INCLUDEPATH.'getid3.lib.php')) {
   174 		}
   333 		}
   175 
   334 
   176 
   335 
   177 		// Needed for Windows only:
   336 		// Needed for Windows only:
   178 		// Define locations of helper applications for Shorten, VorbisComment, MetaFLAC
   337 		// Define locations of helper applications for Shorten, VorbisComment, MetaFLAC
   179 		//   as well as other helper functions such as head, tail, md5sum, etc
   338 		//   as well as other helper functions such as head, etc
   180 		// This path cannot contain spaces, but the below code will attempt to get the
   339 		// This path cannot contain spaces, but the below code will attempt to get the
   181 		//   8.3-equivalent path automatically
   340 		//   8.3-equivalent path automatically
   182 		// IMPORTANT: This path must include the trailing slash
   341 		// IMPORTANT: This path must include the trailing slash
   183 		if (GETID3_OS_ISWINDOWS && !defined('GETID3_HELPERAPPSDIR')) {
   342 		if (GETID3_OS_ISWINDOWS && !defined('GETID3_HELPERAPPSDIR')) {
   184 
   343 
   217 
   376 
   218 		if (!empty($this->startup_error)) {
   377 		if (!empty($this->startup_error)) {
   219 			echo $this->startup_error;
   378 			echo $this->startup_error;
   220 			throw new getid3_exception($this->startup_error);
   379 			throw new getid3_exception($this->startup_error);
   221 		}
   380 		}
   222 
   381 	}
   223 		return true;
   382 
   224 	}
   383 	/**
   225 
   384 	 * @return string
       
   385 	 */
   226 	public function version() {
   386 	public function version() {
   227 		return self::VERSION;
   387 		return self::VERSION;
   228 	}
   388 	}
   229 
   389 
       
   390 	/**
       
   391 	 * @return int
       
   392 	 */
   230 	public function fread_buffer_size() {
   393 	public function fread_buffer_size() {
   231 		return $this->option_fread_buffer_size;
   394 		return $this->option_fread_buffer_size;
   232 	}
   395 	}
   233 
   396 
   234 
   397 	/**
   235 	// public: setOption
   398 	 * @param array $optArray
       
   399 	 *
       
   400 	 * @return bool
       
   401 	 */
   236 	public function setOption($optArray) {
   402 	public function setOption($optArray) {
   237 		if (!is_array($optArray) || empty($optArray)) {
   403 		if (!is_array($optArray) || empty($optArray)) {
   238 			return false;
   404 			return false;
   239 		}
   405 		}
   240 		foreach ($optArray as $opt => $val) {
   406 		foreach ($optArray as $opt => $val) {
   244 			$this->$opt = $val;
   410 			$this->$opt = $val;
   245 		}
   411 		}
   246 		return true;
   412 		return true;
   247 	}
   413 	}
   248 
   414 
   249 
   415 	/**
   250 	public function openfile($filename, $filesize=null) {
   416 	 * @param string   $filename
       
   417 	 * @param int      $filesize
       
   418 	 * @param resource $fp
       
   419 	 *
       
   420 	 * @return bool
       
   421 	 *
       
   422 	 * @throws getid3_exception
       
   423 	 */
       
   424 	public function openfile($filename, $filesize=null, $fp=null) {
   251 		try {
   425 		try {
   252 			if (!empty($this->startup_error)) {
   426 			if (!empty($this->startup_error)) {
   253 				throw new getid3_exception($this->startup_error);
   427 				throw new getid3_exception($this->startup_error);
   254 			}
   428 			}
   255 			if (!empty($this->startup_warning)) {
   429 			if (!empty($this->startup_warning)) {
   268 			if (preg_match('#^(ht|f)tp://#', $filename)) {
   442 			if (preg_match('#^(ht|f)tp://#', $filename)) {
   269 				throw new getid3_exception('Remote files are not supported - please copy the file locally first');
   443 				throw new getid3_exception('Remote files are not supported - please copy the file locally first');
   270 			}
   444 			}
   271 
   445 
   272 			$filename = str_replace('/', DIRECTORY_SEPARATOR, $filename);
   446 			$filename = str_replace('/', DIRECTORY_SEPARATOR, $filename);
   273 			$filename = preg_replace('#(?<!gs:)('.preg_quote(DIRECTORY_SEPARATOR).'{2,})#', DIRECTORY_SEPARATOR, $filename);
   447 			//$filename = preg_replace('#(?<!gs:)('.preg_quote(DIRECTORY_SEPARATOR).'{2,})#', DIRECTORY_SEPARATOR, $filename);
   274 
   448 
   275 			// open local file
   449 			// open local file
   276 			//if (is_readable($filename) && is_file($filename) && ($this->fp = fopen($filename, 'rb'))) { // see http://www.getid3.org/phpBB3/viewtopic.php?t=1720
   450 			//if (is_readable($filename) && is_file($filename) && ($this->fp = fopen($filename, 'rb'))) { // see https://www.getid3.org/phpBB3/viewtopic.php?t=1720
   277 			if ((is_readable($filename) || file_exists($filename)) && is_file($filename) && ($this->fp = fopen($filename, 'rb'))) {
   451 			if (($fp != null) && ((get_resource_type($fp) == 'file') || (get_resource_type($fp) == 'stream'))) {
       
   452 				$this->fp = $fp;
       
   453 			} elseif ((is_readable($filename) || file_exists($filename)) && is_file($filename) && ($this->fp = fopen($filename, 'rb'))) {
   278 				// great
   454 				// great
   279 			} else {
   455 			} else {
   280 				$errormessagelist = array();
   456 				$errormessagelist = array();
   281 				if (!is_readable($filename)) {
   457 				if (!is_readable($filename)) {
   282 					$errormessagelist[] = '!is_readable';
   458 					$errormessagelist[] = '!is_readable';
   329 							fclose($this->fp);
   505 							fclose($this->fp);
   330 							throw new getid3_exception('Unable to determine actual filesize. File is most likely larger than '.round(PHP_INT_MAX / 1073741824).'GB and is not supported by PHP.');
   506 							throw new getid3_exception('Unable to determine actual filesize. File is most likely larger than '.round(PHP_INT_MAX / 1073741824).'GB and is not supported by PHP.');
   331 						} elseif (getid3_lib::intValueSupported($real_filesize)) {
   507 						} elseif (getid3_lib::intValueSupported($real_filesize)) {
   332 							unset($this->info['filesize']);
   508 							unset($this->info['filesize']);
   333 							fclose($this->fp);
   509 							fclose($this->fp);
   334 							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');
   510 							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');
   335 						}
   511 						}
   336 						$this->info['filesize'] = $real_filesize;
   512 						$this->info['filesize'] = $real_filesize;
   337 						$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.');
   513 						$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.');
   338 				}
   514 				}
   339 			}
   515 			}
   340 
   516 
   341 			return true;
   517 			return true;
   342 
   518 
   344 			$this->error($e->getMessage());
   520 			$this->error($e->getMessage());
   345 		}
   521 		}
   346 		return false;
   522 		return false;
   347 	}
   523 	}
   348 
   524 
   349 	// public: analyze file
   525 	/**
   350 	public function analyze($filename, $filesize=null, $original_filename='') {
   526 	 * analyze file
       
   527 	 *
       
   528 	 * @param string   $filename
       
   529 	 * @param int      $filesize
       
   530 	 * @param string   $original_filename
       
   531 	 * @param resource $fp
       
   532 	 *
       
   533 	 * @return array
       
   534 	 */
       
   535 	public function analyze($filename, $filesize=null, $original_filename='', $fp=null) {
   351 		try {
   536 		try {
   352 			if (!$this->openfile($filename, $filesize)) {
   537 			if (!$this->openfile($filename, $filesize, $fp)) {
   353 				return $this->info;
   538 				return $this->info;
   354 			}
   539 			}
   355 
   540 
   356 			// Handle tags
   541 			// Handle tags
   357 			foreach (array('id3v2'=>'id3v2', 'id3v1'=>'id3v1', 'apetag'=>'ape', 'lyrics3'=>'lyrics3') as $tag_name => $tag_key) {
   542 			foreach (array('id3v2'=>'id3v2', 'id3v1'=>'id3v1', 'apetag'=>'ape', 'lyrics3'=>'lyrics3') as $tag_name => $tag_key) {
   381 			if (!$this->option_tag_id3v2) {
   566 			if (!$this->option_tag_id3v2) {
   382 				fseek($this->fp, 0);
   567 				fseek($this->fp, 0);
   383 				$header = fread($this->fp, 10);
   568 				$header = fread($this->fp, 10);
   384 				if ((substr($header, 0, 3) == 'ID3') && (strlen($header) == 10)) {
   569 				if ((substr($header, 0, 3) == 'ID3') && (strlen($header) == 10)) {
   385 					$this->info['id3v2']['header']        = true;
   570 					$this->info['id3v2']['header']        = true;
   386 					$this->info['id3v2']['majorversion']  = ord($header{3});
   571 					$this->info['id3v2']['majorversion']  = ord($header[3]);
   387 					$this->info['id3v2']['minorversion']  = ord($header{4});
   572 					$this->info['id3v2']['minorversion']  = ord($header[4]);
   388 					$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
   573 					$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
   389 				}
   574 				}
   390 			}
   575 			}
   391 
   576 
   392 			// read 32 kb file data
   577 			// read 32 kb file data
   495 		// return info array
   680 		// return info array
   496 		return $this->info;
   681 		return $this->info;
   497 	}
   682 	}
   498 
   683 
   499 
   684 
   500 	// private: error handling
   685 	/**
       
   686 	 * Error handling.
       
   687 	 *
       
   688 	 * @param string $message
       
   689 	 *
       
   690 	 * @return array
       
   691 	 */
   501 	public function error($message) {
   692 	public function error($message) {
   502 		$this->CleanUp();
   693 		$this->CleanUp();
   503 		if (!isset($this->info['error'])) {
   694 		if (!isset($this->info['error'])) {
   504 			$this->info['error'] = array();
   695 			$this->info['error'] = array();
   505 		}
   696 		}
   506 		$this->info['error'][] = $message;
   697 		$this->info['error'][] = $message;
   507 		return $this->info;
   698 		return $this->info;
   508 	}
   699 	}
   509 
   700 
   510 
   701 
   511 	// private: warning handling
   702 	/**
       
   703 	 * Warning handling.
       
   704 	 *
       
   705 	 * @param string $message
       
   706 	 *
       
   707 	 * @return bool
       
   708 	 */
   512 	public function warning($message) {
   709 	public function warning($message) {
   513 		$this->info['warning'][] = $message;
   710 		$this->info['warning'][] = $message;
   514 		return true;
   711 		return true;
   515 	}
   712 	}
   516 
   713 
   517 
   714 
   518 	// private: CleanUp
   715 	/**
       
   716 	 * @return bool
       
   717 	 */
   519 	private function CleanUp() {
   718 	private function CleanUp() {
   520 
   719 
   521 		// remove possible empty keys
   720 		// remove possible empty keys
   522 		$AVpossibleEmptyKeys = array('dataformat', 'bits_per_sample', 'encoder_options', 'streams', 'bitrate');
   721 		$AVpossibleEmptyKeys = array('dataformat', 'bits_per_sample', 'encoder_options', 'streams', 'bitrate');
   523 		foreach ($AVpossibleEmptyKeys as $dummy => $key) {
   722 		foreach ($AVpossibleEmptyKeys as $dummy => $key) {
   560 		unset($this->info['php_memory_limit']);
   759 		unset($this->info['php_memory_limit']);
   561 
   760 
   562 		return true;
   761 		return true;
   563 	}
   762 	}
   564 
   763 
   565 
   764 	/**
   566 	// return array containing information about all supported formats
   765 	 * Return array containing information about all supported formats.
       
   766 	 *
       
   767 	 * @return array
       
   768 	 */
   567 	public function GetFileFormatArray() {
   769 	public function GetFileFormatArray() {
   568 		static $format_info = array();
   770 		static $format_info = array();
   569 		if (empty($format_info)) {
   771 		if (empty($format_info)) {
   570 			$format_info = array(
   772 			$format_info = array(
   571 
   773 
   582 				// AAC  - audio       - Advanced Audio Coding (AAC) - ADIF format
   784 				// AAC  - audio       - Advanced Audio Coding (AAC) - ADIF format
   583 				'adif' => array(
   785 				'adif' => array(
   584 							'pattern'   => '^ADIF',
   786 							'pattern'   => '^ADIF',
   585 							'group'     => 'audio',
   787 							'group'     => 'audio',
   586 							'module'    => 'aac',
   788 							'module'    => 'aac',
   587 							'mime_type' => 'application/octet-stream',
   789 							'mime_type' => 'audio/aac',
   588 							'fail_ape'  => 'WARNING',
   790 							'fail_ape'  => 'WARNING',
   589 						),
   791 						),
   590 
   792 
   591 /*
   793 /*
   592 				// AA   - audio       - Audible Audiobook
   794 				// AA   - audio       - Audible Audiobook
   600 				// AAC  - audio       - Advanced Audio Coding (AAC) - ADTS format (very similar to MP3)
   802 				// AAC  - audio       - Advanced Audio Coding (AAC) - ADTS format (very similar to MP3)
   601 				'adts' => array(
   803 				'adts' => array(
   602 							'pattern'   => '^\\xFF[\\xF0-\\xF1\\xF8-\\xF9]',
   804 							'pattern'   => '^\\xFF[\\xF0-\\xF1\\xF8-\\xF9]',
   603 							'group'     => 'audio',
   805 							'group'     => 'audio',
   604 							'module'    => 'aac',
   806 							'module'    => 'aac',
   605 							'mime_type' => 'application/octet-stream',
   807 							'mime_type' => 'audio/aac',
   606 							'fail_ape'  => 'WARNING',
   808 							'fail_ape'  => 'WARNING',
   607 						),
   809 						),
   608 
   810 
   609 
   811 
   610 				// AU   - audio       - NeXT/Sun AUdio (AU)
   812 				// AU   - audio       - NeXT/Sun AUdio (AU)
   647 							'mime_type' => 'audio/dsd',
   849 							'mime_type' => 'audio/dsd',
   648 						),
   850 						),
   649 
   851 
   650 				// DSS  - audio       - Digital Speech Standard
   852 				// DSS  - audio       - Digital Speech Standard
   651 				'dss'  => array(
   853 				'dss'  => array(
   652 							'pattern'   => '^[\\x02-\\x06]ds[s2]',
   854 							'pattern'   => '^[\\x02-\\x08]ds[s2]',
   653 							'group'     => 'audio',
   855 							'group'     => 'audio',
   654 							'module'    => 'dss',
   856 							'module'    => 'dss',
   655 							'mime_type' => 'application/octet-stream',
   857 							'mime_type' => 'application/octet-stream',
       
   858 						),
       
   859 
       
   860 				// DSDIFF - audio     - Direct Stream Digital Interchange File Format
       
   861 				'dsdiff' => array(
       
   862 							'pattern'   => '^FRM8',
       
   863 							'group'     => 'audio',
       
   864 							'module'    => 'dsdiff',
       
   865 							'mime_type' => 'audio/dsd',
   656 						),
   866 						),
   657 
   867 
   658 				// DTS  - audio       - Dolby Theatre System
   868 				// DTS  - audio       - Dolby Theatre System
   659 				'dts'  => array(
   869 				'dts'  => array(
   660 							'pattern'   => '^\\x7F\\xFE\\x80\\x01',
   870 							'pattern'   => '^\\x7F\\xFE\\x80\\x01',
   666 				// FLAC - audio       - Free Lossless Audio Codec
   876 				// FLAC - audio       - Free Lossless Audio Codec
   667 				'flac' => array(
   877 				'flac' => array(
   668 							'pattern'   => '^fLaC',
   878 							'pattern'   => '^fLaC',
   669 							'group'     => 'audio',
   879 							'group'     => 'audio',
   670 							'module'    => 'flac',
   880 							'module'    => 'flac',
   671 							'mime_type' => 'audio/x-flac',
   881 							'mime_type' => 'audio/flac',
   672 						),
   882 						),
   673 
   883 
   674 				// LA   - audio       - Lossless Audio (LA)
   884 				// LA   - audio       - Lossless Audio (LA)
   675 				'la'   => array(
   885 				'la'   => array(
   676 							'pattern'   => '^LA0[2-4]',
   886 							'pattern'   => '^LA0[2-4]',
   698 				// MAC  - audio       - Monkey's Audio Compressor
   908 				// MAC  - audio       - Monkey's Audio Compressor
   699 				'mac'  => array(
   909 				'mac'  => array(
   700 							'pattern'   => '^MAC ',
   910 							'pattern'   => '^MAC ',
   701 							'group'     => 'audio',
   911 							'group'     => 'audio',
   702 							'module'    => 'monkey',
   912 							'module'    => 'monkey',
   703 							'mime_type' => 'application/octet-stream',
   913 							'mime_type' => 'audio/x-monkeys-audio',
   704 						),
   914 						),
   705 
   915 
   706 // has been known to produce false matches in random files (e.g. JPEGs), leave out until more precise matching available
   916 // has been known to produce false matches in random files (e.g. JPEGs), leave out until more precise matching available
   707 //				// MOD  - audio       - MODule (assorted sub-formats)
   917 //				// MOD  - audio       - MODule (assorted sub-formats)
   708 //				'mod'  => array(
   918 //				'mod'  => array(
   780 							'mime_type' => 'audio/xmms-shn',
   990 							'mime_type' => 'audio/xmms-shn',
   781 							'fail_id3'  => 'ERROR',
   991 							'fail_id3'  => 'ERROR',
   782 							'fail_ape'  => 'ERROR',
   992 							'fail_ape'  => 'ERROR',
   783 						),
   993 						),
   784 
   994 
       
   995 				// TAK  - audio       - Tom's lossless Audio Kompressor
       
   996 				'tak'  => array(
       
   997 							'pattern'   => '^tBaK',
       
   998 							'group'     => 'audio',
       
   999 							'module'    => 'tak',
       
  1000 							'mime_type' => 'application/octet-stream',
       
  1001 						),
       
  1002 
   785 				// TTA  - audio       - TTA Lossless Audio Compressor (http://tta.corecodec.org)
  1003 				// TTA  - audio       - TTA Lossless Audio Compressor (http://tta.corecodec.org)
   786 				'tta'  => array(
  1004 				'tta'  => array(
   787 							'pattern'   => '^TTA',  // could also be '^TTA(\\x01|\\x02|\\x03|2|1)'
  1005 							'pattern'   => '^TTA',  // could also be '^TTA(\\x01|\\x02|\\x03|2|1)'
   788 							'group'     => 'audio',
  1006 							'group'     => 'audio',
   789 							'module'    => 'tta',
  1007 							'module'    => 'tta',
   840 							'group'     => 'audio-video',
  1058 							'group'     => 'audio-video',
   841 							'module'    => 'flv',
  1059 							'module'    => 'flv',
   842 							'mime_type' => 'video/x-flv',
  1060 							'mime_type' => 'video/x-flv',
   843 						),
  1061 						),
   844 
  1062 
       
  1063 				// IVF - audio/video - IVF
       
  1064 				'ivf' => array(
       
  1065 							'pattern'   => '^DKIF',
       
  1066 							'group'     => 'audio-video',
       
  1067 							'module'    => 'ivf',
       
  1068 							'mime_type' => 'video/x-ivf',
       
  1069 						),
       
  1070 
   845 				// MKAV - audio/video - Mastroka
  1071 				// MKAV - audio/video - Mastroka
   846 				'matroska' => array(
  1072 				'matroska' => array(
   847 							'pattern'   => '^\\x1A\\x45\\xDF\\xA3',
  1073 							'pattern'   => '^\\x1A\\x45\\xDF\\xA3',
   848 							'group'     => 'audio-video',
  1074 							'group'     => 'audio-video',
   849 							'module'    => 'matroska',
  1075 							'module'    => 'matroska',
   887 				// RIFF - audio/video - Resource Interchange File Format (RIFF) / WAV / AVI / CD-audio / SDSS = renamed variant used by SmartSound QuickTracks (www.smartsound.com) / FORM = Audio Interchange File Format (AIFF)
  1113 				// RIFF - audio/video - Resource Interchange File Format (RIFF) / WAV / AVI / CD-audio / SDSS = renamed variant used by SmartSound QuickTracks (www.smartsound.com) / FORM = Audio Interchange File Format (AIFF)
   888 				'riff' => array(
  1114 				'riff' => array(
   889 							'pattern'   => '^(RIFF|SDSS|FORM)',
  1115 							'pattern'   => '^(RIFF|SDSS|FORM)',
   890 							'group'     => 'audio-video',
  1116 							'group'     => 'audio-video',
   891 							'module'    => 'riff',
  1117 							'module'    => 'riff',
   892 							'mime_type' => 'audio/x-wav',
  1118 							'mime_type' => 'audio/wav',
   893 							'fail_ape'  => 'WARNING',
  1119 							'fail_ape'  => 'WARNING',
   894 						),
  1120 						),
   895 
  1121 
   896 				// Real - audio/video - RealAudio, RealVideo
  1122 				// Real - audio/video - RealAudio, RealVideo
   897 				'real' => array(
  1123 				'real' => array(
   913 				'ts' => array(
  1139 				'ts' => array(
   914 							'pattern'   => '^(\\x47.{187}){10,}', // packets are 188 bytes long and start with 0x47 "G".  Check for at least 10 packets matching this pattern
  1140 							'pattern'   => '^(\\x47.{187}){10,}', // packets are 188 bytes long and start with 0x47 "G".  Check for at least 10 packets matching this pattern
   915 							'group'     => 'audio-video',
  1141 							'group'     => 'audio-video',
   916 							'module'    => 'ts',
  1142 							'module'    => 'ts',
   917 							'mime_type' => 'video/MP2T',
  1143 							'mime_type' => 'video/MP2T',
       
  1144 						),
       
  1145 
       
  1146 				// WTV - audio/video - Windows Recorded TV Show
       
  1147 				'wtv' => array(
       
  1148 							'pattern'   => '^\\xB7\\xD8\\x00\\x20\\x37\\x49\\xDA\\x11\\xA6\\x4E\\x00\\x07\\xE9\\x5E\\xAD\\x8D',
       
  1149 							'group'     => 'audio-video',
       
  1150 							'module'    => 'wtv',
       
  1151 							'mime_type' => 'video/x-ms-wtv',
   918 						),
  1152 						),
   919 
  1153 
   920 
  1154 
   921 				// Still-Image formats
  1155 				// Still-Image formats
   922 
  1156 
  1016 							'fail_id3'  => 'ERROR',
  1250 							'fail_id3'  => 'ERROR',
  1017 							'fail_ape'  => 'ERROR',
  1251 							'fail_ape'  => 'ERROR',
  1018 							'iconv_req' => false,
  1252 							'iconv_req' => false,
  1019 						),
  1253 						),
  1020 
  1254 
       
  1255 				// HPK  - data        - HPK compressed data
       
  1256 				'hpk'  => array(
       
  1257 							'pattern'   => '^BPUL',
       
  1258 							'group'     => 'archive',
       
  1259 							'module'    => 'hpk',
       
  1260 							'mime_type' => 'application/octet-stream',
       
  1261 							'fail_id3'  => 'ERROR',
       
  1262 							'fail_ape'  => 'ERROR',
       
  1263 						),
       
  1264 
  1021 				// RAR  - data        - RAR compressed data
  1265 				// RAR  - data        - RAR compressed data
  1022 				'rar'  => array(
  1266 				'rar'  => array(
  1023 							'pattern'   => '^Rar\\!',
  1267 							'pattern'   => '^Rar\\!',
  1024 							'group'     => 'archive',
  1268 							'group'     => 'archive',
  1025 							'module'    => 'rar',
  1269 							'module'    => 'rar',
  1026 							'mime_type' => 'application/octet-stream',
  1270 							'mime_type' => 'application/vnd.rar',
  1027 							'fail_id3'  => 'ERROR',
  1271 							'fail_id3'  => 'ERROR',
  1028 							'fail_ape'  => 'ERROR',
  1272 							'fail_ape'  => 'ERROR',
  1029 						),
  1273 						),
  1030 
  1274 
  1031 				// SZIP - audio/data  - SZIP compressed data
  1275 				// SZIP - audio/data  - SZIP compressed data
  1051 				// GZIP  - data        - GZIP compressed data
  1295 				// GZIP  - data        - GZIP compressed data
  1052 				'gz'  => array(
  1296 				'gz'  => array(
  1053 							'pattern'   => '^\\x1F\\x8B\\x08',
  1297 							'pattern'   => '^\\x1F\\x8B\\x08',
  1054 							'group'     => 'archive',
  1298 							'group'     => 'archive',
  1055 							'module'    => 'gzip',
  1299 							'module'    => 'gzip',
  1056 							'mime_type' => 'application/x-gzip',
  1300 							'mime_type' => 'application/gzip',
  1057 							'fail_id3'  => 'ERROR',
  1301 							'fail_id3'  => 'ERROR',
  1058 							'fail_ape'  => 'ERROR',
  1302 							'fail_ape'  => 'ERROR',
  1059 						),
  1303 						),
  1060 
  1304 
  1061 				// ZIP  - data         - ZIP compressed data
  1305 				// ZIP  - data         - ZIP compressed data
  1066 							'mime_type' => 'application/zip',
  1310 							'mime_type' => 'application/zip',
  1067 							'fail_id3'  => 'ERROR',
  1311 							'fail_id3'  => 'ERROR',
  1068 							'fail_ape'  => 'ERROR',
  1312 							'fail_ape'  => 'ERROR',
  1069 						),
  1313 						),
  1070 
  1314 
       
  1315 				// XZ   - data         - XZ compressed data
       
  1316 				'xz'  => array(
       
  1317 							'pattern'   => '^\\xFD7zXZ\\x00',
       
  1318 							'group'     => 'archive',
       
  1319 							'module'    => 'xz',
       
  1320 							'mime_type' => 'application/x-xz',
       
  1321 							'fail_id3'  => 'ERROR',
       
  1322 							'fail_ape'  => 'ERROR',
       
  1323 						),
       
  1324 
  1071 
  1325 
  1072 				// Misc other formats
  1326 				// Misc other formats
  1073 
  1327 
  1074 				// PAR2 - data        - Parity Volume Set Specification 2.0
  1328 				// PAR2 - data        - Parity Volume Set Specification 2.0
  1075 				'par2' => array (
  1329 				'par2' => array (
  1113 		}
  1367 		}
  1114 
  1368 
  1115 		return $format_info;
  1369 		return $format_info;
  1116 	}
  1370 	}
  1117 
  1371 
  1118 
  1372 	/**
  1119 
  1373 	 * @param string $filedata
       
  1374 	 * @param string $filename
       
  1375 	 *
       
  1376 	 * @return mixed|false
       
  1377 	 */
  1120 	public function GetFileFormat(&$filedata, $filename='') {
  1378 	public function GetFileFormat(&$filedata, $filename='') {
  1121 		// this function will determine the format of a file based on usually
  1379 		// this function will determine the format of a file based on usually
  1122 		// the first 2-4 bytes of the file (8 bytes for PNG, 16 bytes for JPG,
  1380 		// the first 2-4 bytes of the file (8 bytes for PNG, 16 bytes for JPG,
  1123 		// and in the case of ISO CD image, 6 bytes offset 32kb from the start
  1381 		// and in the case of ISO CD image, 6 bytes offset 32kb from the start
  1124 		// of the file).
  1382 		// of the file).
  1133 			}
  1391 			}
  1134 		}
  1392 		}
  1135 
  1393 
  1136 
  1394 
  1137 		if (preg_match('#\\.mp[123a]$#i', $filename)) {
  1395 		if (preg_match('#\\.mp[123a]$#i', $filename)) {
  1138 			// Too many mp3 encoders on the market put gabage in front of mpeg files
  1396 			// Too many mp3 encoders on the market put garbage in front of mpeg files
  1139 			// use assume format on these if format detection failed
  1397 			// use assume format on these if format detection failed
  1140 			$GetFileFormatArray = $this->GetFileFormatArray();
  1398 			$GetFileFormatArray = $this->GetFileFormatArray();
  1141 			$info = $GetFileFormatArray['mp3'];
  1399 			$info = $GetFileFormatArray['mp3'];
  1142 			$info['include'] = 'module.'.$info['group'].'.'.$info['module'].'.php';
  1400 			$info['include'] = 'module.'.$info['group'].'.'.$info['module'].'.php';
  1143 			return $info;
  1401 			return $info;
  1152 		}
  1410 		}
  1153 
  1411 
  1154 		return false;
  1412 		return false;
  1155 	}
  1413 	}
  1156 
  1414 
  1157 
  1415 	/**
  1158 	// converts array to $encoding charset from $this->encoding
  1416 	 * Converts array to $encoding charset from $this->encoding.
       
  1417 	 *
       
  1418 	 * @param array  $array
       
  1419 	 * @param string $encoding
       
  1420 	 */
  1159 	public function CharConvert(&$array, $encoding) {
  1421 	public function CharConvert(&$array, $encoding) {
  1160 
  1422 
  1161 		// identical encoding - end here
  1423 		// identical encoding - end here
  1162 		if ($encoding == $this->encoding) {
  1424 		if ($encoding == $this->encoding) {
  1163 			return;
  1425 			return;
  1176 				$array[$key] = trim(getid3_lib::iconv_fallback($encoding, $this->encoding, $value));
  1438 				$array[$key] = trim(getid3_lib::iconv_fallback($encoding, $this->encoding, $value));
  1177 			}
  1439 			}
  1178 		}
  1440 		}
  1179 	}
  1441 	}
  1180 
  1442 
  1181 
  1443 	/**
       
  1444 	 * @return bool
       
  1445 	 */
  1182 	public function HandleAllTags() {
  1446 	public function HandleAllTags() {
  1183 
  1447 
  1184 		// key name => array (tag name, character encoding)
  1448 		// key name => array (tag name, character encoding)
  1185 		static $tags;
  1449 		static $tags;
  1186 		if (empty($tags)) {
  1450 		if (empty($tags)) {
  1203 				'cue'       => array('cue'           , 'ISO-8859-1'),
  1467 				'cue'       => array('cue'           , 'ISO-8859-1'),
  1204 				'matroska'  => array('matroska'      , 'UTF-8'),
  1468 				'matroska'  => array('matroska'      , 'UTF-8'),
  1205 				'flac'      => array('vorbiscomment' , 'UTF-8'),
  1469 				'flac'      => array('vorbiscomment' , 'UTF-8'),
  1206 				'divxtag'   => array('divx'          , 'ISO-8859-1'),
  1470 				'divxtag'   => array('divx'          , 'ISO-8859-1'),
  1207 				'iptc'      => array('iptc'          , 'ISO-8859-1'),
  1471 				'iptc'      => array('iptc'          , 'ISO-8859-1'),
       
  1472 				'dsdiff'    => array('dsdiff'        , 'ISO-8859-1'),
  1208 			);
  1473 			);
  1209 		}
  1474 		}
  1210 
  1475 
  1211 		// loop through comments array
  1476 		// loop through comments array
  1212 		foreach ($tags as $comment_name => $tagname_encoding_array) {
  1477 		foreach ($tags as $comment_name => $tagname_encoding_array) {
  1231 								$this->info['tags'][trim($tag_name)][trim($tag_key)][]     = $value;
  1496 								$this->info['tags'][trim($tag_name)][trim($tag_key)][]     = $value;
  1232 							}
  1497 							}
  1233 						}
  1498 						}
  1234 					}
  1499 					}
  1235 					if ($tag_key == 'picture') {
  1500 					if ($tag_key == 'picture') {
       
  1501 						// 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
  1236 						unset($this->info[$comment_name]['comments'][$tag_key]);
  1502 						unset($this->info[$comment_name]['comments'][$tag_key]);
  1237 					}
  1503 					}
  1238 				}
  1504 				}
  1239 
  1505 
  1240 				if (!isset($this->info['tags'][$tag_name])) {
  1506 				if (!isset($this->info['tags'][$tag_name])) {
  1244 
  1510 
  1245 				$this->CharConvert($this->info['tags'][$tag_name], $this->info[$comment_name]['encoding']);           // only copy gets converted!
  1511 				$this->CharConvert($this->info['tags'][$tag_name], $this->info[$comment_name]['encoding']);           // only copy gets converted!
  1246 
  1512 
  1247 				if ($this->option_tags_html) {
  1513 				if ($this->option_tags_html) {
  1248 					foreach ($this->info['tags'][$tag_name] as $tag_key => $valuearray) {
  1514 					foreach ($this->info['tags'][$tag_name] as $tag_key => $valuearray) {
       
  1515 						if ($tag_key == 'picture') {
       
  1516 							// Do not to try to convert binary picture data to HTML
       
  1517 							// https://github.com/JamesHeinrich/getID3/issues/178
       
  1518 							continue;
       
  1519 						}
  1249 						$this->info['tags_html'][$tag_name][$tag_key] = getid3_lib::recursiveMultiByteCharString2HTML($valuearray, $this->info[$comment_name]['encoding']);
  1520 						$this->info['tags_html'][$tag_name][$tag_key] = getid3_lib::recursiveMultiByteCharString2HTML($valuearray, $this->info[$comment_name]['encoding']);
  1250 					}
  1521 					}
  1251 				}
  1522 				}
  1252 
  1523 
  1253 			}
  1524 			}
  1254 
  1525 
  1255 		}
  1526 		}
  1256 
  1527 
  1257 		// pictures can take up a lot of space, and we don't need multiple copies of them
  1528 		// 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
  1258 		// let there be a single copy in [comments][picture], and not elsewhere
       
  1259 		if (!empty($this->info['tags'])) {
  1529 		if (!empty($this->info['tags'])) {
  1260 			$unset_keys = array('tags', 'tags_html');
  1530 			$unset_keys = array('tags', 'tags_html');
  1261 			foreach ($this->info['tags'] as $tagtype => $tagarray) {
  1531 			foreach ($this->info['tags'] as $tagtype => $tagarray) {
  1262 				foreach ($tagarray as $tagname => $tagdata) {
  1532 				foreach ($tagarray as $tagname => $tagdata) {
  1263 					if ($tagname == 'picture') {
  1533 					if ($tagname == 'picture') {
  1299 			}
  1569 			}
  1300 		}
  1570 		}
  1301 		return true;
  1571 		return true;
  1302 	}
  1572 	}
  1303 
  1573 
       
  1574 	/**
       
  1575 	 * Calls getid3_lib::CopyTagsToComments() but passes in the option_tags_html setting from this instance of getID3
       
  1576 	 *
       
  1577 	 * @param array $ThisFileInfo
       
  1578 	 *
       
  1579 	 * @return bool
       
  1580 	 */
       
  1581 	public function CopyTagsToComments(&$ThisFileInfo) {
       
  1582 	    return getid3_lib::CopyTagsToComments($ThisFileInfo, $this->option_tags_html);
       
  1583 	}
       
  1584 
       
  1585 	/**
       
  1586 	 * @param string $algorithm
       
  1587 	 *
       
  1588 	 * @return array|bool
       
  1589 	 */
  1304 	public function getHashdata($algorithm) {
  1590 	public function getHashdata($algorithm) {
  1305 		switch ($algorithm) {
  1591 		switch ($algorithm) {
  1306 			case 'md5':
  1592 			case 'md5':
  1307 			case 'sha1':
  1593 			case 'sha1':
  1308 				break;
  1594 				break;
  1309 
  1595 
  1310 			default:
  1596 			default:
  1311 				return $this->error('bad algorithm "'.$algorithm.'" in getHashdata()');
  1597 				return $this->error('bad algorithm "'.$algorithm.'" in getHashdata()');
  1312 				break;
       
  1313 		}
  1598 		}
  1314 
  1599 
  1315 		if (!empty($this->info['fileformat']) && !empty($this->info['dataformat']) && ($this->info['fileformat'] == 'ogg') && ($this->info['audio']['dataformat'] == 'vorbis')) {
  1600 		if (!empty($this->info['fileformat']) && !empty($this->info['dataformat']) && ($this->info['fileformat'] == 'ogg') && ($this->info['audio']['dataformat'] == 'vorbis')) {
  1316 
  1601 
  1317 			// We cannot get an identical md5_data value for Ogg files where the comments
  1602 			// We cannot get an identical md5_data value for Ogg files where the comments
  1330 
  1615 
  1331 			// The above-mentioned problem of comments spanning multiple pages and changing
  1616 			// The above-mentioned problem of comments spanning multiple pages and changing
  1332 			// page sequence numbers likely happens for OggSpeex and OggFLAC as well, but
  1617 			// page sequence numbers likely happens for OggSpeex and OggFLAC as well, but
  1333 			// currently vorbiscomment only works on OggVorbis files.
  1618 			// currently vorbiscomment only works on OggVorbis files.
  1334 
  1619 
       
  1620 			// phpcs:ignore PHPCompatibility.IniDirectives.RemovedIniDirectives.safe_modeDeprecatedRemoved
  1335 			if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) {
  1621 			if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) {
  1336 
  1622 
  1337 				$this->warning('Failed making system call to vorbiscomment.exe - '.$algorithm.'_data is incorrect - error returned: PHP running in Safe Mode (backtick operator not available)');
  1623 				$this->warning('Failed making system call to vorbiscomment.exe - '.$algorithm.'_data is incorrect - error returned: PHP running in Safe Mode (backtick operator not available)');
  1338 				$this->info[$algorithm.'_data'] = false;
  1624 				$this->info[$algorithm.'_data'] = false;
  1339 
  1625 
  1363 
  1649 
  1364 					}
  1650 					}
  1365 
  1651 
  1366 				} else {
  1652 				} else {
  1367 
  1653 
  1368 					$commandline = 'vorbiscomment -w -c "'.$empty.'" "'.$file.'" "'.$temp.'" 2>&1';
       
  1369 					$commandline = 'vorbiscomment -w -c '.escapeshellarg($empty).' '.escapeshellarg($file).' '.escapeshellarg($temp).' 2>&1';
  1654 					$commandline = 'vorbiscomment -w -c '.escapeshellarg($empty).' '.escapeshellarg($file).' '.escapeshellarg($temp).' 2>&1';
  1370 					$VorbisCommentError = `$commandline`;
  1655 					$VorbisCommentError = `$commandline`;
  1371 
  1656 
  1372 				}
  1657 				}
  1373 
  1658 
  1421 			}
  1706 			}
  1422 
  1707 
  1423 		}
  1708 		}
  1424 		return true;
  1709 		return true;
  1425 	}
  1710 	}
  1426 
       
  1427 
  1711 
  1428 	public function ChannelsBitratePlaytimeCalculations() {
  1712 	public function ChannelsBitratePlaytimeCalculations() {
  1429 
  1713 
  1430 		// set channelmode on audio
  1714 		// set channelmode on audio
  1431 		if (!empty($this->info['audio']['channelmode']) || !isset($this->info['audio']['channels'])) {
  1715 		if (!empty($this->info['audio']['channelmode']) || !isset($this->info['audio']['channels'])) {
  1487 		if (!empty($this->info['playtime_seconds']) && empty($this->info['playtime_string'])) {
  1771 		if (!empty($this->info['playtime_seconds']) && empty($this->info['playtime_string'])) {
  1488 			$this->info['playtime_string'] = getid3_lib::PlaytimeString($this->info['playtime_seconds']);
  1772 			$this->info['playtime_string'] = getid3_lib::PlaytimeString($this->info['playtime_seconds']);
  1489 		}
  1773 		}
  1490 	}
  1774 	}
  1491 
  1775 
  1492 
  1776 	/**
       
  1777 	 * @return bool
       
  1778 	 */
  1493 	public function CalculateCompressionRatioVideo() {
  1779 	public function CalculateCompressionRatioVideo() {
  1494 		if (empty($this->info['video'])) {
  1780 		if (empty($this->info['video'])) {
  1495 			return false;
  1781 			return false;
  1496 		}
  1782 		}
  1497 		if (empty($this->info['video']['resolution_x']) || empty($this->info['video']['resolution_y'])) {
  1783 		if (empty($this->info['video']['resolution_x']) || empty($this->info['video']['resolution_y'])) {
  1535 
  1821 
  1536 		$this->info['video']['compression_ratio'] = $BitrateCompressed / $BitrateUncompressed;
  1822 		$this->info['video']['compression_ratio'] = $BitrateCompressed / $BitrateUncompressed;
  1537 		return true;
  1823 		return true;
  1538 	}
  1824 	}
  1539 
  1825 
  1540 
  1826 	/**
       
  1827 	 * @return bool
       
  1828 	 */
  1541 	public function CalculateCompressionRatioAudio() {
  1829 	public function CalculateCompressionRatioAudio() {
  1542 		if (empty($this->info['audio']['bitrate']) || empty($this->info['audio']['channels']) || empty($this->info['audio']['sample_rate']) || !is_numeric($this->info['audio']['sample_rate'])) {
  1830 		if (empty($this->info['audio']['bitrate']) || empty($this->info['audio']['channels']) || empty($this->info['audio']['sample_rate']) || !is_numeric($this->info['audio']['sample_rate'])) {
  1543 			return false;
  1831 			return false;
  1544 		}
  1832 		}
  1545 		$this->info['audio']['compression_ratio'] = $this->info['audio']['bitrate'] / ($this->info['audio']['channels'] * $this->info['audio']['sample_rate'] * (!empty($this->info['audio']['bits_per_sample']) ? $this->info['audio']['bits_per_sample'] : 16));
  1833 		$this->info['audio']['compression_ratio'] = $this->info['audio']['bitrate'] / ($this->info['audio']['channels'] * $this->info['audio']['sample_rate'] * (!empty($this->info['audio']['bits_per_sample']) ? $this->info['audio']['bits_per_sample'] : 16));
  1552 			}
  1840 			}
  1553 		}
  1841 		}
  1554 		return true;
  1842 		return true;
  1555 	}
  1843 	}
  1556 
  1844 
  1557 
  1845 	/**
       
  1846 	 * @return bool
       
  1847 	 */
  1558 	public function CalculateReplayGain() {
  1848 	public function CalculateReplayGain() {
  1559 		if (isset($this->info['replay_gain'])) {
  1849 		if (isset($this->info['replay_gain'])) {
  1560 			if (!isset($this->info['replay_gain']['reference_volume'])) {
  1850 			if (!isset($this->info['replay_gain']['reference_volume'])) {
  1561 				$this->info['replay_gain']['reference_volume'] = (double) 89.0;
  1851 				$this->info['replay_gain']['reference_volume'] = 89.0;
  1562 			}
  1852 			}
  1563 			if (isset($this->info['replay_gain']['track']['adjustment'])) {
  1853 			if (isset($this->info['replay_gain']['track']['adjustment'])) {
  1564 				$this->info['replay_gain']['track']['volume'] = $this->info['replay_gain']['reference_volume'] - $this->info['replay_gain']['track']['adjustment'];
  1854 				$this->info['replay_gain']['track']['volume'] = $this->info['replay_gain']['reference_volume'] - $this->info['replay_gain']['track']['adjustment'];
  1565 			}
  1855 			}
  1566 			if (isset($this->info['replay_gain']['album']['adjustment'])) {
  1856 			if (isset($this->info['replay_gain']['album']['adjustment'])) {
  1575 			}
  1865 			}
  1576 		}
  1866 		}
  1577 		return true;
  1867 		return true;
  1578 	}
  1868 	}
  1579 
  1869 
       
  1870 	/**
       
  1871 	 * @return bool
       
  1872 	 */
  1580 	public function ProcessAudioStreams() {
  1873 	public function ProcessAudioStreams() {
  1581 		if (!empty($this->info['audio']['bitrate']) || !empty($this->info['audio']['channels']) || !empty($this->info['audio']['sample_rate'])) {
  1874 		if (!empty($this->info['audio']['bitrate']) || !empty($this->info['audio']['channels']) || !empty($this->info['audio']['sample_rate'])) {
  1582 			if (!isset($this->info['audio']['streams'])) {
  1875 			if (!isset($this->info['audio']['streams'])) {
  1583 				foreach ($this->info['audio'] as $key => $value) {
  1876 				foreach ($this->info['audio'] as $key => $value) {
  1584 					if ($key != 'streams') {
  1877 					if ($key != 'streams') {
  1588 			}
  1881 			}
  1589 		}
  1882 		}
  1590 		return true;
  1883 		return true;
  1591 	}
  1884 	}
  1592 
  1885 
       
  1886 	/**
       
  1887 	 * @return string|bool
       
  1888 	 */
  1593 	public function getid3_tempnam() {
  1889 	public function getid3_tempnam() {
  1594 		return tempnam($this->tempdir, 'gI3');
  1890 		return tempnam($this->tempdir, 'gI3');
  1595 	}
  1891 	}
  1596 
  1892 
       
  1893 	/**
       
  1894 	 * @param string $name
       
  1895 	 *
       
  1896 	 * @return bool
       
  1897 	 *
       
  1898 	 * @throws getid3_exception
       
  1899 	 */
  1597 	public function include_module($name) {
  1900 	public function include_module($name) {
  1598 		//if (!file_exists($this->include_path.'module.'.$name.'.php')) {
  1901 		//if (!file_exists($this->include_path.'module.'.$name.'.php')) {
  1599 		if (!file_exists(GETID3_INCLUDEPATH.'module.'.$name.'.php')) {
  1902 		if (!file_exists(GETID3_INCLUDEPATH.'module.'.$name.'.php')) {
  1600 			throw new getid3_exception('Required module.'.$name.'.php is missing.');
  1903 			throw new getid3_exception('Required module.'.$name.'.php is missing.');
  1601 		}
  1904 		}
  1602 		include_once(GETID3_INCLUDEPATH.'module.'.$name.'.php');
  1905 		include_once(GETID3_INCLUDEPATH.'module.'.$name.'.php');
  1603 		return true;
  1906 		return true;
  1604 	}
  1907 	}
  1605 
  1908 
  1606     public static function is_writable ($filename) {
  1909 	/**
  1607         $ret = is_writable($filename);
  1910 	 * @param string $filename
  1608 
  1911 	 *
  1609         if (!$ret) {
  1912 	 * @return bool
  1610             $perms = fileperms($filename);
  1913 	 */
  1611             $ret = ($perms & 0x0080) || ($perms & 0x0010) || ($perms & 0x0002);
  1914 	public static function is_writable ($filename) {
  1612         }
  1915 		$ret = is_writable($filename);
  1613 
  1916 		if (!$ret) {
  1614         return $ret;
  1917 			$perms = fileperms($filename);
  1615     }
  1918 			$ret = ($perms & 0x0080) || ($perms & 0x0010) || ($perms & 0x0002);
       
  1919 		}
       
  1920 		return $ret;
       
  1921 	}
  1616 
  1922 
  1617 }
  1923 }
  1618 
  1924 
  1619 
  1925 
  1620 abstract class getid3_handler {
  1926 abstract class getid3_handler
       
  1927 {
  1621 
  1928 
  1622 	/**
  1929 	/**
  1623 	* @var getID3
  1930 	* @var getID3
  1624 	*/
  1931 	*/
  1625 	protected $getid3;                       // pointer
  1932 	protected $getid3;                       // pointer
  1626 
  1933 
  1627 	protected $data_string_flag     = false; // analyzing filepointer or string
  1934 	/**
  1628 	protected $data_string          = '';    // string to analyze
  1935 	 * Analyzing filepointer or string.
  1629 	protected $data_string_position = 0;     // seek position in string
  1936 	 *
  1630 	protected $data_string_length   = 0;     // string length
  1937 	 * @var bool
  1631 
  1938 	 */
  1632 	private $dependency_to = null;
  1939 	protected $data_string_flag     = false;
  1633 
  1940 
  1634 
  1941 	/**
       
  1942 	 * String to analyze.
       
  1943 	 *
       
  1944 	 * @var string
       
  1945 	 */
       
  1946 	protected $data_string          = '';
       
  1947 
       
  1948 	/**
       
  1949 	 * Seek position in string.
       
  1950 	 *
       
  1951 	 * @var int
       
  1952 	 */
       
  1953 	protected $data_string_position = 0;
       
  1954 
       
  1955 	/**
       
  1956 	 * String length.
       
  1957 	 *
       
  1958 	 * @var int
       
  1959 	 */
       
  1960 	protected $data_string_length   = 0;
       
  1961 
       
  1962 	/**
       
  1963 	 * @var string
       
  1964 	 */
       
  1965 	private $dependency_to;
       
  1966 
       
  1967 	/**
       
  1968 	 * getid3_handler constructor.
       
  1969 	 *
       
  1970 	 * @param getID3 $getid3
       
  1971 	 * @param string $call_module
       
  1972 	 */
  1635 	public function __construct(getID3 $getid3, $call_module=null) {
  1973 	public function __construct(getID3 $getid3, $call_module=null) {
  1636 		$this->getid3 = $getid3;
  1974 		$this->getid3 = $getid3;
  1637 
  1975 
  1638 		if ($call_module) {
  1976 		if ($call_module) {
  1639 			$this->dependency_to = str_replace('getid3_', '', $call_module);
  1977 			$this->dependency_to = str_replace('getid3_', '', $call_module);
  1640 		}
  1978 		}
  1641 	}
  1979 	}
  1642 
  1980 
  1643 
  1981 	/**
  1644 	// Analyze from file pointer
  1982 	 * Analyze from file pointer.
       
  1983 	 *
       
  1984 	 * @return bool
       
  1985 	 */
  1645 	abstract public function Analyze();
  1986 	abstract public function Analyze();
  1646 
  1987 
  1647 
  1988 	/**
  1648 	// Analyze from string instead
  1989 	 * Analyze from string instead.
       
  1990 	 *
       
  1991 	 * @param string $string
       
  1992 	 */
  1649 	public function AnalyzeString($string) {
  1993 	public function AnalyzeString($string) {
  1650 		// Enter string mode
  1994 		// Enter string mode
  1651 		$this->setStringMode($string);
  1995 		$this->setStringMode($string);
  1652 
  1996 
  1653 		// Save info
  1997 		// Save info
  1669 
  2013 
  1670 		// Exit string mode
  2014 		// Exit string mode
  1671 		$this->data_string_flag = false;
  2015 		$this->data_string_flag = false;
  1672 	}
  2016 	}
  1673 
  2017 
       
  2018 	/**
       
  2019 	 * @param string $string
       
  2020 	 */
  1674 	public function setStringMode($string) {
  2021 	public function setStringMode($string) {
  1675 		$this->data_string_flag   = true;
  2022 		$this->data_string_flag   = true;
  1676 		$this->data_string        = $string;
  2023 		$this->data_string        = $string;
  1677 		$this->data_string_length = strlen($string);
  2024 		$this->data_string_length = strlen($string);
  1678 	}
  2025 	}
  1679 
  2026 
       
  2027 	/**
       
  2028 	 * @return int|bool
       
  2029 	 */
  1680 	protected function ftell() {
  2030 	protected function ftell() {
  1681 		if ($this->data_string_flag) {
  2031 		if ($this->data_string_flag) {
  1682 			return $this->data_string_position;
  2032 			return $this->data_string_position;
  1683 		}
  2033 		}
  1684 		return ftell($this->getid3->fp);
  2034 		return ftell($this->getid3->fp);
  1685 	}
  2035 	}
  1686 
  2036 
       
  2037 	/**
       
  2038 	 * @param int $bytes
       
  2039 	 *
       
  2040 	 * @return string|false
       
  2041 	 *
       
  2042 	 * @throws getid3_exception
       
  2043 	 */
  1687 	protected function fread($bytes) {
  2044 	protected function fread($bytes) {
  1688 		if ($this->data_string_flag) {
  2045 		if ($this->data_string_flag) {
  1689 			$this->data_string_position += $bytes;
  2046 			$this->data_string_position += $bytes;
  1690 			return substr($this->data_string, $this->data_string_position - $bytes, $bytes);
  2047 			return substr($this->data_string, $this->data_string_position - $bytes, $bytes);
  1691 		}
  2048 		}
  1694 			throw new getid3_exception('cannot fread('.$bytes.' from '.$this->ftell().') because beyond PHP filesystem limit', 10);
  2051 			throw new getid3_exception('cannot fread('.$bytes.' from '.$this->ftell().') because beyond PHP filesystem limit', 10);
  1695 		}
  2052 		}
  1696 
  2053 
  1697 		//return fread($this->getid3->fp, $bytes);
  2054 		//return fread($this->getid3->fp, $bytes);
  1698 		/*
  2055 		/*
  1699 		* http://www.getid3.org/phpBB3/viewtopic.php?t=1930
  2056 		* https://www.getid3.org/phpBB3/viewtopic.php?t=1930
  1700 		* "I found out that the root cause for the problem was how getID3 uses the PHP system function fread().
  2057 		* "I found out that the root cause for the problem was how getID3 uses the PHP system function fread().
  1701 		* It seems to assume that fread() would always return as many bytes as were requested.
  2058 		* It seems to assume that fread() would always return as many bytes as were requested.
  1702 		* 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.
  2059 		* 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.
  1703 		* The call may return only part of the requested data and a new call is needed to get more."
  2060 		* The call may return only part of the requested data and a new call is needed to get more."
  1704 		*/
  2061 		*/
  1705 		$contents = '';
  2062 		$contents = '';
  1706 		do {
  2063 		do {
       
  2064 			//if (($this->getid3->memory_limit > 0) && ($bytes > $this->getid3->memory_limit)) {
       
  2065 			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)"
       
  2066 				throw new getid3_exception('cannot fread('.$bytes.' from '.$this->ftell().') that is more than available PHP memory ('.$this->getid3->memory_limit.')', 10);
       
  2067 			}
  1707 			$part = fread($this->getid3->fp, $bytes);
  2068 			$part = fread($this->getid3->fp, $bytes);
  1708 			$partLength  = strlen($part);
  2069 			$partLength  = strlen($part);
  1709 			$bytes      -= $partLength;
  2070 			$bytes      -= $partLength;
  1710 			$contents   .= $part;
  2071 			$contents   .= $part;
  1711 		} while (($bytes > 0) && ($partLength > 0));
  2072 		} while (($bytes > 0) && ($partLength > 0));
  1712 		return $contents;
  2073 		return $contents;
  1713 	}
  2074 	}
  1714 
  2075 
       
  2076 	/**
       
  2077 	 * @param int $bytes
       
  2078 	 * @param int $whence
       
  2079 	 *
       
  2080 	 * @return int
       
  2081 	 *
       
  2082 	 * @throws getid3_exception
       
  2083 	 */
  1715 	protected function fseek($bytes, $whence=SEEK_SET) {
  2084 	protected function fseek($bytes, $whence=SEEK_SET) {
  1716 		if ($this->data_string_flag) {
  2085 		if ($this->data_string_flag) {
  1717 			switch ($whence) {
  2086 			switch ($whence) {
  1718 				case SEEK_SET:
  2087 				case SEEK_SET:
  1719 					$this->data_string_position = $bytes;
  2088 					$this->data_string_position = $bytes;
  1740 			}
  2109 			}
  1741 		}
  2110 		}
  1742 		return fseek($this->getid3->fp, $bytes, $whence);
  2111 		return fseek($this->getid3->fp, $bytes, $whence);
  1743 	}
  2112 	}
  1744 
  2113 
       
  2114 	/**
       
  2115 	 * @return string|false
       
  2116 	 *
       
  2117 	 * @throws getid3_exception
       
  2118 	 */
       
  2119 	protected function fgets() {
       
  2120 		// must be able to handle CR/LF/CRLF but not read more than one lineend
       
  2121 		$buffer   = ''; // final string we will return
       
  2122 		$prevchar = ''; // save previously-read character for end-of-line checking
       
  2123 		if ($this->data_string_flag) {
       
  2124 			while (true) {
       
  2125 				$thischar = substr($this->data_string, $this->data_string_position++, 1);
       
  2126 				if (($prevchar == "\r") && ($thischar != "\n")) {
       
  2127 					// read one byte too many, back up
       
  2128 					$this->data_string_position--;
       
  2129 					break;
       
  2130 				}
       
  2131 				$buffer .= $thischar;
       
  2132 				if ($thischar == "\n") {
       
  2133 					break;
       
  2134 				}
       
  2135 				if ($this->data_string_position >= $this->data_string_length) {
       
  2136 					// EOF
       
  2137 					break;
       
  2138 				}
       
  2139 				$prevchar = $thischar;
       
  2140 			}
       
  2141 
       
  2142 		} else {
       
  2143 
       
  2144 			// Ideally we would just use PHP's fgets() function, however...
       
  2145 			// it does not behave consistently with regards to mixed line endings, may be system-dependent
       
  2146 			// and breaks entirely when given a file with mixed \r vs \n vs \r\n line endings (e.g. some PDFs)
       
  2147 			//return fgets($this->getid3->fp);
       
  2148 			while (true) {
       
  2149 				$thischar = fgetc($this->getid3->fp);
       
  2150 				if (($prevchar == "\r") && ($thischar != "\n")) {
       
  2151 					// read one byte too many, back up
       
  2152 					fseek($this->getid3->fp, -1, SEEK_CUR);
       
  2153 					break;
       
  2154 				}
       
  2155 				$buffer .= $thischar;
       
  2156 				if ($thischar == "\n") {
       
  2157 					break;
       
  2158 				}
       
  2159 				if (feof($this->getid3->fp)) {
       
  2160 					break;
       
  2161 				}
       
  2162 				$prevchar = $thischar;
       
  2163 			}
       
  2164 
       
  2165 		}
       
  2166 		return $buffer;
       
  2167 	}
       
  2168 
       
  2169 	/**
       
  2170 	 * @return bool
       
  2171 	 */
  1745 	protected function feof() {
  2172 	protected function feof() {
  1746 		if ($this->data_string_flag) {
  2173 		if ($this->data_string_flag) {
  1747 			return $this->data_string_position >= $this->data_string_length;
  2174 			return $this->data_string_position >= $this->data_string_length;
  1748 		}
  2175 		}
  1749 		return feof($this->getid3->fp);
  2176 		return feof($this->getid3->fp);
  1750 	}
  2177 	}
  1751 
  2178 
       
  2179 	/**
       
  2180 	 * @param string $module
       
  2181 	 *
       
  2182 	 * @return bool
       
  2183 	 */
  1752 	final protected function isDependencyFor($module) {
  2184 	final protected function isDependencyFor($module) {
  1753 		return $this->dependency_to == $module;
  2185 		return $this->dependency_to == $module;
  1754 	}
  2186 	}
  1755 
  2187 
       
  2188 	/**
       
  2189 	 * @param string $text
       
  2190 	 *
       
  2191 	 * @return bool
       
  2192 	 */
  1756 	protected function error($text) {
  2193 	protected function error($text) {
  1757 		$this->getid3->info['error'][] = $text;
  2194 		$this->getid3->info['error'][] = $text;
  1758 
  2195 
  1759 		return false;
  2196 		return false;
  1760 	}
  2197 	}
  1761 
  2198 
       
  2199 	/**
       
  2200 	 * @param string $text
       
  2201 	 *
       
  2202 	 * @return bool
       
  2203 	 */
  1762 	protected function warning($text) {
  2204 	protected function warning($text) {
  1763 		return $this->getid3->warning($text);
  2205 		return $this->getid3->warning($text);
  1764 	}
  2206 	}
  1765 
  2207 
       
  2208 	/**
       
  2209 	 * @param string $text
       
  2210 	 */
  1766 	protected function notice($text) {
  2211 	protected function notice($text) {
  1767 		// does nothing for now
  2212 		// does nothing for now
  1768 	}
  2213 	}
  1769 
  2214 
       
  2215 	/**
       
  2216 	 * @param string $name
       
  2217 	 * @param int    $offset
       
  2218 	 * @param int    $length
       
  2219 	 * @param string $image_mime
       
  2220 	 *
       
  2221 	 * @return string|null
       
  2222 	 *
       
  2223 	 * @throws Exception
       
  2224 	 * @throws getid3_exception
       
  2225 	 */
  1770 	public function saveAttachment($name, $offset, $length, $image_mime=null) {
  2226 	public function saveAttachment($name, $offset, $length, $image_mime=null) {
  1771 		try {
  2227 		try {
  1772 
  2228 
  1773 			// do not extract at all
  2229 			// do not extract at all
  1774 			if ($this->getid3->option_save_attachments === getID3::ATTACHMENTS_NONE) {
  2230 			if ($this->getid3->option_save_attachments === getID3::ATTACHMENTS_NONE) {
  1818 		} catch (Exception $e) {
  2274 		} catch (Exception $e) {
  1819 
  2275 
  1820 			// close and remove dest file if created
  2276 			// close and remove dest file if created
  1821 			if (isset($fp_dest) && is_resource($fp_dest)) {
  2277 			if (isset($fp_dest) && is_resource($fp_dest)) {
  1822 				fclose($fp_dest);
  2278 				fclose($fp_dest);
       
  2279 			}
       
  2280 
       
  2281 			if (isset($dest) && file_exists($dest)) {
  1823 				unlink($dest);
  2282 				unlink($dest);
  1824 			}
  2283 			}
  1825 
  2284 
  1826 			// do not set any is case of error
  2285 			// do not set any is case of error
  1827 			$attachment = null;
  2286 			$attachment = null;