public function DeleteLyrics3() { // Initialize GetId3 engine $getID3 = new GetId3Core(); $ThisFileInfo = $getID3->analyze($this->filename); if (isset($ThisFileInfo['lyrics3']['tag_offset_start']) && isset($ThisFileInfo['lyrics3']['tag_offset_end'])) { if (is_readable($this->filename) && is_writable($this->filename) && is_file($this->filename) && ($fp = fopen($this->filename, 'a+b'))) { flock($fp, LOCK_EX); $oldignoreuserabort = ignore_user_abort(true); fseek($fp, $ThisFileInfo['lyrics3']['tag_offset_end'], SEEK_SET); $DataAfterLyrics3 = ''; if ($ThisFileInfo['filesize'] > $ThisFileInfo['lyrics3']['tag_offset_end']) { $DataAfterLyrics3 = fread($fp, $ThisFileInfo['filesize'] - $ThisFileInfo['lyrics3']['tag_offset_end']); } ftruncate($fp, $ThisFileInfo['lyrics3']['tag_offset_start']); if (!empty($DataAfterLyrics3)) { fseek($fp, $ThisFileInfo['lyrics3']['tag_offset_start'], SEEK_SET); fwrite($fp, $DataAfterLyrics3, strlen($DataAfterLyrics3)); } flock($fp, LOCK_UN); fclose($fp); ignore_user_abort($oldignoreuserabort); return true; } else { $this->errors[] = 'Cannot fopen(' . $this->filename . ', "a+b")'; return false; } } // no Lyrics3 present return true; }
/** * @return bool */ public function setRealFileSize() { if (PHP_INT_MAX > 2147483647) { $this->filesize = filesize($this->filename); return true; } // 32-bit PHP will not return correct values for filesize() if file is >=2GB // but GetId3->analyze() has workarounds to get actual filesize $getID3 = new GetId3Core(); $getID3->option_tag_id3v1 = false; $getID3->option_tag_id3v2 = false; $getID3->option_tag_apetag = false; $getID3->option_tags_html = false; $getID3->option_extra_info = false; $ThisFileInfo = $getID3->analyze($this->filename); $this->filesize = $ThisFileInfo['filesize']; return true; }
/** * @return bool */ public function DeleteAPEtag() { $getID3 = new GetId3Core(); $ThisFileInfo = $getID3->analyze($this->filename); if (isset($ThisFileInfo['ape']['tag_offset_start']) && isset($ThisFileInfo['ape']['tag_offset_end'])) { if (is_writable($this->filename) && is_file($this->filename) && ($fp = fopen($this->filename, 'a+b'))) { flock($fp, LOCK_EX); $oldignoreuserabort = ignore_user_abort(true); fseek($fp, $ThisFileInfo['ape']['tag_offset_end'], SEEK_SET); $DataAfterAPE = ''; if ($ThisFileInfo['filesize'] > $ThisFileInfo['ape']['tag_offset_end']) { $DataAfterAPE = fread($fp, $ThisFileInfo['filesize'] - $ThisFileInfo['ape']['tag_offset_end']); } ftruncate($fp, $ThisFileInfo['ape']['tag_offset_start']); fseek($fp, $ThisFileInfo['ape']['tag_offset_start'], SEEK_SET); if (!empty($DataAfterAPE)) { fwrite($fp, $DataAfterAPE, strlen($DataAfterAPE)); } flock($fp, LOCK_UN); fclose($fp); ignore_user_abort($oldignoreuserabort); return true; } return false; } return true; }
/** * @return bool */ public function RemoveReal() { // File MUST be writeable - CHMOD(646) at least if (is_writable($this->filename) && is_file($this->filename) && ($fp_source = fopen($this->filename, 'r+b'))) { // Initialize GetId3 engine $getID3 = new GetId3Core(); $OldThisFileInfo = $getID3->analyze($this->filename); if (empty($OldThisFileInfo['real']['chunks']) && !empty($OldThisFileInfo['real']['old_ra_header'])) { $this->errors[] = 'Cannot remove Real tags from old-style file format'; fclose($fp_source); return false; } if (empty($OldThisFileInfo['real']['chunks'])) { $this->errors[] = 'Cannot remove Real tags because cannot find DATA chunk in file'; fclose($fp_source); return false; } foreach ($OldThisFileInfo['real']['chunks'] as $chunknumber => $chunkarray) { $oldChunkInfo[$chunkarray['name']] = $chunkarray; } if (empty($oldChunkInfo['CONT'])) { // no existing CONT chunk fclose($fp_source); return true; } $BeforeOffset = $oldChunkInfo['CONT']['offset']; $AfterOffset = $oldChunkInfo['CONT']['offset'] + $oldChunkInfo['CONT']['length']; if ($tempfilename = tempnam(GetId3Core::getTempDir(), 'getID3')) { if (is_writable($tempfilename) && is_file($tempfilename) && ($fp_temp = fopen($tempfilename, 'wb'))) { rewind($fp_source); fwrite($fp_temp, fread($fp_source, $BeforeOffset)); fseek($fp_source, $AfterOffset, SEEK_SET); while ($buffer = fread($fp_source, $this->fread_buffer_size)) { fwrite($fp_temp, $buffer, strlen($buffer)); } fclose($fp_temp); if (copy($tempfilename, $this->filename)) { unlink($tempfilename); fclose($fp_source); return true; } unlink($tempfilename); $this->errors[] = 'FAILED: copy(' . $tempfilename . ', ' . $this->filename . ')'; } else { $this->errors[] = 'Could not fopen("' . $tempfilename . '", "wb")'; } } fclose($fp_source); return false; } $this->errors[] = 'Could not fopen("' . $this->filename . '", "r+b")'; return false; }
/** * @return bool */ public function WriteTags() { if (empty($this->filename)) { $this->errors[] = 'filename is undefined in GetId3_writetags'; return false; } elseif (!file_exists($this->filename)) { $this->errors[] = 'filename set to non-existant file "' . $this->filename . '" in GetId3_writetags'; return false; } if (!is_array($this->tagformats)) { $this->errors[] = 'tagformats must be an array in GetId3_writetags'; return false; } $TagFormatsToRemove = array(); if (filesize($this->filename) == 0) { // empty file special case - allow any tag format, don't check existing format // could be useful if you want to generate tag data for a non-existant file $this->ThisFileInfo = array('fileformat' => ''); $AllowedTagFormats = array('id3v1', 'id3v2.2', 'id3v2.3', 'id3v2.4', 'ape', 'lyrics3'); } else { $getID3 = new GetId3Core(); $getID3->setEncoding($this->tag_encoding); $this->ThisFileInfo = $getID3->analyze($this->filename); // check for what file types are allowed on this fileformat switch (isset($this->ThisFileInfo['fileformat']) ? $this->ThisFileInfo['fileformat'] : '') { case 'mp3': case 'mp2': case 'mp1': case 'riff': // maybe not officially, but people do it anyway $AllowedTagFormats = array('id3v1', 'id3v2.2', 'id3v2.3', 'id3v2.4', 'ape', 'lyrics3'); break; case 'mpc': $AllowedTagFormats = array('ape'); break; case 'flac': $AllowedTagFormats = array('metaflac'); break; case 'real': $AllowedTagFormats = array('real'); break; case 'ogg': switch (isset($this->ThisFileInfo['audio']['dataformat']) ? $this->ThisFileInfo['audio']['dataformat'] : '') { case 'flac': //$AllowedTagFormats = array('metaflac'); $this->errors[] = 'metaflac is not (yet) compatible with OggFLAC files'; return false; break; case 'vorbis': $AllowedTagFormats = array('vorbiscomment'); break; default: $this->errors[] = 'metaflac is not (yet) compatible with Ogg files other than OggVorbis'; return false; break; } break; default: $AllowedTagFormats = array(); break; } foreach ($this->tagformats as $requested_tag_format) { if (!in_array($requested_tag_format, $AllowedTagFormats)) { $errormessage = 'Tag format "' . $requested_tag_format . '" is not allowed on "' . (isset($this->ThisFileInfo['fileformat']) ? $this->ThisFileInfo['fileformat'] : ''); $errormessage .= isset($this->ThisFileInfo['audio']['dataformat']) ? '.' . $this->ThisFileInfo['audio']['dataformat'] : ''; $errormessage .= '" files'; $this->errors[] = $errormessage; return false; } } // List of other tag formats, removed if requested if ($this->remove_other_tags) { foreach ($AllowedTagFormats as $AllowedTagFormat) { switch ($AllowedTagFormat) { case 'id3v2.2': case 'id3v2.3': case 'id3v2.4': if (!in_array('id3v2', $TagFormatsToRemove) && !in_array('id3v2.2', $this->tagformats) && !in_array('id3v2.3', $this->tagformats) && !in_array('id3v2.4', $this->tagformats)) { $TagFormatsToRemove[] = 'id3v2'; } break; default: if (!in_array($AllowedTagFormat, $this->tagformats)) { $TagFormatsToRemove[] = $AllowedTagFormat; } break; } } } } $WritingFilesToInclude = array_merge($this->tagformats, $TagFormatsToRemove); // Check for required include files and include them foreach ($WritingFilesToInclude as $tagformat) { switch ($tagformat) { case 'ape': $GETID3_ERRORARRAY =& $this->errors; if (!class_exists('Helpers\\GetId3\\Write\\Apetag')) { return false; } break; case 'id3v1': case 'lyrics3': case 'vorbiscomment': case 'metaflac': case 'real': $GETID3_ERRORARRAY =& $this->errors; if (!class_exists('Helpers\\GetId3\\Write\\' . ucfirst($tagformat))) { return false; } break; case 'id3v2.2': case 'id3v2.3': case 'id3v2.4': case 'id3v2': $GETID3_ERRORARRAY =& $this->errors; if (!class_exists('Helpers\\GetId3\\Write\\Id3v2')) { return false; } break; default: $this->errors[] = 'unknown tag format "' . $tagformat . '" in $tagformats in WriteTags()'; return false; break; } } // Validation of supplied data if (!is_array($this->tag_data)) { $this->errors[] = '$this->tag_data is not an array in WriteTags()'; return false; } // convert supplied data array keys to upper case, if they're not already foreach ($this->tag_data as $tag_key => $tag_array) { if (strtoupper($tag_key) !== $tag_key) { $this->tag_data[strtoupper($tag_key)] = $this->tag_data[$tag_key]; unset($this->tag_data[$tag_key]); } } // convert source data array keys to upper case, if they're not already if (!empty($this->ThisFileInfo['tags'])) { foreach ($this->ThisFileInfo['tags'] as $tag_format => $tag_data_array) { foreach ($tag_data_array as $tag_key => $tag_array) { if (strtoupper($tag_key) !== $tag_key) { $this->ThisFileInfo['tags'][$tag_format][strtoupper($tag_key)] = $this->ThisFileInfo['tags'][$tag_format][$tag_key]; unset($this->ThisFileInfo['tags'][$tag_format][$tag_key]); } } } } // Convert "TRACK" to "TRACKNUMBER" (if needed) for compatability with all formats if (isset($this->tag_data['TRACK']) && !isset($this->tag_data['TRACKNUMBER'])) { $this->tag_data['TRACKNUMBER'] = $this->tag_data['TRACK']; unset($this->tag_data['TRACK']); } // Remove all other tag formats, if requested if ($this->remove_other_tags) { $this->DeleteTags($TagFormatsToRemove); } // Write data for each tag format foreach ($this->tagformats as $tagformat) { $success = false; // overridden if tag writing is successful switch ($tagformat) { case 'ape': $ape_writer = new Apetag(); if (($ape_writer->tag_data = $this->FormatDataForAPE()) !== false) { $ape_writer->filename = $this->filename; if (($success = $ape_writer->WriteAPEtag()) === false) { $this->errors[] = 'WriteAPEtag() failed with message(s):<pre><ul><li>' . str_replace("\n", '</li><li>', htmlentities(trim(implode("\n", $ape_writer->errors)))) . '</li></ul></pre>'; } } else { $this->errors[] = 'FormatDataForAPE() failed'; } break; case 'id3v1': $id3v1_writer = new Id3v1(); if (($id3v1_writer->tag_data = $this->FormatDataForID3v1()) !== false) { $id3v1_writer->filename = $this->filename; if (($success = $id3v1_writer->WriteID3v1()) === false) { $this->errors[] = 'WriteID3v1() failed with message(s):<pre><ul><li>' . str_replace("\n", '</li><li>', htmlentities(trim(implode("\n", $id3v1_writer->errors)))) . '</li></ul></pre>'; } } else { $this->errors[] = 'FormatDataForID3v1() failed'; } break; case 'id3v2.2': case 'id3v2.3': case 'id3v2.4': $id3v2_writer = new Id3v2(); $id3v2_writer->majorversion = intval(substr($tagformat, -1)); $id3v2_writer->paddedlength = $this->id3v2_paddedlength; if (($id3v2_writer->tag_data = $this->FormatDataForID3v2($id3v2_writer->majorversion)) !== false) { $id3v2_writer->filename = $this->filename; if (($success = $id3v2_writer->WriteID3v2()) === false) { $this->errors[] = 'WriteID3v2() failed with message(s):<pre><ul><li>' . str_replace("\n", '</li><li>', htmlentities(trim(implode("\n", $id3v2_writer->errors)))) . '</li></ul></pre>'; } } else { $this->errors[] = 'FormatDataForID3v2() failed'; } break; case 'vorbiscomment': $vorbiscomment_writer = new Vorbiscomment(); if (($vorbiscomment_writer->tag_data = $this->FormatDataForVorbisComment()) !== false) { $vorbiscomment_writer->filename = $this->filename; if (($success = $vorbiscomment_writer->WriteVorbisComment()) === false) { $this->errors[] = 'WriteVorbisComment() failed with message(s):<pre><ul><li>' . str_replace("\n", '</li><li>', htmlentities(trim(implode("\n", $vorbiscomment_writer->errors)))) . '</li></ul></pre>'; } } else { $this->errors[] = 'FormatDataForVorbisComment() failed'; } break; case 'metaflac': $metaflac_writer = new Metaflac(); if (($metaflac_writer->tag_data = $this->FormatDataForMetaFLAC()) !== false) { $metaflac_writer->filename = $this->filename; if (($success = $metaflac_writer->WriteMetaFLAC()) === false) { $this->errors[] = 'WriteMetaFLAC() failed with message(s):<pre><ul><li>' . str_replace("\n", '</li><li>', htmlentities(trim(implode("\n", $metaflac_writer->errors)))) . '</li></ul></pre>'; } } else { $this->errors[] = 'FormatDataForMetaFLAC() failed'; } break; case 'real': $real_writer = new Real(); if (($real_writer->tag_data = $this->FormatDataForReal()) !== false) { $real_writer->filename = $this->filename; if (($success = $real_writer->WriteReal()) === false) { $this->errors[] = 'WriteReal() failed with message(s):<pre><ul><li>' . str_replace("\n", '</li><li>', htmlentities(trim(implode("\n", $real_writer->errors)))) . '</li></ul></pre>'; } } else { $this->errors[] = 'FormatDataForReal() failed'; } break; default: $this->errors[] = 'Invalid tag format to write: "' . $tagformat . '"'; return false; break; } if (!$success) { return false; } } return true; }
public function RemoveID3v2() { // File MUST be writeable - CHMOD(646) at least. It's best if the // directory is also writeable, because that method is both faster and less susceptible to errors. if (is_writable(dirname($this->filename))) { // preferred method - only one copying operation, minimal chance of corrupting // original file if script is interrupted, but required directory to be writeable if (is_readable($this->filename) && is_file($this->filename) && ($fp_source = fopen($this->filename, 'rb'))) { // Initialize GetId3 engine $getID3 = new GetId3Core(); $OldThisFileInfo = $getID3->analyze($this->filename); if (!Helper::intValueSupported($OldThisFileInfo['filesize'])) { $this->errors[] = 'Unable to remove ID3v2 because file is larger than ' . round(PHP_INT_MAX / 1073741824) . 'GB'; fclose($fp_source); return false; } rewind($fp_source); if ($OldThisFileInfo['avdataoffset'] !== false) { fseek($fp_source, $OldThisFileInfo['avdataoffset'], SEEK_SET); } if (is_writable($this->filename) && is_file($this->filename) && ($fp_temp = fopen($this->filename . 'getid3tmp', 'w+b'))) { while ($buffer = fread($fp_source, $this->fread_buffer_size)) { fwrite($fp_temp, $buffer, strlen($buffer)); } fclose($fp_temp); } else { $this->errors[] = 'Could not fopen("' . $this->filename . 'getid3tmp", "w+b")'; } fclose($fp_source); } else { $this->errors[] = 'Could not fopen("' . $this->filename . '", "rb")'; } if (file_exists($this->filename)) { unlink($this->filename); } rename($this->filename . 'getid3tmp', $this->filename); } elseif (is_writable($this->filename)) { // less desirable alternate method - double-copies the file, overwrites original file // and could corrupt source file if the script is interrupted or an error occurs. if (is_readable($this->filename) && is_file($this->filename) && ($fp_source = fopen($this->filename, 'rb'))) { // Initialize GetId3 engine $getID3 = new GetId3Core(); $OldThisFileInfo = $getID3->analyze($this->filename); if (!Helper::intValueSupported($OldThisFileInfo['filesize'])) { $this->errors[] = 'Unable to remove ID3v2 because file is larger than ' . round(PHP_INT_MAX / 1073741824) . 'GB'; fclose($fp_source); return false; } rewind($fp_source); if ($OldThisFileInfo['avdataoffset'] !== false) { fseek($fp_source, $OldThisFileInfo['avdataoffset'], SEEK_SET); } if ($fp_temp = tmpfile()) { while ($buffer = fread($fp_source, $this->fread_buffer_size)) { fwrite($fp_temp, $buffer, strlen($buffer)); } fclose($fp_source); if (is_writable($this->filename) && is_file($this->filename) && ($fp_source = fopen($this->filename, 'wb'))) { rewind($fp_temp); while ($buffer = fread($fp_temp, $this->fread_buffer_size)) { fwrite($fp_source, $buffer, strlen($buffer)); } fseek($fp_temp, -128, SEEK_END); fclose($fp_source); } else { $this->errors[] = 'Could not fopen("' . $this->filename . '", "wb")'; } fclose($fp_temp); } else { $this->errors[] = 'Could not create tmpfile()'; } } else { $this->errors[] = 'Could not fopen("' . $this->filename . '", "rb")'; } } else { $this->errors[] = 'Directory and file both not writeable'; } if (!empty($this->errors)) { return false; } return true; }