: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
public function CalculateCompressionRatioAudio() {
if (empty($this->info['audio']['bitrate']) || empty($this->info['audio']['channels']) || empty($this->info['audio']['sample_rate']) || !is_numeric($this->info['audio']['sample_rate'])) {
$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));
if (!empty($this->info['audio']['streams'])) {
foreach ($this->info['audio']['streams'] as $streamnumber => $streamdata) {
if (!empty($streamdata['bitrate']) && !empty($streamdata['channels']) && !empty($streamdata['sample_rate'])) {
$this->info['audio']['streams'][$streamnumber]['compression_ratio'] = $streamdata['bitrate'] / ($streamdata['channels'] * $streamdata['sample_rate'] * (!empty($streamdata['bits_per_sample']) ? $streamdata['bits_per_sample'] : 16));
public function CalculateReplayGain() {
if (isset($this->info['replay_gain'])) {
if (!isset($this->info['replay_gain']['reference_volume'])) {
$this->info['replay_gain']['reference_volume'] = 89.0;
if (isset($this->info['replay_gain']['track']['adjustment'])) {
$this->info['replay_gain']['track']['volume'] = $this->info['replay_gain']['reference_volume'] - $this->info['replay_gain']['track']['adjustment'];
if (isset($this->info['replay_gain']['album']['adjustment'])) {
$this->info['replay_gain']['album']['volume'] = $this->info['replay_gain']['reference_volume'] - $this->info['replay_gain']['album']['adjustment'];
if (isset($this->info['replay_gain']['track']['peak'])) {
$this->info['replay_gain']['track']['max_noclip_gain'] = 0 - getid3_lib::RGADamplitude2dB($this->info['replay_gain']['track']['peak']);
if (isset($this->info['replay_gain']['album']['peak'])) {
$this->info['replay_gain']['album']['max_noclip_gain'] = 0 - getid3_lib::RGADamplitude2dB($this->info['replay_gain']['album']['peak']);
public function ProcessAudioStreams() {
if (!empty($this->info['audio']['bitrate']) || !empty($this->info['audio']['channels']) || !empty($this->info['audio']['sample_rate'])) {
if (!isset($this->info['audio']['streams'])) {
foreach ($this->info['audio'] as $key => $value) {
$this->info['audio']['streams'][0][$key] = $value;
public function getid3_tempnam() {
return tempnam($this->tempdir, 'gI3');
* @throws getid3_exception
public function include_module($name) {
//if (!file_exists($this->include_path.'module.'.$name.'.php')) {
if (!file_exists(GETID3_INCLUDEPATH.'module.'.$name.'.php')) {
throw new getid3_exception('Required module.'.$name.'.php is missing.');
include_once(GETID3_INCLUDEPATH.'module.'.$name.'.php');
* @param string $filename
public static function is_writable ($filename) {
$ret = is_writable($filename);
$perms = fileperms($filename);
$ret = ($perms & 0x0080) || ($perms & 0x0010) || ($perms & 0x0002);
abstract class getid3_handler
protected $getid3; // pointer
* Analyzing filepointer or string.
protected $data_string_flag = false;
protected $data_string = '';
* Seek position in string.
protected $data_string_position = 0;
protected $data_string_length = 0;
* getid3_handler constructor.
* @param string $call_module
public function __construct(getID3 $getid3, $call_module=null) {
$this->dependency_to = str_replace('getid3_', '', $call_module);
* Analyze from file pointer.
abstract public function Analyze();
* Analyze from string instead.
public function AnalyzeString($string) {
$this->setStringMode($string);
$saved_avdataoffset = $this->getid3->info['avdataoffset'];
$saved_avdataend = $this->getid3->info['avdataend'];
$saved_filesize = (isset($this->getid3->info['filesize']) ? $this->getid3->info['filesize'] : null); // may be not set if called as dependency without openfile() call
$this->getid3->info['avdataoffset'] = 0;
$this->getid3->info['avdataend'] = $this->getid3->info['filesize'] = $this->data_string_length;
$this->getid3->info['avdataoffset'] = $saved_avdataoffset;
$this->getid3->info['avdataend'] = $saved_avdataend;
$this->getid3->info['filesize'] = $saved_filesize;
$this->data_string_flag = false;
public function setStringMode($string) {
$this->data_string_flag = true;
$this->data_string = $string;
$this->data_string_length = strlen($string);
protected function ftell() {
if ($this->data_string_flag) {
return $this->data_string_position;
return ftell($this->getid3->fp);
* @throws getid3_exception
protected function fread($bytes) {
if ($this->data_string_flag) {
$this->data_string_position += $bytes;
return substr($this->data_string, $this->data_string_position - $bytes, $bytes);
throw new getid3_exception('cannot fread('.$bytes.' from '.$this->ftell().')', 10);
$pos = $this->ftell() + $bytes;
if (!getid3_lib::intValueSupported($pos)) {
throw new getid3_exception('cannot fread('.$bytes.' from '.$this->ftell().') because beyond PHP filesystem limit', 10);
//return fread($this->getid3->fp, $bytes);
* https://www.getid3.org/phpBB3/viewtopic.php?t=1930
* "I found out that the root cause for the problem was how getID3 uses the PHP system function fread().
* It seems to assume that fread() would always return as many bytes as were requested.
* However, according the PHP manual (http://php.net/manual/en/function.fread.php), this is the case only with regular local files, but not e.g. with Linux pipes.
* The call may return only part of the requested data and a new call is needed to get more."
//if (($this->getid3->memory_limit > 0) && ($bytes > $this->getid3->memory_limit)) {
if (($this->getid3->memory_limit > 0) && (($bytes / $this->getid3->memory_limit) > 0.99)) { // enable a more-fuzzy match to prevent close misses generating errors like "PHP Fatal error: Allowed memory size of 33554432 bytes exhausted (tried to allocate 33554464 bytes)"
throw new getid3_exception('cannot fread('.$bytes.' from '.$this->ftell().') that is more than available PHP memory ('.$this->getid3->memory_limit.')', 10);
$part = fread($this->getid3->fp, $bytes);
$partLength = strlen($part);
} while (($bytes > 0) && ($partLength > 0));
* @throws getid3_exception
protected function fseek($bytes, $whence=SEEK_SET) {
if ($this->data_string_flag) {
$this->data_string_position = $bytes;
$this->data_string_position += $bytes;
$this->data_string_position = $this->data_string_length + $bytes;
return 0; // fseek returns 0 on success
if ($whence == SEEK_CUR) {
$pos = $this->ftell() + $bytes;
} elseif ($whence == SEEK_END) {
$pos = $this->getid3->info['filesize'] + $bytes;
if (!getid3_lib::intValueSupported($pos)) {
throw new getid3_exception('cannot fseek('.$pos.') because beyond PHP filesystem limit', 10);
// https://github.com/JamesHeinrich/getID3/issues/327
$result = fseek($this->getid3->fp, $bytes, $whence);
if ($result !== 0) { // fseek returns 0 on success
throw new getid3_exception('cannot fseek('.$pos.'). resource/stream does not appear to support seeking', 10);
* @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) {
$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--;
if ($this->data_string_position >= $this->data_string_length) {
// 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);
$thischar = fgetc($this->getid3->fp);
if (($prevchar == "\r") && ($thischar != "\n")) {
// read one byte too many, back up
fseek($this->getid3->fp, -1, SEEK_CUR);
if (feof($this->getid3->fp)) {
protected function feof() {
if ($this->data_string_flag) {
return $this->data_string_position >= $this->data_string_length;
return feof($this->getid3->fp);
final protected function isDependencyFor($module) {
return $this->dependency_to == $module;
protected function error($text) {
$this->getid3->info['error'][] = $text;
protected function warning($text) {
return $this->getid3->warning($text);
protected function notice($text) {
* @param string $image_mime
* @throws getid3_exception
public function saveAttachment($name, $offset, $length, $image_mime=null) {
if ($this->getid3->option_save_attachments === getID3::ATTACHMENTS_NONE) {
$attachment = null; // do not set any
// extract to return array
} elseif ($this->getid3->option_save_attachments === getID3::ATTACHMENTS_INLINE) {
$attachment = $this->fread($length); // get whole data in one pass, till it is anyway stored in memory
if ($attachment === false || strlen($attachment) != $length) {
throw new Exception('failed to read attachment data');
// assume directory path is given
// set up destination path
$dir = rtrim(str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $this->getid3->option_save_attachments), DIRECTORY_SEPARATOR);
if (!is_dir($dir) || !getID3::is_writable($dir)) { // check supplied directory
throw new Exception('supplied path ('.$dir.') does not exist, or is not writable');
$dest = $dir.DIRECTORY_SEPARATOR.$name.($image_mime ? '.'.getid3_lib::ImageExtFromMime($image_mime) : '');
if (($fp_dest = fopen($dest, 'wb')) == false) {
throw new Exception('failed to create file '.$dest);
$buffersize = ($this->data_string_flag ? $length : $this->getid3->fread_buffer_size());
if (($buffer = $this->fread(min($buffersize, $bytesleft))) === false || ($byteswritten = fwrite($fp_dest, $buffer)) === false || ($byteswritten === 0)) {
throw new Exception($buffer === false ? 'not enough data to read' : 'failed to write to destination file, may be not enough disk space');
$bytesleft -= $byteswritten;
// close and remove dest file if created
if (isset($fp_dest) && is_resource($fp_dest)) {
if (isset($dest) && file_exists($dest)) {
// do not set any is case of error
$this->warning('Failed to extract attachment '.$name.': '.$e->getMessage());
// seek to the end of attachment
$this->fseek($offset + $length);
class getid3_exception extends Exception