Beispiel #1
0
 /**
  *
  * @return boolean
  */
 public function Analyze()
 {
     $info =& $this->getid3->info;
     $info['fileformat'] = 'jpg';
     $info['video']['dataformat'] = 'jpg';
     $info['video']['lossless'] = false;
     $info['video']['bits_per_sample'] = 24;
     $info['video']['pixel_aspect_ratio'] = (double) 1;
     fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
     $imageinfo = array();
     list($width, $height, $type) = GetId3_Lib_Helper::GetDataImageSize(fread($this->getid3->fp, $info['filesize']), $imageinfo);
     if (isset($imageinfo['APP13'])) {
         // http://php.net/iptcparse
         // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/IPTC.html
         $iptc_parsed = iptcparse($imageinfo['APP13']);
         if (is_array($iptc_parsed)) {
             foreach ($iptc_parsed as $iptc_key_raw => $iptc_values) {
                 list($iptc_record, $iptc_tagkey) = explode('#', $iptc_key_raw);
                 $iptc_tagkey = intval(ltrim($iptc_tagkey, '0'));
                 foreach ($iptc_values as $key => $value) {
                     $IPTCrecordName = $this->IPTCrecordName($iptc_record);
                     $IPTCrecordTagName = $this->IPTCrecordTagName($iptc_record, $iptc_tagkey);
                     if (isset($info['iptc'][$IPTCrecordName][$IPTCrecordTagName])) {
                         $info['iptc'][$IPTCrecordName][$IPTCrecordTagName][] = $value;
                     } else {
                         $info['iptc'][$IPTCrecordName][$IPTCrecordTagName] = array($value);
                     }
                 }
             }
         }
     }
     $returnOK = false;
     switch ($type) {
         case IMG_JPG:
             $info['video']['resolution_x'] = $width;
             $info['video']['resolution_y'] = $height;
             if (isset($imageinfo['APP1'])) {
                 if (function_exists('exif_read_data')) {
                     if (substr($imageinfo['APP1'], 0, 4) == 'Exif') {
                         $info['jpg']['exif'] = @exif_read_data($info['filenamepath'], '', true, false);
                     } else {
                         $info['warning'][] = 'exif_read_data() cannot parse non-EXIF data in APP1 (expected "Exif", found "' . substr($imageinfo['APP1'], 0, 4) . '")';
                     }
                 } else {
                     $info['warning'][] = 'EXIF parsing only available when ' . (GetId3_GetId3::environmentIsWindows() ? 'php_exif.dll enabled' : 'compiled with --enable-exif');
                 }
             }
             $returnOK = true;
             break;
         default:
             break;
     }
     $cast_as_appropriate_keys = array('EXIF', 'IFD0', 'THUMBNAIL');
     foreach ($cast_as_appropriate_keys as $exif_key) {
         if (isset($info['jpg']['exif'][$exif_key])) {
             foreach ($info['jpg']['exif'][$exif_key] as $key => $value) {
                 $info['jpg']['exif'][$exif_key][$key] = $this->CastAsAppropriate($value);
             }
         }
     }
     if (isset($info['jpg']['exif']['GPS'])) {
         if (isset($info['jpg']['exif']['GPS']['GPSVersion'])) {
             for ($i = 0; $i < 4; $i++) {
                 $version_subparts[$i] = ord(substr($info['jpg']['exif']['GPS']['GPSVersion'], $i, 1));
             }
             $info['jpg']['exif']['GPS']['computed']['version'] = 'v' . implode('.', $version_subparts);
         }
         if (isset($info['jpg']['exif']['GPS']['GPSDateStamp'])) {
             $explodedGPSDateStamp = explode(':', $info['jpg']['exif']['GPS']['GPSDateStamp']);
             $computed_time[5] = isset($explodedGPSDateStamp[0]) ? $explodedGPSDateStamp[0] : '';
             $computed_time[3] = isset($explodedGPSDateStamp[1]) ? $explodedGPSDateStamp[1] : '';
             $computed_time[4] = isset($explodedGPSDateStamp[2]) ? $explodedGPSDateStamp[2] : '';
             if (function_exists('date_default_timezone_set')) {
                 date_default_timezone_set('UTC');
             } else {
                 ini_set('date.timezone', 'UTC');
             }
             $computed_time = array(0 => 0, 1 => 0, 2 => 0, 3 => 0, 4 => 0, 5 => 0);
             if (isset($info['jpg']['exif']['GPS']['GPSTimeStamp']) && is_array($info['jpg']['exif']['GPS']['GPSTimeStamp'])) {
                 foreach ($info['jpg']['exif']['GPS']['GPSTimeStamp'] as $key => $value) {
                     $computed_time[$key] = GetId3_Lib_Helper::DecimalizeFraction($value);
                 }
             }
             $info['jpg']['exif']['GPS']['computed']['timestamp'] = mktime($computed_time[0], $computed_time[1], $computed_time[2], $computed_time[3], $computed_time[4], $computed_time[5]);
         }
         if (isset($info['jpg']['exif']['GPS']['GPSLatitude']) && is_array($info['jpg']['exif']['GPS']['GPSLatitude'])) {
             $direction_multiplier = isset($info['jpg']['exif']['GPS']['GPSLatitudeRef']) && $info['jpg']['exif']['GPS']['GPSLatitudeRef'] == 'S' ? -1 : 1;
             foreach ($info['jpg']['exif']['GPS']['GPSLatitude'] as $key => $value) {
                 $computed_latitude[$key] = GetId3_Lib_Helper::DecimalizeFraction($value);
             }
             $info['jpg']['exif']['GPS']['computed']['latitude'] = $direction_multiplier * ($computed_latitude[0] + $computed_latitude[1] / 60 + $computed_latitude[2] / 3600);
         }
         if (isset($info['jpg']['exif']['GPS']['GPSLongitude']) && is_array($info['jpg']['exif']['GPS']['GPSLongitude'])) {
             $direction_multiplier = isset($info['jpg']['exif']['GPS']['GPSLongitudeRef']) && $info['jpg']['exif']['GPS']['GPSLongitudeRef'] == 'W' ? -1 : 1;
             foreach ($info['jpg']['exif']['GPS']['GPSLongitude'] as $key => $value) {
                 $computed_longitude[$key] = GetId3_Lib_Helper::DecimalizeFraction($value);
             }
             $info['jpg']['exif']['GPS']['computed']['longitude'] = $direction_multiplier * ($computed_longitude[0] + $computed_longitude[1] / 60 + $computed_longitude[2] / 3600);
         }
         if (isset($info['jpg']['exif']['GPS']['GPSAltitude'])) {
             $direction_multiplier = isset($info['jpg']['exif']['GPS']['GPSAltitudeRef']) && $info['jpg']['exif']['GPS']['GPSAltitudeRef'] === chr(1) ? -1 : 1;
             $info['jpg']['exif']['GPS']['computed']['altitude'] = $direction_multiplier * GetId3_Lib_Helper::DecimalizeFraction($info['jpg']['exif']['GPS']['GPSAltitude']);
         }
     }
     if (class_exists('GetId3_Module_Tag_Xmp')) {
         if (isset($info['filenamepath'])) {
             $image_xmp = new GetId3_Module_Tag_Xmp($info['filenamepath']);
             $xmp_raw = $image_xmp->getAllTags();
             foreach ($xmp_raw as $key => $value) {
                 list($subsection, $tagname) = explode(':', $key);
                 $info['xmp'][$subsection][$tagname] = $this->CastAsAppropriate($value);
             }
         }
     }
     if (!$returnOK) {
         unset($info['fileformat']);
         return false;
     }
     return true;
 }
