public function analyze() { /** * Overall tag structure: * +-----------------------------+ * | Header (10 bytes) | * +-----------------------------+ * | Extended Header | * | (variable length, OPTIONAL) | * +-----------------------------+ * | Frames (variable length) | * +-----------------------------+ * | Padding | * | (variable length, OPTIONAL) | * +-----------------------------+ * | Footer (10 bytes, OPTIONAL) | * +-----------------------------+ * * Header * ID3v2/file identifier "ID3" * ID3v2 version $04 00 * ID3v2 flags (%ab000000 in v2.2, %abc00000 in v2.3, %abcd0000 in v2.4.x) * ID3v2 size 4 * %0xxxxxxx */ //$fp = $this->_id3->getFilePointer(); $this->_tagInfo = $this->_id3->getFileInfo(); $this->_tagInfo['id3v2']['flags'] = array(); $this->fseek($this->_startingOffset, SEEK_SET); $header = $this->fread(10); if (substr($header, 0, 3) == 'ID3' && strlen($header) == 10) { $this->_tagInfo['id3v2']['majorversion'] = ord($header[3]); $this->_tagInfo['id3v2']['minorversion'] = ord($header[4]); $this->_tagMajorVersion = $this->_tagInfo['id3v2']['majorversion']; } else { return false; } /** * The current max major version is 4 so that's what we support up to. */ if ($this->_tagMajorVersion > 4) { include_once 'Zend/Id3/Adapter/Exception.php'; throw new Zend_Id3_Adapter_Exception('Zend_Id3_Adapter_Id3v2 can only parse upt to Id3v2.4'); } $this->_tagInfo['id3v2']['flags'] = $this->_processTagFlags(ord($header[5])); // length of ID3v2 tag in 10-byte header doesn't include 10-byte header length $this->_tagInfo['id3v2']['headerlength'] = Zend_Id3_ByteConvert::bigEndianSyncSafe2Int(substr($header, 6, 4)) + 10; $this->_tagInfo['id3v2']['tag_offset_start'] = $this->_startingOffset; $this->_tagInfo['id3v2']['tag_offset_end'] = $this->_tagInfo['id3v2']['tag_offset_start'] + $this->_tagInfo['id3v2']['headerlength']; $this->_parseFrameData(); $this->_id3->setFileInfo($this->_tagInfo); return true; }
/** * Parse frame out from v2.3 and higher tags * * Frame ID $xx xx xx xx (four characters) * Size $xx xx xx xx (32-bit integer in v2.3, 28-bit synchsafe in v2.4+) * Flags $xx xx * * @param string $frameData */ protected function _getFrame($frameData) { $info = array(); // take next 10 bytes for header $info['frameHeader'] = substr($frameData, 0, 10); // and leave the rest in $frame_data $info['frameData'] = substr($frameData, 10); $info['frameName'] = substr($info['frameHeader'], 0, 4); $info['frameSize'] = $this->_tagVersion == 3 ? Zend_Id3_ByteConvert::bigEndian2Int(substr($info['frameHeader'], 4, 4)) : Zend_Id3_ByteConvert::bigEndianSyncSafe2Int(substr($info['frameHeader'], 4, 4)); if ($info['frameSize'] < strlen($frameData) + 4) { $arrBrokenMP3extFrames = array("" . 'MP3', "" . 'MP', ' MP3', 'MP3e'); $nextFrameID = substr($frameData, $info['frameSize'], 4); if ($this->_isValidID3v2FrameName($nextFrameID)) { // next frame is OK } else { if (in_array($info['frameName'], $arrBrokenMP3extFrames)) { // MP3ext known broken frames - "ok" for the purposes of this test } else { if ($this->_tagVersion == 4 && $this->_isValidID3v2FrameName(substr($info['frameData'], Zend_Id3_ByteConvert::bigEndian2Int(substr($info['frameHeader'], 4, 4)), 4), 3)) { $this->_tagVersion = 3; $info['frameSize'] = Zend_Id3_ByteConvert::bigEndian2Int(substr($info['frameHeader'], 4, 4)); // 32-bit integer } } } } $info['frameFlag'] = Zend_Id3_ByteConvert::bigEndian2Int(substr($info['frameHeader'], 8, 2)); // padding encountered if ($info['frameName'] == "") { return $this->_parsePadding($info['frameData'], $info['frameHeader']); } return $info; }