diff --git a/src/Zend/Media/Id3v1.php b/src/Zend/Media/Id3v1.php index 977218c..919f3a2 100644 --- a/src/Zend/Media/Id3v1.php +++ b/src/Zend/Media/Id3v1.php @@ -164,7 +164,7 @@ public function __construct($filename = null) */ public function getTitle() { - return $this->_title; + return $this->_title; } /** @@ -175,7 +175,7 @@ public function getTitle() */ public function setTitle($title) { - $this->_title = $title; + $this->_title = $title; } /** @@ -185,7 +185,7 @@ public function setTitle($title) */ public function getArtist() { - return $this->_artist; + return $this->_artist; } /** @@ -196,7 +196,7 @@ public function getArtist() */ public function setArtist($artist) { - $this->_artist = $artist; + $this->_artist = $artist; } /** @@ -206,7 +206,7 @@ public function setArtist($artist) */ public function getAlbum() { - return $this->_album; + return $this->_album; } /** @@ -217,7 +217,7 @@ public function getAlbum() */ public function setAlbum($album) { - $this->_album = $album; + $this->_album = $album; } /** @@ -227,7 +227,7 @@ public function setAlbum($album) */ public function getYear() { - return $this->_year; + return $this->_year; } /** @@ -238,7 +238,7 @@ public function getYear() */ public function setYear($year) { - $this->_year = $year; + $this->_year = $year; } /** @@ -248,7 +248,7 @@ public function setYear($year) */ public function getComment() { - return $this->_comment; + return $this->_comment; } /** @@ -259,7 +259,7 @@ public function getComment() */ public function setComment($comment) { - $this->_comment = $comment; + $this->_comment = $comment; } /** @@ -270,7 +270,7 @@ public function setComment($comment) */ public function getTrack() { - return $this->_track; + return $this->_track; } /** @@ -282,7 +282,7 @@ public function getTrack() */ public function setTrack($track) { - $this->_track = $track; + $this->_track = $track; } /** @@ -368,6 +368,20 @@ public function write($filename = null) $this->_filename = $filename; } + /** + * Removes the ID3v1 tag altogether. + * + * @param string $filename The path to the file. + */ + public static function remove($filename) + { + $reader = new Zend_Io_FileReader($filename, 'r+b'); + $reader->setOffset(-128); + if ($reader->read(3) == 'TAG') { + ftruncate($reader->getFileDescriptor(), $reader->getSize() - 128); + } + } + /** * Magic function so that $obj->value will work. * diff --git a/src/Zend/Media/Id3v2.php b/src/Zend/Media/Id3v2.php index ccb81cf..21c0d4c 100644 --- a/src/Zend/Media/Id3v2.php +++ b/src/Zend/Media/Id3v2.php @@ -81,6 +81,12 @@ final class Zend_Media_Id3v2 extends Zend_Media_Id3_Object * o version -- The ID3v2 tag version to use in write operation. This * option is automatically set when a tag is read from a file and * defaults to version 4.0 for tag write. + * o compat -- Normally unsynchronization is handled automatically behind + * the scenes. However, current versions of Windows operating system and + * Windows Media Player, just to name a few, do not support ID3v2.4 tags + * nor ID3v2.3 tags with unsynchronization. Hence, for compatibility + * reasons, this option is made available to disable automatic tag level + * unsynchronization scheme that version 3.0 supports. * o readonly -- Indicates that the tag is read from a temporary file or * another source it cannot be written back to. The tag can, however, * still be written to another file. @@ -150,9 +156,9 @@ public function __construct($filename = null, $options = array()) ($this->_decodeUnsynchronisation($data)); $tagSize = $this->_reader->getSize(); } - $this->clearOption('unsyncronisation'); + $this->clearOption('unsynchronisation'); if ($this->_header->hasFlag(Zend_Media_Id3_Header::UNSYNCHRONISATION)) { - $this->setOption('unsyncronisation', true); + $this->setOption('unsynchronisation', true); } if ($this->_header->hasFlag(Zend_Media_Id3_Header::EXTENDED_HEADER)) { require_once 'Zend/Media/Id3/ExtendedHeader.php'; @@ -433,8 +439,8 @@ public function setFooter($useFooter) * here as an argument. Regardless, the write operation will override * previous tag information, if found. * - * If write is called without setting any frames to the tag, the tag is - * removed from the file. + * If write is called on a tag without any frames to it, current tag is + * removed from the file altogether. * * @param string|Zend_Io_Writer $filename The optional path to the file, use * null to save to the same file. @@ -443,8 +449,7 @@ public function write($filename) { if ($filename === null && ($filename = $this->_filename) === null) { require_once 'Zend/Media/Id3/Exception.php'; - throw new Zend_Media_Id3_Exception - ('No file given to write to'); + throw new Zend_Media_Id3_Exception('No file given to write to'); } else if ($filename !== null && $filename instanceof Zend_Io_Writer) { require_once 'Zend/Io/Writer.php'; $this->_writeData($filename); @@ -465,6 +470,18 @@ public function write($filename) ('Unable to open file for writing: ' . $filename); } + $hasNoFrames = true; + foreach ($this->_frames as $identifier => $instances) { + if (count($instances) > 0) { + $hasNoFrames = false; + break; + } + } + if ($hasNoFrames === true) { + $this->remove(new Zend_Io_Reader($fd)); + return; + } + if ($this->_reader !== null) { $oldTagSize = 10 /* header */ + $this->_header->getSize(); } else { @@ -479,9 +496,9 @@ public function write($filename) require_once 'Zend/Io/StringWriter.php'; $tag = new Zend_Io_StringWriter(); $this->_writeData($tag); - $tagSize = empty($this->_frames) ? 0 : $tag->getSize(); - - if ($tagSize > $oldTagSize || $tagSize == 0) { + $tagSize = $tag->getSize(); + + if ($tagSize > $oldTagSize) { fseek($fd, 0, SEEK_END); $oldFileSize = ftell($fd); ftruncate @@ -501,7 +518,7 @@ public function write($filename) } } if (($remaining = $oldFileSize % 1024) != 0) { - + // huh? } fseek($fd, 0, SEEK_END); } @@ -523,7 +540,7 @@ public function write($filename) */ private function _writeData($writer) { - $this->clearOption('unsyncronisation'); + $this->clearOption('unsynchronisation'); $buffer = new Zend_Io_StringWriter(); foreach ($this->_frames as $frames) { @@ -535,17 +552,10 @@ private function _writeData($writer) $frameDataLength = strlen($frameData); $paddingLength = 0; - // ID3v2.4.0 supports frame level unsynchronisation. The corresponding - // option is set to true when any of the frames use the - // unsynchronisation scheme. - if ($this->getOption('unsyncronisation', false) === true) { - $this->_header->setFlags - ($this->_header->getFlags() | - Zend_Media_Id3_Header::UNSYNCHRONISATION); - } - - // ID3v2.3.0 supports only tag level unsynchronisation - if ($this->getOption('version', 4) < 4) { + // ID3v2.4.0 supports frame level unsynchronisation while + // ID3v2.3.0 supports only tag level unsynchronisation. + if ($this->getOption('version', 4) < 4 && + $this->getOption('compat', false) !== true) { $frameData = $this->_encodeUnsynchronisation($frameData); if (($len = strlen($frameData)) != $frameDataLength) { $frameDataLength = $len; @@ -615,6 +625,36 @@ private function _writeData($writer) } } + /** + * Removes the ID3v2 tag altogether. + * + * @param string $filename The path to the file. + */ + public static function remove($filename) + { + if ($filename instanceof Zend_Io_Reader) { + $reader = &$filename; + } else { + require_once 'Zend/Io/FileReader.php'; + $reader = new Zend_Io_FileReader($filename, 'r+b'); + } + + $fileSize = $reader->getSize(); + if ($reader->read(3) == 'ID3') { + $header = new Zend_Media_Id3_Header($reader); + $tagSize = 10 /* header */ + $header->getSize(); + } else return; + + $fd = $reader->getFileDescriptor(); + for ($i = 0; $tagSize + ($i * 1024) < $fileSize; $i++) { + fseek($fd, $tagSize + ($i * 1024)); + $buffer = fread($fd, 1024); + fseek($fd, ($i * 1024)); + $bytes = fwrite($fd, $buffer, 1024); + } + ftruncate($fd, $fileSize - $tagSize); + } + /** * Magic function so that $obj->value will work. The method will attempt to * return the first frame that matches the identifier.