Beispiel #2
0
 /**
  *
  * @return boolean
  */
 public function Analyze()
 {
     $info =& $this->getid3->info;
     if (!GetId3_Lib_Helper::intValueSupported($info['filesize'])) {
         $info['warning'][] = 'Unable to check for APEtags because file is larger than ' . round(PHP_INT_MAX / 1073741824) . 'GB';
         return false;
     }
     $id3v1tagsize = 128;
     $apetagheadersize = 32;
     $lyrics3tagsize = 10;
     if ($this->overrideendoffset == 0) {
         fseek($this->getid3->fp, 0 - $id3v1tagsize - $apetagheadersize - $lyrics3tagsize, SEEK_END);
         $APEfooterID3v1 = fread($this->getid3->fp, $id3v1tagsize + $apetagheadersize + $lyrics3tagsize);
         //if (preg_match('/APETAGEX.{24}TAG.{125}$/i', $APEfooterID3v1)) {
         if (substr($APEfooterID3v1, strlen($APEfooterID3v1) - $id3v1tagsize - $apetagheadersize, 8) == 'APETAGEX') {
             // APE tag found before ID3v1
             $info['ape']['tag_offset_end'] = $info['filesize'] - $id3v1tagsize;
             //} elseif (preg_match('/APETAGEX.{24}$/i', $APEfooterID3v1)) {
         } elseif (substr($APEfooterID3v1, strlen($APEfooterID3v1) - $apetagheadersize, 8) == 'APETAGEX') {
             // APE tag found, no ID3v1
             $info['ape']['tag_offset_end'] = $info['filesize'];
         }
     } else {
         fseek($this->getid3->fp, $this->overrideendoffset - $apetagheadersize, SEEK_SET);
         if (fread($this->getid3->fp, 8) == 'APETAGEX') {
             $info['ape']['tag_offset_end'] = $this->overrideendoffset;
         }
     }
     if (!isset($info['ape']['tag_offset_end'])) {
         // APE tag not found
         unset($info['ape']);
         return false;
     }
     // shortcut
     $thisfile_ape =& $info['ape'];
     fseek($this->getid3->fp, $thisfile_ape['tag_offset_end'] - $apetagheadersize, SEEK_SET);
     $APEfooterData = fread($this->getid3->fp, 32);
     if (!($thisfile_ape['footer'] = $this->parseAPEheaderFooter($APEfooterData))) {
         $info['error'][] = 'Error parsing APE footer at offset ' . $thisfile_ape['tag_offset_end'];
         return false;
     }
     if (isset($thisfile_ape['footer']['flags']['header']) && $thisfile_ape['footer']['flags']['header']) {
         fseek($this->getid3->fp, $thisfile_ape['tag_offset_end'] - $thisfile_ape['footer']['raw']['tagsize'] - $apetagheadersize, SEEK_SET);
         $thisfile_ape['tag_offset_start'] = ftell($this->getid3->fp);
         $APEtagData = fread($this->getid3->fp, $thisfile_ape['footer']['raw']['tagsize'] + $apetagheadersize);
     } else {
         $thisfile_ape['tag_offset_start'] = $thisfile_ape['tag_offset_end'] - $thisfile_ape['footer']['raw']['tagsize'];
         fseek($this->getid3->fp, $thisfile_ape['tag_offset_start'], SEEK_SET);
         $APEtagData = fread($this->getid3->fp, $thisfile_ape['footer']['raw']['tagsize']);
     }
     $info['avdataend'] = $thisfile_ape['tag_offset_start'];
     if (isset($info['id3v1']['tag_offset_start']) && $info['id3v1']['tag_offset_start'] < $thisfile_ape['tag_offset_end']) {
         $info['warning'][] = 'ID3v1 tag information ignored since it appears to be a false synch in APEtag data';
         unset($info['id3v1']);
         foreach ($info['warning'] as $key => $value) {
             if ($value == 'Some ID3v1 fields do not use NULL characters for padding') {
                 unset($info['warning'][$key]);
                 sort($info['warning']);
                 break;
             }
         }
     }
     $offset = 0;
     if (isset($thisfile_ape['footer']['flags']['header']) && $thisfile_ape['footer']['flags']['header']) {
         if ($thisfile_ape['header'] = $this->parseAPEheaderFooter(substr($APEtagData, 0, $apetagheadersize))) {
             $offset += $apetagheadersize;
         } else {
             $info['error'][] = 'Error parsing APE header at offset ' . $thisfile_ape['tag_offset_start'];
             return false;
         }
     }
     // shortcut
     $info['replay_gain'] = array();
     $thisfile_replaygain =& $info['replay_gain'];
     for ($i = 0; $i < $thisfile_ape['footer']['raw']['tag_items']; $i++) {
         $value_size = GetId3_Lib_Helper::LittleEndian2Int(substr($APEtagData, $offset, 4));
         $offset += 4;
         $item_flags = GetId3_Lib_Helper::LittleEndian2Int(substr($APEtagData, $offset, 4));
         $offset += 4;
         if (strstr(substr($APEtagData, $offset), "") === false) {
             $info['error'][] = 'Cannot find null-byte (0x00) seperator between ItemKey #' . $i . ' and value. ItemKey starts ' . $offset . ' bytes into the APE tag, at file offset ' . ($thisfile_ape['tag_offset_start'] + $offset);
             return false;
         }
         $ItemKeyLength = strpos($APEtagData, "", $offset) - $offset;
         $item_key = strtolower(substr($APEtagData, $offset, $ItemKeyLength));
         // shortcut
         $thisfile_ape['items'][$item_key] = array();
         $thisfile_ape_items_current =& $thisfile_ape['items'][$item_key];
         $thisfile_ape_items_current['offset'] = $thisfile_ape['tag_offset_start'] + $offset;
         $offset += $ItemKeyLength + 1;
         // skip 0x00 terminator
         $thisfile_ape_items_current['data'] = substr($APEtagData, $offset, $value_size);
         $offset += $value_size;
         $thisfile_ape_items_current['flags'] = $this->parseAPEtagFlags($item_flags);
         switch ($thisfile_ape_items_current['flags']['item_contents_raw']) {
             case 0:
                 // UTF-8
             // UTF-8
             case 3:
                 // Locator (URL, filename, etc), UTF-8 encoded
                 $thisfile_ape_items_current['data'] = explode("", trim($thisfile_ape_items_current['data']));
                 break;
             default:
                 // binary data
                 break;
         }
         switch (strtolower($item_key)) {
             case 'replaygain_track_gain':
                 $thisfile_replaygain['track']['adjustment'] = (double) str_replace(',', '.', $thisfile_ape_items_current['data'][0]);
                 // float casting will see "0,95" as zero!
                 $thisfile_replaygain['track']['originator'] = 'unspecified';
                 break;
             case 'replaygain_track_peak':
                 $thisfile_replaygain['track']['peak'] = (double) str_replace(',', '.', $thisfile_ape_items_current['data'][0]);
                 // float casting will see "0,95" as zero!
                 $thisfile_replaygain['track']['originator'] = 'unspecified';
                 if ($thisfile_replaygain['track']['peak'] <= 0) {
                     $info['warning'][] = 'ReplayGain Track peak from APEtag appears invalid: ' . $thisfile_replaygain['track']['peak'] . ' (original value = "' . $thisfile_ape_items_current['data'][0] . '")';
                 }
                 break;
             case 'replaygain_album_gain':
                 $thisfile_replaygain['album']['adjustment'] = (double) str_replace(',', '.', $thisfile_ape_items_current['data'][0]);
                 // float casting will see "0,95" as zero!
                 $thisfile_replaygain['album']['originator'] = 'unspecified';
                 break;
             case 'replaygain_album_peak':
                 $thisfile_replaygain['album']['peak'] = (double) str_replace(',', '.', $thisfile_ape_items_current['data'][0]);
                 // float casting will see "0,95" as zero!
                 $thisfile_replaygain['album']['originator'] = 'unspecified';
                 if ($thisfile_replaygain['album']['peak'] <= 0) {
                     $info['warning'][] = 'ReplayGain Album peak from APEtag appears invalid: ' . $thisfile_replaygain['album']['peak'] . ' (original value = "' . $thisfile_ape_items_current['data'][0] . '")';
                 }
                 break;
             case 'mp3gain_undo':
                 list($mp3gain_undo_left, $mp3gain_undo_right, $mp3gain_undo_wrap) = explode(',', $thisfile_ape_items_current['data'][0]);
                 $thisfile_replaygain['mp3gain']['undo_left'] = intval($mp3gain_undo_left);
                 $thisfile_replaygain['mp3gain']['undo_right'] = intval($mp3gain_undo_right);
                 $thisfile_replaygain['mp3gain']['undo_wrap'] = $mp3gain_undo_wrap == 'Y' ? true : false;
                 break;
             case 'mp3gain_minmax':
                 list($mp3gain_globalgain_min, $mp3gain_globalgain_max) = explode(',', $thisfile_ape_items_current['data'][0]);
                 $thisfile_replaygain['mp3gain']['globalgain_track_min'] = intval($mp3gain_globalgain_min);
                 $thisfile_replaygain['mp3gain']['globalgain_track_max'] = intval($mp3gain_globalgain_max);
                 break;
             case 'mp3gain_album_minmax':
                 list($mp3gain_globalgain_album_min, $mp3gain_globalgain_album_max) = explode(',', $thisfile_ape_items_current['data'][0]);
                 $thisfile_replaygain['mp3gain']['globalgain_album_min'] = intval($mp3gain_globalgain_album_min);
                 $thisfile_replaygain['mp3gain']['globalgain_album_max'] = intval($mp3gain_globalgain_album_max);
                 break;
             case 'tracknumber':
                 if (is_array($thisfile_ape_items_current['data'])) {
                     foreach ($thisfile_ape_items_current['data'] as $comment) {
                         $thisfile_ape['comments']['track'][] = $comment;
                     }
                 }
                 break;
             case 'cover art (artist)':
             case 'cover art (back)':
             case 'cover art (band logo)':
             case 'cover art (band)':
             case 'cover art (colored fish)':
             case 'cover art (composer)':
             case 'cover art (conductor)':
             case 'cover art (front)':
             case 'cover art (icon)':
             case 'cover art (illustration)':
             case 'cover art (lead)':
             case 'cover art (leaflet)':
             case 'cover art (lyricist)':
             case 'cover art (media)':
             case 'cover art (movie scene)':
             case 'cover art (other icon)':
             case 'cover art (other)':
             case 'cover art (performance)':
             case 'cover art (publisher logo)':
             case 'cover art (recording)':
             case 'cover art (studio)':
                 // list of possible cover arts from http://taglib-sharp.sourcearchive.com/documentation/2.0.3.0-2/Ape_2Tag_8cs-source.html
                 list($thisfile_ape_items_current['filename'], $thisfile_ape_items_current['data']) = explode("", $thisfile_ape_items_current['data'], 2);
                 $thisfile_ape_items_current['data_offset'] = $thisfile_ape_items_current['offset'] + strlen($thisfile_ape_items_current['filename'] . "");
                 $thisfile_ape_items_current['data_length'] = strlen($thisfile_ape_items_current['data']);
                 $thisfile_ape_items_current['image_mime'] = '';
                 $imageinfo = array();
                 $imagechunkcheck = GetId3_Lib_Helper::GetDataImageSize($thisfile_ape_items_current['data'], $imageinfo);
                 $thisfile_ape_items_current['image_mime'] = image_type_to_mime_type($imagechunkcheck[2]);
                 do {
                     if ($this->inline_attachments === false) {
                         // skip entirely
                         unset($thisfile_ape_items_current['data']);
                         break;
                     }
                     if ($this->inline_attachments === true) {
                         // great
                     } elseif (is_int($this->inline_attachments)) {
                         if ($this->inline_attachments < $thisfile_ape_items_current['data_length']) {
                             // too big, skip
                             $info['warning'][] = 'attachment at ' . $thisfile_ape_items_current['offset'] . ' is too large to process inline (' . number_format($thisfile_ape_items_current['data_length']) . ' bytes)';
                             unset($thisfile_ape_items_current['data']);
                             break;
                         }
                     } elseif (is_string($this->inline_attachments)) {
                         $this->inline_attachments = rtrim(str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $this->inline_attachments), DIRECTORY_SEPARATOR);
                         if (!is_dir($this->inline_attachments) || !is_writable($this->inline_attachments)) {
                             // cannot write, skip
                             $info['warning'][] = 'attachment at ' . $thisfile_ape_items_current['offset'] . ' cannot be saved to "' . $this->inline_attachments . '" (not writable)';
                             unset($thisfile_ape_items_current['data']);
                             break;
                         }
                     }
                     // if we get this far, must be OK
                     if (is_string($this->inline_attachments)) {
                         $destination_filename = $this->inline_attachments . DIRECTORY_SEPARATOR . md5($info['filenamepath']) . '_' . $thisfile_ape_items_current['data_offset'];
                         if (!file_exists($destination_filename) || is_writable($destination_filename)) {
                             file_put_contents($destination_filename, $thisfile_ape_items_current['data']);
                         } else {
                             $info['warning'][] = 'attachment at ' . $thisfile_ape_items_current['offset'] . ' cannot be saved to "' . $destination_filename . '" (not writable)';
                         }
                         $thisfile_ape_items_current['data_filename'] = $destination_filename;
                         unset($thisfile_ape_items_current['data']);
                     } else {
                         if (!isset($info['ape']['comments']['picture'])) {
                             $info['ape']['comments']['picture'] = array();
                         }
                         $info['ape']['comments']['picture'][] = array('data' => $thisfile_ape_items_current['data'], 'image_mime' => $thisfile_ape_items_current['image_mime']);
                     }
                 } while (false);
                 break;
             default:
                 if (is_array($thisfile_ape_items_current['data'])) {
                     foreach ($thisfile_ape_items_current['data'] as $comment) {
                         $thisfile_ape['comments'][strtolower($item_key)][] = $comment;
                     }
                 }
                 break;
         }
     }
     if (empty($thisfile_replaygain)) {
         unset($info['replay_gain']);
     }
     return true;
 }
