Changeset 51852 in spip-zone


Ignore:
Timestamp:
Sep 26, 2011, 2:33:32 PM (8 years ago)
Author:
kent1@…
Message:

Mise à jour de getid3 en 1.9.0-20110620 (nécessite PHP 5)

Location:
_plugins_/getID3/getid3
Files:
1 deleted
65 edited

Legend:

Unmodified
Added
Removed
  • _plugins_/getID3/getid3/extension.cache.dbm.php

    r16273 r51852  
    7878                // Check for dba extension
    7979                if (!extension_loaded('dba')) {
    80                         die('PHP is not compiled with dba support, required to use DBM style cache.');
     80                        throw new Exception('PHP is not compiled with dba support, required to use DBM style cache.');
    8181                }
    8282
    8383                // Check for specific dba driver
    84                 if (function_exists('dba_handlers')) {  // PHP 4.3.0+
    85                         if (!in_array('db3', dba_handlers())) {
    86                                 die('PHP is not compiled --with '.$cache_type.' support, required to use DBM style cache.');
    87                         }
    88                 }
    89                 else { // PHP <= 4.2.3
    90                         ob_start(); // nasty, buy the only way to check...
    91                         phpinfo();
    92                         $contents = ob_get_contents();
    93                         ob_end_clean();
    94                         if (!strstr($contents, $cache_type)) {
    95                                 die('PHP is not compiled --with '.$cache_type.' support, required to use DBM style cache.');
    96                         }
     84                if (!function_exists('dba_handlers') || !in_array($cache_type, dba_handlers())) {
     85                        throw new Exception('PHP is not compiled --with '.$cache_type.' support, required to use DBM style cache.');
    9786                }
    9887
     
    10089                if (!file_exists($lock_filename)) {
    10190                        if (!touch($lock_filename)) {
    102                                 die('failed to create lock file: ' . $lock_filename);
     91                                throw new Exception('failed to create lock file: '.$lock_filename);
    10392                        }
    10493                }
     
    10695                // Open lock file for writing
    10796                if (!is_writeable($lock_filename)) {
    108                         die('lock file: ' . $lock_filename . ' is not writable');
     97                        throw new Exception('lock file: '.$lock_filename.' is not writable');
    10998                }
    11099                $this->lock = fopen($lock_filename, 'w');
     
    116105                if (!file_exists($dbm_filename)) {
    117106                        if (!touch($dbm_filename)) {
    118                                 die('failed to create dbm file: ' . $dbm_filename);
     107                                throw new Exception('failed to create dbm file: '.$dbm_filename);
    119108                        }
    120109                }
    121110
    122111                // Try to open dbm file for writing
    123                 $this->dba = @dba_open($dbm_filename, 'w', $cache_type);
     112                $this->dba = dba_open($dbm_filename, 'w', $cache_type);
    124113                if (!$this->dba) {
    125114
     
    128117
    129118                        if (!$this->dba) {
    130                                 die('failed to create dbm file: ' . $dbm_filename);
     119                                throw new Exception('failed to create dbm file: '.$dbm_filename);
    131120                        }
    132121
    133122                        // Insert getID3 version number
    134                         dba_insert(GETID3_VERSION, GETID3_VERSION, $this->dba);
     123                        dba_insert($this::VERSION, $this::VERSION, $this->dba);
    135124                }
    136125
     
    143132
    144133                // Check version number and clear cache if changed
    145                 if (dba_fetch(GETID3_VERSION, $this->dba) != GETID3_VERSION) {
     134                if (dba_fetch($this::VERSION, $this->dba) != $this::VERSION) {
    146135                        $this->clear_cache();
    147136                }
     
    156145
    157146                // Close dbm file
    158                 @dba_close($this->dba);
     147                dba_close($this->dba);
    159148
    160149                // Release exclusive lock
    161                 @flock($this->lock, LOCK_UN);
     150                flock($this->lock, LOCK_UN);
    162151
    163152                // Close lock file
    164                 @fclose($this->lock);
     153                fclose($this->lock);
    165154        }
    166155
     
    177166
    178167                if (!$this->dba) {
    179                         die('failed to clear cache/recreate dbm file: ' . $this->dbm_filename);
     168                        throw new Exception('failed to clear cache/recreate dbm file: '.$this->dbm_filename);
    180169                }
    181170
    182171                // Insert getID3 version number
    183                 dba_insert(GETID3_VERSION, GETID3_VERSION, $this->dba);
    184 
    185                 // Reregister shutdown function
     172                dba_insert($this::VERSION, $this::VERSION, $this->dba);
     173
     174                // Re-register shutdown function
    186175                register_shutdown_function(array($this, '__destruct'));
    187176        }
     
    195184
    196185                        // Calc key     filename::mod_time::size    - should be unique
    197                         $key = $filename . '::' . filemtime($filename) . '::' . filesize($filename);
     186                        $key = $filename.'::'.filemtime($filename).'::'.filesize($filename);
    198187
    199188                        // Loopup key
  • _plugins_/getID3/getid3/extension.cache.mysql.php

    r16273 r51852  
    8383                // Check for mysql support
    8484                if (!function_exists('mysql_pconnect')) {
    85                         die('PHP not compiled with mysql support.');
     85                        throw new Exception('PHP not compiled with mysql support.');
    8686                }
    8787
     
    8989                $this->connection = mysql_pconnect($host, $username, $password);
    9090                if (!$this->connection) {
    91                         die('mysql_pconnect() failed - check permissions and spelling.');
     91                        throw new Exception('mysql_pconnect() failed - check permissions and spelling.');
    9292                }
    9393
    9494                // Select database
    9595                if (!mysql_select_db($database, $this->connection)) {
    96                         die('Cannot use database '.$database);
     96                        throw new Exception('Cannot use database '.$database);
    9797                }
    9898
     
    101101
    102102                // Check version number and clear cache if changed
    103                 $this->cursor = mysql_query("SELECT `value` FROM `getid3_cache` WHERE (`filename` = '".GETID3_VERSION."') AND (`filesize` = '-1') AND (`filetime` = '-1') AND (`analyzetime` = '-1')", $this->connection);
    104                 list($version) = @mysql_fetch_array($this->cursor);
    105                 if ($version != GETID3_VERSION) {
     103                $version = '';
     104                if ($this->cursor = mysql_query("SELECT `value` FROM `getid3_cache` WHERE (`filename` = '".mysql_real_escape_string($this::VERSION)."') AND (`filesize` = '-1') AND (`filetime` = '-1') AND (`analyzetime` = '-1')", $this->connection)) {
     105                        list($version) = mysql_fetch_array($this->cursor);
     106                }
     107                if ($version != $this::VERSION) {
    106108                        $this->clear_cache();
    107109                }
     
    116118
    117119                $this->cursor = mysql_query("DELETE FROM `getid3_cache`", $this->connection);
    118                 $this->cursor = mysql_query("INSERT INTO `getid3_cache` VALUES ('".GETID3_VERSION."', -1, -1, -1, '".GETID3_VERSION."')", $this->connection);
     120                $this->cursor = mysql_query("INSERT INTO `getid3_cache` VALUES ('".$this::VERSION."', -1, -1, -1, '".$this::VERSION."')", $this->connection);
    119121        }
    120122
     
    129131                        $filetime = filemtime($filename);
    130132                        $filesize = filesize($filename);
    131                         $filenam2 = mysql_escape_string($filename);
    132133
    133134                        // Loopup file
    134                         $this->cursor = mysql_query("SELECT `value` FROM `getid3_cache` WHERE (`filename`='".$filenam2."') AND (`filesize`='".$filesize."') AND (`filetime`='".$filetime."')", $this->connection);
    135                         list($result) = @mysql_fetch_array($this->cursor);
    136 
    137                         // Hit
    138                         if ($result) {
    139                                 return unserialize($result);
     135                        $result = '';
     136                        if ($this->cursor = mysql_query("SELECT `value` FROM `getid3_cache` WHERE (`filename` = '".mysql_real_escape_string($filename)."') AND (`filesize` = '".mysql_real_escape_string($filesize)."') AND (`filetime` = '".mysql_real_escape_string($filetime)."')", $this->connection)) {
     137                                // Hit
     138                                list($result) = mysql_fetch_array($this->cursor);
     139                                return unserialize(base64_decode($result));
    140140                        }
    141141                }
    142142
    143143                // Miss
    144                 $result = parent::analyze($filename);
     144                $analysis = parent::analyze($filename);
    145145
    146146                // Save result
    147147                if (file_exists($filename)) {
    148                         $res2 = mysql_escape_string(serialize($result));
    149                         $this->cursor = mysql_query("INSERT INTO `getid3_cache` (`filename`, `filesize`, `filetime`, `analyzetime`, `value`) VALUES ('".$filenam2."', '".$filesize."', '".$filetime."', '".time()."', '".$res2."')", $this->connection);
     148                        $this->cursor = mysql_query("INSERT INTO `getid3_cache` (`filename`, `filesize`, `filetime`, `analyzetime`, `value`) VALUES ('".mysql_real_escape_string($filename)."', '".mysql_real_escape_string($filesize)."', '".mysql_real_escape_string($filetime)."', '".mysql_real_escape_string(time())."', '".mysql_real_escape_string(base64_encode(serialize($analysis)))."')", $this->connection);
    150149                }
    151150                return $result;
     
    155154
    156155        // private: (re)create sql table
    157         function create_table($drop = false) {
     156        function create_table($drop=false) {
    158157
    159158                $this->cursor = mysql_query("CREATE TABLE IF NOT EXISTS `getid3_cache` (
  • _plugins_/getID3/getid3/getid3.lib.php

    r44570 r51852  
    1515{
    1616
    17         function PrintHexBytes($string, $hex=true, $spaces=true, $htmlsafe=true) {
     17        static function PrintHexBytes($string, $hex=true, $spaces=true, $htmlsafe=true) {
    1818                $returnstring = '';
    1919                for ($i = 0; $i < strlen($string); $i++) {
     
    2121                                $returnstring .= str_pad(dechex(ord($string{$i})), 2, '0', STR_PAD_LEFT);
    2222                        } else {
    23                                 $returnstring .= ' '.(preg_match("/[\x20-\x7E]/", $string{$i}) ? $string{$i} : '�');
     23                                $returnstring .= ' '.(preg_match("#[\x20-\x7E]#", $string{$i}) ? $string{$i} : '¤');
    2424                        }
    2525                        if ($spaces) {
     
    3333        }
    3434
    35         function SafeStripSlashes($text) {
    36                 if (get_magic_quotes_gpc()) {
    37                         return stripslashes($text);
    38                 }
    39                 return $text;
    40         }
    41 
    42 
    43         function trunc($floatnumber) {
     35        static function trunc($floatnumber) {
    4436                // truncates a floating-point number at the decimal point
    4537                // returns int (if possible, otherwise float)
     
    5143                        $truncatednumber = 0;
    5244                }
    53                 if ($truncatednumber <= 1073741824) { // 2^30
     45                if (getid3_lib::intValueSupported($truncatednumber)) {
    5446                        $truncatednumber = (int) $truncatednumber;
    5547                }
     
    5850
    5951
    60         function CastAsInt($floatnum) {
     52        static function safe_inc(&$variable, $increment=1) {
     53                if (isset($variable)) {
     54                        $variable += $increment;
     55                } else {
     56                        $variable = $increment;
     57                }
     58                return true;
     59        }
     60
     61        static function CastAsInt($floatnum) {
    6162                // convert to float if not already
    6263                $floatnum = (float) $floatnum;
     
    6566                if (getid3_lib::trunc($floatnum) == $floatnum) {
    6667                        // it's not floating point
    67                         if ($floatnum <= 1073741824) { // 2^30
     68                        if (getid3_lib::intValueSupported($floatnum)) {
    6869                                // it's within int range
    6970                                $floatnum = (int) $floatnum;
     
    7374        }
    7475
    75 
    76         function DecimalBinary2Float($binarynumerator) {
     76        public static function intValueSupported($num) {
     77                // check if integers are 64-bit
     78                static $hasINT64 = null;
     79                if ($hasINT64 === null) { // 10x faster than is_null()
     80                        $hasINT64 = is_int(pow(2, 31)); // 32-bit int are limited to (2^31)-1
     81                        if (!$hasINT64 && !defined('PHP_INT_MIN')) {
     82                                define('PHP_INT_MIN', ~PHP_INT_MAX);
     83                        }
     84                }
     85                // if integers are 64-bit - no other check required
     86                if ($hasINT64 || (($num <= PHP_INT_MAX) && ($num >= PHP_INT_MIN))) {
     87                        return true;
     88                }
     89                return false;
     90        }
     91
     92        static function DecimalizeFraction($fraction) {
     93                list($numerator, $denominator) = explode('/', $fraction);
     94                return $numerator / ($denominator ? $denominator : 1);
     95        }
     96
     97
     98        static function DecimalBinary2Float($binarynumerator) {
    7799                $numerator   = getid3_lib::Bin2Dec($binarynumerator);
    78100                $denominator = getid3_lib::Bin2Dec('1'.str_repeat('0', strlen($binarynumerator)));
     
    81103
    82104
    83         function NormalizeBinaryPoint($binarypointnumber, $maxbits=52) {
     105        static function NormalizeBinaryPoint($binarypointnumber, $maxbits=52) {
    84106                // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/binary.html
    85107                if (strpos($binarypointnumber, '.') === false) {
     
    105127
    106128
    107         function Float2BinaryDecimal($floatvalue) {
     129        static function Float2BinaryDecimal($floatvalue) {
    108130                // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/binary.html
    109131                $maxbits = 128; // to how many bits of precision should the calculations be taken?
     
    121143
    122144
    123         function Float2String($floatvalue, $bits) {
     145        static function Float2String($floatvalue, $bits) {
    124146                // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee-expl.html
    125147                switch ($bits) {
     
    152174
    153175
    154         function LittleEndian2Float($byteword) {
     176        static function LittleEndian2Float($byteword) {
    155177                return getid3_lib::BigEndian2Float(strrev($byteword));
    156178        }
    157179
    158180
    159         function BigEndian2Float($byteword) {
     181        static function BigEndian2Float($byteword) {
    160182                // ANSI/IEEE Standard 754-1985, Standard for Binary Floating Point Arithmetic
    161183                // http://www.psc.edu/general/software/packages/ieee/ieee.html
     
    164186                $bitword = getid3_lib::BigEndian2Bin($byteword);
    165187                if (!$bitword) {
    166             return 0;
    167         }
     188                        return 0;
     189                }
    168190                $signbit = $bitword{0};
    169191
     
    235257
    236258
    237         function BigEndian2Int($byteword, $synchsafe=false, $signed=false) {
     259        static function BigEndian2Int($byteword, $synchsafe=false, $signed=false) {
    238260                $intvalue = 0;
    239261                $bytewordlen = strlen($byteword);
     262                if ($bytewordlen == 0) {
     263                        return false;
     264                }
    240265                for ($i = 0; $i < $bytewordlen; $i++) {
    241266                        if ($synchsafe) { // disregard MSB, effectively 7-bit bytes
    242                                 $intvalue = $intvalue | (ord($byteword{$i}) & 0x7F) << (($bytewordlen - 1 - $i) * 7);
     267                                //$intvalue = $intvalue | (ord($byteword{$i}) & 0x7F) << (($bytewordlen - 1 - $i) * 7); // faster, but runs into problems past 2^31 on 32-bit systems
     268                                $intvalue += (ord($byteword{$i}) & 0x7F) * pow(2, ($bytewordlen - 1 - $i) * 7);
    243269                        } else {
    244270                                $intvalue += ord($byteword{$i}) * pow(256, ($bytewordlen - 1 - $i));
     
    247273                if ($signed && !$synchsafe) {
    248274                        // synchsafe ints are not allowed to be signed
    249                         switch ($bytewordlen) {
    250                                 case 1:
    251                                 case 2:
    252                                 case 3:
    253                                 case 4:
    254                                         $signmaskbit = 0x80 << (8 * ($bytewordlen - 1));
    255                                         if ($intvalue & $signmaskbit) {
    256                                                 $intvalue = 0 - ($intvalue & ($signmaskbit - 1));
    257                                         }
    258                                         break;
    259 
    260                                 default:
    261                                         die('ERROR: Cannot have signed integers larger than 32-bits in getid3_lib::BigEndian2Int()');
    262                                         break;
     275                        if ($bytewordlen <= PHP_INT_SIZE) {
     276                                $signMaskBit = 0x80 << (8 * ($bytewordlen - 1));
     277                                if ($intvalue & $signMaskBit) {
     278                                        $intvalue = 0 - ($intvalue & ($signMaskBit - 1));
     279                                }
     280                        } else {
     281                                throw new Exception('ERROR: Cannot have signed integers larger than '.(8 * PHP_INT_SIZE).'-bits ('.strlen($byteword).') in getid3_lib::BigEndian2Int()');
     282                                break;
    263283                        }
    264284                }
     
    267287
    268288
    269         function LittleEndian2Int($byteword, $signed=false) {
     289        static function LittleEndian2Int($byteword, $signed=false) {
    270290                return getid3_lib::BigEndian2Int(strrev($byteword), false, $signed);
    271291        }
    272292
    273293
    274         function BigEndian2Bin($byteword) {
     294        static function BigEndian2Bin($byteword) {
    275295                $binvalue = '';
    276296                $bytewordlen = strlen($byteword);
     
    282302
    283303
    284         function BigEndian2String($number, $minbytes=1, $synchsafe=false, $signed=false) {
     304        static function BigEndian2String($number, $minbytes=1, $synchsafe=false, $signed=false) {
    285305                if ($number < 0) {
    286                         return false;
     306                        throw new Exception('ERROR: getid3_lib::BigEndian2String() does not support negative numbers');
    287307                }
    288308                $maskbyte = (($synchsafe || $signed) ? 0x7F : 0xFF);
    289309                $intstring = '';
    290310                if ($signed) {
    291                         if ($minbytes > 4) {
    292                                 die('ERROR: Cannot have signed integers larger than 32-bits in getid3_lib::BigEndian2String()');
     311                        if ($minbytes > PHP_INT_SIZE) {
     312                                throw new Exception('ERROR: Cannot have signed integers larger than '.(8 * PHP_INT_SIZE).'-bits in getid3_lib::BigEndian2String()');
    293313                        }
    294314                        $number = $number & (0x80 << (8 * ($minbytes - 1)));
     
    303323
    304324
    305         function Dec2Bin($number) {
     325        static function Dec2Bin($number) {
    306326                while ($number >= 256) {
    307327                        $bytes[] = (($number / 256) - (floor($number / 256))) * 256;
     
    317337
    318338
    319         function Bin2Dec($binstring, $signed=false) {
     339        static function Bin2Dec($binstring, $signed=false) {
    320340                $signmult = 1;
    321341                if ($signed) {
     
    333353
    334354
    335         function Bin2String($binstring) {
     355        static function Bin2String($binstring) {
    336356                // return 'hi' for input of '0110100001101001'
    337357                $string = '';
     
    344364
    345365
    346         function LittleEndian2String($number, $minbytes=1, $synchsafe=false) {
     366        static function LittleEndian2String($number, $minbytes=1, $synchsafe=false) {
    347367                $intstring = '';
    348368                while ($number > 0) {
     
    359379
    360380
    361         function array_merge_clobber($array1, $array2) {
    362                 // written by kchireability*com
     381        static function array_merge_clobber($array1, $array2) {
     382                // written by kcØhireability*com
    363383                // taken from http://www.php.net/manual/en/function.array-merge-recursive.php
    364384                if (!is_array($array1) || !is_array($array2)) {
     
    377397
    378398
    379         function array_merge_noclobber($array1, $array2) {
     399        static function array_merge_noclobber($array1, $array2) {
    380400                if (!is_array($array1) || !is_array($array2)) {
    381401                        return false;
     
    393413
    394414
    395         function fileextension($filename, $numextensions=1) {
     415        static function ksort_recursive(&$theArray) {
     416                ksort($theArray);
     417                foreach ($theArray as $key => $value) {
     418                        if (is_array($value)) {
     419                                self::ksort_recursive($theArray[$key]);
     420                        }
     421                }
     422                return true;
     423        }
     424
     425        static function fileextension($filename, $numextensions=1) {
    396426                if (strstr($filename, '.')) {
    397427                        $reversedfilename = strrev($filename);
     
    409439
    410440
    411         function PlaytimeString($playtimeseconds) {
     441        static function PlaytimeString($playtimeseconds) {
    412442                $sign = (($playtimeseconds < 0) ? '-' : '');
    413443                $playtimeseconds = abs($playtimeseconds);
     
    422452
    423453
    424         function image_type_to_mime_type($imagetypeid) {
    425                 // only available in PHP v4.3.0+
    426                 static $image_type_to_mime_type = array();
    427                 if (empty($image_type_to_mime_type)) {
    428                         $image_type_to_mime_type[1]  = 'image/gif';                     // GIF
    429                         $image_type_to_mime_type[2]  = 'image/jpeg';                    // JPEG
    430                         $image_type_to_mime_type[3]  = 'image/png';                     // PNG
    431                         $image_type_to_mime_type[4]  = 'application/x-shockwave-flash'; // Flash
    432                         $image_type_to_mime_type[5]  = 'image/psd';                     // PSD
    433                         $image_type_to_mime_type[6]  = 'image/bmp';                     // BMP
    434                         $image_type_to_mime_type[7]  = 'image/tiff';                    // TIFF: little-endian (Intel)
    435                         $image_type_to_mime_type[8]  = 'image/tiff';                    // TIFF: big-endian (Motorola)
    436                         //$image_type_to_mime_type[9]  = 'image/jpc';                   // JPC
    437                         //$image_type_to_mime_type[10] = 'image/jp2';                   // JPC
    438                         //$image_type_to_mime_type[11] = 'image/jpx';                   // JPC
    439                         //$image_type_to_mime_type[12] = 'image/jb2';                   // JPC
    440                         $image_type_to_mime_type[13] = 'application/x-shockwave-flash'; // Shockwave
    441                         $image_type_to_mime_type[14] = 'image/iff';                     // IFF
    442                 }
    443                 return (isset($image_type_to_mime_type[$imagetypeid]) ? $image_type_to_mime_type[$imagetypeid] : 'application/octet-stream');
    444         }
    445 
    446 
    447         function DateMac2Unix($macdate) {
     454        static function DateMac2Unix($macdate) {
    448455                // Macintosh timestamp: seconds since 00:00h January 1, 1904
    449456                // UNIX timestamp:      seconds since 00:00h January 1, 1970
     
    452459
    453460
    454         function FixedPoint8_8($rawdata) {
     461        static function FixedPoint8_8($rawdata) {
    455462                return getid3_lib::BigEndian2Int(substr($rawdata, 0, 1)) + (float) (getid3_lib::BigEndian2Int(substr($rawdata, 1, 1)) / pow(2, 8));
    456463        }
    457464
    458465
    459         function FixedPoint16_16($rawdata) {
     466        static function FixedPoint16_16($rawdata) {
    460467                return getid3_lib::BigEndian2Int(substr($rawdata, 0, 2)) + (float) (getid3_lib::BigEndian2Int(substr($rawdata, 2, 2)) / pow(2, 16));
    461468        }
    462469
    463470
    464         function FixedPoint2_30($rawdata) {
     471        static function FixedPoint2_30($rawdata) {
    465472                $binarystring = getid3_lib::BigEndian2Bin($rawdata);
    466                 return getid3_lib::Bin2Dec(substr($binarystring, 0, 2)) + (float) (getid3_lib::Bin2Dec(substr($binarystring, 2, 30)) / 1073741824);
    467         }
    468 
    469 
    470         function CreateDeepArray($ArrayPath, $Separator, $Value) {
     473                return getid3_lib::Bin2Dec(substr($binarystring, 0, 2)) + (float) (getid3_lib::Bin2Dec(substr($binarystring, 2, 30)) / pow(2, 30));
     474        }
     475
     476
     477        static function CreateDeepArray($ArrayPath, $Separator, $Value) {
    471478                // assigns $Value to a nested array path:
    472479                //   $foo = getid3_lib::CreateDeepArray('/path/to/my', '/', 'file.txt')
     
    486493        }
    487494
    488         function array_max($arraydata, $returnkey=false) {
     495        static function array_max($arraydata, $returnkey=false) {
    489496                $maxvalue = false;
    490497                $maxkey = false;
     
    500507        }
    501508
    502         function array_min($arraydata, $returnkey=false) {
     509        static function array_min($arraydata, $returnkey=false) {
    503510                $minvalue = false;
    504511                $minkey = false;
     
    515522
    516523
    517         function md5_file($file) {
    518 
    519                 // md5_file() exists in PHP 4.2.0+.
    520                 if (function_exists('md5_file')) {
    521                         return md5_file($file);
    522                 }
    523 
    524                 if (GETID3_OS_ISWINDOWS) {
    525 
    526                         $RequiredFiles = array('cygwin1.dll', 'md5sum.exe');
    527                         foreach ($RequiredFiles as $required_file) {
    528                                 if (!is_readable(GETID3_HELPERAPPSDIR.$required_file)) {
    529                                         die(implode(' and ', $RequiredFiles).' are required in '.GETID3_HELPERAPPSDIR.' for getid3_lib::md5_file() to function under Windows in PHP < v4.2.0');
    530                                 }
    531                         }
    532                         $commandline = GETID3_HELPERAPPSDIR.'md5sum.exe "'.str_replace('/', DIRECTORY_SEPARATOR, $file).'"';
    533                         if (preg_match("/^[\\]?([0-9a-f]{32})/", strtolower(`$commandline`), $r)) {
    534                                 return $r[1];
    535                         }
    536 
    537                 } else {
    538 
    539                         // The following works under UNIX only
    540                         $file = str_replace('`', '\\`', $file);
    541                         if (preg_match("/^([0-9a-f]{32})[ \t\n\r]/", `md5sum "$file"`, $r)) {
    542                                 return $r[1];
    543                         }
    544 
    545                 }
    546                 return false;
    547         }
    548 
    549 
    550         function sha1_file($file) {
    551 
    552                 // sha1_file() exists in PHP 4.3.0+.
    553                 if (function_exists('sha1_file')) {
    554                         return sha1_file($file);
    555                 }
    556 
    557                 $file = str_replace('`', '\\`', $file);
    558 
    559                 if (GETID3_OS_ISWINDOWS) {
    560 
    561                         $RequiredFiles = array('cygwin1.dll', 'sha1sum.exe');
    562                         foreach ($RequiredFiles as $required_file) {
    563                                 if (!is_readable(GETID3_HELPERAPPSDIR.$required_file)) {
    564                                         die(implode(' and ', $RequiredFiles).' are required in '.GETID3_HELPERAPPSDIR.' for getid3_lib::sha1_file() to function under Windows in PHP < v4.3.0');
    565                                 }
    566                         }
    567                         $commandline = GETID3_HELPERAPPSDIR.'sha1sum.exe "'.str_replace('/', DIRECTORY_SEPARATOR, $file).'"';
    568                         if (preg_match("/^sha1=([0-9a-f]{40})/", strtolower(`$commandline`), $r)) {
    569                                 return $r[1];
    570                         }
    571 
    572                 } else {
    573 
    574                         $commandline = 'sha1sum '.escapeshellarg($file).'';
    575                         if (preg_match("/^([0-9a-f]{40})[ \t\n\r]/", strtolower(`$commandline`), $r)) {
    576                                 return $r[1];
    577                         }
    578 
    579                 }
    580 
    581                 return false;
    582         }
    583 
    584 
    585         // Allan Hansen <ah�artemis*dk>
     524        // Allan Hansen <ahØartemis*dk>
    586525        // getid3_lib::md5_data() - returns md5sum for a file from startuing position to absolute end position
    587         function hash_data($file, $offset, $end, $algorithm) {
    588 
     526        static function hash_data($file, $offset, $end, $algorithm) {
     527                static $tempdir = '';
     528                if (!getid3_lib::intValueSupported($end)) {
     529                        return false;
     530                }
    589531                switch ($algorithm) {
    590532                        case 'md5':
     
    603545
    604546                        default:
    605                                 die('Invalid algorithm ('.$algorithm.') in getid3_lib::hash_data()');
     547                                throw new Exception('Invalid algorithm ('.$algorithm.') in getid3_lib::hash_data()');
    606548                                break;
    607549                }
     
    634576
    635577                        }
    636                         if ((bool) ini_get('safe_mode')) {
    637                                 $ThisFileInfo['warning'][] = 'PHP running in Safe Mode - backtick operator not available, using slower non-system-call '.$algorithm.' algorithm';
     578                        if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) {
     579                                //throw new Exception('PHP running in Safe Mode - backtick operator not available, using slower non-system-call '.$algorithm.' algorithm');
    638580                                break;
    639581                        }
     
    641583                }
    642584
     585                if (empty($tempdir)) {
     586                        // yes this is ugly, feel free to suggest a better way
     587                        require_once(dirname(__FILE__).'/getid3.php');
     588                        $getid3_temp = new getID3();
     589                        $tempdir = $getid3_temp->tempdir;
     590                        unset($getid3_temp);
     591                }
    643592                // try to create a temporary file in the system temp directory - invalid dirname should force to system temp dir
    644                 if (($data_filename = tempnam('*', 'getID3')) === false) {
    645                         // can't find anywhere to create a temp file, just die
     593                if (($data_filename = tempnam($tempdir, 'gI3')) === false) {
     594                        // can't find anywhere to create a temp file, just fail
    646595                        return false;
    647596                }
     
    651600
    652601                // copy parts of file
    653                 if ($fp = @fopen($file, 'rb')) {
    654 
    655                         if ($fp_data = @fopen($data_filename, 'wb')) {
    656 
    657                                 fseek($fp, $offset, SEEK_SET);
    658                                 $byteslefttowrite = $end - $offset;
    659                                 while (($byteslefttowrite > 0) && ($buffer = fread($fp, GETID3_FREAD_BUFFER_SIZE))) {
    660                                         $byteswritten = fwrite($fp_data, $buffer, $byteslefttowrite);
    661                                         $byteslefttowrite -= $byteswritten;
    662                                 }
    663                                 fclose($fp_data);
    664                                 $result = getid3_lib::$hash_function($data_filename);
    665 
    666                         }
    667                         fclose($fp);
     602                try {
     603                        getid3_lib::CopyFileParts($file, $data_filename, $offset, $end - $offset);
     604                        $result = $hash_function($data_filename);
     605                } catch (Exception $e) {
     606                        throw new Exception('getid3_lib::CopyFileParts() failed in getid_lib::hash_data(): '.$e->getMessage());
    668607                }
    669608                unlink($data_filename);
     
    671610        }
    672611
    673 
    674         function iconv_fallback_int_utf8($charval) {
     612        static function CopyFileParts($filename_source, $filename_dest, $offset, $length) {
     613                if (!getid3_lib::intValueSupported($offset + $length)) {
     614                        throw new Exception('cannot copy file portion, it extends beyond the '.round(PHP_INT_MAX / 1073741824).'GB limit');
     615                }
     616                if (is_readable($filename_source) && is_file($filename_source) && ($fp_src = fopen($filename_source, 'rb'))) {
     617                        if (is_writable($filename_dest) && is_file($filename_dest) && ($fp_dest = fopen($filename_dest, 'wb'))) {
     618                                if (fseek($fp_src, $offset, SEEK_SET) == 0) {
     619                                        $byteslefttowrite = $length;
     620                                        while (($byteslefttowrite > 0) && ($buffer = fread($fp_src, min($byteslefttowrite, $this->getid3->fread_buffer_size())))) {
     621                                                $byteswritten = fwrite($fp_dest, $buffer, $byteslefttowrite);
     622                                                $byteslefttowrite -= $byteswritten;
     623                                        }
     624                                        return true;
     625                                } else {
     626                                        throw new Exception('failed to seek to offset '.$offset.' in '.$this->info['filenamepath']);
     627                                }
     628                                fclose($fp_dest);
     629                        } else {
     630                                throw new Exception('failed to open file for reading '.$this->info['filenamepath']);
     631                        }
     632                        fclose($fp_src);
     633                } else {
     634                        throw new Exception('failed to create file for writing '.$dest);
     635                }
     636                return false;
     637        }
     638
     639        static function iconv_fallback_int_utf8($charval) {
    675640                if ($charval < 128) {
    676641                        // 0bbbbbbb
     
    678643                } elseif ($charval < 2048) {
    679644                        // 110bbbbb 10bbbbbb
    680                         $newcharstring  = chr(($charval >> 6) | 0xC0);
     645                        $newcharstring  = chr(($charval >>   6) | 0xC0);
    681646                        $newcharstring .= chr(($charval & 0x3F) | 0x80);
    682647                } elseif ($charval < 65536) {
    683648                        // 1110bbbb 10bbbbbb 10bbbbbb
    684                         $newcharstring  = chr(($charval >> 12) | 0xE0);
    685                         $newcharstring .= chr(($charval >>  6) | 0xC0);
     649                        $newcharstring  = chr(($charval >>  12) | 0xE0);
     650                        $newcharstring .= chr(($charval >>   6) | 0xC0);
    686651                        $newcharstring .= chr(($charval & 0x3F) | 0x80);
    687652                } else {
    688653                        // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb
    689                         $newcharstring  = chr(($charval >> 18) | 0xF0);
    690                         $newcharstring .= chr(($charval >> 12) | 0xC0);
    691                         $newcharstring .= chr(($charval >>  6) | 0xC0);
     654                        $newcharstring  = chr(($charval >>  18) | 0xF0);
     655                        $newcharstring .= chr(($charval >>  12) | 0xC0);
     656                        $newcharstring .= chr(($charval >>   6) | 0xC0);
    692657                        $newcharstring .= chr(($charval & 0x3F) | 0x80);
    693658                }
     
    696661
    697662        // ISO-8859-1 => UTF-8
    698         function iconv_fallback_iso88591_utf8($string, $bom=false) {
     663        static function iconv_fallback_iso88591_utf8($string, $bom=false) {
    699664                if (function_exists('utf8_encode')) {
    700665                        return utf8_encode($string);
     
    713678
    714679        // ISO-8859-1 => UTF-16BE
    715         function iconv_fallback_iso88591_utf16be($string, $bom=false) {
     680        static function iconv_fallback_iso88591_utf16be($string, $bom=false) {
    716681                $newcharstring = '';
    717682                if ($bom) {
     
    725690
    726691        // ISO-8859-1 => UTF-16LE
    727         function iconv_fallback_iso88591_utf16le($string, $bom=false) {
     692        static function iconv_fallback_iso88591_utf16le($string, $bom=false) {
    728693                $newcharstring = '';
    729694                if ($bom) {
     
    737702
    738703        // ISO-8859-1 => UTF-16LE (BOM)
    739         function iconv_fallback_iso88591_utf16($string) {
     704        static function iconv_fallback_iso88591_utf16($string) {
    740705                return getid3_lib::iconv_fallback_iso88591_utf16le($string, true);
    741706        }
    742707
    743708        // UTF-8 => ISO-8859-1
    744         function iconv_fallback_utf8_iso88591($string) {
     709        static function iconv_fallback_utf8_iso88591($string) {
    745710                if (function_exists('utf8_decode')) {
    746711                        return utf8_decode($string);
     
    754719                                // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb
    755720                                $charval = ((ord($string{($offset + 0)}) & 0x07) << 18) &
    756                                            ((ord($string{($offset + 1)}) & 0x3F) << 12) &
    757                                            ((ord($string{($offset + 2)}) & 0x3F) <<  6) &
    758                                             (ord($string{($offset + 3)}) & 0x3F);
     721                                                   ((ord($string{($offset + 1)}) & 0x3F) << 12) &
     722                                                   ((ord($string{($offset + 2)}) & 0x3F) <<  6) &
     723                                                        (ord($string{($offset + 3)}) & 0x3F);
    759724                                $offset += 4;
    760725                        } elseif ((ord($string{$offset}) | 0x0F) == 0xEF) {
    761726                                // 1110bbbb 10bbbbbb 10bbbbbb
    762727                                $charval = ((ord($string{($offset + 0)}) & 0x0F) << 12) &
    763                                            ((ord($string{($offset + 1)}) & 0x3F) <<  6) &
    764                                             (ord($string{($offset + 2)}) & 0x3F);
     728                                                   ((ord($string{($offset + 1)}) & 0x3F) <<  6) &
     729                                                        (ord($string{($offset + 2)}) & 0x3F);
    765730                                $offset += 3;
    766731                        } elseif ((ord($string{$offset}) | 0x1F) == 0xDF) {
    767732                                // 110bbbbb 10bbbbbb
    768733                                $charval = ((ord($string{($offset + 0)}) & 0x1F) <<  6) &
    769                                             (ord($string{($offset + 1)}) & 0x3F);
     734                                                        (ord($string{($offset + 1)}) & 0x3F);
    770735                                $offset += 2;
    771736                        } elseif ((ord($string{$offset}) | 0x7F) == 0x7F) {
     
    786751
    787752        // UTF-8 => UTF-16BE
    788         function iconv_fallback_utf8_utf16be($string, $bom=false) {
     753        static function iconv_fallback_utf8_utf16be($string, $bom=false) {
    789754                $newcharstring = '';
    790755                if ($bom) {
     
    797762                                // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb
    798763                                $charval = ((ord($string{($offset + 0)}) & 0x07) << 18) &
    799                                            ((ord($string{($offset + 1)}) & 0x3F) << 12) &
    800                                            ((ord($string{($offset + 2)}) & 0x3F) <<  6) &
    801                                             (ord($string{($offset + 3)}) & 0x3F);
     764                                                   ((ord($string{($offset + 1)}) & 0x3F) << 12) &
     765                                                   ((ord($string{($offset + 2)}) & 0x3F) <<  6) &
     766                                                        (ord($string{($offset + 3)}) & 0x3F);
    802767                                $offset += 4;
    803768                        } elseif ((ord($string{$offset}) | 0x0F) == 0xEF) {
    804769                                // 1110bbbb 10bbbbbb 10bbbbbb
    805770                                $charval = ((ord($string{($offset + 0)}) & 0x0F) << 12) &
    806                                            ((ord($string{($offset + 1)}) & 0x3F) <<  6) &
    807                                             (ord($string{($offset + 2)}) & 0x3F);
     771                                                   ((ord($string{($offset + 1)}) & 0x3F) <<  6) &
     772                                                        (ord($string{($offset + 2)}) & 0x3F);
    808773                                $offset += 3;
    809774                        } elseif ((ord($string{$offset}) | 0x1F) == 0xDF) {
    810775                                // 110bbbbb 10bbbbbb
    811776                                $charval = ((ord($string{($offset + 0)}) & 0x1F) <<  6) &
    812                                             (ord($string{($offset + 1)}) & 0x3F);
     777                                                        (ord($string{($offset + 1)}) & 0x3F);
    813778                                $offset += 2;
    814779                        } elseif ((ord($string{$offset}) | 0x7F) == 0x7F) {
     
    829794
    830795        // UTF-8 => UTF-16LE
    831         function iconv_fallback_utf8_utf16le($string, $bom=false) {
     796        static function iconv_fallback_utf8_utf16le($string, $bom=false) {
    832797                $newcharstring = '';
    833798                if ($bom) {
     
    840805                                // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb
    841806                                $charval = ((ord($string{($offset + 0)}) & 0x07) << 18) &
    842                                            ((ord($string{($offset + 1)}) & 0x3F) << 12) &
    843                                            ((ord($string{($offset + 2)}) & 0x3F) <<  6) &
    844                                             (ord($string{($offset + 3)}) & 0x3F);
     807                                                   ((ord($string{($offset + 1)}) & 0x3F) << 12) &
     808                                                   ((ord($string{($offset + 2)}) & 0x3F) <<  6) &
     809                                                        (ord($string{($offset + 3)}) & 0x3F);
    845810                                $offset += 4;
    846811                        } elseif ((ord($string{$offset}) | 0x0F) == 0xEF) {
    847812                                // 1110bbbb 10bbbbbb 10bbbbbb
    848813                                $charval = ((ord($string{($offset + 0)}) & 0x0F) << 12) &
    849                                            ((ord($string{($offset + 1)}) & 0x3F) <<  6) &
    850                                             (ord($string{($offset + 2)}) & 0x3F);
     814                                                   ((ord($string{($offset + 1)}) & 0x3F) <<  6) &
     815                                                        (ord($string{($offset + 2)}) & 0x3F);
    851816                                $offset += 3;
    852817                        } elseif ((ord($string{$offset}) | 0x1F) == 0xDF) {
    853818                                // 110bbbbb 10bbbbbb
    854819                                $charval = ((ord($string{($offset + 0)}) & 0x1F) <<  6) &
    855                                             (ord($string{($offset + 1)}) & 0x3F);
     820                                                        (ord($string{($offset + 1)}) & 0x3F);
    856821                                $offset += 2;
    857822                        } elseif ((ord($string{$offset}) | 0x7F) == 0x7F) {
     
    872837
    873838        // UTF-8 => UTF-16LE (BOM)
    874         function iconv_fallback_utf8_utf16($string) {
     839        static function iconv_fallback_utf8_utf16($string) {
    875840                return getid3_lib::iconv_fallback_utf8_utf16le($string, true);
    876841        }
    877842
    878843        // UTF-16BE => UTF-8
    879         function iconv_fallback_utf16be_utf8($string) {
     844        static function iconv_fallback_utf16be_utf8($string) {
    880845                if (substr($string, 0, 2) == "\xFE\xFF") {
    881846                        // strip BOM
     
    891856
    892857        // UTF-16LE => UTF-8
    893         function iconv_fallback_utf16le_utf8($string) {
     858        static function iconv_fallback_utf16le_utf8($string) {
    894859                if (substr($string, 0, 2) == "\xFF\xFE") {
    895860                        // strip BOM
     
    905870
    906871        // UTF-16BE => ISO-8859-1
    907         function iconv_fallback_utf16be_iso88591($string) {
     872        static function iconv_fallback_utf16be_iso88591($string) {
    908873                if (substr($string, 0, 2) == "\xFE\xFF") {
    909874                        // strip BOM
     
    919884
    920885        // UTF-16LE => ISO-8859-1
    921         function iconv_fallback_utf16le_iso88591($string) {
     886        static function iconv_fallback_utf16le_iso88591($string) {
    922887                if (substr($string, 0, 2) == "\xFF\xFE") {
    923888                        // strip BOM
     
    933898
    934899        // UTF-16 (BOM) => ISO-8859-1
    935         function iconv_fallback_utf16_iso88591($string) {
     900        static function iconv_fallback_utf16_iso88591($string) {
    936901                $bom = substr($string, 0, 2);
    937902                if ($bom == "\xFE\xFF") {
     
    944909
    945910        // UTF-16 (BOM) => UTF-8
    946         function iconv_fallback_utf16_utf8($string) {
     911        static function iconv_fallback_utf16_utf8($string) {
    947912                $bom = substr($string, 0, 2);
    948913                if ($bom == "\xFE\xFF") {
     
    954919        }
    955920
    956         function iconv_fallback($in_charset, $out_charset, $string) {
     921        static function iconv_fallback($in_charset, $out_charset, $string) {
    957922
    958923                if ($in_charset == $out_charset) {
     
    962927                // iconv() availble
    963928                if (function_exists('iconv')) {
    964 
    965                     if ($converted_string = @iconv($in_charset, $out_charset.'//TRANSLIT', $string)) {
    966                         switch ($out_charset) {
    967                                 case 'ISO-8859-1':
    968                                         $converted_string = rtrim($converted_string, "\x00");
    969                                         break;
    970                         }
    971                         return $converted_string;
    972                 }
    973 
    974                 // iconv() may sometimes fail with "illegal character in input string" error message
    975                 // and return an empty string, but returning the unconverted string is more useful
    976                 return $string;
    977         }
    978 
    979 
    980         // iconv() not available
     929                        if ($converted_string = @iconv($in_charset, $out_charset.'//TRANSLIT', $string)) {
     930                                switch ($out_charset) {
     931                                        case 'ISO-8859-1':
     932                                                $converted_string = rtrim($converted_string, "\x00");
     933                                                break;
     934                                }
     935                                return $converted_string;
     936                        }
     937
     938                        // iconv() may sometimes fail with "illegal character in input string" error message
     939                        // and return an empty string, but returning the unconverted string is more useful
     940                        return $string;
     941                }
     942
     943
     944                // iconv() not available
    981945                static $ConversionFunctionList = array();
    982946                if (empty($ConversionFunctionList)) {
     
    1000964                        return getid3_lib::$ConversionFunction($string);
    1001965                }
    1002                 die('PHP does not have iconv() support - cannot convert from '.$in_charset.' to '.$out_charset);
    1003         }
    1004 
    1005 
    1006         function MultiByteCharString2HTML($string, $charset='ISO-8859-1') {
     966                throw new Exception('PHP does not have iconv() support - cannot convert from '.$in_charset.' to '.$out_charset);
     967        }
     968
     969
     970        static function MultiByteCharString2HTML($string, $charset='ISO-8859-1') {
     971                $string = (string) $string; // in case trying to pass a numeric (float, int) string, would otherwise return an empty string
    1007972                $HTMLstring = '';
    1008973
    1009974                switch ($charset) {
     975                        case '1251':
     976                        case '1252':
     977                        case '866':
     978                        case '932':
     979                        case '936':
     980                        case '950':
     981                        case 'BIG5':
     982                        case 'BIG5-HKSCS':
     983                        case 'cp1251':
     984                        case 'cp1252':
     985                        case 'cp866':
     986                        case 'EUC-JP':
     987                        case 'EUCJP':
     988                        case 'GB2312':
     989                        case 'ibm866':
    1010990                        case 'ISO-8859-1':
     991                        case 'ISO-8859-15':
    1011992                        case 'ISO8859-1':
    1012                         case 'ISO-8859-15':
    1013993                        case 'ISO8859-15':
    1014                         case 'cp866':
    1015                         case 'ibm866':
    1016                         case '866':
    1017                         case 'cp1251':
    1018                         case 'Windows-1251':
    1019                         case 'win-1251':
    1020                         case '1251':
    1021                         case 'cp1252':
    1022                         case 'Windows-1252':
    1023                         case '1252':
    1024994                        case 'KOI8-R':
    1025995                        case 'koi8-ru':
    1026996                        case 'koi8r':
    1027                         case 'BIG5':
    1028                         case '950':
    1029                         case 'GB2312':
    1030                         case '936':
    1031                         case 'BIG5-HKSCS':
    1032997                        case 'Shift_JIS':
    1033998                        case 'SJIS':
    1034                         case '932':
    1035                         case 'EUC-JP':
    1036                         case 'EUCJP':
     999                        case 'win-1251':
     1000                        case 'Windows-1251':
     1001                        case 'Windows-1252':
    10371002                                $HTMLstring = htmlentities($string, ENT_COMPAT, $charset);
    10381003                                break;
     
    10591024                                        }
    10601025                                        if (($charval >= 32) && ($charval <= 127)) {
    1061                                                 $HTMLstring .= chr($charval);
     1026                                                $HTMLstring .= htmlentities(chr($charval));
    10621027                                        } else {
    10631028                                                $HTMLstring .= '&#'.$charval.';';
     
    10971062
    10981063
    1099         function RGADnameLookup($namecode) {
     1064        static function RGADnameLookup($namecode) {
    11001065                static $RGADname = array();
    11011066                if (empty($RGADname)) {
     
    11091074
    11101075
    1111         function RGADoriginatorLookup($originatorcode) {
     1076        static function RGADoriginatorLookup($originatorcode) {
    11121077                static $RGADoriginator = array();
    11131078                if (empty($RGADoriginator)) {
     
    11221087
    11231088
    1124         function RGADadjustmentLookup($rawadjustment, $signbit) {
     1089        static function RGADadjustmentLookup($rawadjustment, $signbit) {
    11251090                $adjustment = $rawadjustment / 10;
    11261091                if ($signbit == 1) {
     
    11311096
    11321097
    1133         function RGADgainString($namecode, $originatorcode, $replaygain) {
     1098        static function RGADgainString($namecode, $originatorcode, $replaygain) {
    11341099                if ($replaygain < 0) {
    11351100                        $signbit = '1';
     
    11461111        }
    11471112
    1148         function RGADamplitude2dB($amplitude) {
     1113        static function RGADamplitude2dB($amplitude) {
    11491114                return 20 * log10($amplitude);
    11501115        }
    11511116
    11521117
    1153         function GetDataImageSize($imgData) {
     1118        static function GetDataImageSize($imgData, &$imageinfo) {
     1119                static $tempdir = '';
     1120                if (empty($tempdir)) {
     1121                        // yes this is ugly, feel free to suggest a better way
     1122                        require_once(dirname(__FILE__).'/getid3.php');
     1123                        $getid3_temp = new getID3();
     1124                        $tempdir = $getid3_temp->tempdir;
     1125                        unset($getid3_temp);
     1126                }
    11541127                $GetDataImageSize = false;
    1155                 if ($tempfilename = tempnam('*', 'getID3')) {
    1156                         if ($tmp = @fopen($tempfilename, 'wb')) {
     1128                if ($tempfilename = tempnam($tempdir, 'gI3')) {
     1129                        if (is_writable($tempfilename) && is_file($tempfilename) && ($tmp = fopen($tempfilename, 'wb'))) {
    11571130                                fwrite($tmp, $imgData);
    11581131                                fclose($tmp);
    1159                                 $GetDataImageSize = @GetImageSize($tempfilename);
     1132                                $GetDataImageSize = @GetImageSize($tempfilename, $imageinfo);
    11601133                        }
    11611134                        unlink($tempfilename);
     
    11641137        }
    11651138
    1166         function ImageTypesLookup($imagetypeid) {
     1139        static function ImageTypesLookup($imagetypeid) {
    11671140                static $ImageTypesLookup = array();
    11681141                if (empty($ImageTypesLookup)) {
     
    11851158        }
    11861159
    1187         function CopyTagsToComments(&$ThisFileInfo) {
     1160        static function CopyTagsToComments(&$ThisFileInfo) {
    11881161
    11891162                // Copy all entries from ['tags'] into common ['comments']
     
    12081181                                                                }
    12091182
    1210                                                         } else {
     1183                                                        } elseif (!is_array($value)) {
    12111184
    12121185                                                                $newvaluelength = strlen(trim($value));
     
    12201193
    12211194                                                        }
    1222                                                         if (empty($ThisFileInfo['comments'][$tagname]) || !in_array(trim($value), $ThisFileInfo['comments'][$tagname])) {
    1223                                                                 $ThisFileInfo['comments'][$tagname][] = trim($value);
     1195                                                        if (is_array($value) || empty($ThisFileInfo['comments'][$tagname]) || !in_array(trim($value), $ThisFileInfo['comments'][$tagname])) {
     1196                                                                $value = (is_string($value) ? trim($value) : $value);
     1197                                                                $ThisFileInfo['comments'][$tagname][] = $value;
    12241198                                                        }
    12251199                                                }
     
    12291203
    12301204                        // Copy to ['comments_html']
    1231                 foreach ($ThisFileInfo['comments'] as $field => $values) {
    1232                     foreach ($values as $index => $value) {
    1233                         $ThisFileInfo['comments_html'][$field][$index] = str_replace('&#0;', '', getid3_lib::MultiByteCharString2HTML($value, $ThisFileInfo['encoding']));
    1234                     }
    1235             }
    1236                 }
    1237         }
    1238 
    1239 
    1240         function EmbeddedLookup($key, $begin, $end, $file, $name) {
     1205                        foreach ($ThisFileInfo['comments'] as $field => $values) {
     1206                                if ($field == 'picture') {
     1207                                        // pictures can take up a lot of space, and we don't need multiple copies of them
     1208                                        // let there be a single copy in [comments][picture], and not elsewhere
     1209                                        continue;
     1210                                }
     1211                                foreach ($values as $index => $value) {
     1212                                        if (is_array($value)) {
     1213                                                $ThisFileInfo['comments_html'][$field][$index] = $value;
     1214                                        } else {
     1215                                                $ThisFileInfo['comments_html'][$field][$index] = str_replace('&#0;', '', getid3_lib::MultiByteCharString2HTML($value, $ThisFileInfo['encoding']));
     1216                                        }
     1217                                }
     1218                        }
     1219                }
     1220                return true;
     1221        }
     1222
     1223
     1224        static function EmbeddedLookup($key, $begin, $end, $file, $name) {
    12411225
    12421226                // Cached
    12431227                static $cache;
    12441228                if (isset($cache[$file][$name])) {
    1245                         return @$cache[$file][$name][$key];
     1229                        return (isset($cache[$file][$name][$key]) ? $cache[$file][$name][$key] : '');
    12461230                }
    12471231
     
    12731257                        // METHOD B: cache all keys in this lookup - more memory but faster on next lookup of not-previously-looked-up key
    12741258                        //$cache[$file][$name][substr($line, 0, $keylength)] = trim(substr($line, $keylength + 1));
    1275                         @list($ThisKey, $ThisValue) = explode("\t", $line, 2);
     1259                        $explodedLine = explode("\t", $line, 2);
     1260                        $ThisKey   = (isset($explodedLine[0]) ? $explodedLine[0] : '');
     1261                        $ThisValue = (isset($explodedLine[1]) ? $explodedLine[1] : '');
    12761262                        $cache[$file][$name][$ThisKey] = trim($ThisValue);
    12771263                }
     
    12791265                // Close and return
    12801266                fclose($fp);
    1281                 return @$cache[$file][$name][$key];
    1282         }
    1283 
    1284         function IncludeDependency($filename, $sourcefile, $DieOnFailure=false) {
     1267                return (isset($cache[$file][$name][$key]) ? $cache[$file][$name][$key] : '');
     1268        }
     1269
     1270        static function IncludeDependency($filename, $sourcefile, $DieOnFailure=false) {
    12851271                global $GETID3_ERRORARRAY;
    12861272
    12871273                if (file_exists($filename)) {
    1288                         if (@include_once($filename)) {
     1274                        if (include_once($filename)) {
    12891275                                return true;
    12901276                        } else {
     
    12951281                }
    12961282                if ($DieOnFailure) {
    1297                         die($diemessage);
     1283                        throw new Exception($diemessage);
    12981284                } else {
    12991285                        $GETID3_ERRORARRAY[] = $diemessage;
  • _plugins_/getID3/getid3/getid3.php

    r44570 r51852  
    1010/////////////////////////////////////////////////////////////////
    1111
    12 // Defines
    13 define('GETID3_VERSION', '1.7.8b2');
    14 define('GETID3_FREAD_BUFFER_SIZE', 16384); // read buffer size in bytes
    15 
     12// attempt to define temp dir as something flexible but reliable
     13$temp_dir = ini_get('upload_tmp_dir');
     14if ($temp_dir && (!is_dir($temp_dir) || !is_readable($temp_dir))) {
     15        $temp_dir = '';
     16}
     17if (!$temp_dir && function_exists('sys_get_temp_dir')) {
     18        // PHP v5.2.1+
     19        // sys_get_temp_dir() may give inaccessible temp dir, e.g. with open_basedir on virtual hosts
     20        $temp_dir = sys_get_temp_dir();
     21}
     22$temp_dir = realpath($temp_dir);
     23$open_basedir = ini_get('open_basedir');
     24if ($open_basedir) {
     25        // e.g. "/var/www/vhosts/getid3.org/httpdocs/:/tmp/"
     26        $temp_dir     = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $temp_dir);
     27        $open_basedir = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $open_basedir);
     28        if (substr($temp_dir, -1, 1) != DIRECTORY_SEPARATOR) {
     29                $temp_dir .= DIRECTORY_SEPARATOR;
     30        }
     31        $found_valid_tempdir = false;
     32        $open_basedirs = explode(':', $open_basedir);
     33        foreach ($open_basedirs as $basedir) {
     34                if (substr($basedir, -1, 1) != DIRECTORY_SEPARATOR) {
     35                        $basedir .= DIRECTORY_SEPARATOR;
     36                }
     37                if (preg_match('#^'.preg_quote($basedir).'#', $temp_dir)) {
     38                        $found_valid_tempdir = true;
     39                        break;
     40                }
     41        }
     42        if (!$found_valid_tempdir) {
     43                $temp_dir = '';
     44        }
     45        unset($open_basedirs, $found_valid_tempdir, $basedir);
     46}
     47if (!$temp_dir) {
     48        $temp_dir = '*'; // invalid directory name should force tempnam() to use system default temp dir
     49}
     50// $temp_dir = '/something/else/';  // feel free to override temp dir here if it works better for your system
     51define('GETID3_TEMP_DIR', $temp_dir);
     52unset($open_basedir, $temp_dir);
     53
     54
     55// define a constant rather than looking up every time it is needed
     56if (!defined('GETID3_OS_ISWINDOWS')) {
     57        if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') {
     58                define('GETID3_OS_ISWINDOWS', true);
     59        } else {
     60                define('GETID3_OS_ISWINDOWS', false);
     61        }
     62}
     63
     64// Get base path of getID3() - ONCE
     65if (!defined('GETID3_INCLUDEPATH')) {
     66        foreach (get_included_files() as $key => $val) {
     67                if (basename($val) == 'getid3.php') {
     68                        define('GETID3_INCLUDEPATH', dirname($val).DIRECTORY_SEPARATOR);
     69                        break;
     70                }
     71        }
     72}
     73
     74// End: Defines
    1675
    1776
     
    1978{
    2079        // public: Settings
    21         var $encoding        = 'ISO-8859-1';   // CASE SENSITIVE! - i.e. (must be supported by iconv())
    22                                                // Examples:  ISO-8859-1  UTF-8  UTF-16  UTF-16BE
    23 
    24         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'
    25 
    26         var $tempdir         = '*';            // default '*' should use system temp dir
     80        public $encoding        = 'ISO-8859-1';   // CASE SENSITIVE! - i.e. (must be supported by iconv()). Examples:  ISO-8859-1  UTF-8  UTF-16  UTF-16BE
     81        public $encoding_id3v1  = 'ISO-8859-1';   // Should always be 'ISO-8859-1', but some tags may be written in other encodings such as 'EUC-CN'
    2782
    2883        // public: Optional tag checks - disable for speed.
    29         var $option_tag_id3v1         = true;  // Read and process ID3v1 tags
    30         var $option_tag_id3v2         = true;  // Read and process ID3v2 tags
    31         var $option_tag_lyrics3       = true;  // Read and process Lyrics3 tags
    32         var $option_tag_apetag        = true;  // Read and process APE tags
    33         var $option_tags_process      = true;  // Copy tags to root key 'tags' and encode to $this->encoding
    34         var $option_tags_html         = true;  // Copy tags to root key 'tags_html' properly translated from various encodings to HTML entities
     84        public $option_tag_id3v1         = true;  // Read and process ID3v1 tags
     85        public $option_tag_id3v2         = true;  // Read and process ID3v2 tags
     86        public $option_tag_lyrics3       = true;  // Read and process Lyrics3 tags
     87        public $option_tag_apetag        = true;  // Read and process APE tags
     88        public $option_tags_process      = true;  // Copy tags to root key 'tags' and encode to $this->encoding
     89        public $option_tags_html         = true;  // Copy tags to root key 'tags_html' properly translated from various encodings to HTML entities
    3590
    3691        // public: Optional tag/comment calucations
    37         var $option_extra_info        = true;  // Calculate additional info such as bitrate, channelmode etc
     92        public $option_extra_info        = true;  // Calculate additional info such as bitrate, channelmode etc
     93
     94        // public: Optional handling of embedded attachments (e.g. images)
     95        public $option_save_attachments  = true; // defaults to true (ATTACHMENTS_INLINE) for backward compatibility
    3896
    3997        // public: Optional calculations
    40         var $option_md5_data          = false; // Get MD5 sum of data part - slow
    41         var $option_md5_data_source   = false; // Use MD5 of source file if availble - only FLAC and OptimFROG
    42         var $option_sha1_data         = false; // Get SHA1 sum of data part - slow
    43         var $option_max_2gb_check     = true;  // Check whether file is larger than 2 Gb and thus not supported by PHP
    44 
    45         // private
    46         var $filename;
    47 
     98        public $option_md5_data          = false; // Get MD5 sum of data part - slow
     99        public $option_md5_data_source   = false; // Use MD5 of source file if availble - only FLAC and OptimFROG
     100        public $option_sha1_data         = false; // Get SHA1 sum of data part - slow
     101        public $option_max_2gb_check     = null;  // Check whether file is larger than 2GB and thus not supported by 32-bit PHP (null: auto-detect based on PHP_INT_MAX)
     102
     103        // Public variables
     104        public $filename;                         // Filename of file being analysed.
     105        public $fp;                               // Filepointer to file being analysed.
     106        public $info;                             // Result array.
     107
     108        // Protected variables
     109        protected $startup_error   = '';
     110        protected $startup_warning = '';
     111        protected $memory_limit    = 0;
     112
     113        const VERSION           = '1.9.0-20110620';
     114        const FREAD_BUFFER_SIZE = 32768;            // Read buffer size in bytes.
     115        var $tempdir            = GETID3_TEMP_DIR;
     116
     117        const ATTACHMENTS_NONE   = false;
     118        const ATTACHMENTS_INLINE = true;
    48119
    49120        // public: constructor
    50         function getID3()
    51         {
    52 
    53                 $this->startup_error   = '';
    54                 $this->startup_warning = '';
    55 
    56                 // Check for PHP version >= 4.2.0
    57                 if (phpversion() < '4.2.0') {
    58                     $this->startup_error .= 'getID3() requires PHP v4.2.0 or higher - you are running v'.phpversion();
     121        function getID3() {
     122
     123                // Check for PHP version
     124                $required_php_version = '5.0.5';
     125                if (!function_exists('version_compare') || version_compare(PHP_VERSION, $required_php_version, '<')) {
     126                        // version_compare not available before PHP v4.1.0, so don't use for first version checking
     127                        $this->startup_error .= 'getID3() requires PHP v'.$required_php_version.' or higher - you are running v'.PHP_VERSION;
     128                        return false;
    59129                }
    60130
    61131                // Check memory
    62                 $memory_limit = ini_get('memory_limit');
    63                 if (preg_match('/([0-9]+)M/i', $memory_limit, $matches)) {
     132                $this->memory_limit = ini_get('memory_limit');
     133                if (preg_match('#([0-9]+)M#i', $this->memory_limit, $matches)) {
    64134                        // could be stored as "16M" rather than 16777216 for example
    65                         $memory_limit = $matches[1] * 1048576;
    66                 }
    67                 if ($memory_limit <= 0) {
     135                        $this->memory_limit = $matches[1] * 1048576;
     136                } elseif (preg_match('#([0-9]+)G#i', $this->memory_limit, $matches)) { // The 'G' modifier is available since PHP 5.1.0
     137                        // could be stored as "2G" rather than 2147483648 for example
     138                        $this->memory_limit = $matches[1] * 1073741824;
     139                }
     140                if ($this->memory_limit <= 0) {
    68141                        // memory limits probably disabled
    69                 } elseif ($memory_limit <= 3145728) {
    70                 $this->startup_error .= 'PHP has less than 3MB available memory and will very likely run out. Increase memory_limit in php.ini';
    71                 } elseif ($memory_limit <= 12582912) {
    72                 $this->startup_warning .= 'PHP has less than 12MB available memory and might run out if all modules are loaded. Increase memory_limit in php.ini';
     142                } elseif ($this->memory_limit <= 4194304) {
     143                        $this->startup_error .= 'PHP has less than 4MB available memory and will very likely run out. Increase memory_limit in php.ini';
     144                } elseif ($this->memory_limit <= 12582912) {
     145                        $this->startup_warning .= 'PHP has less than 12MB available memory and might run out if all modules are loaded. Increase memory_limit in php.ini';
    73146                }
    74147
    75148                // Check safe_mode off
    76                 if ((bool) ini_get('safe_mode')) {
    77                     $this->warning('WARNING: Safe mode is on, shorten support disabled, md5data/sha1data for ogg vorbis disabled, ogg vorbos/flac tag writing disabled.');
    78                 }
    79 
    80 
    81                 // define a constant rather than looking up every time it is needed
    82                 if (!defined('GETID3_OS_ISWINDOWS')) {
    83                         if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') {
    84                                 define('GETID3_OS_ISWINDOWS', true);
     149                if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) {
     150                        $this->warning('WARNING: Safe mode is on, shorten support disabled, md5data/sha1data for ogg vorbis disabled, ogg vorbos/flac tag writing disabled.');
     151                }
     152
     153                if (intval(ini_get('mbstring.func_overload')) > 0) {
     154                        $this->warning('WARNING: php.ini contains "mbstring.func_overload = '.ini_get('mbstring.func_overload').'", this may break things.');
     155                }
     156
     157                /*
     158                // Check timezone config setting
     159                // this is needed to prevent E_STRICT warnings with any time/date functions
     160                if (!ini_get('date.timezone')) {
     161                        if (function_exists('date_default_timezone_set')) { // exists since PHP v5.1.0
     162                                $this->warning('php.ini should have "date.timezone" set, but it does not. Setting timezone to "'.date_default_timezone_get().'"');
     163                                date_default_timezone_set(date_default_timezone_get());
    85164                        } else {
    86                                 define('GETID3_OS_ISWINDOWS', false);
    87                         }
    88                 }
    89 
    90                 // Get base path of getID3() - ONCE
    91                 if (!defined('GETID3_INCLUDEPATH')) {
    92                         foreach (get_included_files() as $key => $val) {
    93                                 if (basename($val) == 'getid3.php') {
    94                                         define('GETID3_INCLUDEPATH', dirname($val).DIRECTORY_SEPARATOR);
    95                                         break;
    96                                 }
     165                                $this->warning('php.ini should have "date.timezone" set, but it does not.');
     166                        }
     167                }
     168                */
     169
     170                // Check for magic_quotes_runtime
     171                if (function_exists('get_magic_quotes_runtime')) {
     172                        if (get_magic_quotes_runtime()) {
     173                                return $this->startup_error('magic_quotes_runtime must be disabled before running getID3(). Surround getid3 block by set_magic_quotes_runtime(0) and set_magic_quotes_runtime(1).');
     174                        }
     175                }
     176
     177                // Check for magic_quotes_gpc
     178                if (function_exists('magic_quotes_gpc')) {
     179                        if (get_magic_quotes_gpc()) {
     180                                return $this->startup_error('magic_quotes_gpc must be disabled before running getID3(). Surround getid3 block by set_magic_quotes_gpc(0) and set_magic_quotes_gpc(1).');
    97181                        }
    98182                }
     
    103187                }
    104188
     189                if ($this->option_max_2gb_check === null) {
     190                        $this->option_max_2gb_check = (PHP_INT_MAX <= 2147483647);
     191                }
     192
    105193
    106194                // Needed for Windows only:
    107195                // Define locations of helper applications for Shorten, VorbisComment, MetaFLAC
    108196                //   as well as other helper functions such as head, tail, md5sum, etc
    109                 // IMPORTANT: This path cannot have spaces in it. If neccesary, use the 8dot3 equivalent
    110                 //   ie for "C:/Program Files/Apache/" put "C:/PROGRA~1/APACHE/"
     197                // This path cannot contain spaces, but the below code will attempt to get the
     198                //   8.3-equivalent path automatically
    111199                // IMPORTANT: This path must include the trailing slash
    112200                if (GETID3_OS_ISWINDOWS && !defined('GETID3_HELPERAPPSDIR')) {
     
    115203
    116204                        if (!is_dir($helperappsdir)) {
    117                                 $this->startup_error .= '"'.$helperappsdir.'" cannot be defined as GETID3_HELPERAPPSDIR because it does not exist';
     205                                $this->startup_warning .= '"'.$helperappsdir.'" cannot be defined as GETID3_HELPERAPPSDIR because it does not exist';
    118206                        } elseif (strpos(realpath($helperappsdir), ' ') !== false) {
    119207                                $DirPieces = explode(DIRECTORY_SEPARATOR, realpath($helperappsdir));
     208                                $path_so_far = array();
    120209                                foreach ($DirPieces as $key => $value) {
    121                                         if ((strpos($value, '.') !== false) && (strpos($value, ' ') === false)) {
    122                                                 if (strpos($value, '.') > 8) {
    123                                                         $value = substr($value, 0, 6).'~1';
     210                                        if (strpos($value, ' ') !== false) {
     211                                                if (!empty($path_so_far)) {
     212                                                        $commandline = 'dir /x '.escapeshellarg(implode(DIRECTORY_SEPARATOR, $path_so_far));
     213                                                        $dir_listing = `$commandline`;
     214                                                        $lines = explode("\n", $dir_listing);
     215                                                        foreach ($lines as $line) {
     216                                                                $line = trim($line);
     217                                                                if (preg_match('#^([0-9/]{10}) +([0-9:]{4,5}( [AP]M)?) +(<DIR>|[0-9,]+) +([^ ]{0,11}) +(.+)$#', $line, $matches)) {
     218                                                                        list($dummy, $date, $time, $ampm, $filesize, $shortname, $filename) = $matches;
     219                                                                        if ((strtoupper($filesize) == '<DIR>') && (strtolower($filename) == strtolower($value))) {
     220                                                                                $value = $shortname;
     221                                                                        }
     222                                                                }
     223                                                        }
     224                                                } else {
     225                                                        $this->startup_warning .= 'GETID3_HELPERAPPSDIR must not have any spaces in it - use 8dot3 naming convention if neccesary. You can run "dir /x" from the commandline to see the correct 8.3-style names.';
    124226                                                }
    125                                         } elseif ((strpos($value, ' ') !== false) || strlen($value) > 8) {
    126                                                 $value = substr($value, 0, 6).'~1';
    127227                                        }
    128                                         $DirPieces[$key] = strtoupper($value);
    129                                 }
    130                                 $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(DIRECTORY_SEPARATOR, $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.';
    131                         }
    132                         define('GETID3_HELPERAPPSDIR', realpath($helperappsdir).DIRECTORY_SEPARATOR);
    133                 }
    134 
     228                                        $path_so_far[] = $value;
     229                                }
     230                                $helperappsdir = implode(DIRECTORY_SEPARATOR, $path_so_far);
     231                        }
     232                        define('GETID3_HELPERAPPSDIR', $helperappsdir.DIRECTORY_SEPARATOR);
     233                }
     234
     235                return true;
     236        }
     237
     238        function version() {
     239                $version = getID3::VERSION;
     240                if (version_compare(PHP_VERSION, '5.3.0', '>=')) {
     241                        // can't use this syntax, even conditionally, since it registers as a parse error before PHP v5.3.0
     242                        // wrapping the new syntax in an eval call should work without causing parse errors in old PHP
     243                        // return $this::VERSION;
     244                        eval('$version = $this::VERSION;');
     245                }
     246                return $version;
     247        }
     248        function fread_buffer_size() {
     249                $fread_buffer_size = getID3::FREAD_BUFFER_SIZE;
     250                if (version_compare(PHP_VERSION, '5.3.0', '>=')) {
     251                        // can't use this syntax, even conditionally, since it registers as a parse error before PHP v5.3.0
     252                        // wrapping the new syntax in an eval call should work without causing parse errors in old PHP
     253                        // return $this::VERSION;
     254                        eval('$fread_buffer_size = $this::FREAD_BUFFER_SIZE;');
     255                }
     256                return $fread_buffer_size;
    135257        }
    136258
     
    142264                }
    143265                foreach ($optArray as $opt => $val) {
    144                         if (isset($this, $opt) === false) {
     266                        if (isset($this->$opt) === false) {
    145267                                continue;
    146268                        }
     
    151273
    152274
    153         // public: analyze file - replaces GetAllFileInfo() and GetTagOnly()
     275        function openfile($filename) {
     276                try {
     277                        if (!empty($this->startup_error)) {
     278                                return $this->error($this->startup_error);
     279                        }
     280                        if (!empty($this->startup_warning)) {
     281                                $this->warning($this->startup_warning);
     282                        }
     283
     284                        // init result array and set parameters
     285                        $this->filename = $filename;
     286                        $this->info = array();
     287                        $this->info['GETID3_VERSION'] = $this->version();
     288                        $this->info['php_memory_limit'] = $this->memory_limit;
     289
     290                        // remote files not supported
     291                        if (preg_match('/^(ht|f)tp:\/\//', $filename)) {
     292                                return $this->error('Remote files are not supported - please copy the file locally first');
     293                        }
     294
     295                        $filename = str_replace('/', DIRECTORY_SEPARATOR, $filename);
     296                        $filename = preg_replace('#(.+)'.preg_quote(DIRECTORY_SEPARATOR).'{2,}#U', '\1'.DIRECTORY_SEPARATOR, $filename);
     297
     298                        // open local file
     299                        if (is_readable($filename) && is_file($filename) && ($this->fp = fopen($filename, 'rb'))) {
     300                                // great
     301                        } else {
     302                                return $this->error('Could not open "'.$filename.'" (does not exist, or is not a file)');
     303                        }
     304
     305                        $this->info['filesize'] = filesize($filename);
     306                        // set redundant parameters - might be needed in some include file
     307                        $this->info['filename']            = basename($filename);
     308                        $this->info['filepath']            = str_replace('\\', '/', realpath(dirname($filename)));
     309                        $this->info['filenamepath']        = $this->info['filepath'].'/'.$this->info['filename'];
     310
     311
     312                        // option_max_2gb_check
     313                        if ($this->option_max_2gb_check) {
     314                                // PHP (32-bit all, and 64-bit Windows) doesn't support integers larger than 2^31 (~2GB)
     315                                // filesize() simply returns (filesize % (pow(2, 32)), no matter the actual filesize
     316                                // ftell() returns 0 if seeking to the end is beyond the range of unsigned integer
     317                                $fseek = fseek($this->fp, 0, SEEK_END);
     318                                if (($fseek < 0) || (($this->info['filesize'] != 0) && (ftell($this->fp) == 0)) ||
     319                                        ($this->info['filesize'] < 0) ||
     320                                        (ftell($this->fp) < 0)) {
     321                                                $real_filesize = false;
     322                                                if (GETID3_OS_ISWINDOWS) {
     323                                                        $commandline = 'dir /-C "'.str_replace('/', DIRECTORY_SEPARATOR, $filename).'"';
     324                                                        $dir_output = `$commandline`;
     325                                                        if (preg_match('#1 File\(s\)[ ]+([0-9]+) bytes#i', $dir_output, $matches)) {
     326                                                                $real_filesize = (float) $matches[1];
     327                                                        }
     328                                                } else {
     329                                                        $commandline = 'ls -o -g -G --time-style=long-iso '.escapeshellarg($filename);
     330                                                        $dir_output = `$commandline`;
     331                                                        if (preg_match('#([0-9]+) ([0-9]{4}-[0-9]{2}\-[0-9]{2} [0-9]{2}:[0-9]{2}) '.str_replace('#', '\\#', preg_quote($filename)).'$#', $dir_output, $matches)) {
     332                                                                $real_filesize = (float) $matches[1];
     333                                                        }
     334                                                }
     335                                                if ($real_filesize === false) {
     336                                                        unset($this->info['filesize']);
     337                                                        fclose($this->fp);
     338                                                        return $this->error('Unable to determine actual filesize. File is most likely larger than '.round(PHP_INT_MAX / 1073741824).'GB and is not supported by PHP.');
     339                                                } elseif (getid3_lib::intValueSupported($real_filesize)) {
     340                                                        unset($this->info['filesize']);
     341                                                        fclose($this->fp);
     342                                                        return $this->error('PHP seems to think the file is larger than '.round(PHP_INT_MAX / 1073741824).'GB, but filesystem reports it as '.number_format($real_filesize, 3).'GB, please report to info@getid3.org');
     343                                                }
     344                                                $this->info['filesize'] = $real_filesize;
     345                                                $this->error('File is larger than '.round(PHP_INT_MAX / 1073741824).'GB (filesystem reports it as '.number_format($real_filesize, 3).'GB) and is not properly supported by PHP.');
     346                                }
     347                        }
     348
     349                        // set more parameters
     350                        $this->info['avdataoffset']        = 0;
     351                        $this->info['avdataend']           = $this->info['filesize'];
     352                        $this->info['fileformat']          = '';                // filled in later
     353                        $this->info['audio']['dataformat'] = '';                // filled in later, unset if not used
     354                        $this->info['video']['dataformat'] = '';                // filled in later, unset if not used
     355                        $this->info['tags']                = array();           // filled in later, unset if not used
     356                        $this->info['error']               = array();           // filled in later, unset if not used
     357                        $this->info['warning']             = array();           // filled in later, unset if not used
     358                        $this->info['comments']            = array();           // filled in later, unset if not used
     359                        $this->info['encoding']            = $this->encoding;   // required by id3v2 and iso modules - can be unset at the end if desired
     360
     361                } catch (Exception $e) {
     362                        if (isset($this->info['error'])) {
     363                                $this->info['error'][] = 'Caught exception: '.$e->getMessage();
     364                        } else {
     365                                $this->info['error'] = array('Caught exception: '.$e->getMessage());
     366                        }
     367                }
     368        }
     369
     370        // public: analyze file
    154371        function analyze($filename) {
    155 
    156                 if (!empty($this->startup_error)) {
    157                         return $this->error($this->startup_error);
    158                 }
    159                 if (!empty($this->startup_warning)) {
    160                         $this->warning($this->startup_warning);
    161                 }
    162 
    163                 // init result array and set parameters
    164                 $this->info = array();
    165                 $this->info['GETID3_VERSION'] = GETID3_VERSION;
    166 
    167                 // Check encoding/iconv support
    168                 if (!function_exists('iconv') && !in_array($this->encoding, array('ISO-8859-1', 'UTF-8', 'UTF-16LE', 'UTF-16BE', 'UTF-16'))) {
    169                         $errormessage = 'iconv() support is needed for encodings other than ISO-8859-1, UTF-8, UTF-16LE, UTF16-BE, UTF-16. ';
    170                         if (GETID3_OS_ISWINDOWS) {
    171                                 $errormessage .= 'PHP does not have iconv() support. Please enable php_iconv.dll in php.ini, and copy iconv.dll from c:/php/dlls to c:/windows/system32';
     372                try {
     373                        $this->openfile($filename);
     374
     375                        // Handle tags
     376                        foreach (array('id3v2'=>'id3v2', 'id3v1'=>'id3v1', 'apetag'=>'ape', 'lyrics3'=>'lyrics3') as $tag_name => $tag_key) {
     377                                $option_tag = 'option_tag_'.$tag_name;
     378                                if ($this->$option_tag) {
     379                                        $this->include_module('tag.'.$tag_name);
     380                                        try {
     381                                                $tag_class = 'getid3_'.$tag_name;
     382                                                $tag = new $tag_class($this);
     383                                                $tag->Analyze();
     384                                        }
     385                                        catch (getid3_exception $e) {
     386                                                throw $e;
     387                                        }
     388                                }
     389                        }
     390                        if (isset($this->info['id3v2']['tag_offset_start'])) {
     391                                $this->info['avdataoffset'] = max($this->info['avdataoffset'], $this->info['id3v2']['tag_offset_end']);
     392                        }
     393                        foreach (array('id3v1'=>'id3v1', 'apetag'=>'ape', 'lyrics3'=>'lyrics3') as $tag_name => $tag_key) {
     394                                if (isset($this->info[$tag_key]['tag_offset_start'])) {
     395                                        $this->info['avdataend'] = min($this->info['avdataend'], $this->info[$tag_key]['tag_offset_start']);
     396                                }
     397                        }
     398
     399                        // ID3v2 detection (NOT parsing), even if ($this->option_tag_id3v2 == false) done to make fileformat easier
     400                        if (!$this->option_tag_id3v2) {
     401                                fseek($this->fp, 0, SEEK_SET);
     402                                $header = fread($this->fp, 10);
     403                                if ((substr($header, 0, 3) == 'ID3') && (strlen($header) == 10)) {
     404                                        $this->info['id3v2']['header']        = true;
     405                                        $this->info['id3v2']['majorversion']  = ord($header{3});
     406                                        $this->info['id3v2']['minorversion']  = ord($header{4});
     407                                        $this->info['avdataoffset']          += getid3_lib::BigEndian2Int(substr($header, 6, 4), 1) + 10; // length of ID3v2 tag in 10-byte header doesn't include 10-byte header length
     408                                }
     409                        }
     410
     411                        // read 32 kb file data
     412                        fseek($this->fp, $this->info['avdataoffset'], SEEK_SET);
     413                        $formattest = fread($this->fp, 32774);
     414
     415                        // determine format
     416                        $determined_format = $this->GetFileFormat($formattest, $filename);
     417
     418                        // unable to determine file format
     419                        if (!$determined_format) {
     420                                fclose($this->fp);
     421                                return $this->error('unable to determine file format');
     422                        }
     423
     424                        // check for illegal ID3 tags
     425                        if (isset($determined_format['fail_id3']) && (in_array('id3v1', $this->info['tags']) || in_array('id3v2', $this->info['tags']))) {
     426                                if ($determined_format['fail_id3'] === 'ERROR') {
     427                                        fclose($this->fp);
     428                                        return $this->error('ID3 tags not allowed on this file type.');
     429                                } elseif ($determined_format['fail_id3'] === 'WARNING') {
     430                                        $this->info['warning'][] = 'ID3 tags not allowed on this file type.';
     431                                }
     432                        }
     433
     434                        // check for illegal APE tags
     435                        if (isset($determined_format['fail_ape']) && in_array('ape', $this->info['tags'])) {
     436                                if ($determined_format['fail_ape'] === 'ERROR') {
     437                                        fclose($this->fp);
     438                                        return $this->error('APE tags not allowed on this file type.');
     439                                } elseif ($determined_format['fail_ape'] === 'WARNING') {
     440                                        $this->info['warning'][] = 'APE tags not allowed on this file type.';
     441                                }
     442                        }
     443
     444                        // set mime type
     445                        $this->info['mime_type'] = $determined_format['mime_type'];
     446
     447                        // supported format signature pattern detected, but module deleted
     448                        if (!file_exists(GETID3_INCLUDEPATH.$determined_format['include'])) {
     449                                fclose($this->fp);
     450                                return $this->error('Format not supported, module "'.$determined_format['include'].'" was removed.');
     451                        }
     452
     453                        // module requires iconv support
     454                        // Check encoding/iconv support
     455                        if (!empty($determined_format['iconv_req']) && !function_exists('iconv') && !in_array($this->encoding, array('ISO-8859-1', 'UTF-8', 'UTF-16LE', 'UTF-16BE', 'UTF-16'))) {
     456                                $errormessage = 'iconv() support is required for this module ('.$determined_format['include'].') for encodings other than ISO-8859-1, UTF-8, UTF-16LE, UTF16-BE, UTF-16. ';
     457                                if (GETID3_OS_ISWINDOWS) {
     458                                        $errormessage .= 'PHP does not have iconv() support. Please enable php_iconv.dll in php.ini, and copy iconv.dll from c:/php/dlls to c:/windows/system32';
     459                                } else {
     460                                        $errormessage .= 'PHP is not compiled with iconv() support. Please recompile with the --with-iconv switch';
     461                                }
     462                                return $this->error($errormessage);
     463                        }
     464
     465                        // include module
     466                        include_once(GETID3_INCLUDEPATH.$determined_format['include']);
     467
     468                        // instantiate module class
     469                        $class_name = 'getid3_'.$determined_format['module'];
     470                        if (!class_exists($class_name)) {
     471                                return $this->error('Format not supported, module "'.$determined_format['include'].'" is corrupt.');
     472                        }
     473                        //if (isset($determined_format['option'])) {
     474                        //      //$class = new $class_name($this->fp, $this->info, $determined_format['option']);
     475                        //} else {
     476                                //$class = new $class_name($this->fp, $this->info);
     477                                $class = new $class_name($this);
     478                        //}
     479
     480                        if (!empty($determined_format['set_inline_attachments'])) {
     481                                $class->inline_attachments = $this->option_save_attachments;
     482                        }
     483                        $class->Analyze();
     484
     485                        unset($class);
     486
     487                        // close file
     488                        fclose($this->fp);
     489
     490                        // process all tags - copy to 'tags' and convert charsets
     491                        if ($this->option_tags_process) {
     492                                $this->HandleAllTags();
     493                        }
     494
     495                        // perform more calculations
     496                        if ($this->option_extra_info) {
     497                                $this->ChannelsBitratePlaytimeCalculations();
     498                                $this->CalculateCompressionRatioVideo();
     499                                $this->CalculateCompressionRatioAudio();
     500                                $this->CalculateReplayGain();
     501                                $this->ProcessAudioStreams();
     502                        }
     503
     504                        // get the MD5 sum of the audio/video portion of the file - without ID3/APE/Lyrics3/etc header/footer tags
     505                        if ($this->option_md5_data) {
     506                                // do not cald md5_data if md5_data_source is present - set by flac only - future MPC/SV8 too
     507                                if (!$this->option_md5_data_source || empty($this->info['md5_data_source'])) {
     508                                        $this->getHashdata('md5');
     509                                }
     510                        }
     511
     512                        // get the SHA1 sum of the audio/video portion of the file - without ID3/APE/Lyrics3/etc header/footer tags
     513                        if ($this->option_sha1_data) {
     514                                $this->getHashdata('sha1');
     515                        }
     516
     517                        // remove undesired keys
     518                        $this->CleanUp();
     519
     520                } catch (Exception $e) {
     521                        if (isset($this->info['error'])) {
     522                                $this->info['error'][] = 'Caught exception: '.$e->getMessage();
    172523                        } else {
    173                                 $errormessage .= 'PHP is not compiled with iconv() support. Please recompile with the --with-iconv switch';
    174                         }
    175                 return $this->error($errormessage);
    176                 }
    177 
    178                 // Disable magic_quotes_runtime, if neccesary
    179                 $old_magic_quotes_runtime = get_magic_quotes_runtime(); // store current setting of magic_quotes_runtime
    180                 if ($old_magic_quotes_runtime) {
    181                         set_magic_quotes_runtime(0);                        // turn off magic_quotes_runtime
    182                         if (get_magic_quotes_runtime()) {
    183                                 return $this->error('Could not disable magic_quotes_runtime - getID3() cannot work properly with this setting enabled');
    184                         }
    185                 }
    186 
    187                 // remote files not supported
    188                 if (preg_match('/^(ht|f)tp:\/\//', $filename)) {
    189                         return $this->error('Remote files are not supported in this version of getID3() - please copy the file locally first');
    190                 }
    191 
    192                 // open local file
    193                 if (!$fp = @fopen($filename, 'rb')) {
    194                         return $this->error('Could not open file "'.$filename.'"');
    195                 }
    196 
    197                 // set parameters
    198                 $this->info['filesize'] = filesize($filename);
    199 
    200                 // option_max_2gb_check
    201                 if ($this->option_max_2gb_check) {
    202                         // PHP doesn't support integers larger than 31-bit (~2GB)
    203                         // filesize() simply returns (filesize % (pow(2, 32)), no matter the actual filesize
    204                         // ftell() returns 0 if seeking to the end is beyond the range of unsigned integer
    205                         fseek($fp, 0, SEEK_END);
    206                         if ((($this->info['filesize'] != 0) && (ftell($fp) == 0)) ||
    207                                 ($this->info['filesize'] < 0) ||
    208                                 (ftell($fp) < 0)) {
    209                                         unset($this->info['filesize']);
    210                                         fclose($fp);
    211                                         return $this->error('File is most likely larger than 2GB and is not supported by PHP');
    212                         }
    213                 }
    214 
    215                 // set more parameters
    216                 $this->info['avdataoffset']        = 0;
    217                 $this->info['avdataend']           = $this->info['filesize'];
    218                 $this->info['fileformat']          = '';                // filled in later
    219                 $this->info['audio']['dataformat'] = '';                // filled in later, unset if not used
    220                 $this->info['video']['dataformat'] = '';                // filled in later, unset if not used
    221                 $this->info['tags']                = array();           // filled in later, unset if not used
    222                 $this->info['error']               = array();           // filled in later, unset if not used
    223                 $this->info['warning']             = array();           // filled in later, unset if not used
    224                 $this->info['comments']            = array();           // filled in later, unset if not used
    225                 $this->info['encoding']            = $this->encoding;   // required by id3v2 and iso modules - can be unset at the end if desired
    226 
    227                 // set redundant parameters - might be needed in some include file
    228                 $this->info['filename']            = basename($filename);
    229                 $this->info['filepath']            = str_replace('\\', '/', realpath(dirname($filename)));
    230                 $this->info['filenamepath']        = $this->info['filepath'].'/'.$this->info['filename'];
    231 
    232 
    233                 // handle ID3v2 tag - done first - already at beginning of file
    234                 // ID3v2 detection (even if not parsing) is always done otherwise fileformat is much harder to detect
    235                 if ($this->option_tag_id3v2) {
    236 
    237                         $GETID3_ERRORARRAY = &$this->info['warning'];
    238                         if (getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, false)) {
    239                                 $tag = new getid3_id3v2($fp, $this->info);
    240                                 unset($tag);
    241                         }
    242 
    243                 } else {
    244 
    245                         fseek($fp, 0, SEEK_SET);
    246                         $header = fread($fp, 10);
    247                         if (substr($header, 0, 3) == 'ID3'  &&  strlen($header) == 10) {
    248                                 $this->info['id3v2']['header']           = true;
    249                                 $this->info['id3v2']['majorversion']     = ord($header{3});
    250                                 $this->info['id3v2']['minorversion']     = ord($header{4});
    251                                 $this->info['id3v2']['headerlength']     = getid3_lib::BigEndian2Int(substr($header, 6, 4), 1) + 10; // length of ID3v2 tag in 10-byte header doesn't include 10-byte header length
    252 
    253                                 $this->info['id3v2']['tag_offset_start'] = 0;
    254                                 $this->info['id3v2']['tag_offset_end']   = $this->info['id3v2']['tag_offset_start'] + $this->info['id3v2']['headerlength'];
    255                                 $this->info['avdataoffset']              = $this->info['id3v2']['tag_offset_end'];
    256                         }
    257 
    258                 }
    259 
    260 
    261                 // handle ID3v1 tag
    262                 if ($this->option_tag_id3v1) {
    263                         if (!@include_once(GETID3_INCLUDEPATH.'module.tag.id3v1.php')) {
    264                                 return $this->error('module.tag.id3v1.php is missing - you may disable option_tag_id3v1.');
    265                         }
    266                         $tag = new getid3_id3v1($fp, $this->info);
    267                         unset($tag);
    268                 }
    269 
    270                 // handle APE tag
    271                 if ($this->option_tag_apetag) {
    272                         if (!@include_once(GETID3_INCLUDEPATH.'module.tag.apetag.php')) {
    273                                 return $this->error('module.tag.apetag.php is missing - you may disable option_tag_apetag.');
    274                         }
    275                         $tag = new getid3_apetag($fp, $this->info);
    276                         unset($tag);
    277                 }
    278 
    279                 // handle lyrics3 tag
    280                 if ($this->option_tag_lyrics3) {
    281                         if (!@include_once(GETID3_INCLUDEPATH.'module.tag.lyrics3.php')) {
    282                                 return $this->error('module.tag.lyrics3.php is missing - you may disable option_tag_lyrics3.');
    283                         }
    284                         $tag = new getid3_lyrics3($fp, $this->info);
    285                         unset($tag);
    286                 }
    287 
    288                 // read 32 kb file data
    289                 fseek($fp, $this->info['avdataoffset'], SEEK_SET);
    290                 $formattest = fread($fp, 32774);
    291 
    292                 // determine format
    293                 $determined_format = $this->GetFileFormat($formattest, $filename);
    294 
    295                 // unable to determine file format
    296                 if (!$determined_format) {
    297                         fclose($fp);
    298                         return $this->error('unable to determine file format');
    299                 }
    300 
    301                 // check for illegal ID3 tags
    302                 if (isset($determined_format['fail_id3']) && (in_array('id3v1', $this->info['tags']) || in_array('id3v2', $this->info['tags']))) {
    303                         if ($determined_format['fail_id3'] === 'ERROR') {
    304                                 fclose($fp);
    305                                 return $this->error('ID3 tags not allowed on this file type.');
    306                         } elseif ($determined_format['fail_id3'] === 'WARNING') {
    307                                 $this->info['warning'][] = 'ID3 tags not allowed on this file type.';
    308                         }
    309                 }
    310 
    311                 // check for illegal APE tags
    312                 if (isset($determined_format['fail_ape']) && in_array('ape', $this->info['tags'])) {
    313                         if ($determined_format['fail_ape'] === 'ERROR') {
    314                                 fclose($fp);
    315                                 return $this->error('APE tags not allowed on this file type.');
    316                         } elseif ($determined_format['fail_ape'] === 'WARNING') {
    317                                 $this->info['warning'][] = 'APE tags not allowed on this file type.';
    318                         }
    319                 }
    320 
    321                 // set mime type
    322                 $this->info['mime_type'] = $determined_format['mime_type'];
    323 
    324                 // supported format signature pattern detected, but module deleted
    325                 if (!file_exists(GETID3_INCLUDEPATH.$determined_format['include'])) {
    326                         fclose($fp);
    327                         return $this->error('Format not supported, module, '.$determined_format['include'].', was removed.');
    328                 }
    329 
    330                 // module requires iconv support
    331         if (!function_exists('iconv') && @$determined_format['iconv_req']) {
    332                     return $this->error('iconv support is required for this module ('.$determined_format['include'].').');
    333                 }
    334 
    335                 // include module
    336                 include_once(GETID3_INCLUDEPATH.$determined_format['include']);
    337 
    338                 // instantiate module class
    339                 $class_name = 'getid3_'.$determined_format['module'];
    340                 if (!class_exists($class_name)) {
    341                         return $this->error('Format not supported, module, '.$determined_format['include'].', is corrupt.');
    342                 }
    343                 if (isset($determined_format['option'])) {
    344                         $class = new $class_name($fp, $this->info, $determined_format['option']);
    345                 } else {
    346                         $class = new $class_name($fp, $this->info);
    347                 }
    348                 unset($class);
    349 
    350                 // close file
    351                 fclose($fp);
    352 
    353                 // process all tags - copy to 'tags' and convert charsets
    354                 if ($this->option_tags_process) {
    355                         $this->HandleAllTags();
    356                 }
    357 
    358                 // perform more calculations
    359                 if ($this->option_extra_info) {
    360                         $this->ChannelsBitratePlaytimeCalculations();
    361                         $this->CalculateCompressionRatioVideo();
    362                         $this->CalculateCompressionRatioAudio();
    363                         $this->CalculateReplayGain();
    364                         $this->ProcessAudioStreams();
    365                 }
    366 
    367                 // get the MD5 sum of the audio/video portion of the file - without ID3/APE/Lyrics3/etc header/footer tags
    368                 if ($this->option_md5_data) {
    369                         // do not cald md5_data if md5_data_source is present - set by flac only - future MPC/SV8 too
    370                         if (!$this->option_md5_data_source || empty($this->info['md5_data_source'])) {
    371                                 $this->getHashdata('md5');
    372                         }
    373                 }
    374 
    375                 // get the SHA1 sum of the audio/video portion of the file - without ID3/APE/Lyrics3/etc header/footer tags
    376                 if ($this->option_sha1_data) {
    377                         $this->getHashdata('sha1');
    378                 }
    379 
    380                 // remove undesired keys
    381                 $this->CleanUp();
    382 
    383                 // restore magic_quotes_runtime setting
    384                 set_magic_quotes_runtime($old_magic_quotes_runtime);
     524                                $this->info['error'] = array('Caught exception: '.$e->getMessage());
     525                        }
     526                }
    385527
    386528                // return info array
     
    391533        // private: error handling
    392534        function error($message) {
    393 
    394535                $this->CleanUp();
    395536
     
    438579                        }
    439580                }
     581
     582                // remove possible duplicated identical entries
     583                if (!empty($this->info['error'])) {
     584                        $this->info['error'] = array_values(array_unique($this->info['error']));
     585                }
     586                if (!empty($this->info['warning'])) {
     587                        $this->info['warning'] = array_values(array_unique($this->info['warning']));
     588                }
     589
     590                // remove "global variable" type keys
     591                unset($this->info['php_memory_limit']);
     592
     593                return true;
    440594        }
    441595
     
    462616                                                        'group'     => 'audio',
    463617                                                        'module'    => 'aac',
    464                                                         'option'    => 'adif',
    465618                                                        'mime_type' => 'application/octet-stream',
    466619                                                        'fail_ape'  => 'WARNING',
    467620                                                ),
    468621
     622
     623                                // AA   - audio       - Audible Audiobook
     624                                'adts' => array(
     625                                                        'pattern'   => '^.{4}\x57\x90\x75\x36',
     626                                                        'group'     => 'audio',
     627                                                        'module'    => 'aa',
     628                                                        'mime_type' => 'audio/audible ',
     629                                                ),
    469630
    470631                                // AAC  - audio       - Advanced Audio Coding (AAC) - ADTS format (very similar to MP3)
     
    473634                                                        'group'     => 'audio',
    474635                                                        'module'    => 'aac',
    475                                                         'option'    => 'adts',
    476636                                                        'mime_type' => 'application/octet-stream',
    477637                                                        'fail_ape'  => 'WARNING',
     
    503663                                                ),
    504664
     665                                // DSS  - audio       - Digital Speech Standard
     666                                'dss'  => array(
     667                                                        'pattern'   => '^[\x02-\x03]dss',
     668                                                        'group'     => 'audio',
     669                                                        'module'    => 'dss',
     670                                                        'mime_type' => 'application/octet-stream',
     671                                                ),
     672
    505673                                // DTS  - audio       - Dolby Theatre System
    506674                                'dts'  => array(
     
    517685                                                        'module'    => 'flac',
    518686                                                        'mime_type' => 'audio/x-flac',
     687                                                        'set_inline_attachments' => true,
    519688                                                ),
    520689
     
    551720                                                ),
    552721
    553                                 // MOD  - audio       - MODule (assorted sub-formats)
    554                                 'mod'  => array(
    555                                                         'pattern'   => '^.{1080}(M.K.|[5-9]CHN|[1-3][0-9]CH)',
    556                                                         'group'     => 'audio',
    557                                                         'module'    => 'mod',
    558                                                         'option'    => 'mod',
    559                                                         'mime_type' => 'audio/mod',
    560                                                 ),
     722// has been known to produce false matches in random files (e.g. JPEGs), leave out until more precise matching available
     723//                              // MOD  - audio       - MODule (assorted sub-formats)
     724//                              'mod'  => array(
     725//                                                      'pattern'   => '^.{1080}(M\\.K\\.|M!K!|FLT4|FLT8|[5-9]CHN|[1-3][0-9]CH)',
     726//                                                      'group'     => 'audio',
     727//                                                      'module'    => 'mod',
     728//                                                      'option'    => 'mod',
     729//                                                      'mime_type' => 'audio/mod',
     730//                                              ),
    561731
    562732                                // MOD  - audio       - MODule (Impulse Tracker)
     
    565735                                                        'group'     => 'audio',
    566736                                                        'module'    => 'mod',
    567                                                         'option'    => 'it',
     737                                                        //'option'    => 'it',
    568738                                                        'mime_type' => 'audio/it',
    569739                                                ),
     
    574744                                                        'group'     => 'audio',
    575745                                                        'module'    => 'mod',
    576                                                         'option'    => 'xm',
     746                                                        //'option'    => 'xm',
    577747                                                        'mime_type' => 'audio/xm',
    578748                                                ),
     
    583753                                                        'group'     => 'audio',
    584754                                                        'module'    => 'mod',
    585                                                         'option'    => 's3m',
     755                                                        //'option'    => 's3m',
    586756                                                        'mime_type' => 'audio/s3m',
    587757                                                ),
     
    589759                                // MPC  - audio       - Musepack / MPEGplus
    590760                                'mpc'  => array(
    591                                                         'pattern'   => '^(MP\+|[\x00\x01\x10\x11\x40\x41\x50\x51\x80\x81\x90\x91\xC0\xC1\xD0\xD1][\x20-37][\x00\x20\x40\x60\x80\xA0\xC0\xE0])',
     761                                                        'pattern'   => '^(MPCK|MP\+|[\x00\x01\x10\x11\x40\x41\x50\x51\x80\x81\x90\x91\xC0\xC1\xD0\xD1][\x20-37][\x00\x20\x40\x60\x80\xA0\xC0\xE0])',
    592762                                                        'group'     => 'audio',
    593763                                                        'module'    => 'mpc',
     
    597767                                // MP3  - audio       - MPEG-audio Layer 3 (very similar to AAC-ADTS)
    598768                                'mp3'  => array(
    599                                                         'pattern'   => '^\xFF[\xE2-\xE7\xF2-\xF7\xFA-\xFF][\x00-\xEB]',
     769                                                        'pattern'   => '^\xFF[\xE2-\xE7\xF2-\xF7\xFA-\xFF][\x00-\x0B\x10-\x1B\x20-\x2B\x30-\x3B\x40-\x4B\x50-\x5B\x60-\x6B\x70-\x7B\x80-\x8B\x90-\x9B\xA0-\xAB\xB0-\xBB\xC0-\xCB\xD0-\xDB\xE0-\xEB\xF0-\xFB]',
    600770                                                        'group'     => 'audio',
    601771                                                        'module'    => 'mp3',
     
    694864                                                        'group'     => 'audio-video',
    695865                                                        'module'    => 'matroska',
    696                                                         'mime_type' => 'application/octet-stream',
     866                                                        'mime_type' => 'video/x-matroska', // may also be audio/x-matroska
     867                                                        'set_inline_attachments' => true,
    697868                                                ),
    698869
     
    721892                                                        'fail_id3'  => 'WARNING',
    722893                                                        'fail_ape'  => 'WARNING',
     894                                                        'set_inline_attachments' => true,
    723895                                                ),
    724896
     
    742914                                // Real - audio/video - RealAudio, RealVideo
    743915                                'real' => array(
    744                                                         'pattern'   => '^(\.RMF|.ra)',
     916                                                        'pattern'   => '^(\\.RMF|\\.ra)',
    745917                                                        'group'     => 'audio-video',
    746918                                                        'module'    => 'real',
     
    811983
    812984
    813                 // SVG  - still image - Scalable Vector Graphics (SVG)
     985                                // SVG  - still image - Scalable Vector Graphics (SVG)
    814986                                'svg'  => array(
    815                                                         'pattern'   => '<!DOCTYPE svg PUBLIC ',
     987                                                        'pattern'   => '(<!DOCTYPE svg PUBLIC |xmlns="http:\/\/www\.w3\.org\/2000\/svg")',
    816988                                                        'group'     => 'graphic',
    817989                                                        'module'    => 'svg',
     
    8991071                                // Misc other formats
    9001072
    901                 // PAR2 - data        - Parity Volume Set Specification 2.0
    902                 'par2' => array (
    903                                         'pattern'   => '^PAR2\x00PKT',
    904                                         'group'     => 'misc',
     1073                                // PAR2 - data        - Parity Volume Set Specification 2.0
     1074                                'par2' => array (
     1075                                                        'pattern'   => '^PAR2\x00PKT',
     1076                                                        'group'     => 'misc',
    9051077                                                        'module'    => 'par2',
    9061078                                                        'mime_type' => 'application/octet-stream',
     
    9211093                                // MSOFFICE  - data   - ZIP compressed data
    9221094                                'msoffice' => array(
    923                                                         'pattern'   => '^\xD0\xCF\x11\xE0', // D0CF11E == DOCFILE == Microsoft Office Document
     1095                                                        'pattern'   => '^\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1', // D0CF11E == DOCFILE == Microsoft Office Document
    9241096                                                        'group'     => 'misc',
    9251097                                                        'module'    => 'msoffice',
     
    9281100                                                        'fail_ape'  => 'ERROR',
    9291101                                                ),
     1102
     1103                                 // CUE  - data       - CUEsheet (index to single-file disc images)
     1104                                 'cue' => array(
     1105                                                        'pattern'   => '', // empty pattern means cannot be automatically detected, will fall through all other formats and match based on filename and very basic file contents
     1106                                                        'group'     => 'misc',
     1107                                                        'module'    => 'cue',
     1108                                                        'mime_type' => 'application/octet-stream',
     1109                                                   ),
     1110
    9301111                        );
    9311112                }
     
    9441125                // Identify file format - loop through $format_info and detect with reg expr
    9451126                foreach ($this->GetFileFormatArray() as $format_name => $info) {
    946                         // Using preg_match() instead of ereg() - much faster
    9471127                        // The /s switch on preg_match() forces preg_match() NOT to treat
    9481128                        // newline (0x0A) characters as special chars but do a binary match
    949                         if (preg_match('/'.$info['pattern'].'/s', $filedata)) {
     1129                        if (!empty($info['pattern']) && preg_match('#'.$info['pattern'].'#s', $filedata)) {
    9501130                                $info['include'] = 'module.'.$info['group'].'.'.$info['module'].'.php';
    9511131                                return $info;
     
    9541134
    9551135
    956                 if (preg_match('/\.mp[123a]$/i', $filename)) {
     1136                if (preg_match('#\.mp[123a]$#i', $filename)) {
    9571137                        // Too many mp3 encoders on the market put gabage in front of mpeg files
    9581138                        // use assume format on these if format detection failed
     
    9601140                        $info = $GetFileFormatArray['mp3'];
    9611141                        $info['include'] = 'module.'.$info['group'].'.'.$info['module'].'.php';
     1142                        return $info;
     1143                } elseif (preg_match('/\.cue$/i', $filename) && preg_match('#FILE "[^"]+" (BINARY|MOTOROLA|AIFF|WAVE|MP3)#', $filedata)) {
     1144                        // there's not really a useful consistent "magic" at the beginning of .cue files to identify them
     1145                        // so until I think of something better, just go by filename if all other format checks fail
     1146                        // and verify there's at least one instance of "TRACK xx AUDIO" in the file
     1147                        $GetFileFormatArray = $this->GetFileFormatArray();
     1148                        $info = $GetFileFormatArray['cue'];
     1149                        $info['include']   = 'module.'.$info['group'].'.'.$info['module'].'.php';
    9621150                        return $info;
    9631151                }
     
    10031191                                'png'       => array('png'           , 'UTF-8'),
    10041192                                'tiff'      => array('tiff'          , 'ISO-8859-1'),
    1005                                 'quicktime' => array('quicktime'     , 'ISO-8859-1'),
     1193                                'quicktime' => array('quicktime'     , 'UTF-8'),
    10061194                                'real'      => array('real'          , 'ISO-8859-1'),
    10071195                                'vqf'       => array('vqf'           , 'ISO-8859-1'),
     
    10111199                                'id3v1'     => array('id3v1'         , $this->encoding_id3v1),
    10121200                                'id3v2'     => array('id3v2'         , 'UTF-8'), // not according to the specs (every frame can have a different encoding), but getID3() force-converts all encodings to UTF-8
    1013                                 'ape'       => array('ape'           , 'UTF-8')
     1201                                'ape'       => array('ape'           , 'UTF-8'),
     1202                                'cue'       => array('cue'           , 'ISO-8859-1'),
     1203                                'matroska'  => array('matroska'      , 'UTF-8'),
    10141204                        );
    10151205                }
    10161206
    1017                 // loop thru comments array
     1207                // loop through comments array
    10181208                foreach ($tags as $comment_name => $tagname_encoding_array) {
    10191209                        list($tag_name, $encoding) = $tagname_encoding_array;
     
    10291219                                foreach ($this->info[$comment_name]['comments'] as $tag_key => $valuearray) {
    10301220                                        foreach ($valuearray as $key => $value) {
    1031                                                 if (strlen(trim($value)) > 0) {
    1032                                                         $this->info['tags'][trim($tag_name)][trim($tag_key)][] = $value; // do not trim!! Unicode characters will get mangled if trailing nulls are removed!
     1221                                                if (is_string($value)) {
     1222                                                        $value = trim($value, " \r\n\t"); // do not trim nulls from $value!! Unicode characters will get mangled if trailing nulls are removed!
     1223                                                }
     1224                                                if ($value) {
     1225                                                        $this->info['tags'][trim($tag_name)][trim($tag_key)][] = $value;
    10331226                                                }
    10341227                                        }
     
    10451238                                                        if (is_string($value)) {
    10461239                                                                //$this->info['tags_html'][$tag_name][$tag_key][$key] = getid3_lib::MultiByteCharString2HTML($value, $encoding);
    1047                                                                 $this->info['tags_html'][$tag_name][$tag_key][$key] = str_replace('&#0;', '', getid3_lib::MultiByteCharString2HTML($value, $encoding));
     1240                                                                $this->info['tags_html'][$tag_name][$tag_key][$key] = str_replace('&#0;', '', trim(getid3_lib::MultiByteCharString2HTML($value, $encoding)));
    10481241                                                        } else {
    10491242                                                                $this->info['tags_html'][$tag_name][$tag_key][$key] = $value;
     
    10571250
    10581251                }
     1252
     1253                // pictures can take up a lot of space, and we don't need multiple copies of them
     1254                // let there be a single copy in [comments][picture], and not elsewhere
     1255                if (!empty($this->info['tags'])) {
     1256                        $unset_keys = array('tags', 'tags_html');
     1257                        foreach ($this->info['tags'] as $tagtype => $tagarray) {
     1258                                foreach ($tagarray as $tagname => $tagdata) {
     1259                                        if ($tagname == 'picture') {
     1260                                                foreach ($tagdata as $key => $tagarray) {
     1261                                                        $this->info['comments']['picture'][] = $tagarray;
     1262                                                        if (isset($tagarray['data']) && isset($tagarray['image_mime'])) {
     1263                                                                if (isset($this->info['tags'][$tagtype][$tagname][$key])) {
     1264                                                                        unset($this->info['tags'][$tagtype][$tagname][$key]);
     1265                                                                }
     1266                                                                if (isset($this->info['tags_html'][$tagtype][$tagname][$key])) {
     1267                                                                        unset($this->info['tags_html'][$tagtype][$tagname][$key]);
     1268                                                                }
     1269                                                        }
     1270                                                }
     1271                                        }
     1272                                }
     1273                                foreach ($unset_keys as $unset_key) {
     1274                                        // remove possible empty keys from (e.g. [tags][id3v2][picture])
     1275                                        if (empty($this->info[$unset_key][$tagtype]['picture'])) {
     1276                                                unset($this->info[$unset_key][$tagtype]['picture']);
     1277                                        }
     1278                                        if (empty($this->info[$unset_key][$tagtype])) {
     1279                                                unset($this->info[$unset_key][$tagtype]);
     1280                                        }
     1281                                        if (empty($this->info[$unset_key])) {
     1282                                                unset($this->info[$unset_key]);
     1283                                        }
     1284                                }
     1285                                // remove duplicate copy of picture data from (e.g. [id3v2][comments][picture])
     1286                                if (isset($this->info[$tagtype]['comments']['picture'])) {
     1287                                        unset($this->info[$tagtype]['comments']['picture']);
     1288                                }
     1289                                if (empty($this->info[$tagtype]['comments'])) {
     1290                                        unset($this->info[$tagtype]['comments']);
     1291                                }
     1292                                if (empty($this->info[$tagtype])) {
     1293                                        unset($this->info[$tagtype]);
     1294                                }
     1295                        }
     1296                }
    10591297                return true;
    10601298        }
     
    10721310                }
    10731311
    1074                 if ((@$this->info['fileformat'] == 'ogg') && (@$this->info['audio']['dataformat'] == 'vorbis')) {
     1312                if (!empty($this->info['fileformat']) && !empty($this->info['dataformat']) && ($this->info['fileformat'] == 'ogg') && ($this->info['audio']['dataformat'] == 'vorbis')) {
    10751313
    10761314                        // We cannot get an identical md5_data value for Ogg files where the comments
     
    10921330                        // currently vorbiscomment only works on OggVorbis files.
    10931331
    1094                         if ((bool) ini_get('safe_mode')) {
     1332                        if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) {
    10951333
    10961334                                $this->info['warning'][] = 'Failed making system call to vorbiscomment.exe - '.$algorithm.'_data is incorrect - error returned: PHP running in Safe Mode (backtick operator not available)';
     
    11031341
    11041342                                // Create empty file
    1105                                 $empty = tempnam('*', 'getID3');
     1343                                $empty = tempnam(GETID3_TEMP_DIR, 'getID3');
    11061344                                touch($empty);
    11071345
    1108 
    11091346                                // Use vorbiscomment to make temp file without comments
    1110                                 $temp = tempnam('*', 'getID3');
     1347                                $temp = tempnam(GETID3_TEMP_DIR, 'getID3');
    11111348                                $file = $this->info['filenamepath'];
    11121349
     
    11421379                                        switch ($algorithm) {
    11431380                                                case 'md5':
    1144                                                         $this->info[$algorithm.'_data'] = getid3_lib::md5_file($temp);
     1381                                                        $this->info[$algorithm.'_data'] = md5_file($temp);
    11451382                                                        break;
    11461383
    11471384                                                case 'sha1':
    1148                                                         $this->info[$algorithm.'_data'] = getid3_lib::sha1_file($temp);
     1385                                                        $this->info[$algorithm.'_data'] = sha1_file($temp);
    11491386                                                        break;
    11501387                                        }
     
    11721409                                switch ($algorithm) {
    11731410                                        case 'md5':
    1174                                                 $this->info[$algorithm.'_data'] = getid3_lib::md5_file($this->info['filenamepath']);
     1411                                                $this->info[$algorithm.'_data'] = md5_file($this->info['filenamepath']);
    11751412                                                break;
    11761413
    11771414                                        case 'sha1':
    1178                                                 $this->info[$algorithm.'_data'] = getid3_lib::sha1_file($this->info['filenamepath']);
     1415                                                $this->info[$algorithm.'_data'] = sha1_file($this->info['filenamepath']);
    11791416                                                break;
    11801417                                }
     
    11891426
    11901427                // set channelmode on audio
    1191                 if (@$this->info['audio']['channels'] == '1') {
     1428                if (!empty($this->info['audio']['channelmode']) || !isset($this->info['audio']['channels'])) {
     1429                        // ignore
     1430                } elseif ($this->info['audio']['channels'] == 1) {
    11921431                        $this->info['audio']['channelmode'] = 'mono';
    1193                 } elseif (@$this->info['audio']['channels'] == '2') {
     1432                } elseif ($this->info['audio']['channels'] == 2) {
    11941433                        $this->info['audio']['channelmode'] = 'stereo';
    11951434                }
     
    12251464                }
    12261465
    1227                 if (!isset($this->info['playtime_seconds']) && !empty($this->info['bitrate'])) {
     1466                if ((!isset($this->info['playtime_seconds']) || ($this->info['playtime_seconds'] <= 0)) && !empty($this->info['bitrate'])) {
    12281467                        $this->info['playtime_seconds'] = (($this->info['avdataend'] - $this->info['avdataoffset']) * 8) / $this->info['bitrate'];
     1468                }
     1469
     1470                if (!isset($this->info['bitrate']) && !empty($this->info['playtime_seconds'])) {
     1471                        $this->info['bitrate'] = (($this->info['avdataend'] - $this->info['avdataoffset']) * 8) / $this->info['playtime_seconds'];
     1472                }
     1473                if (isset($this->info['bitrate']) && empty($this->info['audio']['bitrate']) && empty($this->info['video']['bitrate'])) {
     1474                        if (isset($this->info['audio']['dataformat']) && empty($this->info['video']['resolution_x'])) {
     1475                                // audio only
     1476                                $this->info['audio']['bitrate'] = $this->info['bitrate'];
     1477                        } elseif (isset($this->info['video']['resolution_x']) && empty($this->info['audio']['dataformat'])) {
     1478                                // video only
     1479                                $this->info['video']['bitrate'] = $this->info['bitrate'];
     1480                        }
    12291481                }
    12301482
     
    13031555        function CalculateReplayGain() {
    13041556                if (isset($this->info['replay_gain'])) {
    1305                         $this->info['replay_gain']['reference_volume'] = 89;
     1557                        if (!isset($this->info['replay_gain']['reference_volume'])) {
     1558                                $this->info['replay_gain']['reference_volume'] = (double) 89.0;
     1559                        }
    13061560                        if (isset($this->info['replay_gain']['track']['adjustment'])) {
    13071561                                $this->info['replay_gain']['track']['volume'] = $this->info['replay_gain']['reference_volume'] - $this->info['replay_gain']['track']['adjustment'];
     
    13381592        }
    13391593
     1594
     1595        public function saveAttachment(&$ThisFileInfoIndex, $filename, $offset, $length) {
     1596                try {
     1597                        if (!getid3_lib::intValueSupported($offset + $length)) {
     1598                                throw new Exception('cannot extract attachment, it extends beyond the '.round(PHP_INT_MAX / 1073741824).'GB limit');
     1599                        }
     1600                        switch ($this->option_save_attachments) {
     1601                                case getID3::ATTACHMENTS_NONE: // do not extract attachments data
     1602                                        unset($ThisFileInfoIndex); // do not set any
     1603                                        break;
     1604
     1605                                case getID3::ATTACHMENTS_INLINE: // extract to return array
     1606                                        // get whole data in one pass, till it is anyway stored in memory
     1607                                        $ThisFileInfoIndex = file_get_contents($this->info['filenamepath'], false, null, $offset, $length);
     1608                                        if (($ThisFileInfoIndex === false) || (strlen($ThisFileInfoIndex) != $length)) { // verify
     1609                                                throw new Exception('failed to read attachment data');
     1610                                        }
     1611                                        break;
     1612
     1613                                default: // assume directory path is given
     1614                                        $dir = rtrim(str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $this->option_save_attachments), DIRECTORY_SEPARATOR);
     1615                                        // check supplied directory
     1616                                        if (!is_dir($dir) || !is_writable($dir)) {
     1617                                                throw new Exception('getID3::saveAttachment() -- supplied path ('.$dir.') does not exist, or is not writable');
     1618                                        }
     1619
     1620                                        // set up destination path
     1621                                        $dest = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $dir).DIRECTORY_SEPARATOR.$filename;
     1622
     1623                                        // optimize speed if read buffer size is configured to be large enough
     1624                                        // here stream_copy_to_stream() may also be used. need to do speed-compare tests
     1625                                        if ($length <= $this->option_read_buffer_size) {
     1626                                                $data = file_get_contents($this->info['filenamepath'], false, null, $offset, $length);
     1627                                                if (($data === false) || (strlen($data) != $length)) { // verify
     1628                                                        throw new Exception('failed to read attachment data');
     1629                                                }
     1630                                                if (!file_put_contents($dest, $data)) {
     1631                                                        throw new Exception('failed to create file '.$dest);
     1632                                                }
     1633                                        } else {
     1634                                                // optimization not available - copy data in loop
     1635                                                // here stream_copy_to_stream() shouldn't be used because it's internal read buffer may be larger than ours!
     1636
     1637                                                try {
     1638                                                        getid3_lib::CopyFileParts($this->info['filenamepath'], $filename, $offset, $length);
     1639                                                } catch (Exception $e) {
     1640                                                        throw $e;
     1641                                                }
     1642                                        }
     1643                                        $ThisFileInfoIndex = $dest;
     1644                                        break;
     1645                        }
     1646                } catch (Exception $e) {
     1647                        unset($ThisFileInfoIndex); // do not set any is case of error
     1648                        $this->warning('Failed to extract attachment '.$filename.': '.$e->getMessage());
     1649                        return false;
     1650                }
     1651                return true;
     1652        }
     1653
     1654
     1655        public function include_module($name) {
     1656                //if (!file_exists($this->include_path.'module.'.$name.'.php')) {
     1657                if (!file_exists(GETID3_INCLUDEPATH.'module.'.$name.'.php')) {
     1658                        throw new getid3_exception('Required module.'.$name.'.php is missing.');
     1659                }
     1660                include_once(GETID3_INCLUDEPATH.'module.'.$name.'.php');
     1661                return true;
     1662        }
     1663
    13401664}
    13411665
     1666
     1667abstract class getid3_handler
     1668{
     1669    protected $getid3;                          // pointer
     1670
     1671    protected $data_string_flag = false;        // analyzing filepointer or string
     1672    protected $data_string;                     // string to analyze
     1673    protected $data_string_position = 0;        // seek position in string
     1674
     1675
     1676    public function __construct(getID3 $getid3) {
     1677        $this->getid3 = $getid3;
     1678    }
     1679
     1680
     1681    // Analyze from file pointer
     1682    abstract public function Analyze();
     1683
     1684
     1685    // Analyze from string instead
     1686    public function AnalyzeString(&$string) {
     1687        // Enter string mode
     1688        $this->data_string_flag = true;
     1689        $this->data_string      = $string;
     1690
     1691        // Save info
     1692        $saved_avdataoffset = $this->getid3->info['avdataoffset'];
     1693        $saved_avdataend    = $this->getid3->info['avdataend'];
     1694        $saved_filesize     = $this->getid3->info['filesize'];
     1695
     1696        // Reset some info
     1697        $this->getid3->info['avdataoffset'] = 0;
     1698        $this->getid3->info['avdataend']    = $this->getid3->info['filesize'] = strlen($string);
     1699
     1700        // Analyze
     1701        $this->Analyze();
     1702
     1703        // Restore some info
     1704        $this->getid3->info['avdataoffset'] = $saved_avdataoffset;
     1705        $this->getid3->info['avdataend']    = $saved_avdataend;
     1706        $this->getid3->info['filesize']     = $saved_filesize;
     1707
     1708        // Exit string mode
     1709        $this->data_string_flag = false;
     1710    }
     1711
     1712
     1713    protected function ftell() {
     1714        if ($this->data_string_flag) {
     1715            return $this->data_string_position;
     1716        }
     1717        return ftell($this->getid3->fp);
     1718    }
     1719
     1720
     1721    protected function fread($bytes) {
     1722        if ($this->data_string_flag) {
     1723            $this->data_string_position += $bytes;
     1724            return substr($this->data_string, $this->data_string_position - $bytes, $bytes);
     1725        }
     1726        return fread($this->getid3->fp, $bytes);
     1727    }
     1728
     1729
     1730    protected function fseek($bytes, $whence = SEEK_SET) {
     1731        if ($this->data_string_flag) {
     1732            switch ($whence) {
     1733                case SEEK_SET:
     1734                    $this->data_string_position = $bytes;
     1735                    return;
     1736
     1737                case SEEK_CUR:
     1738                    $this->data_string_position += $bytes;
     1739                    return;
     1740
     1741                case SEEK_END:
     1742                    $this->data_string_position = strlen($this->data_string) + $bytes;
     1743                    return;
     1744            }
     1745        }
     1746        return fseek($this->getid3->fp, $bytes, $whence);
     1747    }
     1748
     1749}
     1750
     1751
     1752class getid3_exception extends Exception
     1753{
     1754    public $message;
     1755}
     1756
    13421757?>
  • _plugins_/getID3/getid3/module.archive.gzip.php

    r44571 r51852  
    1515//                                                             //
    1616// Module originally written by                                //
    17 //      Mike Mozolin <teddybearmail*ru>                       //
     17//      Mike Mozolin <teddybearØmail*ru>                       //
    1818//                                                             //
    1919/////////////////////////////////////////////////////////////////
    2020
    2121
    22 class getid3_gzip {
     22class getid3_gzip extends getid3_handler {
    2323
    2424        // public: Optional file list - disable for speed.
    2525        var $option_gzip_parse_contents = false; // decode gzipped files, if possible, and parse recursively (.tar.gz for example)
    2626
    27         function getid3_gzip(&$fd, &$ThisFileInfo) {
    28                 $ThisFileInfo['fileformat'] = 'gzip';
     27        function Analyze() {
     28                $info = &$this->getid3->info;
     29
     30                $info['fileformat'] = 'gzip';
    2931
    3032                $start_length = 10;
     
    3335                //|ID1|ID2|CM |FLG|     MTIME     |XFL|OS |
    3436                //+---+---+---+---+---+---+---+---+---+---+
    35                 @fseek($fd, 0);
    36                 $buffer = @fread($fd, $ThisFileInfo['filesize']);
     37
     38                if ($info['filesize'] > $info['php_memory_limit']) {
     39                        $info['error'][] = 'File is too large ('.number_format($info['filesize']).' bytes) to read into memory (limit: '.number_format($info['php_memory_limit'] / 1048576).'MB)';
     40                        return false;
     41                }
     42                fseek($this->getid3->fp, 0);
     43                $buffer = fread($this->getid3->fp, $info['filesize']);
    3744
    3845                $arr_members = explode("\x1F\x8B\x08", $buffer);
     
    6067                }
    6168
    62                 $ThisFileInfo['gzip']['files'] = array();
     69                $info['gzip']['files'] = array();
    6370
    6471                $fpointer = 0;
     
    6875                                continue;
    6976                        }
    70                         $thisThisFileInfo = &$ThisFileInfo['gzip']['member_header'][++$idx];
     77                        $thisInfo = &$info['gzip']['member_header'][++$idx];
    7178
    7279                        $buff = "\x1F\x8B\x08".$arr_members[$i];
    7380
    7481                        $attr = unpack($unpack_header, substr($buff, 0, $start_length));
    75                         $thisThisFileInfo['filemtime']      = getid3_lib::LittleEndian2Int($attr['mtime']);
    76                         $thisThisFileInfo['raw']['id1']     = ord($attr['cmethod']);
    77                         $thisThisFileInfo['raw']['id2']     = ord($attr['cmethod']);
    78                         $thisThisFileInfo['raw']['cmethod'] = ord($attr['cmethod']);
    79                         $thisThisFileInfo['raw']['os']      = ord($attr['os']);
    80                         $thisThisFileInfo['raw']['xflags']  = ord($attr['xflags']);
    81                         $thisThisFileInfo['raw']['flags']   = ord($attr['flags']);
    82 
    83                         $thisThisFileInfo['flags']['crc16']    = (bool) ($thisThisFileInfo['raw']['flags'] & 0x02);
    84                         $thisThisFileInfo['flags']['extra']    = (bool) ($thisThisFileInfo['raw']['flags'] & 0x04);
    85                         $thisThisFileInfo['flags']['filename'] = (bool) ($thisThisFileInfo['raw']['flags'] & 0x08);
    86                         $thisThisFileInfo['flags']['comment']  = (bool) ($thisThisFileInfo['raw']['flags'] & 0x10);
    87 
    88                         $thisThisFileInfo['compression'] = $this->get_xflag_type($thisThisFileInfo['raw']['xflags']);
    89 
    90                         $thisThisFileInfo['os'] = $this->get_os_type($thisThisFileInfo['raw']['os']);
    91                         if (!$thisThisFileInfo['os']) {
    92                                 $ThisFileInfo['error'][] = 'Read error on gzip file';
     82                        $thisInfo['filemtime']      = getid3_lib::LittleEndian2Int($attr['mtime']);
     83                        $thisInfo['raw']['id1']     = ord($attr['cmethod']);
     84                        $thisInfo['raw']['id2']     = ord($attr['cmethod']);
     85                        $thisInfo['raw']['cmethod'] = ord($attr['cmethod']);
     86                        $thisInfo['raw']['os']      = ord($attr['os']);
     87                        $thisInfo['raw']['xflags']  = ord($attr['xflags']);
     88                        $thisInfo['raw']['flags']   = ord($attr['flags']);
     89
     90                        $thisInfo['flags']['crc16']    = (bool) ($thisInfo['raw']['flags'] & 0x02);
     91                        $thisInfo['flags']['extra']    = (bool) ($thisInfo['raw']['flags'] & 0x04);
     92                        $thisInfo['flags']['filename'] = (bool) ($thisInfo['raw']['flags'] & 0x08);
     93                        $thisInfo['flags']['comment']  = (bool) ($thisInfo['raw']['flags'] & 0x10);
     94
     95                        $thisInfo['compression'] = $this->get_xflag_type($thisInfo['raw']['xflags']);
     96
     97                        $thisInfo['os'] = $this->get_os_type($thisInfo['raw']['os']);
     98                        if (!$thisInfo['os']) {
     99                                $info['error'][] = 'Read error on gzip file';
    93100                                return false;
    94101                        }
     
    100107                        //| XLEN  |...XLEN bytes of "extra field"...|
    101108                        //+---+---+=================================+
    102                         if ($thisThisFileInfo['flags']['extra']) {
     109                        if ($thisInfo['flags']['extra']) {
    103110                                $w_xlen = substr($buff, $fpointer, 2);
    104111                                $xlen = getid3_lib::LittleEndian2Int($w_xlen);
    105112                                $fpointer += 2;
    106113
    107                                 $thisThisFileInfo['raw']['xfield'] = substr($buff, $fpointer, $xlen);
     114                                $thisInfo['raw']['xfield'] = substr($buff, $fpointer, $xlen);
    108115                                // Extra SubFields
    109116                                //+---+---+---+---+==================================+
     
    134141                        //+=========================================+
    135142                        // GZIP files may have only one file, with no filename, so assume original filename is current filename without .gz
    136                         $thisThisFileInfo['filename'] = preg_replace('/.gz$/', '', $ThisFileInfo['filename']);
    137                         if ($thisThisFileInfo['flags']['filename']) {
     143                        $thisInfo['filename'] = preg_replace('#\.gz$#i', '', $info['filename']);
     144                        if ($thisInfo['flags']['filename']) {
    138145                                while (true) {
    139146                                        if (ord($buff[$fpointer]) == 0) {
     
    141148                                                break;
    142149                                        }
    143                                         $thisThisFileInfo['filename'] .= $buff[$fpointer];
     150                                        $thisInfo['filename'] .= $buff[$fpointer];
    144151                                        $fpointer++;
    145152                                }
     
    149156                        //|...file comment, zero-terminated...|
    150157                        //+===================================+
    151                         if ($thisThisFileInfo['flags']['comment']) {
     158                        if ($thisInfo['flags']['comment']) {
    152159                                while (true) {
    153160                                        if (ord($buff[$fpointer]) == 0) {
     
    155162                                                break;
    156163                                        }
    157                                         $thisThisFileInfo['comment'] .= $buff[$fpointer];
     164                                        $thisInfo['comment'] .= $buff[$fpointer];
    158165                                        $fpointer++;
    159166                                }
     
    163170                        //| CRC16 |
    164171                        //+---+---+
    165                         if ($thisThisFileInfo['flags']['crc16']) {
     172                        if ($thisInfo['flags']['crc16']) {
    166173                                $w_crc = substr($buff, $fpointer, 2);
    167                                 $thisThisFileInfo['crc16'] = getid3_lib::LittleEndian2Int($w_crc);
     174                                $thisInfo['crc16'] = getid3_lib::LittleEndian2Int($w_crc);
    168175                                $fpointer += 2;
    169176                        }
    170177                        // bit 0 - FLG.FTEXT
    171                         //if ($thisThisFileInfo['raw']['flags'] & 0x01) {
     178                        //if ($thisInfo['raw']['flags'] & 0x01) {
    172179                        //      Ignored...
    173180                        //}
    174181                        // bits 5, 6, 7 - reserved
    175182
    176                         $thisThisFileInfo['crc32']    = getid3_lib::LittleEndian2Int(substr($buff, strlen($buff) - 8, 4));
    177                         $thisThisFileInfo['filesize'] = getid3_lib::LittleEndian2Int(substr($buff, strlen($buff) - 4));
    178 
    179                         $ThisFileInfo['gzip']['files'] = getid3_lib::array_merge_clobber($ThisFileInfo['gzip']['files'], getid3_lib::CreateDeepArray($thisThisFileInfo['filename'], '/', $thisThisFileInfo['filesize']));
     183                        $thisInfo['crc32']    = getid3_lib::LittleEndian2Int(substr($buff, strlen($buff) - 8, 4));
     184                        $thisInfo['filesize'] = getid3_lib::LittleEndian2Int(substr($buff, strlen($buff) - 4));
     185
     186                        $info['gzip']['files'] = getid3_lib::array_merge_clobber($info['gzip']['files'], getid3_lib::CreateDeepArray($thisInfo['filename'], '/', $thisInfo['filesize']));
    180187
    181188                        if ($this->option_gzip_parse_contents) {
     
    191198
    192199                                        // Calculate CRC32 for inflated content
    193                                         $thisThisFileInfo['crc32_valid'] = (bool) (sprintf('%u', crc32($inflated)) == $thisThisFileInfo['crc32']);
     200                                        $thisInfo['crc32_valid'] = (bool) (sprintf('%u', crc32($inflated)) == $thisInfo['crc32']);
    194201
    195202                                        // determine format
    196203                                        $formattest = substr($inflated, 0, 32774);
    197                                         $newgetID3 = new getID3();
    198                                         $determined_format = $newgetID3->GetFileFormat($formattest);
    199                                         unset($newgetID3);
    200 
    201                                 // file format is determined
    202                                 switch (@$determined_format['module']) {
    203                                         case 'tar':
     204                                        $getid3_temp = new getID3();
     205                                        $determined_format = $getid3_temp->GetFileFormat($formattest);
     206                                        unset($getid3_temp);
     207
     208                                        // file format is determined
     209                                        $determined_format['module'] = (isset($determined_format['module']) ? $determined_format['module'] : '');
     210                                        switch ($determined_format['module']) {
     211                                                case 'tar':
    204212                                                        // view TAR-file info
    205                                                         if (file_exists(GETID3_INCLUDEPATH.$determined_format['include']) && @include_once(GETID3_INCLUDEPATH.$determined_format['include'])) {
    206                                                                 if (($temp_tar_filename = tempnam('*', 'getID3')) === false) {
     213                                                        if (file_exists(GETID3_INCLUDEPATH.$determined_format['include']) && include_once(GETID3_INCLUDEPATH.$determined_format['include'])) {
     214                                                                if (($temp_tar_filename = tempnam(GETID3_TEMP_DIR, 'getID3')) === false) {
    207215                                                                        // can't find anywhere to create a temp file, abort
    208                                                                         $ThisFileInfo['error'][] = 'Unable to create temp file to parse TAR inside GZIP file';
     216                                                                        $info['error'][] = 'Unable to create temp file to parse TAR inside GZIP file';
    209217                                                                        break;
    210218                                                                }
    211219                                                                if ($fp_temp_tar = fopen($temp_tar_filename, 'w+b')) {
    212220                                                                        fwrite($fp_temp_tar, $inflated);
    213                                                                         rewind($fp_temp_tar);
    214                                                                         $getid3_tar = new getid3_tar($fp_temp_tar, $dummy);
    215                                                                         $ThisFileInfo['gzip']['member_header'][$idx]['tar'] = $dummy['tar'];
    216                                                                         unset($dummy);
    217                                                                         unset($getid3_tar);
    218221                                                                        fclose($fp_temp_tar);
     222                                                                        $getid3_temp = new getID3();
     223                                                                        $getid3_temp->openfile($temp_tar_filename);
     224                                                                        $getid3_tar = new getid3_tar($getid3_temp);
     225                                                                        $getid3_tar->Analyze();
     226                                                                        $info['gzip']['member_header'][$idx]['tar'] = $getid3_temp->info['tar'];
     227                                                                        unset($getid3_temp, $getid3_tar);
    219228                                                                        unlink($temp_tar_filename);
    220229                                                                } else {
    221                                                                         $ThisFileInfo['error'][] = 'Unable to fopen() temp file to parse TAR inside GZIP file';
     230                                                                        $info['error'][] = 'Unable to fopen() temp file to parse TAR inside GZIP file';
    222231                                                                        break;
    223232                                                                }
     
    225234                                                        break;
    226235
    227                                         case '':
    228                                         default:
    229                                                 // unknown or unhandled format
    230                                                 break;
     236                                                case '':
     237                                                default:
     238                                                        // unknown or unhandled format
     239                                                        break;
    231240                                        }
    232241                                }
     
    255264                        '255' => 'unknown'
    256265                );
    257                 return @$os_type[$key];
     266                return (isset($os_type[$key]) ? $os_type[$key] : '');
    258267        }
    259268
     
    265274                        '4' => 'fastest algorithm'
    266275                );
    267                 return @$xflag_type[$key];
     276                return (isset($xflag_type[$key]) ? $xflag_type[$key] : '');
    268277        }
    269278}
  • _plugins_/getID3/getid3/module.archive.rar.php

    r16273 r51852  
    1515
    1616
    17 class getid3_rar
     17class getid3_rar extends getid3_handler
    1818{
    1919
    20         function getid3_rar(&$fd, &$ThisFileInfo) {
     20        var $option_use_rar_extension = false;
    2121
    22                 $ThisFileInfo['fileformat'] = 'rar';
     22        function Analyze() {
     23                $info = &$this->getid3->info;
    2324
    24                 $ThisFileInfo['error'][] = 'RAR parsing not enabled in this version of getID3()';
     25                $info['fileformat'] = 'rar';
     26
     27                if ($this->option_use_rar_extension === true) {
     28                        if (function_exists('rar_open')) {
     29                                if ($rp = rar_open($info['filenamepath'])) {
     30                                        $info['rar']['files'] = array();
     31                                        $entries = rar_list($rp);
     32                                        foreach ($entries as $entry) {
     33                                                $info['rar']['files'] = getid3_lib::array_merge_clobber($info['rar']['files'], getid3_lib::CreateDeepArray($entry->getName(), '/', $entry->getUnpackedSize()));
     34                                        }
     35                                        rar_close($rp);
     36                                        return true;
     37                                } else {
     38                                        $info['error'][] = 'failed to rar_open('.$info['filename'].')';
     39                                }
     40                        } else {
     41                                $info['error'][] = 'RAR support does not appear to be available in this PHP installation';
     42                        }
     43                } else {
     44                        $info['error'][] = 'PHP-RAR processing has been disabled (set $getid3_rar->option_use_rar_extension=true to enable)';
     45                }
    2546                return false;
    2647
  • _plugins_/getID3/getid3/module.archive.szip.php

    r16273 r51852  
    1515
    1616
    17 class getid3_szip
     17class getid3_szip extends getid3_handler
    1818{
    1919
    20         function getid3_szip(&$fd, &$ThisFileInfo) {
     20        function Analyze() {
     21                $info = &$this->getid3->info;
    2122
    22                 fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
    23                 $SZIPHeader = fread($fd, 6);
    24                 if (substr($SZIPHeader, 0, 4) != 'SZ'."\x0A\x04") {
    25                         $ThisFileInfo['error'][] = 'Expecting "SZ[x0A][x04]" at offset '.$ThisFileInfo['avdataoffset'].', found "'.substr($SZIPHeader, 0, 4).'"';
     23                fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
     24                $SZIPHeader = fread($this->getid3->fp, 6);
     25                if (substr($SZIPHeader, 0, 4) != "SZ\x0A\x04") {
     26                        $info['error'][] = 'Expecting "53 5A 0A 04" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($SZIPHeader, 0, 4)).'"';
    2627                        return false;
    2728                }
     29                $info['fileformat']            = 'szip';
     30                $info['szip']['major_version'] = getid3_lib::BigEndian2Int(substr($SZIPHeader, 4, 1));
     31                $info['szip']['minor_version'] = getid3_lib::BigEndian2Int(substr($SZIPHeader, 5, 1));
    2832
    29                 $ThisFileInfo['fileformat']            = 'szip';
    30 
    31                 $ThisFileInfo['szip']['major_version'] = getid3_lib::BigEndian2Int(substr($SZIPHeader, 4, 1));
    32                 $ThisFileInfo['szip']['minor_version'] = getid3_lib::BigEndian2Int(substr($SZIPHeader, 5, 1));
    33 
    34                 while (!feof($fd)) {
    35                         $NextBlockID = fread($fd, 2);
     33                while (!feof($this->getid3->fp)) {
     34                        $NextBlockID = fread($this->getid3->fp, 2);
    3635                        switch ($NextBlockID) {
    3736                                case 'SZ':
     
    3938                                        // concatenating the files. this also means that global header blocks
    4039                                        // might be present between directory/data blocks.
    41                                         fseek($fd, 4, SEEK_CUR);
     40                                        fseek($this->getid3->fp, 4, SEEK_CUR);
    4241                                        break;
    4342
    4443                                case 'BH':
    45                                         $BHheaderbytes  = getid3_lib::BigEndian2Int(fread($fd, 3));
    46                                         $BHheaderdata   = fread($fd, $BHheaderbytes);
     44                                        $BHheaderbytes  = getid3_lib::BigEndian2Int(fread($this->getid3->fp, 3));
     45                                        $BHheaderdata   = fread($this->getid3->fp, $BHheaderbytes);
    4746                                        $BHheaderoffset = 0;
    4847                                        while (strpos($BHheaderdata, "\x00", $BHheaderoffset) > 0) {
     
    8079                                                $BHheaderoffset += 4;
    8180
    82                                                 $ThisFileInfo['szip']['BH'][] = $BHdataArray;
     81                                                $info['szip']['BH'][] = $BHdataArray;
    8382                                        }
    8483                                        break;
  • _plugins_/getID3/getid3/module.archive.tar.php

    r22745 r51852  
    2020
    2121
    22 class getid3_tar {
     22class getid3_tar extends getid3_handler
     23{
    2324
    24         function getid3_tar(&$fd, &$ThisFileInfo) {
    25                 $ThisFileInfo['fileformat'] = 'tar';
    26                 $ThisFileInfo['tar']['files'] = array();
     25        function Analyze() {
     26                $info = &$this->getid3->info;
     27
     28                $info['fileformat'] = 'tar';
     29                $info['tar']['files'] = array();
    2730
    2831                $unpack_header = 'a100fname/a8mode/a8uid/a8gid/a12size/a12mtime/a8chksum/a1typflag/a100lnkname/a6magic/a2ver/a32uname/a32gname/a8devmaj/a8devmin/a155prefix';
    2932                $null_512k = str_repeat("\x00", 512); // end-of-file marker
    3033
    31                 @fseek($fd, 0);
    32                 while (!feof($fd)) {
    33                         $buffer = fread($fd, 512);
     34                fseek($this->getid3->fp, 0);
     35                while (!feof($this->getid3->fp)) {
     36                        $buffer = fread($this->getid3->fp, 512);
    3437                        if (strlen($buffer) < 512) {
    3538                                break;
     
    4851                        }
    4952                        $attr    = unpack($unpack_header, $buffer);
    50                         $name    =        trim(@$attr['fname']);
    51                         $mode    = octdec(trim(@$attr['mode']));
    52                         $uid     = octdec(trim(@$attr['uid']));
    53                         $gid     = octdec(trim(@$attr['gid']));
    54                         $size    = octdec(trim(@$attr['size']));
    55                         $mtime   = octdec(trim(@$attr['mtime']));
    56                         $chksum  = octdec(trim(@$attr['chksum']));
    57                         $typflag =        trim(@$attr['typflag']);
    58                         $lnkname =        trim(@$attr['lnkname']);
    59                         $magic   =        trim(@$attr['magic']);
    60                         $ver     =        trim(@$attr['ver']);
    61                         $uname   =        trim(@$attr['uname']);
    62                         $gname   =        trim(@$attr['gname']);
    63                         $devmaj  = octdec(trim(@$attr['devmaj']));
    64                         $devmin  = octdec(trim(@$attr['devmin']));
    65                         $prefix  =        trim(@$attr['prefix']);
     53                        $name    =       (isset($attr['fname']  ) ? trim($attr['fname']  ) : '');
     54                        $mode    = octdec(isset($attr['mode']   ) ? trim($attr['mode']   ) : '');
     55                        $uid     = octdec(isset($attr['uid']    ) ? trim($attr['uid']    ) : '');
     56                        $gid     = octdec(isset($attr['gid']    ) ? trim($attr['gid']    ) : '');
     57                        $size    = octdec(isset($attr['size']   ) ? trim($attr['size']   ) : '');
     58                        $mtime   = octdec(isset($attr['mtime']  ) ? trim($attr['mtime']  ) : '');
     59                        $chksum  = octdec(isset($attr['chksum'] ) ? trim($attr['chksum'] ) : '');
     60                        $typflag =       (isset($attr['typflag']) ? trim($attr['typflag']) : '');
     61                        $lnkname =       (isset($attr['lnkname']) ? trim($attr['lnkname']) : '');
     62                        $magic   =       (isset($attr['magic']  ) ? trim($attr['magic']  ) : '');
     63                        $ver     =       (isset($attr['ver']    ) ? trim($attr['ver']    ) : '');
     64                        $uname   =       (isset($attr['uname']  ) ? trim($attr['uname']  ) : '');
     65                        $gname   =       (isset($attr['gname']  ) ? trim($attr['gname']  ) : '');
     66                        $devmaj  = octdec(isset($attr['devmaj'] ) ? trim($attr['devmaj'] ) : '');
     67                        $devmin  = octdec(isset($attr['devmin'] ) ? trim($attr['devmin'] ) : '');
     68                        $prefix  =       (isset($attr['prefix'] ) ? trim($attr['prefix'] ) : '');
    6669                        if (($checksum == 256) && ($chksum == 0)) {
    6770                                // EOF Found
     
    8083
    8184                        // Read to the next chunk
    82                         fseek($fd, $size, SEEK_CUR);
     85                        fseek($this->getid3->fp, $size, SEEK_CUR);
    8386
    8487                        $diff = $size % 512;
    8588                        if ($diff != 0) {
    8689                                // Padding, throw away
    87                                 fseek($fd, (512 - $diff), SEEK_CUR);
     90                                fseek($this->getid3->fp, (512 - $diff), SEEK_CUR);
    8891                        }
    8992                        // Protect against tar-files with garbage at the end
     
    9194                                break;
    9295                        }
    93                         $ThisFileInfo['tar']['file_details'][$name] = array (
     96                        $info['tar']['file_details'][$name] = array (
    9497                                'name'     => $name,
    9598                                'mode_raw' => $mode,
     
    109112                                'devminor' => $devmin
    110113                        );
    111                         $ThisFileInfo['tar']['files'] = getid3_lib::array_merge_clobber($ThisFileInfo['tar']['files'], getid3_lib::CreateDeepArray($ThisFileInfo['tar']['file_details'][$name]['name'], '/', $size));
     114                        $info['tar']['files'] = getid3_lib::array_merge_clobber($info['tar']['files'], getid3_lib::CreateDeepArray($info['tar']['file_details'][$name]['name'], '/', $size));
    112115                }
    113116                return true;
     
    168171                        'V' => 'LF_VOLHDR'
    169172                );
    170                 return @$flag_types[$typflag];
     173                return (isset($flag_types[$typflag]) ? $flag_types[$typflag] : '');
    171174        }
    172175
  • _plugins_/getID3/getid3/module.archive.zip.php

    r22745 r51852  
    1515
    1616
    17 class getid3_zip
     17class getid3_zip extends getid3_handler
    1818{
    1919
    20         function getid3_zip(&$fd, &$ThisFileInfo) {
    21 
    22                 $ThisFileInfo['fileformat']      = 'zip';
    23                 $ThisFileInfo['zip']['encoding'] = 'ISO-8859-1';
    24                 $ThisFileInfo['zip']['files']    = array();
    25 
    26                 $ThisFileInfo['zip']['compressed_size']   = 0;
    27                 $ThisFileInfo['zip']['uncompressed_size'] = 0;
    28                 $ThisFileInfo['zip']['entries_count']     = 0;
    29 
    30                 $EOCDsearchData    = '';
    31                 $EOCDsearchCounter = 0;
    32                 while ($EOCDsearchCounter++ < 512) {
    33 
    34                         fseek($fd, -128 * $EOCDsearchCounter, SEEK_END);
    35                         $EOCDsearchData = fread($fd, 128).$EOCDsearchData;
    36 
    37                         if (strstr($EOCDsearchData, 'PK'."\x05\x06")) {
    38 
    39                                 $EOCDposition = strpos($EOCDsearchData, 'PK'."\x05\x06");
    40                                 fseek($fd, (-128 * $EOCDsearchCounter) + $EOCDposition, SEEK_END);
    41                                 $ThisFileInfo['zip']['end_central_directory'] = $this->ZIPparseEndOfCentralDirectory($fd);
    42 
    43                                 fseek($fd, $ThisFileInfo['zip']['end_central_directory']['directory_offset'], SEEK_SET);
    44                                 $ThisFileInfo['zip']['entries_count'] = 0;
    45                                 while ($centraldirectoryentry = $this->ZIPparseCentralDirectory($fd)) {
    46                                         $ThisFileInfo['zip']['central_directory'][] = $centraldirectoryentry;
    47                                         $ThisFileInfo['zip']['entries_count']++;
    48                                         $ThisFileInfo['zip']['compressed_size']   += $centraldirectoryentry['compressed_size'];
    49                                         $ThisFileInfo['zip']['uncompressed_size'] += $centraldirectoryentry['uncompressed_size'];
    50 
    51                                         if ($centraldirectoryentry['uncompressed_size'] > 0) {
    52                                                 $ThisFileInfo['zip']['files'] = getid3_lib::array_merge_clobber($ThisFileInfo['zip']['files'], getid3_lib::CreateDeepArray($centraldirectoryentry['filename'], '/', $centraldirectoryentry['uncompressed_size']));
    53                                         }
     20        function Analyze() {
     21                $info = &$this->getid3->info;
     22
     23                $info['fileformat']      = 'zip';
     24                $info['zip']['encoding'] = 'ISO-8859-1';
     25                $info['zip']['files']    = array();
     26
     27                $info['zip']['compressed_size']   = 0;
     28                $info['zip']['uncompressed_size'] = 0;
     29                $info['zip']['entries_count']     = 0;
     30
     31                if (!getid3_lib::intValueSupported($info['filesize'])) {
     32                        $info['error'][] = 'File is larger than '.round(PHP_INT_MAX / 1073741824).'GB, not supported by PHP';
     33                        return false;
     34                } else {
     35                        $EOCDsearchData    = '';
     36                        $EOCDsearchCounter = 0;
     37                        while ($EOCDsearchCounter++ < 512) {
     38
     39                                fseek($this->getid3->fp, -128 * $EOCDsearchCounter, SEEK_END);
     40                                $EOCDsearchData = fread($this->getid3->fp, 128).$EOCDsearchData;
     41
     42                                if (strstr($EOCDsearchData, 'PK'."\x05\x06")) {
     43
     44                                        $EOCDposition = strpos($EOCDsearchData, 'PK'."\x05\x06");
     45                                        fseek($this->getid3->fp, (-128 * $EOCDsearchCounter) + $EOCDposition, SEEK_END);
     46                                        $info['zip']['end_central_directory'] = $this->ZIPparseEndOfCentralDirectory();
     47
     48                                        fseek($this->getid3->fp, $info['zip']['end_central_directory']['directory_offset'], SEEK_SET);
     49                                        $info['zip']['entries_count'] = 0;
     50                                        while ($centraldirectoryentry = $this->ZIPparseCentralDirectory($this->getid3->fp)) {
     51                                                $info['zip']['central_directory'][] = $centraldirectoryentry;
     52                                                $info['zip']['entries_count']++;
     53                                                $info['zip']['compressed_size']   += $centraldirectoryentry['compressed_size'];
     54                                                $info['zip']['uncompressed_size'] += $centraldirectoryentry['uncompressed_size'];
     55
     56                                                if ($centraldirectoryentry['uncompressed_size'] > 0) {
     57                                                        $info['zip']['files'] = getid3_lib::array_merge_clobber($info['zip']['files'], getid3_lib::CreateDeepArray($centraldirectoryentry['filename'], '/', $centraldirectoryentry['uncompressed_size']));
     58                                                }
     59                                        }
     60
     61                                        if ($info['zip']['entries_count'] == 0) {
     62                                                $info['error'][] = 'No Central Directory entries found (truncated file?)';
     63                                                return false;
     64                                        }
     65
     66                                        if (!empty($info['zip']['end_central_directory']['comment'])) {
     67                                                $info['zip']['comments']['comment'][] = $info['zip']['end_central_directory']['comment'];
     68                                        }
     69
     70                                        if (isset($info['zip']['central_directory'][0]['compression_method'])) {
     71                                                $info['zip']['compression_method'] = $info['zip']['central_directory'][0]['compression_method'];
     72                                        }
     73                                        if (isset($info['zip']['central_directory'][0]['flags']['compression_speed'])) {
     74                                                $info['zip']['compression_speed']  = $info['zip']['central_directory'][0]['flags']['compression_speed'];
     75                                        }
     76                                        if (isset($info['zip']['compression_method']) && ($info['zip']['compression_method'] == 'store') && !isset($info['zip']['compression_speed'])) {
     77                                                $info['zip']['compression_speed']  = 'store';
     78                                        }
     79
     80                                        return true;
     81
    5482                                }
    55 
    56                                 if ($ThisFileInfo['zip']['entries_count'] == 0) {
    57                                         $ThisFileInfo['error'][] = 'No Central Directory entries found (truncated file?)';
    58                                         return false;
    59                                 }
    60 
    61                                 if (!empty($ThisFileInfo['zip']['end_central_directory']['comment'])) {
    62                                         $ThisFileInfo['zip']['comments']['comment'][] = $ThisFileInfo['zip']['end_central_directory']['comment'];
    63                                 }
    64 
    65                                 if (isset($ThisFileInfo['zip']['central_directory'][0]['compression_method'])) {
    66                                         $ThisFileInfo['zip']['compression_method'] = $ThisFileInfo['zip']['central_directory'][0]['compression_method'];
    67                                 }
    68                                 if (isset($ThisFileInfo['zip']['central_directory'][0]['flags']['compression_speed'])) {
    69                                         $ThisFileInfo['zip']['compression_speed']  = $ThisFileInfo['zip']['central_directory'][0]['flags']['compression_speed'];
    70                                 }
    71                                 if (isset($ThisFileInfo['zip']['compression_method']) && ($ThisFileInfo['zip']['compression_method'] == 'store') && !isset($ThisFileInfo['zip']['compression_speed'])) {
    72                                         $ThisFileInfo['zip']['compression_speed']  = 'store';
    73                                 }
    74 
    75                                 return true;
    76 
    77                         }
    78 
    79                 }
    80 
    81                 if ($this->getZIPentriesFilepointer($fd, $ThisFileInfo)) {
     83                        }
     84                }
     85
     86                if ($this->getZIPentriesFilepointer()) {
    8287
    8388                        // central directory couldn't be found and/or parsed
    8489                        // scan through actual file data entries, recover as much as possible from probable trucated file
    85                         if ($ThisFileInfo['zip']['compressed_size'] > ($ThisFileInfo['filesize'] - 46 - 22)) {
    86                                 $ThisFileInfo['error'][] = 'Warning: Truncated file! - Total compressed file sizes ('.$ThisFileInfo['zip']['compressed_size'].' bytes) is greater than filesize minus Central Directory and End Of Central Directory structures ('.($ThisFileInfo['filesize'] - 46 - 22).' bytes)';
    87                         }
    88                         $ThisFileInfo['error'][] = 'Cannot find End Of Central Directory - returned list of files in [zip][entries] array may not be complete';
    89                         foreach ($ThisFileInfo['zip']['entries'] as $key => $valuearray) {
    90                                 $ThisFileInfo['zip']['files'][$valuearray['filename']] = $valuearray['uncompressed_size'];
     90                        if ($info['zip']['compressed_size'] > ($info['filesize'] - 46 - 22)) {
     91                                $info['error'][] = 'Warning: Truncated file! - Total compressed file sizes ('.$info['zip']['compressed_size'].' bytes) is greater than filesize minus Central Directory and End Of Central Directory structures ('.($info['filesize'] - 46 - 22).' bytes)';
     92                        }
     93                        $info['error'][] = 'Cannot find End Of Central Directory - returned list of files in [zip][entries] array may not be complete';
     94                        foreach ($info['zip']['entries'] as $key => $valuearray) {
     95                                $info['zip']['files'][$valuearray['filename']] = $valuearray['uncompressed_size'];
    9196                        }
    9297                        return true;
     
    9499                } else {
    95100
    96                         unset($ThisFileInfo['zip']);
    97                         $ThisFileInfo['fileformat'] = '';
    98                         $ThisFileInfo['error'][] = 'Cannot find End Of Central Directory (truncated file?)';
    99                         return false;
    100 
    101                 }
    102         }
    103 
    104 
    105         function getZIPHeaderFilepointerTopDown(&$fd, &$ThisFileInfo) {
    106                 $ThisFileInfo['fileformat'] = 'zip';
    107 
    108                 $ThisFileInfo['zip']['compressed_size']   = 0;
    109                 $ThisFileInfo['zip']['uncompressed_size'] = 0;
    110                 $ThisFileInfo['zip']['entries_count']     = 0;
    111 
    112                 rewind($fd);
    113                 while ($fileentry = $this->ZIPparseLocalFileHeader($fd)) {
    114                         $ThisFileInfo['zip']['entries'][] = $fileentry;
    115                         $ThisFileInfo['zip']['entries_count']++;
    116                 }
    117                 if ($ThisFileInfo['zip']['entries_count'] == 0) {
    118                         $ThisFileInfo['error'][] = 'No Local File Header entries found';
    119                         return false;
    120                 }
    121 
    122                 $ThisFileInfo['zip']['entries_count']     = 0;
    123                 while ($centraldirectoryentry = $this->ZIPparseCentralDirectory($fd)) {
    124                         $ThisFileInfo['zip']['central_directory'][] = $centraldirectoryentry;
    125                         $ThisFileInfo['zip']['entries_count']++;
    126                         $ThisFileInfo['zip']['compressed_size']   += $centraldirectoryentry['compressed_size'];
    127                         $ThisFileInfo['zip']['uncompressed_size'] += $centraldirectoryentry['uncompressed_size'];
    128                 }
    129                 if ($ThisFileInfo['zip']['entries_count'] == 0) {
    130                         $ThisFileInfo['error'][] = 'No Central Directory entries found (truncated file?)';
    131                         return false;
    132                 }
    133 
    134                 if ($EOCD = $this->ZIPparseEndOfCentralDirectory($fd)) {
    135                         $ThisFileInfo['zip']['end_central_directory'] = $EOCD;
     101                        unset($info['zip']);
     102                        $info['fileformat'] = '';
     103                        $info['error'][] = 'Cannot find End Of Central Directory (truncated file?)';
     104                        return false;
     105
     106                }
     107        }
     108
     109
     110        function getZIPHeaderFilepointerTopDown() {
     111                $info = &$this->getid3->info;
     112
     113                $info['fileformat'] = 'zip';
     114
     115                $info['zip']['compressed_size']   = 0;
     116                $info['zip']['uncompressed_size'] = 0;
     117                $info['zip']['entries_count']     = 0;
     118
     119                rewind($this->getid3->fp);
     120                while ($fileentry = $this->ZIPparseLocalFileHeader()) {
     121                        $info['zip']['entries'][] = $fileentry;
     122                        $info['zip']['entries_count']++;
     123                }
     124                if ($info['zip']['entries_count'] == 0) {
     125                        $info['error'][] = 'No Local File Header entries found';
     126                        return false;
     127                }
     128
     129                $info['zip']['entries_count']     = 0;
     130                while ($centraldirectoryentry = $this->ZIPparseCentralDirectory($this->getid3->fp)) {
     131                        $info['zip']['central_directory'][] = $centraldirectoryentry;
     132                        $info['zip']['entries_count']++;
     133                        $info['zip']['compressed_size']   += $centraldirectoryentry['compressed_size'];
     134                        $info['zip']['uncompressed_size'] += $centraldirectoryentry['uncompressed_size'];
     135                }
     136                if ($info['zip']['entries_count'] == 0) {
     137                        $info['error'][] = 'No Central Directory entries found (truncated file?)';
     138                        return false;
     139                }
     140
     141                if ($EOCD = $this->ZIPparseEndOfCentralDirectory()) {
     142                        $info['zip']['end_central_directory'] = $EOCD;
    136143                } else {
    137                         $ThisFileInfo['error'][] = 'No End Of Central Directory entry found (truncated file?)';
    138                         return false;
    139                 }
    140 
    141                 if (!empty($ThisFileInfo['zip']['end_central_directory']['comment'])) {
    142                         $ThisFileInfo['zip']['comments']['comment'][] = $ThisFileInfo['zip']['end_central_directory']['comment'];
     144                        $info['error'][] = 'No End Of Central Directory entry found (truncated file?)';
     145                        return false;
     146                }
     147
     148                if (!empty($info['zip']['end_central_directory']['comment'])) {
     149                        $info['zip']['comments']['comment'][] = $info['zip']['end_central_directory']['comment'];
    143150                }
    144151
     
    147154
    148155
    149         function getZIPentriesFilepointer(&$fd, &$ThisFileInfo) {
    150                 $ThisFileInfo['zip']['compressed_size']   = 0;
    151                 $ThisFileInfo['zip']['uncompressed_size'] = 0;
    152                 $ThisFileInfo['zip']['entries_count']     = 0;
    153 
    154                 rewind($fd);
    155                 while ($fileentry = $this->ZIPparseLocalFileHeader($fd)) {
    156                         $ThisFileInfo['zip']['entries'][] = $fileentry;
    157                         $ThisFileInfo['zip']['entries_count']++;
    158                         $ThisFileInfo['zip']['compressed_size']   += $fileentry['compressed_size'];
    159                         $ThisFileInfo['zip']['uncompressed_size'] += $fileentry['uncompressed_size'];
    160                 }
    161                 if ($ThisFileInfo['zip']['entries_count'] == 0) {
    162                         $ThisFileInfo['error'][] = 'No Local File Header entries found';
     156        function getZIPentriesFilepointer() {
     157                $info = &$this->getid3->info;
     158
     159                $info['zip']['compressed_size']   = 0;
     160                $info['zip']['uncompressed_size'] = 0;
     161                $info['zip']['entries_count']     = 0;
     162
     163                rewind($this->getid3->fp);
     164                while ($fileentry = $this->ZIPparseLocalFileHeader()) {
     165                        $info['zip']['entries'][] = $fileentry;
     166                        $info['zip']['entries_count']++;
     167                        $info['zip']['compressed_size']   += $fileentry['compressed_size'];
     168                        $info['zip']['uncompressed_size'] += $fileentry['uncompressed_size'];
     169                }
     170                if ($info['zip']['entries_count'] == 0) {
     171                        $info['error'][] = 'No Local File Header entries found';
    163172                        return false;
    164173                }
     
    168177
    169178
    170         function ZIPparseLocalFileHeader(&$fd) {
    171                 $LocalFileHeader['offset'] = ftell($fd);
    172 
    173                 $ZIPlocalFileHeader = fread($fd, 30);
     179        function ZIPparseLocalFileHeader() {
     180                $LocalFileHeader['offset'] = ftell($this->getid3->fp);
     181
     182                $ZIPlocalFileHeader = fread($this->getid3->fp, 30);
    174183
    175184                $LocalFileHeader['raw']['signature']          = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader,  0, 4));
    176185                if ($LocalFileHeader['raw']['signature'] != 0x04034B50) {
    177186                        // invalid Local File Header Signature
    178                         fseek($fd, $LocalFileHeader['offset'], SEEK_SET); // seek back to where filepointer originally was so it can be handled properly
     187                        fseek($this->getid3->fp, $LocalFileHeader['offset'], SEEK_SET); // seek back to where filepointer originally was so it can be handled properly
    179188                        return false;
    180189                }
     
    200209                $FilenameExtrafieldLength = $LocalFileHeader['raw']['filename_length'] + $LocalFileHeader['raw']['extra_field_length'];
    201210                if ($FilenameExtrafieldLength > 0) {
    202                         $ZIPlocalFileHeader .= fread($fd, $FilenameExtrafieldLength);
     211                        $ZIPlocalFileHeader .= fread($this->getid3->fp, $FilenameExtrafieldLength);
    203212
    204213                        if ($LocalFileHeader['raw']['filename_length'] > 0) {
     
    210219                }
    211220
    212                 $LocalFileHeader['data_offset'] = ftell($fd);
    213                 //$LocalFileHeader['compressed_data'] = fread($fd, $LocalFileHeader['raw']['compressed_size']);
    214                 fseek($fd, $LocalFileHeader['raw']['compressed_size'], SEEK_CUR);
     221                $LocalFileHeader['data_offset'] = ftell($this->getid3->fp);
     222                //$LocalFileHeader['compressed_data'] = fread($this->getid3->fp, $LocalFileHeader['raw']['compressed_size']);
     223                fseek($this->getid3->fp, $LocalFileHeader['raw']['compressed_size'], SEEK_CUR);
    215224
    216225                if ($LocalFileHeader['flags']['data_descriptor_used']) {
    217                         $DataDescriptor = fread($fd, 12);
     226                        $DataDescriptor = fread($this->getid3->fp, 12);
    218227                        $LocalFileHeader['data_descriptor']['crc_32']            = getid3_lib::LittleEndian2Int(substr($DataDescriptor,  0, 4));
    219228                        $LocalFileHeader['data_descriptor']['compressed_size']   = getid3_lib::LittleEndian2Int(substr($DataDescriptor,  4, 4));
     
    225234
    226235
    227         function ZIPparseCentralDirectory(&$fd) {
    228                 $CentralDirectory['offset'] = ftell($fd);
    229 
    230                 $ZIPcentralDirectory = fread($fd, 46);
     236        function ZIPparseCentralDirectory() {
     237                $CentralDirectory['offset'] = ftell($this->getid3->fp);
     238
     239                $ZIPcentralDirectory = fread($this->getid3->fp, 46);
    231240
    232241                $CentralDirectory['raw']['signature']            = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory,  0, 4));
    233242                if ($CentralDirectory['raw']['signature'] != 0x02014B50) {
    234243                        // invalid Central Directory Signature
    235                         fseek($fd, $CentralDirectory['offset'], SEEK_SET); // seek back to where filepointer originally was so it can be handled properly
     244                        fseek($this->getid3->fp, $CentralDirectory['offset'], SEEK_SET); // seek back to where filepointer originally was so it can be handled properly
    236245                        return false;
    237246                }
     
    265274                $FilenameExtrafieldCommentLength = $CentralDirectory['raw']['filename_length'] + $CentralDirectory['raw']['extra_field_length'] + $CentralDirectory['raw']['file_comment_length'];
    266275                if ($FilenameExtrafieldCommentLength > 0) {
    267                         $FilenameExtrafieldComment = fread($fd, $FilenameExtrafieldCommentLength);
     276                        $FilenameExtrafieldComment = fread($this->getid3->fp, $FilenameExtrafieldCommentLength);
    268277
    269278                        if ($CentralDirectory['raw']['filename_length'] > 0) {
     
    281290        }
    282291
    283         function ZIPparseEndOfCentralDirectory(&$fd) {
    284                 $EndOfCentralDirectory['offset'] = ftell($fd);
    285 
    286                 $ZIPendOfCentralDirectory = fread($fd, 22);
     292        function ZIPparseEndOfCentralDirectory() {
     293                $EndOfCentralDirectory['offset'] = ftell($this->getid3->fp);
     294
     295                $ZIPendOfCentralDirectory = fread($this->getid3->fp, 22);
    287296
    288297                $EndOfCentralDirectory['signature']                   = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory,  0, 4));
    289298                if ($EndOfCentralDirectory['signature'] != 0x06054B50) {
    290299                        // invalid End Of Central Directory Signature
    291                         fseek($fd, $EndOfCentralDirectory['offset'], SEEK_SET); // seek back to where filepointer originally was so it can be handled properly
     300                        fseek($this->getid3->fp, $EndOfCentralDirectory['offset'], SEEK_SET); // seek back to where filepointer originally was so it can be handled properly
    292301                        return false;
    293302                }
     
    301310
    302311                if ($EndOfCentralDirectory['comment_length'] > 0) {
    303                         $EndOfCentralDirectory['comment']                 = fread($fd, $EndOfCentralDirectory['comment_length']);
     312                        $EndOfCentralDirectory['comment']                 = fread($this->getid3->fp, $EndOfCentralDirectory['comment_length']);
    304313                }
    305314
     
    308317
    309318
    310         function ZIPparseGeneralPurposeFlags($flagbytes, $compressionmethod) {
     319        static function ZIPparseGeneralPurposeFlags($flagbytes, $compressionmethod) {
    311320                $ParsedFlags['encrypted'] = (bool) ($flagbytes & 0x0001);
    312321
     
    341350
    342351
    343         function ZIPversionOSLookup($index) {
     352        static function ZIPversionOSLookup($index) {
    344353                static $ZIPversionOSLookup = array(
    345354                        0  => 'MS-DOS and OS/2 (FAT / VFAT / FAT32 file systems)',
     
    366375        }
    367376
    368         function ZIPcompressionMethodLookup($index) {
     377        static function ZIPcompressionMethodLookup($index) {
    369378                static $ZIPcompressionMethodLookup = array(
    370379                        0  => 'store',
     
    384393        }
    385394
    386         function DOStime2UNIXtime($DOSdate, $DOStime) {
     395        static function DOStime2UNIXtime($DOSdate, $DOStime) {
    387396                // wFatDate
    388397                // Specifies the MS-DOS date. The date is a packed 16-bit value with the following format:
  • _plugins_/getID3/getid3/module.audio-video.asf.php

    r22745 r51852  
    1616getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true);
    1717
    18 $GUIDarray = getid3_asf::KnownGUIDs();
    19 foreach ($GUIDarray as $GUIDname => $hexstringvalue) {
    20         // initialize all GUID constants
    21         define($GUIDname, getid3_asf::GUIDtoBytestring($hexstringvalue));
    22 }
    23 
    24 
    25 
    26 class getid3_asf
     18class getid3_asf extends getid3_handler
    2719{
    2820
    29         function getid3_asf(&$fd, &$ThisFileInfo) {
     21        function __construct(getID3 $getid3) {
     22                parent::__construct($getid3);  // extends getid3_handler::__construct()
     23
     24                // initialize all GUID constants
     25                $GUIDarray = $this->KnownGUIDs();
     26                foreach ($GUIDarray as $GUIDname => $hexstringvalue) {
     27                        if (!defined($GUIDname)) {
     28                                define($GUIDname, $this->GUIDtoBytestring($hexstringvalue));
     29                        }
     30                }
     31        }
     32
     33        function Analyze() {
     34                $info = &$this->getid3->info;
    3035
    3136                // Shortcuts
    32                 $thisfile_audio = &$ThisFileInfo['audio'];
    33                 $thisfile_video = &$ThisFileInfo['video'];
    34                 $ThisFileInfo['asf'] = array();
    35                 $thisfile_asf        = &$ThisFileInfo['asf'];
     37                $thisfile_audio = &$info['audio'];
     38                $thisfile_video = &$info['video'];
     39                $info['asf'] = array();
     40                $thisfile_asf = &$info['asf'];
    3641                $thisfile_asf['comments'] = array();
    3742                $thisfile_asf_comments    = &$thisfile_asf['comments'];
     
    6065                // Reserved2                    BYTE         8               // hardcoded: 0x02
    6166
    62                 $ThisFileInfo['fileformat'] = 'asf';
    63 
    64                 fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
    65                 $HeaderObjectData = fread($fd, 30);
     67                $info['fileformat'] = 'asf';
     68
     69                fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
     70                $HeaderObjectData = fread($this->getid3->fp, 30);
    6671
    6772                $thisfile_asf_headerobject['objectid']      = substr($HeaderObjectData, 0, 16);
    6873                $thisfile_asf_headerobject['objectid_guid'] = $this->BytestringToGUID($thisfile_asf_headerobject['objectid']);
    6974                if ($thisfile_asf_headerobject['objectid'] != GETID3_ASF_Header_Object) {
    70                         $ThisFileInfo['warning'][] = 'ASF header GUID {'.$this->BytestringToGUID($thisfile_asf_headerobject['objectid']).'} does not match expected "GETID3_ASF_Header_Object" GUID {'.$this->BytestringToGUID(GETID3_ASF_Header_Object).'}';
    71                         unset($ThisFileInfo['fileformat']);
    72                         unset($ThisFileInfo['asf']);
     75                        $info['warning'][] = 'ASF header GUID {'.$this->BytestringToGUID($thisfile_asf_headerobject['objectid']).'} does not match expected "GETID3_ASF_Header_Object" GUID {'.$this->BytestringToGUID(GETID3_ASF_Header_Object).'}';
     76                        unset($info['fileformat']);
     77                        unset($info['asf']);
    7378                        return false;
    7479                        break;
     
    7984                $thisfile_asf_headerobject['reserved2']     = getid3_lib::LittleEndian2Int(substr($HeaderObjectData, 29, 1));
    8085
    81                 $ASFHeaderData = fread($fd, $thisfile_asf_headerobject['objectsize'] - 30);
     86                $NextObjectOffset = ftell($this->getid3->fp);
     87                $ASFHeaderData = fread($this->getid3->fp, $thisfile_asf_headerobject['objectsize'] - 30);
    8288                $offset = 0;
    8389
    8490                for ($HeaderObjectsCounter = 0; $HeaderObjectsCounter < $thisfile_asf_headerobject['headerobjects']; $HeaderObjectsCounter++) {
    85                         $NextObjectGUID     = substr($ASFHeaderData, $offset, 16);
     91                        $NextObjectGUID = substr($ASFHeaderData, $offset, 16);
    8692                        $offset += 16;
    8793                        $NextObjectGUIDtext = $this->BytestringToGUID($NextObjectGUID);
     
    114120                                        $thisfile_asf_filepropertiesobject      = &$thisfile_asf['file_properties_object'];
    115121
     122                                        $thisfile_asf_filepropertiesobject['offset']             = $NextObjectOffset + $offset;
    116123                                        $thisfile_asf_filepropertiesobject['objectid']           = $NextObjectGUID;
    117124                                        $thisfile_asf_filepropertiesobject['objectid_guid']      = $NextObjectGUIDtext;
     
    158165
    159166                                                // broadcast flag NOT set, perform calculations
    160                                                 $ThisFileInfo['playtime_seconds'] = ($thisfile_asf_filepropertiesobject['play_duration'] / 10000000) - ($thisfile_asf_filepropertiesobject['preroll'] / 1000);
    161 
    162                                                 //$ThisFileInfo['bitrate'] = $thisfile_asf_filepropertiesobject['max_bitrate'];
    163                                                 $ThisFileInfo['bitrate'] = ((isset($thisfile_asf_filepropertiesobject['filesize']) ? $thisfile_asf_filepropertiesobject['filesize'] : $ThisFileInfo['filesize']) * 8) / $ThisFileInfo['playtime_seconds'];
     167                                                $info['playtime_seconds'] = ($thisfile_asf_filepropertiesobject['play_duration'] / 10000000) - ($thisfile_asf_filepropertiesobject['preroll'] / 1000);
     168
     169                                                //$info['bitrate'] = $thisfile_asf_filepropertiesobject['max_bitrate'];
     170                                                $info['bitrate'] = ((isset($thisfile_asf_filepropertiesobject['filesize']) ? $thisfile_asf_filepropertiesobject['filesize'] : $info['filesize']) * 8) / $info['playtime_seconds'];
    164171                                        }
    165172                                        break;
     
    187194                                        // it is decoded to a temporary variable and then stuck in the appropriate index later
    188195
     196                                        $StreamPropertiesObjectData['offset']             = $NextObjectOffset + $offset;
    189197                                        $StreamPropertiesObjectData['objectid']           = $NextObjectGUID;
    190198                                        $StreamPropertiesObjectData['objectid_guid']      = $NextObjectGUIDtext;
     
    254262                                        $thisfile_asf_headerextensionobject      = &$thisfile_asf['header_extension_object'];
    255263
     264                                        $thisfile_asf_headerextensionobject['offset']              = $NextObjectOffset + $offset;
    256265                                        $thisfile_asf_headerextensionobject['objectid']            = $NextObjectGUID;
    257266                                        $thisfile_asf_headerextensionobject['objectid_guid']       = $NextObjectGUIDtext;
     
    261270                                        $thisfile_asf_headerextensionobject['reserved_1_guid']     = $this->BytestringToGUID($thisfile_asf_headerextensionobject['reserved_1']);
    262271                                        if ($thisfile_asf_headerextensionobject['reserved_1'] != GETID3_ASF_Reserved_1) {
    263                                                 $ThisFileInfo['warning'][] = 'header_extension_object.reserved_1 GUID ('.$this->BytestringToGUID($thisfile_asf_headerextensionobject['reserved_1']).') does not match expected "GETID3_ASF_Reserved_1" GUID ('.$this->BytestringToGUID(GETID3_ASF_Reserved_1).')';
     272                                                $info['warning'][] = 'header_extension_object.reserved_1 GUID ('.$this->BytestringToGUID($thisfile_asf_headerextensionobject['reserved_1']).') does not match expected "GETID3_ASF_Reserved_1" GUID ('.$this->BytestringToGUID(GETID3_ASF_Reserved_1).')';
    264273                                                //return false;
    265274                                                break;
     
    268277                                        $offset += 2;
    269278                                        if ($thisfile_asf_headerextensionobject['reserved_2'] != 6) {
    270                                                 $ThisFileInfo['warning'][] = 'header_extension_object.reserved_2 ('.getid3_lib::PrintHexBytes($thisfile_asf_headerextensionobject['reserved_2']).') does not match expected value of "6"';
     279                                                $info['warning'][] = 'header_extension_object.reserved_2 ('.getid3_lib::PrintHexBytes($thisfile_asf_headerextensionobject['reserved_2']).') does not match expected value of "6"';
    271280                                                //return false;
    272281                                                break;
     
    298307                                        $thisfile_asf_codeclistobject      = &$thisfile_asf['codec_list_object'];
    299308
     309                                        $thisfile_asf_codeclistobject['offset']                    = $NextObjectOffset + $offset;
    300310                                        $thisfile_asf_codeclistobject['objectid']                  = $NextObjectGUID;
    301311                                        $thisfile_asf_codeclistobject['objectid_guid']             = $NextObjectGUIDtext;
     
    305315                                        $thisfile_asf_codeclistobject['reserved_guid']             = $this->BytestringToGUID($thisfile_asf_codeclistobject['reserved']);
    306316                                        if ($thisfile_asf_codeclistobject['reserved'] != $this->GUIDtoBytestring('86D15241-311D-11D0-A3A4-00A0C90348F6')) {
    307                                                 $ThisFileInfo['warning'][] = 'codec_list_object.reserved GUID {'.$this->BytestringToGUID($thisfile_asf_codeclistobject['reserved']).'} does not match expected "GETID3_ASF_Reserved_1" GUID {86D15241-311D-11D0-A3A4-00A0C90348F6}';
     317                                                $info['warning'][] = 'codec_list_object.reserved GUID {'.$this->BytestringToGUID($thisfile_asf_codeclistobject['reserved']).'} does not match expected "GETID3_ASF_Reserved_1" GUID {86D15241-311D-11D0-A3A4-00A0C90348F6}';
    308318                                                //return false;
    309319                                                break;
     
    335345                                                $offset += $CodecInformationLength;
    336346
    337                                                 if ($thisfile_asf_codeclistobject_codecentries_current['type_raw'] == 2) {
    338                                                         // audio codec
     347                                                if ($thisfile_asf_codeclistobject_codecentries_current['type_raw'] == 2) { // audio codec
     348
    339349                                                        if (strpos($thisfile_asf_codeclistobject_codecentries_current['description'], ',') === false) {
    340                                                                 $ThisFileInfo['error'][] = '[asf][codec_list_object][codec_entries]['.$CodecEntryCounter.'][description] expected to contain comma-seperated list of parameters: "'.$thisfile_asf_codeclistobject_codecentries_current['description'].'"';
    341                                                                 return false;
    342                                                         }
    343                                                         list($AudioCodecBitrate, $AudioCodecFrequency, $AudioCodecChannels) = explode(',', $this->TrimConvert($thisfile_asf_codeclistobject_codecentries_current['description']));
    344                                                         $thisfile_audio['codec'] = $this->TrimConvert($thisfile_asf_codeclistobject_codecentries_current['name']);
    345 
    346                                                         if (!isset($thisfile_audio['bitrate']) && strstr($AudioCodecBitrate, 'kbps')) {
    347                                                                 $thisfile_audio['bitrate'] = (int) (trim(str_replace('kbps', '', $AudioCodecBitrate)) * 1000);
    348                                                         }
    349                                                         //if (!isset($thisfile_video['bitrate']) && isset($thisfile_audio['bitrate']) && isset($thisfile_asf['file_properties_object']['max_bitrate']) && ($thisfile_asf_codeclistobject['codec_entries_count'] > 1)) {
    350                                                         if (!@$thisfile_video['bitrate'] && @$thisfile_audio['bitrate'] && @$ThisFileInfo['bitrate']) {
    351                                                                 //$thisfile_video['bitrate'] = $thisfile_asf['file_properties_object']['max_bitrate'] - $thisfile_audio['bitrate'];
    352                                                                 $thisfile_video['bitrate'] = $ThisFileInfo['bitrate'] - $thisfile_audio['bitrate'];
    353                                                         }
    354 
    355                                                         $AudioCodecFrequency = (int) trim(str_replace('kHz', '', $AudioCodecFrequency));
    356                                                         switch ($AudioCodecFrequency) {
    357                                                                 case 8:
    358                                                                 case 8000:
    359                                                                         $thisfile_audio['sample_rate'] = 8000;
    360                                                                         break;
    361 
    362                                                                 case 11:
    363                                                                 case 11025:
    364                                                                         $thisfile_audio['sample_rate'] = 11025;
    365                                                                         break;
    366 
    367                                                                 case 12:
    368                                                                 case 12000:
    369                                                                         $thisfile_audio['sample_rate'] = 12000;
    370                                                                         break;
    371 
    372                                                                 case 16:
    373                                                                 case 16000:
    374                                                                         $thisfile_audio['sample_rate'] = 16000;
    375                                                                         break;
    376 
    377                                                                 case 22:
    378                                                                 case 22050:
    379                                                                         $thisfile_audio['sample_rate'] = 22050;
    380                                                                         break;
    381 
    382                                                                 case 24:
    383                                                                 case 24000:
    384                                                                         $thisfile_audio['sample_rate'] = 24000;
    385                                                                         break;
    386 
    387                                                                 case 32:
    388                                                                 case 32000:
    389                                                                         $thisfile_audio['sample_rate'] = 32000;
    390                                                                         break;
    391 
    392                                                                 case 44:
    393                                                                 case 441000:
    394                                                                         $thisfile_audio['sample_rate'] = 44100;
    395                                                                         break;
    396 
    397                                                                 case 48:
    398                                                                 case 48000:
    399                                                                         $thisfile_audio['sample_rate'] = 48000;
    400                                                                         break;
    401 
    402                                                                 default:
    403                                                                         $ThisFileInfo['warning'][] = 'unknown frequency: "'.$AudioCodecFrequency.'" ('.$this->TrimConvert($thisfile_asf_codeclistobject_codecentries_current['description']).')';
    404                                                                         break;
    405                                                         }
    406 
    407                                                         if (!isset($thisfile_audio['channels'])) {
    408                                                                 if (strstr($AudioCodecChannels, 'stereo')) {
    409                                                                         $thisfile_audio['channels'] = 2;
    410                                                                 } elseif (strstr($AudioCodecChannels, 'mono')) {
    411                                                                         $thisfile_audio['channels'] = 1;
     350                                                                $info['warning'][] = '[asf][codec_list_object][codec_entries]['.$CodecEntryCounter.'][description] expected to contain comma-seperated list of parameters: "'.$thisfile_asf_codeclistobject_codecentries_current['description'].'"';
     351                                                        } else {
     352
     353                                                                list($AudioCodecBitrate, $AudioCodecFrequency, $AudioCodecChannels) = explode(',', $this->TrimConvert($thisfile_asf_codeclistobject_codecentries_current['description']));
     354                                                                $thisfile_audio['codec'] = $this->TrimConvert($thisfile_asf_codeclistobject_codecentries_current['name']);
     355
     356                                                                if (!isset($thisfile_audio['bitrate']) && strstr($AudioCodecBitrate, 'kbps')) {
     357                                                                        $thisfile_audio['bitrate'] = (int) (trim(str_replace('kbps', '', $AudioCodecBitrate)) * 1000);
    412358                                                                }
     359                                                                //if (!isset($thisfile_video['bitrate']) && isset($thisfile_audio['bitrate']) && isset($thisfile_asf['file_properties_object']['max_bitrate']) && ($thisfile_asf_codeclistobject['codec_entries_count'] > 1)) {
     360                                                                if (empty($thisfile_video['bitrate']) && !empty($thisfile_audio['bitrate']) && !empty($info['bitrate'])) {
     361                                                                        //$thisfile_video['bitrate'] = $thisfile_asf['file_properties_object']['max_bitrate'] - $thisfile_audio['bitrate'];
     362                                                                        $thisfile_video['bitrate'] = $info['bitrate'] - $thisfile_audio['bitrate'];
     363                                                                }
     364
     365                                                                $AudioCodecFrequency = (int) trim(str_replace('kHz', '', $AudioCodecFrequency));
     366                                                                switch ($AudioCodecFrequency) {
     367                                                                        case 8:
     368                                                                        case 8000:
     369                                                                                $thisfile_audio['sample_rate'] = 8000;
     370                                                                                break;
     371
     372                                                                        case 11:
     373                                                                        case 11025:
     374                                                                                $thisfile_audio['sample_rate'] = 11025;
     375                                                                                break;
     376
     377                                                                        case 12:
     378                                                                        case 12000:
     379                                                                                $thisfile_audio['sample_rate'] = 12000;
     380                                                                                break;
     381
     382                                                                        case 16:
     383                                                                        case 16000:
     384                                                                                $thisfile_audio['sample_rate'] = 16000;
     385                                                                                break;
     386
     387                                                                        case 22:
     388                                                                        case 22050:
     389                                                                                $thisfile_audio['sample_rate'] = 22050;
     390                                                                                break;
     391
     392                                                                        case 24:
     393                                                                        case 24000:
     394                                                                                $thisfile_audio['sample_rate'] = 24000;
     395                                                                                break;
     396
     397                                                                        case 32:
     398                                                                        case 32000:
     399                                                                                $thisfile_audio['sample_rate'] = 32000;
     400                                                                                break;
     401
     402                                                                        case 44:
     403                                                                        case 441000:
     404                                                                                $thisfile_audio['sample_rate'] = 44100;
     405                                                                                break;
     406
     407                                                                        case 48:
     408                                                                        case 48000:
     409                                                                                $thisfile_audio['sample_rate'] = 48000;
     410                                                                                break;
     411
     412                                                                        default:
     413                                                                                $info['warning'][] = 'unknown frequency: "'.$AudioCodecFrequency.'" ('.$this->TrimConvert($thisfile_asf_codeclistobject_codecentries_current['description']).')';
     414                                                                                break;
     415                                                                }
     416
     417                                                                if (!isset($thisfile_audio['channels'])) {
     418                                                                        if (strstr($AudioCodecChannels, 'stereo')) {
     419                                                                                $thisfile_audio['channels'] = 2;
     420                                                                        } elseif (strstr($AudioCodecChannels, 'mono')) {
     421                                                                                $thisfile_audio['channels'] = 1;
     422                                                                        }
     423                                                                }
     424
    413425                                                        }
    414426                                                }
     
    437449                                        $thisfile_asf_scriptcommandobject      = &$thisfile_asf['script_command_object'];
    438450
     451                                        $thisfile_asf_scriptcommandobject['offset']               = $NextObjectOffset + $offset;
    439452                                        $thisfile_asf_scriptcommandobject['objectid']             = $NextObjectGUID;
    440453                                        $thisfile_asf_scriptcommandobject['objectid_guid']        = $NextObjectGUIDtext;
     
    444457                                        $thisfile_asf_scriptcommandobject['reserved_guid']        = $this->BytestringToGUID($thisfile_asf_scriptcommandobject['reserved']);
    445458                                        if ($thisfile_asf_scriptcommandobject['reserved'] != $this->GUIDtoBytestring('4B1ACBE3-100B-11D0-A39B-00A0C90348F6')) {
    446                                                 $ThisFileInfo['warning'][] = 'script_command_object.reserved GUID {'.$this->BytestringToGUID($thisfile_asf_scriptcommandobject['reserved']).'} does not match expected "GETID3_ASF_Reserved_1" GUID {4B1ACBE3-100B-11D0-A39B-00A0C90348F6}';
     459                                                $info['warning'][] = 'script_command_object.reserved GUID {'.$this->BytestringToGUID($thisfile_asf_scriptcommandobject['reserved']).'} does not match expected "GETID3_ASF_Reserved_1" GUID {4B1ACBE3-100B-11D0-A39B-00A0C90348F6}';
    447460                                                //return false;
    448461                                                break;
     
    495508                                        $thisfile_asf_markerobject     = &$thisfile_asf['marker_object'];
    496509
     510                                        $thisfile_asf_markerobject['offset']               = $NextObjectOffset + $offset;
    497511                                        $thisfile_asf_markerobject['objectid']             = $NextObjectGUID;
    498512                                        $thisfile_asf_markerobject['objectid_guid']        = $NextObjectGUIDtext;
     
    502516                                        $thisfile_asf_markerobject['reserved_guid']        = $this->BytestringToGUID($thisfile_asf_markerobject['reserved']);
    503517                                        if ($thisfile_asf_markerobject['reserved'] != $this->GUIDtoBytestring('4CFEDB20-75F6-11CF-9C0F-00A0C90349CB')) {
    504                                                 $ThisFileInfo['warning'][] = 'marker_object.reserved GUID {'.$this->BytestringToGUID($thisfile_asf_markerobject['reserved_1']).'} does not match expected "GETID3_ASF_Reserved_1" GUID {4CFEDB20-75F6-11CF-9C0F-00A0C90349CB}';
     518                                                $info['warning'][] = 'marker_object.reserved GUID {'.$this->BytestringToGUID($thisfile_asf_markerobject['reserved_1']).'} does not match expected "GETID3_ASF_Reserved_1" GUID {4CFEDB20-75F6-11CF-9C0F-00A0C90349CB}';
    505519                                                break;
    506520                                        }
     
    510524                                        $offset += 2;
    511525                                        if ($thisfile_asf_markerobject['reserved_2'] != 0) {
    512                                                 $ThisFileInfo['warning'][] = 'marker_object.reserved_2 ('.getid3_lib::PrintHexBytes($thisfile_asf_markerobject['reserved_2']).') does not match expected value of "0"';
     526                                                $info['warning'][] = 'marker_object.reserved_2 ('.getid3_lib::PrintHexBytes($thisfile_asf_markerobject['reserved_2']).') does not match expected value of "0"';
    513527                                                break;
    514528                                        }
     
    553567                                        $thisfile_asf_bitratemutualexclusionobject       = &$thisfile_asf['bitrate_mutual_exclusion_object'];
    554568
     569                                        $thisfile_asf_bitratemutualexclusionobject['offset']               = $NextObjectOffset + $offset;
    555570                                        $thisfile_asf_bitratemutualexclusionobject['objectid']             = $NextObjectGUID;
    556571                                        $thisfile_asf_bitratemutualexclusionobject['objectid_guid']        = $NextObjectGUIDtext;
     
    560575                                        $offset += 16;
    561576                                        if (($thisfile_asf_bitratemutualexclusionobject['reserved'] != GETID3_ASF_Mutex_Bitrate) && ($thisfile_asf_bitratemutualexclusionobject['reserved'] != GETID3_ASF_Mutex_Unknown)) {
    562                                                 $ThisFileInfo['warning'][] = 'bitrate_mutual_exclusion_object.reserved GUID {'.$this->BytestringToGUID($thisfile_asf_bitratemutualexclusionobject['reserved']).'} does not match expected "GETID3_ASF_Mutex_Bitrate" GUID {'.$this->BytestringToGUID(GETID3_ASF_Mutex_Bitrate).'} or  "GETID3_ASF_Mutex_Unknown" GUID {'.$this->BytestringToGUID(GETID3_ASF_Mutex_Unknown).'}';
     577                                                $info['warning'][] = 'bitrate_mutual_exclusion_object.reserved GUID {'.$this->BytestringToGUID($thisfile_asf_bitratemutualexclusionobject['reserved']).'} does not match expected "GETID3_ASF_Mutex_Bitrate" GUID {'.$this->BytestringToGUID(GETID3_ASF_Mutex_Bitrate).'} or  "GETID3_ASF_Mutex_Unknown" GUID {'.$this->BytestringToGUID(GETID3_ASF_Mutex_Unknown).'}';
    563578                                                //return false;
    564579                                                break;
     
    585600                                        $thisfile_asf_errorcorrectionobject      = &$thisfile_asf['error_correction_object'];
    586601
     602                                        $thisfile_asf_errorcorrectionobject['offset']                = $NextObjectOffset + $offset;
    587603                                        $thisfile_asf_errorcorrectionobject['objectid']              = $NextObjectGUID;
    588604                                        $thisfile_asf_errorcorrectionobject['objectid_guid']         = $NextObjectGUIDtext;
     
    620636
    621637                                                default:
    622                                                         $ThisFileInfo['warning'][] = 'error_correction_object.error_correction_type GUID {'.$this->BytestringToGUID($thisfile_asf_errorcorrectionobject['reserved']).'} does not match expected "GETID3_ASF_No_Error_Correction" GUID {'.$this->BytestringToGUID(GETID3_ASF_No_Error_Correction).'} or  "GETID3_ASF_Audio_Spread" GUID {'.$this->BytestringToGUID(GETID3_ASF_Audio_Spread).'}';
     638                                                        $info['warning'][] = 'error_correction_object.error_correction_type GUID {'.$this->BytestringToGUID($thisfile_asf_errorcorrectionobject['reserved']).'} does not match expected "GETID3_ASF_No_Error_Correction" GUID {'.$this->BytestringToGUID(GETID3_ASF_No_Error_Correction).'} or  "GETID3_ASF_Audio_Spread" GUID {'.$this->BytestringToGUID(GETID3_ASF_Audio_Spread).'}';
    623639                                                        //return false;
    624640                                                        break;
     
    647663                                        $thisfile_asf_contentdescriptionobject      = &$thisfile_asf['content_description_object'];
    648664
     665                                        $thisfile_asf_contentdescriptionobject['offset']                = $NextObjectOffset + $offset;
    649666                                        $thisfile_asf_contentdescriptionobject['objectid']              = $NextObjectGUID;
    650667                                        $thisfile_asf_contentdescriptionobject['objectid_guid']         = $NextObjectGUIDtext;
     
    702719                                        $thisfile_asf_extendedcontentdescriptionobject       = &$thisfile_asf['extended_content_description_object'];
    703720
     721                                        $thisfile_asf_extendedcontentdescriptionobject['offset']                    = $NextObjectOffset + $offset;
    704722                                        $thisfile_asf_extendedcontentdescriptionobject['objectid']                  = $NextObjectGUID;
    705723                                        $thisfile_asf_extendedcontentdescriptionobject['objectid_guid']             = $NextObjectGUIDtext;
     
    742760
    743761                                                        default:
    744                                                                 $ThisFileInfo['warning'][] = 'extended_content_description.content_descriptors.'.$ExtendedContentDescriptorsCounter.'.value_type is invalid ('.$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_type'].')';
     762                                                                $info['warning'][] = 'extended_content_description.content_descriptors.'.$ExtendedContentDescriptorsCounter.'.value_type is invalid ('.$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_type'].')';
    745763                                                                //return false;
    746764                                                                break;
     
    750768                                                        case 'wm/albumartist':
    751769                                                        case 'artist':
    752                                                                 $thisfile_asf_comments['artist'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
     770                                                                // Note: not 'artist', that comes from 'author' tag
     771                                                                $thisfile_asf_comments['albumartist'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
    753772                                                                break;
    754773
     
    763782                                                                break;
    764783
     784                                                        case 'wm/partofset':
     785                                                                $thisfile_asf_comments['partofset'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
     786                                                                break;
     787
    765788                                                        case 'wm/tracknumber':
    766789                                                        case 'tracknumber':
    767                                                                 $thisfile_asf_comments['track'] = array(intval($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'])));
     790                                                                // be careful casting to int: casting unicode strings to int gives unexpected results (stops parsing at first non-numeric character)
     791                                                                $thisfile_asf_comments['track'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
     792                                                                foreach ($thisfile_asf_comments['track'] as $key => $value) {
     793                                                                        if (preg_match('/^[0-9\x00]+$/', $value)) {
     794                                                                                $thisfile_asf_comments['track'][$key] = intval(str_replace("\x00", '', $value));
     795                                                                        }
     796                                                                }
    768797                                                                break;
    769798
     
    795824                                                                // id3v2 module might not be loaded
    796825                                                                if (class_exists('getid3_id3v2')) {
    797                                                                     $tempfile         = tempnam('*', 'getID3');
    798                                                                     $tempfilehandle   = fopen($tempfile, "wb");
    799                                                                         $tempThisfileInfo = array('encoding'=>$ThisFileInfo['encoding']);
     826                                                                        $tempfile         = tempnam(GETID3_TEMP_DIR, 'getID3');
     827                                                                        $tempfilehandle   = fopen($tempfile, 'wb');
     828                                                                        $tempThisfileInfo = array('encoding'=>$info['encoding']);
    800829                                                                        fwrite($tempfilehandle, $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']);
    801830                                                                        fclose($tempfilehandle);
    802831
    803                                                                         $tempfilehandle = fopen($tempfile, "rb");
    804                                                                         $id3 = new getid3_id3v2($tempfilehandle, $tempThisfileInfo);
    805                                                                         unset($id3);
    806                                                                         fclose($tempfilehandle);
     832                                                                        $getid3_temp = new getID3();
     833                                                                        $getid3_temp->openfile($tempfile);
     834                                                                        $getid3_id3v2 = new getid3_id3v2($getid3_temp);
     835                                                                        $getid3_id3v2->Analyze();
     836                                                                        $info['id3v2'] = $getid3_temp->info['id3v2'];
     837                                                                        unset($getid3_temp, $getid3_id3v2);
     838
    807839                                                                        unlink($tempfile);
    808 
    809                                                                         $ThisFileInfo['id3v2'] = $tempThisfileInfo['id3v2'];
    810                                                                         unset($tempThisfileInfo);
    811840                                                                }
    812841                                                                break;
     
    851880                                                                unset($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']);
    852881
     882                                                                $imageinfo = array();
     883                                                                $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_mime'] = '';
     884                                                                $imagechunkcheck = getid3_lib::GetDataImageSize($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['data'], $imageinfo);
     885                                                                unset($imageinfo);
     886                                                                if (!empty($imagechunkcheck)) {
     887                                                                        $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_mime'] = image_type_to_mime_type($imagechunkcheck[2]);
     888                                                                }
     889                                                                if (!isset($thisfile_asf_comments['picture'])) {
     890                                                                        $thisfile_asf_comments['picture'] = array();
     891                                                                }