public function Analyze()
 {
     $getid3 = $this->getid3;
     // dependency
     $getid3->include_module('tag.id3v1');
     if ($getid3->option_tags_images) {
         $getid3->include_module('lib.image_size');
     }
     //    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
     // shortcuts
     $getid3->info['id3v2']['header'] = true;
     $info_id3v2 =& $getid3->info['id3v2'];
     $info_id3v2['flags'] = array();
     $info_id3v2_flags =& $info_id3v2['flags'];
     $this->fseek($this->option_starting_offset, SEEK_SET);
     $header = $this->fread(10);
     if (substr($header, 0, 3) == 'ID3' && strlen($header) == 10) {
         $info_id3v2['majorversion'] = ord($header[3]);
         $info_id3v2['minorversion'] = ord($header[4]);
         // shortcut
         $id3v2_major_version =& $info_id3v2['majorversion'];
     } else {
         unset($getid3->info['id3v2']);
         return false;
     }
     if ($id3v2_major_version > 4) {
         // this script probably won't correctly parse ID3v2.5.x and above (if it ever exists)
         throw new getid3_exception('this script only parses up to ID3v2.4.x - this tag is ID3v2.' . $id3v2_major_version . '.' . $info_id3v2['minorversion']);
     }
     $id3_flags = ord($header[5]);
     switch ($id3v2_major_version) {
         case 2:
             // %ab000000 in v2.2
             $info_id3v2_flags['unsynch'] = (bool) ($id3_flags & 0x80);
             // a - Unsynchronisation
             $info_id3v2_flags['compression'] = (bool) ($id3_flags & 0x40);
             // b - Compression
             break;
         case 3:
             // %abc00000 in v2.3
             $info_id3v2_flags['unsynch'] = (bool) ($id3_flags & 0x80);
             // a - Unsynchronisation
             $info_id3v2_flags['exthead'] = (bool) ($id3_flags & 0x40);
             // b - Extended header
             $info_id3v2_flags['experim'] = (bool) ($id3_flags & 0x20);
             // c - Experimental indicator
             break;
         case 4:
             // %abcd0000 in v2.4
             $info_id3v2_flags['unsynch'] = (bool) ($id3_flags & 0x80);
             // a - Unsynchronisation
             $info_id3v2_flags['exthead'] = (bool) ($id3_flags & 0x40);
             // b - Extended header
             $info_id3v2_flags['experim'] = (bool) ($id3_flags & 0x20);
             // c - Experimental indicator
             $info_id3v2_flags['isfooter'] = (bool) ($id3_flags & 0x10);
             // d - Footer present
             break;
     }
     $info_id3v2['headerlength'] = getid3_lib::BigEndianSyncSafe2Int(substr($header, 6, 4)) + 10;
     // length of ID3v2 tag in 10-byte header doesn't include 10-byte header length
     $info_id3v2['tag_offset_start'] = $this->option_starting_offset;
     $info_id3v2['tag_offset_end'] = $info_id3v2['tag_offset_start'] + $info_id3v2['headerlength'];
     // Frames
     //     All ID3v2 frames consists of one frame header followed by one or more
     //     fields containing the actual information. The header is always 10
     //     bytes and laid out as follows:
     //
     //     Frame ID      $xx xx xx xx  (four characters)
     //     Size      4 * %0xxxxxxx
     //     Flags         $xx xx
     $size_of_frames = $info_id3v2['headerlength'] - 10;
     // not including 10-byte initial header
     if (@$info_id3v2['exthead']['length']) {
         $size_of_frames -= $info_id3v2['exthead']['length'] + 4;
     }
     if (@$info_id3v2_flags['isfooter']) {
         $size_of_frames -= 10;
         // footer takes last 10 bytes of ID3v2 header, after frame data, before audio
     }
     if ($size_of_frames > 0) {
         $frame_data = $this->fread($size_of_frames);
         // read all frames from file into $frame_data variable
         //    if entire frame data is unsynched, de-unsynch it now (ID3v2.3.x)
         if (@$info_id3v2_flags['unsynch'] && $id3v2_major_version <= 3) {
             $frame_data = str_replace("ÿ", "ÿ", $frame_data);
         }
         //        [in ID3v2.4.0] Unsynchronisation [S:6.1] is done on frame level, instead
         //        of on tag level, making it easier to skip frames, increasing the streamability
         //        of the tag. The unsynchronisation flag in the header [S:3.1] indicates that
         //        there exists an unsynchronised frame, while the new unsynchronisation flag in
         //        the frame header [S:4.1.2] indicates unsynchronisation.
         //$frame_data_offset = 10 + (@$info_id3v2['exthead']['length'] ? $info_id3v2['exthead']['length'] + 4 : 0); // how many bytes into the stream - start from after the 10-byte header (and extended header length+4, if present)
         $frame_data_offset = 10;
         // how many bytes into the stream - start from after the 10-byte header
         //    Extended Header
         if (@$info_id3v2_flags['exthead']) {
             $extended_header_offset = 0;
             if ($id3v2_major_version == 3) {
                 // v2.3 definition:
                 //Extended header size  $xx xx xx xx   // 32-bit integer
                 //Extended Flags        $xx xx
                 //     %x0000000 %00000000 // v2.3
                 //     x - CRC data present
                 //Size of padding       $xx xx xx xx
                 $info_id3v2['exthead']['length'] = getid3_lib::BigEndian2Int(substr($frame_data, $extended_header_offset, 4), 0);
                 $extended_header_offset += 4;
                 $info_id3v2['exthead']['flag_bytes'] = 2;
                 $info_id3v2['exthead']['flag_raw'] = getid3_lib::BigEndian2Int(substr($frame_data, $extended_header_offset, $info_id3v2['exthead']['flag_bytes']));
                 $extended_header_offset += $info_id3v2['exthead']['flag_bytes'];
                 $info_id3v2['exthead']['flags']['crc'] = (bool) ($info_id3v2['exthead']['flag_raw'] & 0x8000);
                 $info_id3v2['exthead']['padding_size'] = getid3_lib::BigEndian2Int(substr($frame_data, $extended_header_offset, 4));
                 $extended_header_offset += 4;
                 if ($info_id3v2['exthead']['flags']['crc']) {
                     $info_id3v2['exthead']['flag_data']['crc'] = getid3_lib::BigEndian2Int(substr($frame_data, $extended_header_offset, 4));
                     $extended_header_offset += 4;
                 }
                 $extended_header_offset += $info_id3v2['exthead']['padding_size'];
             } elseif ($id3v2_major_version == 4) {
                 // v2.4 definition:
                 //Extended header size   4 * %0xxxxxxx // 28-bit synchsafe integer
                 //Number of flag bytes       $01
                 //Extended Flags             $xx
                 //     %0bcd0000 // v2.4
                 //     b - Tag is an update
                 //         Flag data length       $00
                 //     c - CRC data present
                 //         Flag data length       $05
                 //         Total frame CRC    5 * %0xxxxxxx
                 //     d - Tag restrictions
                 //         Flag data length       $01
                 $info_id3v2['exthead']['length'] = getid3_lib::BigEndian2Int(substr($frame_data, $extended_header_offset, 4), 1);
                 $extended_header_offset += 4;
                 $info_id3v2['exthead']['flag_bytes'] = 1;
                 $info_id3v2['exthead']['flag_raw'] = getid3_lib::BigEndian2Int(substr($frame_data, $extended_header_offset, $info_id3v2['exthead']['flag_bytes']));
                 $extended_header_offset += $info_id3v2['exthead']['flag_bytes'];
                 $info_id3v2['exthead']['flags']['update'] = (bool) ($info_id3v2['exthead']['flag_raw'] & 0x4000);
                 $info_id3v2['exthead']['flags']['crc'] = (bool) ($info_id3v2['exthead']['flag_raw'] & 0x2000);
                 $info_id3v2['exthead']['flags']['restrictions'] = (bool) ($info_id3v2['exthead']['flag_raw'] & 0x1000);
                 if ($info_id3v2['exthead']['flags']['crc']) {
                     $info_id3v2['exthead']['flag_data']['crc'] = getid3_lib::BigEndian2Int(substr($frame_data, $extended_header_offset, 5), 1);
                     $extended_header_offset += 5;
                 }
                 if ($info_id3v2['exthead']['flags']['restrictions']) {
                     // %ppqrrstt
                     $restrictions_raw = getid3_lib::BigEndian2Int(substr($frame_data, $extended_header_offset, 1));
                     $extended_header_offset += 1;
                     $info_id3v2['exthead']['flags']['restrictions']['tagsize'] = ($restrictions_raw && 0xc0) >> 6;
                     // p - Tag size restrictions
                     $info_id3v2['exthead']['flags']['restrictions']['textenc'] = ($restrictions_raw && 0x20) >> 5;
                     // q - Text encoding restrictions
                     $info_id3v2['exthead']['flags']['restrictions']['textsize'] = ($restrictions_raw && 0x18) >> 3;
                     // r - Text fields size restrictions
                     $info_id3v2['exthead']['flags']['restrictions']['imgenc'] = ($restrictions_raw && 0x4) >> 2;
                     // s - Image encoding restrictions
                     $info_id3v2['exthead']['flags']['restrictions']['imgsize'] = ($restrictions_raw && 0x3) >> 0;
                     // t - Image size restrictions
                 }
             }
             $frame_data_offset += $extended_header_offset;
             $frame_data = substr($frame_data, $extended_header_offset);
         }
         // end extended header
         while (isset($frame_data) && strlen($frame_data) > 0) {
             // cycle through until no more frame data is left to parse
             if (strlen($frame_data) <= ($id3v2_major_version == 2 ? 6 : 10)) {
                 // insufficient room left in ID3v2 header for actual data - must be padding
                 $info_id3v2['padding']['start'] = $frame_data_offset;
                 $info_id3v2['padding']['length'] = strlen($frame_data);
                 $info_id3v2['padding']['valid'] = true;
                 for ($i = 0; $i < $info_id3v2['padding']['length']; $i++) {
                     if ($frame_data[$i] != "") {
                         $info_id3v2['padding']['valid'] = false;
                         $info_id3v2['padding']['errorpos'] = $info_id3v2['padding']['start'] + $i;
                         $getid3->warning('Invalid ID3v2 padding found at offset ' . $info_id3v2['padding']['errorpos'] . ' (the remaining ' . ($info_id3v2['padding']['length'] - $i) . ' bytes are considered invalid)');
                         break;
                     }
                 }
                 break;
                 // skip rest of ID3v2 header
             }
             if ($id3v2_major_version == 2) {
                 // Frame ID  $xx xx xx (three characters)
                 // Size      $xx xx xx (24-bit integer)
                 // Flags     $xx xx
                 $frame_header = substr($frame_data, 0, 6);
                 // take next 6 bytes for header
                 $frame_data = substr($frame_data, 6);
                 // and leave the rest in $frame_data
                 $frame_name = substr($frame_header, 0, 3);
                 $frame_size = getid3_lib::BigEndian2Int(substr($frame_header, 3, 3));
                 $frame_flags = 0;
                 // not used for anything in ID3v2.2, just set to avoid E_NOTICEs
             } elseif ($id3v2_major_version > 2) {
                 // 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
                 $frame_header = substr($frame_data, 0, 10);
                 // take next 10 bytes for header
                 $frame_data = substr($frame_data, 10);
                 // and leave the rest in $frame_data
                 $frame_name = substr($frame_header, 0, 4);
                 if ($id3v2_major_version == 3) {
                     $frame_size = getid3_lib::BigEndian2Int(substr($frame_header, 4, 4));
                     // 32-bit integer
                 } else {
                     // ID3v2.4+
                     $frame_size = getid3_lib::BigEndianSyncSafe2Int(substr($frame_header, 4, 4));
                     // 32-bit synchsafe integer (28-bit value)
                 }
                 if ($frame_size < strlen($frame_data) + 4) {
                     $nextFrameID = substr($frame_data, $frame_size, 4);
                     if (getid3_id3v2::IsValidID3v2FrameName($nextFrameID, $id3v2_major_version)) {
                         // next frame is OK
                     } elseif ($frame_name == "" . 'MP3' || $frame_name == "" . 'MP' || $frame_name == ' MP3' || $frame_name == 'MP3e') {
                         // MP3ext known broken frames - "ok" for the purposes of this test
                     } elseif ($id3v2_major_version == 4 && getid3_id3v2::IsValidID3v2FrameName(substr($frame_data, getid3_lib::BigEndian2Int(substr($frame_header, 4, 4)), 4), 3)) {
                         $getid3->warning('ID3v2 tag written as ID3v2.4, but with non-synchsafe integers (ID3v2.3 style). Older versions of (Helium2; iTunes) are known culprits of this. Tag has been parsed as ID3v2.3');
                         $id3v2_major_version = 3;
                         $frame_size = getid3_lib::BigEndian2Int(substr($frame_header, 4, 4));
                         // 32-bit integer
                     }
                 }
                 $frame_flags = getid3_lib::BigEndian2Int(substr($frame_header, 8, 2));
             }
             if ($id3v2_major_version == 2 && $frame_name == "" || $frame_name == "") {
                 // padding encountered
                 $info_id3v2['padding']['start'] = $frame_data_offset;
                 $info_id3v2['padding']['length'] = strlen($frame_header) + strlen($frame_data);
                 $info_id3v2['padding']['valid'] = true;
                 $len = strlen($frame_data);
                 for ($i = 0; $i < $len; $i++) {
                     if ($frame_data[$i] != "") {
                         $info_id3v2['padding']['valid'] = false;
                         $info_id3v2['padding']['errorpos'] = $info_id3v2['padding']['start'] + $i;
                         $getid3->warning('Invalid ID3v2 padding found at offset ' . $info_id3v2['padding']['errorpos'] . ' (the remaining ' . ($info_id3v2['padding']['length'] - $i) . ' bytes are considered invalid)');
                         break;
                     }
                 }
                 break;
                 // skip rest of ID3v2 header
             }
             if ($frame_name == 'COM ') {
                 $getid3->warning('error parsing "' . $frame_name . '" (' . $frame_data_offset . ' bytes into the ID3v2.' . $id3v2_major_version . ' tag). (ERROR: IsValidID3v2FrameName("' . str_replace("", ' ', $frame_name) . '", ' . $id3v2_major_version . '))). [Note: this particular error has been known to happen with tags edited by iTunes (versions "X v2.0.3", "v3.0.1" are known-guilty, probably others too)]');
                 $frame_name = 'COMM';
             }
             if ($frame_size <= strlen($frame_data) && getid3_id3v2::IsValidID3v2FrameName($frame_name, $id3v2_major_version)) {
                 unset($parsed_frame);
                 $parsed_frame['frame_name'] = $frame_name;
                 $parsed_frame['frame_flags_raw'] = $frame_flags;
                 $parsed_frame['data'] = substr($frame_data, 0, $frame_size);
                 $parsed_frame['datalength'] = (int) $frame_size;
                 $parsed_frame['dataoffset'] = $frame_data_offset;
                 $this->ParseID3v2Frame($parsed_frame);
                 $info_id3v2[$frame_name][] = $parsed_frame;
                 $frame_data = substr($frame_data, $frame_size);
             } else {
                 // invalid frame length or FrameID
                 if ($frame_size <= strlen($frame_data)) {
                     if (getid3_id3v2::IsValidID3v2FrameName(substr($frame_data, $frame_size, 4), $id3v2_major_version)) {
                         // next frame is valid, just skip the current frame
                         $frame_data = substr($frame_data, $frame_size);
                         $getid3->warning('Next ID3v2 frame is valid, skipping current frame.');
                     } else {
                         // next frame is invalid too, abort processing
                         throw new getid3_exception('Next ID3v2 frame is also invalid, aborting processing.');
                     }
                 } elseif ($frame_size == strlen($frame_data)) {
                     // this is the last frame, just skip
                     $getid3->warning('This was the last ID3v2 frame.');
                 } else {
                     // next frame is invalid too, abort processing
                     $frame_data = null;
                     $getid3->warning('Invalid ID3v2 frame size, aborting.');
                 }
                 if (!getid3_id3v2::IsValidID3v2FrameName($frame_name, $id3v2_major_version)) {
                     switch ($frame_name) {
                         case "" . 'MP':
                         case "" . 'MP3':
                         case ' MP3':
                         case 'MP3e':
                         case "" . 'MP':
                         case ' MP':
                         case 'MP3':
                             $getid3->warning('error parsing "' . $frame_name . '" (' . $frame_data_offset . ' bytes into the ID3v2.' . $id3v2_major_version . ' tag). (ERROR: !IsValidID3v2FrameName("' . str_replace("", ' ', $frame_name) . '", ' . $id3v2_major_version . '))). [Note: this particular error has been known to happen with tags edited by "MP3ext (www.mutschler.de/mp3ext/)"]');
                             break;
                         default:
                             $getid3->warning('error parsing "' . $frame_name . '" (' . $frame_data_offset . ' bytes into the ID3v2.' . $id3v2_major_version . ' tag). (ERROR: !IsValidID3v2FrameName("' . str_replace("", ' ', $frame_name) . '", ' . $id3v2_major_version . '))).');
                             break;
                     }
                 } elseif ($frame_size > strlen(@$frame_data)) {
                     throw new getid3_exception('error parsing "' . $frame_name . '" (' . $frame_data_offset . ' bytes into the ID3v2.' . $id3v2_major_version . ' tag). (ERROR: $frame_size (' . $frame_size . ') > strlen($frame_data) (' . strlen($frame_data) . ')).');
                 } else {
                     throw new getid3_exception('error parsing "' . $frame_name . '" (' . $frame_data_offset . ' bytes into the ID3v2.' . $id3v2_major_version . ' tag).');
                 }
             }
             $frame_data_offset += $frame_size + ($id3v2_major_version == 2 ? 6 : 10);
         }
     }
     //    Footer
     //    The footer is a copy of the header, but with a different identifier.
     //        ID3v2 identifier           "3DI"
     //        ID3v2 version              $04 00
     //        ID3v2 flags                %abcd0000
     //        ID3v2 size             4 * %0xxxxxxx
     if (isset($info_id3v2_flags['isfooter']) && $info_id3v2_flags['isfooter']) {
         $footer = fread($getid3->fp, 10);
         if (substr($footer, 0, 3) == '3DI') {
             $info_id3v2['footer'] = true;
             $info_id3v2['majorversion_footer'] = ord($footer[3]);
             $info_id3v2['minorversion_footer'] = ord($footer[4]);
         }
         if ($info_id3v2['majorversion_footer'] <= 4) {
             $id3_flags = ord($footer[5]);
             $info_id3v2_flags['unsynch_footer'] = (bool) ($id3_flags & 0x80);
             $info_id3v2_flags['extfoot_footer'] = (bool) ($id3_flags & 0x40);
             $info_id3v2_flags['experim_footer'] = (bool) ($id3_flags & 0x20);
             $info_id3v2_flags['isfooter_footer'] = (bool) ($id3_flags & 0x10);
             $info_id3v2['footerlength'] = getid3_lib::BigEndianSyncSafe2Int(substr($footer, 6, 4));
         }
     }
     // end footer
     if (isset($info_id3v2['comments']['genre'])) {
         foreach ($info_id3v2['comments']['genre'] as $key => $value) {
             unset($info_id3v2['comments']['genre'][$key]);
             $info_id3v2['comments'] = getid3_id3v2::array_merge_noclobber($info_id3v2['comments'], getid3_id3v2::ParseID3v2GenreString($value));
         }
     }
     if (isset($info_id3v2['comments']['track'])) {
         foreach ($info_id3v2['comments']['track'] as $key => $value) {
             if (strstr($value, '/')) {
                 list($info_id3v2['comments']['track'][$key], $info_id3v2['comments']['totaltracks'][$key]) = explode('/', $info_id3v2['comments']['track'][$key]);
             }
         }
     }
     // Use year from recording time if year not set
     if (!isset($info_id3v2['comments']['year']) && ereg('^([0-9]{4})', @$info_id3v2['comments']['recording_time'][0], $matches)) {
         $info_id3v2['comments']['year'] = array($matches[1]);
     }
     // Set avdataoffset
     $getid3->info['avdataoffset'] = $info_id3v2['headerlength'];
     if (isset($info_id3v2['footer'])) {
         $getid3->info['avdataoffset'] += 10;
     }
     return true;
 }