Beispiel #3
0
 /**
  *
  * @return boolean
  */
 public function ParseVorbisComments()
 {
     $info =& $this->getid3->info;
     $OriginalOffset = $this->ftell();
     $commentdataoffset = 0;
     $VorbisCommentPage = 1;
     switch ($info['audio']['dataformat']) {
         case 'vorbis':
         case 'speex':
             $CommentStartOffset = $info['ogg']['pageheader'][$VorbisCommentPage]['page_start_offset'];
             // Second Ogg page, after header block
             $this->fseek($CommentStartOffset);
             $commentdataoffset = 27 + $info['ogg']['pageheader'][$VorbisCommentPage]['page_segments'];
             $commentdata = $this->fread(self::OggPageSegmentLength($info['ogg']['pageheader'][$VorbisCommentPage], 1) + $commentdataoffset);
             if ($info['audio']['dataformat'] == 'vorbis') {
                 $commentdataoffset += strlen('vorbis') + 1;
             }
             break;
         case 'flac':
             $CommentStartOffset = $info['flac']['VORBIS_COMMENT']['raw']['offset'] + 4;
             $this->fseek($CommentStartOffset);
             $commentdata = $this->fread($info['flac']['VORBIS_COMMENT']['raw']['block_length']);
             break;
         default:
             return false;
     }
     $VendorSize = GetId3_Lib_Helper::LittleEndian2Int(substr($commentdata, $commentdataoffset, 4));
     $commentdataoffset += 4;
     $info['ogg']['vendor'] = substr($commentdata, $commentdataoffset, $VendorSize);
     $commentdataoffset += $VendorSize;
     $CommentsCount = GetId3_Lib_Helper::LittleEndian2Int(substr($commentdata, $commentdataoffset, 4));
     $commentdataoffset += 4;
     $info['avdataoffset'] = $CommentStartOffset + $commentdataoffset;
     $basicfields = array('TITLE', 'ARTIST', 'ALBUM', 'TRACKNUMBER', 'GENRE', 'DATE', 'DESCRIPTION', 'COMMENT');
     $ThisFileInfo_ogg_comments_raw =& $info['ogg']['comments_raw'];
     for ($i = 0; $i < $CommentsCount; $i++) {
         $ThisFileInfo_ogg_comments_raw[$i]['dataoffset'] = $CommentStartOffset + $commentdataoffset;
         if ($this->ftell() < $ThisFileInfo_ogg_comments_raw[$i]['dataoffset'] + 4) {
             if ($oggpageinfo = $this->ParseOggPageHeader()) {
                 $info['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo;
                 $VorbisCommentPage++;
                 // First, save what we haven't read yet
                 $AsYetUnusedData = substr($commentdata, $commentdataoffset);
                 // Then take that data off the end
                 $commentdata = substr($commentdata, 0, $commentdataoffset);
                 // Add [headerlength] bytes of dummy data for the Ogg Page Header, just to keep absolute offsets correct
                 $commentdata .= str_repeat("", 27 + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']);
                 $commentdataoffset += 27 + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments'];
                 // Finally, stick the unused data back on the end
                 $commentdata .= $AsYetUnusedData;
                 //$commentdata .= $this->fread($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']);
                 $commentdata .= $this->fread($this->OggPageSegmentLength($info['ogg']['pageheader'][$VorbisCommentPage], 1));
             }
         }
         $ThisFileInfo_ogg_comments_raw[$i]['size'] = GetId3_Lib_Helper::LittleEndian2Int(substr($commentdata, $commentdataoffset, 4));
         // replace avdataoffset with position just after the last vorbiscomment
         $info['avdataoffset'] = $ThisFileInfo_ogg_comments_raw[$i]['dataoffset'] + $ThisFileInfo_ogg_comments_raw[$i]['size'] + 4;
         $commentdataoffset += 4;
         while (strlen($commentdata) - $commentdataoffset < $ThisFileInfo_ogg_comments_raw[$i]['size']) {
             if ($ThisFileInfo_ogg_comments_raw[$i]['size'] > $info['avdataend'] || $ThisFileInfo_ogg_comments_raw[$i]['size'] < 0) {
                 $info['warning'][] = 'Invalid Ogg comment size (comment #' . $i . ', claims to be ' . number_format($ThisFileInfo_ogg_comments_raw[$i]['size']) . ' bytes) - aborting reading comments';
                 break 2;
             }
             $VorbisCommentPage++;
             $oggpageinfo = $this->ParseOggPageHeader();
             $info['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo;
             // First, save what we haven't read yet
             $AsYetUnusedData = substr($commentdata, $commentdataoffset);
             // Then take that data off the end
             $commentdata = substr($commentdata, 0, $commentdataoffset);
             // Add [headerlength] bytes of dummy data for the Ogg Page Header, just to keep absolute offsets correct
             $commentdata .= str_repeat("", 27 + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']);
             $commentdataoffset += 27 + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments'];
             // Finally, stick the unused data back on the end
             $commentdata .= $AsYetUnusedData;
             //$commentdata .= $this->fread($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']);
             if (!isset($info['ogg']['pageheader'][$VorbisCommentPage])) {
                 $info['warning'][] = 'undefined Vorbis Comment page "' . $VorbisCommentPage . '" at offset ' . $this->ftell();
                 break;
             }
             $readlength = self::OggPageSegmentLength($info['ogg']['pageheader'][$VorbisCommentPage], 1);
             if ($readlength <= 0) {
                 $info['warning'][] = 'invalid length Vorbis Comment page "' . $VorbisCommentPage . '" at offset ' . $this->ftell();
                 break;
             }
             $commentdata .= $this->fread($readlength);
             //$filebaseoffset += $oggpageinfo['header_end_offset'] - $oggpageinfo['page_start_offset'];
         }
         $ThisFileInfo_ogg_comments_raw[$i]['offset'] = $commentdataoffset;
         $commentstring = substr($commentdata, $commentdataoffset, $ThisFileInfo_ogg_comments_raw[$i]['size']);
         $commentdataoffset += $ThisFileInfo_ogg_comments_raw[$i]['size'];
         if (!$commentstring) {
             // no comment?
             $info['warning'][] = 'Blank Ogg comment [' . $i . ']';
         } elseif (strstr($commentstring, '=')) {
             $commentexploded = explode('=', $commentstring, 2);
             $ThisFileInfo_ogg_comments_raw[$i]['key'] = strtoupper($commentexploded[0]);
             $ThisFileInfo_ogg_comments_raw[$i]['value'] = isset($commentexploded[1]) ? $commentexploded[1] : '';
             $ThisFileInfo_ogg_comments_raw[$i]['data'] = base64_decode($ThisFileInfo_ogg_comments_raw[$i]['value']);
             $ThisFileInfo_ogg_comments_raw[$i]['data_length'] = strlen($ThisFileInfo_ogg_comments_raw[$i]['data']);
             if ($ThisFileInfo_ogg_comments_raw[$i]['key'] == 'METADATA_BLOCK_PICTURE') {
                 // http://wiki.xiph.org/VorbisComment#METADATA_BLOCK_PICTURE
                 // The unencoded format is that of the FLAC picture block. The fields are stored in big endian order as in FLAC, picture data is stored according to the relevant standard.
                 // http://flac.sourceforge.net/format.html#metadata_block_picture
                 $getid3_temp = new GetId3_GetId3();
                 $getid3_flac = new GetId3_Module_Audio_Flac($getid3_temp);
                 $getid3_flac->data_string = $ThisFileInfo_ogg_comments_raw[$i]['data'];
                 $getid3_flac->data_string_flag = true;
                 if ($getid3_flac->parsePICTURE()) {
                     if (!empty($getid3_temp->info['flac']['PICTURE'])) {
                         foreach ($getid3_temp->info['flac']['PICTURE'] as $key => $value) {
                             $ThisFileInfo_ogg_comments_raw[$i]['data'] = $value['data'];
                             $ThisFileInfo_ogg_comments_raw[$i]['data_length'] = strlen($value['data']);
                             $ThisFileInfo_ogg_comments_raw[$i]['image_mime'] = $value['image_mime'];
                             $ThisFileInfo_ogg_comments_raw[$i]['width'] = $value['width'];
                             $ThisFileInfo_ogg_comments_raw[$i]['height'] = $value['height'];
                             $ThisFileInfo_ogg_comments_raw[$i]['type'] = $value['type'];
                             $ThisFileInfo_ogg_comments_raw[$i]['typeid'] = $value['typeid'];
                             $ThisFileInfo_ogg_comments_raw[$i]['color_depth'] = $value['color_depth'];
                             $ThisFileInfo_ogg_comments_raw[$i]['colors_indexed'] = $value['colors_indexed'];
                         }
                     }
                 } else {
                     $info['warning'][] = 'Failed to GetId3_flac.parsePICTURE()';
                 }
                 unset($getid3_flac, $getid3_temp);
             }
             if (preg_match('#^(BM|GIF|\\xFF\\xD8\\xFF|\\x89\\x50\\x4E\\x47\\x0D\\x0A\\x1A\\x0A|II\\x2A\\x00|MM\\x00\\x2A)#s', $ThisFileInfo_ogg_comments_raw[$i]['data'])) {
                 $imageinfo = array();
                 $imagechunkcheck = GetId3_Lib_Helper::GetDataImageSize($ThisFileInfo_ogg_comments_raw[$i]['data'], $imageinfo);
                 unset($imageinfo);
                 if (!empty($imagechunkcheck)) {
                     $ThisFileInfo_ogg_comments_raw[$i]['image_mime'] = image_type_to_mime_type($imagechunkcheck[2]);
                     if ($ThisFileInfo_ogg_comments_raw[$i]['image_mime'] && $ThisFileInfo_ogg_comments_raw[$i]['image_mime'] != 'application/octet-stream') {
                         unset($ThisFileInfo_ogg_comments_raw[$i]['value']);
                     }
                 }
             }
             if (isset($ThisFileInfo_ogg_comments_raw[$i]['value'])) {
                 unset($ThisFileInfo_ogg_comments_raw[$i]['data']);
                 $info['ogg']['comments'][strtolower($ThisFileInfo_ogg_comments_raw[$i]['key'])][] = $ThisFileInfo_ogg_comments_raw[$i]['value'];
             } else {
                 do {
                     if ($this->inline_attachments === false) {
                         // skip entirely
                         unset($ThisFileInfo_ogg_comments_raw[$i]['data']);
                         break;
                     }
                     if ($this->inline_attachments === true) {
                         // great
                     } elseif (is_int($this->inline_attachments)) {
                         if ($this->inline_attachments < $ThisFileInfo_ogg_comments_raw[$i]['data_length']) {
                             // too big, skip
                             $info['warning'][] = 'attachment at ' . $ThisFileInfo_ogg_comments_raw[$i]['offset'] . ' is too large to process inline (' . number_format($ThisFileInfo_ogg_comments_raw[$i]['data_length']) . ' bytes)';
                             unset($ThisFileInfo_ogg_comments_raw[$i]['data']);
                             break;
                         }
                     } elseif (is_string($this->inline_attachments)) {
                         $this->inline_attachments = rtrim(str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $this->inline_attachments), DIRECTORY_SEPARATOR);
                         if (!is_dir($this->inline_attachments) || !is_writable($this->inline_attachments)) {
                             // cannot write, skip
                             $info['warning'][] = 'attachment at ' . $ThisFileInfo_ogg_comments_raw[$i]['offset'] . ' cannot be saved to "' . $this->inline_attachments . '" (not writable)';
                             unset($ThisFileInfo_ogg_comments_raw[$i]['data']);
                             break;
                         }
                     }
                     // if we get this far, must be OK
                     if (is_string($this->inline_attachments)) {
                         $destination_filename = $this->inline_attachments . DIRECTORY_SEPARATOR . md5($info['filenamepath']) . '_' . $ThisFileInfo_ogg_comments_raw[$i]['offset'];
                         if (!file_exists($destination_filename) || is_writable($destination_filename)) {
                             file_put_contents($destination_filename, $ThisFileInfo_ogg_comments_raw[$i]['data']);
                         } else {
                             $info['warning'][] = 'attachment at ' . $ThisFileInfo_ogg_comments_raw[$i]['offset'] . ' cannot be saved to "' . $destination_filename . '" (not writable)';
                         }
                         $ThisFileInfo_ogg_comments_raw[$i]['data_filename'] = $destination_filename;
                         unset($ThisFileInfo_ogg_comments_raw[$i]['data']);
                     } else {
                         $info['ogg']['comments']['picture'][] = array('data' => $ThisFileInfo_ogg_comments_raw[$i]['data'], 'image_mime' => $ThisFileInfo_ogg_comments_raw[$i]['image_mime']);
                     }
                 } while (false);
             }
         } else {
             $info['warning'][] = '[known problem with CDex >= v1.40, < v1.50b7] Invalid Ogg comment name/value pair [' . $i . ']: ' . $commentstring;
         }
     }
     // Replay Gain Adjustment
     // http://privatewww.essex.ac.uk/~djmrob/replaygain/
     if (isset($info['ogg']['comments']) && is_array($info['ogg']['comments'])) {
         foreach ($info['ogg']['comments'] as $index => $commentvalue) {
             switch ($index) {
                 case 'rg_audiophile':
                 case 'replaygain_album_gain':
                     $info['replay_gain']['album']['adjustment'] = (double) $commentvalue[0];
                     unset($info['ogg']['comments'][$index]);
                     break;
                 case 'rg_radio':
                 case 'replaygain_track_gain':
                     $info['replay_gain']['track']['adjustment'] = (double) $commentvalue[0];
                     unset($info['ogg']['comments'][$index]);
                     break;
                 case 'replaygain_album_peak':
                     $info['replay_gain']['album']['peak'] = (double) $commentvalue[0];
                     unset($info['ogg']['comments'][$index]);
                     break;
                 case 'rg_peak':
                 case 'replaygain_track_peak':
                     $info['replay_gain']['track']['peak'] = (double) $commentvalue[0];
                     unset($info['ogg']['comments'][$index]);
                     break;
                 case 'replaygain_reference_loudness':
                     $info['replay_gain']['reference_volume'] = (double) $commentvalue[0];
                     unset($info['ogg']['comments'][$index]);
                     break;
                 default:
                     // do nothing
                     break;
             }
         }
     }
     $this->fseek($OriginalOffset);
     return true;
 }
Beispiel #4
0
 public function ASF_WMpicture(&$data)
 {
     //typedef struct _WMPicture{
     //  LPWSTR  pwszMIMEType;
     //  BYTE  bPictureType;
     //  LPWSTR  pwszDescription;
     //  DWORD  dwDataLen;
     //  BYTE*  pbData;
     //} WM_PICTURE;
     $WMpicture = array();
     $offset = 0;
     $WMpicture['image_type_id'] = GetId3_Lib_Helper::LittleEndian2Int(substr($data, $offset, 1));
     $offset += 1;
     $WMpicture['image_type'] = $this->WMpictureTypeLookup($WMpicture['image_type_id']);
     $WMpicture['image_size'] = GetId3_Lib_Helper::LittleEndian2Int(substr($data, $offset, 4));
     $offset += 4;
     $WMpicture['image_mime'] = '';
     do {
         $next_byte_pair = substr($data, $offset, 2);
         $offset += 2;
         $WMpicture['image_mime'] .= $next_byte_pair;
     } while ($next_byte_pair !== "");
     $WMpicture['image_description'] = '';
     do {
         $next_byte_pair = substr($data, $offset, 2);
         $offset += 2;
         $WMpicture['image_description'] .= $next_byte_pair;
     } while ($next_byte_pair !== "");
     $WMpicture['dataoffset'] = $offset;
     $WMpicture['data'] = substr($data, $offset);
     $imageinfo = array();
     $WMpicture['image_mime'] = '';
     $imagechunkcheck = GetId3_Lib_Helper::GetDataImageSize($WMpicture['data'], $imageinfo);
     unset($imageinfo);
     if (!empty($imagechunkcheck)) {
         $WMpicture['image_mime'] = image_type_to_mime_type($imagechunkcheck[2]);
     }
     if (!isset($this->getid3->info['asf']['comments']['picture'])) {
         $this->getid3->info['asf']['comments']['picture'] = array();
     }
     $this->getid3->info['asf']['comments']['picture'][] = array('data' => $WMpicture['data'], 'image_mime' => $WMpicture['image_mime']);
     return $WMpicture;
 }