[pLog-svn] r3790 - plog/trunk/class/gallery/getid3
mark at devel.lifetype.net
mark at devel.lifetype.net
Mon Jul 24 16:56:08 GMT 2006
Author: mark
Date: 2006-07-24 16:56:08 +0000 (Mon, 24 Jul 2006)
New Revision: 3790
Added:
plog/trunk/class/gallery/getid3/extension.cache.dbm.php
plog/trunk/class/gallery/getid3/extension.cache.mysql.php
plog/trunk/class/gallery/getid3/module.audio-video.flv.php
plog/trunk/class/gallery/getid3/module.graphic.svg.php
plog/trunk/class/gallery/getid3/write.apetag.php
plog/trunk/class/gallery/getid3/write.id3v1.php
plog/trunk/class/gallery/getid3/write.id3v2.php
plog/trunk/class/gallery/getid3/write.lyrics3.php
plog/trunk/class/gallery/getid3/write.metaflac.php
plog/trunk/class/gallery/getid3/write.php
plog/trunk/class/gallery/getid3/write.real.php
plog/trunk/class/gallery/getid3/write.vorbiscomment.php
Modified:
plog/trunk/class/gallery/getid3/getid3.lib.php
plog/trunk/class/gallery/getid3/getid3.php
plog/trunk/class/gallery/getid3/module.archive.gzip.php
plog/trunk/class/gallery/getid3/module.archive.tar.php
plog/trunk/class/gallery/getid3/module.archive.zip.php
plog/trunk/class/gallery/getid3/module.audio-video.asf.php
plog/trunk/class/gallery/getid3/module.audio-video.quicktime.php
plog/trunk/class/gallery/getid3/module.audio-video.riff.php
plog/trunk/class/gallery/getid3/module.audio.aac.php
plog/trunk/class/gallery/getid3/module.audio.flac.php
plog/trunk/class/gallery/getid3/module.audio.midi.php
plog/trunk/class/gallery/getid3/module.audio.mp3.php
plog/trunk/class/gallery/getid3/module.audio.shorten.php
plog/trunk/class/gallery/getid3/module.misc.iso.php
plog/trunk/class/gallery/getid3/module.tag.id3v2.php
Log:
Upgrade getID3 to 1.7.7
Added: plog/trunk/class/gallery/getid3/extension.cache.dbm.php
===================================================================
--- plog/trunk/class/gallery/getid3/extension.cache.dbm.php 2006-07-24 16:40:16 UTC (rev 3789)
+++ plog/trunk/class/gallery/getid3/extension.cache.dbm.php 2006-07-24 16:56:08 UTC (rev 3790)
@@ -0,0 +1,222 @@
+<?php
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info at getid3.org> //
+// available at http://getid3.sourceforge.net //
+// or http://www.getid3.org //
+/////////////////////////////////////////////////////////////////
+// //
+// extension.cache.dbm.php - part of getID3() //
+// Please see readme.txt for more information //
+// ///
+/////////////////////////////////////////////////////////////////
+// //
+// This extension written by Allan Hansen <ahØartemis*dk> //
+// ///
+/////////////////////////////////////////////////////////////////
+
+
+/**
+* This is a caching extension for getID3(). It works the exact same
+* way as the getID3 class, but return cached information very fast
+*
+* Example:
+*
+* Normal getID3 usage (example):
+*
+* require_once 'getid3/getid3.php';
+* $getID3 = new getID3;
+* $getID3->encoding = 'UTF-8';
+* $info1 = $getID3->analyze('file1.flac');
+* $info2 = $getID3->analyze('file2.wv');
+*
+* getID3_cached usage:
+*
+* require_once 'getid3/getid3.php';
+* require_once 'getid3/getid3/extension.cache.dbm.php';
+* $getID3 = new getID3_cached('db3', '/tmp/getid3_cache.dbm',
+* '/tmp/getid3_cache.lock');
+* $getID3->encoding = 'UTF-8';
+* $info1 = $getID3->analyze('file1.flac');
+* $info2 = $getID3->analyze('file2.wv');
+*
+*
+* Supported Cache Types
+*
+* SQL Databases: (use extension.cache.mysql)
+*
+* cache_type cache_options
+* -------------------------------------------------------------------
+* mysql host, database, username, password
+*
+*
+* DBM-Style Databases: (this extension)
+*
+* cache_type cache_options
+* -------------------------------------------------------------------
+* gdbm dbm_filename, lock_filename
+* ndbm dbm_filename, lock_filename
+* db2 dbm_filename, lock_filename
+* db3 dbm_filename, lock_filename
+* db4 dbm_filename, lock_filename (PHP5 required)
+*
+* PHP must have write access to both dbm_filename and lock_filename.
+*
+*
+* Recommended Cache Types
+*
+* Infrequent updates, many reads any DBM
+* Frequent updates mysql
+*/
+
+
+class getID3_cached_dbm extends getID3
+{
+
+ // public: constructor - see top of this file for cache type and cache_options
+ function getID3_cached_dbm($cache_type, $dbm_filename, $lock_filename) {
+
+ // Check for dba extension
+ if (!extension_loaded('dba')) {
+ die('PHP is not compiled with dba support, required to use DBM style cache.');
+ }
+
+ // Check for specific dba driver
+ if (function_exists('dba_handlers')) { // PHP 4.3.0+
+ if (!in_array('db3', dba_handlers())) {
+ die('PHP is not compiled --with '.$cache_type.' support, required to use DBM style cache.');
+ }
+ }
+ else { // PHP <= 4.2.3
+ ob_start(); // nasty, buy the only way to check...
+ phpinfo();
+ $contents = ob_get_contents();
+ ob_end_clean();
+ if (!strstr($contents, $cache_type)) {
+ die('PHP is not compiled --with '.$cache_type.' support, required to use DBM style cache.');
+ }
+ }
+
+ // Create lock file if needed
+ if (!file_exists($lock_filename)) {
+ if (!touch($lock_filename)) {
+ die('failed to create lock file: ' . $lock_filename);
+ }
+ }
+
+ // Open lock file for writing
+ if (!is_writeable($lock_filename)) {
+ die('lock file: ' . $lock_filename . ' is not writable');
+ }
+ $this->lock = fopen($lock_filename, 'w');
+
+ // Acquire exclusive write lock to lock file
+ flock($this->lock, LOCK_EX);
+
+ // Create dbm-file if needed
+ if (!file_exists($dbm_filename)) {
+ if (!touch($dbm_filename)) {
+ die('failed to create dbm file: ' . $dbm_filename);
+ }
+ }
+
+ // Try to open dbm file for writing
+ $this->dba = @dba_open($dbm_filename, 'w', $cache_type);
+ if (!$this->dba) {
+
+ // Failed - create new dbm file
+ $this->dba = dba_open($dbm_filename, 'n', $cache_type);
+
+ if (!$this->dba) {
+ die('failed to create dbm file: ' . $dbm_filename);
+ }
+
+ // Insert getID3 version number
+ dba_insert(GETID3_VERSION, GETID3_VERSION, $this->dba);
+ }
+
+ // Init misc values
+ $this->cache_type = $cache_type;
+ $this->dbm_filename = $dbm_filename;
+
+ // Register destructor
+ register_shutdown_function(array($this, '__destruct'));
+
+ // Check version number and clear cache if changed
+ if (dba_fetch(GETID3_VERSION, $this->dba) != GETID3_VERSION) {
+ $this->clear_cache();
+ }
+
+ parent::getID3();
+ }
+
+
+
+ // public: destuctor
+ function __destruct() {
+
+ // Close dbm file
+ @dba_close($this->dba);
+
+ // Release exclusive lock
+ @flock($this->lock, LOCK_UN);
+
+ // Close lock file
+ @fclose($this->lock);
+ }
+
+
+
+ // public: clear cache
+ function clear_cache() {
+
+ // Close dbm file
+ dba_close($this->dba);
+
+ // Create new dbm file
+ $this->dba = dba_open($this->dbm_filename, 'n', $this->cache_type);
+
+ if (!$this->dba) {
+ die('failed to clear cache/recreate dbm file: ' . $this->dbm_filename);
+ }
+
+ // Insert getID3 version number
+ dba_insert(GETID3_VERSION, GETID3_VERSION, $this->dba);
+
+ // Reregister shutdown function
+ register_shutdown_function(array($this, '__destruct'));
+ }
+
+
+
+ // public: analyze file
+ function analyze($filename) {
+
+ if (file_exists($filename)) {
+
+ // Calc key filename::mod_time::size - should be unique
+ $key = $filename . '::' . filemtime($filename) . '::' . filesize($filename);
+
+ // Loopup key
+ $result = dba_fetch($key, $this->dba);
+
+ // Hit
+ if ($result !== false) {
+ return unserialize($result);
+ }
+ }
+
+ // Miss
+ $result = parent::analyze($filename);
+
+ // Save result
+ if (file_exists($filename)) {
+ dba_insert($key, serialize($result), $this->dba);
+ }
+
+ return $result;
+ }
+
+}
+
+
+?>
\ No newline at end of file
Added: plog/trunk/class/gallery/getid3/extension.cache.mysql.php
===================================================================
--- plog/trunk/class/gallery/getid3/extension.cache.mysql.php 2006-07-24 16:40:16 UTC (rev 3789)
+++ plog/trunk/class/gallery/getid3/extension.cache.mysql.php 2006-07-24 16:56:08 UTC (rev 3790)
@@ -0,0 +1,171 @@
+<?php
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info at getid3.org> //
+// available at http://getid3.sourceforge.net //
+// or http://www.getid3.org //
+/////////////////////////////////////////////////////////////////
+// //
+// extension.cache.mysql.php - part of getID3() //
+// Please see readme.txt for more information //
+// ///
+/////////////////////////////////////////////////////////////////
+// //
+// This extension written by Allan Hansen <ahØartemis*dk> //
+// ///
+/////////////////////////////////////////////////////////////////
+
+
+/**
+* This is a caching extension for getID3(). It works the exact same
+* way as the getID3 class, but return cached information very fast
+*
+* Example: (see also demo.cache.mysql.php in /demo/)
+*
+* Normal getID3 usage (example):
+*
+* require_once 'getid3/getid3.php';
+* $getID3 = new getID3;
+* $getID3->encoding = 'UTF-8';
+* $info1 = $getID3->analyze('file1.flac');
+* $info2 = $getID3->analyze('file2.wv');
+*
+* getID3_cached usage:
+*
+* require_once 'getid3/getid3.php';
+* require_once 'getid3/getid3/extension.cache.mysql.php';
+* $getID3 = new getID3_cached_mysql('localhost', 'database',
+* 'username', 'password');
+* $getID3->encoding = 'UTF-8';
+* $info1 = $getID3->analyze('file1.flac');
+* $info2 = $getID3->analyze('file2.wv');
+*
+*
+* Supported Cache Types (this extension)
+*
+* SQL Databases:
+*
+* cache_type cache_options
+* -------------------------------------------------------------------
+* mysql host, database, username, password
+*
+*
+* DBM-Style Databases: (use extension.cache.dbm)
+*
+* cache_type cache_options
+* -------------------------------------------------------------------
+* gdbm dbm_filename, lock_filename
+* ndbm dbm_filename, lock_filename
+* db2 dbm_filename, lock_filename
+* db3 dbm_filename, lock_filename
+* db4 dbm_filename, lock_filename (PHP5 required)
+*
+* PHP must have write access to both dbm_filename and lock_filename.
+*
+*
+* Recommended Cache Types
+*
+* Infrequent updates, many reads any DBM
+* Frequent updates mysql
+*/
+
+
+class getID3_cached_mysql extends getID3
+{
+
+ // private vars
+ var $cursor;
+ var $connection;
+
+
+ // public: constructor - see top of this file for cache type and cache_options
+ function getID3_cached_mysql($host, $database, $username, $password) {
+
+ // Check for mysql support
+ if (!function_exists('mysql_pconnect')) {
+ die('PHP not compiled with mysql support.');
+ }
+
+ // Connect to database
+ $this->connection = mysql_pconnect($host, $username, $password);
+ if (!$this->connection) {
+ die('mysql_pconnect() failed - check permissions and spelling.');
+ }
+
+ // Select database
+ if (!mysql_select_db($database, $this->connection)) {
+ die('Cannot use database '.$database);
+ }
+
+ // Create cache table if not exists
+ $this->create_table();
+
+ // Check version number and clear cache if changed
+ $this->cursor = mysql_query("SELECT `value` FROM `getid3_cache` WHERE (`filename` = '".GETID3_VERSION."') AND (`filesize` = '-1') AND (`filetime` = '-1') AND (`analyzetime` = '-1')", $this->connection);
+ list($version) = @mysql_fetch_array($this->cursor);
+ if ($version != GETID3_VERSION) {
+ $this->clear_cache();
+ }
+
+ parent::getID3();
+ }
+
+
+
+ // public: clear cache
+ function clear_cache() {
+
+ $this->cursor = mysql_query("DELETE FROM `getid3_cache`", $this->connection);
+ $this->cursor = mysql_query("INSERT INTO `getid3_cache` VALUES ('".GETID3_VERSION."', -1, -1, -1, '".GETID3_VERSION."')", $this->connection);
+ }
+
+
+
+ // public: analyze file
+ function analyze($filename) {
+
+ if (file_exists($filename)) {
+
+ // Short-hands
+ $filetime = filemtime($filename);
+ $filesize = filesize($filename);
+ $filenam2 = mysql_escape_string($filename);
+
+ // Loopup file
+ $this->cursor = mysql_query("SELECT `value` FROM `getid3_cache` WHERE (`filename`='".$filenam2."') AND (`filesize`='".$filesize."') AND (`filetime`='".$filetime."')", $this->connection);
+ list($result) = @mysql_fetch_array($this->cursor);
+
+ // Hit
+ if ($result) {
+ return unserialize($result);
+ }
+ }
+
+ // Miss
+ $result = parent::analyze($filename);
+
+ // Save result
+ if (file_exists($filename)) {
+ $res2 = mysql_escape_string(serialize($result));
+ $this->cursor = mysql_query("INSERT INTO `getid3_cache` (`filename`, `filesize`, `filetime`, `analyzetime`, `value`) VALUES ('".$filenam2."', '".$filesize."', '".$filetime."', '".time()."', '".$res2."')", $this->connection);
+ }
+ return $result;
+ }
+
+
+
+ // private: (re)create sql table
+ function create_table($drop = false) {
+
+ $this->cursor = mysql_query("CREATE TABLE IF NOT EXISTS `getid3_cache` (
+ `filename` VARCHAR(255) NOT NULL DEFAULT '',
+ `filesize` INT(11) NOT NULL DEFAULT '0',
+ `filetime` INT(11) NOT NULL DEFAULT '0',
+ `analyzetime` INT(11) NOT NULL DEFAULT '0',
+ `value` TEXT NOT NULL,
+ PRIMARY KEY (`filename`,`filesize`,`filetime`)) TYPE=MyISAM", $this->connection);
+ echo mysql_error($this->connection);
+ }
+}
+
+
+?>
\ No newline at end of file
Modified: plog/trunk/class/gallery/getid3/getid3.lib.php
===================================================================
--- plog/trunk/class/gallery/getid3/getid3.lib.php 2006-07-24 16:40:16 UTC (rev 3789)
+++ plog/trunk/class/gallery/getid3/getid3.lib.php 2006-07-24 16:56:08 UTC (rev 3790)
@@ -7,54 +7,10 @@
// //
// getid3.lib.php - part of getID3() //
// See readme.txt for more details //
-// //
-/////////////////////////////////////////////////////////////////
-// getid3_lib::GetURLImageSize( $urlpic ) determines the //
-// dimensions of local/remote URL pictures. //
-// returns array with ($width, $height, $type) //
-// //
-// Thanks to: Oyvind Hallsteinsen aka Gosub / ELq - //
-// gosubØelq*org for the original size determining code //
-// //
-// PHP Hack by Filipe Laborde-Basto Oct 21/2000 //
-// FREELY DISTRIBUTABLE -- use at your sole discretion! :) //
-// Enjoy. (Not to be sold in commercial packages though, //
-// keep it free!) Feel free to contact me at filØrezox*com //
-// (http://www.rezox.com) //
-// //
-// Modified by James Heinrich <getid3Øusers*sourceforge*net> //
-// June 1, 2001 - created GetDataImageSize($imgData) by //
-// seperating the fopen() stuff to GetURLImageSize($urlpic) //
-// which then calls GetDataImageSize($imgData). The idea being //
-// you can call GetDataImageSize($imgData) with image data //
-// from a database etc. //
// ///
/////////////////////////////////////////////////////////////////
-define('GETID3_GIF_SIG', "\x47\x49\x46"); // 'GIF'
-define('GETID3_PNG_SIG', "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A");
-define('GETID3_JPG_SIG', "\xFF\xD8\xFF");
-define('GETID3_JPG_SOS', "\xDA"); // Start Of Scan - image data start
-define('GETID3_JPG_SOF0', "\xC0"); // Start Of Frame N
-define('GETID3_JPG_SOF1', "\xC1"); // N indicates which compression process
-define('GETID3_JPG_SOF2', "\xC2"); // Only SOF0-SOF2 are now in common use
-define('GETID3_JPG_SOF3', "\xC3");
-// NB: codes C4 and CC are *not* SOF markers
-define('GETID3_JPG_SOF5', "\xC5");
-define('GETID3_JPG_SOF6', "\xC6");
-define('GETID3_JPG_SOF7', "\xC7");
-define('GETID3_JPG_SOF9', "\xC9");
-define('GETID3_JPG_SOF10', "\xCA");
-define('GETID3_JPG_SOF11', "\xCB");
-// NB: codes C4 and CC are *not* SOF markers
-define('GETID3_JPG_SOF13', "\xCD");
-define('GETID3_JPG_SOF14', "\xCE");
-define('GETID3_JPG_SOF15', "\xCF");
-define('GETID3_JPG_EOI', "\xD9"); // End Of Image (end of datastream)
-
-
-
class getid3_lib
{
@@ -568,7 +524,7 @@
die(implode(' and ', $RequiredFiles).' are required in '.GETID3_HELPERAPPSDIR.' for getid3_lib::md5_file() to function under Windows in PHP < v4.2.0');
}
}
- $commandline = GETID3_HELPERAPPSDIR.'md5sum.exe "'.str_replace('/', GETID3_OS_DIRSLASH, $file).'"';
+ $commandline = GETID3_HELPERAPPSDIR.'md5sum.exe "'.str_replace('/', DIRECTORY_SEPARATOR, $file).'"';
if (ereg("^[\\]?([0-9a-f]{32})", strtolower(`$commandline`), $r)) {
return $r[1];
}
@@ -603,14 +559,14 @@
die(implode(' and ', $RequiredFiles).' are required in '.GETID3_HELPERAPPSDIR.' for getid3_lib::sha1_file() to function under Windows in PHP < v4.3.0');
}
}
- $commandline = GETID3_HELPERAPPSDIR.'sha1sum.exe "'.str_replace('/', GETID3_OS_DIRSLASH, $file).'"';
+ $commandline = GETID3_HELPERAPPSDIR.'sha1sum.exe "'.str_replace('/', DIRECTORY_SEPARATOR, $file).'"';
if (ereg("^sha1=([0-9a-f]{40})", strtolower(`$commandline`), $r)) {
return $r[1];
}
} else {
- $commandline = 'sha1sum "'.$file.'"';
+ $commandline = 'sha1sum '.escapeshellarg($file).'';
if (ereg("^([0-9a-f]{40})[ \t\n\r]", strtolower(`$commandline`), $r)) {
return $r[1];
}
@@ -661,14 +617,14 @@
break;
}
}
- $commandline = GETID3_HELPERAPPSDIR.'head.exe -c '.$end.' "'.str_replace('/', GETID3_OS_DIRSLASH, $file).'" | ';
+ $commandline = GETID3_HELPERAPPSDIR.'head.exe -c '.$end.' "'.escapeshellarg(str_replace('/', DIRECTORY_SEPARATOR, $file)).'" | ';
$commandline .= GETID3_HELPERAPPSDIR.'tail.exe -c '.$size.' | ';
$commandline .= GETID3_HELPERAPPSDIR.$windows_call;
} else {
- $commandline = 'head -c '.$end.' "'.$file.'" | ';
- $commandline .= 'tail -c '.$size.' | ';
+ $commandline = 'head -c'.$end.' '.escapeshellarg($file).' | ';
+ $commandline .= 'tail -c'.$size.' | ';
$commandline .= $unix_call;
}
@@ -1211,84 +1167,19 @@
}
- function GetURLImageSize($urlpic) {
- if ($fd = @fopen($urlpic, 'rb')){
- $imgData = fread($fd, filesize($urlpic));
- fclose($fd);
- return getid3_lib::GetDataImageSize($imgData);
+ function GetDataImageSize($imgData) {
+ $GetDataImageSize = false;
+ if ($tempfilename = tempnam('*', 'getID3')) {
+ if ($tmp = @fopen($tempfilename, 'wb')) {
+ fwrite($tmp, $imgData);
+ fclose($tmp);
+ $GetDataImageSize = @GetImageSize($tempfilename);
+ }
+ unlink($tempfilename);
}
- return array('', '', '');
+ return $GetDataImageSize;
}
-
- function GetDataImageSize($imgData) {
- $height = '';
- $width = '';
- $type = '';
- if ((substr($imgData, 0, 3) == GETID3_GIF_SIG) && (strlen($imgData) > 10)) {
- $dim = unpack('v2dim', substr($imgData, 6, 4));
- $width = $dim['dim1'];
- $height = $dim['dim2'];
- $type = 1;
- } elseif ((substr($imgData, 0, 8) == GETID3_PNG_SIG) && (strlen($imgData) > 24)) {
- $dim = unpack('N2dim', substr($imgData, 16, 8));
- $width = $dim['dim1'];
- $height = $dim['dim2'];
- $type = 3;
- } elseif ((substr($imgData, 0, 3) == GETID3_JPG_SIG) && (strlen($imgData) > 4)) {
- ///////////////// JPG CHUNK SCAN ////////////////////
- $imgPos = 2;
- $type = 2;
- $buffer = strlen($imgData) - 2;
- while ($imgPos < strlen($imgData)) {
- // synchronize to the marker 0xFF
- $imgPos = strpos($imgData, 0xFF, $imgPos) + 1;
- $marker = $imgData[$imgPos];
- do {
- $marker = ord($imgData[$imgPos++]);
- } while ($marker == 255);
- // find dimensions of block
- switch (chr($marker)) {
- // Grab width/height from SOF segment (these are acceptable chunk types)
- case GETID3_JPG_SOF0:
- case GETID3_JPG_SOF1:
- case GETID3_JPG_SOF2:
- case GETID3_JPG_SOF3:
- case GETID3_JPG_SOF5:
- case GETID3_JPG_SOF6:
- case GETID3_JPG_SOF7:
- case GETID3_JPG_SOF9:
- case GETID3_JPG_SOF10:
- case GETID3_JPG_SOF11:
- case GETID3_JPG_SOF13:
- case GETID3_JPG_SOF14:
- case GETID3_JPG_SOF15:
- $dim = unpack('n2dim', substr($imgData, $imgPos + 3, 4));
- $height = $dim['dim1'];
- $width = $dim['dim2'];
- break 2; // found it so exit
- case GETID3_JPG_EOI:
- case GETID3_JPG_SOS:
- return false; // End loop in case we find one of these markers
- default: // We're not interested in other markers
- $skiplen = (ord($imgData[$imgPos++]) << 8) + ord($imgData[$imgPos++]) - 2;
- // if the skip is more than what we've read in, read more
- $buffer -= $skiplen;
- if ($buffer < 512) { // if the buffer of data is too low, read more file.
- // $imgData .= fread($fd, $skiplen + 1024);
- // $buffer += $skiplen + 1024;
- return false; // End loop in case we find run out of data
- }
- $imgPos += $skiplen;
- break;
- } // endswitch check marker type
- } // endif loop through JPG chunks
- } // endif chk for valid file types
-
- return array($width, $height, $type);
- } // end function
-
-
function ImageTypesLookup($imagetypeid) {
static $ImageTypesLookup = array();
if (empty($ImageTypesLookup)) {
@@ -1311,7 +1202,8 @@
}
function CopyTagsToComments(&$ThisFileInfo) {
- // Copy all entries from ['tags'] into common ['comments'] and ['comments_html']
+
+ // Copy all entries from ['tags'] into common ['comments']
if (!empty($ThisFileInfo['tags'])) {
foreach ($ThisFileInfo['tags'] as $tagtype => $tagarray) {
foreach ($tagarray as $tagname => $tagdata) {
@@ -1346,14 +1238,18 @@
}
if (empty($ThisFileInfo['comments'][$tagname]) || !in_array(trim($value), $ThisFileInfo['comments'][$tagname])) {
$ThisFileInfo['comments'][$tagname][] = trim($value);
- if (isset($ThisFileInfo['tags_html'][$tagtype][$tagname][$key])) {
- $ThisFileInfo['comments_html'][$tagname][] = $ThisFileInfo['tags_html'][$tagtype][$tagname][$key];
- }
}
}
}
}
}
+
+ // Copy to ['comments_html']
+ foreach ($ThisFileInfo['comments'] as $field => $values) {
+ foreach ($values as $index => $value) {
+ $ThisFileInfo['comments_html'][$field][$index] = str_replace('�', '', getid3_lib::MultiByteCharString2HTML($value, $ThisFileInfo['encoding']));
+ }
+ }
}
}
Modified: plog/trunk/class/gallery/getid3/getid3.php
===================================================================
--- plog/trunk/class/gallery/getid3/getid3.php 2006-07-24 16:40:16 UTC (rev 3789)
+++ plog/trunk/class/gallery/getid3/getid3.php 2006-07-24 16:56:08 UTC (rev 3790)
@@ -10,7 +10,7 @@
/////////////////////////////////////////////////////////////////
// Defines
-define('GETID3_VERSION', '1.7.4');
+define('GETID3_VERSION', '1.7.7');
define('GETID3_FREAD_BUFFER_SIZE', 16384); // read buffer size in bytes
@@ -18,28 +18,29 @@
class getID3
{
// public: Settings
- var $encoding = 'ISO-8859-1'; // CASE SENSITIVE! - i.e. (must be supported by iconv())
- // Examples: ISO-8859-1 UTF-8 UTF-16 UTF-16BE
+ var $encoding = 'ISO-8859-1'; // CASE SENSITIVE! - i.e. (must be supported by iconv())
+ // Examples: ISO-8859-1 UTF-8 UTF-16 UTF-16BE
- var $encoding_id3v1 = 'ISO-8859-1'; // Should always be 'ISO-8859-1', but some tags may be written
- // in other encodings such as 'EUC-CN'
+ var $encoding_id3v1 = 'ISO-8859-1'; // Should always be 'ISO-8859-1', but some tags may be written in other encodings such as 'EUC-CN'
+ var $tempdir = '*'; // default '*' should use system temp dir
+
// public: Optional tag checks - disable for speed.
- var $option_tag_id3v1 = true; // Read and process ID3v1 tags
- var $option_tag_id3v2 = true; // Read and process ID3v2 tags
- var $option_tag_lyrics3 = true; // Read and process Lyrics3 tags
- var $option_tag_apetag = true; // Read and process APE tags
- var $option_tags_process = true; // Copy tags to root key 'tags' and encode to $this->encoding
- var $option_tags_html = true; // Copy tags to root key 'tags_html' properly translated from various encodings to HTML entities
+ var $option_tag_id3v1 = true; // Read and process ID3v1 tags
+ var $option_tag_id3v2 = true; // Read and process ID3v2 tags
+ var $option_tag_lyrics3 = true; // Read and process Lyrics3 tags
+ var $option_tag_apetag = true; // Read and process APE tags
+ var $option_tags_process = true; // Copy tags to root key 'tags' and encode to $this->encoding
+ var $option_tags_html = true; // Copy tags to root key 'tags_html' properly translated from various encodings to HTML entities
// public: Optional tag/comment calucations
- var $option_extra_info = true; // Calculate additional info such as bitrate, channelmode etc
+ var $option_extra_info = true; // Calculate additional info such as bitrate, channelmode etc
// public: Optional calculations
- var $option_md5_data = false; // Get MD5 sum of data part - slow
- var $option_md5_data_source = false; // Use MD5 of source file if availble - only FLAC and OptimFROG
- var $option_sha1_data = false; // Get SHA1 sum of data part - slow
- var $option_max_2gb_check = true; // Check whether file is larger than 2 Gb and thus not supported by PHP
+ var $option_md5_data = false; // Get MD5 sum of data part - slow
+ var $option_md5_data_source = false; // Use MD5 of source file if availble - only FLAC and OptimFROG
+ var $option_sha1_data = false; // Get SHA1 sum of data part - slow
+ var $option_max_2gb_check = true; // Check whether file is larger than 2 Gb and thus not supported by PHP
// private
var $filename;
@@ -88,11 +89,9 @@
// Get base path of getID3() - ONCE
if (!defined('GETID3_INCLUDEPATH')) {
- define('GETID3_OS_DIRSLASH', (GETID3_OS_ISWINDOWS ? '\\' : '/'));
-
foreach (get_included_files() as $key => $val) {
if (basename($val) == 'getid3.php') {
- define('GETID3_INCLUDEPATH', dirname($val).GETID3_OS_DIRSLASH);
+ define('GETID3_INCLUDEPATH', dirname($val).DIRECTORY_SEPARATOR);
break;
}
}
@@ -111,32 +110,60 @@
// ie for "C:/Program Files/Apache/" put "C:/PROGRA~1/APACHE/"
// IMPORTANT: This path must include the trailing slash
if (GETID3_OS_ISWINDOWS && !defined('GETID3_HELPERAPPSDIR')) {
+ $helperappsdir = GETID3_INCLUDEPATH.'..'.DIRECTORY_SEPARATOR.'helperapps'; // must not have any space in this path
- $helperappsdir = GETID3_INCLUDEPATH.'..'.GETID3_OS_DIRSLASH.'helperapps'; // must not have any space in this path
+ if (!is_dir($helperappsdir)) {
- if (!is_dir($helperappsdir)) {
$this->startup_error .= '"'.$helperappsdir.'" cannot be defined as GETID3_HELPERAPPSDIR because it does not exist';
+
} elseif (strpos(realpath($helperappsdir), ' ') !== false) {
- $DirPieces = explode(GETID3_OS_DIRSLASH, realpath($helperappsdir));
- foreach ($DirPieces as $key => $value) {
- if ((strpos($value, '.') !== false) && (strpos($value, ' ') === false)) {
- if (strpos($value, '.') > 8) {
- $value = substr($value, 0, 6).'~1';
- }
- } elseif ((strpos($value, ' ') !== false) || strlen($value) > 8) {
- $value = substr($value, 0, 6).'~1';
- }
- $DirPieces[$key] = strtoupper($value);
+
+ $DirPieces = explode(DIRECTORY_SEPARATOR, realpath($helperappsdir));
+ $DirPieces8 = $DirPieces;
+
+ $CLIdir = $DirPieces[0].' && cd \\';
+ for ($i = 1; $i < count($DirPieces); $i++) {
+ if (strpos($DirPieces[$i], ' ') === false) {
+ $CLIdir .= ' && cd '.$DirPieces[$i];
+ } else {
+ ob_start();
+ system($CLIdir.' && dir /ad /x');
+ $subdirsraw = explode("\n", ob_get_contents());
+ ob_end_clean();
+ foreach ($subdirsraw as $dummy => $line) {
+ if (eregi('^[0-9]{4}/[0-9]{2}/[0-9]{2} [0-9]{2}:[0-9]{2} [AP]M <DIR> ([^ ]{8}) '.preg_quote($DirPieces[$i]).'$', trim($line), $matches)) {
+ $CLIdir .= ' && cd '.$matches[1];
+ break;
+ }
+ }
+ $DirPieces8[$i] = $matches[1];
+ }
}
- $this->startup_error .= 'GETID3_HELPERAPPSDIR must not have any spaces in it - use 8dot3 naming convention if neccesary (on this server that would be something like "'.implode(GETID3_OS_DIRSLASH, $DirPieces).'" - NOTE: this may or may not be the actual 8.3 equivalent of "'.$helperappsdir.'", please double-check). You can run "dir /x" from the commandline to see the correct 8.3-style names. You need to edit the file "'.GETID3_INCLUDEPATH.'/getid3.php" around line '.(__LINE__ - 16);
+ $helperappsdir = implode(DIRECTORY_SEPARATOR, $DirPieces8);
+
}
- define('GETID3_HELPERAPPSDIR', realpath($helperappsdir).GETID3_OS_DIRSLASH);
+ define('GETID3_HELPERAPPSDIR', realpath($helperappsdir).DIRECTORY_SEPARATOR);
+
}
}
+ // public: setOption
+ function setOption($optArray) {
+ if (!is_array($optArray) || empty($optArray)) {
+ return false;
+ }
+ foreach ($optArray as $opt => $val) {
+ if (isset($this, $opt) === false) {
+ continue;
+ }
+ $this->$opt = $val;
+ }
+ return true;
+ }
+
// public: analyze file - replaces GetAllFileInfo() and GetTagOnly()
function analyze($filename) {
@@ -392,7 +419,7 @@
// remove possible empty keys
$AVpossibleEmptyKeys = array('dataformat', 'bits_per_sample', 'encoder_options', 'streams');
- foreach ($AVpossibleEmptyKeys as $key) {
+ foreach ($AVpossibleEmptyKeys as $dummy => $key) {
if (empty($this->info['audio'][$key]) && isset($this->info['audio'][$key])) {
unset($this->info['audio'][$key]);
}
@@ -436,7 +463,7 @@
'group' => 'audio',
'module' => 'ac3',
'mime_type' => 'audio/ac3',
- ),
+ ),
// AAC - audio - Advanced Audio Coding (AAC) - ADIF format
'adif' => array(
@@ -446,7 +473,7 @@
'option' => 'adif',
'mime_type' => 'application/octet-stream',
'fail_ape' => 'WARNING',
- ),
+ ),
// AAC - audio - Advanced Audio Coding (AAC) - ADTS format (very similar to MP3)
@@ -457,7 +484,7 @@
'option' => 'adts',
'mime_type' => 'application/octet-stream',
'fail_ape' => 'WARNING',
- ),
+ ),
// AU - audio - NeXT/Sun AUdio (AU)
@@ -466,7 +493,7 @@
'group' => 'audio',
'module' => 'au',
'mime_type' => 'audio/basic',
- ),
+ ),
// AVR - audio - Audio Visual Research
'avr' => array(
@@ -474,7 +501,7 @@
'group' => 'audio',
'module' => 'avr',
'mime_type' => 'application/octet-stream',
- ),
+ ),
// BONK - audio - Bonk v0.9+
'bonk' => array(
@@ -482,7 +509,7 @@
'group' => 'audio',
'module' => 'bonk',
'mime_type' => 'audio/xmms-bonk',
- ),
+ ),
// FLAC - audio - Free Lossless Audio Codec
'flac' => array(
@@ -490,7 +517,7 @@
'group' => 'audio',
'module' => 'flac',
'mime_type' => 'audio/x-flac',
- ),
+ ),
// LA - audio - Lossless Audio (LA)
'la' => array(
@@ -498,7 +525,7 @@
'group' => 'audio',
'module' => 'la',
'mime_type' => 'application/octet-stream',
- ),
+ ),
// LPAC - audio - Lossless Predictive Audio Compression (LPAC)
'lpac' => array(
@@ -506,7 +533,7 @@
'group' => 'audio',
'module' => 'lpac',
'mime_type' => 'application/octet-stream',
- ),
+ ),
// MIDI - audio - MIDI (Musical Instrument Digital Interface)
'midi' => array(
@@ -514,7 +541,7 @@
'group' => 'audio',
'module' => 'midi',
'mime_type' => 'audio/midi',
- ),
+ ),
// MAC - audio - Monkey's Audio Compressor
'mac' => array(
@@ -522,7 +549,7 @@
'group' => 'audio',
'module' => 'monkey',
'mime_type' => 'application/octet-stream',
- ),
+ ),
// MOD - audio - MODule (assorted sub-formats)
'mod' => array(
@@ -531,7 +558,7 @@
'module' => 'mod',
'option' => 'mod',
'mime_type' => 'audio/mod',
- ),
+ ),
// MOD - audio - MODule (Impulse Tracker)
'it' => array(
@@ -540,7 +567,7 @@
'module' => 'mod',
'option' => 'it',
'mime_type' => 'audio/it',
- ),
+ ),
// MOD - audio - MODule (eXtended Module, various sub-formats)
'xm' => array(
@@ -549,7 +576,7 @@
'module' => 'mod',
'option' => 'xm',
'mime_type' => 'audio/xm',
- ),
+ ),
// MOD - audio - MODule (ScreamTracker)
's3m' => array(
@@ -558,7 +585,7 @@
'module' => 'mod',
'option' => 's3m',
'mime_type' => 'audio/s3m',
- ),
+ ),
// MPC - audio - Musepack / MPEGplus
'mpc' => array(
@@ -566,7 +593,7 @@
'group' => 'audio',
'module' => 'mpc',
'mime_type' => 'application/octet-stream',
- ),
+ ),
// MP3 - audio - MPEG-audio Layer 3 (very similar to AAC-ADTS)
'mp3' => array(
@@ -574,7 +601,7 @@
'group' => 'audio',
'module' => 'mp3',
'mime_type' => 'audio/mpeg',
- ),
+ ),
// OFR - audio - OptimFROG
'ofr' => array(
@@ -582,7 +609,7 @@
'group' => 'audio',
'module' => 'optimfrog',
'mime_type' => 'application/octet-stream',
- ),
+ ),
// RKAU - audio - RKive AUdio compressor
'rkau' => array(
@@ -590,7 +617,7 @@
'group' => 'audio',
'module' => 'rkau',
'mime_type' => 'application/octet-stream',
- ),
+ ),
// SHN - audio - Shorten
'shn' => array(
@@ -600,7 +627,7 @@
'mime_type' => 'audio/xmms-shn',
'fail_id3' => 'ERROR',
'fail_ape' => 'ERROR',
- ),
+ ),
// TTA - audio - TTA Lossless Audio Compressor (http://tta.corecodec.org)
'tta' => array(
@@ -608,7 +635,7 @@
'group' => 'audio',
'module' => 'tta',
'mime_type' => 'application/octet-stream',
- ),
+ ),
// VOC - audio - Creative Voice (VOC)
'voc' => array(
@@ -616,7 +643,7 @@
'group' => 'audio',
'module' => 'voc',
'mime_type' => 'audio/voc',
- ),
+ ),
// VQF - audio - transform-domain weighted interleave Vector Quantization Format (VQF)
'vqf' => array(
@@ -624,7 +651,7 @@
'group' => 'audio',
'module' => 'vqf',
'mime_type' => 'application/octet-stream',
- ),
+ ),
// WV - audio - WavPack (v4.0+)
'wv' => array(
@@ -632,7 +659,7 @@
'group' => 'audio',
'module' => 'wavpack',
'mime_type' => 'application/octet-stream',
- ),
+ ),
// Audio-Video formats
@@ -644,23 +671,31 @@
'module' => 'asf',
'mime_type' => 'video/x-ms-asf',
'iconv_req' => false,
- ),
+ ),
- // BINK - audio/video - Bink / Smacker
+ // BINK - audio/video - Bink / Smacker
'bink' => array(
'pattern' => '^(BIK|SMK)',
'group' => 'audio-video',
'module' => 'bink',
'mime_type' => 'application/octet-stream',
- ),
+ ),
+ // FLV - audio/video - FLash Video
+ 'flv' => array(
+ 'pattern' => '^FLV\x01',
+ 'group' => 'audio-video',
+ 'module' => 'flv',
+ 'mime_type' => 'video/x-flv',
+ ),
+
// MKAV - audio/video - Mastroka
'matroska' => array(
'pattern' => '^\x1A\x45\xDF\xA3',
'group' => 'audio-video',
'module' => 'matroska',
'mime_type' => 'application/octet-stream',
- ),
+ ),
// MPEG - audio/video - MPEG (Moving Pictures Experts Group)
'mpeg' => array(
@@ -668,7 +703,7 @@
'group' => 'audio-video',
'module' => 'mpeg',
'mime_type' => 'video/mpeg',
- ),
+ ),
// NSV - audio/video - Nullsoft Streaming Video (NSV)
'nsv' => array(
@@ -676,7 +711,7 @@
'group' => 'audio-video',
'module' => 'nsv',
'mime_type' => 'application/octet-stream',
- ),
+ ),
// Ogg - audio/video - Ogg (Ogg-Vorbis, Ogg-FLAC, Speex, Ogg-Theora(*), Ogg-Tarkin(*))
'ogg' => array(
@@ -686,7 +721,7 @@
'mime_type' => 'application/ogg',
'fail_id3' => 'WARNING',
'fail_ape' => 'WARNING',
- ),
+ ),
// QT - audio/video - Quicktime
'quicktime' => array(
@@ -694,7 +729,7 @@
'group' => 'audio-video',
'module' => 'quicktime',
'mime_type' => 'video/quicktime',
- ),
+ ),
// RIFF - audio/video - Resource Interchange File Format (RIFF) / WAV / AVI / CD-audio / SDSS = renamed variant used by SmartSound QuickTracks (www.smartsound.com) / FORM = Audio Interchange File Format (AIFF)
'riff' => array(
@@ -703,7 +738,7 @@
'module' => 'riff',
'mime_type' => 'audio/x-wave',
'fail_ape' => 'WARNING',
- ),
+ ),
// Real - audio/video - RealAudio, RealVideo
'real' => array(
@@ -711,7 +746,7 @@
'group' => 'audio-video',
'module' => 'real',
'mime_type' => 'audio/x-realaudio',
- ),
+ ),
// SWF - audio/video - ShockWave Flash
'swf' => array(
@@ -719,7 +754,7 @@
'group' => 'audio-video',
'module' => 'swf',
'mime_type' => 'application/x-shockwave-flash',
- ),
+ ),
// Still-Image formats
@@ -732,7 +767,7 @@
'mime_type' => 'image/bmp',
'fail_id3' => 'ERROR',
'fail_ape' => 'ERROR',
- ),
+ ),
// GIF - still image - Graphics Interchange Format
'gif' => array(
@@ -742,7 +777,7 @@
'mime_type' => 'image/gif',
'fail_id3' => 'ERROR',
'fail_ape' => 'ERROR',
- ),
+ ),
// JPEG - still image - Joint Photographic Experts Group (JPEG)
'jpg' => array(
@@ -752,7 +787,7 @@
'mime_type' => 'image/jpeg',
'fail_id3' => 'ERROR',
'fail_ape' => 'ERROR',
- ),
+ ),
// PCD - still image - Kodak Photo CD
'pcd' => array(
@@ -762,7 +797,7 @@
'mime_type' => 'image/x-photo-cd',
'fail_id3' => 'ERROR',
'fail_ape' => 'ERROR',
- ),
+ ),
// PNG - still image - Portable Network Graphics (PNG)
@@ -773,7 +808,7 @@
'mime_type' => 'image/png',
'fail_id3' => 'ERROR',
'fail_ape' => 'ERROR',
- ),
+ ),
// TIFF - still image - Tagged Information File Format (TIFF)
@@ -784,7 +819,7 @@
'mime_type' => 'image/tiff',
'fail_id3' => 'ERROR',
'fail_ape' => 'ERROR',
- ),
+ ),
// Data formats
@@ -798,7 +833,7 @@
'fail_id3' => 'ERROR',
'fail_ape' => 'ERROR',
'iconv_req' => false,
- ),
+ ),
// RAR - data - RAR compressed data
'rar' => array(
@@ -808,9 +843,9 @@
'mime_type' => 'application/octet-stream',
'fail_id3' => 'ERROR',
'fail_ape' => 'ERROR',
- ),
+ ),
- // SZIP - audio - SZIP compressed data
+ // SZIP - audio/data - SZIP compressed data
'szip' => array(
'pattern' => '^SZ\x0A\x04',
'group' => 'archive',
@@ -818,7 +853,7 @@
'mime_type' => 'application/octet-stream',
'fail_id3' => 'ERROR',
'fail_ape' => 'ERROR',
- ),
+ ),
// TAR - data - TAR compressed data
'tar' => array(
@@ -828,7 +863,7 @@
'mime_type' => 'application/x-tar',
'fail_id3' => 'ERROR',
'fail_ape' => 'ERROR',
- ),
+ ),
// GZIP - data - GZIP compressed data
'gz' => array(
@@ -838,9 +873,9 @@
'mime_type' => 'application/x-gzip',
'fail_id3' => 'ERROR',
'fail_ape' => 'ERROR',
- ),
+ ),
- // ZIP - data - ZIP compressed data
+ // ZIP - data - ZIP compressed data
'zip' => array(
'pattern' => '^PK\x03\x04',
'group' => 'archive',
@@ -848,7 +883,30 @@
'mime_type' => 'application/zip',
'fail_id3' => 'ERROR',
'fail_ape' => 'ERROR',
- )
+ ),
+
+
+ // Misc other formats
+
+ // PDF - data - ZIP compressed data
+ 'pdf' => array(
+ 'pattern' => '^\x25PDF',
+ 'group' => 'misc',
+ 'module' => 'pdf',
+ 'mime_type' => 'application/pdf',
+ 'fail_id3' => 'ERROR',
+ 'fail_ape' => 'ERROR',
+ ),
+
+ // MSOFFICE - data - ZIP compressed data
+ 'msoffice' => array(
+ 'pattern' => '^\xD0\xCF\x11\xE0', // D0CF11E == DOCFILE == Microsoft Office Document
+ 'group' => 'misc',
+ 'module' => 'msoffice',
+ 'mime_type' => 'application/octet-stream',
+ 'fail_id3' => 'ERROR',
+ 'fail_ape' => 'ERROR',
+ ),
);
}
@@ -876,29 +934,12 @@
if (preg_match('/\.mp[123a]$/i', $filename)) {
-
// Too many mp3 encoders on the market put gabage in front of mpeg files
// use assume format on these if format detection failed
$GetFileFormatArray = $this->GetFileFormatArray();
$info = $GetFileFormatArray['mp3'];
$info['include'] = 'module.'.$info['group'].'.'.$info['module'].'.php';
return $info;
-
- //} elseif (preg_match('/\.tar$/i', $filename)) {
- //
- // // TAR files don't have any useful header to work from
- // // TAR - data - TAR compressed data
- // $info = array(
- // 'pattern' => '^.{512}',
- // 'group' => 'archive',
- // 'module' => 'tar',
- // 'mime_type' => 'application/octet-stream',
- // 'fail_id3' => 'ERROR',
- // 'fail_ape' => 'ERROR',
- // );
- // $info['include'] = 'module.'.$info['group'].'.'.$info['module'].'.php';
- // return $info;
-
}
return false;
@@ -1065,6 +1106,7 @@
} else {
$commandline = 'vorbiscomment -w -c "'.$empty.'" "'.$file.'" "'.$temp.'" 2>&1';
+ $commandline = 'vorbiscomment -w -c '.escapeshellarg($empty).' '.escapeshellarg($file).' '.escapeshellarg($temp).' 2>&1';
$VorbisCommentError = `$commandline`;
}
@@ -1254,6 +1296,10 @@
return true;
}
+ function getid3_tempnam() {
+ return tempnam($this->tempdir, 'gI3');
+ }
+
}
?>
\ No newline at end of file
Modified: plog/trunk/class/gallery/getid3/module.archive.gzip.php
===================================================================
--- plog/trunk/class/gallery/getid3/module.archive.gzip.php 2006-07-24 16:40:16 UTC (rev 3789)
+++ plog/trunk/class/gallery/getid3/module.archive.gzip.php 2006-07-24 16:56:08 UTC (rev 3790)
@@ -17,16 +17,11 @@
class getid3_gzip {
// public: Optional file list - disable for speed.
- var $option_gzip_parse_contents = true; // decode gzipped files, if possible, and parse recursively (.tar.gz for example)
+ var $option_gzip_parse_contents = false; // decode gzipped files, if possible, and parse recursively (.tar.gz for example)
function getid3_gzip(&$fd, &$ThisFileInfo) {
$ThisFileInfo['fileformat'] = 'gzip';
- return $this->read_gzip($fd, $ThisFileInfo);
- }
- // Reads the gzip-file
- function read_gzip($fd, &$ThisFileInfo) {
-
$start_length = 10;
$unpack_header = 'a1id1/a1id2/a1cmethod/a1flags/a4mtime/a1xflags/a1os';
//+---+---+---+---+---+---+---+---+---+---+
Modified: plog/trunk/class/gallery/getid3/module.archive.tar.php
===================================================================
--- plog/trunk/class/gallery/getid3/module.archive.tar.php 2006-07-24 16:40:16 UTC (rev 3789)
+++ plog/trunk/class/gallery/getid3/module.archive.tar.php 2006-07-24 16:56:08 UTC (rev 3790)
@@ -18,35 +18,25 @@
function getid3_tar(&$fd, &$ThisFileInfo) {
$ThisFileInfo['fileformat'] = 'tar';
+ $ThisFileInfo['tar']['files'] = array();
- @fseek($fd, 0);
- $filebuffer = @fread($fd, $ThisFileInfo['filesize']);
- return $this->read_tar($filebuffer, $ThisFileInfo);
- }
-
- // Reads the tar-file
- function read_tar(&$filebuffer, &$ThisFileInfo) {
-
- $header_length = 512;
$unpack_header = 'a100fname/a8mode/a8uid/a8gid/a12size/a12mtime/a8chksum/a1typflag/a100lnkname/a6magic/a2ver/a32uname/a32gname/a8devmaj/a8devmin/a155/prefix';
-
$null_512k = str_repeat("\0", 512); // end-of-file marker
- $ThisFileInfo['tar']['files'] = array();
+ @fseek($fd, 0);
+ while (!feof($fd)) {
+ $buffer = fread($fd, 512);
- while(strlen($filebuffer) != 0) {
- $buffer = substr($filebuffer, 0, $header_length);
- $filebuffer = substr($filebuffer, strlen($buffer));
// check the block
$checksum = 0;
for ($i = 0; $i < 148; $i++) {
- $checksum += ord(substr($buffer, $i, 1));
+ $checksum += ord($buffer{$i});
}
for ($i = 148; $i < 156; $i++) {
$checksum += ord(' ');
}
for ($i = 156; $i < 512; $i++) {
- $checksum += ord(substr($buffer, $i, 1));
+ $checksum += ord($buffer{$i});
}
$attr = unpack($unpack_header, $buffer);
$name = trim(@$attr['fname']);
@@ -65,8 +55,8 @@
$devmaj = octdec(trim(@$attr['devmaj']));
$devmin = octdec(trim(@$attr['devmin']));
$prefix = trim(@$attr['prefix']);
- // EOF Found
if (($checksum == 256) && ($chksum == 0)) {
+ // EOF Found
break;
}
if ($prefix) {
@@ -75,22 +65,18 @@
if ((preg_match('#/$#', $name)) && !$name) {
$typeflag = 5;
}
- // If it's the end of the tar-file...
if ($buffer == $null_512k) {
+ // it's the end of the tar-file...
break;
}
- // Read the next chunk
- $data = substr($filebuffer, 0, $size);
- $filebuffer = substr($filebuffer, strlen($data));
- if (strlen($data) != $size) {
- $ThisFileInfo['error'][] = 'Read error on tar file';
- return false;
- }
+
+ // Read to the next chunk
+ fseek($fd, $size, SEEK_CUR);
+
$diff = $size % 512;
if ($diff != 0) {
// Padding, throw away
- $buff = substr($filebuffer, 0, (512 - $diff));
- $filebuffer = substr($filebuffer, strlen($buff));
+ fseek($fd, (512 - $diff), SEEK_CUR);
}
// Protect against tar-files with garbage at the end
if ($name == '') {
@@ -122,7 +108,7 @@
// Parses the file mode to file permissions
function display_perms($mode) {
// Determine Type
- if ($mode & 0x1000) $type='p'; // FIFO pipe
+ if ($mode & 0x1000) $type='p'; // FIFO pipe
elseif ($mode & 0x2000) $type='c'; // Character special
elseif ($mode & 0x4000) $type='d'; // Directory
elseif ($mode & 0x6000) $type='b'; // Block special
Modified: plog/trunk/class/gallery/getid3/module.archive.zip.php
===================================================================
--- plog/trunk/class/gallery/getid3/module.archive.zip.php 2006-07-24 16:40:16 UTC (rev 3789)
+++ plog/trunk/class/gallery/getid3/module.archive.zip.php 2006-07-24 16:56:08 UTC (rev 3790)
@@ -406,7 +406,7 @@
$UNIXminute = (($DOStime & 0x07E0) >> 5);
$UNIXhour = (($DOStime & 0xF800) >> 11);
- return mktime($UNIXhour, $UNIXminute, $UNIXsecond, $UNIXmonth, $UNIXday, $UNIXyear);
+ return gmmktime($UNIXhour, $UNIXminute, $UNIXsecond, $UNIXmonth, $UNIXday, $UNIXyear);
}
}
Modified: plog/trunk/class/gallery/getid3/module.audio-video.asf.php
===================================================================
--- plog/trunk/class/gallery/getid3/module.audio-video.asf.php 2006-07-24 16:40:16 UTC (rev 3789)
+++ plog/trunk/class/gallery/getid3/module.audio-video.asf.php 2006-07-24 16:56:08 UTC (rev 3790)
@@ -146,7 +146,8 @@
$offset += 4;
$thisfile_asf_filepropertiesobject['max_bitrate'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
$offset += 4;
- $ThisFileInfo['bitrate'] = $thisfile_asf_filepropertiesobject['max_bitrate'];
+ //$ThisFileInfo['bitrate'] = $thisfile_asf_filepropertiesobject['max_bitrate'];
+ $ThisFileInfo['bitrate'] = ($thisfile_asf_filepropertiesobject['filesize'] * 8) / $ThisFileInfo['playtime_seconds'];
break;
case GETID3_ASF_Stream_Properties_Object:
@@ -331,45 +332,56 @@
if (!isset($thisfile_audio['bitrate']) && strstr($AudioCodecBitrate, 'kbps')) {
$thisfile_audio['bitrate'] = (int) (trim(str_replace('kbps', '', $AudioCodecBitrate)) * 1000);
}
- if (!isset($thisfile_video['bitrate']) && isset($thisfile_audio['bitrate']) && isset($thisfile_asf['file_properties_object']['max_bitrate']) && ($thisfile_asf_codeclistobject['codec_entries_count'] > 1)) {
- $thisfile_video['bitrate'] = $thisfile_asf['file_properties_object']['max_bitrate'] - $thisfile_audio['bitrate'];
+ //if (!isset($thisfile_video['bitrate']) && isset($thisfile_audio['bitrate']) && isset($thisfile_asf['file_properties_object']['max_bitrate']) && ($thisfile_asf_codeclistobject['codec_entries_count'] > 1)) {
+ if (!@$thisfile_video['bitrate'] && @$thisfile_audio['bitrate'] && @$ThisFileInfo['bitrate']) {
+ //$thisfile_video['bitrate'] = $thisfile_asf['file_properties_object']['max_bitrate'] - $thisfile_audio['bitrate'];
+ $thisfile_video['bitrate'] = $ThisFileInfo['bitrate'] - $thisfile_audio['bitrate'];
}
$AudioCodecFrequency = (int) trim(str_replace('kHz', '', $AudioCodecFrequency));
switch ($AudioCodecFrequency) {
case 8:
+ case 8000:
$thisfile_audio['sample_rate'] = 8000;
break;
case 11:
+ case 11025:
$thisfile_audio['sample_rate'] = 11025;
break;
case 12:
+ case 12000:
$thisfile_audio['sample_rate'] = 12000;
break;
case 16:
+ case 16000:
$thisfile_audio['sample_rate'] = 16000;
break;
case 22:
+ case 22050:
$thisfile_audio['sample_rate'] = 22050;
break;
case 24:
+ case 24000:
$thisfile_audio['sample_rate'] = 24000;
break;
case 32:
+ case 32000:
$thisfile_audio['sample_rate'] = 32000;
break;
case 44:
+ case 441000:
$thisfile_audio['sample_rate'] = 44100;
break;
case 48:
+ case 48000:
$thisfile_audio['sample_rate'] = 48000;
break;
@@ -754,6 +766,11 @@
$thisfile_asf_comments['year'] = array( $this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
break;
+ case 'wm/lyrics':
+ case 'lyrics':
+ $thisfile_asf_comments['lyrics'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
+ break;
+
case 'isvbr':
if ($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']) {
$thisfile_audio['bitrate_mode'] = 'vbr';
@@ -769,12 +786,12 @@
$tempThisfileInfo = array('encoding'=>$ThisFileInfo['encoding']);
fwrite($tempfilehandle, $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']);
fclose($tempfilehandle);
-
+
$tempfilehandle = fopen($tempfile, "rb");
$id3 = new getid3_id3v2($tempfilehandle, $tempThisfileInfo);
fclose($tempfilehandle);
unlink($tempfile);
-
+
$ThisFileInfo['id3v2'] = $tempThisfileInfo['id3v2'];
}
break;
@@ -853,16 +870,16 @@
$thisfile_asf['stream_bitrate_properties_object'] = array();
$thisfile_asf_streambitratepropertiesobject = &$thisfile_asf['stream_bitrate_properties_object'];
- $thisfile_asf_streambitrateproperties['objectid'] = $NextObjectGUID;
- $thisfile_asf_streambitrateproperties['objectid_guid'] = $NextObjectGUIDtext;
- $thisfile_asf_streambitrateproperties['objectsize'] = $NextObjectSize;
- $thisfile_asf_streambitrateproperties['bitrate_records_count'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
+ $thisfile_asf_streambitratepropertiesobject['objectid'] = $NextObjectGUID;
+ $thisfile_asf_streambitratepropertiesobject['objectid_guid'] = $NextObjectGUIDtext;
+ $thisfile_asf_streambitratepropertiesobject['objectsize'] = $NextObjectSize;
+ $thisfile_asf_streambitratepropertiesobject['bitrate_records_count'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
$offset += 2;
- for ($BitrateRecordsCounter = 0; $BitrateRecordsCounter < $thisfile_asf_streambitrateproperties['bitrate_records_count']; $BitrateRecordsCounter++) {
- $thisfile_asf_streambitrateproperties['bitrate_records'][$BitrateRecordsCounter]['flags_raw'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
+ for ($BitrateRecordsCounter = 0; $BitrateRecordsCounter < $thisfile_asf_streambitratepropertiesobject['bitrate_records_count']; $BitrateRecordsCounter++) {
+ $thisfile_asf_streambitratepropertiesobject['bitrate_records'][$BitrateRecordsCounter]['flags_raw'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
$offset += 2;
- $thisfile_asf_streambitrateproperties['bitrate_records'][$BitrateRecordsCounter]['flags']['stream_number'] = $thisfile_asf_streambitrateproperties['bitrate_records'][$BitrateRecordsCounter]['flags_raw'] & 0x007F;
- $thisfile_asf_streambitrateproperties['bitrate_records'][$BitrateRecordsCounter]['bitrate'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
+ $thisfile_asf_streambitratepropertiesobject['bitrate_records'][$BitrateRecordsCounter]['flags']['stream_number'] = $thisfile_asf_streambitratepropertiesobject['bitrate_records'][$BitrateRecordsCounter]['flags_raw'] & 0x007F;
+ $thisfile_asf_streambitratepropertiesobject['bitrate_records'][$BitrateRecordsCounter]['bitrate'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
$offset += 4;
}
break;
@@ -923,14 +940,17 @@
}
}
if ($ASFbitrateAudio > 0) {
- $thisfile_audio['bitrate'] = $ASFbitrateAudio;
+ $thisfile_audio['bitrate'] = $ASFbitrateAudio;
}
if ($ASFbitrateVideo > 0) {
- $thisfile_video['bitrate'] = $ASFbitrateVideo;
+ $thisfile_video['bitrate'] = $ASFbitrateVideo;
}
}
if (isset($thisfile_asf['stream_properties_object']) && is_array($thisfile_asf['stream_properties_object'])) {
+ $thisfile_audio['bitrate'] = 0;
+ $thisfile_video['bitrate'] = 0;
+
foreach ($thisfile_asf['stream_properties_object'] as $streamnumber => $streamdata) {
switch ($streamdata['stream_type']) {
@@ -962,8 +982,20 @@
break;
}
- if (!isset($thisfile_audio['bitrate'])) {
- $thisfile_audio['bitrate'] = $thisfile_asf_audiomedia_currentstream['bytes_sec'] * 8;
+ if (!empty($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'])) {
+ foreach ($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'] as $dummy => $dataarray) {
+ if (@$dataarray['flags']['stream_number'] == $streamnumber) {
+ $thisfile_asf_audiomedia_currentstream['bitrate'] = $dataarray['bitrate'];
+ $thisfile_audio['bitrate'] += $dataarray['bitrate'];
+ break;
+ }
+ }
+ } else {
+ if (@$thisfile_asf_audiomedia_currentstream['bytes_sec']) {
+ $thisfile_audio['bitrate'] += $thisfile_asf_audiomedia_currentstream['bytes_sec'] * 8;
+ } elseif (@$thisfile_asf_audiomedia_currentstream['bitrate']) {
+ $thisfile_audio['bitrate'] += $thisfile_asf_audiomedia_currentstream['bitrate'];
+ }
}
$thisfile_audio['streams'][$streamnumber] = $thisfile_asf_audiomedia_currentstream;
$thisfile_audio['streams'][$streamnumber]['wformattag'] = $thisfile_asf_audiomedia_currentstream['raw']['wFormatTag'];
@@ -1035,14 +1067,24 @@
$videomediaoffset += 4;
$thisfile_asf_videomedia_currentstream['format_data']['codec_data'] = substr($streamdata['type_specific_data'], $videomediaoffset);
+ if (!empty($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'])) {
+ foreach ($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'] as $dummy => $dataarray) {
+ if (@$dataarray['flags']['stream_number'] == $streamnumber) {
+ $thisfile_asf_videomedia_currentstream['bitrate'] = $dataarray['bitrate'];
+ $thisfile_video['streams'][$streamnumber]['bitrate'] = $dataarray['bitrate'];
+ $thisfile_video['bitrate'] += $dataarray['bitrate'];
+ break;
+ }
+ }
+ }
$thisfile_asf_videomedia_currentstream['format_data']['codec'] = getid3_riff::RIFFfourccLookup($thisfile_asf_videomedia_currentstream['format_data']['codec_fourcc']);
- $thisfile_video['fourcc'] = $thisfile_asf_videomedia_currentstream['format_data']['codec_fourcc'];
- $thisfile_video['codec'] = $thisfile_asf_videomedia_currentstream['format_data']['codec'];
- $thisfile_video['resolution_x'] = $thisfile_asf_videomedia_currentstream['image_width'];
- $thisfile_video['resolution_y'] = $thisfile_asf_videomedia_currentstream['image_height'];
- $thisfile_video['bits_per_sample'] = $thisfile_asf_videomedia_currentstream['format_data']['bits_per_pixel'];
+ $thisfile_video['streams'][$streamnumber]['fourcc'] = $thisfile_asf_videomedia_currentstream['format_data']['codec_fourcc'];
+ $thisfile_video['streams'][$streamnumber]['codec'] = $thisfile_asf_videomedia_currentstream['format_data']['codec'];
+ $thisfile_video['streams'][$streamnumber]['resolution_x'] = $thisfile_asf_videomedia_currentstream['image_width'];
+ $thisfile_video['streams'][$streamnumber]['resolution_y'] = $thisfile_asf_videomedia_currentstream['image_height'];
+ $thisfile_video['streams'][$streamnumber]['bits_per_sample'] = $thisfile_asf_videomedia_currentstream['format_data']['bits_per_pixel'];
break;
default:
@@ -1278,7 +1320,7 @@
}
}
- switch ($thisfile_audio['codec']) {
+ switch (@$thisfile_audio['codec']) {
case 'MPEG Layer-3':
$thisfile_audio['dataformat'] = 'mp3';
break;
@@ -1321,7 +1363,7 @@
$thisfile_video['pixel_aspect_ratio'] = (isset($thisfile_audio['pixel_aspect_ratio']) ? $thisfile_audio['pixel_aspect_ratio'] : (float) 1);
$thisfile_video['dataformat'] = (!empty($thisfile_video['dataformat']) ? $thisfile_video['dataformat'] : 'asf');
}
-
+ $ThisFileInfo['bitrate'] = @$thisfile_audio['bitrate'] + @$thisfile_video['bitrate'];
return true;
}
Added: plog/trunk/class/gallery/getid3/module.audio-video.flv.php
===================================================================
--- plog/trunk/class/gallery/getid3/module.audio-video.flv.php 2006-07-24 16:40:16 UTC (rev 3789)
+++ plog/trunk/class/gallery/getid3/module.audio-video.flv.php 2006-07-24 16:56:08 UTC (rev 3790)
@@ -0,0 +1,497 @@
+<?php
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info at getid3.org> //
+// available at http://getid3.sourceforge.net //
+// or http://www.getid3.org //
+// //
+// FLV module by Seth Kaufman <seth at whirl-i-gig.com> //
+// //
+// * version 0.1 (26 June 2005) //
+// //
+// minor modifications by James Heinrich <info at getid3.org> //
+// * version 0.1.1 (15 July 2005) //
+// //
+// Support for On2 VP6 codec and meta information by //
+// Steve Webster <steve.webster at featurecreep.com> //
+// * version 0.2 (22 February 2006) //
+// //
+// Modified to not read entire file into memory //
+// by James Heinrich <info at getid3.org> //
+// * version 0.3 (15 June 2006) //
+// //
+/////////////////////////////////////////////////////////////////
+// //
+// module.audio-video.flv.php //
+// module for analyzing Shockwave Flash Video files //
+// dependencies: NONE //
+// ///
+/////////////////////////////////////////////////////////////////
+
+define('GETID3_FLV_TAG_AUDIO', 8);
+define('GETID3_FLV_TAG_VIDEO', 9);
+define('GETID3_FLV_TAG_META', 18);
+
+define('GETID3_FLV_VIDEO_H263', 2);
+define('GETID3_FLV_VIDEO_SCREEN', 3);
+define('GETID3_FLV_VIDEO_VP6', 4);
+
+class getid3_flv
+{
+
+ function getid3_flv(&$fd, &$ThisFileInfo, $ReturnAllTagData=false) {
+ fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
+
+ $FLVdataLength = $ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset'];
+ $FLVheader = fread($fd, 5);
+
+ $ThisFileInfo['fileformat'] = 'flv';
+ $ThisFileInfo['flv']['header']['signature'] = substr($FLVheader, 0, 3);
+ $ThisFileInfo['flv']['header']['version'] = getid3_lib::BigEndian2Int(substr($FLVheader, 3, 1));
+ $TypeFlags = getid3_lib::BigEndian2Int(substr($FLVheader, 4, 1));
+
+ if ($ThisFileInfo['flv']['header']['signature'] != 'FLV') {
+ $ThisFileInfo['error'][] = 'Expecting "FLV" at offset '.$ThisFileInfo['avdataoffset'].', found "'.$ThisFileInfo['flv']['header']['signature'].'"';
+ unset($ThisFileInfo['flv']);
+ unset($ThisFileInfo['fileformat']);
+ return false;
+ }
+
+ $ThisFileInfo['flv']['header']['hasAudio'] = (bool) ($TypeFlags & 0x04);
+ $ThisFileInfo['flv']['header']['hasVideo'] = (bool) ($TypeFlags & 0x01);
+
+ $FrameSizeDataLength = getid3_lib::BigEndian2Int(fread($fd, 4));
+ $FLVheaderFrameLength = 9;
+ if ($FrameSizeDataLength > $FLVheaderFrameLength) {
+ fseek($fd, $FrameSizeDataLength - $FLVheaderFrameLength, SEEK_CUR);
+ }
+
+ $Duration = 0;
+ while ((ftell($fd) + 1) < $ThisFileInfo['avdataend']) {
+ //if (!$ThisFileInfo['flv']['header']['hasAudio'] || isset($ThisFileInfo['flv']['audio']['audioFormat'])) {
+ // if (!$ThisFileInfo['flv']['header']['hasVideo'] || isset($ThisFileInfo['flv']['video']['videoCodec'])) {
+ // break;
+ // }
+ //}
+
+ $ThisTagHeader = fread($fd, 16);
+
+ $PreviousTagLength = getid3_lib::BigEndian2Int(substr($ThisTagHeader, 0, 4));
+ $TagType = getid3_lib::BigEndian2Int(substr($ThisTagHeader, 4, 1));
+ $DataLength = getid3_lib::BigEndian2Int(substr($ThisTagHeader, 5, 3));
+ $Timestamp = getid3_lib::BigEndian2Int(substr($ThisTagHeader, 8, 3));
+ $LastHeaderByte = getid3_lib::BigEndian2Int(substr($ThisTagHeader, 15, 1));
+ $NextOffset = ftell($fd) - 1 + $DataLength;
+
+ switch ($TagType) {
+ case GETID3_FLV_TAG_AUDIO:
+ if (!isset($ThisFileInfo['flv']['audio']['audioFormat'])) {
+ $ThisFileInfo['flv']['audio']['audioFormat'] = $LastHeaderByte & 0x07;
+ $ThisFileInfo['flv']['audio']['audioRate'] = ($LastHeaderByte & 0x30) / 0x10;
+ $ThisFileInfo['flv']['audio']['audioSampleSize'] = ($LastHeaderByte & 0x40) / 0x40;
+ $ThisFileInfo['flv']['audio']['audioType'] = ($LastHeaderByte & 0x80) / 0x80;
+ }
+ break;
+
+ case GETID3_FLV_TAG_VIDEO:
+ if (!isset($ThisFileInfo['flv']['video']['videoCodec'])) {
+ $ThisFileInfo['flv']['video']['videoCodec'] = $LastHeaderByte & 0x07;
+
+ $FLVvideoHeader = fread($fd, 11);
+
+ if ($ThisFileInfo['flv']['video']['videoCodec'] != GETID3_FLV_VIDEO_VP6) {
+
+ $PictureSizeType = (getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 3, 2))) >> 7;
+ $PictureSizeType = $PictureSizeType & 0x0007;
+ $ThisFileInfo['flv']['header']['videoSizeType'] = $PictureSizeType;
+ switch ($PictureSizeType) {
+ case 0:
+ $PictureSizeEnc = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 5, 2));
+ $PictureSizeEnc <<= 1;
+ $ThisFileInfo['video']['resolution_x'] = ($PictureSizeEnc & 0xFF00) >> 8;
+ $PictureSizeEnc = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 6, 2));
+ $PictureSizeEnc <<= 1;
+ $ThisFileInfo['video']['resolution_y'] = ($PictureSizeEnc & 0xFF00) >> 8;
+ break;
+
+ case 1:
+ $PictureSizeEnc = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 5, 4));
+ $PictureSizeEnc <<= 1;
+ $ThisFileInfo['video']['resolution_x'] = ($PictureSizeEnc & 0xFFFF0000) >> 16;
+
+ $PictureSizeEnc = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 7, 4));
+ $PictureSizeEnc <<= 1;
+ $ThisFileInfo['video']['resolution_y'] = ($PictureSizeEnc & 0xFFFF0000) >> 16;
+ break;
+
+ case 2:
+ $ThisFileInfo['video']['resolution_x'] = 352;
+ $ThisFileInfo['video']['resolution_y'] = 288;
+ break;
+
+ case 3:
+ $ThisFileInfo['video']['resolution_x'] = 176;
+ $ThisFileInfo['video']['resolution_y'] = 144;
+ break;
+
+ case 4:
+ $ThisFileInfo['video']['resolution_x'] = 128;
+ $ThisFileInfo['video']['resolution_y'] = 96;
+ break;
+
+ case 5:
+ $ThisFileInfo['video']['resolution_x'] = 320;
+ $ThisFileInfo['video']['resolution_y'] = 240;
+ break;
+
+ case 6:
+ $ThisFileInfo['video']['resolution_x'] = 160;
+ $ThisFileInfo['video']['resolution_y'] = 120;
+ break;
+
+ default:
+ $ThisFileInfo['video']['resolution_x'] = 0;
+ $ThisFileInfo['video']['resolution_y'] = 0;
+ break;
+
+ }
+ }
+ }
+ break;
+
+ // Meta tag
+ case GETID3_FLV_TAG_META:
+
+ fseek($fd, -1, SEEK_CUR);
+ $reader = new AMFReader(new AMFStream(fread($fd, $DataLength)));
+ $eventName = $reader->readData();
+ $ThisFileInfo['meta'][$eventName] = $reader->readData();
+ unset($reader);
+
+ $ThisFileInfo['video']['frame_rate'] = $ThisFileInfo['meta']['onMetaData']['framerate'];
+ $ThisFileInfo['video']['resolution_x'] = $ThisFileInfo['meta']['onMetaData']['width'];
+ $ThisFileInfo['video']['resolution_y'] = $ThisFileInfo['meta']['onMetaData']['height'];
+ break;
+
+ default:
+ // noop
+ break;
+ }
+
+ if ($Timestamp > $Duration) {
+ $Duration = $Timestamp;
+ }
+
+ fseek($fd, $NextOffset, SEEK_SET);
+ }
+
+ $ThisFileInfo['playtime_seconds'] = $Duration / 1000;
+ $ThisFileInfo['bitrate'] = ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) / $ThisFileInfo['playtime_seconds'];
+
+ if ($ThisFileInfo['flv']['header']['hasAudio']) {
+ $ThisFileInfo['audio']['codec'] = $this->FLVaudioFormat($ThisFileInfo['flv']['audio']['audioFormat']);
+ $ThisFileInfo['audio']['sample_rate'] = $this->FLVaudioRate($ThisFileInfo['flv']['audio']['audioRate']);
+ $ThisFileInfo['audio']['bits_per_sample'] = $this->FLVaudioBitDepth($ThisFileInfo['flv']['audio']['audioSampleSize']);
+
+ $ThisFileInfo['audio']['channels'] = $ThisFileInfo['flv']['audio']['audioType'] + 1; // 0=mono,1=stereo
+ $ThisFileInfo['audio']['lossless'] = ($ThisFileInfo['flv']['audio']['audioFormat'] ? false : true); // 0=uncompressed
+ $ThisFileInfo['audio']['dataformat'] = 'flv';
+ }
+ if (@$ThisFileInfo['flv']['header']['hasVideo']) {
+ $ThisFileInfo['video']['codec'] = $this->FLVvideoCodec($ThisFileInfo['flv']['video']['videoCodec']);
+ $ThisFileInfo['video']['dataformat'] = 'flv';
+ $ThisFileInfo['video']['lossless'] = false;
+ }
+
+ return true;
+ }
+
+
+ function FLVaudioFormat($id) {
+ $FLVaudioFormat = array(
+ 0 => 'uncompressed',
+ 1 => 'ADPCM',
+ 2 => 'mp3',
+ 5 => 'Nellymoser 8kHz mono',
+ 6 => 'Nellymoser',
+ );
+ return (@$FLVaudioFormat[$id] ? @$FLVaudioFormat[$id] : false);
+ }
+
+ function FLVaudioRate($id) {
+ $FLVaudioRate = array(
+ 0 => 5500,
+ 1 => 11025,
+ 2 => 22050,
+ 3 => 44100,
+ );
+ return (@$FLVaudioRate[$id] ? @$FLVaudioRate[$id] : false);
+ }
+
+ function FLVaudioBitDepth($id) {
+ $FLVaudioBitDepth = array(
+ 0 => 8,
+ 1 => 16,
+ );
+ return (@$FLVaudioBitDepth[$id] ? @$FLVaudioBitDepth[$id] : false);
+ }
+
+ function FLVvideoCodec($id) {
+ $FLVvideoCodec = array(
+ GETID3_FLV_VIDEO_H263 => 'Sorenson H.263',
+ GETID3_FLV_VIDEO_SCREEN => 'Screen video',
+ GETID3_FLV_VIDEO_VP6 => 'On2 VP6',
+ );
+ return (@$FLVvideoCodec[$id] ? @$FLVvideoCodec[$id] : false);
+ }
+}
+
+class AMFStream {
+ var $bytes;
+ var $pos;
+
+ function AMFStream(&$bytes) {
+ $this->bytes =& $bytes;
+ $this->pos = 0;
+ }
+
+ function readByte() {
+ return getid3_lib::BigEndian2Int(substr($this->bytes, $this->pos++, 1));
+ }
+
+ function readInt() {
+ return ($this->readByte() << 8) + $this->readByte();
+ }
+
+ function readLong() {
+ return ($this->readByte() << 24) + ($this->readByte() << 16) + ($this->readByte() << 8) + $this->readByte();
+ }
+
+ function readDouble() {
+ return getid3_lib::BigEndian2Float($this->read(8));
+ }
+
+ function readUTF() {
+ $length = $this->readInt();
+ return $this->read($length);
+ }
+
+ function readLongUTF() {
+ $length = $this->readLong();
+ return $this->read($length);
+ }
+
+ function read($length) {
+ $val = substr($this->bytes, $this->pos, $length);
+ $this->pos += $length;
+ return $val;
+ }
+
+ function peekByte() {
+ $pos = $this->pos;
+ $val = $this->readByte();
+ $this->pos = $pos;
+ return $val;
+ }
+
+ function peekInt() {
+ $pos = $this->pos;
+ $val = $this->readInt();
+ $this->pos = $pos;
+ return $val;
+ }
+
+ function peekLong() {
+ $pos = $this->pos;
+ $val = $this->readLong();
+ $this->pos = $pos;
+ return $val;
+ }
+
+ function peekDouble() {
+ $pos = $this->pos;
+ $val = $this->readDouble();
+ $this->pos = $pos;
+ return $val;
+ }
+
+ function peekUTF() {
+ $pos = $this->pos;
+ $val = $this->readUTF();
+ $this->pos = $pos;
+ return $val;
+ }
+
+ function peekLongUTF() {
+ $pos = $this->pos;
+ $val = $this->readLongUTF();
+ $this->pos = $pos;
+ return $val;
+ }
+}
+
+class AMFReader {
+ var $stream;
+
+ function AMFReader(&$stream) {
+ $this->stream =& $stream;
+ }
+
+ function readData() {
+ $value = null;
+
+ $type = $this->stream->readByte();
+
+ switch($type) {
+ // Double
+ case 0:
+ $value = $this->readDouble();
+ break;
+
+ // Boolean
+ case 1:
+ $value = $this->readBoolean();
+ break;
+
+ // String
+ case 2:
+ $value = $this->readString();
+ break;
+
+ // Object
+ case 3:
+ $value = $this->readObject();
+ break;
+
+ // null
+ case 6:
+ return null;
+ break;
+
+ // Mixed array
+ case 8:
+ $value = $this->readMixedArray();
+ break;
+
+ // Array
+ case 10:
+ $value = $this->readArray();
+ break;
+
+ // Date
+ case 11:
+ $value = $this->readDate();
+ break;
+
+ // Long string
+ case 13:
+ $value = $this->readLongString();
+ break;
+
+ // XML (handled as string)
+ case 15:
+ $value = $this->readXML();
+ break;
+
+ // Typed object (handled as object)
+ case 16:
+ $value = $this->readTypedObject();
+ break;
+
+ // Long string
+ default:
+ $value = '(unknown or unsupported data type)';
+ break;
+ }
+
+ return $value;
+ }
+
+ function readDouble() {
+ return $this->stream->readDouble();
+ }
+
+ function readBoolean() {
+ return $this->stream->readByte() == 1;
+ }
+
+ function readString() {
+ return $this->stream->readUTF();
+ }
+
+ function readObject() {
+ // Get highest numerical index - ignored
+ $highestIndex = $this->stream->readLong();
+
+ $data = array();
+
+ while ($key = $this->stream->readUTF()) {
+ // Mixed array record ends with empty string (0x00 0x00) and 0x09
+ if (($key == '') && ($this->stream->peekByte() == 0x09)) {
+ // Consume byte
+ $this->stream->readByte();
+ break;
+ }
+
+ $data[$key] = $this->readData();
+ }
+
+ return $data;
+ }
+
+ function readMixedArray() {
+ // Get highest numerical index - ignored
+ $highestIndex = $this->stream->readLong();
+
+ $data = array();
+
+ while ($key = $this->stream->readUTF()) {
+ // Mixed array record ends with empty string (0x00 0x00) and 0x09
+ if (($key == '') && ($this->stream->peekByte() == 0x09)) {
+ // Consume byte
+ $this->stream->readByte();
+ break;
+ }
+
+ if (is_numeric($key)) {
+ $key = (float) $key;
+ }
+
+ $data[$key] = $this->readData();
+ }
+
+ return $data;
+ }
+
+ function readArray() {
+ $length = $this->stream->readLong();
+
+ $data = array();
+
+ for ($i = 0; $i < count($length); $i++) {
+ $data[] = $this->readData();
+ }
+
+ return $data;
+ }
+
+ function readDate() {
+ $timestamp = $this->stream->readDouble();
+ $timezone = $this->stream->readInt();
+ return $timestamp;
+ }
+
+ function readLongString() {
+ return $this->stream->readLongUTF();
+ }
+
+ function readXML() {
+ return $this->stream->readLongUTF();
+ }
+
+ function readTypedObject() {
+ $className = $this->stream->readUTF();
+ return $this->readObject();
+ }
+}
+
+?>
\ No newline at end of file
Modified: plog/trunk/class/gallery/getid3/module.audio-video.quicktime.php
===================================================================
--- plog/trunk/class/gallery/getid3/module.audio-video.quicktime.php 2006-07-24 16:40:16 UTC (rev 3789)
+++ plog/trunk/class/gallery/getid3/module.audio-video.quicktime.php 2006-07-24 16:56:08 UTC (rev 3790)
@@ -520,7 +520,7 @@
$atomstructure['time_to_sample_table'][$i]['sample_duration'] = getid3_lib::BigEndian2Int(substr($atomdata, $sttsEntriesDataOffset, 4));
$sttsEntriesDataOffset += 4;
- if (!empty($ThisFileInfo['quicktime']['time_scale'])) {
+ if (!empty($ThisFileInfo['quicktime']['time_scale']) && (@$atomstructure['time_to_sample_table'][$i]['sample_duration'] > 0)) {
$stts_new_framerate = $ThisFileInfo['quicktime']['time_scale'] / $atomstructure['time_to_sample_table'][$i]['sample_duration'];
if ($stts_new_framerate <= 60) {
// some atoms have durations of "1" giving a very large framerate, which probably is not right
@@ -853,8 +853,10 @@
$ThisFileInfo['video']['resolution_x'] = $atomstructure['width'];
$ThisFileInfo['video']['resolution_y'] = $atomstructure['height'];
}
- $ThisFileInfo['video']['resolution_x'] = max($ThisFileInfo['video']['resolution_x'], $atomstructure['width']);
- $ThisFileInfo['video']['resolution_y'] = max($ThisFileInfo['video']['resolution_y'], $atomstructure['height']);
+ if ($atomstructure['flags']['enabled'] == 1) {
+ $ThisFileInfo['video']['resolution_x'] = max($ThisFileInfo['video']['resolution_x'], $atomstructure['width']);
+ $ThisFileInfo['video']['resolution_y'] = max($ThisFileInfo['video']['resolution_y'], $atomstructure['height']);
+ }
if (!empty($ThisFileInfo['video']['resolution_x']) && !empty($ThisFileInfo['video']['resolution_y'])) {
$ThisFileInfo['quicktime']['video']['resolution_x'] = $ThisFileInfo['video']['resolution_x'];
$ThisFileInfo['quicktime']['video']['resolution_y'] = $ThisFileInfo['video']['resolution_y'];
Modified: plog/trunk/class/gallery/getid3/module.audio-video.riff.php
===================================================================
--- plog/trunk/class/gallery/getid3/module.audio-video.riff.php 2006-07-24 16:40:16 UTC (rev 3789)
+++ plog/trunk/class/gallery/getid3/module.audio-video.riff.php 2006-07-24 16:56:08 UTC (rev 3790)
@@ -201,7 +201,7 @@
$thisfile_riff_WAVE_bext_0['reserved'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_bext_0['data'], 347, 254));
$thisfile_riff_WAVE_bext_0['coding_history'] = explode("\r\n", trim(substr($thisfile_riff_WAVE_bext_0['data'], 601)));
- $thisfile_riff_WAVE_bext_0['origin_date_unix'] = mktime(
+ $thisfile_riff_WAVE_bext_0['origin_date_unix'] = gmmktime(
substr($thisfile_riff_WAVE_bext_0['origin_time'], 0, 2),
substr($thisfile_riff_WAVE_bext_0['origin_time'], 3, 2),
substr($thisfile_riff_WAVE_bext_0['origin_time'], 6, 2),
@@ -1005,7 +1005,7 @@
}
- function RIFFcommentsParse(&$RIFFinfoArray, &$CommentsTargetArray) {
+ function RIFFcommentsParse(&$RIFFinfoArray, &$CommentsTargetArray) {
$RIFFinfoKeyLookup = array(
'IARL'=>'archivallocation',
'IART'=>'artist',
@@ -1055,9 +1055,9 @@
}
}
}
- }
+ }
return true;
- }
+ }
function ParseRIFF(&$fd, $startoffset, $maxoffset, &$ThisFileInfo) {
@@ -1953,8 +1953,6 @@
XMPG Xing MPEG (I-Frame only)
XVID XviD MPEG-4 (www.xvid.org)
XXAN ?XXAN?
- Y422 ADS Technologies Copy of UYVY used in Pyro WebCam firewire camera
- Y800 Simple, single Y plane for monochrome images
YU92 Intel YUV (YU92)
YUNV Nvidia Uncompressed YUV 4:2:2
YUVP Extended PAL format YUV palette (www.riff.org)
@@ -1965,6 +1963,8 @@
Y41T Brooktree PC1 YUV 4:1:1 with transparency
Y42B Weitek YUV 4:2:2 Planar
Y42T Brooktree UYUV 4:2:2 with transparency
+ Y422 ADS Technologies Copy of UYVY used in Pyro WebCam firewire camera
+ Y800 Simple, single Y plane for monochrome images
Y8 Grayscale video
YC12 Intel YUV 12 codec
YUV8 Winnov Caviar YUV8
Modified: plog/trunk/class/gallery/getid3/module.audio.aac.php
===================================================================
--- plog/trunk/class/gallery/getid3/module.audio.aac.php 2006-07-24 16:40:16 UTC (rev 3789)
+++ plog/trunk/class/gallery/getid3/module.audio.aac.php 2006-07-24 16:56:08 UTC (rev 3790)
@@ -299,7 +299,7 @@
}
// used to calculate bitrate below
- static $BitrateCache = array();
+ $BitrateCache = array();
while (true) {
Modified: plog/trunk/class/gallery/getid3/module.audio.flac.php
===================================================================
--- plog/trunk/class/gallery/getid3/module.audio.flac.php 2006-07-24 16:40:16 UTC (rev 3789)
+++ plog/trunk/class/gallery/getid3/module.audio.flac.php 2006-07-24 16:56:08 UTC (rev 3790)
@@ -47,7 +47,7 @@
$METAdataBlockLength = getid3_lib::BigEndian2Int(substr($METAdataBlockHeader, 1, 3));
$METAdataBlockTypeText = getid3_flac::FLACmetaBlockTypeLookup($METAdataBlockType);
- if ($METAdataBlockLength <= 0) {
+ if ($METAdataBlockLength < 0) {
$ThisFileInfo['error'][] = 'corrupt or invalid METADATA_BLOCK_HEADER.BLOCK_TYPE ('.$METAdataBlockType.') at offset '.$METAdataBlockOffset;
break;
}
@@ -60,7 +60,7 @@
$ThisFileInfo_flac_METAdataBlockTypeText_raw['block_type'] = $METAdataBlockType;
$ThisFileInfo_flac_METAdataBlockTypeText_raw['block_type_text'] = $METAdataBlockTypeText;
$ThisFileInfo_flac_METAdataBlockTypeText_raw['block_length'] = $METAdataBlockLength;
- $ThisFileInfo_flac_METAdataBlockTypeText_raw['block_data'] = fread($fd, $METAdataBlockLength);
+ $ThisFileInfo_flac_METAdataBlockTypeText_raw['block_data'] = @fread($fd, $METAdataBlockLength);
$ThisFileInfo['avdataoffset'] = ftell($fd);
switch ($METAdataBlockTypeText) {
Modified: plog/trunk/class/gallery/getid3/module.audio.midi.php
===================================================================
--- plog/trunk/class/gallery/getid3/module.audio.midi.php 2006-07-24 16:40:16 UTC (rev 3789)
+++ plog/trunk/class/gallery/getid3/module.audio.midi.php 2006-07-24 16:56:08 UTC (rev 3790)
@@ -273,10 +273,7 @@
}
$previoustickoffset = null;
- if ($MicroSecondsPerQuarterNoteAfter != null)
- {
- ksort($MicroSecondsPerQuarterNoteAfter);
- }
+ ksort($MicroSecondsPerQuarterNoteAfter);
foreach ($MicroSecondsPerQuarterNoteAfter as $tickoffset => $microsecondsperbeat) {
if (is_null($previoustickoffset)) {
$prevmicrosecondsperbeat = $microsecondsperbeat;
Modified: plog/trunk/class/gallery/getid3/module.audio.mp3.php
===================================================================
--- plog/trunk/class/gallery/getid3/module.audio.mp3.php 2006-07-24 16:40:16 UTC (rev 3789)
+++ plog/trunk/class/gallery/getid3/module.audio.mp3.php 2006-07-24 16:56:08 UTC (rev 3790)
@@ -320,8 +320,9 @@
'fast standard|19000' => 19000,
'r3mix|19500' => 19500, // 3.90, 3.90.1, 3.92
'r3mix|19600' => 19600, // 3.90.2, 3.90.3, 3.91
- 'r3mix|18000' => 18000); // 3.94, 3.95
- if (!isset($ExpectedLowpass[$ExplodedOptions[1].'|'.$thisfile_mpeg_audio_lame['lowpass_frequency']])) {
+ 'r3mix|18000' => 18000, // 3.94, 3.95
+ );
+ if (!isset($ExpectedLowpass[$ExplodedOptions[1].'|'.$thisfile_mpeg_audio_lame['lowpass_frequency']]) && ($thisfile_mpeg_audio_lame['lowpass_frequency'] < 22050) && (round($thisfile_mpeg_audio_lame['lowpass_frequency'] / 1000) < round($thisfile_mpeg_audio['sample_rate'] / 2000))) {
$encoder_options .= ' --lowpass '.$thisfile_mpeg_audio_lame['lowpass_frequency'];
}
break;
@@ -1636,23 +1637,17 @@
if (isset($MPEGaudioVersionLookup[$rawarray['version']])) {
$decodedVersion = $MPEGaudioVersionLookup[$rawarray['version']];
} else {
- if ($echoerrors) {
- echo "\n".'invalid Version ('.$rawarray['version'].')';
- }
+ echo ($echoerrors ? "\n".'invalid Version ('.$rawarray['version'].')' : '');
return false;
}
if (isset($MPEGaudioLayerLookup[$rawarray['layer']])) {
$decodedLayer = $MPEGaudioLayerLookup[$rawarray['layer']];
} else {
- if ($echoerrors) {
- echo "\n".'invalid Layer ('.$rawarray['layer'].')';
- }
+ echo ($echoerrors ? "\n".'invalid Layer ('.$rawarray['layer'].')' : '');
return false;
}
if (!isset($MPEGaudioBitrateLookup[$decodedVersion][$decodedLayer][$rawarray['bitrate']])) {
- if ($echoerrors) {
- echo "\n".'invalid Bitrate ('.$rawarray['bitrate'].')';
- }
+ echo ($echoerrors ? "\n".'invalid Bitrate ('.$rawarray['bitrate'].')' : '');
if ($rawarray['bitrate'] == 15) {
// known issue in LAME 3.90 - 3.93.1 where free-format has bitrate ID of 15 instead of 0
// let it go through here otherwise file will not be identified
@@ -1664,27 +1659,19 @@
}
}
if (!isset($MPEGaudioFrequencyLookup[$decodedVersion][$rawarray['sample_rate']])) {
- if ($echoerrors) {
- echo "\n".'invalid Frequency ('.$rawarray['sample_rate'].')';
- }
+ echo ($echoerrors ? "\n".'invalid Frequency ('.$rawarray['sample_rate'].')' : '');
return false;
}
if (!isset($MPEGaudioChannelModeLookup[$rawarray['channelmode']])) {
- if ($echoerrors) {
- echo "\n".'invalid ChannelMode ('.$rawarray['channelmode'].')';
- }
+ echo ($echoerrors ? "\n".'invalid ChannelMode ('.$rawarray['channelmode'].')' : '');
return false;
}
if (!isset($MPEGaudioModeExtensionLookup[$decodedLayer][$rawarray['modeextension']])) {
- if ($echoerrors) {
- echo "\n".'invalid Mode Extension ('.$rawarray['modeextension'].')';
- }
+ echo ($echoerrors ? "\n".'invalid Mode Extension ('.$rawarray['modeextension'].')' : '');
return false;
}
if (!isset($MPEGaudioEmphasisLookup[$rawarray['emphasis']])) {
- if ($echoerrors) {
- echo "\n".'invalid Emphasis ('.$rawarray['emphasis'].')';
- }
+ echo ($echoerrors ? "\n".'invalid Emphasis ('.$rawarray['emphasis'].')' : '');
return false;
}
// These are just either set or not set, you can't mess that up :)
@@ -1893,52 +1880,58 @@
}
function LAMEpresetUsedLookup($LAMEtag) {
- if ($LAMEtag['preset_used_id'] == 0) {
- // no preset used (LAME >=3.93)
- // no preset recorded (LAME <3.93)
- return '';
- }
- static $LAMEpresetUsedLookup = array();
- if (empty($LAMEpresetUsedLookup)) {
- for ($i = 8; $i <= 320; $i++) {
- switch ($LAMEtag['vbr_method']) {
- case 'cbr':
- $LAMEpresetUsedLookup[$i] = '--alt-preset '.$LAMEtag['vbr_method'].' '.$i;
- break;
- case 'abr':
- default: // other VBR modes shouldn't be here(?)
- $LAMEpresetUsedLookup[$i] = '--alt-preset '.$i;
- break;
- }
- }
- // named old-style presets (studio, phone, voice, etc) are handled in GuessEncoderOptions()
+ if ($LAMEtag['preset_used_id'] == 0) {
+ // no preset used (LAME >=3.93)
+ // no preset recorded (LAME <3.93)
+ return '';
+ }
+ $LAMEpresetUsedLookup = array();
- // named alt-presets
- $LAMEpresetUsedLookup[1000] = '--r3mix';
- $LAMEpresetUsedLookup[1001] = '--alt-preset standard';
- $LAMEpresetUsedLookup[1002] = '--alt-preset extreme';
- $LAMEpresetUsedLookup[1003] = '--alt-preset insane';
- $LAMEpresetUsedLookup[1004] = '--alt-preset fast standard';
- $LAMEpresetUsedLookup[1005] = '--alt-preset fast extreme';
- $LAMEpresetUsedLookup[1006] = '--alt-preset medium';
- $LAMEpresetUsedLookup[1007] = '--alt-preset fast medium';
+ ///// THIS PART CANNOT BE STATIC .
+ for ($i = 8; $i <= 320; $i++) {
+ switch ($LAMEtag['vbr_method']) {
+ case 'cbr':
+ $LAMEpresetUsedLookup[$i] = '--alt-preset '.$LAMEtag['vbr_method'].' '.$i;
+ break;
+ case 'abr':
+ default: // other VBR modes shouldn't be here(?)
+ $LAMEpresetUsedLookup[$i] = '--alt-preset '.$i;
+ break;
+ }
+ }
- // LAME 3.94 additions/changes
- $LAMEpresetUsedLookup[1010] = '--preset portable'; // 3.94a15 Oct 21 2003
- $LAMEpresetUsedLookup[1015] = '--preset radio'; // 3.94a15 Oct 21 2003
+ // named old-style presets (studio, phone, voice, etc) are handled in GuessEncoderOptions()
- $LAMEpresetUsedLookup[320] = '--preset insane'; // 3.94a15 Nov 12 2003
- $LAMEpresetUsedLookup[430] = '--preset radio'; // 3.94a15 Nov 12 2003
- $LAMEpresetUsedLookup[450] = '--preset '.(($LAMEtag['raw']['vbr_method'] == 4) ? 'fast ' : '').'portable'; // 3.94a15 Nov 12 2003
- $LAMEpresetUsedLookup[460] = '--preset '.(($LAMEtag['raw']['vbr_method'] == 4) ? 'fast ' : '').'medium'; // 3.94a15 Nov 12 2003
- $LAMEpresetUsedLookup[470] = '--r3mix'; // 3.94b1 Dec 18 2003
- $LAMEpresetUsedLookup[480] = '--preset '.(($LAMEtag['raw']['vbr_method'] == 4) ? 'fast ' : '').'standard'; // 3.94a15 Nov 12 2003
- $LAMEpresetUsedLookup[500] = '--preset '.(($LAMEtag['raw']['vbr_method'] == 4) ? 'fast ' : '').'extreme'; // 3.94a15 Nov 12 2003
- }
- return (isset($LAMEpresetUsedLookup[$LAMEtag['preset_used_id']]) ? $LAMEpresetUsedLookup[$LAMEtag['preset_used_id']] : 'new/unknown preset: '.$LAMEtag['preset_used_id'].' - report to info at getid3.org');
- }
+ // named alt-presets
+ $LAMEpresetUsedLookup[1000] = '--r3mix';
+ $LAMEpresetUsedLookup[1001] = '--alt-preset standard';
+ $LAMEpresetUsedLookup[1002] = '--alt-preset extreme';
+ $LAMEpresetUsedLookup[1003] = '--alt-preset insane';
+ $LAMEpresetUsedLookup[1004] = '--alt-preset fast standard';
+ $LAMEpresetUsedLookup[1005] = '--alt-preset fast extreme';
+ $LAMEpresetUsedLookup[1006] = '--alt-preset medium';
+ $LAMEpresetUsedLookup[1007] = '--alt-preset fast medium';
+ // LAME 3.94 additions/changes
+ $LAMEpresetUsedLookup[1010] = '--preset portable'; // 3.94a15 Oct 21 2003
+ $LAMEpresetUsedLookup[1015] = '--preset radio'; // 3.94a15 Oct 21 2003
+
+ $LAMEpresetUsedLookup[320] = '--preset insane'; // 3.94a15 Nov 12 2003
+ $LAMEpresetUsedLookup[410] = '-V9';
+ $LAMEpresetUsedLookup[420] = '-V8';
+ $LAMEpresetUsedLookup[440] = '-V6';
+ $LAMEpresetUsedLookup[430] = '--preset radio'; // 3.94a15 Nov 12 2003
+ $LAMEpresetUsedLookup[450] = '--preset '.(($LAMEtag['raw']['vbr_method'] == 4) ? 'fast ' : '').'portable'; // 3.94a15 Nov 12 2003
+ $LAMEpresetUsedLookup[460] = '--preset '.(($LAMEtag['raw']['vbr_method'] == 4) ? 'fast ' : '').'medium'; // 3.94a15 Nov 12 2003
+ $LAMEpresetUsedLookup[470] = '--r3mix'; // 3.94b1 Dec 18 2003
+ $LAMEpresetUsedLookup[480] = '--preset '.(($LAMEtag['raw']['vbr_method'] == 4) ? 'fast ' : '').'standard'; // 3.94a15 Nov 12 2003
+ $LAMEpresetUsedLookup[490] = '-V1';
+ $LAMEpresetUsedLookup[500] = '--preset '.(($LAMEtag['raw']['vbr_method'] == 4) ? 'fast ' : '').'extreme'; // 3.94a15 Nov 12 2003
+
+ return (isset($LAMEpresetUsedLookup[$LAMEtag['preset_used_id']]) ? $LAMEpresetUsedLookup[$LAMEtag['preset_used_id']] : 'new/unknown preset: '.$LAMEtag['preset_used_id'].' - report to info at getid3.org');
+ }
+
}
?>
\ No newline at end of file
Modified: plog/trunk/class/gallery/getid3/module.audio.shorten.php
===================================================================
--- plog/trunk/class/gallery/getid3/module.audio.shorten.php 2006-07-24 16:40:16 UTC (rev 3789)
+++ plog/trunk/class/gallery/getid3/module.audio.shorten.php 2006-07-24 16:56:08 UTC (rev 3790)
@@ -124,6 +124,7 @@
}
}
$commandline = GETID3_HELPERAPPSDIR.'shorten.exe -x "'.$ThisFileInfo['filenamepath'].'" - | '.GETID3_HELPERAPPSDIR.'head.exe -c 44';
+ $commandline = str_replace('/', '\\', $commandline);
} else {
@@ -135,7 +136,7 @@
$ThisFileInfo['error'][] = 'shorten binary was not found in path or /usr/local/bin';
return false;
}
- $commandline = (file_exists('/usr/local/bin/shorten') ? '/usr/local/bin/' : '' ) . 'shorten -x "'.$ThisFileInfo['filenamepath'].'" - | head -c 44';
+ $commandline = (file_exists('/usr/local/bin/shorten') ? '/usr/local/bin/' : '' ) . 'shorten -x '.escapeshellarg($ThisFileInfo['filenamepath']).' - | head -c 44';
}
Added: plog/trunk/class/gallery/getid3/module.graphic.svg.php
===================================================================
--- plog/trunk/class/gallery/getid3/module.graphic.svg.php 2006-07-24 16:40:16 UTC (rev 3789)
+++ plog/trunk/class/gallery/getid3/module.graphic.svg.php 2006-07-24 16:56:08 UTC (rev 3790)
@@ -0,0 +1,52 @@
+<?php
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info at getid3.org> //
+// available at http://getid3.sourceforge.net //
+// or http://www.getid3.org //
+/////////////////////////////////////////////////////////////////
+// See readme.txt for more details //
+/////////////////////////////////////////////////////////////////
+// //
+// module.graphic.svg.php //
+// module for analyzing SVG Image files //
+// dependencies: NONE //
+// author: Bryce Harrington <bryceØbryceharrington*org> //
+// ///
+/////////////////////////////////////////////////////////////////
+
+
+class getid3_svg
+{
+
+
+ function getid3_svg(&$fd, &$ThisFileInfo) {
+ fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
+
+ // I'm making this up, please modify as appropriate
+ $SVGheader = fread($fd, 32);
+ $ThisFileInfo['svg']['magic'] = substr($SVGheader, 0, 4);
+ if ($ThisFileInfo['svg']['magic'] == 'aBcD') {
+
+ $ThisFileInfo['fileformat'] = 'svg';
+ $ThisFileInfo['video']['dataformat'] = 'svg';
+ $ThisFileInfo['video']['lossless'] = true;
+ $ThisFileInfo['video']['bits_per_sample'] = 24;
+ $ThisFileInfo['video']['pixel_aspect_ratio'] = (float) 1;
+
+ $ThisFileInfo['svg']['width'] = getid3_lib::LittleEndian2Int(substr($fileData, 4, 4));
+ $ThisFileInfo['svg']['height'] = getid3_lib::LittleEndian2Int(substr($fileData, 8, 4));
+
+ $ThisFileInfo['video']['resolution_x'] = $ThisFileInfo['svg']['width'];
+ $ThisFileInfo['video']['resolution_y'] = $ThisFileInfo['svg']['height'];
+
+ return true;
+ }
+ $ThisFileInfo['error'][] = 'Did not find SVG magic bytes "aBcD" at '.$ThisFileInfo['avdataoffset'];
+ unset($ThisFileInfo['fileformat']);
+ return false;
+ }
+
+}
+
+
+?>
\ No newline at end of file
Modified: plog/trunk/class/gallery/getid3/module.misc.iso.php
===================================================================
--- plog/trunk/class/gallery/getid3/module.misc.iso.php 2006-07-24 16:40:16 UTC (rev 3789)
+++ plog/trunk/class/gallery/getid3/module.misc.iso.php 2006-07-24 16:56:08 UTC (rev 3790)
@@ -338,7 +338,7 @@
if (!$UNIXyear) {
return false;
}
- return mktime($UNIXhour, $UNIXminute, $UNIXsecond, $UNIXmonth, $UNIXday, $UNIXyear);
+ return gmmktime($UNIXhour, $UNIXminute, $UNIXsecond, $UNIXmonth, $UNIXday, $UNIXyear);
}
function ISOtime2UNIXtime($ISOtime) {
@@ -359,7 +359,7 @@
$UNIXsecond = ord($ISOtime{5});
$GMToffset = $this->TwosCompliment2Decimal(ord($ISOtime{5}));
- return mktime($UNIXhour, $UNIXminute, $UNIXsecond, $UNIXmonth, $UNIXday, $UNIXyear);
+ return gmmktime($UNIXhour, $UNIXminute, $UNIXsecond, $UNIXmonth, $UNIXday, $UNIXyear);
}
function TwosCompliment2Decimal($BinaryValue) {
Modified: plog/trunk/class/gallery/getid3/module.tag.id3v2.php
===================================================================
--- plog/trunk/class/gallery/getid3/module.tag.id3v2.php 2006-07-24 16:40:16 UTC (rev 3789)
+++ plog/trunk/class/gallery/getid3/module.tag.id3v2.php 2006-07-24 16:56:08 UTC (rev 3790)
@@ -101,47 +101,51 @@
$thisfile_id3v2['tag_offset_start'] = $StartingOffset;
$thisfile_id3v2['tag_offset_end'] = $thisfile_id3v2['tag_offset_start'] + $thisfile_id3v2['headerlength'];
- // Extended Header
+ // Extended Header
if (isset($thisfile_id3v2_flags['exthead']) && $thisfile_id3v2_flags['exthead']) {
- // Extended header size 4 * %0xxxxxxx
- // Number of flag bytes $01
- // Extended Flags $xx
- // Where the 'Extended header size' is the size of the whole extended header, stored as a 32 bit synchsafe integer.
- $extheader = fread ($fd, 4);
- $thisfile_id3v2['extheaderlength'] = getid3_lib::BigEndian2Int($extheader, 1);
+ // Extended header size 4 * %0xxxxxxx
+ // Number of flag bytes $01
+ // Extended Flags $xx
+ // Where the 'Extended header size' is the size of the whole extended header, stored as a 32 bit synchsafe integer.
+ $thisfile_id3v2['exthead_length'] = getid3_lib::BigEndian2Int(fread($fd, 4), 1);
- // The extended flags field, with its size described by 'number of flag bytes', is defined as:
- // %0bcd0000
- // 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
- $extheaderflagbytes = fread ($fd, 1);
- $extheaderflags = fread ($fd, $extheaderflagbytes);
- $id3_exthead_flags = getid3_lib::BigEndian2Bin(substr($header, 5, 1));
- $thisfile_id3v2['exthead_flags']['update'] = substr($id3_exthead_flags, 1, 1);
- $thisfile_id3v2['exthead_flags']['CRC'] = substr($id3_exthead_flags, 2, 1);
- if ($thisfile_id3v2['exthead_flags']['CRC']) {
- $extheaderrawCRC = fread ($fd, 5);
- $thisfile_id3v2['exthead_flags']['CRC'] = getid3_lib::BigEndian2Int($extheaderrawCRC, 1);
+ $thisfile_id3v2['exthead_flag_bytes'] = ord(fread($fd, 1));
+ if ($thisfile_id3v2['exthead_flag_bytes'] == 1) {
+ // The extended flags field, with its size described by 'number of flag bytes', is defined as:
+ // %0bcd0000
+ // 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
+ $extheaderflags = fread($fd, $thisfile_id3v2['exthead_flag_bytes']);
+ $id3_exthead_flags = getid3_lib::BigEndian2Bin(substr($header, 5, 1));
+ $thisfile_id3v2['exthead_flags']['update'] = substr($id3_exthead_flags, 1, 1);
+ $thisfile_id3v2['exthead_flags']['CRC'] = substr($id3_exthead_flags, 2, 1);
+ if ($thisfile_id3v2['exthead_flags']['CRC']) {
+ $extheaderrawCRC = fread($fd, 5);
+ $thisfile_id3v2['exthead_flags']['CRC'] = getid3_lib::BigEndian2Int($extheaderrawCRC, 1);
+ }
+ $thisfile_id3v2['exthead_flags']['restrictions'] = substr($id3_exthead_flags, 3, 1);
+ if ($thisfile_id3v2['exthead_flags']['restrictions']) {
+ // Restrictions %ppqrrstt
+ $extheaderrawrestrictions = fread($fd, 1);
+ $thisfile_id3v2['exthead_flags']['restrictions_tagsize'] = (bindec('11000000') & ord($extheaderrawrestrictions)) >> 6; // p - Tag size restrictions
+ $thisfile_id3v2['exthead_flags']['restrictions_textenc'] = (bindec('00100000') & ord($extheaderrawrestrictions)) >> 5; // q - Text encoding restrictions
+ $thisfile_id3v2['exthead_flags']['restrictions_textsize'] = (bindec('00011000') & ord($extheaderrawrestrictions)) >> 3; // r - Text fields size restrictions
+ $thisfile_id3v2['exthead_flags']['restrictions_imgenc'] = (bindec('00000100') & ord($extheaderrawrestrictions)) >> 2; // s - Image encoding restrictions
+ $thisfile_id3v2['exthead_flags']['restrictions_imgsize'] = (bindec('00000011') & ord($extheaderrawrestrictions)) >> 0; // t - Image size restrictions
+ }
+ } else {
+ $ThisFileInfo['warning'][] = '$thisfile_id3v2[exthead_flag_bytes] = "'.$thisfile_id3v2['exthead_flag_bytes'].'" (expecting "1")';
+ fseek($fd, $thisfile_id3v2['exthead_length'] - 1, SEEK_CUR);
+ //return false;
}
- $thisfile_id3v2['exthead_flags']['restrictions'] = substr($id3_exthead_flags, 3, 1);
- if ($thisfile_id3v2['exthead_flags']['restrictions']) {
- // Restrictions %ppqrrstt
- $extheaderrawrestrictions = fread ($fd, 1);
- $thisfile_id3v2['exthead_flags']['restrictions_tagsize'] = (bindec('11000000') & ord($extheaderrawrestrictions)) >> 6; // p - Tag size restrictions
- $thisfile_id3v2['exthead_flags']['restrictions_textenc'] = (bindec('00100000') & ord($extheaderrawrestrictions)) >> 5; // q - Text encoding restrictions
- $thisfile_id3v2['exthead_flags']['restrictions_textsize'] = (bindec('00011000') & ord($extheaderrawrestrictions)) >> 3; // r - Text fields size restrictions
- $thisfile_id3v2['exthead_flags']['restrictions_imgenc'] = (bindec('00000100') & ord($extheaderrawrestrictions)) >> 2; // s - Image encoding restrictions
- $thisfile_id3v2['exthead_flags']['restrictions_imgsize'] = (bindec('00000011') & ord($extheaderrawrestrictions)) >> 0; // t - Image size restrictions
- }
} // end extended header
-
// create 'encoding' key - used by getid3::HandleAllTags()
// in ID3v2 every field can have it's own encoding type
// so force everything to UTF-8 so it can be handled consistantly
@@ -159,10 +163,10 @@
// Flags $xx xx
$sizeofframes = $thisfile_id3v2['headerlength'] - 10; // not including 10-byte initial header
- if (isset($thisfile_id3v2['extheaderlength'])) {
- $sizeofframes -= $thisfile_id3v2['extheaderlength'];
+ if (@$thisfile_id3v2['exthead_length']) {
+ $sizeofframes -= ($thisfile_id3v2['exthead_length'] + 4);
}
- if (isset($thisfile_id3v2_flags['isfooter']) && $thisfile_id3v2_flags['isfooter']) {
+ if (@$thisfile_id3v2_flags['isfooter']) {
$sizeofframes -= 10; // footer takes last 10 bytes of ID3v2 header, after frame data, before audio
}
if ($sizeofframes > 0) {
@@ -170,7 +174,7 @@
$framedata = fread($fd, $sizeofframes); // read all frames from file into $framedata variable
// if entire frame data is unsynched, de-unsynch it now (ID3v2.3.x)
- if (isset($thisfile_id3v2_flags['unsynch']) && $thisfile_id3v2_flags['unsynch'] && ($id3v2_majorversion <= 3)) {
+ if (@$thisfile_id3v2_flags['unsynch'] && ($id3v2_majorversion <= 3)) {
$framedata = $this->DeUnsynchronise($framedata);
}
// [in ID3v2.4.0] Unsynchronisation [S:6.1] is done on frame level, instead
@@ -179,7 +183,7 @@
// there exists an unsynchronised frame, while the new unsynchronisation flag in
// the frame header [S:4.1.2] indicates unsynchronisation.
- $framedataoffset = 10; // how many bytes into the stream - start from after the 10-byte header
+ $framedataoffset = 10 + (@$thisfile_id3v2['exthead_length'] ? $thisfile_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)
while (isset($framedata) && (strlen($framedata) > 0)) { // cycle through until no more frame data is left to parse
if (strlen($framedata) <= $this->ID3v2HeaderLength($id3v2_majorversion)) {
// insufficient room left in ID3v2 header for actual data - must be padding
@@ -230,7 +234,7 @@
} elseif (($frame_name == "\x00".'MP3') || ($frame_name == "\x00\x00".'MP') || ($frame_name == ' MP3') || ($frame_name == 'MP3e')) {
// MP3ext known broken frames - "ok" for the purposes of this test
} elseif (($id3v2_majorversion == 4) && ($this->IsValidID3v2FrameName(substr($framedata, getid3_lib::BigEndian2Int(substr($frame_header, 4, 4), 0), 4), 3))) {
- $ThisFileInfo['warning'][] = 'ID3v2 tag written as ID3v2.4, but with non-synchsafe integers (ID3v2.3 style). Older versions of Helium2 (www.helium2.com) is a known culprit of this. Tag has been parsed as ID3v2.3';
+ $ThisFileInfo['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_majorversion = 3;
$frame_size = getid3_lib::BigEndian2Int(substr($frame_header, 4, 4), 0); // 32-bit integer
}
@@ -288,7 +292,8 @@
} else {
// next frame is invalid too, abort processing
- unset($framedata);
+ //unset($framedata);
+ $framedata = null;
$ThisFileInfo['error'][] = 'Next ID3v2 frame is also invalid, aborting processing.';
}
@@ -301,7 +306,8 @@
} else {
// next frame is invalid too, abort processing
- unset($framedata);
+ //unset($framedata);
+ $framedata = null;
$ThisFileInfo['warning'][] = 'Invalid ID3v2 frame size, aborting.';
}
@@ -350,7 +356,7 @@
// ID3v2 size 4 * %0xxxxxxx
if (isset($thisfile_id3v2_flags['isfooter']) && $thisfile_id3v2_flags['isfooter']) {
- $footer = fread ($fd, 10);
+ $footer = fread($fd, 10);
if (substr($footer, 0, 3) == '3DI') {
$thisfile_id3v2['footer'] = true;
$thisfile_id3v2['majorversion_footer'] = ord($footer{3});
@@ -382,7 +388,11 @@
}
}
+ if (!isset($thisfile_id3v2['comments']['year']) && ereg('^([0-9]{4})', trim(@$thisfile_id3v2['comments']['recording_time'][0]), $matches)) {
+ $thisfile_id3v2['comments']['year'] = array($matches[1]);
+ }
+
// Set avdataoffset
$ThisFileInfo['avdataoffset'] = $thisfile_id3v2['headerlength'];
if (isset($thisfile_id3v2['footer'])) {
@@ -2869,89 +2879,169 @@
$begin = __LINE__;
- /** This is not a comment!
+ /** This is not a comment!
+
+ AENC audio_encryption
+ APIC attached_picture
+ ASPI audio_seek_point_index
+ BUF recommended_buffer_size
+ CNT play_counter
+ COM comments
+ COMM comments
+ COMR commercial_frame
+ CRA audio_encryption
+ CRM encrypted_meta_frame
+ ENCR encryption_method_registration
+ EQU equalisation
+ EQU2 equalisation
+ EQUA equalisation
+ ETC event_timing_codes
+ ETCO event_timing_codes
+ GEO general_encapsulated_object
+ GEOB general_encapsulated_object
+ GRID group_identification_registration
+ IPL involved_people_list
+ IPLS involved_people_list
+ LINK linked_information
+ LNK linked_information
+ MCDI music_cd_identifier
+ MCI music_cd_identifier
+ MLL mpeg_location_lookup_table
+ MLLT mpeg_location_lookup_table
+ OWNE ownership_frame
+ PCNT play_counter
+ PIC attached_picture
+ POP popularimeter
+ POPM popularimeter
+ POSS position_synchronisation_frame
+ PRIV private_frame
+ RBUF recommended_buffer_size
+ REV reverb
+ RVA relative_volume_adjustment
+ RVA2 relative_volume_adjustment
+ RVAD relative_volume_adjustment
+ RVRB reverb
+ SEEK seek_frame
+ SIGN signature_frame
+ SLT synchronised_lyric
+ STC synced_tempo_codes
+ SYLT synchronised_lyric
+ SYTC synchronised_tempo_codes
+ TAL album
+ TALB album
+ TBP bpm
+ TBPM bpm
+ TCM composer
+ TCO content_type
+ TCOM composer
+ TCON content_type
+ TCOP copyright_message
+ TCR copyright_message
+ TDA date
+ TDAT date
+ TDEN encoding_time
+ TDLY playlist_delay
+ TDOR original_release_time
+ TDRC recording_time
+ TDRL release_time
+ TDTG tagging_time
+ TDY playlist_delay
+ TEN encoded_by
+ TENC encoded_by
+ TEXT lyricist
+ TFLT file_type
+ TFT file_type
+ TIM time
+ TIME time
+ TIPL involved_people_list
+ TIT1 content_group_description
+ TIT2 title
+ TIT3 subtitle
+ TKE initial_key
+ TKEY initial_key
+ TLA language
+ TLAN language
+ TLE length
+ TLEN length
+ TMCL musician_credits_list
+ TMED media_type
+ TMOO mood
+ TMT media_type
+ TOA original_artist
+ TOAL original_album
+ TOF original_filename
+ TOFN original_filename
+ TOL original_lyricist
+ TOLY original_lyricist
+ TOPE original_artist
+ TOR original_year
+ TORY original_year
+ TOT original_album
+ TOWN file_owner
+ TP1 artist
+ TP2 band
+ TP3 conductor
+ TP4 remixer
+ TPA part_of_a_set
+ TPB publisher
+ TPE1 artist
+ TPE2 band
+ TPE3 conductor
+ TPE4 remixer
+ TPOS part_of_a_set
+ TPRO produced_notice
+ TPUB publisher
+ TRC isrc
+ TRCK track_number
+ TRD recording_dates
+ TRDA recording_dates
+ TRK track_number
+ TRSN internet_radio_station_name
+ TRSO internet_radio_station_owner
+ TSI size
+ TSIZ size
+ TSOA album_sort_order
+ TSOP performer_sort_order
+ TSOT title_sort_order
+ TSRC isrc
+ TSS encoder_settings
+ TSSE encoder_settings
+ TSST set_subtitle
+ TT1 description
+ TT2 title
+ TT3 subtitle
+ TXT lyricist
+ TXX text
+ TXXX text
+ TYE year
+ TYER year
+ UFI unique_file_identifier
+ UFID unique_file_identifier
+ ULT unsychronised_lyric
+ USER terms_of_use
+ USLT unsynchronised_lyric
+ WAF url_file
+ WAR url_artist
+ WAS url_source
+ WCM commercial_information
+ WCOM commercial_information
+ WCOP copyright
+ WCP copyright
+ WOAF url_file
+ WOAR url_artist
+ WOAS url_source
+ WORS url_station
+ WPAY url_payment
+ WPB url_publisher
+ WPUB url_publisher
+ WXX url_user
+ WXXX url_user
+ TFEA featured_artist
+ TSTU recording_studio
+ rgad replay_gain_adjustment
+
+ */
- COM comment
- COMM comment
- TAL album
- TALB album
- TBP bpm
- TBPM bpm
- TCM composer
- TCO genre
- TCOM composer
- TCON genre
- TCOP copyright
- TCR copyright
- TEN encoded_by
- TENC encoded_by
- TEXT lyricist
- TIT1 description
- TIT2 title
- TIT3 subtitle
- TLA language
- TLAN language
- TLE length
- TLEN length
- TMOO mood
- TOA original_artist
- TOAL original_album
- TOF original_filename
- TOFN original_filename
- TOL original_lyricist
- TOLY original_lyricist
- TOPE original_artist
- TOT original_album
- TP1 artist
- TP2 band
- TP3 conductor
- TP4 remixer
- TPB publisher
- TPE1 artist
- TPE2 band
- TPE3 conductor
- TPE4 remixer
- TPUB publisher
- TRC isrc
- TRCK track
- TRK track
- TSI size
- TSIZ size
- TSRC isrc
- TSS encoder_settings
- TSSE encoder_settings
- TSST subtitle
- TT1 description
- TT2 title
- TT3 subtitle
- TXT lyricist
- TXX text
- TXXX text
- TYE year
- TYER year
- UFI unique_file_identifier
- UFID unique_file_identifier
- ULT unsychronised_lyric
- USER terms_of_use
- USLT unsynchronised lyric
- WAF url_file
- WAR url_artist
- WAS url_source
- WCOP copyright
- WCP copyright
- WOAF url_file
- WOAR url_artist
- WOAS url_source
- WORS url_station
- WPB url_publisher
- WPUB url_publisher
- WXX url_user
- WXXX url_user
- TFEA featured_artist
- TSTU studio
-
- */
-
return getid3_lib::EmbeddedLookup($framename, $begin, __LINE__, __FILE__, 'id3v2-framename_short');
}
Added: plog/trunk/class/gallery/getid3/write.apetag.php
===================================================================
--- plog/trunk/class/gallery/getid3/write.apetag.php 2006-07-24 16:40:16 UTC (rev 3789)
+++ plog/trunk/class/gallery/getid3/write.apetag.php 2006-07-24 16:56:08 UTC (rev 3790)
@@ -0,0 +1,228 @@
+<?php
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info at getid3.org> //
+// available at http://getid3.sourceforge.net //
+// or http://www.getid3.org //
+/////////////////////////////////////////////////////////////////
+// See readme.txt for more details //
+/////////////////////////////////////////////////////////////////
+// //
+// write.apetag.php //
+// module for writing APE tags //
+// dependencies: module.tag.apetag.php //
+// ///
+/////////////////////////////////////////////////////////////////
+
+
+getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.apetag.php', __FILE__, true);
+
+class getid3_write_apetag
+{
+
+ var $filename;
+ var $tag_data;
+ var $always_preserve_replaygain = true; // ReplayGain / MP3gain tags will be copied from old tag even if not passed in data
+ var $warnings = array(); // any non-critical errors will be stored here
+ var $errors = array(); // any critical errors will be stored here
+
+ function getid3_write_apetag() {
+ return true;
+ }
+
+ function WriteAPEtag() {
+ // NOTE: All data passed to this function must be UTF-8 format
+
+ $getID3 = new getID3;
+ $ThisFileInfo = $getID3->analyze($this->filename);
+
+ if (isset($ThisFileInfo['ape']['tag_offset_start']) && isset($ThisFileInfo['lyrics3']['tag_offset_end'])) {
+ if ($ThisFileInfo['ape']['tag_offset_start'] >= $ThisFileInfo['lyrics3']['tag_offset_end']) {
+ // Current APE tag between Lyrics3 and ID3v1/EOF
+ // This break Lyrics3 functionality
+ if (!$this->DeleteAPEtag()) {
+ return false;
+ }
+ $ThisFileInfo = $getID3->analyze($this->filename);
+ }
+ }
+
+ if ($this->always_preserve_replaygain) {
+ $ReplayGainTagsToPreserve = array('mp3gain_minmax', 'mp3gain_album_minmax', 'mp3gain_undo', 'replaygain_track_peak', 'replaygain_track_gain', 'replaygain_album_peak', 'replaygain_album_gain');
+ foreach ($ReplayGainTagsToPreserve as $rg_key) {
+ if (isset($ThisFileInfo['ape']['items'][strtolower($rg_key)]['data'][0]) && !isset($this->tag_data[strtoupper($rg_key)][0])) {
+ $this->tag_data[strtoupper($rg_key)][0] = $ThisFileInfo['ape']['items'][strtolower($rg_key)]['data'][0];
+ }
+ }
+ }
+
+ if ($APEtag = $this->GenerateAPEtag()) {
+ if ($fp = @fopen($this->filename, 'a+b')) {
+ $oldignoreuserabort = ignore_user_abort(true);
+ flock($fp, LOCK_EX);
+
+ $PostAPEdataOffset = $ThisFileInfo['avdataend'];
+ if (isset($ThisFileInfo['ape']['tag_offset_end'])) {
+ $PostAPEdataOffset = max($PostAPEdataOffset, $ThisFileInfo['ape']['tag_offset_end']);
+ }
+ if (isset($ThisFileInfo['lyrics3']['tag_offset_start'])) {
+ $PostAPEdataOffset = max($PostAPEdataOffset, $ThisFileInfo['lyrics3']['tag_offset_start']);
+ }
+ fseek($fp, $PostAPEdataOffset, SEEK_SET);
+ $PostAPEdata = '';
+ if ($ThisFileInfo['filesize'] > $PostAPEdataOffset) {
+ $PostAPEdata = fread($fp, $ThisFileInfo['filesize'] - $PostAPEdataOffset);
+ }
+
+ fseek($fp, $PostAPEdataOffset, SEEK_SET);
+ if (isset($ThisFileInfo['ape']['tag_offset_start'])) {
+ fseek($fp, $ThisFileInfo['ape']['tag_offset_start'], SEEK_SET);
+ }
+ ftruncate($fp, ftell($fp));
+ fwrite($fp, $APEtag, strlen($APEtag));
+ if (!empty($PostAPEdata)) {
+ fwrite($fp, $PostAPEdata, strlen($PostAPEdata));
+ }
+ flock($fp, LOCK_UN);
+ fclose($fp);
+ ignore_user_abort($oldignoreuserabort);
+ return true;
+
+ }
+ return false;
+ }
+ return false;
+ }
+
+ function DeleteAPEtag() {
+ $getID3 = new getID3;
+ $ThisFileInfo = $getID3->analyze($this->filename);
+ if (isset($ThisFileInfo['ape']['tag_offset_start']) && isset($ThisFileInfo['ape']['tag_offset_end'])) {
+ if ($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;
+ }
+
+
+ function GenerateAPEtag() {
+ // NOTE: All data passed to this function must be UTF-8 format
+
+ $items = array();
+ if (!is_array($this->tag_data)) {
+ return false;
+ }
+ foreach ($this->tag_data as $key => $arrayofvalues) {
+ if (!is_array($arrayofvalues)) {
+ return false;
+ }
+
+ $valuestring = '';
+ foreach ($arrayofvalues as $value) {
+ $valuestring .= str_replace("\x00", '', $value)."\x00";
+ }
+ $valuestring = rtrim($valuestring, "\x00");
+
+ // Length of the assigned value in bytes
+ $tagitem = getid3_lib::LittleEndian2String(strlen($valuestring), 4);
+
+ //$tagitem .= $this->GenerateAPEtagFlags(true, true, false, 0, false);
+ $tagitem .= "\x00\x00\x00\x00";
+
+ $tagitem .= $this->CleanAPEtagItemKey($key)."\x00";
+ $tagitem .= $valuestring;
+
+ $items[] = $tagitem;
+
+ }
+
+ return $this->GenerateAPEtagHeaderFooter($items, true).implode('', $items).$this->GenerateAPEtagHeaderFooter($items, false);
+ }
+
+ function GenerateAPEtagHeaderFooter(&$items, $isheader=false) {
+ $tagdatalength = 0;
+ foreach ($items as $itemdata) {
+ $tagdatalength += strlen($itemdata);
+ }
+
+ $APEheader = 'APETAGEX';
+ $APEheader .= getid3_lib::LittleEndian2String(2000, 4);
+ $APEheader .= getid3_lib::LittleEndian2String(32 + $tagdatalength, 4);
+ $APEheader .= getid3_lib::LittleEndian2String(count($items), 4);
+ $APEheader .= $this->GenerateAPEtagFlags(true, true, $isheader, 0, false);
+ $APEheader .= str_repeat("\x00", 8);
+
+ return $APEheader;
+ }
+
+ function GenerateAPEtagFlags($header=true, $footer=true, $isheader=false, $encodingid=0, $readonly=false) {
+ $APEtagFlags = array_fill(0, 4, 0);
+ if ($header) {
+ $APEtagFlags[0] |= 0x80; // Tag contains a header
+ }
+ if (!$footer) {
+ $APEtagFlags[0] |= 0x40; // Tag contains no footer
+ }
+ if ($isheader) {
+ $APEtagFlags[0] |= 0x20; // This is the header, not the footer
+ }
+
+ // 0: Item contains text information coded in UTF-8
+ // 1: Item contains binary information °)
+ // 2: Item is a locator of external stored information °°)
+ // 3: reserved
+ $APEtagFlags[3] |= ($encodingid << 1);
+
+ if ($readonly) {
+ $APEtagFlags[3] |= 0x01; // Tag or Item is Read Only
+ }
+
+ return chr($APEtagFlags[3]).chr($APEtagFlags[2]).chr($APEtagFlags[1]).chr($APEtagFlags[0]);
+ }
+
+ function CleanAPEtagItemKey($itemkey) {
+ $itemkey = eregi_replace("[^\x20-\x7E]", '', $itemkey);
+
+ // http://www.personal.uni-jena.de/~pfk/mpp/sv8/apekey.html
+ switch (strtoupper($itemkey)) {
+ case 'EAN/UPC':
+ case 'ISBN':
+ case 'LC':
+ case 'ISRC':
+ $itemkey = strtoupper($itemkey);
+ break;
+
+ default:
+ $itemkey = ucwords($itemkey);
+ break;
+ }
+ return $itemkey;
+
+ }
+
+}
+
+?>
\ No newline at end of file
Added: plog/trunk/class/gallery/getid3/write.id3v1.php
===================================================================
--- plog/trunk/class/gallery/getid3/write.id3v1.php 2006-07-24 16:40:16 UTC (rev 3789)
+++ plog/trunk/class/gallery/getid3/write.id3v1.php 2006-07-24 16:56:08 UTC (rev 3790)
@@ -0,0 +1,104 @@
+<?php
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info at getid3.org> //
+// available at http://getid3.sourceforge.net //
+// or http://www.getid3.org //
+/////////////////////////////////////////////////////////////////
+// See readme.txt for more details //
+/////////////////////////////////////////////////////////////////
+// //
+// write.id3v1.php //
+// module for writing ID3v1 tags //
+// dependencies: module.tag.id3v1.php //
+// ///
+/////////////////////////////////////////////////////////////////
+
+getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v1.php', __FILE__, true);
+
+class getid3_write_id3v1
+{
+ var $filename;
+ var $tag_data;
+ var $warnings = array(); // any non-critical errors will be stored here
+ var $errors = array(); // any critical errors will be stored here
+
+ function getid3_write_id3v1() {
+ return true;
+ }
+
+ function WriteID3v1() {
+ // File MUST be writeable - CHMOD(646) at least
+ if (is_writeable($this->filename)) {
+ if ($fp_source = @fopen($this->filename, 'r+b')) {
+
+ fseek($fp_source, -128, SEEK_END);
+ if (fread($fp_source, 3) == 'TAG') {
+ fseek($fp_source, -128, SEEK_END); // overwrite existing ID3v1 tag
+ } else {
+ fseek($fp_source, 0, SEEK_END); // append new ID3v1 tag
+ }
+
+ $new_id3v1_tag_data = getid3_id3v1::GenerateID3v1Tag(
+ @$this->tag_data['title'],
+ @$this->tag_data['artist'],
+ @$this->tag_data['album'],
+ @$this->tag_data['year'],
+ @$this->tag_data['genreid'],
+ @$this->tag_data['comment'],
+ @$this->tag_data['track']);
+ fwrite($fp_source, $new_id3v1_tag_data, 128);
+ fclose($fp_source);
+ return true;
+
+ } else {
+ $this->errors[] = 'Could not open '.$this->filename.' mode "r+b"';
+ return false;
+ }
+ }
+ $this->errors[] = 'File is not writeable: '.$this->filename;
+ return false;
+ }
+
+ function FixID3v1Padding() {
+ // ID3v1 data is supposed to be padded with NULL characters, but some taggers incorrectly use spaces
+ // This function rewrites the ID3v1 tag with correct padding
+
+ // Initialize getID3 engine
+ $getID3 = new getID3;
+ $ThisFileInfo = $getID3->analyze($this->filename);
+ if (isset($ThisFileInfo['tags']['id3v1'])) {
+ foreach ($ThisFileInfo['tags']['id3v1'] as $key => $value) {
+ $id3v1data[$key] = implode(',', $value);
+ }
+ $this->tag_data = $id3v1data;
+ return $this->WriteID3v1();
+ }
+ return false;
+ }
+
+ function RemoveID3v1() {
+ // File MUST be writeable - CHMOD(646) at least
+ if (is_writeable($this->filename)) {
+ if ($fp_source = @fopen($this->filename, 'r+b')) {
+
+ fseek($fp_source, -128, SEEK_END);
+ if (fread($fp_source, 3) == 'TAG') {
+ ftruncate($fp_source, filesize($this->filename) - 128);
+ } else {
+ // no ID3v1 tag to begin with - do nothing
+ }
+ fclose($fp_source);
+ return true;
+
+ } else {
+ $this->errors[] = 'Could not open '.$this->filename.' mode "r+b"';
+ }
+ } else {
+ $this->errors[] = $this->filename.' is not writeable';
+ }
+ return false;
+ }
+
+}
+
+?>
\ No newline at end of file
Added: plog/trunk/class/gallery/getid3/write.id3v2.php
===================================================================
--- plog/trunk/class/gallery/getid3/write.id3v2.php 2006-07-24 16:40:16 UTC (rev 3789)
+++ plog/trunk/class/gallery/getid3/write.id3v2.php 2006-07-24 16:56:08 UTC (rev 3790)
@@ -0,0 +1,2038 @@
+<?php
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info at getid3.org> //
+// available at http://getid3.sourceforge.net //
+// or http://www.getid3.org //
+/////////////////////////////////////////////////////////////////
+// See readme.txt for more details //
+/////////////////////////////////////////////////////////////////
+/// //
+// write.id3v2.php //
+// module for writing ID3v2 tags //
+// dependencies: module.tag.id3v2.php //
+// ///
+/////////////////////////////////////////////////////////////////
+
+getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true);
+
+class getid3_write_id3v2
+{
+ var $filename;
+ var $tag_data;
+ var $paddedlength = 4096; // minimum length of ID3v2 tag in bytes
+ var $majorversion = 3; // ID3v2 major version (2, 3 (recommended), 4)
+ var $minorversion = 0; // ID3v2 minor version - always 0
+ var $merge_existing_data = false; // if true, merge new data with existing tags; if false, delete old tag data and only write new tags
+ var $id3v2_default_encodingid = 0; // default text encoding (ISO-8859-1) if not explicitly passed
+ var $id3v2_use_unsynchronisation = false; // the specs say it should be TRUE, but most other ID3v2-aware programs are broken if unsynchronization is used, so by default don't use it.
+ var $warnings = array(); // any non-critical errors will be stored here
+ var $errors = array(); // any critical errors will be stored here
+
+ function getid3_write_id3v2() {
+ return true;
+ }
+
+ function WriteID3v2() {
+ // 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_writeable($this->filename) || (!file_exists($this->filename) && is_writeable(dirname($this->filename)))) {
+ // Initialize getID3 engine
+ $getID3 = new getID3;
+ $OldThisFileInfo = $getID3->analyze($this->filename);
+ if ($this->merge_existing_data) {
+ // merge with existing data
+ if (!empty($OldThisFileInfo['id3v2'])) {
+ $this->tag_data = $this->array_join_merge($OldThisFileInfo['id3v2'], $this->tag_data);
+ }
+ }
+ $this->paddedlength = max(@$OldThisFileInfo['id3v2']['headerlength'], $this->paddedlength);
+
+ if ($NewID3v2Tag = $this->GenerateID3v2Tag()) {
+
+ if (file_exists($this->filename) && is_writeable($this->filename) && isset($OldThisFileInfo['id3v2']['headerlength']) && ($OldThisFileInfo['id3v2']['headerlength'] == strlen($NewID3v2Tag))) {
+
+ // best and fastest method - insert-overwrite existing tag (padded to length of old tag if neccesary)
+ if (file_exists($this->filename)) {
+
+ ob_start();
+ if ($fp = fopen($this->filename, 'r+b')) {
+ rewind($fp);
+ fwrite($fp, $NewID3v2Tag, strlen($NewID3v2Tag));
+ fclose($fp);
+ } else {
+ $this->errors[] = 'Could not open '.$this->filename.' mode "r+b" - '.strip_tags(ob_get_contents());
+ }
+ ob_end_clean();
+
+ } else {
+
+ ob_start();
+ if ($fp = fopen($this->filename, 'wb')) {
+ rewind($fp);
+ fwrite($fp, $NewID3v2Tag, strlen($NewID3v2Tag));
+ fclose($fp);
+ } else {
+ $this->errors[] = 'Could not open '.$this->filename.' mode "wb" - '.strip_tags(ob_get_contents());
+ }
+ ob_end_clean();
+
+ }
+
+ } else {
+
+ if ($tempfilename = tempnam('*', 'getID3')) {
+ ob_start();
+ if ($fp_source = fopen($this->filename, 'rb')) {
+ if ($fp_temp = fopen($tempfilename, 'wb')) {
+
+ fwrite($fp_temp, $NewID3v2Tag, strlen($NewID3v2Tag));
+
+ rewind($fp_source);
+ if (!empty($OldThisFileInfo['avdataoffset'])) {
+ fseek($fp_source, $OldThisFileInfo['avdataoffset'], SEEK_SET);
+ }
+
+ while ($buffer = fread($fp_source, GETID3_FREAD_BUFFER_SIZE)) {
+ fwrite($fp_temp, $buffer, strlen($buffer));
+ }
+
+ fclose($fp_temp);
+ fclose($fp_source);
+ copy($tempfilename, $this->filename);
+ unlink($tempfilename);
+ ob_end_clean();
+ return true;
+
+ } else {
+
+ $this->errors[] = 'Could not open '.$tempfilename.' mode "wb" - '.strip_tags(ob_get_contents());
+
+ }
+ fclose($fp_source);
+
+ } else {
+
+ $this->errors[] = 'Could not open '.$this->filename.' mode "rb" - '.strip_tags(ob_get_contents());
+
+ }
+ ob_end_clean();
+ }
+ return false;
+
+ }
+
+ } else {
+
+ $this->errors[] = '$this->GenerateID3v2Tag() failed';
+
+ }
+
+ if (!empty($this->errors)) {
+ return false;
+ }
+ return true;
+ } else {
+ $this->errors[] = '!is_writeable('.$this->filename.')';
+ }
+ return false;
+ }
+
+ 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_writeable(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 ($fp_source = @fopen($this->filename, 'rb')) {
+ // Initialize getID3 engine
+ $getID3 = new getID3;
+ $OldThisFileInfo = $getID3->analyze($this->filename);
+ rewind($fp_source);
+ if ($OldThisFileInfo['avdataoffset'] !== false) {
+ fseek($fp_source, $OldThisFileInfo['avdataoffset'], SEEK_SET);
+ }
+ if ($fp_temp = @fopen($this->filename.'getid3tmp', 'w+b')) {
+ while ($buffer = fread($fp_source, GETID3_FREAD_BUFFER_SIZE)) {
+ fwrite($fp_temp, $buffer, strlen($buffer));
+ }
+ fclose($fp_temp);
+ } else {
+ $this->errors[] = 'Could not open '.$this->filename.'getid3tmp mode "w+b"';
+ }
+ fclose($fp_source);
+ } else {
+ $this->errors[] = 'Could not open '.$this->filename.' mode "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 ($fp_source = @fopen($this->filename, 'rb')) {
+ // Initialize getID3 engine
+ $getID3 = new getID3;
+ $OldThisFileInfo = $getID3->analyze($this->filename);
+ rewind($fp_source);
+ if ($OldThisFileInfo['avdataoffset'] !== false) {
+ fseek($fp_source, $OldThisFileInfo['avdataoffset'], SEEK_SET);
+ }
+ if ($fp_temp = tmpfile()) {
+ while ($buffer = fread($fp_source, GETID3_FREAD_BUFFER_SIZE)) {
+ fwrite($fp_temp, $buffer, strlen($buffer));
+ }
+ fclose($fp_source);
+ if ($fp_source = @fopen($this->filename, 'wb')) {
+ rewind($fp_temp);
+ while ($buffer = fread($fp_temp, GETID3_FREAD_BUFFER_SIZE)) {
+ fwrite($fp_source, $buffer, strlen($buffer));
+ }
+ fseek($fp_temp, -128, SEEK_END);
+ fclose($fp_source);
+ } else {
+ $this->errors[] = 'Could not open '.$this->filename.' mode "wb"';
+ }
+ fclose($fp_temp);
+ } else {
+ $this->errors[] = 'Could not create tmpfile()';
+ }
+ } else {
+ $this->errors[] = 'Could not open '.$this->filename.' mode "rb"';
+ }
+
+ } else {
+
+ $this->errors[] = 'Directory and file both not writeable';
+
+ }
+
+ if (!empty($this->errors)) {
+ return false;
+ }
+ return true;
+ }
+
+
+ function GenerateID3v2TagFlags($flags) {
+ switch ($this->majorversion) {
+ case 4:
+ // %abcd0000
+ $flag = (@$flags['unsynchronisation'] ? '1' : '0'); // a - Unsynchronisation
+ $flag .= (@$flags['extendedheader'] ? '1' : '0'); // b - Extended header
+ $flag .= (@$flags['experimental'] ? '1' : '0'); // c - Experimental indicator
+ $flag .= (@$flags['footer'] ? '1' : '0'); // d - Footer present
+ $flag .= '0000';
+ break;
+
+ case 3:
+ // %abc00000
+ $flag = (@$flags['unsynchronisation'] ? '1' : '0'); // a - Unsynchronisation
+ $flag .= (@$flags['extendedheader'] ? '1' : '0'); // b - Extended header
+ $flag .= (@$flags['experimental'] ? '1' : '0'); // c - Experimental indicator
+ $flag .= '00000';
+ break;
+
+ case 2:
+ // %ab000000
+ $flag = (@$flags['unsynchronisation'] ? '1' : '0'); // a - Unsynchronisation
+ $flag .= (@$flags['compression'] ? '1' : '0'); // b - Compression
+ $flag .= '000000';
+ break;
+
+ default:
+ return false;
+ break;
+ }
+ return chr(bindec($flag));
+ }
+
+
+ function GenerateID3v2FrameFlags($TagAlter=false, $FileAlter=false, $ReadOnly=false, $Compression=false, $Encryption=false, $GroupingIdentity=false, $Unsynchronisation=false, $DataLengthIndicator=false) {
+ switch ($this->majorversion) {
+ case 4:
+ // %0abc0000 %0h00kmnp
+ $flag1 = '0';
+ $flag1 .= $TagAlter ? '1' : '0'; // a - Tag alter preservation (true == discard)
+ $flag1 .= $FileAlter ? '1' : '0'; // b - File alter preservation (true == discard)
+ $flag1 .= $ReadOnly ? '1' : '0'; // c - Read only (true == read only)
+ $flag1 .= '0000';
+
+ $flag2 = '0';
+ $flag2 .= $GroupingIdentity ? '1' : '0'; // h - Grouping identity (true == contains group information)
+ $flag2 .= '00';
+ $flag2 .= $Compression ? '1' : '0'; // k - Compression (true == compressed)
+ $flag2 .= $Encryption ? '1' : '0'; // m - Encryption (true == encrypted)
+ $flag2 .= $Unsynchronisation ? '1' : '0'; // n - Unsynchronisation (true == unsynchronised)
+ $flag2 .= $DataLengthIndicator ? '1' : '0'; // p - Data length indicator (true == data length indicator added)
+ break;
+
+ case 3:
+ // %abc00000 %ijk00000
+ $flag1 = $TagAlter ? '1' : '0'; // a - Tag alter preservation (true == discard)
+ $flag1 .= $FileAlter ? '1' : '0'; // b - File alter preservation (true == discard)
+ $flag1 .= $ReadOnly ? '1' : '0'; // c - Read only (true == read only)
+ $flag1 .= '00000';
+
+ $flag2 = $Compression ? '1' : '0'; // i - Compression (true == compressed)
+ $flag2 .= $Encryption ? '1' : '0'; // j - Encryption (true == encrypted)
+ $flag2 .= $GroupingIdentity ? '1' : '0'; // k - Grouping identity (true == contains group information)
+ $flag2 .= '00000';
+ break;
+
+ default:
+ return false;
+ break;
+
+ }
+ return chr(bindec($flag1)).chr(bindec($flag2));
+ }
+
+ function GenerateID3v2FrameData($frame_name, $source_data_array) {
+ if (!getid3_id3v2::IsValidID3v2FrameName($frame_name, $this->majorversion)) {
+ return false;
+ }
+ $framedata = '';
+
+ if (($this->majorversion < 3) || ($this->majorversion > 4)) {
+
+ $this->errors[] = 'Only ID3v2.3 and ID3v2.4 are supported in GenerateID3v2FrameData()';
+
+ } else { // $this->majorversion 3 or 4
+
+ switch ($frame_name) {
+ case 'UFID':
+ // 4.1 UFID Unique file identifier
+ // Owner identifier <text string> $00
+ // Identifier <up to 64 bytes binary data>
+ if (strlen($source_data_array['data']) > 64) {
+ $this->errors[] = 'Identifier not allowed to be longer than 64 bytes in '.$frame_name.' (supplied data was '.strlen($source_data_array['data']).' bytes long)';
+ } else {
+ $framedata .= str_replace("\x00", '', $source_data_array['ownerid'])."\x00";
+ $framedata .= substr($source_data_array['data'], 0, 64); // max 64 bytes - truncate anything longer
+ }
+ break;
+
+ case 'TXXX':
+ // 4.2.2 TXXX User defined text information frame
+ // Text encoding $xx
+ // Description <text string according to encoding> $00 (00)
+ // Value <text string according to encoding>
+ $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid);
+ if (!$this->ID3v2IsValidTextEncoding($source_data_array['encodingid'], $this->majorversion)) {
+ $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].') for ID3v2.'.$this->majorversion;
+ } else {
+ $framedata .= chr($source_data_array['encodingid']);
+ $framedata .= $source_data_array['description'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']);
+ $framedata .= $source_data_array['data'];
+ }
+ break;
+
+ case 'WXXX':
+ // 4.3.2 WXXX User defined URL link frame
+ // Text encoding $xx
+ // Description <text string according to encoding> $00 (00)
+ // URL <text string>
+ $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid);
+ if (!$this->ID3v2IsValidTextEncoding($source_data_array['encodingid'], $this->majorversion)) {
+ $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].') for ID3v2.'.$this->majorversion;
+ } elseif (!isset($source_data_array['data']) || !$this->IsValidURL($source_data_array['data'], false, false)) {
+ //$this->errors[] = 'Invalid URL in '.$frame_name.' ('.$source_data_array['data'].')';
+ // probably should be an error, need to rewrite IsValidURL() to handle other encodings
+ $this->warnings[] = 'Invalid URL in '.$frame_name.' ('.$source_data_array['data'].')';
+ } else {
+ $framedata .= chr($source_data_array['encodingid']);
+ $framedata .= $source_data_array['description'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']);
+ $framedata .= $source_data_array['data'];
+ }
+ break;
+
+ case 'IPLS':
+ // 4.4 IPLS Involved people list (ID3v2.3 only)
+ // Text encoding $xx
+ // People list strings <textstrings>
+ $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid);
+ if (!$this->ID3v2IsValidTextEncoding($source_data_array['encodingid'], $this->majorversion)) {
+ $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].') for ID3v2.'.$this->majorversion;
+ } else {
+ $framedata .= chr($source_data_array['encodingid']);
+ $framedata .= $source_data_array['data'];
+ }
+ break;
+
+ case 'MCDI':
+ // 4.4 MCDI Music CD identifier
+ // CD TOC <binary data>
+ $framedata .= $source_data_array['data'];
+ break;
+
+ case 'ETCO':
+ // 4.5 ETCO Event timing codes
+ // Time stamp format $xx
+ // Where time stamp format is:
+ // $01 (32-bit value) MPEG frames from beginning of file
+ // $02 (32-bit value) milliseconds from beginning of file
+ // Followed by a list of key events in the following format:
+ // Type of event $xx
+ // Time stamp $xx (xx ...)
+ // The 'Time stamp' is set to zero if directly at the beginning of the sound
+ // or after the previous event. All events MUST be sorted in chronological order.
+ if (($source_data_array['timestampformat'] > 2) || ($source_data_array['timestampformat'] < 1)) {
+ $this->errors[] = 'Invalid Time Stamp Format byte in '.$frame_name.' ('.$source_data_array['timestampformat'].')';
+ } else {
+ $framedata .= chr($source_data_array['timestampformat']);
+ foreach ($source_data_array as $key => $val) {
+ if (!$this->ID3v2IsValidETCOevent($val['typeid'])) {
+ $this->errors[] = 'Invalid Event Type byte in '.$frame_name.' ('.$val['typeid'].')';
+ } elseif (($key != 'timestampformat') && ($key != 'flags')) {
+ if (($val['timestamp'] > 0) && ($previousETCOtimestamp >= $val['timestamp'])) {
+ // The 'Time stamp' is set to zero if directly at the beginning of the sound
+ // or after the previous event. All events MUST be sorted in chronological order.
+ $this->errors[] = 'Out-of-order timestamp in '.$frame_name.' ('.$val['timestamp'].') for Event Type ('.$val['typeid'].')';
+ } else {
+ $framedata .= chr($val['typeid']);
+ $framedata .= getid3_lib::BigEndian2String($val['timestamp'], 4, false);
+ }
+ }
+ }
+ }
+ break;
+
+ case 'MLLT':
+ // 4.6 MLLT MPEG location lookup table
+ // MPEG frames between reference $xx xx
+ // Bytes between reference $xx xx xx
+ // Milliseconds between reference $xx xx xx
+ // Bits for bytes deviation $xx
+ // Bits for milliseconds dev. $xx
+ // Then for every reference the following data is included;
+ // Deviation in bytes %xxx....
+ // Deviation in milliseconds %xxx....
+ if (($source_data_array['framesbetweenreferences'] > 0) && ($source_data_array['framesbetweenreferences'] <= 65535)) {
+ $framedata .= getid3_lib::BigEndian2String($source_data_array['framesbetweenreferences'], 2, false);
+ } else {
+ $this->errors[] = 'Invalid MPEG Frames Between References in '.$frame_name.' ('.$source_data_array['framesbetweenreferences'].')';
+ }
+ if (($source_data_array['bytesbetweenreferences'] > 0) && ($source_data_array['bytesbetweenreferences'] <= 16777215)) {
+ $framedata .= getid3_lib::BigEndian2String($source_data_array['bytesbetweenreferences'], 3, false);
+ } else {
+ $this->errors[] = 'Invalid bytes Between References in '.$frame_name.' ('.$source_data_array['bytesbetweenreferences'].')';
+ }
+ if (($source_data_array['msbetweenreferences'] > 0) && ($source_data_array['msbetweenreferences'] <= 16777215)) {
+ $framedata .= getid3_lib::BigEndian2String($source_data_array['msbetweenreferences'], 3, false);
+ } else {
+ $this->errors[] = 'Invalid Milliseconds Between References in '.$frame_name.' ('.$source_data_array['msbetweenreferences'].')';
+ }
+ if (!$this->IsWithinBitRange($source_data_array['bitsforbytesdeviation'], 8, false)) {
+ if (($source_data_array['bitsforbytesdeviation'] % 4) == 0) {
+ $framedata .= chr($source_data_array['bitsforbytesdeviation']);
+ } else {
+ $this->errors[] = 'Bits For Bytes Deviation in '.$frame_name.' ('.$source_data_array['bitsforbytesdeviation'].') must be a multiple of 4.';
+ }
+ } else {
+ $this->errors[] = 'Invalid Bits For Bytes Deviation in '.$frame_name.' ('.$source_data_array['bitsforbytesdeviation'].')';
+ }
+ if (!$this->IsWithinBitRange($source_data_array['bitsformsdeviation'], 8, false)) {
+ if (($source_data_array['bitsformsdeviation'] % 4) == 0) {
+ $framedata .= chr($source_data_array['bitsformsdeviation']);
+ } else {
+ $this->errors[] = 'Bits For Milliseconds Deviation in '.$frame_name.' ('.$source_data_array['bitsforbytesdeviation'].') must be a multiple of 4.';
+ }
+ } else {
+ $this->errors[] = 'Invalid Bits For Milliseconds Deviation in '.$frame_name.' ('.$source_data_array['bitsformsdeviation'].')';
+ }
+ foreach ($source_data_array as $key => $val) {
+ if (($key != 'framesbetweenreferences') && ($key != 'bytesbetweenreferences') && ($key != 'msbetweenreferences') && ($key != 'bitsforbytesdeviation') && ($key != 'bitsformsdeviation') && ($key != 'flags')) {
+ $unwrittenbitstream .= str_pad(getid3_lib::Dec2Bin($val['bytedeviation']), $source_data_array['bitsforbytesdeviation'], '0', STR_PAD_LEFT);
+ $unwrittenbitstream .= str_pad(getid3_lib::Dec2Bin($val['msdeviation']), $source_data_array['bitsformsdeviation'], '0', STR_PAD_LEFT);
+ }
+ }
+ for ($i = 0; $i < strlen($unwrittenbitstream); $i += 8) {
+ $highnibble = bindec(substr($unwrittenbitstream, $i, 4)) << 4;
+ $lownibble = bindec(substr($unwrittenbitstream, $i + 4, 4));
+ $framedata .= chr($highnibble & $lownibble);
+ }
+ break;
+
+ case 'SYTC':
+ // 4.7 SYTC Synchronised tempo codes
+ // Time stamp format $xx
+ // Tempo data <binary data>
+ // Where time stamp format is:
+ // $01 (32-bit value) MPEG frames from beginning of file
+ // $02 (32-bit value) milliseconds from beginning of file
+ if (($source_data_array['timestampformat'] > 2) || ($source_data_array['timestampformat'] < 1)) {
+ $this->errors[] = 'Invalid Time Stamp Format byte in '.$frame_name.' ('.$source_data_array['timestampformat'].')';
+ } else {
+ $framedata .= chr($source_data_array['timestampformat']);
+ foreach ($source_data_array as $key => $val) {
+ if (!$this->ID3v2IsValidETCOevent($val['typeid'])) {
+ $this->errors[] = 'Invalid Event Type byte in '.$frame_name.' ('.$val['typeid'].')';
+ } elseif (($key != 'timestampformat') && ($key != 'flags')) {
+ if (($val['tempo'] < 0) || ($val['tempo'] > 510)) {
+ $this->errors[] = 'Invalid Tempo (max = 510) in '.$frame_name.' ('.$val['tempo'].') at timestamp ('.$val['timestamp'].')';
+ } else {
+ if ($val['tempo'] > 255) {
+ $framedata .= chr(255);
+ $val['tempo'] -= 255;
+ }
+ $framedata .= chr($val['tempo']);
+ $framedata .= getid3_lib::BigEndian2String($val['timestamp'], 4, false);
+ }
+ }
+ }
+ }
+ break;
+
+ case 'USLT':
+ // 4.8 USLT Unsynchronised lyric/text transcription
+ // Text encoding $xx
+ // Language $xx xx xx
+ // Content descriptor <text string according to encoding> $00 (00)
+ // Lyrics/text <full text string according to encoding>
+ $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid);
+ if (!$this->ID3v2IsValidTextEncoding($source_data_array['encodingid'])) {
+ $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].') for ID3v2.'.$this->majorversion;
+ } elseif (getid3_id3v2::LanguageLookup($source_data_array['language'], true) == '') {
+ $this->errors[] = 'Invalid Language in '.$frame_name.' ('.$source_data_array['language'].')';
+ } else {
+ $framedata .= chr($source_data_array['encodingid']);
+ $framedata .= strtolower($source_data_array['language']);
+ $framedata .= $source_data_array['description'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']);
+ $framedata .= $source_data_array['data'];
+ }
+ break;
+
+ case 'SYLT':
+ // 4.9 SYLT Synchronised lyric/text
+ // Text encoding $xx
+ // Language $xx xx xx
+ // Time stamp format $xx
+ // $01 (32-bit value) MPEG frames from beginning of file
+ // $02 (32-bit value) milliseconds from beginning of file
+ // Content type $xx
+ // Content descriptor <text string according to encoding> $00 (00)
+ // Terminated text to be synced (typically a syllable)
+ // Sync identifier (terminator to above string) $00 (00)
+ // Time stamp $xx (xx ...)
+ $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid);
+ if (!$this->ID3v2IsValidTextEncoding($source_data_array['encodingid'])) {
+ $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].') for ID3v2.'.$this->majorversion;
+ } elseif (getid3_id3v2::LanguageLookup($source_data_array['language'], true) == '') {
+ $this->errors[] = 'Invalid Language in '.$frame_name.' ('.$source_data_array['language'].')';
+ } elseif (($source_data_array['timestampformat'] > 2) || ($source_data_array['timestampformat'] < 1)) {
+ $this->errors[] = 'Invalid Time Stamp Format byte in '.$frame_name.' ('.$source_data_array['timestampformat'].')';
+ } elseif (!$this->ID3v2IsValidSYLTtype($source_data_array['contenttypeid'])) {
+ $this->errors[] = 'Invalid Content Type byte in '.$frame_name.' ('.$source_data_array['contenttypeid'].')';
+ } elseif (!is_array($source_data_array['data'])) {
+ $this->errors[] = 'Invalid Lyric/Timestamp data in '.$frame_name.' (must be an array)';
+ } else {
+ $framedata .= chr($source_data_array['encodingid']);
+ $framedata .= strtolower($source_data_array['language']);
+ $framedata .= chr($source_data_array['timestampformat']);
+ $framedata .= chr($source_data_array['contenttypeid']);
+ $framedata .= $source_data_array['description'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']);
+ ksort($source_data_array['data']);
+ foreach ($source_data_array['data'] as $key => $val) {
+ $framedata .= $val['data'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']);
+ $framedata .= getid3_lib::BigEndian2String($val['timestamp'], 4, false);
+ }
+ }
+ break;
+
+ case 'COMM':
+ // 4.10 COMM Comments
+ // Text encoding $xx
+ // Language $xx xx xx
+ // Short content descrip. <text string according to encoding> $00 (00)
+ // The actual text <full text string according to encoding>
+ $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid);
+ if (!$this->ID3v2IsValidTextEncoding($source_data_array['encodingid'])) {
+ $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].') for ID3v2.'.$this->majorversion;
+ } elseif (getid3_id3v2::LanguageLookup($source_data_array['language'], true) == '') {
+ $this->errors[] = 'Invalid Language in '.$frame_name.' ('.$source_data_array['language'].')';
+ } else {
+ $framedata .= chr($source_data_array['encodingid']);
+ $framedata .= strtolower($source_data_array['language']);
+ $framedata .= $source_data_array['description'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']);
+ $framedata .= $source_data_array['data'];
+ }
+ break;
+
+ case 'RVA2':
+ // 4.11 RVA2 Relative volume adjustment (2) (ID3v2.4+ only)
+ // Identification <text string> $00
+ // The 'identification' string is used to identify the situation and/or
+ // device where this adjustment should apply. The following is then
+ // repeated for every channel:
+ // Type of channel $xx
+ // Volume adjustment $xx xx
+ // Bits representing peak $xx
+ // Peak volume $xx (xx ...)
+ $framedata .= str_replace("\x00", '', $source_data_array['description'])."\x00";
+ foreach ($source_data_array as $key => $val) {
+ if ($key != 'description') {
+ $framedata .= chr($val['channeltypeid']);
+ $framedata .= getid3_lib::BigEndian2String($val['volumeadjust'], 2, false, true); // signed 16-bit
+ if (!$this->IsWithinBitRange($source_data_array['bitspeakvolume'], 8, false)) {
+ $framedata .= chr($val['bitspeakvolume']);
+ if ($val['bitspeakvolume'] > 0) {
+ $framedata .= getid3_lib::BigEndian2String($val['peakvolume'], ceil($val['bitspeakvolume'] / 8), false, false);
+ }
+ } else {
+ $this->errors[] = 'Invalid Bits Representing Peak Volume in '.$frame_name.' ('.$val['bitspeakvolume'].') (range = 0 to 255)';
+ }
+ }
+ }
+ break;
+
+ case 'RVAD':
+ // 4.12 RVAD Relative volume adjustment (ID3v2.3 only)
+ // Increment/decrement %00fedcba
+ // Bits used for volume descr. $xx
+ // Relative volume change, right $xx xx (xx ...) // a
+ // Relative volume change, left $xx xx (xx ...) // b
+ // Peak volume right $xx xx (xx ...)
+ // Peak volume left $xx xx (xx ...)
+ // Relative volume change, right back $xx xx (xx ...) // c
+ // Relative volume change, left back $xx xx (xx ...) // d
+ // Peak volume right back $xx xx (xx ...)
+ // Peak volume left back $xx xx (xx ...)
+ // Relative volume change, center $xx xx (xx ...) // e
+ // Peak volume center $xx xx (xx ...)
+ // Relative volume change, bass $xx xx (xx ...) // f
+ // Peak volume bass $xx xx (xx ...)
+ if (!$this->IsWithinBitRange($source_data_array['bitsvolume'], 8, false)) {
+ $this->errors[] = 'Invalid Bits For Volume Description byte in '.$frame_name.' ('.$source_data_array['bitsvolume'].') (range = 1 to 255)';
+ } else {
+ $incdecflag .= '00';
+ $incdecflag .= $source_data_array['incdec']['right'] ? '1' : '0'; // a - Relative volume change, right
+ $incdecflag .= $source_data_array['incdec']['left'] ? '1' : '0'; // b - Relative volume change, left
+ $incdecflag .= $source_data_array['incdec']['rightrear'] ? '1' : '0'; // c - Relative volume change, right back
+ $incdecflag .= $source_data_array['incdec']['leftrear'] ? '1' : '0'; // d - Relative volume change, left back
+ $incdecflag .= $source_data_array['incdec']['center'] ? '1' : '0'; // e - Relative volume change, center
+ $incdecflag .= $source_data_array['incdec']['bass'] ? '1' : '0'; // f - Relative volume change, bass
+ $framedata .= chr(bindec($incdecflag));
+ $framedata .= chr($source_data_array['bitsvolume']);
+ $framedata .= getid3_lib::BigEndian2String($source_data_array['volumechange']['right'], ceil($source_data_array['bitsvolume'] / 8), false);
+ $framedata .= getid3_lib::BigEndian2String($source_data_array['volumechange']['left'], ceil($source_data_array['bitsvolume'] / 8), false);
+ $framedata .= getid3_lib::BigEndian2String($source_data_array['peakvolume']['right'], ceil($source_data_array['bitsvolume'] / 8), false);
+ $framedata .= getid3_lib::BigEndian2String($source_data_array['peakvolume']['left'], ceil($source_data_array['bitsvolume'] / 8), false);
+ if ($source_data_array['volumechange']['rightrear'] || $source_data_array['volumechange']['leftrear'] ||
+ $source_data_array['peakvolume']['rightrear'] || $source_data_array['peakvolume']['leftrear'] ||
+ $source_data_array['volumechange']['center'] || $source_data_array['peakvolume']['center'] ||
+ $source_data_array['volumechange']['bass'] || $source_data_array['peakvolume']['bass']) {
+ $framedata .= getid3_lib::BigEndian2String($source_data_array['volumechange']['rightrear'], ceil($source_data_array['bitsvolume']/8), false);
+ $framedata .= getid3_lib::BigEndian2String($source_data_array['volumechange']['leftrear'], ceil($source_data_array['bitsvolume']/8), false);
+ $framedata .= getid3_lib::BigEndian2String($source_data_array['peakvolume']['rightrear'], ceil($source_data_array['bitsvolume']/8), false);
+ $framedata .= getid3_lib::BigEndian2String($source_data_array['peakvolume']['leftrear'], ceil($source_data_array['bitsvolume']/8), false);
+ }
+ if ($source_data_array['volumechange']['center'] || $source_data_array['peakvolume']['center'] ||
+ $source_data_array['volumechange']['bass'] || $source_data_array['peakvolume']['bass']) {
+ $framedata .= getid3_lib::BigEndian2String($source_data_array['volumechange']['center'], ceil($source_data_array['bitsvolume']/8), false);
+ $framedata .= getid3_lib::BigEndian2String($source_data_array['peakvolume']['center'], ceil($source_data_array['bitsvolume']/8), false);
+ }
+ if ($source_data_array['volumechange']['bass'] || $source_data_array['peakvolume']['bass']) {
+ $framedata .= getid3_lib::BigEndian2String($source_data_array['volumechange']['bass'], ceil($source_data_array['bitsvolume']/8), false);
+ $framedata .= getid3_lib::BigEndian2String($source_data_array['peakvolume']['bass'], ceil($source_data_array['bitsvolume']/8), false);
+ }
+ }
+ break;
+
+ case 'EQU2':
+ // 4.12 EQU2 Equalisation (2) (ID3v2.4+ only)
+ // Interpolation method $xx
+ // $00 Band
+ // $01 Linear
+ // Identification <text string> $00
+ // The following is then repeated for every adjustment point
+ // Frequency $xx xx
+ // Volume adjustment $xx xx
+ if (($source_data_array['interpolationmethod'] < 0) || ($source_data_array['interpolationmethod'] > 1)) {
+ $this->errors[] = 'Invalid Interpolation Method byte in '.$frame_name.' ('.$source_data_array['interpolationmethod'].') (valid = 0 or 1)';
+ } else {
+ $framedata .= chr($source_data_array['interpolationmethod']);
+ $framedata .= str_replace("\x00", '', $source_data_array['description'])."\x00";
+ foreach ($source_data_array['data'] as $key => $val) {
+ $framedata .= getid3_lib::BigEndian2String(intval(round($key * 2)), 2, false);
+ $framedata .= getid3_lib::BigEndian2String($val, 2, false, true); // signed 16-bit
+ }
+ }
+ break;
+
+ case 'EQUA':
+ // 4.12 EQUA Equalisation (ID3v2.3 only)
+ // Adjustment bits $xx
+ // This is followed by 2 bytes + ('adjustment bits' rounded up to the
+ // nearest byte) for every equalisation band in the following format,
+ // giving a frequency range of 0 - 32767Hz:
+ // Increment/decrement %x (MSB of the Frequency)
+ // Frequency (lower 15 bits)
+ // Adjustment $xx (xx ...)
+ if (!$this->IsWithinBitRange($source_data_array['bitsvolume'], 8, false)) {
+ $this->errors[] = 'Invalid Adjustment Bits byte in '.$frame_name.' ('.$source_data_array['bitsvolume'].') (range = 1 to 255)';
+ } else {
+ $framedata .= chr($source_data_array['adjustmentbits']);
+ foreach ($source_data_array as $key => $val) {
+ if ($key != 'bitsvolume') {
+ if (($key > 32767) || ($key < 0)) {
+ $this->errors[] = 'Invalid Frequency in '.$frame_name.' ('.$key.') (range = 0 to 32767)';
+ } else {
+ if ($val >= 0) {
+ // put MSB of frequency to 1 if increment, 0 if decrement
+ $key |= 0x8000;
+ }
+ $framedata .= getid3_lib::BigEndian2String($key, 2, false);
+ $framedata .= getid3_lib::BigEndian2String($val, ceil($source_data_array['adjustmentbits'] / 8), false);
+ }
+ }
+ }
+ }
+ break;
+
+ case 'RVRB':
+ // 4.13 RVRB Reverb
+ // Reverb left (ms) $xx xx
+ // Reverb right (ms) $xx xx
+ // Reverb bounces, left $xx
+ // Reverb bounces, right $xx
+ // Reverb feedback, left to left $xx
+ // Reverb feedback, left to right $xx
+ // Reverb feedback, right to right $xx
+ // Reverb feedback, right to left $xx
+ // Premix left to right $xx
+ // Premix right to left $xx
+ if (!$this->IsWithinBitRange($source_data_array['left'], 16, false)) {
+ $this->errors[] = 'Invalid Reverb Left in '.$frame_name.' ('.$source_data_array['left'].') (range = 0 to 65535)';
+ } elseif (!$this->IsWithinBitRange($source_data_array['right'], 16, false)) {
+ $this->errors[] = 'Invalid Reverb Left in '.$frame_name.' ('.$source_data_array['right'].') (range = 0 to 65535)';
+ } elseif (!$this->IsWithinBitRange($source_data_array['bouncesL'], 8, false)) {
+ $this->errors[] = 'Invalid Reverb Bounces, Left in '.$frame_name.' ('.$source_data_array['bouncesL'].') (range = 0 to 255)';
+ } elseif (!$this->IsWithinBitRange($source_data_array['bouncesR'], 8, false)) {
+ $this->errors[] = 'Invalid Reverb Bounces, Right in '.$frame_name.' ('.$source_data_array['bouncesR'].') (range = 0 to 255)';
+ } elseif (!$this->IsWithinBitRange($source_data_array['feedbackLL'], 8, false)) {
+ $this->errors[] = 'Invalid Reverb Feedback, Left-To-Left in '.$frame_name.' ('.$source_data_array['feedbackLL'].') (range = 0 to 255)';
+ } elseif (!$this->IsWithinBitRange($source_data_array['feedbackLR'], 8, false)) {
+ $this->errors[] = 'Invalid Reverb Feedback, Left-To-Right in '.$frame_name.' ('.$source_data_array['feedbackLR'].') (range = 0 to 255)';
+ } elseif (!$this->IsWithinBitRange($source_data_array['feedbackRR'], 8, false)) {
+ $this->errors[] = 'Invalid Reverb Feedback, Right-To-Right in '.$frame_name.' ('.$source_data_array['feedbackRR'].') (range = 0 to 255)';
+ } elseif (!$this->IsWithinBitRange($source_data_array['feedbackRL'], 8, false)) {
+ $this->errors[] = 'Invalid Reverb Feedback, Right-To-Left in '.$frame_name.' ('.$source_data_array['feedbackRL'].') (range = 0 to 255)';
+ } elseif (!$this->IsWithinBitRange($source_data_array['premixLR'], 8, false)) {
+ $this->errors[] = 'Invalid Premix, Left-To-Right in '.$frame_name.' ('.$source_data_array['premixLR'].') (range = 0 to 255)';
+ } elseif (!$this->IsWithinBitRange($source_data_array['premixRL'], 8, false)) {
+ $this->errors[] = 'Invalid Premix, Right-To-Left in '.$frame_name.' ('.$source_data_array['premixRL'].') (range = 0 to 255)';
+ } else {
+ $framedata .= getid3_lib::BigEndian2String($source_data_array['left'], 2, false);
+ $framedata .= getid3_lib::BigEndian2String($source_data_array['right'], 2, false);
+ $framedata .= chr($source_data_array['bouncesL']);
+ $framedata .= chr($source_data_array['bouncesR']);
+ $framedata .= chr($source_data_array['feedbackLL']);
+ $framedata .= chr($source_data_array['feedbackLR']);
+ $framedata .= chr($source_data_array['feedbackRR']);
+ $framedata .= chr($source_data_array['feedbackRL']);
+ $framedata .= chr($source_data_array['premixLR']);
+ $framedata .= chr($source_data_array['premixRL']);
+ }
+ break;
+
+ case 'APIC':
+ // 4.14 APIC Attached picture
+ // Text encoding $xx
+ // MIME type <text string> $00
+ // Picture type $xx
+ // Description <text string according to encoding> $00 (00)
+ // Picture data <binary data>
+ $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid);
+ if (!$this->ID3v2IsValidTextEncoding($source_data_array['encodingid'])) {
+ $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].') for ID3v2.'.$this->majorversion;
+ } elseif (!$this->ID3v2IsValidAPICpicturetype($source_data_array['picturetypeid'])) {
+ $this->errors[] = 'Invalid Picture Type byte in '.$frame_name.' ('.$source_data_array['picturetypeid'].') for ID3v2.'.$this->majorversion;
+ } elseif (($this->majorversion >= 3) && (!$this->ID3v2IsValidAPICimageformat($source_data_array['mime']))) {
+ $this->errors[] = 'Invalid MIME Type in '.$frame_name.' ('.$source_data_array['mime'].') for ID3v2.'.$this->majorversion;
+ } elseif (($source_data_array['mime'] == '-->') && (!$this->IsValidURL($source_data_array['data'], false, false))) {
+ //$this->errors[] = 'Invalid URL in '.$frame_name.' ('.$source_data_array['data'].')';
+ // probably should be an error, need to rewrite IsValidURL() to handle other encodings
+ $this->warnings[] = 'Invalid URL in '.$frame_name.' ('.$source_data_array['data'].')';
+ } else {
+ $framedata .= chr($source_data_array['encodingid']);
+ $framedata .= str_replace("\x00", '', $source_data_array['mime'])."\x00";
+ $framedata .= chr($source_data_array['picturetypeid']);
+ $framedata .= @$source_data_array['description'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']);
+ $framedata .= $source_data_array['data'];
+ }
+ break;
+
+ case 'GEOB':
+ // 4.15 GEOB General encapsulated object
+ // Text encoding $xx
+ // MIME type <text string> $00
+ // Filename <text string according to encoding> $00 (00)
+ // Content description <text string according to encoding> $00 (00)
+ // Encapsulated object <binary data>
+ $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid);
+ if (!$this->ID3v2IsValidTextEncoding($source_data_array['encodingid'])) {
+ $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].') for ID3v2.'.$this->majorversion;
+ } elseif (!$this->IsValidMIMEstring($source_data_array['mime'])) {
+ $this->errors[] = 'Invalid MIME Type in '.$frame_name.' ('.$source_data_array['mime'].')';
+ } elseif (!$source_data_array['description']) {
+ $this->errors[] = 'Missing Description in '.$frame_name;
+ } else {
+ $framedata .= chr($source_data_array['encodingid']);
+ $framedata .= str_replace("\x00", '', $source_data_array['mime'])."\x00";
+ $framedata .= $source_data_array['filename'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']);
+ $framedata .= $source_data_array['description'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']);
+ $framedata .= $source_data_array['data'];
+ }
+ break;
+
+ case 'PCNT':
+ // 4.16 PCNT Play counter
+ // When the counter reaches all one's, one byte is inserted in
+ // front of the counter thus making the counter eight bits bigger
+ // Counter $xx xx xx xx (xx ...)
+ $framedata .= getid3_lib::BigEndian2String($source_data_array['data'], 4, false);
+ break;
+
+ case 'POPM':
+ // 4.17 POPM Popularimeter
+ // When the counter reaches all one's, one byte is inserted in
+ // front of the counter thus making the counter eight bits bigger
+ // Email to user <text string> $00
+ // Rating $xx
+ // Counter $xx xx xx xx (xx ...)
+ if (!$this->IsWithinBitRange($source_data_array['rating'], 8, false)) {
+ $this->errors[] = 'Invalid Rating byte in '.$frame_name.' ('.$source_data_array['rating'].') (range = 0 to 255)';
+ } elseif (!IsValidEmail($source_data_array['email'])) {
+ $this->errors[] = 'Invalid Email in '.$frame_name.' ('.$source_data_array['email'].')';
+ } else {
+ $framedata .= str_replace("\x00", '', $source_data_array['email'])."\x00";
+ $framedata .= chr($source_data_array['rating']);
+ $framedata .= getid3_lib::BigEndian2String($source_data_array['data'], 4, false);
+ }
+ break;
+
+ case 'RBUF':
+ // 4.18 RBUF Recommended buffer size
+ // Buffer size $xx xx xx
+ // Embedded info flag %0000000x
+ // Offset to next tag $xx xx xx xx
+ if (!$this->IsWithinBitRange($source_data_array['buffersize'], 24, false)) {
+ $this->errors[] = 'Invalid Buffer Size in '.$frame_name;
+ } elseif (!$this->IsWithinBitRange($source_data_array['nexttagoffset'], 32, false)) {
+ $this->errors[] = 'Invalid Offset To Next Tag in '.$frame_name;
+ } else {
+ $framedata .= getid3_lib::BigEndian2String($source_data_array['buffersize'], 3, false);
+ $flag .= '0000000';
+ $flag .= $source_data_array['flags']['embededinfo'] ? '1' : '0';
+ $framedata .= chr(bindec($flag));
+ $framedata .= getid3_lib::BigEndian2String($source_data_array['nexttagoffset'], 4, false);
+ }
+ break;
+
+ case 'AENC':
+ // 4.19 AENC Audio encryption
+ // Owner identifier <text string> $00
+ // Preview start $xx xx
+ // Preview length $xx xx
+ // Encryption info <binary data>
+ if (!$this->IsWithinBitRange($source_data_array['previewstart'], 16, false)) {
+ $this->errors[] = 'Invalid Preview Start in '.$frame_name.' ('.$source_data_array['previewstart'].')';
+ } elseif (!$this->IsWithinBitRange($source_data_array['previewlength'], 16, false)) {
+ $this->errors[] = 'Invalid Preview Length in '.$frame_name.' ('.$source_data_array['previewlength'].')';
+ } else {
+ $framedata .= str_replace("\x00", '', $source_data_array['ownerid'])."\x00";
+ $framedata .= getid3_lib::BigEndian2String($source_data_array['previewstart'], 2, false);
+ $framedata .= getid3_lib::BigEndian2String($source_data_array['previewlength'], 2, false);
+ $framedata .= $source_data_array['encryptioninfo'];
+ }
+ break;
+
+ case 'LINK':
+ // 4.20 LINK Linked information
+ // Frame identifier $xx xx xx xx
+ // URL <text string> $00
+ // ID and additional data <text string(s)>
+ if (!getid3_id3v2::IsValidID3v2FrameName($source_data_array['frameid'], $this->majorversion)) {
+ $this->errors[] = 'Invalid Frame Identifier in '.$frame_name.' ('.$source_data_array['frameid'].')';
+ } elseif (!$this->IsValidURL($source_data_array['data'], true, false)) {
+ //$this->errors[] = 'Invalid URL in '.$frame_name.' ('.$source_data_array['data'].')';
+ // probably should be an error, need to rewrite IsValidURL() to handle other encodings
+ $this->warnings[] = 'Invalid URL in '.$frame_name.' ('.$source_data_array['data'].')';
+ } elseif ((($source_data_array['frameid'] == 'AENC') || ($source_data_array['frameid'] == 'APIC') || ($source_data_array['frameid'] == 'GEOB') || ($source_data_array['frameid'] == 'TXXX')) && ($source_data_array['additionaldata'] == '')) {
+ $this->errors[] = 'Content Descriptor must be specified as additional data for Frame Identifier of '.$source_data_array['frameid'].' in '.$frame_name;
+ } elseif (($source_data_array['frameid'] == 'USER') && (getid3_id3v2::LanguageLookup($source_data_array['additionaldata'], true) == '')) {
+ $this->errors[] = 'Language must be specified as additional data for Frame Identifier of '.$source_data_array['frameid'].' in '.$frame_name;
+ } elseif (($source_data_array['frameid'] == 'PRIV') && ($source_data_array['additionaldata'] == '')) {
+ $this->errors[] = 'Owner Identifier must be specified as additional data for Frame Identifier of '.$source_data_array['frameid'].' in '.$frame_name;
+ } elseif ((($source_data_array['frameid'] == 'COMM') || ($source_data_array['frameid'] == 'SYLT') || ($source_data_array['frameid'] == 'USLT')) && ((getid3_id3v2::LanguageLookup(substr($source_data_array['additionaldata'], 0, 3), true) == '') || (substr($source_data_array['additionaldata'], 3) == ''))) {
+ $this->errors[] = 'Language followed by Content Descriptor must be specified as additional data for Frame Identifier of '.$source_data_array['frameid'].' in '.$frame_name;
+ } else {
+ $framedata .= $source_data_array['frameid'];
+ $framedata .= str_replace("\x00", '', $source_data_array['data'])."\x00";
+ switch ($source_data_array['frameid']) {
+ case 'COMM':
+ case 'SYLT':
+ case 'USLT':
+ case 'PRIV':
+ case 'USER':
+ case 'AENC':
+ case 'APIC':
+ case 'GEOB':
+ case 'TXXX':
+ $framedata .= $source_data_array['additionaldata'];
+ break;
+ case 'ASPI':
+ case 'ETCO':
+ case 'EQU2':
+ case 'MCID':
+ case 'MLLT':
+ case 'OWNE':
+ case 'RVA2':
+ case 'RVRB':
+ case 'SYTC':
+ case 'IPLS':
+ case 'RVAD':
+ case 'EQUA':
+ // no additional data required
+ break;
+ case 'RBUF':
+ if ($this->majorversion == 3) {
+ // no additional data required
+ } else {
+ $this->errors[] = $source_data_array['frameid'].' is not a valid Frame Identifier in '.$frame_name.' (in ID3v2.'.$this->majorversion.')';
+ }
+
+ default:
+ if ((substr($source_data_array['frameid'], 0, 1) == 'T') || (substr($source_data_array['frameid'], 0, 1) == 'W')) {
+ // no additional data required
+ } else {
+ $this->errors[] = $source_data_array['frameid'].' is not a valid Frame Identifier in '.$frame_name.' (in ID3v2.'.$this->majorversion.')';
+ }
+ break;
+ }
+ }
+ break;
+
+ case 'POSS':
+ // 4.21 POSS Position synchronisation frame (ID3v2.3+ only)
+ // Time stamp format $xx
+ // Position $xx (xx ...)
+ if (($source_data_array['timestampformat'] < 1) || ($source_data_array['timestampformat'] > 2)) {
+ $this->errors[] = 'Invalid Time Stamp Format in '.$frame_name.' ('.$source_data_array['timestampformat'].') (valid = 1 or 2)';
+ } elseif (!$this->IsWithinBitRange($source_data_array['position'], 32, false)) {
+ $this->errors[] = 'Invalid Position in '.$frame_name.' ('.$source_data_array['position'].') (range = 0 to 4294967295)';
+ } else {
+ $framedata .= chr($source_data_array['timestampformat']);
+ $framedata .= getid3_lib::BigEndian2String($source_data_array['position'], 4, false);
+ }
+ break;
+
+ case 'USER':
+ // 4.22 USER Terms of use (ID3v2.3+ only)
+ // Text encoding $xx
+ // Language $xx xx xx
+ // The actual text <text string according to encoding>
+ $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid);
+ if (!$this->ID3v2IsValidTextEncoding($source_data_array['encodingid'])) {
+ $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].')';
+ } elseif (getid3_id3v2::LanguageLookup($source_data_array['language'], true) == '') {
+ $this->errors[] = 'Invalid Language in '.$frame_name.' ('.$source_data_array['language'].')';
+ } else {
+ $framedata .= chr($source_data_array['encodingid']);
+ $framedata .= strtolower($source_data_array['language']);
+ $framedata .= $source_data_array['data'];
+ }
+ break;
+
+ case 'OWNE':
+ // 4.23 OWNE Ownership frame (ID3v2.3+ only)
+ // Text encoding $xx
+ // Price paid <text string> $00
+ // Date of purch. <text string>
+ // Seller <text string according to encoding>
+ $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid);
+ if (!$this->ID3v2IsValidTextEncoding($source_data_array['encodingid'])) {
+ $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].')';
+ } elseif (!$this->IsANumber($source_data_array['pricepaid']['value'], false)) {
+ $this->errors[] = 'Invalid Price Paid in '.$frame_name.' ('.$source_data_array['pricepaid']['value'].')';
+ } elseif (!$this->IsValidDateStampString($source_data_array['purchasedate'])) {
+ $this->errors[] = 'Invalid Date Of Purchase in '.$frame_name.' ('.$source_data_array['purchasedate'].') (format = YYYYMMDD)';
+ } else {
+ $framedata .= chr($source_data_array['encodingid']);
+ $framedata .= str_replace("\x00", '', $source_data_array['pricepaid']['value'])."\x00";
+ $framedata .= $source_data_array['purchasedate'];
+ $framedata .= $source_data_array['seller'];
+ }
+ break;
+
+ case 'COMR':
+ // 4.24 COMR Commercial frame (ID3v2.3+ only)
+ // Text encoding $xx
+ // Price string <text string> $00
+ // Valid until <text string>
+ // Contact URL <text string> $00
+ // Received as $xx
+ // Name of seller <text string according to encoding> $00 (00)
+ // Description <text string according to encoding> $00 (00)
+ // Picture MIME type <string> $00
+ // Seller logo <binary data>
+ $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid);
+ if (!$this->ID3v2IsValidTextEncoding($source_data_array['encodingid'])) {
+ $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].')';
+ } elseif (!$this->IsValidDateStampString($source_data_array['pricevaliduntil'])) {
+ $this->errors[] = 'Invalid Valid Until date in '.$frame_name.' ('.$source_data_array['pricevaliduntil'].') (format = YYYYMMDD)';
+ } elseif (!$this->IsValidURL($source_data_array['contacturl'], false, true)) {
+ $this->errors[] = 'Invalid Contact URL in '.$frame_name.' ('.$source_data_array['contacturl'].') (allowed schemes: http, https, ftp, mailto)';
+ } elseif (!$this->ID3v2IsValidCOMRreceivedAs($source_data_array['receivedasid'])) {
+ $this->errors[] = 'Invalid Received As byte in '.$frame_name.' ('.$source_data_array['contacturl'].') (range = 0 to 8)';
+ } elseif (!$this->IsValidMIMEstring($source_data_array['mime'])) {
+ $this->errors[] = 'Invalid MIME Type in '.$frame_name.' ('.$source_data_array['mime'].')';
+ } else {
+ $framedata .= chr($source_data_array['encodingid']);
+ unset($pricestring);
+ foreach ($source_data_array['price'] as $key => $val) {
+ if ($this->ID3v2IsValidPriceString($key.$val['value'])) {
+ $pricestrings[] = $key.$val['value'];
+ } else {
+ $this->errors[] = 'Invalid Price String in '.$frame_name.' ('.$key.$val['value'].')';
+ }
+ }
+ $framedata .= implode('/', $pricestrings);
+ $framedata .= $source_data_array['pricevaliduntil'];
+ $framedata .= str_replace("\x00", '', $source_data_array['contacturl'])."\x00";
+ $framedata .= chr($source_data_array['receivedasid']);
+ $framedata .= $source_data_array['sellername'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']);
+ $framedata .= $source_data_array['description'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']);
+ $framedata .= $source_data_array['mime']."\x00";
+ $framedata .= $source_data_array['logo'];
+ }
+ break;
+
+ case 'ENCR':
+ // 4.25 ENCR Encryption method registration (ID3v2.3+ only)
+ // Owner identifier <text string> $00
+ // Method symbol $xx
+ // Encryption data <binary data>
+ if (!$this->IsWithinBitRange($source_data_array['methodsymbol'], 8, false)) {
+ $this->errors[] = 'Invalid Group Symbol in '.$frame_name.' ('.$source_data_array['methodsymbol'].') (range = 0 to 255)';
+ } else {
+ $framedata .= str_replace("\x00", '', $source_data_array['ownerid'])."\x00";
+ $framedata .= ord($source_data_array['methodsymbol']);
+ $framedata .= $source_data_array['data'];
+ }
+ break;
+
+ case 'GRID':
+ // 4.26 GRID Group identification registration (ID3v2.3+ only)
+ // Owner identifier <text string> $00
+ // Group symbol $xx
+ // Group dependent data <binary data>
+ if (!$this->IsWithinBitRange($source_data_array['groupsymbol'], 8, false)) {
+ $this->errors[] = 'Invalid Group Symbol in '.$frame_name.' ('.$source_data_array['groupsymbol'].') (range = 0 to 255)';
+ } else {
+ $framedata .= str_replace("\x00", '', $source_data_array['ownerid'])."\x00";
+ $framedata .= ord($source_data_array['groupsymbol']);
+ $framedata .= $source_data_array['data'];
+ }
+ break;
+
+ case 'PRIV':
+ // 4.27 PRIV Private frame (ID3v2.3+ only)
+ // Owner identifier <text string> $00
+ // The private data <binary data>
+ $framedata .= str_replace("\x00", '', $source_data_array['ownerid'])."\x00";
+ $framedata .= $source_data_array['data'];
+ break;
+
+ case 'SIGN':
+ // 4.28 SIGN Signature frame (ID3v2.4+ only)
+ // Group symbol $xx
+ // Signature <binary data>
+ if (!$this->IsWithinBitRange($source_data_array['groupsymbol'], 8, false)) {
+ $this->errors[] = 'Invalid Group Symbol in '.$frame_name.' ('.$source_data_array['groupsymbol'].') (range = 0 to 255)';
+ } else {
+ $framedata .= ord($source_data_array['groupsymbol']);
+ $framedata .= $source_data_array['data'];
+ }
+ break;
+
+ case 'SEEK':
+ // 4.29 SEEK Seek frame (ID3v2.4+ only)
+ // Minimum offset to next tag $xx xx xx xx
+ if (!$this->IsWithinBitRange($source_data_array['data'], 32, false)) {
+ $this->errors[] = 'Invalid Minimum Offset in '.$frame_name.' ('.$source_data_array['data'].') (range = 0 to 4294967295)';
+ } else {
+ $framedata .= getid3_lib::BigEndian2String($source_data_array['data'], 4, false);
+ }
+ break;
+
+ case 'ASPI':
+ // 4.30 ASPI Audio seek point index (ID3v2.4+ only)
+ // Indexed data start (S) $xx xx xx xx
+ // Indexed data length (L) $xx xx xx xx
+ // Number of index points (N) $xx xx
+ // Bits per index point (b) $xx
+ // Then for every index point the following data is included:
+ // Fraction at index (Fi) $xx (xx)
+ if (!$this->IsWithinBitRange($source_data_array['datastart'], 32, false)) {
+ $this->errors[] = 'Invalid Indexed Data Start in '.$frame_name.' ('.$source_data_array['datastart'].') (range = 0 to 4294967295)';
+ } elseif (!$this->IsWithinBitRange($source_data_array['datalength'], 32, false)) {
+ $this->errors[] = 'Invalid Indexed Data Length in '.$frame_name.' ('.$source_data_array['datalength'].') (range = 0 to 4294967295)';
+ } elseif (!$this->IsWithinBitRange($source_data_array['indexpoints'], 16, false)) {
+ $this->errors[] = 'Invalid Number Of Index Points in '.$frame_name.' ('.$source_data_array['indexpoints'].') (range = 0 to 65535)';
+ } elseif (!$this->IsWithinBitRange($source_data_array['bitsperpoint'], 8, false)) {
+ $this->errors[] = 'Invalid Bits Per Index Point in '.$frame_name.' ('.$source_data_array['bitsperpoint'].') (range = 0 to 255)';
+ } elseif ($source_data_array['indexpoints'] != count($source_data_array['indexes'])) {
+ $this->errors[] = 'Number Of Index Points does not match actual supplied data in '.$frame_name;
+ } else {
+ $framedata .= getid3_lib::BigEndian2String($source_data_array['datastart'], 4, false);
+ $framedata .= getid3_lib::BigEndian2String($source_data_array['datalength'], 4, false);
+ $framedata .= getid3_lib::BigEndian2String($source_data_array['indexpoints'], 2, false);
+ $framedata .= getid3_lib::BigEndian2String($source_data_array['bitsperpoint'], 1, false);
+ foreach ($source_data_array['indexes'] as $key => $val) {
+ $framedata .= getid3_lib::BigEndian2String($val, ceil($source_data_array['bitsperpoint'] / 8), false);
+ }
+ }
+ break;
+
+ case 'RGAD':
+ // RGAD Replay Gain Adjustment
+ // http://privatewww.essex.ac.uk/~djmrob/replaygain/
+ // Peak Amplitude $xx $xx $xx $xx
+ // Radio Replay Gain Adjustment %aaabbbcd %dddddddd
+ // Audiophile Replay Gain Adjustment %aaabbbcd %dddddddd
+ // a - name code
+ // b - originator code
+ // c - sign bit
+ // d - replay gain adjustment
+
+ if (($source_data_array['track_adjustment'] > 51) || ($source_data_array['track_adjustment'] < -51)) {
+ $this->errors[] = 'Invalid Track Adjustment in '.$frame_name.' ('.$source_data_array['track_adjustment'].') (range = -51.0 to +51.0)';
+ } elseif (($source_data_array['album_adjustment'] > 51) || ($source_data_array['album_adjustment'] < -51)) {
+ $this->errors[] = 'Invalid Album Adjustment in '.$frame_name.' ('.$source_data_array['album_adjustment'].') (range = -51.0 to +51.0)';
+ } elseif (!$this->ID3v2IsValidRGADname($source_data_array['raw']['track_name'])) {
+ $this->errors[] = 'Invalid Track Name Code in '.$frame_name.' ('.$source_data_array['raw']['track_name'].') (range = 0 to 2)';
+ } elseif (!$this->ID3v2IsValidRGADname($source_data_array['raw']['album_name'])) {
+ $this->errors[] = 'Invalid Album Name Code in '.$frame_name.' ('.$source_data_array['raw']['album_name'].') (range = 0 to 2)';
+ } elseif (!$this->ID3v2IsValidRGADoriginator($source_data_array['raw']['track_originator'])) {
+ $this->errors[] = 'Invalid Track Originator Code in '.$frame_name.' ('.$source_data_array['raw']['track_originator'].') (range = 0 to 3)';
+ } elseif (!$this->ID3v2IsValidRGADoriginator($source_data_array['raw']['album_originator'])) {
+ $this->errors[] = 'Invalid Album Originator Code in '.$frame_name.' ('.$source_data_array['raw']['album_originator'].') (range = 0 to 3)';
+ } else {
+ $framedata .= getid3_lib::Float2String($source_data_array['peakamplitude'], 32);
+ $framedata .= getid3_lib::RGADgainString($source_data_array['raw']['track_name'], $source_data_array['raw']['track_originator'], $source_data_array['track_adjustment']);
+ $framedata .= getid3_lib::RGADgainString($source_data_array['raw']['album_name'], $source_data_array['raw']['album_originator'], $source_data_array['album_adjustment']);
+ }
+ break;
+
+ default:
+ if ($frame_name{0} == 'T') {
+ // 4.2. T??? Text information frames
+ // Text encoding $xx
+ // Information <text string(s) according to encoding>
+ $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid);
+ if (!$this->ID3v2IsValidTextEncoding($source_data_array['encodingid'])) {
+ $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].') for ID3v2.'.$this->majorversion;
+ } else {
+ $framedata .= chr($source_data_array['encodingid']);
+ $framedata .= $source_data_array['data'];
+ }
+ } elseif ($frame_name{0} == 'W') {
+ // 4.3. W??? URL link frames
+ // URL <text string>
+ if (!$this->IsValidURL($source_data_array['data'], false, false)) {
+ //$this->errors[] = 'Invalid URL in '.$frame_name.' ('.$source_data_array['data'].')';
+ // probably should be an error, need to rewrite IsValidURL() to handle other encodings
+ $this->warnings[] = 'Invalid URL in '.$frame_name.' ('.$source_data_array['data'].')';
+ } else {
+ $framedata .= $source_data_array['data'];
+ }
+ } else {
+ $this->errors[] = $frame_name.' not yet supported in $this->GenerateID3v2FrameData()';
+ }
+ break;
+ }
+ }
+ if (!empty($this->errors)) {
+ return false;
+ }
+ return $framedata;
+ }
+
+ function ID3v2FrameIsAllowed($frame_name, $source_data_array) {
+ static $PreviousFrames = array();
+
+ if ($frame_name === null) {
+ // if the writing functions are called multiple times, the static array needs to be
+ // cleared - this can be done by calling $this->ID3v2FrameIsAllowed(null, '')
+ $PreviousFrames = array();
+ return true;
+ }
+
+ if ($this->majorversion == 4) {
+ switch ($frame_name) {
+ case 'UFID':
+ case 'AENC':
+ case 'ENCR':
+ case 'GRID':
+ if (!isset($source_data_array['ownerid'])) {
+ $this->errors[] = '[ownerid] not specified for '.$frame_name;
+ } elseif (in_array($frame_name.$source_data_array['ownerid'], $PreviousFrames)) {
+ $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same OwnerID ('.$source_data_array['ownerid'].')';
+ } else {
+ $PreviousFrames[] = $frame_name.$source_data_array['ownerid'];
+ }
+ break;
+
+ case 'TXXX':
+ case 'WXXX':
+ case 'RVA2':
+ case 'EQU2':
+ case 'APIC':
+ case 'GEOB':
+ if (!isset($source_data_array['description'])) {
+ $this->errors[] = '[description] not specified for '.$frame_name;
+ } elseif (in_array($frame_name.$source_data_array['description'], $PreviousFrames)) {
+ $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same Description ('.$source_data_array['description'].')';
+ } else {
+ $PreviousFrames[] = $frame_name.$source_data_array['description'];
+ }
+ break;
+
+ case 'USER':
+ if (!isset($source_data_array['language'])) {
+ $this->errors[] = '[language] not specified for '.$frame_name;
+ } elseif (in_array($frame_name.$source_data_array['language'], $PreviousFrames)) {
+ $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same Language ('.$source_data_array['language'].')';
+ } else {
+ $PreviousFrames[] = $frame_name.$source_data_array['language'];
+ }
+ break;
+
+ case 'USLT':
+ case 'SYLT':
+ case 'COMM':
+ if (!isset($source_data_array['language'])) {
+ $this->errors[] = '[language] not specified for '.$frame_name;
+ } elseif (!isset($source_data_array['description'])) {
+ $this->errors[] = '[description] not specified for '.$frame_name;
+ } elseif (in_array($frame_name.$source_data_array['language'].$source_data_array['description'], $PreviousFrames)) {
+ $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same Language + Description ('.$source_data_array['language'].' + '.$source_data_array['description'].')';
+ } else {
+ $PreviousFrames[] = $frame_name.$source_data_array['language'].$source_data_array['description'];
+ }
+ break;
+
+ case 'POPM':
+ if (!isset($source_data_array['email'])) {
+ $this->errors[] = '[email] not specified for '.$frame_name;
+ } elseif (in_array($frame_name.$source_data_array['email'], $PreviousFrames)) {
+ $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same Email ('.$source_data_array['email'].')';
+ } else {
+ $PreviousFrames[] = $frame_name.$source_data_array['email'];
+ }
+ break;
+
+ case 'IPLS':
+ case 'MCDI':
+ case 'ETCO':
+ case 'MLLT':
+ case 'SYTC':
+ case 'RVRB':
+ case 'PCNT':
+ case 'RBUF':
+ case 'POSS':
+ case 'OWNE':
+ case 'SEEK':
+ case 'ASPI':
+ case 'RGAD':
+ if (in_array($frame_name, $PreviousFrames)) {
+ $this->errors[] = 'Only one '.$frame_name.' tag allowed';
+ } else {
+ $PreviousFrames[] = $frame_name;
+ }
+ break;
+
+ case 'LINK':
+ // this isn't implemented quite right (yet) - it should check the target frame data for compliance
+ // but right now it just allows one linked frame of each type, to be safe.
+ if (!isset($source_data_array['frameid'])) {
+ $this->errors[] = '[frameid] not specified for '.$frame_name;
+ } elseif (in_array($frame_name.$source_data_array['frameid'], $PreviousFrames)) {
+ $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same FrameID ('.$source_data_array['frameid'].')';
+ } elseif (in_array($source_data_array['frameid'], $PreviousFrames)) {
+ // no links to singleton tags
+ $this->errors[] = 'Cannot specify a '.$frame_name.' tag to a singleton tag that already exists ('.$source_data_array['frameid'].')';
+ } else {
+ $PreviousFrames[] = $frame_name.$source_data_array['frameid']; // only one linked tag of this type
+ $PreviousFrames[] = $source_data_array['frameid']; // no non-linked singleton tags of this type
+ }
+ break;
+
+ case 'COMR':
+ // There may be more than one 'commercial frame' in a tag, but no two may be identical
+ // Checking isn't implemented at all (yet) - just assumes that it's OK.
+ break;
+
+ case 'PRIV':
+ case 'SIGN':
+ if (!isset($source_data_array['ownerid'])) {
+ $this->errors[] = '[ownerid] not specified for '.$frame_name;
+ } elseif (!isset($source_data_array['data'])) {
+ $this->errors[] = '[data] not specified for '.$frame_name;
+ } elseif (in_array($frame_name.$source_data_array['ownerid'].$source_data_array['data'], $PreviousFrames)) {
+ $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same OwnerID + Data ('.$source_data_array['ownerid'].' + '.$source_data_array['data'].')';
+ } else {
+ $PreviousFrames[] = $frame_name.$source_data_array['ownerid'].$source_data_array['data'];
+ }
+ break;
+
+ default:
+ if (($frame_name{0} != 'T') && ($frame_name{0} != 'W')) {
+ $this->errors[] = 'Frame not allowed in ID3v2.'.$this->majorversion.': '.$frame_name;
+ }
+ break;
+ }
+
+ } elseif ($this->majorversion == 3) {
+
+ switch ($frame_name) {
+ case 'UFID':
+ case 'AENC':
+ case 'ENCR':
+ case 'GRID':
+ if (!isset($source_data_array['ownerid'])) {
+ $this->errors[] = '[ownerid] not specified for '.$frame_name;
+ } elseif (in_array($frame_name.$source_data_array['ownerid'], $PreviousFrames)) {
+ $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same OwnerID ('.$source_data_array['ownerid'].')';
+ } else {
+ $PreviousFrames[] = $frame_name.$source_data_array['ownerid'];
+ }
+ break;
+
+ case 'TXXX':
+ case 'WXXX':
+ case 'APIC':
+ case 'GEOB':
+ if (!isset($source_data_array['description'])) {
+ $this->errors[] = '[description] not specified for '.$frame_name;
+ } elseif (in_array($frame_name.$source_data_array['description'], $PreviousFrames)) {
+ $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same Description ('.$source_data_array['description'].')';
+ } else {
+ $PreviousFrames[] = $frame_name.$source_data_array['description'];
+ }
+ break;
+
+ case 'USER':
+ if (!isset($source_data_array['language'])) {
+ $this->errors[] = '[language] not specified for '.$frame_name;
+ } elseif (in_array($frame_name.$source_data_array['language'], $PreviousFrames)) {
+ $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same Language ('.$source_data_array['language'].')';
+ } else {
+ $PreviousFrames[] = $frame_name.$source_data_array['language'];
+ }
+ break;
+
+ case 'USLT':
+ case 'SYLT':
+ case 'COMM':
+ if (!isset($source_data_array['language'])) {
+ $this->errors[] = '[language] not specified for '.$frame_name;
+ } elseif (!isset($source_data_array['description'])) {
+ $this->errors[] = '[description] not specified for '.$frame_name;
+ } elseif (in_array($frame_name.$source_data_array['language'].$source_data_array['description'], $PreviousFrames)) {
+ $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same Language + Description ('.$source_data_array['language'].' + '.$source_data_array['description'].')';
+ } else {
+ $PreviousFrames[] = $frame_name.$source_data_array['language'].$source_data_array['description'];
+ }
+ break;
+
+ case 'POPM':
+ if (!isset($source_data_array['email'])) {
+ $this->errors[] = '[email] not specified for '.$frame_name;
+ } elseif (in_array($frame_name.$source_data_array['email'], $PreviousFrames)) {
+ $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same Email ('.$source_data_array['email'].')';
+ } else {
+ $PreviousFrames[] = $frame_name.$source_data_array['email'];
+ }
+ break;
+
+ case 'IPLS':
+ case 'MCDI':
+ case 'ETCO':
+ case 'MLLT':
+ case 'SYTC':
+ case 'RVAD':
+ case 'EQUA':
+ case 'RVRB':
+ case 'PCNT':
+ case 'RBUF':
+ case 'POSS':
+ case 'OWNE':
+ case 'RGAD':
+ if (in_array($frame_name, $PreviousFrames)) {
+ $this->errors[] = 'Only one '.$frame_name.' tag allowed';
+ } else {
+ $PreviousFrames[] = $frame_name;
+ }
+ break;
+
+ case 'LINK':
+ // this isn't implemented quite right (yet) - it should check the target frame data for compliance
+ // but right now it just allows one linked frame of each type, to be safe.
+ if (!isset($source_data_array['frameid'])) {
+ $this->errors[] = '[frameid] not specified for '.$frame_name;
+ } elseif (in_array($frame_name.$source_data_array['frameid'], $PreviousFrames)) {
+ $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same FrameID ('.$source_data_array['frameid'].')';
+ } elseif (in_array($source_data_array['frameid'], $PreviousFrames)) {
+ // no links to singleton tags
+ $this->errors[] = 'Cannot specify a '.$frame_name.' tag to a singleton tag that already exists ('.$source_data_array['frameid'].')';
+ } else {
+ $PreviousFrames[] = $frame_name.$source_data_array['frameid']; // only one linked tag of this type
+ $PreviousFrames[] = $source_data_array['frameid']; // no non-linked singleton tags of this type
+ }
+ break;
+
+ case 'COMR':
+ // There may be more than one 'commercial frame' in a tag, but no two may be identical
+ // Checking isn't implemented at all (yet) - just assumes that it's OK.
+ break;
+
+ case 'PRIV':
+ if (!isset($source_data_array['ownerid'])) {
+ $this->errors[] = '[ownerid] not specified for '.$frame_name;
+ } elseif (!isset($source_data_array['data'])) {
+ $this->errors[] = '[data] not specified for '.$frame_name;
+ } elseif (in_array($frame_name.$source_data_array['ownerid'].$source_data_array['data'], $PreviousFrames)) {
+ $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same OwnerID + Data ('.$source_data_array['ownerid'].' + '.$source_data_array['data'].')';
+ } else {
+ $PreviousFrames[] = $frame_name.$source_data_array['ownerid'].$source_data_array['data'];
+ }
+ break;
+
+ default:
+ if (($frame_name{0} != 'T') && ($frame_name{0} != 'W')) {
+ $this->errors[] = 'Frame not allowed in ID3v2.'.$this->majorversion.': '.$frame_name;
+ }
+ break;
+ }
+
+ } elseif ($this->majorversion == 2) {
+
+ switch ($frame_name) {
+ case 'UFI':
+ case 'CRM':
+ case 'CRA':
+ if (!isset($source_data_array['ownerid'])) {
+ $this->errors[] = '[ownerid] not specified for '.$frame_name;
+ } elseif (in_array($frame_name.$source_data_array['ownerid'], $PreviousFrames)) {
+ $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same OwnerID ('.$source_data_array['ownerid'].')';
+ } else {
+ $PreviousFrames[] = $frame_name.$source_data_array['ownerid'];
+ }
+ break;
+
+ case 'TXX':
+ case 'WXX':
+ case 'PIC':
+ case 'GEO':
+ if (!isset($source_data_array['description'])) {
+ $this->errors[] = '[description] not specified for '.$frame_name;
+ } elseif (in_array($frame_name.$source_data_array['description'], $PreviousFrames)) {
+ $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same Description ('.$source_data_array['description'].')';
+ } else {
+ $PreviousFrames[] = $frame_name.$source_data_array['description'];
+ }
+ break;
+
+ case 'ULT':
+ case 'SLT':
+ case 'COM':
+ if (!isset($source_data_array['language'])) {
+ $this->errors[] = '[language] not specified for '.$frame_name;
+ } elseif (!isset($source_data_array['description'])) {
+ $this->errors[] = '[description] not specified for '.$frame_name;
+ } elseif (in_array($frame_name.$source_data_array['language'].$source_data_array['description'], $PreviousFrames)) {
+ $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same Language + Description ('.$source_data_array['language'].' + '.$source_data_array['description'].')';
+ } else {
+ $PreviousFrames[] = $frame_name.$source_data_array['language'].$source_data_array['description'];
+ }
+ break;
+
+ case 'POP':
+ if (!isset($source_data_array['email'])) {
+ $this->errors[] = '[email] not specified for '.$frame_name;
+ } elseif (in_array($frame_name.$source_data_array['email'], $PreviousFrames)) {
+ $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same Email ('.$source_data_array['email'].')';
+ } else {
+ $PreviousFrames[] = $frame_name.$source_data_array['email'];
+ }
+ break;
+
+ case 'IPL':
+ case 'MCI':
+ case 'ETC':
+ case 'MLL':
+ case 'STC':
+ case 'RVA':
+ case 'EQU':
+ case 'REV':
+ case 'CNT':
+ case 'BUF':
+ if (in_array($frame_name, $PreviousFrames)) {
+ $this->errors[] = 'Only one '.$frame_name.' tag allowed';
+ } else {
+ $PreviousFrames[] = $frame_name;
+ }
+ break;
+
+ case 'LNK':
+ // this isn't implemented quite right (yet) - it should check the target frame data for compliance
+ // but right now it just allows one linked frame of each type, to be safe.
+ if (!isset($source_data_array['frameid'])) {
+ $this->errors[] = '[frameid] not specified for '.$frame_name;
+ } elseif (in_array($frame_name.$source_data_array['frameid'], $PreviousFrames)) {
+ $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same FrameID ('.$source_data_array['frameid'].')';
+ } elseif (in_array($source_data_array['frameid'], $PreviousFrames)) {
+ // no links to singleton tags
+ $this->errors[] = 'Cannot specify a '.$frame_name.' tag to a singleton tag that already exists ('.$source_data_array['frameid'].')';
+ } else {
+ $PreviousFrames[] = $frame_name.$source_data_array['frameid']; // only one linked tag of this type
+ $PreviousFrames[] = $source_data_array['frameid']; // no non-linked singleton tags of this type
+ }
+ break;
+
+ default:
+ if (($frame_name{0} != 'T') && ($frame_name{0} != 'W')) {
+ $this->errors[] = 'Frame not allowed in ID3v2.'.$this->majorversion.': '.$frame_name;
+ }
+ break;
+ }
+ }
+
+ if (!empty($this->errors)) {
+ return false;
+ }
+ return true;
+ }
+
+ 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("\x00", $this->paddedlength - strlen($tagstring) - getid3_id3v2::ID3v2HeaderLength($this->majorversion));
+ }
+ if ($this->id3v2_use_unsynchronisation && (substr($tagstring, strlen($tagstring) - 1, 1) == "\xFF")) {
+ // special unsynchronisation case:
+ // if last byte == $FF then appended a $00
+ $TagUnsynchronisation = true;
+ $tagstring .= "\x00";
+ }
+
+ $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;
+ }
+
+ function ID3v2IsValidPriceString($pricestring) {
+ if (getid3_id3v2::LanguageLookup(substr($pricestring, 0, 3), true) == '') {
+ return false;
+ } elseif (!$this->IsANumber(substr($pricestring, 3), true)) {
+ return false;
+ }
+ return true;
+ }
+
+ function ID3v2FrameFlagsLookupTagAlter($framename) {
+ // unfinished
+ switch ($framename) {
+ case 'RGAD':
+ $allow = true;
+ default:
+ $allow = false;
+ break;
+ }
+ return $allow;
+ }
+
+ function ID3v2FrameFlagsLookupFileAlter($framename) {
+ // unfinished
+ switch ($framename) {
+ case 'RGAD':
+ return false;
+ break;
+
+ default:
+ return false;
+ break;
+ }
+ }
+
+ function ID3v2IsValidETCOevent($eventid) {
+ if (($eventid < 0) || ($eventid > 0xFF)) {
+ // outside range of 1 byte
+ return false;
+ } elseif (($eventid >= 0xF0) && ($eventid <= 0xFC)) {
+ // reserved for future use
+ return false;
+ } elseif (($eventid >= 0x17) && ($eventid <= 0xDF)) {
+ // reserved for future use
+ return false;
+ } elseif (($eventid >= 0x0E) && ($eventid <= 0x16) && ($this->majorversion == 2)) {
+ // not defined in ID3v2.2
+ return false;
+ } elseif (($eventid >= 0x15) && ($eventid <= 0x16) && ($this->majorversion == 3)) {
+ // not defined in ID3v2.3
+ return false;
+ }
+ return true;
+ }
+
+ function ID3v2IsValidSYLTtype($contenttype) {
+ if (($contenttype >= 0) && ($contenttype <= 8) && ($this->majorversion == 4)) {
+ return true;
+ } elseif (($contenttype >= 0) && ($contenttype <= 6) && ($this->majorversion == 3)) {
+ return true;
+ }
+ return false;
+ }
+
+ function ID3v2IsValidRVA2channeltype($channeltype) {
+ if (($channeltype >= 0) && ($channeltype <= 8) && ($this->majorversion == 4)) {
+ return true;
+ }
+ return false;
+ }
+
+ function ID3v2IsValidAPICpicturetype($picturetype) {
+ if (($picturetype >= 0) && ($picturetype <= 0x14) && ($this->majorversion >= 2) && ($this->majorversion <= 4)) {
+ return true;
+ }
+ return false;
+ }
+
+ function ID3v2IsValidAPICimageformat($imageformat) {
+ if ($imageformat == '-->') {
+ return true;
+ } elseif ($this->majorversion == 2) {
+ if ((strlen($imageformat) == 3) && ($imageformat == strtoupper($imageformat))) {
+ return true;
+ }
+ } elseif (($this->majorversion == 3) || ($this->majorversion == 4)) {
+ if ($this->IsValidMIMEstring($imageformat)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ function ID3v2IsValidCOMRreceivedAs($receivedas) {
+ if (($this->majorversion >= 3) && ($receivedas >= 0) && ($receivedas <= 8)) {
+ return true;
+ }
+ return false;
+ }
+
+ function ID3v2IsValidRGADname($RGADname) {
+ if (($RGADname >= 0) && ($RGADname <= 2)) {
+ return true;
+ }
+ return false;
+ }
+
+ function ID3v2IsValidRGADoriginator($RGADoriginator) {
+ if (($RGADoriginator >= 0) && ($RGADoriginator <= 3)) {
+ return true;
+ }
+ return false;
+ }
+
+ function ID3v2IsValidTextEncoding($textencodingbyte) {
+ static $ID3v2IsValidTextEncoding_cache = array(
+ 2 => array(true, true),
+ 3 => array(true, true),
+ 4 => array(true, true, true, true));
+ return isset($ID3v2IsValidTextEncoding_cache[$this->majorversion][$textencodingbyte]);
+ }
+
+ function Unsynchronise($data) {
+ // Whenever a false synchronisation is found within the tag, one zeroed
+ // byte is inserted after the first false synchronisation byte. The
+ // format of a correct sync that should be altered by ID3 encoders is as
+ // follows:
+ // %11111111 111xxxxx
+ // And should be replaced with:
+ // %11111111 00000000 111xxxxx
+ // This has the side effect that all $FF 00 combinations have to be
+ // altered, so they won't be affected by the decoding process. Therefore
+ // all the $FF 00 combinations have to be replaced with the $FF 00 00
+ // combination during the unsynchronisation.
+
+ $data = str_replace("\xFF\x00", "\xFF\x00\x00", $data);
+ $unsyncheddata = '';
+ $datalength = strlen($data);
+ for ($i = 0; $i < $datalength; $i++) {
+ $thischar = $data{$i};
+ $unsyncheddata .= $thischar;
+ if ($thischar == "\xFF") {
+ $nextchar = ord($data{$i + 1});
+ if (($nextchar & 0xE0) == 0xE0) {
+ // previous byte = 11111111, this byte = 111?????
+ $unsyncheddata .= "\x00";
+ }
+ }
+ }
+ return $unsyncheddata;
+ }
+
+ function is_hash($var) {
+ // written by dev-nullØchristophe*vg
+ // taken from http://www.php.net/manual/en/function.array-merge-recursive.php
+ if (is_array($var)) {
+ $keys = array_keys($var);
+ $all_num = true;
+ for ($i = 0; $i < count($keys); $i++) {
+ if (is_string($keys[$i])) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ function array_join_merge($arr1, $arr2) {
+ // written by dev-nullØchristophe*vg
+ // taken from http://www.php.net/manual/en/function.array-merge-recursive.php
+ if (is_array($arr1) && is_array($arr2)) {
+ // the same -> merge
+ $new_array = array();
+
+ if ($this->is_hash($arr1) && $this->is_hash($arr2)) {
+ // hashes -> merge based on keys
+ $keys = array_merge(array_keys($arr1), array_keys($arr2));
+ foreach ($keys as $key) {
+ $new_array[$key] = $this->array_join_merge(@$arr1[$key], @$arr2[$key]);
+ }
+ } else {
+ // two real arrays -> merge
+ $new_array = array_reverse(array_unique(array_reverse(array_merge($arr1, $arr2))));
+ }
+ return $new_array;
+ } else {
+ // not the same ... take new one if defined, else the old one stays
+ return $arr2 ? $arr2 : $arr1;
+ }
+ }
+
+ function IsValidMIMEstring($mimestring) {
+ if ((strlen($mimestring) >= 3) && (strpos($mimestring, '/') > 0) && (strpos($mimestring, '/') < (strlen($mimestring) - 1))) {
+ return true;
+ }
+ return false;
+ }
+
+ function IsWithinBitRange($number, $maxbits, $signed=false) {
+ if ($signed) {
+ if (($number > (0 - pow(2, $maxbits - 1))) && ($number <= pow(2, $maxbits - 1))) {
+ return true;
+ }
+ } else {
+ if (($number >= 0) && ($number <= pow(2, $maxbits))) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ function safe_parse_url($url) {
+ $parts = @parse_url($url);
+ $parts['scheme'] = (isset($parts['scheme']) ? $parts['scheme'] : '');
+ $parts['host'] = (isset($parts['host']) ? $parts['host'] : '');
+ $parts['user'] = (isset($parts['user']) ? $parts['user'] : '');
+ $parts['pass'] = (isset($parts['pass']) ? $parts['pass'] : '');
+ $parts['path'] = (isset($parts['path']) ? $parts['path'] : '');
+ $parts['query'] = (isset($parts['query']) ? $parts['query'] : '');
+ return $parts;
+ }
+
+ function IsValidURL($url, $allowUserPass=false) {
+ if ($url == '') {
+ return false;
+ }
+ if ($allowUserPass !== true) {
+ if (strstr($url, '@')) {
+ // in the format http://user:pass@example.com or http://user@example.com
+ // but could easily be somebody incorrectly entering an email address in place of a URL
+ return false;
+ }
+ }
+ if ($parts = $this->safe_parse_url($url)) {
+ if (($parts['scheme'] != 'http') && ($parts['scheme'] != 'https') && ($parts['scheme'] != 'ftp') && ($parts['scheme'] != 'gopher')) {
+ return false;
+ } elseif (!eregi("^[[:alnum:]]([-.]?[0-9a-z])*\.[a-z]{2,3}$", $parts['host'], $regs) && !IsValidDottedIP($parts['host'])) {
+ return false;
+ } elseif (!eregi("^([[:alnum:]-]|[\_])*$", $parts['user'], $regs)) {
+ return false;
+ } elseif (!eregi("^([[:alnum:]-]|[\_])*$", $parts['pass'], $regs)) {
+ return false;
+ } elseif (!eregi("^[[:alnum:]/_\.@~-]*$", $parts['path'], $regs)) {
+ return false;
+ } elseif (!eregi("^[[:alnum:]?&=+:;_()%#/,\.-]*$", $parts['query'], $regs)) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ function ID3v2ShortFrameNameLookup($majorversion, $long_description) {
+ $long_description = str_replace(' ', '_', strtolower(trim($long_description)));
+ static $ID3v2ShortFrameNameLookup = array();
+ if (empty($ID3v2ShortFrameNameLookup)) {
+
+ // The following are unique to ID3v2.2
+ $ID3v2ShortFrameNameLookup[2]['comment'] = 'COM';
+ $ID3v2ShortFrameNameLookup[2]['album'] = 'TAL';
+ $ID3v2ShortFrameNameLookup[2]['beats_per_minute'] = 'TBP';
+ $ID3v2ShortFrameNameLookup[2]['composer'] = 'TCM';
+ $ID3v2ShortFrameNameLookup[2]['genre'] = 'TCO';
+ $ID3v2ShortFrameNameLookup[2]['copyright'] = 'TCR';
+ $ID3v2ShortFrameNameLookup[2]['encoded_by'] = 'TEN';
+ $ID3v2ShortFrameNameLookup[2]['language'] = 'TLA';
+ $ID3v2ShortFrameNameLookup[2]['length'] = 'TLE';
+ $ID3v2ShortFrameNameLookup[2]['original_artist'] = 'TOA';
+ $ID3v2ShortFrameNameLookup[2]['original_filename'] = 'TOF';
+ $ID3v2ShortFrameNameLookup[2]['original_lyricist'] = 'TOL';
+ $ID3v2ShortFrameNameLookup[2]['original_album_title'] = 'TOT';
+ $ID3v2ShortFrameNameLookup[2]['artist'] = 'TP1';
+ $ID3v2ShortFrameNameLookup[2]['band'] = 'TP2';
+ $ID3v2ShortFrameNameLookup[2]['conductor'] = 'TP3';
+ $ID3v2ShortFrameNameLookup[2]['remixer'] = 'TP4';
+ $ID3v2ShortFrameNameLookup[2]['publisher'] = 'TPB';
+ $ID3v2ShortFrameNameLookup[2]['isrc'] = 'TRC';
+ $ID3v2ShortFrameNameLookup[2]['tracknumber'] = 'TRK';
+ $ID3v2ShortFrameNameLookup[2]['size'] = 'TSI';
+ $ID3v2ShortFrameNameLookup[2]['encoder_settings'] = 'TSS';
+ $ID3v2ShortFrameNameLookup[2]['description'] = 'TT1';
+ $ID3v2ShortFrameNameLookup[2]['title'] = 'TT2';
+ $ID3v2ShortFrameNameLookup[2]['subtitle'] = 'TT3';
+ $ID3v2ShortFrameNameLookup[2]['lyricist'] = 'TXT';
+ $ID3v2ShortFrameNameLookup[2]['user_text'] = 'TXX';
+ $ID3v2ShortFrameNameLookup[2]['year'] = 'TYE';
+ $ID3v2ShortFrameNameLookup[2]['unique_file_identifier'] = 'UFI';
+ $ID3v2ShortFrameNameLookup[2]['unsynchronised_lyrics'] = 'ULT';
+ $ID3v2ShortFrameNameLookup[2]['url_file'] = 'WAF';
+ $ID3v2ShortFrameNameLookup[2]['url_artist'] = 'WAR';
+ $ID3v2ShortFrameNameLookup[2]['url_source'] = 'WAS';
+ $ID3v2ShortFrameNameLookup[2]['copyright_information'] = 'WCP';
+ $ID3v2ShortFrameNameLookup[2]['url_publisher'] = 'WPB';
+ $ID3v2ShortFrameNameLookup[2]['url_user'] = 'WXX';
+
+ // The following are common to ID3v2.3 and ID3v2.4
+ $ID3v2ShortFrameNameLookup[3]['audio_encryption'] = 'AENC';
+ $ID3v2ShortFrameNameLookup[3]['attached_picture'] = 'APIC';
+ $ID3v2ShortFrameNameLookup[3]['comment'] = 'COMM';
+ $ID3v2ShortFrameNameLookup[3]['commercial'] = 'COMR';
+ $ID3v2ShortFrameNameLookup[3]['encryption_method_registration'] = 'ENCR';
+ $ID3v2ShortFrameNameLookup[3]['event_timing_codes'] = 'ETCO';
+ $ID3v2ShortFrameNameLookup[3]['general_encapsulated_object'] = 'GEOB';
+ $ID3v2ShortFrameNameLookup[3]['group_identification_registration'] = 'GRID';
+ $ID3v2ShortFrameNameLookup[3]['linked_information'] = 'LINK';
+ $ID3v2ShortFrameNameLookup[3]['music_cd_identifier'] = 'MCDI';
+ $ID3v2ShortFrameNameLookup[3]['mpeg_location_lookup_table'] = 'MLLT';
+ $ID3v2ShortFrameNameLookup[3]['ownership'] = 'OWNE';
+ $ID3v2ShortFrameNameLookup[3]['play_counter'] = 'PCNT';
+ $ID3v2ShortFrameNameLookup[3]['popularimeter'] = 'POPM';
+ $ID3v2ShortFrameNameLookup[3]['position_synchronisation'] = 'POSS';
+ $ID3v2ShortFrameNameLookup[3]['private'] = 'PRIV';
+ $ID3v2ShortFrameNameLookup[3]['recommended_buffer_size'] = 'RBUF';
+ $ID3v2ShortFrameNameLookup[3]['reverb'] = 'RVRB';
+ $ID3v2ShortFrameNameLookup[3]['synchronised_lyrics'] = 'SYLT';
+ $ID3v2ShortFrameNameLookup[3]['synchronised_tempo_codes'] = 'SYTC';
+ $ID3v2ShortFrameNameLookup[3]['album'] = 'TALB';
+ $ID3v2ShortFrameNameLookup[3]['beats_per_minute'] = 'TBPM';
+ $ID3v2ShortFrameNameLookup[3]['composer'] = 'TCOM';
+ $ID3v2ShortFrameNameLookup[3]['genre'] = 'TCON';
+ $ID3v2ShortFrameNameLookup[3]['copyright'] = 'TCOP';
+ $ID3v2ShortFrameNameLookup[3]['playlist_delay'] = 'TDLY';
+ $ID3v2ShortFrameNameLookup[3]['encoded_by'] = 'TENC';
+ $ID3v2ShortFrameNameLookup[3]['lyricist'] = 'TEXT';
+ $ID3v2ShortFrameNameLookup[3]['file_type'] = 'TFLT';
+ $ID3v2ShortFrameNameLookup[3]['content_group_description'] = 'TIT1';
+ $ID3v2ShortFrameNameLookup[3]['title'] = 'TIT2';
+ $ID3v2ShortFrameNameLookup[3]['subtitle'] = 'TIT3';
+ $ID3v2ShortFrameNameLookup[3]['initial_key'] = 'TKEY';
+ $ID3v2ShortFrameNameLookup[3]['language'] = 'TLAN';
+ $ID3v2ShortFrameNameLookup[3]['length'] = 'TLEN';
+ $ID3v2ShortFrameNameLookup[3]['media_type'] = 'TMED';
+ $ID3v2ShortFrameNameLookup[3]['original_album_title'] = 'TOAL';
+ $ID3v2ShortFrameNameLookup[3]['original_filename'] = 'TOFN';
+ $ID3v2ShortFrameNameLookup[3]['original_lyricist'] = 'TOLY';
+ $ID3v2ShortFrameNameLookup[3]['original_artist'] = 'TOPE';
+ $ID3v2ShortFrameNameLookup[3]['file_owner'] = 'TOWN';
+ $ID3v2ShortFrameNameLookup[3]['artist'] = 'TPE1';
+ $ID3v2ShortFrameNameLookup[3]['band'] = 'TPE2';
+ $ID3v2ShortFrameNameLookup[3]['conductor'] = 'TPE3';
+ $ID3v2ShortFrameNameLookup[3]['remixer'] = 'TPE4';
+ $ID3v2ShortFrameNameLookup[3]['part_of_set'] = 'TPOS';
+ $ID3v2ShortFrameNameLookup[3]['publisher'] = 'TPUB';
+ $ID3v2ShortFrameNameLookup[3]['tracknumber'] = 'TRCK';
+ $ID3v2ShortFrameNameLookup[3]['internet_radio_station_name'] = 'TRSN';
+ $ID3v2ShortFrameNameLookup[3]['internet_radio_station_owner'] = 'TRSO';
+ $ID3v2ShortFrameNameLookup[3]['isrc'] = 'TSRC';
+ $ID3v2ShortFrameNameLookup[3]['encoder_settings'] = 'TSSE';
+ $ID3v2ShortFrameNameLookup[3]['user_text'] = 'TXXX';
+ $ID3v2ShortFrameNameLookup[3]['unique_file_identifier'] = 'UFID';
+ $ID3v2ShortFrameNameLookup[3]['terms_of_use'] = 'USER';
+ $ID3v2ShortFrameNameLookup[3]['unsynchronised_lyrics'] = 'USLT';
+ $ID3v2ShortFrameNameLookup[3]['commercial'] = 'WCOM';
+ $ID3v2ShortFrameNameLookup[3]['copyright_information'] = 'WCOP';
+ $ID3v2ShortFrameNameLookup[3]['url_file'] = 'WOAF';
+ $ID3v2ShortFrameNameLookup[3]['url_artist'] = 'WOAR';
+ $ID3v2ShortFrameNameLookup[3]['url_source'] = 'WOAS';
+ $ID3v2ShortFrameNameLookup[3]['url_station'] = 'WORS';
+ $ID3v2ShortFrameNameLookup[3]['payment'] = 'WPAY';
+ $ID3v2ShortFrameNameLookup[3]['url_publisher'] = 'WPUB';
+ $ID3v2ShortFrameNameLookup[3]['url_user'] = 'WXXX';
+
+ // The above are common to ID3v2.3 and ID3v2.4
+ // so copy them to ID3v2.4 before adding specifics for 2.3 and 2.4
+ $ID3v2ShortFrameNameLookup[4] = $ID3v2ShortFrameNameLookup[3];
+
+ // The following are unique to ID3v2.3
+ $ID3v2ShortFrameNameLookup[3]['equalisation'] = 'EQUA';
+ $ID3v2ShortFrameNameLookup[3]['involved_people_list'] = 'IPLS';
+ $ID3v2ShortFrameNameLookup[3]['relative_volume_adjustment'] = 'RVAD';
+ $ID3v2ShortFrameNameLookup[3]['date'] = 'TDAT';
+ $ID3v2ShortFrameNameLookup[3]['time'] = 'TIME';
+ $ID3v2ShortFrameNameLookup[3]['original_release_year'] = 'TORY';
+ $ID3v2ShortFrameNameLookup[3]['recording_dates'] = 'TRDA';
+ $ID3v2ShortFrameNameLookup[3]['size'] = 'TSIZ';
+ $ID3v2ShortFrameNameLookup[3]['year'] = 'TYER';
+
+
+ // The following are unique to ID3v2.4
+ $ID3v2ShortFrameNameLookup[4]['audio_seek_point_index'] = 'ASPI';
+ $ID3v2ShortFrameNameLookup[4]['equalisation'] = 'EQU2';
+ $ID3v2ShortFrameNameLookup[4]['relative_volume_adjustment'] = 'RVA2';
+ $ID3v2ShortFrameNameLookup[4]['seek'] = 'SEEK';
+ $ID3v2ShortFrameNameLookup[4]['signature'] = 'SIGN';
+ $ID3v2ShortFrameNameLookup[4]['encoding_time'] = 'TDEN';
+ $ID3v2ShortFrameNameLookup[4]['original_release_time'] = 'TDOR';
+ $ID3v2ShortFrameNameLookup[4]['recording_time'] = 'TDRC';
+ $ID3v2ShortFrameNameLookup[4]['release_time'] = 'TDRL';
+ $ID3v2ShortFrameNameLookup[4]['tagging_time'] = 'TDTG';
+ $ID3v2ShortFrameNameLookup[4]['involved_people_list'] = 'TIPL';
+ $ID3v2ShortFrameNameLookup[4]['musician_credits_list'] = 'TMCL';
+ $ID3v2ShortFrameNameLookup[4]['mood'] = 'TMOO';
+ $ID3v2ShortFrameNameLookup[4]['produced_notice'] = 'TPRO';
+ $ID3v2ShortFrameNameLookup[4]['album_sort_order'] = 'TSOA';
+ $ID3v2ShortFrameNameLookup[4]['performer_sort_order'] = 'TSOP';
+ $ID3v2ShortFrameNameLookup[4]['title_sort_order'] = 'TSOT';
+ $ID3v2ShortFrameNameLookup[4]['set_subtitle'] = 'TSST';
+ }
+ return @$ID3v2ShortFrameNameLookup[$majorversion][strtolower($long_description)];
+
+ }
+
+}
+
+?>
Added: plog/trunk/class/gallery/getid3/write.lyrics3.php
===================================================================
--- plog/trunk/class/gallery/getid3/write.lyrics3.php 2006-07-24 16:40:16 UTC (rev 3789)
+++ plog/trunk/class/gallery/getid3/write.lyrics3.php 2006-07-24 16:56:08 UTC (rev 3790)
@@ -0,0 +1,78 @@
+<?php
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info at getid3.org> //
+// available at http://getid3.sourceforge.net //
+// or http://www.getid3.org //
+/////////////////////////////////////////////////////////////////
+// See readme.txt for more details //
+/////////////////////////////////////////////////////////////////
+// //
+// write.lyrics3.php //
+// module for writing Lyrics3 tags //
+// dependencies: module.tag.lyrics3.php //
+// ///
+/////////////////////////////////////////////////////////////////
+
+
+class getid3_write_lyrics3
+{
+ var $filename;
+ var $tag_data;
+ //var $lyrics3_version = 2; // 1 or 2
+ var $warnings = array(); // any non-critical errors will be stored here
+ var $errors = array(); // any critical errors will be stored here
+
+ function getid3_write_lyrics3() {
+ return true;
+ }
+
+ function WriteLyrics3() {
+ $this->errors[] = 'WriteLyrics3() not yet functional - cannot write Lyrics3';
+ return false;
+ }
+
+ function DeleteLyrics3() {
+ // Initialize getID3 engine
+ $getID3 = new getID3;
+ $ThisFileInfo = $getID3->analyze($this->filename);
+ if (isset($ThisFileInfo['lyrics3']['tag_offset_start']) && isset($ThisFileInfo['lyrics3']['tag_offset_end'])) {
+ if ($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 open "'.$this->filename.'" in "a+b" mode';
+ return false;
+
+ }
+ }
+ // no Lyrics3 present
+ return true;
+ }
+
+
+
+}
+
+?>
\ No newline at end of file
Added: plog/trunk/class/gallery/getid3/write.metaflac.php
===================================================================
--- plog/trunk/class/gallery/getid3/write.metaflac.php 2006-07-24 16:40:16 UTC (rev 3789)
+++ plog/trunk/class/gallery/getid3/write.metaflac.php 2006-07-24 16:56:08 UTC (rev 3790)
@@ -0,0 +1,167 @@
+<?php
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info at getid3.org> //
+// available at http://getid3.sourceforge.net //
+// or http://www.getid3.org //
+/////////////////////////////////////////////////////////////////
+// See readme.txt for more details //
+/////////////////////////////////////////////////////////////////
+// //
+// write.metaflac.php //
+// module for writing metaflac tags //
+// dependencies: /helperapps/metaflac.exe //
+// ///
+/////////////////////////////////////////////////////////////////
+
+
+class getid3_write_metaflac
+{
+
+ var $filename;
+ var $tag_data;
+ var $warnings = array(); // any non-critical errors will be stored here
+ var $errors = array(); // any critical errors will be stored here
+
+ function getid3_write_metaflac() {
+ return true;
+ }
+
+ function WriteMetaFLAC() {
+
+ if (!ini_get('safe_mode')) {
+
+ // Create file with new comments
+ $tempcommentsfilename = tempnam('*', 'getID3');
+ if ($fpcomments = @fopen($tempcommentsfilename, 'wb')) {
+
+ foreach ($this->tag_data as $key => $value) {
+ foreach ($value as $commentdata) {
+ fwrite($fpcomments, $this->CleanmetaflacName($key).'='.$commentdata."\n");
+ }
+ }
+ fclose($fpcomments);
+
+ } else {
+
+ $this->errors[] = 'failed to open temporary tags file "'.$tempcommentsfilename.'", tags not written';
+ return false;
+
+ }
+
+ $oldignoreuserabort = ignore_user_abort(true);
+ if (GETID3_OS_ISWINDOWS) {
+
+ if (file_exists(GETID3_HELPERAPPSDIR.'metaflac.exe')) {
+ //$commandline = '"'.GETID3_HELPERAPPSDIR.'metaflac.exe" --no-utf8-convert --remove-vc-all --import-vc-from="'.$tempcommentsfilename.'" "'.str_replace('/', '\\', $this->filename).'"';
+ // metaflac works fine if you copy-paste the above commandline into a command prompt,
+ // but refuses to work with `backtick` if there are "doublequotes" present around BOTH
+ // the metaflac pathname and the target filename. For whatever reason...??
+ // The solution is simply ensure that the metaflac pathname has no spaces,
+ // and therefore does not need to be quoted
+
+ // On top of that, if error messages are not always captured properly under Windows
+ // To at least see if there was a problem, compare file modification timestamps before and after writing
+ clearstatcache();
+ $timestampbeforewriting = filemtime($this->filename);
+
+ $commandline = GETID3_HELPERAPPSDIR.'metaflac.exe --no-utf8-convert --remove-vc-all --import-vc-from="'.$tempcommentsfilename.'" "'.$this->filename.'" 2>&1';
+ $metaflacError = `$commandline`;
+
+ if (empty($metaflacError)) {
+ clearstatcache();
+ if ($timestampbeforewriting == filemtime($this->filename)) {
+ $metaflacError = 'File modification timestamp has not changed - it looks like the tags were not written';
+ }
+ }
+ } else {
+ $metaflacError = 'metaflac.exe not found in '.GETID3_HELPERAPPSDIR;
+ }
+
+ } else {
+
+ // It's simpler on *nix
+ $commandline = 'metaflac --no-utf8-convert --remove-vc-all --import-vc-from='.$tempcommentsfilename.' "'.$this->filename.'" 2>&1';
+ $metaflacError = `$commandline`;
+
+ }
+
+ // Remove temporary comments file
+ unlink($tempcommentsfilename);
+ ignore_user_abort($oldignoreuserabort);
+
+ if (!empty($metaflacError)) {
+
+ $this->errors[] = 'System call to metaflac failed with this message returned: '."\n\n".$metaflacError;
+ return false;
+
+ }
+
+ return true;
+ }
+
+ $this->errors[] = 'PHP running in Safe Mode (backtick operator not available) - cannot call metaflac, tags not written';
+ return false;
+ }
+
+
+ function DeleteMetaFLAC() {
+
+ if (!ini_get('safe_mode')) {
+
+ $oldignoreuserabort = ignore_user_abort(true);
+ if (GETID3_OS_ISWINDOWS) {
+
+ if (file_exists(GETID3_HELPERAPPSDIR.'metaflac.exe')) {
+ // To at least see if there was a problem, compare file modification timestamps before and after writing
+ clearstatcache();
+ $timestampbeforewriting = filemtime($this->filename);
+
+ $commandline = GETID3_HELPERAPPSDIR.'metaflac.exe --remove-vc-all "'.$this->filename.'" 2>&1';
+ $metaflacError = `$commandline`;
+
+ if (empty($metaflacError)) {
+ clearstatcache();
+ if ($timestampbeforewriting == filemtime($this->filename)) {
+ $metaflacError = 'File modification timestamp has not changed - it looks like the tags were not deleted';
+ }
+ }
+ } else {
+ $metaflacError = 'metaflac.exe not found in '.GETID3_HELPERAPPSDIR;
+ }
+
+ } else {
+
+ // It's simpler on *nix
+ $commandline = 'metaflac --remove-vc-all "'.$this->filename.'" 2>&1';
+ $metaflacError = `$commandline`;
+
+ }
+
+ ignore_user_abort($oldignoreuserabort);
+
+ if (!empty($metaflacError)) {
+ $this->errors[] = 'System call to metaflac failed with this message returned: '."\n\n".$metaflacError;
+ return false;
+ }
+ return true;
+ }
+ $this->errors[] = 'PHP running in Safe Mode (backtick operator not available) - cannot call metaflac, tags not deleted';
+ return false;
+ }
+
+
+ function CleanmetaflacName($originalcommentname) {
+ // A case-insensitive field name that may consist of ASCII 0x20 through 0x7D, 0x3D ('=') excluded.
+ // ASCII 0x41 through 0x5A inclusive (A-Z) is to be considered equivalent to ASCII 0x61 through
+ // 0x7A inclusive (a-z).
+
+ // replace invalid chars with a space, return uppercase text
+ // Thanks Chris Bolt <chris-getid3Øbolt*cx> for improving this function
+ // note: ereg_replace() replaces nulls with empty string (not space)
+ return strtoupper(ereg_replace('[^ -<>-}]', ' ', str_replace("\x00", ' ', $originalcommentname)));
+
+ }
+
+}
+
+?>
\ No newline at end of file
Added: plog/trunk/class/gallery/getid3/write.php
===================================================================
--- plog/trunk/class/gallery/getid3/write.php 2006-07-24 16:40:16 UTC (rev 3789)
+++ plog/trunk/class/gallery/getid3/write.php 2006-07-24 16:56:08 UTC (rev 3790)
@@ -0,0 +1,592 @@
+<?php
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info at getid3.org> //
+// available at http://getid3.sourceforge.net //
+// or http://www.getid3.org //
+/////////////////////////////////////////////////////////////////
+// See readme.txt for more details //
+/////////////////////////////////////////////////////////////////
+/// //
+// write.php //
+// module for writing tags (APEv2, ID3v1, ID3v2) //
+// dependencies: getid3.lib.php //
+// write.apetag.php (optional) //
+// write.id3v1.php (optional) //
+// write.id3v2.php (optional) //
+// write.vorbiscomment.php (optional) //
+// write.metaflac.php (optional) //
+// write.lyrics3.php (optional) //
+// ///
+/////////////////////////////////////////////////////////////////
+
+if (!defined('GETID3_INCLUDEPATH')) {
+ die('getid3.php MUST be included before calling getid3_writetags');
+}
+if (!include_once(GETID3_INCLUDEPATH.'getid3.lib.php')) {
+ die('write.php depends on getid3.lib.php, which is missing.');
+}
+
+
+// NOTES:
+//
+// You should pass data here with standard field names as follows:
+// * TITLE
+// * ARTIST
+// * ALBUM
+// * TRACKNUMBER
+// * COMMENT
+// * GENRE
+// * YEAR
+// * ATTACHED_PICTURE (ID3v2 only)
+//
+// http://www.personal.uni-jena.de/~pfk/mpp/sv8/apekey.html
+// The APEv2 Tag Items Keys definition says "TRACK" is correct but foobar2000 uses "TRACKNUMBER" instead
+// Pass data here as "TRACKNUMBER" for compatability with all formats
+
+
+class getid3_writetags
+{
+ // public
+ var $filename; // absolute filename of file to write tags to
+ var $tagformats = array(); // array of tag formats to write ('id3v1', 'id3v2.2', 'id2v2.3', 'id3v2.4', 'ape', 'vorbiscomment', 'metaflac', 'real')
+ var $tag_data = array(array()); // 2-dimensional array of tag data (ex: $data['ARTIST'][0] = 'Elvis')
+ var $tag_encoding = 'ISO-8859-1'; // text encoding used for tag data ('ISO-8859-1', 'UTF-8', 'UTF-16', 'UTF-16LE', 'UTF-16BE', )
+ var $overwrite_tags = true; // if true will erase existing tag data and write only passed data; if false will merge passed data with existing tag data
+ var $remove_other_tags = false; // if true will erase remove all existing tags and only write those passed in $tagformats; if false will ignore any tags not mentioned in $tagformats
+
+ var $id3v2_tag_language = 'eng'; // ISO-639-2 3-character language code needed for some ID3v2 frames (http://www.id3.org/iso639-2.html)
+ var $id3v2_paddedlength = 4096; // minimum length of ID3v2 tags (will be padded to this length if tag data is shorter)
+
+ var $warnings = array(); // any non-critical errors will be stored here
+ var $errors = array(); // any critical errors will be stored here
+
+ // private
+ var $ThisFileInfo; // analysis of file before writing
+
+ function getid3_writetags() {
+ return true;
+ }
+
+
+ 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 getID3;
+ $getID3->encoding = $this->tag_encoding;
+ $this->ThisFileInfo = $getID3->analyze($this->filename);
+
+ // check for what file types are allowed on this fileformat
+ switch (@$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 (@$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 "'.@$this->ThisFileInfo['fileformat'];
+ if (@$this->ThisFileInfo['fileformat'] != @$this->ThisFileInfo['audio']['dataformat']) {
+ $errormessage .= '.'.@$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 (!getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'write.apetag.php', __FILE__, false)) {
+ return false;
+ }
+ break;
+
+ case 'id3v1':
+ case 'lyrics3':
+ case 'vorbiscomment':
+ case 'metaflac':
+ case 'real':
+ $GETID3_ERRORARRAY = &$this->errors;
+ if (!getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'write.'.$tagformat.'.php', __FILE__, false)) {
+ return false;
+ }
+ break;
+
+ case 'id3v2.2':
+ case 'id3v2.3':
+ case 'id3v2.4':
+ case 'id3v2':
+ $GETID3_ERRORARRAY = &$this->errors;
+ if (!getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'write.id3v2.php', __FILE__, false)) {
+ 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[] = '$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 getid3_write_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>'.trim(implode('</LI><LI>', $ape_writer->errors)).'</LI></UL></PRE>';
+ }
+ } else {
+ $this->errors[] = 'FormatDataForAPE() failed';
+ }
+ break;
+
+ case 'id3v1':
+ $id3v1_writer = new getid3_write_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>'.trim(implode('</LI><LI>', $id3v1_writer->errors)).'</LI></UL></PRE>';
+ }
+ } else {
+ $this->errors[] = 'FormatDataForID3v1() failed';
+ }
+ break;
+
+ case 'id3v2.2':
+ case 'id3v2.3':
+ case 'id3v2.4':
+ $id3v2_writer = new getid3_write_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>'.trim(implode('</LI><LI>', $id3v2_writer->errors)).'</LI></UL></PRE>';
+ }
+ } else {
+ $this->errors[] = 'FormatDataForID3v2() failed';
+ }
+ break;
+
+ case 'vorbiscomment':
+ $vorbiscomment_writer = new getid3_write_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>'.trim(implode('</LI><LI>', $vorbiscomment_writer->errors)).'</LI></UL></PRE>';
+ }
+ } else {
+ $this->errors[] = 'FormatDataForVorbisComment() failed';
+ }
+ break;
+
+ case 'metaflac':
+ $metaflac_writer = new getid3_write_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>'.trim(implode('</LI><LI>', $metaflac_writer->errors)).'</LI></UL></PRE>';
+ }
+ } else {
+ $this->errors[] = 'FormatDataForMetaFLAC() failed';
+ }
+ break;
+
+ case 'real':
+ $real_writer = new getid3_write_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>'.trim(implode('</LI><LI>', $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;
+
+ }
+
+
+ function DeleteTags($TagFormatsToDelete) {
+ foreach ($TagFormatsToDelete as $DeleteTagFormat) {
+ $success = false; // overridden if tag deletion is successful
+ switch ($DeleteTagFormat) {
+ case 'id3v1':
+ $id3v1_writer = new getid3_write_id3v1;
+ $id3v1_writer->filename = $this->filename;
+ if (($success = $id3v1_writer->RemoveID3v1()) === false) {
+ $this->errors[] = 'RemoveID3v1() failed with message(s):<PRE><UL><LI>'.trim(implode('</LI><LI>', $id3v1_writer->errors)).'</LI></UL></PRE>';
+ }
+ break;
+
+ case 'id3v2':
+ $id3v2_writer = new getid3_write_id3v2;
+ $id3v2_writer->filename = $this->filename;
+ if (($success = $id3v2_writer->RemoveID3v2()) === false) {
+ $this->errors[] = 'RemoveID3v2() failed with message(s):<PRE><UL><LI>'.trim(implode('</LI><LI>', $id3v2_writer->errors)).'</LI></UL></PRE>';
+ }
+ break;
+
+ case 'ape':
+ $ape_writer = new getid3_write_apetag;
+ $ape_writer->filename = $this->filename;
+ if (($success = $ape_writer->DeleteAPEtag()) === false) {
+ $this->errors[] = 'DeleteAPEtag() failed with message(s):<PRE><UL><LI>'.trim(implode('</LI><LI>', $ape_writer->errors)).'</LI></UL></PRE>';
+ }
+ break;
+
+ case 'vorbiscomment':
+ $vorbiscomment_writer = new getid3_write_vorbiscomment;
+ $vorbiscomment_writer->filename = $this->filename;
+ if (($success = $vorbiscomment_writer->DeleteVorbisComment()) === false) {
+ $this->errors[] = 'DeleteVorbisComment() failed with message(s):<PRE><UL><LI>'.trim(implode('</LI><LI>', $vorbiscomment_writer->errors)).'</LI></UL></PRE>';
+ }
+ break;
+
+ case 'metaflac':
+ $metaflac_writer = new getid3_write_metaflac;
+ $metaflac_writer->filename = $this->filename;
+ if (($success = $metaflac_writer->DeleteMetaFLAC()) === false) {
+ $this->errors[] = 'DeleteMetaFLAC() failed with message(s):<PRE><UL><LI>'.trim(implode('</LI><LI>', $metaflac_writer->errors)).'</LI></UL></PRE>';
+ }
+ break;
+
+ case 'lyrics3':
+ $lyrics3_writer = new getid3_write_lyrics3;
+ $lyrics3_writer->filename = $this->filename;
+ if (($success = $lyrics3_writer->DeleteLyrics3()) === false) {
+ $this->errors[] = 'DeleteLyrics3() failed with message(s):<PRE><UL><LI>'.trim(implode('</LI><LI>', $lyrics3_writer->errors)).'</LI></UL></PRE>';
+ }
+ break;
+
+ case 'real':
+ $real_writer = new getid3_write_real;
+ $real_writer->filename = $this->filename;
+ if (($success = $real_writer->RemoveReal()) === false) {
+ $this->errors[] = 'RemoveReal() failed with message(s):<PRE><UL><LI>'.trim(implode('</LI><LI>', $real_writer->errors)).'</LI></UL></PRE>';
+ }
+ break;
+
+ default:
+ $this->errors[] = 'Invalid tag format to delete: "'.$tagformat.'"';
+ return false;
+ break;
+ }
+ if (!$success) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+ function MergeExistingTagData($TagFormat, &$tag_data) {
+ // Merge supplied data with existing data, if requested
+ if ($this->overwrite_tags) {
+ // do nothing - ignore previous data
+ } else {
+ if (!isset($this->ThisFileInfo['tags'][$TagFormat])) {
+ return false;
+ }
+ $tag_data = array_merge_recursive($tag_data, $this->ThisFileInfo['tags'][$TagFormat]);
+ }
+ return true;
+ }
+
+ function FormatDataForAPE() {
+ $ape_tag_data = array();
+ foreach ($this->tag_data as $tag_key => $valuearray) {
+ switch ($tag_key) {
+ case 'ATTACHED_PICTURE':
+ // ATTACHED_PICTURE is ID3v2 only - ignore
+ $this->warnings[] = '$data['.$tag_key.'] is assumed to be ID3v2 APIC data - NOT written to APE tag';
+ break;
+
+ default:
+ foreach ($valuearray as $key => $value) {
+ if (is_string($value) || is_numeric($value)) {
+ $ape_tag_data[$tag_key][$key] = getid3_lib::iconv_fallback($this->tag_encoding, 'UTF-8', $value);
+ } else {
+ $this->warnings[] = '$data['.$tag_key.']['.$key.'] is not a string value - all of $data['.$tag_key.'] NOT written to APE tag';
+ unset($ape_tag_data[$tag_key]);
+ break;
+ }
+ }
+ break;
+ }
+ }
+ $this->MergeExistingTagData('ape', $ape_tag_data);
+ return $ape_tag_data;
+ }
+
+
+ function FormatDataForID3v1() {
+ $tag_data_id3v1['genreid'] = 255;
+ if (!empty($this->tag_data['GENRE'])) {
+ foreach ($this->tag_data['GENRE'] as $key => $value) {
+ if (getid3_id3v1::LookupGenreID($value) !== false) {
+ $tag_data_id3v1['genreid'] = getid3_id3v1::LookupGenreID($value);
+ break;
+ }
+ }
+ }
+
+ $tag_data_id3v1['title'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', @implode(' ', @$this->tag_data['TITLE']));
+ $tag_data_id3v1['artist'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', @implode(' ', @$this->tag_data['ARTIST']));
+ $tag_data_id3v1['album'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', @implode(' ', @$this->tag_data['ALBUM']));
+ $tag_data_id3v1['year'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', @implode(' ', @$this->tag_data['YEAR']));
+ $tag_data_id3v1['comment'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', @implode(' ', @$this->tag_data['COMMENT']));
+
+ $tag_data_id3v1['track'] = intval(getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', @implode(' ', @$this->tag_data['TRACKNUMBER'])));
+ if ($tag_data_id3v1['track'] <= 0) {
+ $tag_data_id3v1['track'] = '';
+ }
+
+ $this->MergeExistingTagData('id3v1', $tag_data_id3v1);
+ return $tag_data_id3v1;
+ }
+
+ function FormatDataForID3v2($id3v2_majorversion) {
+ $tag_data_id3v2 = array();
+
+ $ID3v2_text_encoding_lookup[2] = array('ISO-8859-1'=>0, 'UTF-16'=>1);
+ $ID3v2_text_encoding_lookup[3] = array('ISO-8859-1'=>0, 'UTF-16'=>1);
+ $ID3v2_text_encoding_lookup[4] = array('ISO-8859-1'=>0, 'UTF-16'=>1, 'UTF-16BE'=>2, 'UTF-8'=>3);
+ foreach ($this->tag_data as $tag_key => $valuearray) {
+ $ID3v2_framename = getid3_write_id3v2::ID3v2ShortFrameNameLookup($id3v2_majorversion, $tag_key);
+ switch ($ID3v2_framename) {
+ case 'APIC':
+ foreach ($valuearray as $key => $apic_data_array) {
+ if (isset($apic_data_array['data']) &&
+ isset($apic_data_array['picturetypeid']) &&
+ isset($apic_data_array['description']) &&
+ isset($apic_data_array['mime'])) {
+ $tag_data_id3v2['APIC'][] = $apic_data_array;
+ } else {
+ $this->errors[] = 'ID3v2 APIC data is not properly structured';
+ return false;
+ }
+ }
+ break;
+
+ case '':
+ $this->errors[] = 'ID3v2: Skipping "'.$tag_key.'" because cannot match it to a known ID3v2 frame type';
+ // some other data type, don't know how to handle it, ignore it
+ break;
+
+ default:
+ // most other (text) frames can be copied over as-is
+ foreach ($valuearray as $key => $value) {
+ if (isset($ID3v2_text_encoding_lookup[$id3v2_majorversion][$this->tag_encoding])) {
+ // source encoding is valid in ID3v2 - use it with no conversion
+ $tag_data_id3v2[$ID3v2_framename][$key]['encodingid'] = $ID3v2_text_encoding_lookup[$id3v2_majorversion][$this->tag_encoding];
+ $tag_data_id3v2[$ID3v2_framename][$key]['data'] = $value;
+ } else {
+ // source encoding is NOT valid in ID3v2 - convert it to an ID3v2-valid encoding first
+ if ($id3v2_majorversion < 4) {
+ // convert data from other encoding to UTF-16
+ $tag_data_id3v2[$ID3v2_framename][$key]['encodingid'] = 1;
+ $tag_data_id3v2[$ID3v2_framename][$key]['data'] = getid3_lib::iconv_fallback($this->tag_encoding, 'UTF-16', $value);
+
+ } else {
+ // convert data from other encoding to UTF-8
+ $tag_data_id3v2[$ID3v2_framename][$key]['encodingid'] = 3;
+ $tag_data_id3v2[$ID3v2_framename][$key]['data'] = getid3_lib::iconv_fallback($this->tag_encoding, 'UTF-8', $value);
+ }
+ }
+
+ // These values are not needed for all frame types, but if they're not used no matter
+ $tag_data_id3v2[$ID3v2_framename][$key]['description'] = '';
+ $tag_data_id3v2[$ID3v2_framename][$key]['language'] = $this->id3v2_tag_language;
+ }
+ break;
+ }
+ }
+ $this->MergeExistingTagData('id3v2', $tag_data_id3v2);
+ return $tag_data_id3v2;
+ }
+
+ function FormatDataForVorbisComment() {
+ $tag_data_vorbiscomment = $this->tag_data;
+
+ // check for multi-line comment values - split out to multiple comments if neccesary
+ // and convert data to UTF-8 strings
+ foreach ($tag_data_vorbiscomment as $tag_key => $valuearray) {
+ foreach ($valuearray as $key => $value) {
+ str_replace("\r", "\n", $value);
+ if (strstr($value, "\n")) {
+ unset($tag_data_vorbiscomment[$tag_key][$key]);
+ $multilineexploded = explode("\n", $value);
+ foreach ($multilineexploded as $newcomment) {
+ if (strlen(trim($newcomment)) > 0) {
+ $tag_data_vorbiscomment[$tag_key][] = getid3_lib::iconv_fallback($this->tag_encoding, 'UTF-8', $newcomment);
+ }
+ }
+ } elseif (is_string($value) || is_numeric($value)) {
+ $tag_data_vorbiscomment[$tag_key][$key] = getid3_lib::iconv_fallback($this->tag_encoding, 'UTF-8', $value);
+ } else {
+ $this->warnings[] = '$data['.$tag_key.']['.$key.'] is not a string value - all of $data['.$tag_key.'] NOT written to VorbisComment tag';
+ unset($tag_data_vorbiscomment[$tag_key]);
+ break;
+ }
+ }
+ }
+ $this->MergeExistingTagData('vorbiscomment', $tag_data_vorbiscomment);
+ return $tag_data_vorbiscomment;
+ }
+
+ function FormatDataForMetaFLAC() {
+ // FLAC & OggFLAC use VorbisComments same as OggVorbis
+ // but require metaflac to do the writing rather than vorbiscomment
+ return $this->FormatDataForVorbisComment();
+ }
+
+ function FormatDataForReal() {
+ $tag_data_real['title'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', @implode(' ', @$this->tag_data['TITLE']));
+ $tag_data_real['artist'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', @implode(' ', @$this->tag_data['ARTIST']));
+ $tag_data_real['copyright'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', @implode(' ', @$this->tag_data['COPYRIGHT']));
+ $tag_data_real['comment'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', @implode(' ', @$this->tag_data['COMMENT']));
+
+ $this->MergeExistingTagData('real', $tag_data_real);
+ return $tag_data_real;
+ }
+
+}
+
+?>
\ No newline at end of file
Added: plog/trunk/class/gallery/getid3/write.real.php
===================================================================
--- plog/trunk/class/gallery/getid3/write.real.php 2006-07-24 16:40:16 UTC (rev 3789)
+++ plog/trunk/class/gallery/getid3/write.real.php 2006-07-24 16:56:08 UTC (rev 3790)
@@ -0,0 +1,295 @@
+<?php
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info at getid3.org> //
+// available at http://getid3.sourceforge.net //
+// or http://www.getid3.org //
+/////////////////////////////////////////////////////////////////
+// See readme.txt for more details //
+/////////////////////////////////////////////////////////////////
+// //
+// write.real.php //
+// module for writing RealAudio/RealVideo tags //
+// dependencies: module.tag.real.php //
+// ///
+/////////////////////////////////////////////////////////////////
+
+class getid3_write_real
+{
+ var $filename;
+ var $tag_data = array();
+ var $warnings = array(); // any non-critical errors will be stored here
+ var $errors = array(); // any critical errors will be stored here
+ var $paddedlength = 512; // minimum length of CONT tag in bytes
+
+ function getid3_write_real() {
+ return true;
+ }
+
+ function WriteReal() {
+ // File MUST be writeable - CHMOD(646) at least
+ if (is_writeable($this->filename)) {
+ if ($fp_source = @fopen($this->filename, 'r+b')) {
+
+ // Initialize getID3 engine
+ $getID3 = new getID3;
+ $OldThisFileInfo = $getID3->analyze($this->filename);
+ if (empty($OldThisFileInfo['real']['chunks']) && !empty($OldThisFileInfo['real']['old_ra_header'])) {
+ $this->errors[] = 'Cannot write Real tags on old-style file format';
+ fclose($fp_source);
+ return false;
+ }
+
+ if (empty($OldThisFileInfo['real']['chunks'])) {
+ $this->errors[] = 'Cannot write 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']['length'])) {
+ $this->paddedlength = max($oldChunkInfo['CONT']['length'], $this->paddedlength);
+ }
+
+ $new_CONT_tag_data = $this->GenerateCONTchunk();
+ $new_PROP_tag_data = $this->GeneratePROPchunk($OldThisFileInfo['real']['chunks'], $new_CONT_tag_data);
+ $new__RMF_tag_data = $this->GenerateRMFchunk($OldThisFileInfo['real']['chunks']);
+
+ if (@$oldChunkInfo['.RMF']['length'] == strlen($new__RMF_tag_data)) {
+ fseek($fp_source, $oldChunkInfo['.RMF']['offset'], SEEK_SET);
+ fwrite($fp_source, $new__RMF_tag_data);
+ } else {
+ $this->errors[] = 'new .RMF tag ('.strlen($new__RMF_tag_data).' bytes) different length than old .RMF tag ('.$oldChunkInfo['.RMF']['length'].' bytes)';
+ fclose($fp_source);
+ return false;
+ }
+
+ if (@$oldChunkInfo['PROP']['length'] == strlen($new_PROP_tag_data)) {
+ fseek($fp_source, $oldChunkInfo['PROP']['offset'], SEEK_SET);
+ fwrite($fp_source, $new_PROP_tag_data);
+ } else {
+ $this->errors[] = 'new PROP tag ('.strlen($new_PROP_tag_data).' bytes) different length than old PROP tag ('.$oldChunkInfo['PROP']['length'].' bytes)';
+ fclose($fp_source);
+ return false;
+ }
+
+ if (@$oldChunkInfo['CONT']['length'] == strlen($new_CONT_tag_data)) {
+
+ // new data length is same as old data length - just overwrite
+ fseek($fp_source, $oldChunkInfo['CONT']['offset'], SEEK_SET);
+ fwrite($fp_source, $new_CONT_tag_data);
+ fclose($fp_source);
+ return true;
+
+ } else {
+
+ if (empty($oldChunkInfo['CONT'])) {
+ // no existing CONT chunk
+ $BeforeOffset = $oldChunkInfo['DATA']['offset'];
+ $AfterOffset = $oldChunkInfo['DATA']['offset'];
+ } else {
+ // new data is longer than old data
+ $BeforeOffset = $oldChunkInfo['CONT']['offset'];
+ $AfterOffset = $oldChunkInfo['CONT']['offset'] + $oldChunkInfo['CONT']['length'];
+ }
+ if ($tempfilename = tempnam('*', 'getID3')) {
+ ob_start();
+ if ($fp_temp = fopen($tempfilename, 'wb')) {
+
+ rewind($fp_source);
+ fwrite($fp_temp, fread($fp_source, $BeforeOffset));
+ fwrite($fp_temp, $new_CONT_tag_data);
+ fseek($fp_source, $AfterOffset, SEEK_SET);
+ while ($buffer = fread($fp_source, GETID3_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.') - '.strip_tags(ob_get_contents());
+
+ } else {
+
+ $this->errors[] = 'Could not open '.$tempfilename.' mode "wb" - '.strip_tags(ob_get_contents());
+
+ }
+ ob_end_clean();
+ }
+ fclose($fp_source);
+ return false;
+
+ }
+
+
+ } else {
+ $this->errors[] = 'Could not open '.$this->filename.' mode "r+b"';
+ return false;
+ }
+ }
+ $this->errors[] = 'File is not writeable: '.$this->filename;
+ return false;
+ }
+
+ function GenerateRMFchunk(&$chunks) {
+ $oldCONTexists = false;
+ foreach ($chunks as $key => $chunk) {
+ $chunkNameKeys[$chunk['name']] = $key;
+ if ($chunk['name'] == 'CONT') {
+ $oldCONTexists = true;
+ }
+ }
+ $newHeadersCount = $chunks[$chunkNameKeys['.RMF']]['headers_count'] + ($oldCONTexists ? 0 : 1);
+
+ $RMFchunk = "\x00\x00"; // object version
+ $RMFchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['.RMF']]['file_version'], 4);
+ $RMFchunk .= getid3_lib::BigEndian2String($newHeadersCount, 4);
+
+ $RMFchunk = '.RMF'.getid3_lib::BigEndian2String(strlen($RMFchunk) + 8, 4).$RMFchunk; // .RMF chunk identifier + chunk length
+ return $RMFchunk;
+ }
+
+ function GeneratePROPchunk(&$chunks, &$new_CONT_tag_data) {
+ $old_CONT_length = 0;
+ $old_DATA_offset = 0;
+ $old_INDX_offset = 0;
+ foreach ($chunks as $key => $chunk) {
+ $chunkNameKeys[$chunk['name']] = $key;
+ if ($chunk['name'] == 'CONT') {
+ $old_CONT_length = $chunk['length'];
+ } elseif ($chunk['name'] == 'DATA') {
+ if (!$old_DATA_offset) {
+ $old_DATA_offset = $chunk['offset'];
+ }
+ } elseif ($chunk['name'] == 'INDX') {
+ if (!$old_INDX_offset) {
+ $old_INDX_offset = $chunk['offset'];
+ }
+ }
+ }
+ $CONTdelta = strlen($new_CONT_tag_data) - $old_CONT_length;
+
+ $PROPchunk = "\x00\x00"; // object version
+ $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['max_bit_rate'], 4);
+ $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['avg_bit_rate'], 4);
+ $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['max_packet_size'], 4);
+ $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['avg_packet_size'], 4);
+ $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['num_packets'], 4);
+ $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['duration'], 4);
+ $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['preroll'], 4);
+ $PROPchunk .= getid3_lib::BigEndian2String(max(0, $old_INDX_offset + $CONTdelta), 4);
+ $PROPchunk .= getid3_lib::BigEndian2String(max(0, $old_DATA_offset + $CONTdelta), 4);
+ $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['num_streams'], 2);
+ $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['flags_raw'], 2);
+
+ $PROPchunk = 'PROP'.getid3_lib::BigEndian2String(strlen($PROPchunk) + 8, 4).$PROPchunk; // PROP chunk identifier + chunk length
+ return $PROPchunk;
+ }
+
+ function GenerateCONTchunk() {
+ foreach ($this->tag_data as $key => $value) {
+ // limit each value to 0xFFFF bytes
+ $this->tag_data[$key] = substr($value, 0, 65535);
+ }
+
+ $CONTchunk = "\x00\x00"; // object version
+
+ $CONTchunk .= getid3_lib::BigEndian2String(strlen(@$this->tag_data['title']), 2);
+ $CONTchunk .= @$this->tag_data['title'];
+
+ $CONTchunk .= getid3_lib::BigEndian2String(strlen(@$this->tag_data['artist']), 2);
+ $CONTchunk .= @$this->tag_data['artist'];
+
+ $CONTchunk .= getid3_lib::BigEndian2String(strlen(@$this->tag_data['copyright']), 2);
+ $CONTchunk .= @$this->tag_data['copyright'];
+
+ $CONTchunk .= getid3_lib::BigEndian2String(strlen(@$this->tag_data['comment']), 2);
+ $CONTchunk .= @$this->tag_data['comment'];
+
+ if ($this->paddedlength > (strlen($CONTchunk) + 8)) {
+ $CONTchunk .= str_repeat("\x00", $this->paddedlength - strlen($CONTchunk) - 8);
+ }
+
+ $CONTchunk = 'CONT'.getid3_lib::BigEndian2String(strlen($CONTchunk) + 8, 4).$CONTchunk; // CONT chunk identifier + chunk length
+
+ return $CONTchunk;
+ }
+
+ function RemoveReal() {
+ // File MUST be writeable - CHMOD(646) at least
+ if (is_writeable($this->filename)) {
+ if ($fp_source = @fopen($this->filename, 'r+b')) {
+
+ // Initialize getID3 engine
+ $getID3 = new getID3;
+ $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('*', 'getID3')) {
+ ob_start();
+ if ($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, GETID3_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.') - '.strip_tags(ob_get_contents());
+
+ } else {
+
+ $this->errors[] = 'Could not open '.$tempfilename.' mode "wb" - '.strip_tags(ob_get_contents());
+
+ }
+ ob_end_clean();
+ }
+ fclose($fp_source);
+ return false;
+
+
+ } else {
+ $this->errors[] = 'Could not open '.$this->filename.' mode "r+b"';
+ return false;
+ }
+ }
+ $this->errors[] = 'File is not writeable: '.$this->filename;
+ return false;
+ }
+
+}
+
+?>
\ No newline at end of file
Added: plog/trunk/class/gallery/getid3/write.vorbiscomment.php
===================================================================
--- plog/trunk/class/gallery/getid3/write.vorbiscomment.php 2006-07-24 16:40:16 UTC (rev 3789)
+++ plog/trunk/class/gallery/getid3/write.vorbiscomment.php 2006-07-24 16:56:08 UTC (rev 3790)
@@ -0,0 +1,124 @@
+<?php
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info at getid3.org> //
+// available at http://getid3.sourceforge.net //
+// or http://www.getid3.org //
+/////////////////////////////////////////////////////////////////
+// See readme.txt for more details //
+/////////////////////////////////////////////////////////////////
+// //
+// write.vorbiscomment.php //
+// module for writing VorbisComment tags //
+// dependencies: /helperapps/vorbiscomment.exe //
+// ///
+/////////////////////////////////////////////////////////////////
+
+
+class getid3_write_vorbiscomment
+{
+
+ var $filename;
+ var $tag_data;
+ var $warnings = array(); // any non-critical errors will be stored here
+ var $errors = array(); // any critical errors will be stored here
+
+ function getid3_write_vorbiscomment() {
+ return true;
+ }
+
+ function WriteVorbisComment() {
+
+ if (!ini_get('safe_mode')) {
+
+ // Create file with new comments
+ $tempcommentsfilename = tempnam('*', 'getID3');
+ if ($fpcomments = @fopen($tempcommentsfilename, 'wb')) {
+
+ foreach ($this->tag_data as $key => $value) {
+ foreach ($value as $commentdata) {
+ fwrite($fpcomments, $this->CleanVorbisCommentName($key).'='.$commentdata."\n");
+ }
+ }
+ fclose($fpcomments);
+
+ } else {
+
+ $this->errors[] = 'failed to open temporary tags file "'.$tempcommentsfilename.'", tags not written';
+ return false;
+
+ }
+
+ $oldignoreuserabort = ignore_user_abort(true);
+ if (GETID3_OS_ISWINDOWS) {
+
+ if (file_exists(GETID3_HELPERAPPSDIR.'vorbiscomment.exe')) {
+ //$commandline = '"'.GETID3_HELPERAPPSDIR.'vorbiscomment.exe" -w --raw -c "'.$tempcommentsfilename.'" "'.str_replace('/', '\\', $this->filename).'"';
+ // vorbiscomment works fine if you copy-paste the above commandline into a command prompt,
+ // but refuses to work with `backtick` if there are "doublequotes" present around BOTH
+ // the metaflac pathname and the target filename. For whatever reason...??
+ // The solution is simply ensure that the metaflac pathname has no spaces,
+ // and therefore does not need to be quoted
+
+ // On top of that, if error messages are not always captured properly under Windows
+ // To at least see if there was a problem, compare file modification timestamps before and after writing
+ clearstatcache();
+ $timestampbeforewriting = filemtime($this->filename);
+
+ $commandline = GETID3_HELPERAPPSDIR.'vorbiscomment.exe -w --raw -c "'.$tempcommentsfilename.'" "'.$this->filename.'" 2>&1';
+ $VorbiscommentError = `$commandline`;
+
+ if (empty($VorbiscommentError)) {
+ clearstatcache();
+ if ($timestampbeforewriting == filemtime($this->filename)) {
+ $VorbiscommentError = 'File modification timestamp has not changed - it looks like the tags were not written';
+ }
+ }
+ } else {
+ $VorbiscommentError = 'vorbiscomment.exe not found in '.GETID3_HELPERAPPSDIR;
+ }
+
+ } else {
+
+ $commandline = 'vorbiscomment -w --raw -c "'.$tempcommentsfilename.'" "'.$this->filename.'" 2>&1';
+ $VorbiscommentError = `$commandline`;
+
+ }
+
+ // Remove temporary comments file
+ unlink($tempcommentsfilename);
+ ignore_user_abort($oldignoreuserabort);
+
+ if (!empty($VorbiscommentError)) {
+
+ $this->errors[] = 'system call to vorbiscomment failed with message: '."\n\n".$VorbiscommentError;
+ return false;
+
+ }
+
+ return true;
+ }
+
+ $this->errors[] = 'PHP running in Safe Mode (backtick operator not available) - cannot call vorbiscomment, tags not written';
+ return false;
+ }
+
+ function DeleteVorbisComment() {
+ $this->tag_data = array(array());
+ return $this->WriteVorbisComment();
+ }
+
+ function CleanVorbisCommentName($originalcommentname) {
+ // A case-insensitive field name that may consist of ASCII 0x20 through 0x7D, 0x3D ('=') excluded.
+ // ASCII 0x41 through 0x5A inclusive (A-Z) is to be considered equivalent to ASCII 0x61 through
+ // 0x7A inclusive (a-z).
+
+ // replace invalid chars with a space, return uppercase text
+ // Thanks Chris Bolt <chris-getid3Øbolt*cx> for improving this function
+ // note: ereg_replace() replaces nulls with empty string (not space)
+ return strtoupper(ereg_replace('[^ -<>-}]', ' ', str_replace("\x00", ' ', $originalcommentname)));
+
+ }
+
+}
+
+?>
\ No newline at end of file
More information about the pLog-svn
mailing list