示例#2
0
 function GenerateID3v2Tag($noerrorsonly = true)
 {
     $this->ID3v2FrameIsAllowed(null, '');
     // clear static array in case this isn't the first call to $this->GenerateID3v2Tag()
     $tagstring = '';
     if (is_array($this->tag_data)) {
         foreach ($this->tag_data as $frame_name => $frame_rawinputdata) {
             foreach ($frame_rawinputdata as $irrelevantindex => $source_data_array) {
                 if (getid3_id3v2::IsValidID3v2FrameName($frame_name, $this->majorversion)) {
                     unset($frame_length);
                     unset($frame_flags);
                     $frame_data = false;
                     if ($this->ID3v2FrameIsAllowed($frame_name, $source_data_array)) {
                         if ($frame_data = $this->GenerateID3v2FrameData($frame_name, $source_data_array)) {
                             $FrameUnsynchronisation = false;
                             if ($this->majorversion >= 4) {
                                 // frame-level unsynchronisation
                                 $unsynchdata = $frame_data;
                                 if ($this->id3v2_use_unsynchronisation) {
                                     $unsynchdata = $this->Unsynchronise($frame_data);
                                 }
                                 if (strlen($unsynchdata) != strlen($frame_data)) {
                                     // unsynchronisation needed
                                     $FrameUnsynchronisation = true;
                                     $frame_data = $unsynchdata;
                                     if (isset($TagUnsynchronisation) && $TagUnsynchronisation === false) {
                                         // only set to true if ALL frames are unsynchronised
                                     } else {
                                         $TagUnsynchronisation = true;
                                     }
                                 } else {
                                     if (isset($TagUnsynchronisation)) {
                                         $TagUnsynchronisation = false;
                                     }
                                 }
                                 unset($unsynchdata);
                                 $frame_length = getid3_lib::BigEndian2String(strlen($frame_data), 4, true);
                             } else {
                                 $frame_length = getid3_lib::BigEndian2String(strlen($frame_data), 4, false);
                             }
                             $frame_flags = $this->GenerateID3v2FrameFlags($this->ID3v2FrameFlagsLookupTagAlter($frame_name), $this->ID3v2FrameFlagsLookupFileAlter($frame_name), false, false, false, false, $FrameUnsynchronisation, false);
                         }
                     } else {
                         $this->errors[] = 'Frame "' . $frame_name . '" is NOT allowed';
                     }
                     if ($frame_data === false) {
                         $this->errors[] = '$this->GenerateID3v2FrameData() failed for "' . $frame_name . '"';
                         if ($noerrorsonly) {
                             return false;
                         } else {
                             unset($frame_name);
                         }
                     }
                 } else {
                     // ignore any invalid frame names, including 'title', 'header', etc
                     $this->warnings[] = 'Ignoring invalid ID3v2 frame type: "' . $frame_name . '"';
                     unset($frame_name);
                     unset($frame_length);
                     unset($frame_flags);
                     unset($frame_data);
                 }
                 if (isset($frame_name) && isset($frame_length) && isset($frame_flags) && isset($frame_data)) {
                     $tagstring .= $frame_name . $frame_length . $frame_flags . $frame_data;
                 }
             }
         }
         if (!isset($TagUnsynchronisation)) {
             $TagUnsynchronisation = false;
         }
         if ($this->majorversion <= 3 && $this->id3v2_use_unsynchronisation) {
             // tag-level unsynchronisation
             $unsynchdata = $this->Unsynchronise($tagstring);
             if (strlen($unsynchdata) != strlen($tagstring)) {
                 // unsynchronisation needed
                 $TagUnsynchronisation = true;
                 $tagstring = $unsynchdata;
             }
         }
         while ($this->paddedlength < strlen($tagstring) + getid3_id3v2::ID3v2HeaderLength($this->majorversion)) {
             $this->paddedlength += 1024;
         }
         $footer = false;
         // ID3v2 footers not yet supported in getID3()
         if (!$footer && $this->paddedlength > strlen($tagstring) + getid3_id3v2::ID3v2HeaderLength($this->majorversion)) {
             // pad up to $paddedlength bytes if unpadded tag is shorter than $paddedlength
             // "Furthermore it MUST NOT have any padding when a tag footer is added to the tag."
             $tagstring .= @str_repeat("", $this->paddedlength - strlen($tagstring) - getid3_id3v2::ID3v2HeaderLength($this->majorversion));
         }
         if ($this->id3v2_use_unsynchronisation && substr($tagstring, strlen($tagstring) - 1, 1) == "ÿ") {
             // special unsynchronisation case:
             // if last byte == $FF then appended a $00
             $TagUnsynchronisation = true;
             $tagstring .= "";
         }
         $tagheader = 'ID3';
         $tagheader .= chr($this->majorversion);
         $tagheader .= chr($this->minorversion);
         $tagheader .= $this->GenerateID3v2TagFlags(array('unsynchronisation' => $TagUnsynchronisation));
         $tagheader .= getid3_lib::BigEndian2String(strlen($tagstring), 4, true);
         return $tagheader . $tagstring;
     }
     $this->errors[] = 'tag_data is not an array in GenerateID3v2Tag()';
     return false;
 }